Upgrade V8 to version 4.9.385.28
https://chromium.googlesource.com/v8/v8/+/4.9.385.28
FPIIM-449
Change-Id: I4b2e74289d4bf3667f2f3dc8aa2e541f63e26eb4
diff --git a/src/frames.cc b/src/frames.cc
index 0ba8ea0..d60ab29 100644
--- a/src/frames.cc
+++ b/src/frames.cc
@@ -6,23 +6,20 @@
#include <sstream>
-#include "src/v8.h"
-
-#include "src/ast.h"
+#include "src/ast/ast.h"
+#include "src/ast/scopeinfo.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/full-codegen/full-codegen.h"
+#include "src/register-configuration.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 {
-
ReturnAddressLocationResolver
StackFrame::return_address_location_resolver_ = NULL;
@@ -188,7 +185,7 @@
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());
+ Script::TYPE_NATIVE != Script::cast(script)->type());
}
@@ -321,9 +318,6 @@
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;
}
@@ -340,11 +334,8 @@
// 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;
- }
+ frame_->state_.pc_address =
+ external_callback_scope_->callback_entrypoint_address();
external_callback_scope_ = external_callback_scope_->previous();
DCHECK(external_callback_scope_ == NULL ||
external_callback_scope_->scope_address() > frame_->fp());
@@ -380,20 +371,13 @@
}
-bool StackFrame::HasHandler() const {
- StackHandlerIterator it(this, top_handler());
- return !it.done();
-}
-
-
#ifdef DEBUG
static bool GcSafeCodeContains(HeapObject* object, Address addr);
#endif
-void StackFrame::IteratePc(ObjectVisitor* v,
- Address* pc_address,
- Code* holder) {
+void StackFrame::IteratePc(ObjectVisitor* v, Address* pc_address,
+ Address* constant_pool_address, Code* holder) {
Address pc = *pc_address;
DCHECK(GcSafeCodeContains(holder, pc));
unsigned pc_offset = static_cast<unsigned>(pc - holder->instruction_start());
@@ -403,6 +387,9 @@
holder = reinterpret_cast<Code*>(code);
pc = holder->instruction_start() + pc_offset;
*pc_address = pc;
+ if (FLAG_enable_embedded_constant_pool && constant_pool_address) {
+ *constant_pool_address = holder->constant_pool();
+ }
}
}
@@ -417,25 +404,67 @@
StackFrame::Type StackFrame::ComputeType(const StackFrameIteratorBase* iterator,
State* state) {
DCHECK(state->fp != NULL);
- if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) {
- return ARGUMENTS_ADAPTOR;
+
+ if (!iterator->can_access_heap_objects_) {
+ // TODO(titzer): "can_access_heap_objects" is kind of bogus. It really
+ // means that we are being called from the profiler, which can interrupt
+ // the VM with a signal at any arbitrary instruction, with essentially
+ // anything on the stack. So basically none of these checks are 100%
+ // reliable.
+ if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) {
+ // An adapter frame has a special SMI constant for the context and
+ // is not distinguished through the marker.
+ return ARGUMENTS_ADAPTOR;
+ }
+ Object* marker =
+ Memory::Object_at(state->fp + StandardFrameConstants::kMarkerOffset);
+ if (marker->IsSmi()) {
+ return static_cast<StackFrame::Type>(Smi::cast(marker)->value());
+ } else {
+ return JAVA_SCRIPT;
+ }
}
- // The marker and function offsets overlap. If the marker isn't a
- // smi then the frame is a JavaScript frame -- and the marker is
- // really the function.
- const int offset = StandardFrameConstants::kMarkerOffset;
- Object* marker = Memory::Object_at(state->fp + offset);
- if (!marker->IsSmi()) {
- // If we're using a "safe" stack iterator, we treat optimized
- // 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 (!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;
+
+ // Look up the code object to figure out the type of the stack frame.
+ Code* code_obj = GetContainingCode(iterator->isolate(), *(state->pc_address));
+
+ Object* marker =
+ Memory::Object_at(state->fp + StandardFrameConstants::kMarkerOffset);
+ if (code_obj != nullptr) {
+ switch (code_obj->kind()) {
+ case Code::FUNCTION:
+ return JAVA_SCRIPT;
+ case Code::OPTIMIZED_FUNCTION:
+ return OPTIMIZED;
+ case Code::WASM_FUNCTION:
+ return STUB;
+ case Code::BUILTIN:
+ if (!marker->IsSmi()) {
+ if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) {
+ // An adapter frame has a special SMI constant for the context and
+ // is not distinguished through the marker.
+ return ARGUMENTS_ADAPTOR;
+ } else {
+ // The interpreter entry trampoline has a non-SMI marker.
+ DCHECK(code_obj->is_interpreter_entry_trampoline());
+ return INTERPRETED;
+ }
+ }
+ break; // Marker encodes the frame type.
+ case Code::HANDLER:
+ if (!marker->IsSmi()) {
+ // Only hydrogen code stub handlers can have a non-SMI marker.
+ DCHECK(code_obj->is_hydrogen_stub());
+ return OPTIMIZED;
+ }
+ break; // Marker encodes the frame type.
+ default:
+ break; // Marker encodes the frame type.
+ }
}
+
+ // Didn't find a code object, or the code kind wasn't specific enough.
+ // The marker should encode the frame type.
return static_cast<StackFrame::Type>(Smi::cast(marker)->value());
}
@@ -512,7 +541,7 @@
state->fp = Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset);
state->pc_address = ResolveReturnAddressLocation(
reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset));
- if (FLAG_enable_ool_constant_pool) {
+ if (FLAG_enable_embedded_constant_pool) {
state->constant_pool_address = reinterpret_cast<Address*>(
fp() + ExitFrameConstants::kConstantPoolOffset);
}
@@ -527,11 +556,8 @@
void ExitFrame::Iterate(ObjectVisitor* v) const {
// The arguments are traversed as part of the expression stack of
// the calling frame.
- IteratePc(v, pc_address(), LookupCode());
+ IteratePc(v, pc_address(), constant_pool_address(), LookupCode());
v->VisitPointer(&code_slot());
- if (FLAG_enable_ool_constant_pool) {
- v->VisitPointer(&constant_pool_slot());
- }
}
@@ -559,8 +585,11 @@
state->fp = fp;
state->pc_address = ResolveReturnAddressLocation(
reinterpret_cast<Address*>(sp - 1 * kPCOnStackSize));
- state->constant_pool_address =
- reinterpret_cast<Address*>(fp + ExitFrameConstants::kConstantPoolOffset);
+ // The constant pool recorded in the exit frame is not associated
+ // with the pc in this state (the return address into a C entry
+ // stub). ComputeCallerState will retrieve the constant pool
+ // together with the associated caller pc.
+ state->constant_pool_address = NULL;
}
@@ -608,15 +637,6 @@
}
-bool StandardFrame::IsExpressionInsideHandler(int n) const {
- Address address = GetExpressionAddress(n);
- for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
- if (it.handler()->includes(address)) return true;
- }
- return false;
-}
-
-
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.
@@ -645,7 +665,9 @@
if (safepoint_entry.has_doubles()) {
// Number of doubles not known at snapshot time.
DCHECK(!isolate()->serializer_enabled());
- parameters_base += DoubleRegister::NumAllocatableRegisters() *
+ parameters_base +=
+ RegisterConfiguration::ArchDefault(RegisterConfiguration::CRANKSHAFT)
+ ->num_allocatable_double_registers() *
kDoubleSize / kPointerSize;
}
@@ -678,7 +700,7 @@
}
// Visit the return address in the callee and incoming arguments.
- IteratePc(v, pc_address(), code);
+ IteratePc(v, pc_address(), constant_pool_address(), code);
// Visit the context in stub frame and JavaScript frame.
// Visit the function in JavaScript frame.
@@ -710,12 +732,6 @@
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);
}
@@ -735,9 +751,18 @@
}
+bool JavaScriptFrame::HasInlinedFrames() const {
+ List<JSFunction*> functions(1);
+ GetFunctions(&functions);
+ return functions.length() > 1;
+}
+
+
int JavaScriptFrame::GetArgumentsLength() const {
// If there is an arguments adaptor frame get the arguments length from it.
if (has_adapted_arguments()) {
+ STATIC_ASSERT(ArgumentsAdaptorFrameConstants::kLengthOffset ==
+ StandardFrameConstants::kExpressionsOffset);
return Smi::cast(GetExpression(caller_fp(), 0))->value();
} else {
return GetNumberOfIncomingArguments();
@@ -754,7 +779,7 @@
DCHECK(can_access_heap_objects() &&
isolate()->heap()->gc_state() == Heap::NOT_IN_GC);
- return function()->shared()->formal_parameter_count();
+ return function()->shared()->internal_formal_parameter_count();
}
@@ -763,7 +788,7 @@
}
-void JavaScriptFrame::GetFunctions(List<JSFunction*>* functions) {
+void JavaScriptFrame::GetFunctions(List<JSFunction*>* functions) const {
DCHECK(functions->length() == 0);
functions->Add(function());
}
@@ -782,6 +807,16 @@
}
+int JavaScriptFrame::LookupExceptionHandlerInTable(
+ int* stack_slots, HandlerTable::CatchPrediction* prediction) {
+ Code* code = LookupCode();
+ DCHECK(!code->is_optimized_code());
+ HandlerTable* table = HandlerTable::cast(code->handler_table());
+ int pc_offset = static_cast<int>(pc() - code->entry());
+ return table->LookupRange(pc_offset, stack_slots, prediction);
+}
+
+
void JavaScriptFrame::PrintFunctionAndOffset(JSFunction* function, Code* code,
Address pc, FILE* file,
bool print_line_number) {
@@ -799,7 +834,7 @@
Object* script_name_raw = script->name();
if (script_name_raw->IsString()) {
String* script_name = String::cast(script->name());
- SmartArrayPointer<char> c_script_name =
+ base::SmartArrayPointer<char> c_script_name =
script_name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
PrintF(file, " at %s:%d", c_script_name.get(), line);
} else {
@@ -843,72 +878,34 @@
}
-void JavaScriptFrame::SaveOperandStack(FixedArray* store,
- int* stack_handler_index) const {
+void JavaScriptFrame::SaveOperandStack(FixedArray* store) 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--) {
+ for (int i = 0; i < operands_count; i++) {
store->set(i, GetOperand(i));
}
}
-void JavaScriptFrame::RestoreOperandStack(FixedArray* store,
- int stack_handler_index) {
+void JavaScriptFrame::RestoreOperandStack(FixedArray* store) {
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++) {
+ for (int i = 0; i < operands_count; i++) {
DCHECK_EQ(GetOperand(i), isolate()->heap()->the_hole_value());
Memory::Object_at(GetOperandSlot(i)) = store->get(i);
}
}
+FrameSummary::FrameSummary(Object* receiver, JSFunction* function, Code* code,
+ int offset, bool is_constructor)
+ : receiver_(receiver, function->GetIsolate()),
+ function_(function),
+ code_(code),
+ offset_(offset),
+ is_constructor_(is_constructor) {}
+
+
void FrameSummary::Print() {
PrintF("receiver: ");
receiver_->ShortPrint();
@@ -922,85 +919,74 @@
}
-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) {
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) {
+ if (LookupCode()->is_turbofanned() && function()->shared()->asm_function() &&
+ !FLAG_turbo_asm_deoptimization) {
return JavaScriptFrame::Summarize(frames);
}
+ DisallowHeapAllocation no_gc;
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.
- DCHECK(deopt_index != Safepoint::kNoDeoptimizationIndex);
+ DeoptimizationInputData* const data = GetDeoptimizationData(&deopt_index);
+ FixedArray* const literal_array = data->LiteralArray();
TranslationIterator it(data->TranslationByteArray(),
data->TranslationIndex(deopt_index)->value());
- Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
- DCHECK(opcode == Translation::BEGIN);
+ Translation::Opcode frame_opcode =
+ static_cast<Translation::Opcode>(it.Next());
+ DCHECK_EQ(Translation::BEGIN, frame_opcode);
it.Next(); // Drop frame count.
int jsframe_count = it.Next();
// We create the summary in reverse order because the frames
// in the deoptimization translation are ordered bottom-to-top.
bool is_constructor = IsConstructor();
- int i = jsframe_count;
- while (i > 0) {
- opcode = static_cast<Translation::Opcode>(it.Next());
- if (opcode == Translation::JS_FRAME) {
- i--;
- BailoutId ast_id = BailoutId(it.Next());
- JSFunction* function = LiteralAt(literal_array, it.Next());
+ while (jsframe_count != 0) {
+ frame_opcode = static_cast<Translation::Opcode>(it.Next());
+ if (frame_opcode == Translation::JS_FRAME ||
+ frame_opcode == Translation::INTERPRETED_FRAME) {
+ jsframe_count--;
+ BailoutId const ast_id = BailoutId(it.Next());
+ SharedFunctionInfo* const shared_info =
+ SharedFunctionInfo::cast(literal_array->get(it.Next()));
it.Next(); // Skip height.
- // The translation commands are ordered and the receiver is always
- // at the first position.
+ // The translation commands are ordered and the function is always
+ // at the first position, and the receiver is next.
+ Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
+
+ // Get the correct function in the optimized frame.
+ JSFunction* function;
+ if (opcode == Translation::LITERAL) {
+ function = JSFunction::cast(literal_array->get(it.Next()));
+ } else if (opcode == Translation::STACK_SLOT) {
+ function = JSFunction::cast(StackSlotAt(it.Next()));
+ } else {
+ CHECK_EQ(Translation::JS_FRAME_FUNCTION, opcode);
+ function = this->function();
+ }
+ DCHECK_EQ(shared_info, function->shared());
+
// 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());
- int index = it.Next();
// Get the correct receiver in the optimized frame.
- Object* receiver = NULL;
+ Object* receiver;
if (opcode == Translation::LITERAL) {
- receiver = data->LiteralArray()->get(index);
+ receiver = literal_array->get(it.Next());
} 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.
- if (index >= 0) {
- receiver = GetExpression(index);
- } else {
- // Index -1 overlaps with last parameter, -n with the first parameter,
- // (-n - 1) with the receiver with n being the number of parameters
- // of the outermost, optimized frame.
- int parameter_count = ComputeParametersCount();
- int parameter_index = index + parameter_count;
- receiver = (parameter_index == -1)
- ? this->receiver()
- : this->GetParameter(parameter_index);
- }
+ receiver = StackSlotAt(it.Next());
+ } else if (opcode == Translation::JS_FRAME_FUNCTION) {
+ receiver = this->function();
} else {
// The receiver is not in a stack slot nor in a literal. We give up.
+ it.Skip(Translation::NumberOfOperandsFor(opcode));
// 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
@@ -1008,35 +994,53 @@
receiver = isolate()->heap()->undefined_value();
}
- Code* code = function->shared()->code();
- DeoptimizationOutputData* output_data =
- DeoptimizationOutputData::cast(code->deoptimization_data());
- unsigned entry = Deoptimizer::GetOutputInfo(output_data,
- ast_id,
- function->shared());
- unsigned pc_offset =
- FullCodeGenerator::PcField::decode(entry) + Code::kHeaderSize;
- DCHECK(pc_offset > 0);
+ Code* const code = shared_info->code();
+ unsigned pc_offset;
+ if (frame_opcode == Translation::JS_FRAME) {
+ DeoptimizationOutputData* const output_data =
+ DeoptimizationOutputData::cast(code->deoptimization_data());
+ unsigned const entry =
+ Deoptimizer::GetOutputInfo(output_data, ast_id, shared_info);
+ pc_offset =
+ FullCodeGenerator::PcField::decode(entry) + Code::kHeaderSize;
+ DCHECK_NE(0U, pc_offset);
+ } else {
+ // TODO(rmcilroy): Modify FrameSummary to enable us to summarize
+ // based on the BytecodeArray and bytecode offset.
+ DCHECK_EQ(frame_opcode, Translation::INTERPRETED_FRAME);
+ pc_offset = 0;
+ }
FrameSummary summary(receiver, function, code, pc_offset, is_constructor);
frames->Add(summary);
is_constructor = false;
- } else if (opcode == Translation::CONSTRUCT_STUB_FRAME) {
+ } else if (frame_opcode == Translation::CONSTRUCT_STUB_FRAME) {
// The next encountered JS_FRAME will be marked as a constructor call.
- it.Skip(Translation::NumberOfOperandsFor(opcode));
+ it.Skip(Translation::NumberOfOperandsFor(frame_opcode));
DCHECK(!is_constructor);
is_constructor = true;
} else {
// Skip over operands to advance to the next opcode.
- it.Skip(Translation::NumberOfOperandsFor(opcode));
+ it.Skip(Translation::NumberOfOperandsFor(frame_opcode));
}
}
DCHECK(!is_constructor);
}
+int OptimizedFrame::LookupExceptionHandlerInTable(
+ int* stack_slots, HandlerTable::CatchPrediction* prediction) {
+ Code* code = LookupCode();
+ DCHECK(code->is_optimized_code());
+ HandlerTable* table = HandlerTable::cast(code->handler_table());
+ int pc_offset = static_cast<int>(pc() - code->entry());
+ *stack_slots = code->stack_slots();
+ return table->LookupReturn(pc_offset, prediction);
+}
+
+
DeoptimizationInputData* OptimizedFrame::GetDeoptimizationData(
- int* deopt_index) {
+ int* deopt_index) const {
DCHECK(is_optimized());
JSFunction* opt_function = function();
@@ -1060,68 +1064,70 @@
}
-int OptimizedFrame::GetInlineCount() {
- 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);
-
- TranslationIterator it(data->TranslationByteArray(),
- data->TranslationIndex(deopt_index)->value());
- Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
- DCHECK(opcode == Translation::BEGIN);
- USE(opcode);
- it.Next(); // Drop frame count.
- int jsframe_count = it.Next();
- return jsframe_count;
-}
-
-
-void OptimizedFrame::GetFunctions(List<JSFunction*>* functions) {
+void OptimizedFrame::GetFunctions(List<JSFunction*>* functions) const {
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) {
+ if (LookupCode()->is_turbofanned() && function()->shared()->asm_function() &&
+ !FLAG_turbo_asm_deoptimization) {
return JavaScriptFrame::GetFunctions(functions);
}
+ DisallowHeapAllocation no_gc;
int deopt_index = Safepoint::kNoDeoptimizationIndex;
- DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index);
- FixedArray* literal_array = data->LiteralArray();
+ DeoptimizationInputData* const data = GetDeoptimizationData(&deopt_index);
+ FixedArray* const literal_array = data->LiteralArray();
TranslationIterator it(data->TranslationByteArray(),
data->TranslationIndex(deopt_index)->value());
Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
- DCHECK(opcode == Translation::BEGIN);
- it.Next(); // Drop frame count.
+ DCHECK_EQ(Translation::BEGIN, opcode);
+ it.Next(); // Skip frame count.
int jsframe_count = it.Next();
// We insert the frames in reverse order because the frames
// in the deoptimization translation are ordered bottom-to-top.
- while (jsframe_count > 0) {
+ while (jsframe_count != 0) {
opcode = static_cast<Translation::Opcode>(it.Next());
- if (opcode == Translation::JS_FRAME) {
+ // Skip over operands to advance to the next opcode.
+ it.Skip(Translation::NumberOfOperandsFor(opcode));
+ if (opcode == Translation::JS_FRAME ||
+ opcode == Translation::INTERPRETED_FRAME) {
jsframe_count--;
- it.Next(); // Skip ast id.
- JSFunction* function = LiteralAt(literal_array, it.Next());
- it.Next(); // Skip height.
- functions->Add(function);
- } else {
- // Skip over operands to advance to the next opcode.
- it.Skip(Translation::NumberOfOperandsFor(opcode));
+
+ // The translation commands are ordered and the function is always at the
+ // first position.
+ opcode = static_cast<Translation::Opcode>(it.Next());
+
+ // Get the correct function in the optimized frame.
+ Object* function;
+ if (opcode == Translation::LITERAL) {
+ function = literal_array->get(it.Next());
+ } else if (opcode == Translation::STACK_SLOT) {
+ function = StackSlotAt(it.Next());
+ } else {
+ CHECK_EQ(Translation::JS_FRAME_FUNCTION, opcode);
+ function = this->function();
+ }
+ functions->Add(JSFunction::cast(function));
}
}
}
+int OptimizedFrame::StackSlotOffsetRelativeToFp(int slot_index) {
+ return StandardFrameConstants::kCallerSPOffset -
+ ((slot_index + 1) * kPointerSize);
+}
+
+
+Object* OptimizedFrame::StackSlotAt(int index) const {
+ return Memory::Object_at(fp() + StackSlotOffsetRelativeToFp(index));
+}
+
+
int ArgumentsAdaptorFrame::GetNumberOfIncomingArguments() const {
return Smi::cast(GetExpression(0))->value();
}
@@ -1160,6 +1166,24 @@
}
+namespace {
+
+
+void PrintFunctionSource(StringStream* accumulator, SharedFunctionInfo* shared,
+ Code* code) {
+ if (FLAG_max_stack_trace_source_length != 0 && code != NULL) {
+ std::ostringstream os;
+ 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.str().c_str());
+ }
+}
+
+
+} // namespace
+
+
void JavaScriptFrame::Print(StringStream* accumulator,
PrintMode mode,
int index) const {
@@ -1197,7 +1221,7 @@
accumulator->Add(":~%d", line);
}
- accumulator->Add("] ");
+ accumulator->Add("] [pc=%p] ", pc);
}
accumulator->Add("(this=%o", receiver);
@@ -1222,7 +1246,9 @@
return;
}
if (is_optimized()) {
- accumulator->Add(" {\n// optimized frame\n}\n");
+ accumulator->Add(" {\n// optimized frame\n");
+ PrintFunctionSource(accumulator, shared, code);
+ accumulator->Add("}\n");
return;
}
accumulator->Add(" {\n");
@@ -1286,19 +1312,10 @@
accumulator->Add(" // expression stack (top to bottom)\n");
}
for (int i = expressions_count - 1; i >= expressions_start; i--) {
- if (IsExpressionInsideHandler(i)) continue;
accumulator->Add(" [%02d] : %o\n", i, GetExpression(i));
}
- // Print details about the function.
- if (FLAG_max_stack_trace_source_length != 0 && code != NULL) {
- std::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.str().c_str());
- }
+ PrintFunctionSource(accumulator, shared, code);
accumulator->Add("}\n\n");
}
@@ -1310,7 +1327,7 @@
int actual = ComputeParametersCount();
int expected = -1;
JSFunction* function = this->function();
- expected = function->shared()->formal_parameter_count();
+ expected = function->shared()->internal_formal_parameter_count();
PrintIndex(accumulator, mode, index);
accumulator->Add("arguments adaptor frame: %d->%d", actual, expected);
@@ -1335,18 +1352,7 @@
void EntryFrame::Iterate(ObjectVisitor* v) const {
- StackHandlerIterator it(this, top_handler());
- DCHECK(!it.done());
- StackHandler* handler = it.handler();
- 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();
- DCHECK(it.done());
-#endif
- IteratePc(v, pc_address(), LookupCode());
+ IteratePc(v, pc_address(), constant_pool_address(), LookupCode());
}
@@ -1354,24 +1360,13 @@
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()) {
- StackHandler* handler = it.handler();
- // Traverse pointers down to - but not including - the next
- // handler in the handler chain. Update the base to skip the
- // handler and allow the handler to traverse its own pointers.
- const Address address = handler->address();
- v->VisitPointers(base, reinterpret_cast<Object**>(address));
- base = reinterpret_cast<Object**>(address + StackHandlerConstants::kSize);
- // Traverse the pointers in the handler itself.
- handler->Iterate(v, LookupCode());
- }
v->VisitPointers(base, limit);
}
void JavaScriptFrame::Iterate(ObjectVisitor* v) const {
IterateExpressions(v);
- IteratePc(v, pc_address(), LookupCode());
+ IteratePc(v, pc_address(), constant_pool_address(), LookupCode());
}
@@ -1379,7 +1374,7 @@
// Internal frames only have object pointers on the expression stack
// as they never have any arguments.
IterateExpressions(v);
- IteratePc(v, pc_address(), LookupCode());
+ IteratePc(v, pc_address(), constant_pool_address(), LookupCode());
}
@@ -1392,7 +1387,7 @@
const int offset = StandardFrameConstants::kLastObjectOffset;
limit = &Memory::Object_at(fp() + offset) + 1;
v->VisitPointers(base, limit);
- IteratePc(v, pc_address(), LookupCode());
+ IteratePc(v, pc_address(), constant_pool_address(), LookupCode());
}
@@ -1472,6 +1467,11 @@
Code* InnerPointerToCodeCache::GcSafeFindCodeForInnerPointer(
Address inner_pointer) {
Heap* heap = isolate_->heap();
+ if (!heap->code_space()->Contains(inner_pointer) &&
+ !heap->lo_space()->Contains(inner_pointer)) {
+ return nullptr;
+ }
+
// Check if the inner pointer points into a large object chunk.
LargePage* large_page = heap->lo_space()->FindPage(inner_pointer);
if (large_page != NULL) {
@@ -1482,6 +1482,9 @@
// after the inner pointer.
Page* page = Page::FromAddress(inner_pointer);
+ DCHECK_EQ(page->owner(), heap->code_space());
+ heap->mark_compact_collector()->SweepOrWaitUntilSweepingCompleted(page);
+
Address addr = page->skip_list()->StartFor(inner_pointer);
Address top = heap->code_space()->top();
@@ -1506,9 +1509,8 @@
InnerPointerToCodeCache::GetCacheEntry(Address inner_pointer) {
isolate_->counters()->pc_to_code()->Increment();
DCHECK(base::bits::IsPowerOfTwo32(kInnerPointerToCodeCacheSize));
- uint32_t hash = ComputeIntegerHash(
- static_cast<uint32_t>(reinterpret_cast<uintptr_t>(inner_pointer)),
- v8::internal::kZeroHashSeed);
+ uint32_t hash = ComputeIntegerHash(ObjectAddressForHashing(inner_pointer),
+ v8::internal::kZeroHashSeed);
uint32_t index = hash & (kInnerPointerToCodeCacheSize - 1);
InnerPointerToCodeCacheEntry* entry = cache(index);
if (entry->inner_pointer == inner_pointer) {
@@ -1530,60 +1532,7 @@
// -------------------------------------------------------------------------
-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();
-}
-
-
-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));
-
- 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); }
+int NumRegs(RegList reglist) { return base::bits::CountPopulation(reglist); }
struct JSCallerSavedCodeData {
@@ -1645,4 +1594,5 @@
}
-} } // namespace v8::internal
+} // namespace internal
+} // namespace v8