diff options
Diffstat (limited to 'deps/v8/src/frames.cc')
-rw-r--r-- | deps/v8/src/frames.cc | 293 |
1 files changed, 165 insertions, 128 deletions
diff --git a/deps/v8/src/frames.cc b/deps/v8/src/frames.cc index f52b3ce4e4..723db4ae13 100644 --- a/deps/v8/src/frames.cc +++ b/deps/v8/src/frames.cc @@ -321,9 +321,6 @@ bool SafeStackFrameIterator::IsValidExitFrame(Address fp) const { 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; } @@ -385,9 +382,8 @@ 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()); @@ -397,6 +393,9 @@ void StackFrame::IteratePc(ObjectVisitor* v, 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(); + } } } @@ -425,10 +424,27 @@ StackFrame::Type StackFrame::ComputeType(const StackFrameIteratorBase* iterator, // 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; + Code* code_obj = + GetContainingCode(iterator->isolate(), *(state->pc_address)); + switch (code_obj->kind()) { + case Code::FUNCTION: + return JAVA_SCRIPT; + + case Code::HANDLER: +#ifdef DEBUG + if (!code_obj->is_hydrogen_stub()) { + // There's currently no support for non-hydrogen stub handlers. If + // you this, you'll have to implement it yourself. + UNREACHABLE(); + } +#endif + case Code::OPTIMIZED_FUNCTION: + return OPTIMIZED; + + default: + UNREACHABLE(); + return JAVA_SCRIPT; + } } return static_cast<StackFrame::Type>(Smi::cast(marker)->value()); } @@ -506,7 +522,7 @@ void ExitFrame::ComputeCallerState(State* state) const { 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); } @@ -521,11 +537,8 @@ void ExitFrame::SetCallerFp(Address caller_fp) { 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()); - } } @@ -553,8 +566,11 @@ void ExitFrame::FillState(Address fp, Address sp, State* state) { 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; } @@ -663,7 +679,7 @@ void StandardFrame::IterateCompiledFrame(ObjectVisitor* v) const { } // 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. @@ -714,9 +730,24 @@ bool JavaScriptFrame::IsConstructor() const { } +Object* JavaScriptFrame::GetOriginalConstructor() const { + Address fp = caller_fp(); + if (has_adapted_arguments()) { + // Skip the arguments adaptor frame and look at the real caller. + fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset); + } + DCHECK(IsConstructFrame(fp)); + STATIC_ASSERT(ConstructFrameConstants::kOriginalConstructorOffset == + StandardFrameConstants::kExpressionsOffset - 2 * kPointerSize); + return GetExpression(fp, 2); +} + + 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(); @@ -761,12 +792,13 @@ void JavaScriptFrame::Summarize(List<FrameSummary>* functions) { } -int JavaScriptFrame::LookupExceptionHandlerInTable(int* stack_slots) { +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); + return table->LookupRange(pc_offset, stack_slots, prediction); } @@ -863,85 +895,72 @@ void FrameSummary::Print() { } -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); + DCHECK_EQ(Translation::BEGIN, 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) { + while (jsframe_count != 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()); + 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. + 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 @@ -949,15 +968,14 @@ void OptimizedFrame::Summarize(List<FrameSummary>* frames) { receiver = isolate()->heap()->undefined_value(); } - Code* code = function->shared()->code(); - DeoptimizationOutputData* output_data = + Code* const code = shared_info->code(); + DeoptimizationOutputData* const output_data = DeoptimizationOutputData::cast(code->deoptimization_data()); - unsigned entry = Deoptimizer::GetOutputInfo(output_data, - ast_id, - function->shared()); - unsigned pc_offset = + unsigned const entry = + Deoptimizer::GetOutputInfo(output_data, ast_id, shared_info); + unsigned const pc_offset = FullCodeGenerator::PcField::decode(entry) + Code::kHeaderSize; - DCHECK(pc_offset > 0); + DCHECK_NE(0U, pc_offset); FrameSummary summary(receiver, function, code, pc_offset, is_constructor); frames->Add(summary); @@ -976,13 +994,14 @@ void OptimizedFrame::Summarize(List<FrameSummary>* frames) { } -int OptimizedFrame::LookupExceptionHandlerInTable(int* stack_slots) { +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); + return table->LookupReturn(pc_offset, prediction); } @@ -1011,68 +1030,73 @@ DeoptimizationInputData* OptimizedFrame::GetDeoptimizationData( } -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) { 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()); + // Skip over operands to advance to the next opcode. + it.Skip(Translation::NumberOfOperandsFor(opcode)); if (opcode == Translation::JS_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)); } } } +Object* OptimizedFrame::StackSlotAt(int index) const { + // Positive index means the value is spilled to the locals + // area. Negative means it is stored in the incoming parameter + // area. + if (index >= 0) return GetExpression(index); + + // 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 const parameter_count = ComputeParametersCount(); + int const parameter_index = index + parameter_count; + return (parameter_index == -1) ? receiver() : GetParameter(parameter_index); +} + + int ArgumentsAdaptorFrame::GetNumberOfIncomingArguments() const { return Smi::cast(GetExpression(0))->value(); } @@ -1111,6 +1135,24 @@ void StackFrame::PrintIndex(StringStream* accumulator, } +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 { @@ -1148,7 +1190,7 @@ void JavaScriptFrame::Print(StringStream* accumulator, accumulator->Add(":~%d", line); } - accumulator->Add("] "); + accumulator->Add("] [pc=%p] ", pc); } accumulator->Add("(this=%o", receiver); @@ -1173,7 +1215,9 @@ void JavaScriptFrame::Print(StringStream* accumulator, 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"); @@ -1240,15 +1284,7 @@ void JavaScriptFrame::Print(StringStream* accumulator, 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"); } @@ -1285,7 +1321,7 @@ void ArgumentsAdaptorFrame::Print(StringStream* accumulator, void EntryFrame::Iterate(ObjectVisitor* v) const { - IteratePc(v, pc_address(), LookupCode()); + IteratePc(v, pc_address(), constant_pool_address(), LookupCode()); } @@ -1299,7 +1335,7 @@ void StandardFrame::IterateExpressions(ObjectVisitor* v) const { void JavaScriptFrame::Iterate(ObjectVisitor* v) const { IterateExpressions(v); - IteratePc(v, pc_address(), LookupCode()); + IteratePc(v, pc_address(), constant_pool_address(), LookupCode()); } @@ -1307,7 +1343,7 @@ void InternalFrame::Iterate(ObjectVisitor* v) const { // 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()); } @@ -1320,7 +1356,7 @@ void StubFailureTrampolineFrame::Iterate(ObjectVisitor* v) const { 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()); } @@ -1458,7 +1494,7 @@ InnerPointerToCodeCache::InnerPointerToCodeCacheEntry* // ------------------------------------------------------------------------- -int NumRegs(RegList reglist) { return base::bits::CountPopulation32(reglist); } +int NumRegs(RegList reglist) { return base::bits::CountPopulation(reglist); } struct JSCallerSavedCodeData { @@ -1520,4 +1556,5 @@ Vector<StackFrame*> CreateStackMap(Isolate* isolate, Zone* zone) { } -} } // namespace v8::internal +} // namespace internal +} // namespace v8 |