Commit 7b07c779 authored by Benedikt Meurer's avatar Benedikt Meurer Committed by Commit Bot

[stack-traces] Cache source position on StackFrameInfos.

Previously we had cached the source position information on
JSStackFrame (C++) objects and reused that between calls to
GetLineNumber() and GetColumnNumber(). The refactoring in
https://crrev.com/eed0d27c2f774b3adbc85d0a5fb30a8cf0f018a8
effectively removed that cache, while still making things
faster though.

This CL puts back the caching on the StackFrameInfo objects
by reusing the `offset` slot to store the computed source
position (as indicated by a bit in the `flags`). For promise
combinator async frames, the bit is always set and the
`offset_or_source_position` slot thus always contains the source
position (aka the `promise index` in this case). We also
added a `StackFrameInfo::ComputeLocation()` method to remove the
last remaining place where we'd peek into the StackFrameInfo from
outside stack-frame-info.{cc,h}.

Also-By: kimanh@chromium.org
Bug: chromium:1077657, v8:8742, chromium:1069425
Change-Id: I59e26a91965617163776e6cc2610b88e6925452c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2695386
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Auto-Submit: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72752}
parent a1270d00
...@@ -98,15 +98,16 @@ BUILTIN(CallSitePrototypeGetMethodName) { ...@@ -98,15 +98,16 @@ BUILTIN(CallSitePrototypeGetMethodName) {
BUILTIN(CallSitePrototypeGetPosition) { BUILTIN(CallSitePrototypeGetPosition) {
HandleScope scope(isolate); HandleScope scope(isolate);
CHECK_CALLSITE(frame, "getPosition"); CHECK_CALLSITE(frame, "getPosition");
return Smi::FromInt(StackFrameInfo::GetSourcePosition(isolate, frame)); return Smi::FromInt(StackFrameInfo::GetSourcePosition(frame));
} }
BUILTIN(CallSitePrototypeGetPromiseIndex) { BUILTIN(CallSitePrototypeGetPromiseIndex) {
HandleScope scope(isolate); HandleScope scope(isolate);
CHECK_CALLSITE(frame, "getPromiseIndex"); CHECK_CALLSITE(frame, "getPromiseIndex");
int index = frame->GetPromiseCombinatorIndex(); if (!frame->IsPromiseAll() && !frame->IsPromiseAny()) {
if (index < 0) return ReadOnlyRoots(isolate).null_value(); return ReadOnlyRoots(isolate).null_value();
return Smi::FromInt(index); }
return Smi::FromInt(StackFrameInfo::GetSourcePosition(frame));
} }
BUILTIN(CallSitePrototypeGetScriptNameOrSourceURL) { BUILTIN(CallSitePrototypeGetScriptNameOrSourceURL) {
......
...@@ -2284,7 +2284,8 @@ void StackFrameInfo::StackFrameInfoPrint(std::ostream& os) { // NOLINT ...@@ -2284,7 +2284,8 @@ void StackFrameInfo::StackFrameInfoPrint(std::ostream& os) { // NOLINT
os << "\n - receiver_or_instance: " << Brief(receiver_or_instance()); os << "\n - receiver_or_instance: " << Brief(receiver_or_instance());
os << "\n - function: " << Brief(function()); os << "\n - function: " << Brief(function());
os << "\n - code_object: " << Brief(code_object()); os << "\n - code_object: " << Brief(code_object());
os << "\n - offset: " << offset(); os << "\n - code_offset_or_source_position: "
<< code_offset_or_source_position();
os << "\n - flags: " << flags(); os << "\n - flags: " << flags();
os << "\n - parameters: " << Brief(parameters()); os << "\n - parameters: " << Brief(parameters());
os << "\n"; os << "\n";
......
...@@ -662,7 +662,8 @@ class StackTraceBuilder { ...@@ -662,7 +662,8 @@ class StackTraceBuilder {
void AppendPromiseCombinatorFrame(Handle<JSFunction> element_function, void AppendPromiseCombinatorFrame(Handle<JSFunction> element_function,
Handle<JSFunction> combinator) { Handle<JSFunction> combinator) {
if (!IsVisibleInStackTrace(combinator)) return; if (!IsVisibleInStackTrace(combinator)) return;
int flags = StackFrameInfo::kIsAsync; int flags =
StackFrameInfo::kIsAsync | StackFrameInfo::kIsSourcePositionComputed;
Handle<Object> receiver(combinator->native_context().promise_function(), Handle<Object> receiver(combinator->native_context().promise_function(),
isolate_); isolate_);
...@@ -673,9 +674,10 @@ class StackTraceBuilder { ...@@ -673,9 +674,10 @@ class StackTraceBuilder {
// We store the offset of the promise into the element function's // We store the offset of the promise into the element function's
// hash field for element callbacks. // hash field for element callbacks.
int offset = Smi::ToInt(Smi::cast(element_function->GetIdentityHash())) - 1; int promise_index =
Smi::ToInt(Smi::cast(element_function->GetIdentityHash())) - 1;
AppendFrame(receiver, combinator, code, offset, flags, parameters); AppendFrame(receiver, combinator, code, promise_index, flags, parameters);
} }
void AppendJavaScriptFrame( void AppendJavaScriptFrame(
...@@ -2172,35 +2174,7 @@ bool Isolate::ComputeLocationFromStackTrace(MessageLocation* target, ...@@ -2172,35 +2174,7 @@ bool Isolate::ComputeLocationFromStackTrace(MessageLocation* target,
Handle<FixedArray> stack = Handle<FixedArray>::cast(property); Handle<FixedArray> stack = Handle<FixedArray>::cast(property);
for (int i = 0; i < stack->length(); i++) { for (int i = 0; i < stack->length(); i++) {
Handle<StackFrameInfo> frame(StackFrameInfo::cast(stack->get(i)), this); Handle<StackFrameInfo> frame(StackFrameInfo::cast(stack->get(i)), this);
if (frame->IsWasm()) { if (StackFrameInfo::ComputeLocation(frame, target)) return true;
auto offset = StackFrameInfo::GetSourcePosition(this, frame);
Handle<Script> script(frame->GetWasmInstance().module_object().script(),
this);
*target = MessageLocation(script, offset, offset + 1);
return true;
}
Handle<JSFunction> fun = handle(JSFunction::cast(frame->function()), this);
if (!fun->shared().IsSubjectToDebugging()) continue;
Object script = fun->shared().script();
if (script.IsScript() &&
!(Script::cast(script).source().IsUndefined(this))) {
Handle<SharedFunctionInfo> shared = handle(fun->shared(), this);
AbstractCode abstract_code = AbstractCode::cast(frame->code_object());
const int code_offset = frame->offset();
Handle<Script> casted_script(Script::cast(script), this);
if (shared->HasBytecodeArray() &&
shared->GetBytecodeArray(this).HasSourcePositionTable()) {
int pos = abstract_code.SourcePosition(code_offset);
*target = MessageLocation(casted_script, pos, pos + 1, shared);
} else {
*target = MessageLocation(casted_script, shared, code_offset);
}
return true;
}
} }
return false; return false;
} }
......
...@@ -2940,14 +2940,14 @@ Handle<BreakPoint> Factory::NewBreakPoint(int id, Handle<String> condition) { ...@@ -2940,14 +2940,14 @@ Handle<BreakPoint> Factory::NewBreakPoint(int id, Handle<String> condition) {
Handle<StackFrameInfo> Factory::NewStackFrameInfo( Handle<StackFrameInfo> Factory::NewStackFrameInfo(
Handle<Object> receiver_or_instance, Handle<Object> function, Handle<Object> receiver_or_instance, Handle<Object> function,
Handle<HeapObject> code_object, int offset, int flags, Handle<HeapObject> code_object, int code_offset_or_source_position,
Handle<FixedArray> parameters) { int flags, Handle<FixedArray> parameters) {
Handle<StackFrameInfo> info = Handle<StackFrameInfo> info =
Handle<StackFrameInfo>::cast(NewStruct(STACK_FRAME_INFO_TYPE)); Handle<StackFrameInfo>::cast(NewStruct(STACK_FRAME_INFO_TYPE));
info->set_receiver_or_instance(*receiver_or_instance); info->set_receiver_or_instance(*receiver_or_instance);
info->set_function(*function); info->set_function(*function);
info->set_code_object(*code_object); info->set_code_object(*code_object);
info->set_offset(offset); info->set_code_offset_or_source_position(code_offset_or_source_position);
info->set_flags(flags); info->set_flags(flags);
info->set_parameters(*parameters); info->set_parameters(*parameters);
return info; return info;
......
...@@ -371,7 +371,8 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> { ...@@ -371,7 +371,8 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
Handle<StackFrameInfo> NewStackFrameInfo(Handle<Object> receiver_or_instance, Handle<StackFrameInfo> NewStackFrameInfo(Handle<Object> receiver_or_instance,
Handle<Object> function, Handle<Object> function,
Handle<HeapObject> code_object, Handle<HeapObject> code_object,
int offset, int flags, int code_offset_or_source_position,
int flags,
Handle<FixedArray> parameters); Handle<FixedArray> parameters);
// Allocate various microtasks. // Allocate various microtasks.
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "src/objects/stack-frame-info.h" #include "src/objects/stack-frame-info.h"
#include "src/objects/shared-function-info.h"
#include "src/objects/stack-frame-info-inl.h" #include "src/objects/stack-frame-info-inl.h"
#include "src/strings/string-builder-inl.h" #include "src/strings/string-builder-inl.h"
...@@ -57,7 +58,7 @@ int StackFrameInfo::GetLineNumber(Handle<StackFrameInfo> info) { ...@@ -57,7 +58,7 @@ int StackFrameInfo::GetLineNumber(Handle<StackFrameInfo> info) {
} }
Handle<Script> script; Handle<Script> script;
if (GetScript(isolate, info).ToHandle(&script)) { if (GetScript(isolate, info).ToHandle(&script)) {
int position = GetSourcePosition(isolate, info); int position = GetSourcePosition(info);
return Script::GetLineNumber(script, position) + 1; return Script::GetLineNumber(script, position) + 1;
} }
return Message::kNoLineNumberInfo; return Message::kNoLineNumberInfo;
...@@ -66,7 +67,7 @@ int StackFrameInfo::GetLineNumber(Handle<StackFrameInfo> info) { ...@@ -66,7 +67,7 @@ int StackFrameInfo::GetLineNumber(Handle<StackFrameInfo> info) {
// static // static
int StackFrameInfo::GetColumnNumber(Handle<StackFrameInfo> info) { int StackFrameInfo::GetColumnNumber(Handle<StackFrameInfo> info) {
Isolate* isolate = info->GetIsolate(); Isolate* isolate = info->GetIsolate();
int position = GetSourcePosition(isolate, info); int position = GetSourcePosition(info);
if (info->IsWasm() && !info->IsAsmJsWasm()) { if (info->IsWasm() && !info->IsAsmJsWasm()) {
return position + 1; return position + 1;
} }
...@@ -402,10 +403,6 @@ Handle<Object> StackFrameInfo::GetTypeName(Handle<StackFrameInfo> info) { ...@@ -402,10 +403,6 @@ Handle<Object> StackFrameInfo::GetTypeName(Handle<StackFrameInfo> info) {
return JSReceiver::GetConstructorName(receiver); return JSReceiver::GetConstructorName(receiver);
} }
int StackFrameInfo::GetPromiseCombinatorIndex() const {
return (IsPromiseAll() || IsPromiseAny()) ? offset() : kUnknown;
}
uint32_t StackFrameInfo::GetWasmFunctionIndex() const { uint32_t StackFrameInfo::GetWasmFunctionIndex() const {
DCHECK(IsWasm()); DCHECK(IsWasm());
return Smi::ToInt(Smi::cast(function())); return Smi::ToInt(Smi::cast(function()));
...@@ -417,24 +414,62 @@ WasmInstanceObject StackFrameInfo::GetWasmInstance() const { ...@@ -417,24 +414,62 @@ WasmInstanceObject StackFrameInfo::GetWasmInstance() const {
} }
// static // static
int StackFrameInfo::GetSourcePosition(Isolate* isolate, int StackFrameInfo::GetSourcePosition(Handle<StackFrameInfo> info) {
Handle<StackFrameInfo> info) { if (info->flags() & kIsSourcePositionComputed) {
int offset = info->offset(); return info->code_offset_or_source_position();
}
DCHECK(!info->IsPromiseAll());
DCHECK(!info->IsPromiseAny());
int source_position =
ComputeSourcePosition(info, info->code_offset_or_source_position());
info->set_code_offset_or_source_position(source_position);
info->set_flags(info->flags() | kIsSourcePositionComputed);
return source_position;
}
// static
bool StackFrameInfo::ComputeLocation(Handle<StackFrameInfo> info,
MessageLocation* location) {
Isolate* isolate = info->GetIsolate();
if (info->IsWasm()) {
int pos = GetSourcePosition(info);
Handle<Script> script(info->GetWasmInstance().module_object().script(),
isolate);
*location = MessageLocation(script, pos, pos + 1);
return true;
}
Handle<SharedFunctionInfo> shared(info->GetSharedFunctionInfo(), isolate);
if (!shared->IsSubjectToDebugging()) return false;
Handle<Script> script(Script::cast(shared->script()), isolate);
if (script->source().IsUndefined()) return false;
if (info->flags() & kIsSourcePositionComputed ||
(shared->HasBytecodeArray() &&
shared->GetBytecodeArray(isolate).HasSourcePositionTable())) {
int pos = GetSourcePosition(info);
*location = MessageLocation(script, pos, pos + 1, shared);
} else {
int code_offset = info->code_offset_or_source_position();
*location = MessageLocation(script, shared, code_offset);
}
return true;
}
// static
int StackFrameInfo::ComputeSourcePosition(Handle<StackFrameInfo> info,
int offset) {
Isolate* isolate = info->GetIsolate();
if (info->IsWasm()) { if (info->IsWasm()) {
auto code_ref = Managed<wasm::GlobalWasmCodeRef>::cast(info->code_object()); auto code_ref = Managed<wasm::GlobalWasmCodeRef>::cast(info->code_object());
offset = code_ref.get()->code()->GetSourcePositionBefore(offset); int byte_offset = code_ref.get()->code()->GetSourcePositionBefore(offset);
auto module = info->GetWasmInstance().module(); auto module = info->GetWasmInstance().module();
auto func_index = info->GetWasmFunctionIndex(); uint32_t func_index = info->GetWasmFunctionIndex();
offset = wasm::GetSourcePosition(module, func_index, offset, return wasm::GetSourcePosition(module, func_index, byte_offset,
info->IsAsmJsAtNumberConversion()); info->IsAsmJsAtNumberConversion());
} else {
Handle<SharedFunctionInfo> shared(info->GetSharedFunctionInfo(), isolate);
SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate, shared);
offset = AbstractCode::cast(info->code_object()).SourcePosition(offset);
} }
// A possible optimization here would be to cache the computed position in Handle<SharedFunctionInfo> shared(info->GetSharedFunctionInfo(), isolate);
// the offset slot and somehow mark the StackFrameInfo object appropriately. SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate, shared);
return offset; return AbstractCode::cast(info->code_object()).SourcePosition(offset);
} }
// static // static
...@@ -599,7 +634,7 @@ void SerializeJSStackFrame(Isolate* isolate, Handle<StackFrameInfo> frame, ...@@ -599,7 +634,7 @@ void SerializeJSStackFrame(Isolate* isolate, Handle<StackFrameInfo> frame,
builder->AppendCString("Promise."); builder->AppendCString("Promise.");
builder->AppendString(Handle<String>::cast(function_name)); builder->AppendString(Handle<String>::cast(function_name));
builder->AppendCString(" (index "); builder->AppendCString(" (index ");
builder->AppendInt(frame->GetPromiseCombinatorIndex()); builder->AppendInt(StackFrameInfo::GetSourcePosition(frame));
builder->AppendCString(")"); builder->AppendCString(")");
return; return;
} }
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
class MessageLocation;
class WasmInstanceObject; class WasmInstanceObject;
#include "torque-generated/src/objects/stack-frame-info-tq.inc" #include "torque-generated/src/objects/stack-frame-info-tq.inc"
...@@ -61,10 +62,6 @@ class StackFrameInfo ...@@ -61,10 +62,6 @@ class StackFrameInfo
static Handle<Object> GetMethodName(Handle<StackFrameInfo> info); static Handle<Object> GetMethodName(Handle<StackFrameInfo> info);
static Handle<Object> GetTypeName(Handle<StackFrameInfo> info); static Handle<Object> GetTypeName(Handle<StackFrameInfo> info);
// Returns the promise combinator input index for Promise.all()
// and Promise.any() async frames, kUnknown otherwise.
int GetPromiseCombinatorIndex() const;
// These methods are only valid for Wasm and asm.js Wasm frames. // These methods are only valid for Wasm and asm.js Wasm frames.
uint32_t GetWasmFunctionIndex() const; uint32_t GetWasmFunctionIndex() const;
WasmInstanceObject GetWasmInstance() const; WasmInstanceObject GetWasmInstance() const;
...@@ -72,14 +69,22 @@ class StackFrameInfo ...@@ -72,14 +69,22 @@ class StackFrameInfo
// Returns the 0-based source position, which is the offset into the // Returns the 0-based source position, which is the offset into the
// Script in case of JavaScript and Asm.js, and the bytecode offset // Script in case of JavaScript and Asm.js, and the bytecode offset
// in the module in case of actual Wasm. // in the module in case of actual Wasm. In case of async promise
static int GetSourcePosition(Isolate* isolate, Handle<StackFrameInfo> info); // combinator frames, this returns the index of the promise.
static int GetSourcePosition(Handle<StackFrameInfo> info);
// Attempts to fill the |location| based on the |info|, and avoids
// triggering source position table building for JavaScript frames.
static bool ComputeLocation(Handle<StackFrameInfo> info,
MessageLocation* location);
private: private:
// Bit position in the flag, from least significant bit position. // Bit position in the flag, from least significant bit position.
DEFINE_TORQUE_GENERATED_STACK_FRAME_INFO_FLAGS() DEFINE_TORQUE_GENERATED_STACK_FRAME_INFO_FLAGS()
friend class StackTraceBuilder; friend class StackTraceBuilder;
static int ComputeSourcePosition(Handle<StackFrameInfo> info, int offset);
base::Optional<Script> GetScript() const; base::Optional<Script> GetScript() const;
SharedFunctionInfo GetSharedFunctionInfo() const; SharedFunctionInfo GetSharedFunctionInfo() const;
......
...@@ -9,6 +9,9 @@ bitfield struct StackFrameInfoFlags extends uint31 { ...@@ -9,6 +9,9 @@ bitfield struct StackFrameInfoFlags extends uint31 {
is_constructor: bool: 1 bit; is_constructor: bool: 1 bit;
is_asm_js_at_number_conversion: bool: 1 bit; is_asm_js_at_number_conversion: bool: 1 bit;
is_async: bool: 1 bit; is_async: bool: 1 bit;
// whether offset_or_source_position contains the source position.
is_source_position_computed: bool: 1 bit;
} }
@generateCppClass @generateCppClass
...@@ -16,7 +19,7 @@ extern class StackFrameInfo extends Struct { ...@@ -16,7 +19,7 @@ extern class StackFrameInfo extends Struct {
receiver_or_instance: JSAny; receiver_or_instance: JSAny;
function: JSFunction|Smi; function: JSFunction|Smi;
code_object: HeapObject; code_object: HeapObject;
offset: Smi; code_offset_or_source_position: Smi;
flags: SmiTagged<StackFrameInfoFlags>; flags: SmiTagged<StackFrameInfoFlags>;
parameters: FixedArray; parameters: FixedArray;
} }
...@@ -890,7 +890,7 @@ own<Frame> CreateFrameFromInternal(i::Handle<i::FixedArray> frames, int index, ...@@ -890,7 +890,7 @@ own<Frame> CreateFrameFromInternal(i::Handle<i::FixedArray> frames, int index,
i::StackFrameInfo::cast(frames->get(index)), isolate); i::StackFrameInfo::cast(frames->get(index)), isolate);
i::Handle<i::WasmInstanceObject> instance(frame->GetWasmInstance(), isolate); i::Handle<i::WasmInstanceObject> instance(frame->GetWasmInstance(), isolate);
uint32_t func_index = frame->GetWasmFunctionIndex(); uint32_t func_index = frame->GetWasmFunctionIndex();
size_t module_offset = i::StackFrameInfo::GetSourcePosition(isolate, frame); size_t module_offset = i::StackFrameInfo::GetSourcePosition(frame);
size_t func_offset = module_offset - i::wasm::GetWasmFunctionOffset( size_t func_offset = module_offset - i::wasm::GetWasmFunctionOffset(
instance->module(), func_index); instance->module(), func_index);
return own<Frame>(seal<Frame>(new (std::nothrow) FrameImpl( return own<Frame>(seal<Frame>(new (std::nothrow) FrameImpl(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment