From 19e838026197f320a94cd2892823d1b502f5c736 Mon Sep 17 00:00:00 2001 From: jgruber Date: Wed, 24 Aug 2016 01:48:34 -0700 Subject: [PATCH] Add new FrameArray type A FrameArray encodes information about a set of stack frames into a fixed array. This commit is a pure refactoring to make the structure of fixed array-encoded frames explicit. BUG= Review-Url: https://codereview.chromium.org/2270783002 Cr-Commit-Position: refs/heads/master@{#38852} --- src/factory.cc | 8 ++ src/factory.h | 3 + src/heap-symbols.h | 1 + src/isolate.cc | 132 +++++++++++++------------------- src/messages.cc | 62 ++++++++------- src/objects-inl.h | 35 +++++++++ src/objects.cc | 62 +++++++++++++-- src/objects.h | 75 +++++++++++++++++- src/runtime/runtime-internal.cc | 17 ++-- 9 files changed, 272 insertions(+), 123 deletions(-) diff --git a/src/factory.cc b/src/factory.cc index bedcb9b61a..8d22eb15a2 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -178,6 +178,14 @@ Handle Factory::NewFixedDoubleArrayWithHoles( return array; } +Handle Factory::NewFrameArray(int number_of_frames, + PretenureFlag pretenure) { + DCHECK_LE(0, number_of_frames); + Handle result = + NewFixedArrayWithHoles(FrameArray::LengthFor(number_of_frames)); + result->set(FrameArray::kFrameCountIndex, Smi::FromInt(0)); + return Handle::cast(result); +} Handle Factory::NewOrderedHashSet() { return OrderedHashSet::Allocate(isolate(), OrderedHashSet::kMinCapacity); diff --git a/src/factory.h b/src/factory.h index 4908d5fad8..848924af4b 100644 --- a/src/factory.h +++ b/src/factory.h @@ -52,6 +52,9 @@ class Factory final { int size, PretenureFlag pretenure = NOT_TENURED); + Handle NewFrameArray(int number_of_frames, + PretenureFlag pretenure = NOT_TENURED); + Handle NewOrderedHashSet(); Handle NewOrderedHashMap(); diff --git a/src/heap-symbols.h b/src/heap-symbols.h index d83f63fdbe..5a622a3435 100644 --- a/src/heap-symbols.h +++ b/src/heap-symbols.h @@ -128,6 +128,7 @@ V(sourceText_string, "sourceText") \ V(source_url_string, "source_url") \ V(stack_string, "stack") \ + V(stackTraceLimit_string, "stackTraceLimit") \ V(strict_compare_ic_string, "===") \ V(string_string, "string") \ V(String_string, "String") \ diff --git a/src/isolate.cc b/src/isolate.cc index 624f2a8d93..3a9b93a42d 100644 --- a/src/isolate.cc +++ b/src/isolate.cc @@ -315,21 +315,7 @@ void Isolate::PushStackTraceAndDie(unsigned int magic, void* ptr1, void* ptr2, base::OS::Abort(); } -static Handle MaybeGrow(Isolate* isolate, - Handle elements, - int cur_position, int new_size) { - if (new_size > elements->length()) { - int new_capacity = JSObject::NewElementsCapacity(elements->length()); - Handle new_elements = - isolate->factory()->NewFixedArrayWithHoles(new_capacity); - for (int i = 0; i < cur_position; i++) { - new_elements->set(i, elements->get(i)); - } - elements = new_elements; - } - DCHECK(new_size <= elements->length()); - return elements; -} +namespace { class StackTraceHelper { public: @@ -435,8 +421,6 @@ class StackTraceHelper { bool encountered_strict_function_; }; -namespace { - // TODO(jgruber): Fix all cases in which frames give us a hole value (e.g. the // receiver in RegExp constructor frames. Handle TheHoleToUndefined(Isolate* isolate, Handle in) { @@ -444,35 +428,36 @@ Handle TheHoleToUndefined(Isolate* isolate, Handle in) { ? Handle::cast(isolate->factory()->undefined_value()) : in; } + +bool GetStackTraceLimit(Isolate* isolate, int* result) { + Handle error = isolate->error_function(); + + Handle key = isolate->factory()->stackTraceLimit_string(); + Handle stack_trace_limit = JSReceiver::GetDataProperty(error, key); + if (!stack_trace_limit->IsNumber()) return false; + + // Ensure that limit is not negative. + *result = Max(FastD2IChecked(stack_trace_limit->Number()), 0); + return true; } +} // namespace + Handle Isolate::CaptureSimpleStackTrace(Handle error_object, FrameSkipMode mode, Handle caller) { DisallowJavascriptExecution no_js(this); - // Get stack trace limit. - Handle error = error_function(); - Handle stackTraceLimit = - factory()->InternalizeUtf8String("stackTraceLimit"); - DCHECK(!stackTraceLimit.is_null()); - Handle stack_trace_limit = - JSReceiver::GetDataProperty(error, stackTraceLimit); - if (!stack_trace_limit->IsNumber()) return factory()->undefined_value(); - int limit = FastD2IChecked(stack_trace_limit->Number()); - limit = Max(limit, 0); // Ensure that limit is not negative. + int limit; + if (!GetStackTraceLimit(this, &limit)) return factory()->undefined_value(); - int initial_size = Min(limit, 10); - Handle elements = - factory()->NewFixedArrayWithHoles(initial_size * 4 + 1); + const int initial_size = Min(limit, 10); + Handle elements = factory()->NewFrameArray(initial_size); StackTraceHelper helper(this, mode, caller); - // First element is reserved to store the number of sloppy frames. - int cursor = 1; - int frames_seen = 0; - for (StackFrameIterator iter(this); !iter.done() && frames_seen < limit; - iter.Advance()) { + for (StackFrameIterator iter(this); + !iter.done() && elements->FrameCount() < limit; iter.Advance()) { StackFrame* frame = iter.frame(); switch (frame->type()) { @@ -502,14 +487,11 @@ Handle Isolate::CaptureSimpleStackTrace(Handle error_object, recv = handle(heap()->call_site_constructor_symbol(), this); } } - Handle offset(Smi::FromInt(frames[i].code_offset()), this); + const int offset = frames[i].code_offset(); - elements = MaybeGrow(this, elements, cursor, cursor + 4); - elements->set(cursor++, *TheHoleToUndefined(this, recv)); - elements->set(cursor++, *fun); - elements->set(cursor++, *abstract_code); - elements->set(cursor++, *offset); - frames_seen++; + elements = FrameArray::AppendJSFrame(elements, + TheHoleToUndefined(this, recv), + fun, abstract_code, offset); } } break; @@ -534,39 +516,39 @@ Handle Isolate::CaptureSimpleStackTrace(Handle error_object, recv = handle(exit_frame->receiver(), this); } - elements = MaybeGrow(this, elements, cursor, cursor + 4); - elements->set(cursor++, *recv); - elements->set(cursor++, *fun); - elements->set(cursor++, *code); - elements->set(cursor++, Smi::FromInt(offset)); - frames_seen++; + elements = FrameArray::AppendJSFrame( + elements, recv, fun, Handle::cast(code), offset); } break; case StackFrame::WASM: { WasmFrame* wasm_frame = WasmFrame::cast(frame); + Handle wasm_object = handle(wasm_frame->wasm_obj(), this); + const int wasm_function_index = wasm_frame->function_index(); Code* code = wasm_frame->unchecked_code(); Handle abstract_code = Handle(AbstractCode::cast(code), this); - int offset = + const int offset = static_cast(wasm_frame->pc() - code->instruction_start()); - elements = MaybeGrow(this, elements, cursor, cursor + 4); - elements->set(cursor++, wasm_frame->wasm_obj()); - elements->set(cursor++, Smi::FromInt(wasm_frame->function_index())); - elements->set(cursor++, *abstract_code); - elements->set(cursor++, Smi::FromInt(offset)); - frames_seen++; + + // TODO(wasm): The wasm object returned by the WasmFrame should always + // be a wasm object. + DCHECK(wasm::IsWasmObject(*wasm_object) || + wasm_object->IsUndefined(this)); + + elements = FrameArray::AppendWasmFrame( + elements, wasm_object, wasm_function_index, abstract_code, offset); } break; default: break; } } - elements->set(0, Smi::FromInt(helper.sloppy_frames())); - elements->Shrink(cursor); - Handle result = factory()->NewJSArrayWithElements(elements); - result->set_length(Smi::FromInt(cursor)); + + elements->SetSloppyFrameCount(helper.sloppy_frames()); + elements->ShrinkToFit(); + // TODO(yangguo): Queue this structured stack trace for preprocessing on GC. - return result; + return factory()->NewJSArrayWithElements(elements); } MaybeHandle Isolate::CaptureAndSetDetailedStackTrace( @@ -773,19 +755,6 @@ class CaptureStackTraceHelper { Handle constructor_key_; }; - -int PositionFromStackTrace(Handle elements, int index) { - DisallowHeapAllocation no_gc; - Object* maybe_code = elements->get(index + 2); - if (maybe_code->IsSmi()) { - return Smi::cast(maybe_code)->value(); - } else { - AbstractCode* abstract_code = AbstractCode::cast(maybe_code); - int code_offset = Smi::cast(elements->get(index + 3))->value(); - return abstract_code->SourcePosition(code_offset); - } -} - Handle Isolate::CaptureCurrentStackTrace( int frame_limit, StackTrace::StackTraceOptions options) { DisallowJavascriptExecution no_js(this); @@ -1531,22 +1500,25 @@ bool Isolate::ComputeLocationFromStackTrace(MessageLocation* target, if (!property->IsJSArray()) return false; Handle simple_stack_trace = Handle::cast(property); - Handle elements(FixedArray::cast(simple_stack_trace->elements())); - int elements_limit = Smi::cast(simple_stack_trace->length())->value(); + Handle elements(FrameArray::cast(simple_stack_trace->elements())); - for (int i = 1; i < elements_limit; i += 4) { - Handle fun_obj = handle(elements->get(i + 1), this); - if (fun_obj->IsSmi()) { + const int frame_count = elements->FrameCount(); + for (int i = 0; i < frame_count; i++) { + if (elements->IsWasmFrame(i)) { // TODO(clemensh): handle wasm frames return false; } - Handle fun = Handle::cast(fun_obj); + + Handle fun = handle(elements->Function(i), this); if (!fun->shared()->IsSubjectToDebugging()) continue; Object* script = fun->shared()->script(); if (script->IsScript() && !(Script::cast(script)->source()->IsUndefined(this))) { - int pos = PositionFromStackTrace(elements, i); + AbstractCode* abstract_code = elements->Code(i); + const int code_offset = elements->Offset(i)->value(); + const int pos = abstract_code->SourcePosition(code_offset); + Handle