[wasm] Provide correct eval origin for asm.js code

This CL moves all methods related to scripts and eval origin (HasScript,
GetScript, IsEval, GetEvalOrigin) from JSStackFrame to StackFrameBase,
because it also applies to WasmFrames.
This makes the AppendFileLocation method append the same information to
WasmStackFrames and AsmJsWasmStackFrames than to JSStackFrames.

R=titzer@chromium.org, mstarzinger@chromium.org
BUG=v8:4203

Review-Url: https://codereview.chromium.org/2557923005
Cr-Commit-Position: refs/heads/master@{#41642}
This commit is contained in:
clemensh 2016-12-12 05:31:16 -08:00 committed by Commit bot
parent 9b6808bfb5
commit c4057d4645
3 changed files with 145 additions and 125 deletions

View File

@ -165,6 +165,115 @@ std::unique_ptr<char[]> MessageHandler::GetLocalizedMessage(
return GetMessage(isolate, data)->ToCString(DISALLOW_NULLS);
}
namespace {
Object* EvalFromFunctionName(Isolate* isolate, Handle<Script> script) {
if (script->eval_from_shared()->IsUndefined(isolate))
return isolate->heap()->undefined_value();
Handle<SharedFunctionInfo> shared(
SharedFunctionInfo::cast(script->eval_from_shared()));
// Find the name of the function calling eval.
if (shared->name()->BooleanValue()) {
return shared->name();
}
return shared->inferred_name();
}
Object* EvalFromScript(Isolate* isolate, Handle<Script> script) {
if (script->eval_from_shared()->IsUndefined(isolate))
return isolate->heap()->undefined_value();
Handle<SharedFunctionInfo> eval_from_shared(
SharedFunctionInfo::cast(script->eval_from_shared()));
return eval_from_shared->script()->IsScript()
? eval_from_shared->script()
: isolate->heap()->undefined_value();
}
MaybeHandle<String> FormatEvalOrigin(Isolate* isolate, Handle<Script> script) {
Handle<Object> sourceURL(script->GetNameOrSourceURL(), isolate);
if (!sourceURL->IsUndefined(isolate)) {
DCHECK(sourceURL->IsString());
return Handle<String>::cast(sourceURL);
}
IncrementalStringBuilder builder(isolate);
builder.AppendCString("eval at ");
Handle<Object> eval_from_function_name =
handle(EvalFromFunctionName(isolate, script), isolate);
if (eval_from_function_name->BooleanValue()) {
Handle<String> str;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, str, Object::ToString(isolate, eval_from_function_name),
String);
builder.AppendString(str);
} else {
builder.AppendCString("<anonymous>");
}
Handle<Object> eval_from_script_obj =
handle(EvalFromScript(isolate, script), isolate);
if (eval_from_script_obj->IsScript()) {
Handle<Script> eval_from_script =
Handle<Script>::cast(eval_from_script_obj);
builder.AppendCString(" (");
if (eval_from_script->compilation_type() == Script::COMPILATION_TYPE_EVAL) {
// Eval script originated from another eval.
Handle<String> str;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, str, FormatEvalOrigin(isolate, eval_from_script), String);
builder.AppendString(str);
} else {
DCHECK(eval_from_script->compilation_type() !=
Script::COMPILATION_TYPE_EVAL);
// eval script originated from "real" source.
Handle<Object> name_obj = handle(eval_from_script->name(), isolate);
if (eval_from_script->name()->IsString()) {
builder.AppendString(Handle<String>::cast(name_obj));
Script::PositionInfo info;
if (Script::GetPositionInfo(eval_from_script, script->GetEvalPosition(),
&info, Script::NO_OFFSET)) {
builder.AppendCString(":");
Handle<String> str = isolate->factory()->NumberToString(
handle(Smi::FromInt(info.line + 1), isolate));
builder.AppendString(str);
builder.AppendCString(":");
str = isolate->factory()->NumberToString(
handle(Smi::FromInt(info.column + 1), isolate));
builder.AppendString(str);
}
} else {
DCHECK(!eval_from_script->name()->IsString());
builder.AppendCString("unknown source");
}
}
builder.AppendCString(")");
}
Handle<String> result;
ASSIGN_RETURN_ON_EXCEPTION(isolate, result, builder.Finish(), String);
return result;
}
} // namespace
Handle<Object> StackFrameBase::GetEvalOrigin() {
if (!HasScript()) return isolate_->factory()->undefined_value();
return FormatEvalOrigin(isolate_, GetScript()).ToHandleChecked();
}
bool StackFrameBase::IsEval() {
return HasScript() &&
GetScript()->compilation_type() == Script::COMPILATION_TYPE_EVAL;
}
void JSStackFrame::FromFrameArray(Isolate* isolate, Handle<FrameArray> array,
int frame_ix) {
DCHECK(!array->IsWasmFrame(frame_ix));
@ -179,10 +288,12 @@ void JSStackFrame::FromFrameArray(Isolate* isolate, Handle<FrameArray> array,
is_strict_ = (flags & FrameArray::kIsStrict) != 0;
}
JSStackFrame::JSStackFrame() {}
JSStackFrame::JSStackFrame(Isolate* isolate, Handle<Object> receiver,
Handle<JSFunction> function,
Handle<AbstractCode> code, int offset)
: isolate_(isolate),
: StackFrameBase(isolate),
receiver_(receiver),
function_(function),
code_(code),
@ -190,8 +301,6 @@ JSStackFrame::JSStackFrame(Isolate* isolate, Handle<Object> receiver,
force_constructor_(false),
is_strict_(false) {}
JSStackFrame::JSStackFrame() {}
Handle<Object> JSStackFrame::GetFunction() const {
return Handle<Object>::cast(function_);
}
@ -298,105 +407,6 @@ Handle<Object> JSStackFrame::GetMethodName() {
return isolate_->factory()->null_value();
}
namespace {
Object* EvalFromFunctionName(Isolate* isolate, Handle<Script> script) {
if (script->eval_from_shared()->IsUndefined(isolate))
return isolate->heap()->undefined_value();
Handle<SharedFunctionInfo> shared(
SharedFunctionInfo::cast(script->eval_from_shared()));
// Find the name of the function calling eval.
if (shared->name()->BooleanValue()) {
return shared->name();
}
return shared->inferred_name();
}
Object* EvalFromScript(Isolate* isolate, Handle<Script> script) {
if (script->eval_from_shared()->IsUndefined(isolate))
return isolate->heap()->undefined_value();
Handle<SharedFunctionInfo> eval_from_shared(
SharedFunctionInfo::cast(script->eval_from_shared()));
return eval_from_shared->script()->IsScript()
? eval_from_shared->script()
: isolate->heap()->undefined_value();
}
MaybeHandle<String> FormatEvalOrigin(Isolate* isolate, Handle<Script> script) {
Handle<Object> sourceURL(script->GetNameOrSourceURL(), isolate);
if (!sourceURL->IsUndefined(isolate)) {
DCHECK(sourceURL->IsString());
return Handle<String>::cast(sourceURL);
}
IncrementalStringBuilder builder(isolate);
builder.AppendCString("eval at ");
Handle<Object> eval_from_function_name =
handle(EvalFromFunctionName(isolate, script), isolate);
if (eval_from_function_name->BooleanValue()) {
Handle<String> str;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, str, Object::ToString(isolate, eval_from_function_name),
String);
builder.AppendString(str);
} else {
builder.AppendCString("<anonymous>");
}
Handle<Object> eval_from_script_obj =
handle(EvalFromScript(isolate, script), isolate);
if (eval_from_script_obj->IsScript()) {
Handle<Script> eval_from_script =
Handle<Script>::cast(eval_from_script_obj);
builder.AppendCString(" (");
if (eval_from_script->compilation_type() == Script::COMPILATION_TYPE_EVAL) {
// Eval script originated from another eval.
Handle<String> str;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, str, FormatEvalOrigin(isolate, eval_from_script), String);
builder.AppendString(str);
} else {
DCHECK(eval_from_script->compilation_type() !=
Script::COMPILATION_TYPE_EVAL);
// eval script originated from "real" source.
Handle<Object> name_obj = handle(eval_from_script->name(), isolate);
if (eval_from_script->name()->IsString()) {
builder.AppendString(Handle<String>::cast(name_obj));
Script::PositionInfo info;
if (Script::GetPositionInfo(eval_from_script, script->GetEvalPosition(),
&info, Script::NO_OFFSET)) {
builder.AppendCString(":");
Handle<String> str = isolate->factory()->NumberToString(
handle(Smi::FromInt(info.line + 1), isolate));
builder.AppendString(str);
builder.AppendCString(":");
str = isolate->factory()->NumberToString(
handle(Smi::FromInt(info.column + 1), isolate));
builder.AppendString(str);
}
} else {
DCHECK(!eval_from_script->name()->IsString());
builder.AppendCString("unknown source");
}
}
builder.AppendCString(")");
}
Handle<String> result;
ASSIGN_RETURN_ON_EXCEPTION(isolate, result, builder.Finish(), String);
return result;
}
} // namespace
Handle<Object> JSStackFrame::GetTypeName() {
// TODO(jgruber): Check for strict/constructor here as in
// CallSitePrototypeGetThis.
@ -411,11 +421,6 @@ Handle<Object> JSStackFrame::GetTypeName() {
return JSReceiver::GetConstructorName(receiver_object);
}
Handle<Object> JSStackFrame::GetEvalOrigin() {
if (!HasScript()) return isolate_->factory()->undefined_value();
return FormatEvalOrigin(isolate_, GetScript()).ToHandleChecked();
}
int JSStackFrame::GetLineNumber() {
DCHECK_LE(0, GetPosition());
if (HasScript()) return Script::GetLineNumber(GetScript(), GetPosition()) + 1;
@ -439,11 +444,6 @@ bool JSStackFrame::IsToplevel() {
receiver_->IsUndefined(isolate_);
}
bool JSStackFrame::IsEval() {
return HasScript() &&
GetScript()->compilation_type() == Script::COMPILATION_TYPE_EVAL;
}
bool JSStackFrame::IsConstructor() {
if (force_constructor_) return true;
if (!receiver_->IsJSObject()) return false;
@ -619,6 +619,8 @@ Handle<Script> JSStackFrame::GetScript() const {
return handle(Script::cast(function_->shared()->script()), isolate_);
}
WasmStackFrame::WasmStackFrame() {}
void WasmStackFrame::FromFrameArray(Isolate* isolate, Handle<FrameArray> array,
int frame_ix) {
// This function is called for both wasm and asm.js->wasm frames.
@ -681,6 +683,16 @@ Handle<Object> WasmStackFrame::Null() const {
return isolate_->factory()->null_value();
}
bool WasmStackFrame::HasScript() const { return true; }
Handle<Script> WasmStackFrame::GetScript() const {
return WasmInstanceObject::cast(*wasm_instance_)
->get_compiled_module()
->script();
}
AsmJsWasmStackFrame::AsmJsWasmStackFrame() {}
void AsmJsWasmStackFrame::FromFrameArray(Isolate* isolate,
Handle<FrameArray> array,
int frame_ix) {

View File

@ -56,7 +56,7 @@ class StackFrameBase {
virtual Handle<Object> GetScriptNameOrSourceUrl() = 0;
virtual Handle<Object> GetMethodName() = 0;
virtual Handle<Object> GetTypeName() = 0;
virtual Handle<Object> GetEvalOrigin() = 0;
virtual Handle<Object> GetEvalOrigin();
virtual int GetPosition() const = 0;
// Return 1-based line number, including line offset.
@ -66,11 +66,20 @@ class StackFrameBase {
virtual bool IsNative() = 0;
virtual bool IsToplevel() = 0;
virtual bool IsEval() = 0;
virtual bool IsEval();
virtual bool IsConstructor() = 0;
virtual bool IsStrict() const = 0;
virtual MaybeHandle<String> ToString() = 0;
protected:
StackFrameBase() {}
explicit StackFrameBase(Isolate* isolate) : isolate_(isolate) {}
Isolate* isolate_;
private:
virtual bool HasScript() const = 0;
virtual Handle<Script> GetScript() const = 0;
};
class JSStackFrame : public StackFrameBase {
@ -88,7 +97,6 @@ class JSStackFrame : public StackFrameBase {
Handle<Object> GetScriptNameOrSourceUrl() override;
Handle<Object> GetMethodName() override;
Handle<Object> GetTypeName() override;
Handle<Object> GetEvalOrigin() override;
int GetPosition() const override;
int GetLineNumber() override;
@ -96,7 +104,6 @@ class JSStackFrame : public StackFrameBase {
bool IsNative() override;
bool IsToplevel() override;
bool IsEval() override;
bool IsConstructor() override;
bool IsStrict() const override { return is_strict_; }
@ -106,10 +113,8 @@ class JSStackFrame : public StackFrameBase {
JSStackFrame();
void FromFrameArray(Isolate* isolate, Handle<FrameArray> array, int frame_ix);
bool HasScript() const;
Handle<Script> GetScript() const;
Isolate* isolate_;
bool HasScript() const override;
Handle<Script> GetScript() const override;
Handle<Object> receiver_;
Handle<JSFunction> function_;
@ -134,7 +139,6 @@ class WasmStackFrame : public StackFrameBase {
Handle<Object> GetScriptNameOrSourceUrl() override { return Null(); }
Handle<Object> GetMethodName() override { return Null(); }
Handle<Object> GetTypeName() override { return Null(); }
Handle<Object> GetEvalOrigin() override { return Null(); }
int GetPosition() const override;
int GetLineNumber() override { return wasm_func_index_; }
@ -142,7 +146,6 @@ class WasmStackFrame : public StackFrameBase {
bool IsNative() override { return false; }
bool IsToplevel() override { return false; }
bool IsEval() override { return false; }
bool IsConstructor() override { return false; }
bool IsStrict() const override { return false; }
@ -151,7 +154,8 @@ class WasmStackFrame : public StackFrameBase {
protected:
Handle<Object> Null() const;
Isolate* isolate_;
bool HasScript() const override;
Handle<Script> GetScript() const override;
// TODO(wasm): Use proper typing.
Handle<Object> wasm_instance_;
@ -160,6 +164,7 @@ class WasmStackFrame : public StackFrameBase {
int offset_;
private:
WasmStackFrame();
void FromFrameArray(Isolate* isolate, Handle<FrameArray> array, int frame_ix);
friend class FrameArrayIterator;
@ -184,6 +189,7 @@ class AsmJsWasmStackFrame : public WasmStackFrame {
private:
friend class FrameArrayIterator;
AsmJsWasmStackFrame();
void FromFrameArray(Isolate* isolate, Handle<FrameArray> array, int frame_ix);
bool is_at_number_conversion_;

View File

@ -80,7 +80,8 @@ function testAll(expected_stack, expected_frames, input) {
var expected_stack = [
'^Error: user-thrown$',
'^ *at sym \\(' + filename + ':\\d+:9\\)$',
'^ *at callSym \\(.*<anonymous>:\\d+:12\\)$',
'^ *at callSym \\(eval at testHelper \\(' + filename +
':\\d+:19\\), <anonymous>:\\d+:12\\)$',
];
var expected_frames = [
// function pos
@ -94,7 +95,8 @@ function testAll(expected_stack, expected_frames, input) {
(function testStackForThrowAtConversion() {
var expected_stack = [
'^TypeError: Cannot convert a Symbol value to a number$',
'^ *at callSym \\(.*<anonymous>:\\d+:21\\)$',
'^ *at callSym \\(eval at testHelper \\(' + filename +
':\\d+:19\\), <anonymous>:\\d+:21\\)$',
];
var expected_frames = [
// function pos