Commit e47f37eb authored by Michael Starzinger's avatar Michael Starzinger Committed by Commit Bot

[runtime] Fix detection of construct frames in stack traces.

This removes the heuristic from {JSStackFrame::IsConstructor} that tried
to infer whether a frame was called as a constructor or not from the
receiver value. We are now carrying along the appropriate bit derived
from the frame type instead.

R=jgruber@chromium.org
TEST=message/regress/regress-5727
BUG=v8:5727

Change-Id: I0e2f1d0f95485c84c4ebcd3cbfe0123c6afd2e01
Reviewed-on: https://chromium-review.googlesource.com/500313
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#45972}
parent d5dd51ae
...@@ -518,18 +518,18 @@ Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object, ...@@ -518,18 +518,18 @@ Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object,
Handle<AbstractCode> abstract_code = summ.abstract_code(); Handle<AbstractCode> abstract_code = summ.abstract_code();
const int offset = frames[i].code_offset(); const int offset = frames[i].code_offset();
bool force_constructor = false; bool is_constructor = frames[i].is_constructor();
if (frame->type() == StackFrame::BUILTIN) { if (frame->type() == StackFrame::BUILTIN) {
// Help CallSite::IsConstructor correctly detect hand-written // Help CallSite::IsConstructor correctly detect hand-written
// construct stubs. // construct stubs.
if (Code::cast(*abstract_code)->is_construct_stub()) { if (Code::cast(*abstract_code)->is_construct_stub()) {
force_constructor = true; is_constructor = true;
} }
} }
int flags = 0; int flags = 0;
if (helper.IsStrictFrame(*fun)) flags |= FrameArray::kIsStrict; if (helper.IsStrictFrame(*fun)) flags |= FrameArray::kIsStrict;
if (force_constructor) flags |= FrameArray::kForceConstructor; if (is_constructor) flags |= FrameArray::kIsConstructor;
elements = FrameArray::AppendJSFrame( elements = FrameArray::AppendJSFrame(
elements, TheHoleToUndefined(this, recv), fun, abstract_code, elements, TheHoleToUndefined(this, recv), fun, abstract_code,
...@@ -551,7 +551,7 @@ Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object, ...@@ -551,7 +551,7 @@ Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object,
int flags = 0; int flags = 0;
if (helper.IsStrictFrame(*fun)) flags |= FrameArray::kIsStrict; if (helper.IsStrictFrame(*fun)) flags |= FrameArray::kIsStrict;
if (exit_frame->IsConstructor()) flags |= FrameArray::kForceConstructor; if (exit_frame->IsConstructor()) flags |= FrameArray::kIsConstructor;
elements = FrameArray::AppendJSFrame(elements, recv, fun, elements = FrameArray::AppendJSFrame(elements, recv, fun,
Handle<AbstractCode>::cast(code), Handle<AbstractCode>::cast(code),
......
...@@ -302,7 +302,7 @@ void JSStackFrame::FromFrameArray(Isolate* isolate, Handle<FrameArray> array, ...@@ -302,7 +302,7 @@ void JSStackFrame::FromFrameArray(Isolate* isolate, Handle<FrameArray> array,
offset_ = array->Offset(frame_ix)->value(); offset_ = array->Offset(frame_ix)->value();
const int flags = array->Flags(frame_ix)->value(); const int flags = array->Flags(frame_ix)->value();
force_constructor_ = (flags & FrameArray::kForceConstructor) != 0; is_constructor_ = (flags & FrameArray::kIsConstructor) != 0;
is_strict_ = (flags & FrameArray::kIsStrict) != 0; is_strict_ = (flags & FrameArray::kIsStrict) != 0;
} }
...@@ -316,7 +316,7 @@ JSStackFrame::JSStackFrame(Isolate* isolate, Handle<Object> receiver, ...@@ -316,7 +316,7 @@ JSStackFrame::JSStackFrame(Isolate* isolate, Handle<Object> receiver,
function_(function), function_(function),
code_(code), code_(code),
offset_(offset), offset_(offset),
force_constructor_(false), is_constructor_(false),
is_strict_(false) {} is_strict_(false) {}
Handle<Object> JSStackFrame::GetFunction() const { Handle<Object> JSStackFrame::GetFunction() const {
...@@ -458,15 +458,6 @@ bool JSStackFrame::IsToplevel() { ...@@ -458,15 +458,6 @@ bool JSStackFrame::IsToplevel() {
return receiver_->IsJSGlobalProxy() || receiver_->IsNullOrUndefined(isolate_); return receiver_->IsJSGlobalProxy() || receiver_->IsNullOrUndefined(isolate_);
} }
bool JSStackFrame::IsConstructor() {
if (force_constructor_) return true;
if (!receiver_->IsJSObject()) return false;
Handle<Object> constructor =
JSReceiver::GetDataProperty(Handle<JSObject>::cast(receiver_),
isolate_->factory()->constructor_string());
return constructor.is_identical_to(function_);
}
namespace { namespace {
bool IsNonEmptyString(Handle<Object> object) { bool IsNonEmptyString(Handle<Object> object) {
......
...@@ -106,7 +106,7 @@ class JSStackFrame : public StackFrameBase { ...@@ -106,7 +106,7 @@ class JSStackFrame : public StackFrameBase {
bool IsNative() override; bool IsNative() override;
bool IsToplevel() override; bool IsToplevel() override;
bool IsConstructor() override; bool IsConstructor() override { return is_constructor_; }
bool IsStrict() const override { return is_strict_; } bool IsStrict() const override { return is_strict_; }
MaybeHandle<String> ToString() override; MaybeHandle<String> ToString() override;
...@@ -123,7 +123,7 @@ class JSStackFrame : public StackFrameBase { ...@@ -123,7 +123,7 @@ class JSStackFrame : public StackFrameBase {
Handle<AbstractCode> code_; Handle<AbstractCode> code_;
int offset_; int offset_;
bool force_constructor_; bool is_constructor_;
bool is_strict_; bool is_strict_;
friend class FrameArrayIterator; friend class FrameArrayIterator;
......
...@@ -48,7 +48,7 @@ class FrameArray : public FixedArray { ...@@ -48,7 +48,7 @@ class FrameArray : public FixedArray {
kIsWasmInterpretedFrame = 1 << 1, kIsWasmInterpretedFrame = 1 << 1,
kIsAsmJsWasmFrame = 1 << 2, kIsAsmJsWasmFrame = 1 << 2,
kIsStrict = 1 << 3, kIsStrict = 1 << 3,
kForceConstructor = 1 << 4, kIsConstructor = 1 << 4,
kAsmJsAtNumberConversion = 1 << 5 kAsmJsAtNumberConversion = 1 << 5
}; };
......
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
function Foo(do_throw) {
if (do_throw) throw new Error("get me outta here");
}
var foo = new Foo(false);
(function caller() {
Foo.call(foo, true);
})();
# Copyright 2017 the V8 project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
*%(basename)s:6: Error: get me outta here
if (do_throw) throw new Error("get me outta here");
^
Error: get me outta here
at Foo (*%(basename)s:6:23)
at caller (*%(basename)s:10:7)
at *%(basename)s:11:3
...@@ -46,7 +46,8 @@ function getStack(error) { ...@@ -46,7 +46,8 @@ function getStack(error) {
filter(function(line) { filter(function(line) {
return /^\s*at @?[a-zA-Z0-9_]/.test(line); return /^\s*at @?[a-zA-Z0-9_]/.test(line);
}). }).
map(line => line.replace(/^\s*at (@?[a-zA-Z0-9_\.\[\]]+)(.*)/, "$1")); map(line =>
line.replace(/^\s*at (@?(?:new )?[a-zA-Z0-9_\.\[\]]+)(.*)/, "$1"));
// remove `Promise.then()` invocation by assertEqualsAsync() // remove `Promise.then()` invocation by assertEqualsAsync()
if (stack[2] === "assertEqualsAsync") return []; if (stack[2] === "assertEqualsAsync") return [];
...@@ -96,6 +97,6 @@ assertEqualsAsync( ...@@ -96,6 +97,6 @@ assertEqualsAsync(
}), }),
"should call Promise[@@Species] after non-internal Then"); "should call Promise[@@Species] after non-internal Then");
assertEquals([ assertEquals([
"@@Species: [@testThenOnReturnedPromise > Promise.then > FakePromise]", "@@Species: [@testThenOnReturnedPromise > Promise.then > new FakePromise]",
"Then: foo" "Then: foo"
], log); ], log);
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