Correctly format builtin constructors in stack traces
CallSite::IsConstructor() was unable to recognize builtin construct stubs (NumberConstructor_ConstructStub and StringConstructor_ConstructStub) as constructors, and thus these frames were not formatted correctly in stack traces. Fix this by explicitly marking their Code objects as construct stubs and passing along a special receiver value when we encounter such cases in CaptureSimpleStackTrace. R=mstarzinger@chromium.org, yangguo@chromium.org BUG= Review-Url: https://codereview.chromium.org/2125163004 Cr-Commit-Position: refs/heads/master@{#37631}
This commit is contained in:
parent
71becab88d
commit
be5808bff8
@ -1226,7 +1226,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
function_fun->set_prototype_or_initial_map(
|
||||
*sloppy_function_map_writable_prototype_);
|
||||
function_fun->shared()->DontAdaptArguments();
|
||||
function_fun->shared()->set_construct_stub(
|
||||
function_fun->shared()->SetConstructStub(
|
||||
*isolate->builtins()->FunctionConstructor());
|
||||
function_fun->shared()->set_length(1);
|
||||
InstallWithIntrinsicDefaultProto(isolate, function_fun,
|
||||
@ -1308,7 +1308,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
CacheInitialJSArrayMaps(native_context(), initial_map);
|
||||
ArrayConstructorStub array_constructor_stub(isolate);
|
||||
Handle<Code> code = array_constructor_stub.GetCode();
|
||||
array_function->shared()->set_construct_stub(*code);
|
||||
array_function->shared()->SetConstructStub(*code);
|
||||
|
||||
Handle<JSFunction> is_arraylike = SimpleInstallFunction(
|
||||
array_function, isolate->factory()->InternalizeUtf8String("isArray"),
|
||||
@ -1321,7 +1321,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
global, "Number", JS_VALUE_TYPE, JSValue::kSize,
|
||||
isolate->initial_object_prototype(), Builtins::kNumberConstructor);
|
||||
number_fun->shared()->DontAdaptArguments();
|
||||
number_fun->shared()->set_construct_stub(
|
||||
number_fun->shared()->SetConstructStub(
|
||||
*isolate->builtins()->NumberConstructor_ConstructStub());
|
||||
number_fun->shared()->set_length(1);
|
||||
InstallWithIntrinsicDefaultProto(isolate, number_fun,
|
||||
@ -1360,7 +1360,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
isolate->initial_object_prototype(),
|
||||
Builtins::kBooleanConstructor);
|
||||
boolean_fun->shared()->DontAdaptArguments();
|
||||
boolean_fun->shared()->set_construct_stub(
|
||||
boolean_fun->shared()->SetConstructStub(
|
||||
*isolate->builtins()->BooleanConstructor_ConstructStub());
|
||||
boolean_fun->shared()->set_length(1);
|
||||
InstallWithIntrinsicDefaultProto(isolate, boolean_fun,
|
||||
@ -1387,7 +1387,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
Handle<JSFunction> string_fun = InstallFunction(
|
||||
global, "String", JS_VALUE_TYPE, JSValue::kSize,
|
||||
isolate->initial_object_prototype(), Builtins::kStringConstructor);
|
||||
string_fun->shared()->set_construct_stub(
|
||||
string_fun->shared()->SetConstructStub(
|
||||
*isolate->builtins()->StringConstructor_ConstructStub());
|
||||
string_fun->shared()->DontAdaptArguments();
|
||||
string_fun->shared()->set_length(1);
|
||||
@ -1452,7 +1452,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
Handle<JSFunction> symbol_fun =
|
||||
InstallFunction(global, "Symbol", JS_VALUE_TYPE, JSValue::kSize,
|
||||
prototype, Builtins::kSymbolConstructor);
|
||||
symbol_fun->shared()->set_construct_stub(
|
||||
symbol_fun->shared()->SetConstructStub(
|
||||
*isolate->builtins()->SymbolConstructor_ConstructStub());
|
||||
symbol_fun->shared()->set_length(0);
|
||||
symbol_fun->shared()->DontAdaptArguments();
|
||||
@ -1497,7 +1497,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
Builtins::kDateConstructor);
|
||||
InstallWithIntrinsicDefaultProto(isolate, date_fun,
|
||||
Context::DATE_FUNCTION_INDEX);
|
||||
date_fun->shared()->set_construct_stub(
|
||||
date_fun->shared()->SetConstructStub(
|
||||
*isolate->builtins()->DateConstructor_ConstructStub());
|
||||
date_fun->shared()->set_length(7);
|
||||
date_fun->shared()->DontAdaptArguments();
|
||||
@ -1630,7 +1630,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
Builtins::kIllegal);
|
||||
InstallWithIntrinsicDefaultProto(isolate, regexp_fun,
|
||||
Context::REGEXP_FUNCTION_INDEX);
|
||||
regexp_fun->shared()->set_construct_stub(
|
||||
regexp_fun->shared()->SetConstructStub(
|
||||
*isolate->builtins()->JSBuiltinsConstructStub());
|
||||
|
||||
DCHECK(regexp_fun->has_initial_map());
|
||||
@ -1874,7 +1874,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
Builtins::kDataViewConstructor);
|
||||
InstallWithIntrinsicDefaultProto(isolate, data_view_fun,
|
||||
Context::DATA_VIEW_FUN_INDEX);
|
||||
data_view_fun->shared()->set_construct_stub(
|
||||
data_view_fun->shared()->SetConstructStub(
|
||||
*isolate->builtins()->DataViewConstructor_ConstructStub());
|
||||
data_view_fun->shared()->set_length(3);
|
||||
data_view_fun->shared()->DontAdaptArguments();
|
||||
@ -1971,7 +1971,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
proxy_function, Handle<Map>(native_context()->proxy_map(), isolate),
|
||||
factory->null_value());
|
||||
|
||||
proxy_function->shared()->set_construct_stub(
|
||||
proxy_function->shared()->SetConstructStub(
|
||||
*isolate->builtins()->ProxyConstructor_ConstructStub());
|
||||
proxy_function->shared()->set_internal_formal_parameter_count(2);
|
||||
proxy_function->shared()->set_length(2);
|
||||
@ -2512,7 +2512,7 @@ void Bootstrapper::ExportFromRuntime(Isolate* isolate,
|
||||
generator_function_function->set_prototype_or_initial_map(
|
||||
native_context->sloppy_generator_function_map());
|
||||
generator_function_function->shared()->DontAdaptArguments();
|
||||
generator_function_function->shared()->set_construct_stub(
|
||||
generator_function_function->shared()->SetConstructStub(
|
||||
*isolate->builtins()->GeneratorFunctionConstructor());
|
||||
generator_function_function->shared()->set_length(1);
|
||||
InstallWithIntrinsicDefaultProto(
|
||||
@ -2709,7 +2709,7 @@ void Bootstrapper::ExportFromRuntime(Isolate* isolate,
|
||||
async_function_prototype, Builtins::kAsyncFunctionConstructor,
|
||||
kUseStrictFunctionMap);
|
||||
async_function_constructor->shared()->DontAdaptArguments();
|
||||
async_function_constructor->shared()->set_construct_stub(
|
||||
async_function_constructor->shared()->SetConstructStub(
|
||||
*isolate->builtins()->AsyncFunctionConstructor());
|
||||
async_function_constructor->shared()->set_length(1);
|
||||
InstallWithIntrinsicDefaultProto(isolate, async_function_constructor,
|
||||
@ -2920,7 +2920,7 @@ Handle<JSFunction> Genesis::InstallArrayBuffer(Handle<JSObject> target,
|
||||
InstallFunction(target, name, JS_ARRAY_BUFFER_TYPE,
|
||||
JSArrayBuffer::kSizeWithInternalFields, prototype,
|
||||
Builtins::kArrayBufferConstructor);
|
||||
array_buffer_fun->shared()->set_construct_stub(
|
||||
array_buffer_fun->shared()->SetConstructStub(
|
||||
*isolate()->builtins()->ArrayBufferConstructor_ConstructStub());
|
||||
array_buffer_fun->shared()->DontAdaptArguments();
|
||||
array_buffer_fun->shared()->set_length(1);
|
||||
@ -2957,7 +2957,7 @@ Handle<JSFunction> Genesis::InstallInternalArray(Handle<JSObject> target,
|
||||
|
||||
InternalArrayConstructorStub internal_array_constructor_stub(isolate());
|
||||
Handle<Code> code = internal_array_constructor_stub.GetCode();
|
||||
array_function->shared()->set_construct_stub(*code);
|
||||
array_function->shared()->SetConstructStub(*code);
|
||||
array_function->shared()->DontAdaptArguments();
|
||||
|
||||
Handle<Map> original_map(array_function->initial_map());
|
||||
@ -3147,7 +3147,7 @@ bool Genesis::InstallNatives(GlobalContextType context_type) {
|
||||
JSReceiver::GetProperty(global_object, key).ToHandleChecked());
|
||||
JSFunction::EnsureHasInitialMap(function);
|
||||
function->initial_map()->set_instance_type(JS_PROMISE_TYPE);
|
||||
function->shared()->set_construct_stub(
|
||||
function->shared()->SetConstructStub(
|
||||
*isolate()->builtins()->JSBuiltinsConstructStub());
|
||||
InstallWithIntrinsicDefaultProto(isolate(), function,
|
||||
Context::PROMISE_FUNCTION_INDEX);
|
||||
|
@ -1744,7 +1744,7 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForNative(
|
||||
Handle<SharedFunctionInfo> shared = isolate->factory()->NewSharedFunctionInfo(
|
||||
name, fun->shared()->num_literals(), FunctionKind::kNormalFunction, code,
|
||||
Handle<ScopeInfo>(fun->shared()->scope_info()));
|
||||
shared->set_construct_stub(*construct_stub);
|
||||
shared->SetConstructStub(*construct_stub);
|
||||
shared->set_feedback_metadata(fun->shared()->feedback_metadata());
|
||||
|
||||
// Copy the function data to the shared function info.
|
||||
|
@ -2119,7 +2119,7 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
|
||||
Handle<Code> construct_stub =
|
||||
is_constructor ? isolate()->builtins()->JSConstructStubGeneric()
|
||||
: isolate()->builtins()->ConstructedNonConstructable();
|
||||
share->set_construct_stub(*construct_stub);
|
||||
share->SetConstructStub(*construct_stub);
|
||||
share->set_instance_class_name(*Object_string());
|
||||
share->set_function_data(*undefined_value(), SKIP_WRITE_BARRIER);
|
||||
share->set_script(*undefined_value(), SKIP_WRITE_BARRIER);
|
||||
|
@ -446,6 +446,14 @@ Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object,
|
||||
|
||||
Handle<Object> recv = frames[i].receiver();
|
||||
Handle<AbstractCode> abstract_code = frames[i].abstract_code();
|
||||
if (frame->type() == StackFrame::BUILTIN) {
|
||||
// Help CallSite::IsConstructor correctly detect hand-written
|
||||
// construct stubs.
|
||||
Code* code = Code::cast(*abstract_code);
|
||||
if (code->is_construct_stub()) {
|
||||
recv = handle(heap()->call_site_constructor_symbol(), this);
|
||||
}
|
||||
}
|
||||
Handle<Smi> offset(Smi::FromInt(frames[i].code_offset()), this);
|
||||
|
||||
elements = MaybeGrow(this, elements, cursor, cursor + 4);
|
||||
|
@ -4987,6 +4987,18 @@ inline void Code::set_can_have_weak_objects(bool value) {
|
||||
WRITE_UINT32_FIELD(this, kKindSpecificFlags1Offset, updated);
|
||||
}
|
||||
|
||||
inline bool Code::is_construct_stub() {
|
||||
DCHECK(kind() == BUILTIN);
|
||||
return IsConstructStubField::decode(
|
||||
READ_UINT32_FIELD(this, kKindSpecificFlags1Offset));
|
||||
}
|
||||
|
||||
inline void Code::set_is_construct_stub(bool value) {
|
||||
DCHECK(kind() == BUILTIN);
|
||||
int previous = READ_UINT32_FIELD(this, kKindSpecificFlags1Offset);
|
||||
int updated = IsConstructStubField::update(previous, value);
|
||||
WRITE_UINT32_FIELD(this, kKindSpecificFlags1Offset, updated);
|
||||
}
|
||||
|
||||
bool Code::has_deoptimization_support() {
|
||||
DCHECK_EQ(FUNCTION, kind());
|
||||
|
@ -995,7 +995,7 @@ Handle<SharedFunctionInfo> FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(
|
||||
Handle<SharedFunctionInfo> result =
|
||||
isolate->factory()->NewSharedFunctionInfo(name, code, is_constructor);
|
||||
if (is_constructor) {
|
||||
result->set_construct_stub(*isolate->builtins()->JSConstructStubApi());
|
||||
result->SetConstructStub(*isolate->builtins()->JSConstructStubApi());
|
||||
}
|
||||
|
||||
result->set_length(info->length());
|
||||
@ -13244,7 +13244,7 @@ void SharedFunctionInfo::InitFromFunctionLiteral(
|
||||
shared_info->set_never_compiled(true);
|
||||
shared_info->set_kind(lit->kind());
|
||||
if (!IsConstructable(lit->kind(), lit->language_mode())) {
|
||||
shared_info->set_construct_stub(
|
||||
shared_info->SetConstructStub(
|
||||
*shared_info->GetIsolate()->builtins()->ConstructedNonConstructable());
|
||||
}
|
||||
shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
|
||||
@ -13263,6 +13263,10 @@ bool SharedFunctionInfo::VerifyBailoutId(BailoutId id) {
|
||||
return true; // Return true if there was no DCHECK.
|
||||
}
|
||||
|
||||
void SharedFunctionInfo::SetConstructStub(Code* code) {
|
||||
if (code->kind() == Code::BUILTIN) code->set_is_construct_stub(true);
|
||||
set_construct_stub(code);
|
||||
}
|
||||
|
||||
void Map::StartInobjectSlackTracking() {
|
||||
DCHECK(!IsInobjectSlackTrackingInProgress());
|
||||
|
@ -5063,6 +5063,12 @@ class Code: public HeapObject {
|
||||
inline bool can_have_weak_objects();
|
||||
inline void set_can_have_weak_objects(bool value);
|
||||
|
||||
// [is_construct_stub]: For kind BUILTIN, tells whether the code object
|
||||
// represents a hand-written construct stub
|
||||
// (e.g., NumberConstructor_ConstructStub).
|
||||
inline bool is_construct_stub();
|
||||
inline void set_is_construct_stub(bool value);
|
||||
|
||||
// [has_deoptimization_support]: For FUNCTION kind, tells if it has
|
||||
// deoptimization support.
|
||||
inline bool has_deoptimization_support();
|
||||
@ -5398,9 +5404,11 @@ class Code: public HeapObject {
|
||||
kStackSlotsFirstBit + kStackSlotsBitCount;
|
||||
static const int kIsTurbofannedBit = kMarkedForDeoptimizationBit + 1;
|
||||
static const int kCanHaveWeakObjects = kIsTurbofannedBit + 1;
|
||||
// Could be moved to overlap previous bits when we need more space.
|
||||
static const int kIsConstructStub = kCanHaveWeakObjects + 1;
|
||||
|
||||
STATIC_ASSERT(kStackSlotsFirstBit + kStackSlotsBitCount <= 32);
|
||||
STATIC_ASSERT(kCanHaveWeakObjects + 1 <= 32);
|
||||
STATIC_ASSERT(kIsConstructStub + 1 <= 32);
|
||||
|
||||
class StackSlotsField: public BitField<int,
|
||||
kStackSlotsFirstBit, kStackSlotsBitCount> {}; // NOLINT
|
||||
@ -5410,6 +5418,8 @@ class Code: public HeapObject {
|
||||
}; // NOLINT
|
||||
class CanHaveWeakObjectsField
|
||||
: public BitField<bool, kCanHaveWeakObjects, 1> {}; // NOLINT
|
||||
class IsConstructStubField : public BitField<bool, kIsConstructStub, 1> {
|
||||
}; // NOLINT
|
||||
|
||||
// KindSpecificFlags2 layout (ALL)
|
||||
static const int kIsCrankshaftedBit = 0;
|
||||
@ -6878,6 +6888,10 @@ class SharedFunctionInfo: public HeapObject {
|
||||
// [construct stub]: Code stub for constructing instances of this function.
|
||||
DECL_ACCESSORS(construct_stub, Code)
|
||||
|
||||
// Sets the given code as the construct stub, and marks builtin code objects
|
||||
// as a construct stub.
|
||||
void SetConstructStub(Code* code);
|
||||
|
||||
// Returns if this function has been compiled to native code yet.
|
||||
inline bool is_compiled();
|
||||
|
||||
|
@ -130,7 +130,7 @@ static MaybeHandle<Object> DefineClass(Isolate* isolate,
|
||||
// constructor. Hence we can reuse the builtins construct stub for derived
|
||||
// classes.
|
||||
Handle<Code> stub(isolate->builtins()->JSBuiltinsConstructStubForDerived());
|
||||
constructor->shared()->set_construct_stub(*stub);
|
||||
constructor->shared()->SetConstructStub(*stub);
|
||||
}
|
||||
|
||||
JSFunction::SetPrototype(constructor, prototype);
|
||||
|
@ -49,7 +49,7 @@ RUNTIME_FUNCTION(Runtime_FunctionRemovePrototype) {
|
||||
|
||||
CONVERT_ARG_CHECKED(JSFunction, f, 0);
|
||||
CHECK(f->RemovePrototype());
|
||||
f->shared()->set_construct_stub(
|
||||
f->shared()->SetConstructStub(
|
||||
*isolate->builtins()->ConstructedNonConstructable());
|
||||
|
||||
return isolate->heap()->undefined_value();
|
||||
|
@ -33,12 +33,10 @@ testBuiltinInStackTrace("Date.prototype.getUTCDate.call('')",
|
||||
"at String.getUTCDate");
|
||||
testBuiltinInStackTrace("Date.prototype.getTime.call('')", "at String.getTime");
|
||||
|
||||
// TODO(jgruber): These use a more generic expected string until detection of
|
||||
// assembly builtin constructors is fixed.
|
||||
testBuiltinInStackTrace("Number(thrower);", "Number");
|
||||
testBuiltinInStackTrace("new Number(thrower);", "Number");
|
||||
testBuiltinInStackTrace("String(thrower);", "String");
|
||||
testBuiltinInStackTrace("new String(thrower);", "String");
|
||||
testBuiltinInStackTrace("Number(thrower);", "at Number");
|
||||
testBuiltinInStackTrace("new Number(thrower);", "at new Number");
|
||||
testBuiltinInStackTrace("String(thrower);", "at String");
|
||||
testBuiltinInStackTrace("new String(thrower);", "at new String");
|
||||
|
||||
// Ensure we correctly pick up the receiver's string tag.
|
||||
testBuiltinInStackTrace("Math.acos(thrower);", "at Math.acos");
|
||||
|
Loading…
Reference in New Issue
Block a user