Upgrade to 3.29
Update V8 to 3.29.88.17 and update makefiles to support building on
all the relevant platforms.
Bug: 17370214
Change-Id: Ia3407c157fd8d72a93e23d8318ccaf6ecf77fa4e
diff --git a/src/frames.cc b/src/frames.cc
index 0571a81..f116fd2 100644
--- a/src/frames.cc
+++ b/src/frames.cc
@@ -1,61 +1,26 @@
// Copyright 2012 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
-#include "v8.h"
+#include "src/v8.h"
-#include "ast.h"
-#include "deoptimizer.h"
-#include "frames-inl.h"
-#include "full-codegen.h"
-#include "lazy-instance.h"
-#include "mark-compact.h"
-#include "safepoint-table.h"
-#include "scopeinfo.h"
-#include "string-stream.h"
-
-#include "allocation-inl.h"
+#include "src/ast.h"
+#include "src/base/bits.h"
+#include "src/deoptimizer.h"
+#include "src/frames-inl.h"
+#include "src/full-codegen.h"
+#include "src/heap/mark-compact.h"
+#include "src/safepoint-table.h"
+#include "src/scopeinfo.h"
+#include "src/string-stream.h"
+#include "src/vm-state-inl.h"
namespace v8 {
namespace internal {
-static ReturnAddressLocationResolver return_address_location_resolver = NULL;
-
-
-// Resolves pc_address through the resolution address function if one is set.
-static inline Address* ResolveReturnAddressLocation(Address* pc_address) {
- if (return_address_location_resolver == NULL) {
- return pc_address;
- } else {
- return reinterpret_cast<Address*>(
- return_address_location_resolver(
- reinterpret_cast<uintptr_t>(pc_address)));
- }
-}
+ReturnAddressLocationResolver
+ StackFrame::return_address_location_resolver_ = NULL;
// Iterator that supports traversing the stack handlers of a
@@ -65,7 +30,7 @@
StackHandlerIterator(const StackFrame* frame, StackHandler* handler)
: limit_(frame->fp()), handler_(handler) {
// Make sure the handler has already been unwound to this frame.
- ASSERT(frame->sp() <= handler->address());
+ DCHECK(frame->sp() <= handler->address());
}
StackHandler* handler() const { return handler_; }
@@ -74,7 +39,7 @@
return handler_ == NULL || handler_->address() > limit_;
}
void Advance() {
- ASSERT(!done());
+ DCHECK(!done());
handler_ = handler_->next();
}
@@ -88,48 +53,30 @@
#define INITIALIZE_SINGLETON(type, field) field##_(this),
-StackFrameIterator::StackFrameIterator()
- : isolate_(Isolate::Current()),
- STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
- frame_(NULL), handler_(NULL),
- thread_(isolate_->thread_local_top()),
- fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
- Reset();
-}
-StackFrameIterator::StackFrameIterator(Isolate* isolate)
+StackFrameIteratorBase::StackFrameIteratorBase(Isolate* isolate,
+ bool can_access_heap_objects)
: isolate_(isolate),
STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
frame_(NULL), handler_(NULL),
- thread_(isolate_->thread_local_top()),
- fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
- Reset();
+ can_access_heap_objects_(can_access_heap_objects) {
}
-StackFrameIterator::StackFrameIterator(Isolate* isolate, ThreadLocalTop* t)
- : isolate_(isolate),
- STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
- frame_(NULL), handler_(NULL), thread_(t),
- fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
- Reset();
-}
-StackFrameIterator::StackFrameIterator(Isolate* isolate,
- bool use_top, Address fp, Address sp)
- : isolate_(isolate),
- STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
- frame_(NULL), handler_(NULL),
- thread_(use_top ? isolate_->thread_local_top() : NULL),
- fp_(use_top ? NULL : fp), sp_(sp),
- advance_(use_top ? &StackFrameIterator::AdvanceWithHandler :
- &StackFrameIterator::AdvanceWithoutHandler) {
- if (use_top || fp != NULL) {
- Reset();
- }
-}
-
#undef INITIALIZE_SINGLETON
-void StackFrameIterator::AdvanceWithHandler() {
- ASSERT(!done());
+StackFrameIterator::StackFrameIterator(Isolate* isolate)
+ : StackFrameIteratorBase(isolate, true) {
+ Reset(isolate->thread_local_top());
+}
+
+
+StackFrameIterator::StackFrameIterator(Isolate* isolate, ThreadLocalTop* t)
+ : StackFrameIteratorBase(isolate, true) {
+ Reset(t);
+}
+
+
+void StackFrameIterator::Advance() {
+ DCHECK(!done());
// Compute the state of the calling frame before restoring
// callee-saved registers and unwinding handlers. This allows the
// frame code that computes the caller state to access the top
@@ -147,51 +94,31 @@
// When we're done iterating over the stack frames, the handler
// chain must have been completely unwound.
- ASSERT(!done() || handler_ == NULL);
+ DCHECK(!done() || handler_ == NULL);
}
-void StackFrameIterator::AdvanceWithoutHandler() {
- // A simpler version of Advance which doesn't care about handler.
- ASSERT(!done());
+void StackFrameIterator::Reset(ThreadLocalTop* top) {
StackFrame::State state;
- StackFrame::Type type = frame_->GetCallerState(&state);
- frame_ = SingletonFor(type, &state);
-}
-
-
-void StackFrameIterator::Reset() {
- StackFrame::State state;
- StackFrame::Type type;
- if (thread_ != NULL) {
- type = ExitFrame::GetStateForFramePointer(
- Isolate::c_entry_fp(thread_), &state);
- handler_ = StackHandler::FromAddress(
- Isolate::handler(thread_));
- } else {
- ASSERT(fp_ != NULL);
- state.fp = fp_;
- state.sp = sp_;
- state.pc_address = ResolveReturnAddressLocation(
- reinterpret_cast<Address*>(StandardFrame::ComputePCAddress(fp_)));
- type = StackFrame::ComputeType(isolate(), &state);
- }
+ StackFrame::Type type = ExitFrame::GetStateForFramePointer(
+ Isolate::c_entry_fp(top), &state);
+ handler_ = StackHandler::FromAddress(Isolate::handler(top));
if (SingletonFor(type) == NULL) return;
frame_ = SingletonFor(type, &state);
}
-StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type,
+StackFrame* StackFrameIteratorBase::SingletonFor(StackFrame::Type type,
StackFrame::State* state) {
if (type == StackFrame::NONE) return NULL;
StackFrame* result = SingletonFor(type);
- ASSERT(result != NULL);
+ DCHECK(result != NULL);
result->state_ = *state;
return result;
}
-StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type) {
+StackFrame* StackFrameIteratorBase::SingletonFor(StackFrame::Type type) {
#define FRAME_TYPE_CASE(type, field) \
case StackFrame::type: result = &field##_; break;
@@ -210,11 +137,33 @@
// -------------------------------------------------------------------------
-StackTraceFrameIterator::StackTraceFrameIterator() {
- if (!done() && !IsValidFrame()) Advance();
+JavaScriptFrameIterator::JavaScriptFrameIterator(
+ Isolate* isolate, StackFrame::Id id)
+ : iterator_(isolate) {
+ while (!done()) {
+ Advance();
+ if (frame()->id() == id) return;
+ }
}
+void JavaScriptFrameIterator::Advance() {
+ do {
+ iterator_.Advance();
+ } while (!iterator_.done() && !iterator_.frame()->is_java_script());
+}
+
+
+void JavaScriptFrameIterator::AdvanceToArgumentsFrame() {
+ if (!frame()->has_adapted_arguments()) return;
+ iterator_.Advance();
+ DCHECK(iterator_.frame()->is_arguments_adaptor());
+}
+
+
+// -------------------------------------------------------------------------
+
+
StackTraceFrameIterator::StackTraceFrameIterator(Isolate* isolate)
: JavaScriptFrameIterator(isolate) {
if (!done() && !IsValidFrame()) Advance();
@@ -229,9 +178,10 @@
}
}
+
bool StackTraceFrameIterator::IsValidFrame() {
if (!frame()->function()->IsJSFunction()) return false;
- Object* script = JSFunction::cast(frame()->function())->shared()->script();
+ Object* script = frame()->function()->shared()->script();
// Don't show functions from native scripts to user.
return (script->IsScript() &&
Script::TYPE_NATIVE != Script::cast(script)->type()->value());
@@ -241,85 +191,93 @@
// -------------------------------------------------------------------------
-bool SafeStackFrameIterator::ExitFrameValidator::IsValidFP(Address fp) {
- if (!validator_.IsValid(fp)) return false;
- Address sp = ExitFrame::ComputeStackPointer(fp);
- if (!validator_.IsValid(sp)) return false;
- StackFrame::State state;
- ExitFrame::FillState(fp, sp, &state);
- if (!validator_.IsValid(reinterpret_cast<Address>(state.pc_address))) {
- return false;
- }
- return *state.pc_address != NULL;
-}
-
-
-SafeStackFrameIterator::ActiveCountMaintainer::ActiveCountMaintainer(
- Isolate* isolate)
- : isolate_(isolate) {
- isolate_->set_safe_stack_iterator_counter(
- isolate_->safe_stack_iterator_counter() + 1);
-}
-
-
-SafeStackFrameIterator::ActiveCountMaintainer::~ActiveCountMaintainer() {
- isolate_->set_safe_stack_iterator_counter(
- isolate_->safe_stack_iterator_counter() - 1);
-}
-
-
SafeStackFrameIterator::SafeStackFrameIterator(
Isolate* isolate,
- Address fp, Address sp, Address low_bound, Address high_bound) :
- maintainer_(isolate),
- stack_validator_(low_bound, high_bound),
- is_valid_top_(IsValidTop(isolate, low_bound, high_bound)),
- is_valid_fp_(IsWithinBounds(low_bound, high_bound, fp)),
- is_working_iterator_(is_valid_top_ || is_valid_fp_),
- iteration_done_(!is_working_iterator_),
- iterator_(isolate, is_valid_top_, is_valid_fp_ ? fp : NULL, sp) {
-}
-
-bool SafeStackFrameIterator::is_active(Isolate* isolate) {
- return isolate->safe_stack_iterator_counter() > 0;
-}
-
-
-bool SafeStackFrameIterator::IsValidTop(Isolate* isolate,
- Address low_bound, Address high_bound) {
+ Address fp, Address sp, Address js_entry_sp)
+ : StackFrameIteratorBase(isolate, false),
+ low_bound_(sp),
+ high_bound_(js_entry_sp),
+ top_frame_type_(StackFrame::NONE),
+ external_callback_scope_(isolate->external_callback_scope()) {
+ StackFrame::State state;
+ StackFrame::Type type;
ThreadLocalTop* top = isolate->thread_local_top();
- Address fp = Isolate::c_entry_fp(top);
- ExitFrameValidator validator(low_bound, high_bound);
- if (!validator.IsValidFP(fp)) return false;
- return Isolate::handler(top) != NULL;
+ if (IsValidTop(top)) {
+ type = ExitFrame::GetStateForFramePointer(Isolate::c_entry_fp(top), &state);
+ top_frame_type_ = type;
+ } else if (IsValidStackAddress(fp)) {
+ DCHECK(fp != NULL);
+ state.fp = fp;
+ state.sp = sp;
+ state.pc_address = StackFrame::ResolveReturnAddressLocation(
+ reinterpret_cast<Address*>(StandardFrame::ComputePCAddress(fp)));
+ // StackFrame::ComputeType will read both kContextOffset and kMarkerOffset,
+ // we check only that kMarkerOffset is within the stack bounds and do
+ // compile time check that kContextOffset slot is pushed on the stack before
+ // kMarkerOffset.
+ STATIC_ASSERT(StandardFrameConstants::kMarkerOffset <
+ StandardFrameConstants::kContextOffset);
+ Address frame_marker = fp + StandardFrameConstants::kMarkerOffset;
+ if (IsValidStackAddress(frame_marker)) {
+ type = StackFrame::ComputeType(this, &state);
+ top_frame_type_ = type;
+ } else {
+ // Mark the frame as JAVA_SCRIPT if we cannot determine its type.
+ // The frame anyways will be skipped.
+ type = StackFrame::JAVA_SCRIPT;
+ // Top frame is incomplete so we cannot reliably determine its type.
+ top_frame_type_ = StackFrame::NONE;
+ }
+ } else {
+ return;
+ }
+ if (SingletonFor(type) == NULL) return;
+ frame_ = SingletonFor(type, &state);
+ if (frame_ == NULL) return;
+
+ Advance();
+
+ if (frame_ != NULL && !frame_->is_exit() &&
+ external_callback_scope_ != NULL &&
+ external_callback_scope_->scope_address() < frame_->fp()) {
+ // Skip top ExternalCallbackScope if we already advanced to a JS frame
+ // under it. Sampler will anyways take this top external callback.
+ external_callback_scope_ = external_callback_scope_->previous();
+ }
}
-void SafeStackFrameIterator::Advance() {
- ASSERT(is_working_iterator_);
- ASSERT(!done());
- StackFrame* last_frame = iterator_.frame();
+bool SafeStackFrameIterator::IsValidTop(ThreadLocalTop* top) const {
+ Address c_entry_fp = Isolate::c_entry_fp(top);
+ if (!IsValidExitFrame(c_entry_fp)) return false;
+ // There should be at least one JS_ENTRY stack handler.
+ Address handler = Isolate::handler(top);
+ if (handler == NULL) return false;
+ // Check that there are no js frames on top of the native frames.
+ return c_entry_fp < handler;
+}
+
+
+void SafeStackFrameIterator::AdvanceOneFrame() {
+ DCHECK(!done());
+ StackFrame* last_frame = frame_;
Address last_sp = last_frame->sp(), last_fp = last_frame->fp();
- // Before advancing to the next stack frame, perform pointer validity tests
- iteration_done_ = !IsValidFrame(last_frame) ||
- !CanIterateHandles(last_frame, iterator_.handler()) ||
- !IsValidCaller(last_frame);
- if (iteration_done_) return;
+ // Before advancing to the next stack frame, perform pointer validity tests.
+ if (!IsValidFrame(last_frame) || !IsValidCaller(last_frame)) {
+ frame_ = NULL;
+ return;
+ }
- iterator_.Advance();
- if (iterator_.done()) return;
- // Check that we have actually moved to the previous frame in the stack
- StackFrame* prev_frame = iterator_.frame();
- iteration_done_ = prev_frame->sp() < last_sp || prev_frame->fp() < last_fp;
-}
+ // Advance to the previous frame.
+ StackFrame::State state;
+ StackFrame::Type type = frame_->GetCallerState(&state);
+ frame_ = SingletonFor(type, &state);
+ if (frame_ == NULL) return;
-
-bool SafeStackFrameIterator::CanIterateHandles(StackFrame* frame,
- StackHandler* handler) {
- // If StackIterator iterates over StackHandles, verify that
- // StackHandlerIterator can be instantiated (see StackHandlerIterator
- // constructor.)
- return !is_valid_top_ || (frame->sp() <= handler->address());
+ // Check that we have actually moved to the previous frame in the stack.
+ if (frame_->sp() < last_sp || frame_->fp() < last_fp) {
+ frame_ = NULL;
+ }
}
@@ -336,8 +294,7 @@
// sure that caller FP address is valid.
Address caller_fp = Memory::Address_at(
frame->fp() + EntryFrameConstants::kCallerFPOffset);
- ExitFrameValidator validator(stack_validator_);
- if (!validator.IsValidFP(caller_fp)) return false;
+ if (!IsValidExitFrame(caller_fp)) return false;
} else if (frame->is_arguments_adaptor()) {
// See ArgumentsAdaptorFrame::GetCallerStackPointer. It assumes that
// the number of arguments is stored on stack as Smi. We need to check
@@ -350,14 +307,46 @@
}
frame->ComputeCallerState(&state);
return IsValidStackAddress(state.sp) && IsValidStackAddress(state.fp) &&
- iterator_.SingletonFor(frame->GetCallerState(&state)) != NULL;
+ SingletonFor(frame->GetCallerState(&state)) != NULL;
}
-void SafeStackFrameIterator::Reset() {
- if (is_working_iterator_) {
- iterator_.Reset();
- iteration_done_ = false;
+bool SafeStackFrameIterator::IsValidExitFrame(Address fp) const {
+ if (!IsValidStackAddress(fp)) return false;
+ Address sp = ExitFrame::ComputeStackPointer(fp);
+ if (!IsValidStackAddress(sp)) return false;
+ StackFrame::State state;
+ ExitFrame::FillState(fp, sp, &state);
+ if (!IsValidStackAddress(reinterpret_cast<Address>(state.pc_address))) {
+ return false;
+ }
+ return *state.pc_address != NULL;
+}
+
+
+void SafeStackFrameIterator::Advance() {
+ while (true) {
+ AdvanceOneFrame();
+ if (done()) return;
+ if (frame_->is_java_script()) return;
+ if (frame_->is_exit() && external_callback_scope_) {
+ // Some of the EXIT frames may have ExternalCallbackScope allocated on
+ // top of them. In that case the scope corresponds to the first EXIT
+ // frame beneath it. There may be other EXIT frames on top of the
+ // ExternalCallbackScope, just skip them as we cannot collect any useful
+ // information about them.
+ if (external_callback_scope_->scope_address() < frame_->fp()) {
+ Address* callback_address =
+ external_callback_scope_->callback_address();
+ if (*callback_address != NULL) {
+ frame_->state_.pc_address = callback_address;
+ }
+ external_callback_scope_ = external_callback_scope_->previous();
+ DCHECK(external_callback_scope_ == NULL ||
+ external_callback_scope_->scope_address() > frame_->fp());
+ return;
+ }
+ }
}
}
@@ -365,23 +354,6 @@
// -------------------------------------------------------------------------
-SafeStackTraceFrameIterator::SafeStackTraceFrameIterator(
- Isolate* isolate,
- Address fp, Address sp, Address low_bound, Address high_bound) :
- SafeJavaScriptFrameIterator(isolate, fp, sp, low_bound, high_bound) {
- if (!done() && !frame()->is_java_script()) Advance();
-}
-
-
-void SafeStackTraceFrameIterator::Advance() {
- while (true) {
- SafeJavaScriptFrameIterator::Advance();
- if (done()) return;
- if (frame()->is_java_script()) return;
- }
-}
-
-
Code* StackFrame::GetSafepointData(Isolate* isolate,
Address inner_pointer,
SafepointEntry* safepoint_entry,
@@ -390,9 +362,9 @@
isolate->inner_pointer_to_code_cache()->GetCacheEntry(inner_pointer);
if (!entry->safepoint_entry.is_valid()) {
entry->safepoint_entry = entry->code->GetSafepointEntry(inner_pointer);
- ASSERT(entry->safepoint_entry.is_valid());
+ DCHECK(entry->safepoint_entry.is_valid());
} else {
- ASSERT(entry->safepoint_entry.Equals(
+ DCHECK(entry->safepoint_entry.Equals(
entry->code->GetSafepointEntry(inner_pointer)));
}
@@ -419,7 +391,7 @@
Address* pc_address,
Code* holder) {
Address pc = *pc_address;
- ASSERT(GcSafeCodeContains(holder, pc));
+ DCHECK(GcSafeCodeContains(holder, pc));
unsigned pc_offset = static_cast<unsigned>(pc - holder->instruction_start());
Object* code = holder;
v->VisitPointer(&code);
@@ -433,13 +405,14 @@
void StackFrame::SetReturnAddressLocationResolver(
ReturnAddressLocationResolver resolver) {
- ASSERT(return_address_location_resolver == NULL);
- return_address_location_resolver = resolver;
+ DCHECK(return_address_location_resolver_ == NULL);
+ return_address_location_resolver_ = resolver;
}
-StackFrame::Type StackFrame::ComputeType(Isolate* isolate, State* state) {
- ASSERT(state->fp != NULL);
+StackFrame::Type StackFrame::ComputeType(const StackFrameIteratorBase* iterator,
+ State* state) {
+ DCHECK(state->fp != NULL);
if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) {
return ARGUMENTS_ADAPTOR;
}
@@ -453,24 +426,45 @@
// frames as normal JavaScript frames to avoid having to look
// into the heap to determine the state. This is safe as long
// as nobody tries to GC...
- if (SafeStackFrameIterator::is_active(isolate)) return JAVA_SCRIPT;
- Code::Kind kind = GetContainingCode(isolate, *(state->pc_address))->kind();
- ASSERT(kind == Code::FUNCTION || kind == Code::OPTIMIZED_FUNCTION);
+ if (!iterator->can_access_heap_objects_) return JAVA_SCRIPT;
+ Code::Kind kind = GetContainingCode(iterator->isolate(),
+ *(state->pc_address))->kind();
+ DCHECK(kind == Code::FUNCTION || kind == Code::OPTIMIZED_FUNCTION);
return (kind == Code::OPTIMIZED_FUNCTION) ? OPTIMIZED : JAVA_SCRIPT;
}
return static_cast<StackFrame::Type>(Smi::cast(marker)->value());
}
+#ifdef DEBUG
+bool StackFrame::can_access_heap_objects() const {
+ return iterator_->can_access_heap_objects_;
+}
+#endif
+
StackFrame::Type StackFrame::GetCallerState(State* state) const {
ComputeCallerState(state);
- return ComputeType(isolate(), state);
+ return ComputeType(iterator_, state);
+}
+
+
+Address StackFrame::UnpaddedFP() const {
+#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87
+ if (!is_optimized()) return fp();
+ int32_t alignment_state = Memory::int32_at(
+ fp() + JavaScriptFrameConstants::kDynamicAlignmentStateOffset);
+
+ return (alignment_state == kAlignmentPaddingPushed) ?
+ (fp() + kPointerSize) : fp();
+#else
+ return fp();
+#endif
}
Code* EntryFrame::unchecked_code() const {
- return HEAP->raw_unchecked_js_entry_code();
+ return isolate()->heap()->js_entry_code();
}
@@ -493,7 +487,7 @@
Code* EntryConstructFrame::unchecked_code() const {
- return HEAP->raw_unchecked_js_construct_entry_code();
+ return isolate()->heap()->js_construct_entry_code();
}
@@ -514,6 +508,10 @@
state->fp = Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset);
state->pc_address = ResolveReturnAddressLocation(
reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset));
+ if (FLAG_enable_ool_constant_pool) {
+ state->constant_pool_address = reinterpret_cast<Address*>(
+ fp() + ExitFrameConstants::kConstantPoolOffset);
+ }
}
@@ -527,6 +525,9 @@
// the calling frame.
IteratePc(v, pc_address(), LookupCode());
v->VisitPointer(&code_slot());
+ if (FLAG_enable_ool_constant_pool) {
+ v->VisitPointer(&constant_pool_slot());
+ }
}
@@ -539,16 +540,23 @@
if (fp == 0) return NONE;
Address sp = ComputeStackPointer(fp);
FillState(fp, sp, state);
- ASSERT(*state->pc_address != NULL);
+ DCHECK(*state->pc_address != NULL);
return EXIT;
}
+Address ExitFrame::ComputeStackPointer(Address fp) {
+ return Memory::Address_at(fp + ExitFrameConstants::kSPOffset);
+}
+
+
void ExitFrame::FillState(Address fp, Address sp, State* state) {
state->sp = sp;
state->fp = fp;
state->pc_address = ResolveReturnAddressLocation(
- reinterpret_cast<Address*>(sp - 1 * kPointerSize));
+ reinterpret_cast<Address*>(sp - 1 * kPCOnStackSize));
+ state->constant_pool_address =
+ reinterpret_cast<Address*>(fp + ExitFrameConstants::kConstantPoolOffset);
}
@@ -574,7 +582,7 @@
StandardFrameConstants::kExpressionsOffset + kPointerSize;
Address base = fp() + offset;
Address limit = sp();
- ASSERT(base >= limit); // stack grows downwards
+ DCHECK(base >= limit); // stack grows downwards
// Include register-allocated locals in number of expressions.
return static_cast<int>((base - limit) / kPointerSize);
}
@@ -585,6 +593,8 @@
state->fp = caller_fp();
state->pc_address = ResolveReturnAddressLocation(
reinterpret_cast<Address*>(ComputePCAddress(fp())));
+ state->constant_pool_address =
+ reinterpret_cast<Address*>(ComputeConstantPoolAddress(fp()));
}
@@ -603,16 +613,10 @@
}
-void OptimizedFrame::Iterate(ObjectVisitor* v) const {
-#ifdef DEBUG
- // Make sure that optimized frames do not contain any stack handlers.
- StackHandlerIterator it(this, top_handler());
- ASSERT(it.done());
-#endif
-
+void StandardFrame::IterateCompiledFrame(ObjectVisitor* v) const {
// Make sure that we're not doing "safe" stack frame iteration. We cannot
// possibly find pointers in optimized frames in that state.
- ASSERT(!SafeStackFrameIterator::is_active(isolate()));
+ DCHECK(can_access_heap_objects());
// Compute the safepoint information.
unsigned stack_slots = 0;
@@ -635,7 +639,9 @@
// Skip saved double registers.
if (safepoint_entry.has_doubles()) {
- parameters_base += DoubleRegister::kNumAllocatableRegisters *
+ // Number of doubles not known at snapshot time.
+ DCHECK(!isolate()->serializer_enabled());
+ parameters_base += DoubleRegister::NumAllocatableRegisters() *
kDoubleSize / kPointerSize;
}
@@ -667,14 +673,51 @@
}
}
- // Visit the context and the function.
- Object** fixed_base = &Memory::Object_at(
- fp() + JavaScriptFrameConstants::kFunctionOffset);
- Object** fixed_limit = &Memory::Object_at(fp());
- v->VisitPointers(fixed_base, fixed_limit);
-
// Visit the return address in the callee and incoming arguments.
IteratePc(v, pc_address(), code);
+
+ // Visit the context in stub frame and JavaScript frame.
+ // Visit the function in JavaScript frame.
+ Object** fixed_base = &Memory::Object_at(
+ fp() + StandardFrameConstants::kMarkerOffset);
+ Object** fixed_limit = &Memory::Object_at(fp());
+ v->VisitPointers(fixed_base, fixed_limit);
+}
+
+
+void StubFrame::Iterate(ObjectVisitor* v) const {
+ IterateCompiledFrame(v);
+}
+
+
+Code* StubFrame::unchecked_code() const {
+ return static_cast<Code*>(isolate()->FindCodeObject(pc()));
+}
+
+
+Address StubFrame::GetCallerStackPointer() const {
+ return fp() + ExitFrameConstants::kCallerSPDisplacement;
+}
+
+
+int StubFrame::GetNumberOfIncomingArguments() const {
+ return 0;
+}
+
+
+void OptimizedFrame::Iterate(ObjectVisitor* v) const {
+#ifdef DEBUG
+ // Make sure that optimized frames do not contain any stack handlers.
+ StackHandlerIterator it(this, top_handler());
+ DCHECK(it.done());
+#endif
+
+ IterateCompiledFrame(v);
+}
+
+
+void JavaScriptFrame::SetParameterValue(int index, Object* value) const {
+ Memory::Object_at(GetParameterSlot(index)) = value;
}
@@ -699,17 +742,15 @@
Code* JavaScriptFrame::unchecked_code() const {
- JSFunction* function = JSFunction::cast(this->function());
- return function->unchecked_code();
+ return function()->code();
}
int JavaScriptFrame::GetNumberOfIncomingArguments() const {
- ASSERT(!SafeStackFrameIterator::is_active(isolate()) &&
+ DCHECK(can_access_heap_objects() &&
isolate()->heap()->gc_state() == Heap::NOT_IN_GC);
- JSFunction* function = JSFunction::cast(this->function());
- return function->shared()->formal_parameter_count();
+ return function()->shared()->formal_parameter_count();
}
@@ -719,17 +760,17 @@
void JavaScriptFrame::GetFunctions(List<JSFunction*>* functions) {
- ASSERT(functions->length() == 0);
- functions->Add(JSFunction::cast(function()));
+ DCHECK(functions->length() == 0);
+ functions->Add(function());
}
void JavaScriptFrame::Summarize(List<FrameSummary>* functions) {
- ASSERT(functions->length() == 0);
+ DCHECK(functions->length() == 0);
Code* code_pointer = LookupCode();
int offset = static_cast<int>(pc() - code_pointer->address());
FrameSummary summary(receiver(),
- JSFunction::cast(function()),
+ function(),
code_pointer,
offset,
IsConstructor());
@@ -737,54 +778,47 @@
}
-void JavaScriptFrame::PrintTop(FILE* file,
- bool print_args,
+void JavaScriptFrame::PrintFunctionAndOffset(JSFunction* function, Code* code,
+ Address pc, FILE* file,
+ bool print_line_number) {
+ PrintF(file, "%s", function->IsOptimized() ? "*" : "~");
+ function->PrintName(file);
+ int code_offset = static_cast<int>(pc - code->instruction_start());
+ PrintF(file, "+%d", code_offset);
+ if (print_line_number) {
+ SharedFunctionInfo* shared = function->shared();
+ int source_pos = code->SourcePosition(pc);
+ Object* maybe_script = shared->script();
+ if (maybe_script->IsScript()) {
+ Script* script = Script::cast(maybe_script);
+ int line = script->GetLineNumber(source_pos) + 1;
+ Object* script_name_raw = script->name();
+ if (script_name_raw->IsString()) {
+ String* script_name = String::cast(script->name());
+ SmartArrayPointer<char> c_script_name =
+ script_name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+ PrintF(file, " at %s:%d", c_script_name.get(), line);
+ } else {
+ PrintF(file, " at <unknown>:%d", line);
+ }
+ } else {
+ PrintF(file, " at <unknown>:<unknown>");
+ }
+ }
+}
+
+
+void JavaScriptFrame::PrintTop(Isolate* isolate, FILE* file, bool print_args,
bool print_line_number) {
// constructor calls
- HandleScope scope;
- AssertNoAllocation no_allocation;
- JavaScriptFrameIterator it;
+ DisallowHeapAllocation no_allocation;
+ JavaScriptFrameIterator it(isolate);
while (!it.done()) {
if (it.frame()->is_java_script()) {
JavaScriptFrame* frame = it.frame();
if (frame->IsConstructor()) PrintF(file, "new ");
- // function name
- Object* maybe_fun = frame->function();
- if (maybe_fun->IsJSFunction()) {
- JSFunction* fun = JSFunction::cast(maybe_fun);
- fun->PrintName();
- Code* js_code = frame->unchecked_code();
- Address pc = frame->pc();
- int code_offset =
- static_cast<int>(pc - js_code->instruction_start());
- PrintF("+%d", code_offset);
- SharedFunctionInfo* shared = fun->shared();
- if (print_line_number) {
- Code* code = Code::cast(
- v8::internal::Isolate::Current()->heap()->FindCodeObject(pc));
- int source_pos = code->SourcePosition(pc);
- Object* maybe_script = shared->script();
- if (maybe_script->IsScript()) {
- Handle<Script> script(Script::cast(maybe_script));
- int line = GetScriptLineNumberSafe(script, source_pos) + 1;
- Object* script_name_raw = script->name();
- if (script_name_raw->IsString()) {
- String* script_name = String::cast(script->name());
- SmartArrayPointer<char> c_script_name =
- script_name->ToCString(DISALLOW_NULLS,
- ROBUST_STRING_TRAVERSAL);
- PrintF(file, " at %s:%d", *c_script_name, line);
- } else {
- PrintF(file, "at <unknown>:%d", line);
- }
- } else {
- PrintF(file, " at <unknown>:<unknown>");
- }
- }
- } else {
- PrintF("<unknown>");
- }
-
+ PrintFunctionAndOffset(frame->function(), frame->unchecked_code(),
+ frame->pc(), file, print_line_number);
if (print_args) {
// function arguments
// (we are intentionally only printing the actually
@@ -805,6 +839,72 @@
}
+void JavaScriptFrame::SaveOperandStack(FixedArray* store,
+ int* stack_handler_index) const {
+ int operands_count = store->length();
+ DCHECK_LE(operands_count, ComputeOperandsCount());
+
+ // Visit the stack in LIFO order, saving operands and stack handlers into the
+ // array. The saved stack handlers store a link to the next stack handler,
+ // which will allow RestoreOperandStack to rewind the handlers.
+ StackHandlerIterator it(this, top_handler());
+ int i = operands_count - 1;
+ *stack_handler_index = -1;
+ for (; !it.done(); it.Advance()) {
+ StackHandler* handler = it.handler();
+ // Save operands pushed after the handler was pushed.
+ for (; GetOperandSlot(i) < handler->address(); i--) {
+ store->set(i, GetOperand(i));
+ }
+ DCHECK_GE(i + 1, StackHandlerConstants::kSlotCount);
+ DCHECK_EQ(handler->address(), GetOperandSlot(i));
+ int next_stack_handler_index = i + 1 - StackHandlerConstants::kSlotCount;
+ handler->Unwind(isolate(), store, next_stack_handler_index,
+ *stack_handler_index);
+ *stack_handler_index = next_stack_handler_index;
+ i -= StackHandlerConstants::kSlotCount;
+ }
+
+ // Save any remaining operands.
+ for (; i >= 0; i--) {
+ store->set(i, GetOperand(i));
+ }
+}
+
+
+void JavaScriptFrame::RestoreOperandStack(FixedArray* store,
+ int stack_handler_index) {
+ int operands_count = store->length();
+ DCHECK_LE(operands_count, ComputeOperandsCount());
+ int i = 0;
+ while (i <= stack_handler_index) {
+ if (i < stack_handler_index) {
+ // An operand.
+ DCHECK_EQ(GetOperand(i), isolate()->heap()->the_hole_value());
+ Memory::Object_at(GetOperandSlot(i)) = store->get(i);
+ i++;
+ } else {
+ // A stack handler.
+ DCHECK_EQ(i, stack_handler_index);
+ // The FixedArray store grows up. The stack grows down. So the operand
+ // slot for i actually points to the bottom of the top word in the
+ // handler. The base of the StackHandler* is the address of the bottom
+ // word, which will be the last slot that is in the handler.
+ int handler_slot_index = i + StackHandlerConstants::kSlotCount - 1;
+ StackHandler *handler =
+ StackHandler::FromAddress(GetOperandSlot(handler_slot_index));
+ stack_handler_index = handler->Rewind(isolate(), store, i, fp());
+ i += StackHandlerConstants::kSlotCount;
+ }
+ }
+
+ for (; i < operands_count; i++) {
+ DCHECK_EQ(GetOperand(i), isolate()->heap()->the_hole_value());
+ Memory::Object_at(GetOperandSlot(i)) = store->get(i);
+ }
+}
+
+
void FrameSummary::Print() {
PrintF("receiver: ");
receiver_->ShortPrint();
@@ -818,27 +918,41 @@
}
+JSFunction* OptimizedFrame::LiteralAt(FixedArray* literal_array,
+ int literal_id) {
+ if (literal_id == Translation::kSelfLiteralId) {
+ return function();
+ }
+
+ return JSFunction::cast(literal_array->get(literal_id));
+}
+
+
void OptimizedFrame::Summarize(List<FrameSummary>* frames) {
- ASSERT(frames->length() == 0);
- ASSERT(is_optimized());
+ DCHECK(frames->length() == 0);
+ DCHECK(is_optimized());
+
+ // Delegate to JS frame in absence of turbofan deoptimization.
+ // TODO(turbofan): Revisit once we support deoptimization across the board.
+ if (LookupCode()->is_turbofanned() && !FLAG_turbo_deoptimization) {
+ return JavaScriptFrame::Summarize(frames);
+ }
int deopt_index = Safepoint::kNoDeoptimizationIndex;
DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index);
+ FixedArray* literal_array = data->LiteralArray();
// BUG(3243555): Since we don't have a lazy-deopt registered at
// throw-statements, we can't use the translation at the call-site of
// throw. An entry with no deoptimization index indicates a call-site
// without a lazy-deopt. As a consequence we are not allowed to inline
// functions containing throw.
- if (deopt_index == Safepoint::kNoDeoptimizationIndex) {
- JavaScriptFrame::Summarize(frames);
- return;
- }
+ DCHECK(deopt_index != Safepoint::kNoDeoptimizationIndex);
TranslationIterator it(data->TranslationByteArray(),
data->TranslationIndex(deopt_index)->value());
Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
- ASSERT(opcode == Translation::BEGIN);
+ DCHECK(opcode == Translation::BEGIN);
it.Next(); // Drop frame count.
int jsframe_count = it.Next();
@@ -850,25 +964,22 @@
opcode = static_cast<Translation::Opcode>(it.Next());
if (opcode == Translation::JS_FRAME) {
i--;
- int ast_id = it.Next();
- int function_id = it.Next();
+ BailoutId ast_id = BailoutId(it.Next());
+ JSFunction* function = LiteralAt(literal_array, it.Next());
it.Next(); // Skip height.
- JSFunction* function =
- JSFunction::cast(data->LiteralArray()->get(function_id));
// The translation commands are ordered and the receiver is always
- // at the first position. Since we are always at a call when we need
- // to construct a stack trace, the receiver is always in a stack slot.
+ // at the first position.
+ // If we are at a call, the receiver is always in a stack slot.
+ // Otherwise we are not guaranteed to get the receiver value.
opcode = static_cast<Translation::Opcode>(it.Next());
- ASSERT(opcode == Translation::STACK_SLOT ||
- opcode == Translation::LITERAL);
int index = it.Next();
// Get the correct receiver in the optimized frame.
Object* receiver = NULL;
if (opcode == Translation::LITERAL) {
receiver = data->LiteralArray()->get(index);
- } else {
+ } else if (opcode == Translation::STACK_SLOT) {
// Positive index means the value is spilled to the locals
// area. Negative means it is stored in the incoming parameter
// area.
@@ -884,6 +995,13 @@
? this->receiver()
: this->GetParameter(parameter_index);
}
+ } else {
+ // The receiver is not in a stack slot nor in a literal. We give up.
+ // TODO(3029): Materializing a captured object (or duplicated
+ // object) is hard, we return undefined for now. This breaks the
+ // produced stack trace, as constructor frames aren't marked as
+ // such anymore.
+ receiver = isolate()->heap()->undefined_value();
}
Code* code = function->shared()->code();
@@ -894,7 +1012,7 @@
function->shared());
unsigned pc_offset =
FullCodeGenerator::PcField::decode(entry) + Code::kHeaderSize;
- ASSERT(pc_offset > 0);
+ DCHECK(pc_offset > 0);
FrameSummary summary(receiver, function, code, pc_offset, is_constructor);
frames->Add(summary);
@@ -902,22 +1020,22 @@
} else if (opcode == Translation::CONSTRUCT_STUB_FRAME) {
// The next encountered JS_FRAME will be marked as a constructor call.
it.Skip(Translation::NumberOfOperandsFor(opcode));
- ASSERT(!is_constructor);
+ DCHECK(!is_constructor);
is_constructor = true;
} else {
// Skip over operands to advance to the next opcode.
it.Skip(Translation::NumberOfOperandsFor(opcode));
}
}
- ASSERT(!is_constructor);
+ DCHECK(!is_constructor);
}
DeoptimizationInputData* OptimizedFrame::GetDeoptimizationData(
int* deopt_index) {
- ASSERT(is_optimized());
+ DCHECK(is_optimized());
- JSFunction* opt_function = JSFunction::cast(function());
+ JSFunction* opt_function = function();
Code* code = opt_function->code();
// The code object may have been replaced by lazy deoptimization. Fall
@@ -927,19 +1045,25 @@
code = isolate()->inner_pointer_to_code_cache()->
GcSafeFindCodeForInnerPointer(pc());
}
- ASSERT(code != NULL);
- ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION);
+ DCHECK(code != NULL);
+ DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
SafepointEntry safepoint_entry = code->GetSafepointEntry(pc());
*deopt_index = safepoint_entry.deoptimization_index();
- ASSERT(*deopt_index != Safepoint::kNoDeoptimizationIndex);
+ DCHECK(*deopt_index != Safepoint::kNoDeoptimizationIndex);
return DeoptimizationInputData::cast(code->deoptimization_data());
}
int OptimizedFrame::GetInlineCount() {
- ASSERT(is_optimized());
+ DCHECK(is_optimized());
+
+ // Delegate to JS frame in absence of turbofan deoptimization.
+ // TODO(turbofan): Revisit once we support deoptimization across the board.
+ if (LookupCode()->is_turbofanned() && !FLAG_turbo_deoptimization) {
+ return JavaScriptFrame::GetInlineCount();
+ }
int deopt_index = Safepoint::kNoDeoptimizationIndex;
DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index);
@@ -947,7 +1071,7 @@
TranslationIterator it(data->TranslationByteArray(),
data->TranslationIndex(deopt_index)->value());
Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
- ASSERT(opcode == Translation::BEGIN);
+ DCHECK(opcode == Translation::BEGIN);
USE(opcode);
it.Next(); // Drop frame count.
int jsframe_count = it.Next();
@@ -956,16 +1080,23 @@
void OptimizedFrame::GetFunctions(List<JSFunction*>* functions) {
- ASSERT(functions->length() == 0);
- ASSERT(is_optimized());
+ DCHECK(functions->length() == 0);
+ DCHECK(is_optimized());
+
+ // Delegate to JS frame in absence of turbofan deoptimization.
+ // TODO(turbofan): Revisit once we support deoptimization across the board.
+ if (LookupCode()->is_turbofanned() && !FLAG_turbo_deoptimization) {
+ return JavaScriptFrame::GetFunctions(functions);
+ }
int deopt_index = Safepoint::kNoDeoptimizationIndex;
DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index);
+ FixedArray* literal_array = data->LiteralArray();
TranslationIterator it(data->TranslationByteArray(),
data->TranslationIndex(deopt_index)->value());
Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
- ASSERT(opcode == Translation::BEGIN);
+ DCHECK(opcode == Translation::BEGIN);
it.Next(); // Drop frame count.
int jsframe_count = it.Next();
@@ -976,10 +1107,8 @@
if (opcode == Translation::JS_FRAME) {
jsframe_count--;
it.Next(); // Skip ast id.
- int function_id = it.Next();
+ JSFunction* function = LiteralAt(literal_array, it.Next());
it.Next(); // Skip height.
- JSFunction* function =
- JSFunction::cast(data->LiteralArray()->get(function_id));
functions->Add(function);
} else {
// Skip over operands to advance to the next opcode.
@@ -1015,7 +1144,7 @@
Code* InternalFrame::unchecked_code() const {
const int offset = InternalFrameConstants::kCodeOffset;
Object* code = Memory::Object_at(fp() + offset);
- ASSERT(code != NULL);
+ DCHECK(code != NULL);
return reinterpret_cast<Code*>(code);
}
@@ -1030,9 +1159,9 @@
void JavaScriptFrame::Print(StringStream* accumulator,
PrintMode mode,
int index) const {
- HandleScope scope;
+ DisallowHeapAllocation no_gc;
Object* receiver = this->receiver();
- Object* function = this->function();
+ JSFunction* function = this->function();
accumulator->PrintSecurityTokenIfChanged(function);
PrintIndex(accumulator, mode, index);
@@ -1044,31 +1173,27 @@
// doesn't contain scope info, scope_info will return 0 for the number of
// parameters, stack local variables, context local variables, stack slots,
// or context slots.
- Handle<ScopeInfo> scope_info(ScopeInfo::Empty());
+ SharedFunctionInfo* shared = function->shared();
+ ScopeInfo* scope_info = shared->scope_info();
+ Object* script_obj = shared->script();
+ if (script_obj->IsScript()) {
+ Script* script = Script::cast(script_obj);
+ accumulator->Add(" [");
+ accumulator->PrintName(script->name());
- if (function->IsJSFunction()) {
- Handle<SharedFunctionInfo> shared(JSFunction::cast(function)->shared());
- scope_info = Handle<ScopeInfo>(shared->scope_info());
- Object* script_obj = shared->script();
- if (script_obj->IsScript()) {
- Handle<Script> script(Script::cast(script_obj));
- accumulator->Add(" [");
- accumulator->PrintName(script->name());
-
- Address pc = this->pc();
- if (code != NULL && code->kind() == Code::FUNCTION &&
- pc >= code->instruction_start() && pc < code->instruction_end()) {
- int source_pos = code->SourcePosition(pc);
- int line = GetScriptLineNumberSafe(script, source_pos) + 1;
- accumulator->Add(":%d", line);
- } else {
- int function_start_pos = shared->start_position();
- int line = GetScriptLineNumberSafe(script, function_start_pos) + 1;
- accumulator->Add(":~%d", line);
- }
-
- accumulator->Add("] ");
+ Address pc = this->pc();
+ if (code != NULL && code->kind() == Code::FUNCTION &&
+ pc >= code->instruction_start() && pc < code->instruction_end()) {
+ int source_pos = code->SourcePosition(pc);
+ int line = script->GetLineNumber(source_pos) + 1;
+ accumulator->Add(":%d", line);
+ } else {
+ int function_start_pos = shared->start_position();
+ int line = script->GetLineNumber(function_start_pos) + 1;
+ accumulator->Add(":~%d", line);
}
+
+ accumulator->Add("] ");
}
accumulator->Add("(this=%o", receiver);
@@ -1124,6 +1249,10 @@
if (this->context() != NULL && this->context()->IsContext()) {
context = Context::cast(this->context());
}
+ while (context->IsWithContext()) {
+ context = context->previous();
+ DCHECK(context != NULL);
+ }
// Print heap-allocated local variables.
if (heap_locals_count > 0) {
@@ -1134,8 +1263,9 @@
accumulator->PrintName(scope_info->ContextLocalName(i));
accumulator->Add(" = ");
if (context != NULL) {
- if (i < context->length()) {
- accumulator->Add("%o", context->get(Context::MIN_CONTEXT_SLOTS + i));
+ int index = Context::MIN_CONTEXT_SLOTS + i;
+ if (index < context->length()) {
+ accumulator->Add("%o", context->get(index));
} else {
accumulator->Add(
"// warning: missing context slot - inconsistent frame?");
@@ -1158,10 +1288,12 @@
// Print details about the function.
if (FLAG_max_stack_trace_source_length != 0 && code != NULL) {
- SharedFunctionInfo* shared = JSFunction::cast(function)->shared();
- accumulator->Add("--------- s o u r c e c o d e ---------\n");
- shared->SourceCodePrint(accumulator, FLAG_max_stack_trace_source_length);
- accumulator->Add("\n-----------------------------------------\n");
+ OStringStream os;
+ SharedFunctionInfo* shared = function->shared();
+ os << "--------- s o u r c e c o d e ---------\n"
+ << SourceCodeOf(shared, FLAG_max_stack_trace_source_length)
+ << "\n-----------------------------------------\n";
+ accumulator->Add(os.c_str());
}
accumulator->Add("}\n\n");
@@ -1173,10 +1305,8 @@
int index) const {
int actual = ComputeParametersCount();
int expected = -1;
- Object* function = this->function();
- if (function->IsJSFunction()) {
- expected = JSFunction::cast(function)->shared()->formal_parameter_count();
- }
+ JSFunction* function = this->function();
+ expected = function->shared()->formal_parameter_count();
PrintIndex(accumulator, mode, index);
accumulator->Add("arguments adaptor frame: %d->%d", actual, expected);
@@ -1202,22 +1332,22 @@
void EntryFrame::Iterate(ObjectVisitor* v) const {
StackHandlerIterator it(this, top_handler());
- ASSERT(!it.done());
+ DCHECK(!it.done());
StackHandler* handler = it.handler();
- ASSERT(handler->is_js_entry());
+ DCHECK(handler->is_js_entry());
handler->Iterate(v, LookupCode());
#ifdef DEBUG
// Make sure that the entry frame does not contain more than one
// stack handler.
it.Advance();
- ASSERT(it.done());
+ DCHECK(it.done());
#endif
IteratePc(v, pc_address(), LookupCode());
}
void StandardFrame::IterateExpressions(ObjectVisitor* v) const {
- const int offset = StandardFrameConstants::kContextOffset;
+ const int offset = StandardFrameConstants::kLastObjectOffset;
Object** base = &Memory::Object_at(sp());
Object** limit = &Memory::Object_at(fp() + offset) + 1;
for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
@@ -1249,11 +1379,48 @@
}
+void StubFailureTrampolineFrame::Iterate(ObjectVisitor* v) const {
+ Object** base = &Memory::Object_at(sp());
+ Object** limit = &Memory::Object_at(fp() +
+ kFirstRegisterParameterFrameOffset);
+ v->VisitPointers(base, limit);
+ base = &Memory::Object_at(fp() + StandardFrameConstants::kMarkerOffset);
+ const int offset = StandardFrameConstants::kLastObjectOffset;
+ limit = &Memory::Object_at(fp() + offset) + 1;
+ v->VisitPointers(base, limit);
+ IteratePc(v, pc_address(), LookupCode());
+}
+
+
+Address StubFailureTrampolineFrame::GetCallerStackPointer() const {
+ return fp() + StandardFrameConstants::kCallerSPOffset;
+}
+
+
+Code* StubFailureTrampolineFrame::unchecked_code() const {
+ Code* trampoline;
+ StubFailureTrampolineStub(isolate(), NOT_JS_FUNCTION_STUB_MODE).
+ FindCodeInCache(&trampoline);
+ if (trampoline->contains(pc())) {
+ return trampoline;
+ }
+
+ StubFailureTrampolineStub(isolate(), JS_FUNCTION_STUB_MODE).
+ FindCodeInCache(&trampoline);
+ if (trampoline->contains(pc())) {
+ return trampoline;
+ }
+
+ UNREACHABLE();
+ return NULL;
+}
+
+
// -------------------------------------------------------------------------
JavaScriptFrame* StackFrameLocator::FindJavaScriptFrame(int n) {
- ASSERT(n >= 0);
+ DCHECK(n >= 0);
for (int i = 0; i <= n; i++) {
while (!iterator_.frame()->is_java_script()) iterator_.Advance();
if (i == n) return JavaScriptFrame::cast(iterator_.frame());
@@ -1282,7 +1449,7 @@
#ifdef DEBUG
static bool GcSafeCodeContains(HeapObject* code, Address addr) {
Map* map = GcSafeMapOfCodeSpaceObject(code);
- ASSERT(map == code->GetHeap()->code_map());
+ DCHECK(map == code->GetHeap()->code_map());
Address start = code->address();
Address end = code->address() + code->SizeFromMap(map);
return start <= addr && addr < end;
@@ -1293,7 +1460,7 @@
Code* InnerPointerToCodeCache::GcSafeCastToCode(HeapObject* object,
Address inner_pointer) {
Code* code = reinterpret_cast<Code*>(object);
- ASSERT(code != NULL && GcSafeCodeContains(code, inner_pointer));
+ DCHECK(code != NULL && GcSafeCodeContains(code, inner_pointer));
return code;
}
@@ -1334,7 +1501,7 @@
InnerPointerToCodeCache::InnerPointerToCodeCacheEntry*
InnerPointerToCodeCache::GetCacheEntry(Address inner_pointer) {
isolate_->counters()->pc_to_code()->Increment();
- ASSERT(IsPowerOf2(kInnerPointerToCodeCacheSize));
+ DCHECK(base::bits::IsPowerOfTwo32(kInnerPointerToCodeCacheSize));
uint32_t hash = ComputeIntegerHash(
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(inner_pointer)),
v8::internal::kZeroHashSeed);
@@ -1342,7 +1509,7 @@
InnerPointerToCodeCacheEntry* entry = cache(index);
if (entry->inner_pointer == inner_pointer) {
isolate_->counters()->pc_to_code_cached()->Increment();
- ASSERT(entry->code == GcSafeFindCodeForInnerPointer(inner_pointer));
+ DCHECK(entry->code == GcSafeFindCodeForInnerPointer(inner_pointer));
} else {
// Because this code may be interrupted by a profiling signal that
// also queries the cache, we cannot update inner_pointer before the code
@@ -1358,35 +1525,82 @@
// -------------------------------------------------------------------------
-int NumRegs(RegList reglist) {
- int n = 0;
- while (reglist != 0) {
- n++;
- reglist &= reglist - 1; // clear one bit
- }
- return n;
+
+void StackHandler::Unwind(Isolate* isolate,
+ FixedArray* array,
+ int offset,
+ int previous_handler_offset) const {
+ STATIC_ASSERT(StackHandlerConstants::kSlotCount >= 5);
+ DCHECK_LE(0, offset);
+ DCHECK_GE(array->length(), offset + StackHandlerConstants::kSlotCount);
+ // Unwinding a stack handler into an array chains it in the opposite
+ // direction, re-using the "next" slot as a "previous" link, so that stack
+ // handlers can be later re-wound in the correct order. Decode the "state"
+ // slot into "index" and "kind" and store them separately, using the fp slot.
+ array->set(offset, Smi::FromInt(previous_handler_offset)); // next
+ array->set(offset + 1, *code_address()); // code
+ array->set(offset + 2, Smi::FromInt(static_cast<int>(index()))); // state
+ array->set(offset + 3, *context_address()); // context
+ array->set(offset + 4, Smi::FromInt(static_cast<int>(kind()))); // fp
+
+ *isolate->handler_address() = next()->address();
}
-struct JSCallerSavedCodeData {
- JSCallerSavedCodeData() {
- int i = 0;
- for (int r = 0; r < kNumRegs; r++)
- if ((kJSCallerSaved & (1 << r)) != 0)
- reg_code[i++] = r;
+int StackHandler::Rewind(Isolate* isolate,
+ FixedArray* array,
+ int offset,
+ Address fp) {
+ STATIC_ASSERT(StackHandlerConstants::kSlotCount >= 5);
+ DCHECK_LE(0, offset);
+ DCHECK_GE(array->length(), offset + StackHandlerConstants::kSlotCount);
+ Smi* prev_handler_offset = Smi::cast(array->get(offset));
+ Code* code = Code::cast(array->get(offset + 1));
+ Smi* smi_index = Smi::cast(array->get(offset + 2));
+ Object* context = array->get(offset + 3);
+ Smi* smi_kind = Smi::cast(array->get(offset + 4));
- ASSERT(i == kNumJSCallerSaved);
- }
+ unsigned state = KindField::encode(static_cast<Kind>(smi_kind->value())) |
+ IndexField::encode(static_cast<unsigned>(smi_index->value()));
+
+ Memory::Address_at(address() + StackHandlerConstants::kNextOffset) =
+ *isolate->handler_address();
+ Memory::Object_at(address() + StackHandlerConstants::kCodeOffset) = code;
+ Memory::uintptr_at(address() + StackHandlerConstants::kStateOffset) = state;
+ Memory::Object_at(address() + StackHandlerConstants::kContextOffset) =
+ context;
+ SetFp(address() + StackHandlerConstants::kFPOffset, fp);
+
+ *isolate->handler_address() = address();
+
+ return prev_handler_offset->value();
+}
+
+
+// -------------------------------------------------------------------------
+
+int NumRegs(RegList reglist) { return base::bits::CountPopulation32(reglist); }
+
+
+struct JSCallerSavedCodeData {
int reg_code[kNumJSCallerSaved];
};
+JSCallerSavedCodeData caller_saved_code_data;
-static LazyInstance<JSCallerSavedCodeData>::type caller_saved_code_data =
- LAZY_INSTANCE_INITIALIZER;
+void SetUpJSCallerSavedCodeData() {
+ int i = 0;
+ for (int r = 0; r < kNumRegs; r++)
+ if ((kJSCallerSaved & (1 << r)) != 0)
+ caller_saved_code_data.reg_code[i++] = r;
+
+ DCHECK(i == kNumJSCallerSaved);
+}
+
int JSCallerSavedCode(int n) {
- ASSERT(0 <= n && n < kNumJSCallerSaved);
- return caller_saved_code_data.Get().reg_code[n];
+ DCHECK(0 <= n && n < kNumJSCallerSaved);
+ return caller_saved_code_data.reg_code[n];
}
@@ -1400,11 +1614,11 @@
STACK_FRAME_TYPE_LIST(DEFINE_WRAPPER)
#undef DEFINE_WRAPPER
-static StackFrame* AllocateFrameCopy(StackFrame* frame) {
+static StackFrame* AllocateFrameCopy(StackFrame* frame, Zone* zone) {
#define FRAME_TYPE_CASE(type, field) \
case StackFrame::type: { \
field##_Wrapper* wrapper = \
- new field##_Wrapper(*(reinterpret_cast<field*>(frame))); \
+ new(zone) field##_Wrapper(*(reinterpret_cast<field*>(frame))); \
return &wrapper->frame_; \
}
@@ -1416,11 +1630,12 @@
return NULL;
}
-Vector<StackFrame*> CreateStackMap() {
- ZoneList<StackFrame*> list(10);
- for (StackFrameIterator it; !it.done(); it.Advance()) {
- StackFrame* frame = AllocateFrameCopy(it.frame());
- list.Add(frame);
+
+Vector<StackFrame*> CreateStackMap(Isolate* isolate, Zone* zone) {
+ ZoneList<StackFrame*> list(10, zone);
+ for (StackFrameIterator it(isolate); !it.done(); it.Advance()) {
+ StackFrame* frame = AllocateFrameCopy(it.frame(), zone);
+ list.Add(frame, zone);
}
return list.ToVector();
}