| Index: src/runtime.cc
|
| diff --git a/src/runtime.cc b/src/runtime.cc
|
| index e0785793fec68df1a6581f221ba6495202c41315..3c40896f742cf8bd23de10f79f6e5f9ad73fabc0 100644
|
| --- a/src/runtime.cc
|
| +++ b/src/runtime.cc
|
| @@ -1,4 +1,4 @@
|
| -// Copyright 2006-2009 the V8 project authors. All rights reserved.
|
| +// Copyright 2010 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:
|
| @@ -33,16 +33,19 @@
|
| #include "api.h"
|
| #include "arguments.h"
|
| #include "codegen.h"
|
| +#include "compilation-cache.h"
|
| #include "compiler.h"
|
| #include "cpu.h"
|
| #include "dateparser-inl.h"
|
| #include "debug.h"
|
| +#include "deoptimizer.h"
|
| #include "execution.h"
|
| #include "jsregexp.h"
|
| #include "liveedit.h"
|
| #include "parser.h"
|
| #include "platform.h"
|
| #include "runtime.h"
|
| +#include "runtime-profiler.h"
|
| #include "scopeinfo.h"
|
| #include "smart-pointer.h"
|
| #include "stub-cache.h"
|
| @@ -641,6 +644,23 @@ static MaybeObject* Runtime_SetHiddenPrototype(RUNTIME_CALLING_CONVENTION) {
|
| }
|
|
|
|
|
| +// Sets the magic number that identifies a function as one of the special
|
| +// math functions that can be inlined.
|
| +static MaybeObject* Runtime_SetMathFunctionId(RUNTIME_CALLING_CONVENTION) {
|
| + RUNTIME_GET_ISOLATE;
|
| + NoHandleAllocation ha;
|
| + ASSERT(args.length() == 2);
|
| + CONVERT_CHECKED(JSFunction, function, args[0]);
|
| + CONVERT_CHECKED(Smi, id, args[1]);
|
| + RUNTIME_ASSERT(id->value() >= 0);
|
| + RUNTIME_ASSERT(id->value() < SharedFunctionInfo::max_math_id_number());
|
| +
|
| + function->shared()->set_math_function_id(id->value());
|
| +
|
| + return isolate->heap()->undefined_value();
|
| +}
|
| +
|
| +
|
| static MaybeObject* Runtime_IsConstructCall(RUNTIME_CALLING_CONVENTION) {
|
| RUNTIME_GET_ISOLATE;
|
| NoHandleAllocation ha;
|
| @@ -1715,14 +1735,13 @@ static MaybeObject* Runtime_FunctionGetPositionForOffset(
|
| RUNTIME_GET_ISOLATE;
|
| ASSERT(args.length() == 2);
|
|
|
| - CONVERT_CHECKED(JSFunction, fun, args[0]);
|
| + CONVERT_CHECKED(Code, code, args[0]);
|
| CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
|
|
|
| - Code* code = fun->code();
|
| RUNTIME_ASSERT(0 <= offset && offset < code->Size());
|
|
|
| Address pc = code->address() + offset;
|
| - return Smi::FromInt(fun->code()->SourcePosition(pc));
|
| + return Smi::FromInt(code->SourcePosition(pc));
|
| }
|
|
|
|
|
| @@ -1807,10 +1826,14 @@ static MaybeObject* Runtime_SetCode(RUNTIME_CALLING_CONVENTION) {
|
| if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
|
| return Failure::Exception();
|
| }
|
| + // Since we don't store the source for this we should never
|
| + // optimize this.
|
| + shared->code()->set_optimizable(false);
|
| +
|
| // Set the code, scope info, formal parameter count,
|
| // and the length of the target function.
|
| target->shared()->set_code(shared->code());
|
| - target->set_code(shared->code());
|
| + target->ReplaceCode(shared->code());
|
| target->shared()->set_scope_info(shared->scope_info());
|
| target->shared()->set_length(shared->length());
|
| target->shared()->set_formal_parameter_count(
|
| @@ -1840,6 +1863,7 @@ static MaybeObject* Runtime_SetCode(RUNTIME_CALLING_CONVENTION) {
|
| // It's okay to skip the write barrier here because the literals
|
| // are guaranteed to be in old space.
|
| target->set_literals(*literals, SKIP_WRITE_BARRIER);
|
| + target->set_next_function_link(isolate->heap()->undefined_value());
|
| }
|
|
|
| target->set_context(*context);
|
| @@ -5576,6 +5600,14 @@ static MaybeObject* Runtime_NumberToSmi(RUNTIME_CALLING_CONVENTION) {
|
| }
|
|
|
|
|
| +static MaybeObject* Runtime_AllocateHeapNumber(RUNTIME_CALLING_CONVENTION) {
|
| + RUNTIME_GET_ISOLATE;
|
| + NoHandleAllocation ha;
|
| + ASSERT(args.length() == 0);
|
| + return isolate->heap()->AllocateHeapNumber(0);
|
| +}
|
| +
|
| +
|
| static MaybeObject* Runtime_NumberAdd(RUNTIME_CALLING_CONVENTION) {
|
| RUNTIME_GET_ISOLATE;
|
| NoHandleAllocation ha;
|
| @@ -6904,9 +6936,12 @@ static MaybeObject* Runtime_NewObject(RUNTIME_CALLING_CONVENTION) {
|
| }
|
| }
|
|
|
| - // The function should be compiled for the optimization hints to be available.
|
| - Handle<SharedFunctionInfo> shared(function->shared());
|
| - EnsureCompiled(shared, CLEAR_EXCEPTION);
|
| + // The function should be compiled for the optimization hints to be
|
| + // available. We cannot use EnsureCompiled because that forces a
|
| + // compilation through the shared function info which makes it
|
| + // impossible for us to optimize.
|
| + Handle<SharedFunctionInfo> shared(function->shared(), isolate);
|
| + if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
|
|
|
| if (!function->has_initial_map() &&
|
| shared->IsInobjectSlackTrackingInProgress()) {
|
| @@ -6952,7 +6987,7 @@ static MaybeObject* Runtime_LazyCompile(RUNTIME_CALLING_CONVENTION) {
|
| #ifdef DEBUG
|
| if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
|
| PrintF("[lazy: ");
|
| - function->shared()->name()->Print();
|
| + function->PrintName();
|
| PrintF("]\n");
|
| }
|
| #endif
|
| @@ -6969,10 +7004,242 @@ static MaybeObject* Runtime_LazyCompile(RUNTIME_CALLING_CONVENTION) {
|
| return Failure::Exception();
|
| }
|
|
|
| + // All done. Return the compiled code.
|
| + ASSERT(function->is_compiled());
|
| return function->code();
|
| }
|
|
|
|
|
| +static MaybeObject* Runtime_LazyRecompile(RUNTIME_CALLING_CONVENTION) {
|
| + RUNTIME_GET_ISOLATE;
|
| + HandleScope scope(isolate);
|
| + ASSERT(args.length() == 1);
|
| + Handle<JSFunction> function = args.at<JSFunction>(0);
|
| + // If the function is not optimizable or debugger is active continue using the
|
| + // code from the full compiler.
|
| + if (!function->shared()->code()->optimizable() ||
|
| + isolate->debug()->has_break_points()) {
|
| + function->ReplaceCode(function->shared()->code());
|
| + return function->code();
|
| + }
|
| + if (CompileOptimized(function, AstNode::kNoNumber)) {
|
| + return function->code();
|
| + }
|
| + function->ReplaceCode(function->shared()->code());
|
| + return Failure::Exception();
|
| +}
|
| +
|
| +
|
| +static MaybeObject* Runtime_NotifyDeoptimized(RUNTIME_CALLING_CONVENTION) {
|
| + RUNTIME_GET_ISOLATE;
|
| + HandleScope scope(isolate);
|
| + ASSERT(args.length() == 1);
|
| + RUNTIME_ASSERT(args[0]->IsSmi());
|
| + Deoptimizer::BailoutType type =
|
| + static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
|
| + Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
|
| + ASSERT(isolate->heap()->IsAllocationAllowed());
|
| + int frames = deoptimizer->output_count();
|
| +
|
| + JavaScriptFrameIterator it;
|
| + JavaScriptFrame* frame = NULL;
|
| + for (int i = 0; i < frames; i++) {
|
| + if (i != 0) it.Advance();
|
| + frame = it.frame();
|
| + deoptimizer->InsertHeapNumberValues(frames - i - 1, frame);
|
| + }
|
| + delete deoptimizer;
|
| +
|
| + RUNTIME_ASSERT(frame->function()->IsJSFunction());
|
| + Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
|
| + Handle<Object> arguments;
|
| + for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
|
| + if (frame->GetExpression(i) == isolate->heap()->the_hole_value()) {
|
| + if (arguments.is_null()) {
|
| + // FunctionGetArguments can't throw an exception, so cast away the
|
| + // doubt with an assert.
|
| + arguments = Handle<Object>(
|
| + Accessors::FunctionGetArguments(*function,
|
| + NULL)->ToObjectUnchecked());
|
| + ASSERT(*arguments != isolate->heap()->null_value());
|
| + ASSERT(*arguments != isolate->heap()->undefined_value());
|
| + }
|
| + frame->SetExpression(i, *arguments);
|
| + }
|
| + }
|
| +
|
| + isolate->compilation_cache()->MarkForLazyOptimizing(function);
|
| + if (type == Deoptimizer::EAGER) {
|
| + RUNTIME_ASSERT(function->IsOptimized());
|
| + } else {
|
| + RUNTIME_ASSERT(!function->IsOptimized());
|
| + }
|
| +
|
| + // Avoid doing too much work when running with --always-opt and keep
|
| + // the optimized code around.
|
| + if (FLAG_always_opt || type == Deoptimizer::LAZY) {
|
| + return isolate->heap()->undefined_value();
|
| + }
|
| +
|
| + // Count the number of optimized activations of the function.
|
| + int activations = 0;
|
| + while (!it.done()) {
|
| + JavaScriptFrame* frame = it.frame();
|
| + if (frame->is_optimized() && frame->function() == *function) {
|
| + activations++;
|
| + }
|
| + it.Advance();
|
| + }
|
| +
|
| + // TODO(kasperl): For now, we cannot support removing the optimized
|
| + // code when we have recursive invocations of the same function.
|
| + if (activations == 0) {
|
| + if (FLAG_trace_deopt) {
|
| + PrintF("[removing optimized code for: ");
|
| + function->PrintName();
|
| + PrintF("]\n");
|
| + }
|
| + function->ReplaceCode(function->shared()->code());
|
| + }
|
| + return isolate->heap()->undefined_value();
|
| +}
|
| +
|
| +
|
| +static MaybeObject* Runtime_NotifyOSR(RUNTIME_CALLING_CONVENTION) {
|
| + RUNTIME_GET_ISOLATE;
|
| + Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
|
| + delete deoptimizer;
|
| + return isolate->heap()->undefined_value();
|
| +}
|
| +
|
| +
|
| +static MaybeObject* Runtime_DeoptimizeFunction(RUNTIME_CALLING_CONVENTION) {
|
| + RUNTIME_GET_ISOLATE;
|
| + HandleScope scope(isolate);
|
| + ASSERT(args.length() == 1);
|
| + CONVERT_ARG_CHECKED(JSFunction, function, 0);
|
| + if (!function->IsOptimized()) return isolate->heap()->undefined_value();
|
| +
|
| + Deoptimizer::DeoptimizeFunction(*function);
|
| +
|
| + return isolate->heap()->undefined_value();
|
| +}
|
| +
|
| +
|
| +static MaybeObject* Runtime_CompileForOnStackReplacement(
|
| + RUNTIME_CALLING_CONVENTION) {
|
| + RUNTIME_GET_ISOLATE;
|
| + HandleScope scope(isolate);
|
| + ASSERT(args.length() == 1);
|
| + CONVERT_ARG_CHECKED(JSFunction, function, 0);
|
| +
|
| + // We're not prepared to handle a function with arguments object.
|
| + ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
|
| +
|
| + // We have hit a back edge in an unoptimized frame for a function that was
|
| + // selected for on-stack replacement. Find the unoptimized code object.
|
| + Handle<Code> unoptimized(function->shared()->code(), isolate);
|
| + // Keep track of whether we've succeeded in optimizing.
|
| + bool succeeded = unoptimized->optimizable();
|
| + if (succeeded) {
|
| + // If we are trying to do OSR when there are already optimized
|
| + // activations of the function, it means (a) the function is directly or
|
| + // indirectly recursive and (b) an optimized invocation has been
|
| + // deoptimized so that we are currently in an unoptimized activation.
|
| + // Check for optimized activations of this function.
|
| + JavaScriptFrameIterator it;
|
| + while (succeeded && !it.done()) {
|
| + JavaScriptFrame* frame = it.frame();
|
| + succeeded = !frame->is_optimized() || frame->function() != *function;
|
| + it.Advance();
|
| + }
|
| + }
|
| +
|
| + int ast_id = AstNode::kNoNumber;
|
| + if (succeeded) {
|
| + // The top JS function is this one, the PC is somewhere in the
|
| + // unoptimized code.
|
| + JavaScriptFrameIterator it;
|
| + JavaScriptFrame* frame = it.frame();
|
| + ASSERT(frame->function() == *function);
|
| + ASSERT(frame->LookupCode(isolate) == *unoptimized);
|
| + ASSERT(unoptimized->contains(frame->pc()));
|
| +
|
| + // Use linear search of the unoptimized code's stack check table to find
|
| + // the AST id matching the PC.
|
| + Address start = unoptimized->instruction_start();
|
| + unsigned target_pc_offset = frame->pc() - start;
|
| + Address table_cursor = start + unoptimized->stack_check_table_start();
|
| + uint32_t table_length = Memory::uint32_at(table_cursor);
|
| + table_cursor += kIntSize;
|
| + for (unsigned i = 0; i < table_length; ++i) {
|
| + // Table entries are (AST id, pc offset) pairs.
|
| + uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
|
| + if (pc_offset == target_pc_offset) {
|
| + ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
|
| + break;
|
| + }
|
| + table_cursor += 2 * kIntSize;
|
| + }
|
| + ASSERT(ast_id != AstNode::kNoNumber);
|
| + if (FLAG_trace_osr) {
|
| + PrintF("[replacing on-stack at AST id %d in ", ast_id);
|
| + function->PrintName();
|
| + PrintF("]\n");
|
| + }
|
| +
|
| + // Try to compile the optimized code. A true return value from
|
| + // CompileOptimized means that compilation succeeded, not necessarily
|
| + // that optimization succeeded.
|
| + if (CompileOptimized(function, ast_id) && function->IsOptimized()) {
|
| + DeoptimizationInputData* data = DeoptimizationInputData::cast(
|
| + function->code()->deoptimization_data());
|
| + if (FLAG_trace_osr) {
|
| + PrintF("[on-stack replacement offset %d in optimized code]\n",
|
| + data->OsrPcOffset()->value());
|
| + }
|
| + ASSERT(data->OsrAstId()->value() == ast_id);
|
| + ASSERT(data->OsrPcOffset()->value() >= 0);
|
| + } else {
|
| + succeeded = false;
|
| + }
|
| + }
|
| +
|
| + // Revert to the original stack checks in the original unoptimized code.
|
| + if (FLAG_trace_osr) {
|
| + PrintF("[restoring original stack checks in ");
|
| + function->PrintName();
|
| + PrintF("]\n");
|
| + }
|
| + StackCheckStub check_stub;
|
| + Handle<Code> check_code = check_stub.GetCode();
|
| + Handle<Code> replacement_code(
|
| + isolate->builtins()->builtin(Builtins::OnStackReplacement));
|
| + // Iterate the unoptimized code and revert all the patched stack checks.
|
| + for (RelocIterator it(*unoptimized, RelocInfo::kCodeTargetMask);
|
| + !it.done();
|
| + it.next()) {
|
| + RelocInfo* rinfo = it.rinfo();
|
| + if (rinfo->target_address() == replacement_code->entry()) {
|
| + Deoptimizer::RevertStackCheckCode(rinfo, *check_code);
|
| + }
|
| + }
|
| +
|
| + // Allow OSR only at nesting level zero again.
|
| + unoptimized->set_allow_osr_at_loop_nesting_level(0);
|
| +
|
| + // If the optimization attempt succeeded, return the AST id tagged as a
|
| + // smi. This tells the builtin that we need to translate the unoptimized
|
| + // frame to an optimized one.
|
| + if (succeeded) {
|
| + ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
|
| + return Smi::FromInt(ast_id);
|
| + } else {
|
| + return Smi::FromInt(-1);
|
| + }
|
| +}
|
| +
|
| +
|
| static MaybeObject* Runtime_GetFunctionDelegate(RUNTIME_CALLING_CONVENTION) {
|
| RUNTIME_GET_ISOLATE;
|
| HandleScope scope(isolate);
|
| @@ -8312,7 +8579,7 @@ static MaybeObject* Runtime_GetArrayKeys(RUNTIME_CALLING_CONVENTION) {
|
| int keys_length = keys->length();
|
| for (int i = 0; i < keys_length; i++) {
|
| Object* key = keys->get(i);
|
| - uint32_t index;
|
| + uint32_t index = 0;
|
| if (!key->ToArrayIndex(&index) || index >= length) {
|
| // Zap invalid keys.
|
| keys->set_undefined(i);
|
| @@ -8446,6 +8713,7 @@ static MaybeObject* DebugLookupResultValue(Heap* heap,
|
| MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
|
| receiver, structure, name, result->holder());
|
| if (!maybe_value->ToObject(&value)) {
|
| + if (maybe_value->IsRetryAfterGC()) return maybe_value;
|
| ASSERT(maybe_value->IsException());
|
| maybe_value = heap->isolate()->pending_exception();
|
| heap->isolate()->clear_pending_exception();
|
| @@ -8766,6 +9034,9 @@ static MaybeObject* Runtime_GetFrameDetails(RUNTIME_CALLING_CONVENTION) {
|
| }
|
| if (it.done()) return heap->undefined_value();
|
|
|
| + bool is_optimized_frame =
|
| + it.frame()->LookupCode(isolate)->kind() == Code::OPTIMIZED_FUNCTION;
|
| +
|
| // Traverse the saved contexts chain to find the active context for the
|
| // selected frame.
|
| SaveContext* save = isolate->save_context();
|
| @@ -8799,18 +9070,28 @@ static MaybeObject* Runtime_GetFrameDetails(RUNTIME_CALLING_CONVENTION) {
|
| // confusing.
|
| Handle<FixedArray> locals =
|
| isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
|
| +
|
| + // Fill in the names of the locals.
|
| for (int i = 0; i < info.NumberOfLocals(); i++) {
|
| - // Name of the local.
|
| locals->set(i * 2, *info.LocalName(i));
|
| + }
|
|
|
| - // Fetch the value of the local - either from the stack or from a
|
| - // heap-allocated context.
|
| - if (i < info.number_of_stack_slots()) {
|
| + // Fill in the values of the locals.
|
| + for (int i = 0; i < info.NumberOfLocals(); i++) {
|
| + if (is_optimized_frame) {
|
| + // If we are inspecting an optimized frame use undefined as the
|
| + // value for all locals.
|
| + //
|
| + // TODO(3141533): We should be able to get the correct values
|
| + // for locals in optimized frames.
|
| + locals->set(i * 2 + 1, isolate->heap()->undefined_value());
|
| + } else if (i < info.number_of_stack_slots()) {
|
| + // Get the value from the stack.
|
| locals->set(i * 2 + 1, it.frame()->GetExpression(i));
|
| } else {
|
| - Handle<String> name = info.LocalName(i);
|
| // Traverse the context chain to the function context as all local
|
| // variables stored in the context will be on the function context.
|
| + Handle<String> name = info.LocalName(i);
|
| while (!context->is_function_context()) {
|
| context = Handle<Context>(context->previous());
|
| }
|
| @@ -8820,9 +9101,12 @@ static MaybeObject* Runtime_GetFrameDetails(RUNTIME_CALLING_CONVENTION) {
|
| }
|
| }
|
|
|
| - // Check whether this frame is positioned at return.
|
| - int at_return = (index == 0) ?
|
| - isolate->debug()->IsBreakAtReturn(it.frame()) : false;
|
| + // Check whether this frame is positioned at return. If not top
|
| + // frame or if the frame is optimized it cannot be at a return.
|
| + bool at_return = false;
|
| + if (!is_optimized_frame && index == 0) {
|
| + at_return = isolate->debug()->IsBreakAtReturn(it.frame());
|
| + }
|
|
|
| // If positioned just before return find the value to be returned and add it
|
| // to the frame information.
|
| @@ -8918,8 +9202,13 @@ static MaybeObject* Runtime_GetFrameDetails(RUNTIME_CALLING_CONVENTION) {
|
| details->set(details_index++, heap->undefined_value());
|
| }
|
|
|
| - // Parameter value.
|
| - if (i < it.frame()->GetProvidedParametersCount()) {
|
| + // Parameter value. If we are inspecting an optimized frame, use
|
| + // undefined as the value.
|
| + //
|
| + // TODO(3141533): We should be able to get the actual parameter
|
| + // value for optimized frames.
|
| + if (!is_optimized_frame &&
|
| + (i < it.frame()->GetProvidedParametersCount())) {
|
| details->set(details_index++, it.frame()->GetParameter(i));
|
| } else {
|
| details->set(details_index++, heap->undefined_value());
|
| @@ -9538,7 +9827,7 @@ Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
|
| // Iterate the heap looking for SharedFunctionInfo generated from the
|
| // script. The inner most SharedFunctionInfo containing the source position
|
| // for the requested break point is found.
|
| - // NOTE: This might reqire several heap iterations. If the SharedFunctionInfo
|
| + // NOTE: This might require several heap iterations. If the SharedFunctionInfo
|
| // which is found is not compiled it is compiled and the heap is iterated
|
| // again as the compilation might create inner functions from the newly
|
| // compiled function and the actual requested break point might be in one of
|
| @@ -10395,6 +10684,17 @@ static MaybeObject* Runtime_LiveEditReplaceScript(RUNTIME_CALLING_CONVENTION) {
|
| }
|
| }
|
|
|
| +
|
| +static MaybeObject* Runtime_LiveEditFunctionSourceUpdated(
|
| + RUNTIME_CALLING_CONVENTION) {
|
| + RUNTIME_GET_ISOLATE;
|
| + ASSERT(args.length() == 1);
|
| + HandleScope scope(isolate);
|
| + CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
|
| + return LiveEdit::FunctionSourceUpdated(shared_info);
|
| +}
|
| +
|
| +
|
| // Replaces code of SharedFunctionInfo with a new one.
|
| static MaybeObject* Runtime_LiveEditReplaceFunctionCode(
|
| RUNTIME_CALLING_CONVENTION) {
|
| @@ -10508,7 +10808,12 @@ static MaybeObject* Runtime_GetFunctionCodePositionFromSource(
|
| CONVERT_ARG_CHECKED(JSFunction, function, 0);
|
| CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
|
|
|
| - Handle<Code> code(function->code());
|
| + Handle<Code> code(function->code(), isolate);
|
| +
|
| + if (code->kind() != Code::FUNCTION &&
|
| + code->kind() != Code::OPTIMIZED_FUNCTION) {
|
| + return isolate->heap()->undefined_value();
|
| + }
|
|
|
| RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
|
| int closest_pc = 0;
|
| @@ -10668,9 +10973,9 @@ static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
|
| }
|
|
|
|
|
| -// Collect the raw data for a stack trace. Returns an array of three
|
| -// element segments each containing a receiver, function and native
|
| -// code offset.
|
| +// Collect the raw data for a stack trace. Returns an array of 4
|
| +// element segments each containing a receiver, function, code and
|
| +// native code offset.
|
| static MaybeObject* Runtime_CollectStackTrace(RUNTIME_CALLING_CONVENTION) {
|
| RUNTIME_GET_ISOLATE;
|
| ASSERT_EQ(args.length(), 2);
|
| @@ -10681,7 +10986,7 @@ static MaybeObject* Runtime_CollectStackTrace(RUNTIME_CALLING_CONVENTION) {
|
|
|
| limit = Max(limit, 0); // Ensure that limit is not negative.
|
| int initial_size = Min(limit, 10);
|
| - Handle<JSArray> result = isolate->factory()->NewJSArray(initial_size * 3);
|
| + Handle<JSArray> result = isolate->factory()->NewJSArray(initial_size * 4);
|
|
|
| StackFrameIterator iter;
|
| // If the caller parameter is a function we skip frames until we're
|
| @@ -10694,23 +10999,25 @@ static MaybeObject* Runtime_CollectStackTrace(RUNTIME_CALLING_CONVENTION) {
|
| if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
|
| frames_seen++;
|
| JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
|
| - Object* recv = frame->receiver();
|
| - Object* fun = frame->function();
|
| - Address pc = frame->pc();
|
| - Address start = frame->LookupCode(isolate)->address();
|
| - Smi* offset = Smi::FromInt(static_cast<int>(pc - start));
|
| - FixedArray* elements = FixedArray::cast(result->elements());
|
| - if (cursor + 2 < elements->length()) {
|
| - elements->set(cursor++, recv);
|
| - elements->set(cursor++, fun);
|
| - elements->set(cursor++, offset);
|
| - } else {
|
| - HandleScope scope(isolate);
|
| - Handle<Object> recv_handle(recv, isolate);
|
| - Handle<Object> fun_handle(fun, isolate);
|
| - SetElement(result, cursor++, recv_handle);
|
| - SetElement(result, cursor++, fun_handle);
|
| - SetElement(result, cursor++, Handle<Smi>(offset));
|
| + List<FrameSummary> frames(3); // Max 2 levels of inlining.
|
| + frame->Summarize(&frames);
|
| + for (int i = frames.length() - 1; i >= 0; i--) {
|
| + Handle<Object> recv = frames[i].receiver();
|
| + Handle<JSFunction> fun = frames[i].function();
|
| + Handle<Code> code = frames[i].code();
|
| + Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
|
| + FixedArray* elements = FixedArray::cast(result->elements());
|
| + if (cursor + 3 < elements->length()) {
|
| + elements->set(cursor++, *recv);
|
| + elements->set(cursor++, *fun);
|
| + elements->set(cursor++, *code);
|
| + elements->set(cursor++, *offset);
|
| + } else {
|
| + SetElement(result, cursor++, recv);
|
| + SetElement(result, cursor++, fun);
|
| + SetElement(result, cursor++, code);
|
| + SetElement(result, cursor++, offset);
|
| + }
|
| }
|
| }
|
| iter.Advance();
|
|
|