Reland "[compiler] Don't collect source positions for the top frame"
Fixed crashes by adding missing call to EnsureSourcePositionsAvailable, which requires clearing and restoring the pending exception. > While most source positions were not collected even throwing exceptions, > the top frame still was always collected as it was used to initialize > the JSMessageObject. This skips even that frame, by storing the > SharedFunctionInfo and bytecode offset in the JSMessageObject allowing > it to lazily evaluate the actual source position. > > Also adds tests to test-api.cc that test each of the source position > functions in isolation to ensure that they don't rely on previous > invocations to call the source collection function. > > Since no source positions are now collected at the point when an > exception is thrown, the mjsunit/stack-traces-overflow now passes again > with the flag enabled. (cctest/test-cpu-profiler/Inlining2 is now the > only failure). Bug: v8:8510 Change-Id: Ifa5fe31d3db34a6c6d6a9cef3d646ad620dabd81 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1601270 Commit-Queue: Dan Elphick <delphick@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org> Cr-Commit-Position: refs/heads/master@{#61372}
This commit is contained in:
parent
7dc6afd498
commit
f2e652264d
32
src/api.cc
32
src/api.cc
@ -2857,20 +2857,28 @@ Maybe<int> Message::GetLineNumber(Local<Context> context) const {
|
|||||||
i::Isolate* isolate = self->GetIsolate();
|
i::Isolate* isolate = self->GetIsolate();
|
||||||
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
|
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
|
||||||
EscapableHandleScope handle_scope(reinterpret_cast<Isolate*>(isolate));
|
EscapableHandleScope handle_scope(reinterpret_cast<Isolate*>(isolate));
|
||||||
auto msg = i::Handle<i::JSMessageObject>::cast(self);
|
i::JSMessageObject::EnsureSourcePositionsAvailable(isolate, self);
|
||||||
return Just(msg->GetLineNumber());
|
return Just(self->GetLineNumber());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int Message::GetStartPosition() const {
|
int Message::GetStartPosition() const {
|
||||||
auto self = Utils::OpenHandle(this);
|
auto self = Utils::OpenHandle(this);
|
||||||
return self->start_position();
|
i::Isolate* isolate = self->GetIsolate();
|
||||||
|
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
|
||||||
|
EscapableHandleScope handle_scope(reinterpret_cast<Isolate*>(isolate));
|
||||||
|
i::JSMessageObject::EnsureSourcePositionsAvailable(isolate, self);
|
||||||
|
return self->GetStartPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int Message::GetEndPosition() const {
|
int Message::GetEndPosition() const {
|
||||||
auto self = Utils::OpenHandle(this);
|
auto self = Utils::OpenHandle(this);
|
||||||
return self->end_position();
|
i::Isolate* isolate = self->GetIsolate();
|
||||||
|
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
|
||||||
|
EscapableHandleScope handle_scope(reinterpret_cast<Isolate*>(isolate));
|
||||||
|
i::JSMessageObject::EnsureSourcePositionsAvailable(isolate, self);
|
||||||
|
return self->GetEndPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Message::ErrorLevel() const {
|
int Message::ErrorLevel() const {
|
||||||
@ -2883,8 +2891,8 @@ int Message::GetStartColumn() const {
|
|||||||
i::Isolate* isolate = self->GetIsolate();
|
i::Isolate* isolate = self->GetIsolate();
|
||||||
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
|
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
|
||||||
EscapableHandleScope handle_scope(reinterpret_cast<Isolate*>(isolate));
|
EscapableHandleScope handle_scope(reinterpret_cast<Isolate*>(isolate));
|
||||||
auto msg = i::Handle<i::JSMessageObject>::cast(self);
|
i::JSMessageObject::EnsureSourcePositionsAvailable(isolate, self);
|
||||||
return msg->GetColumnNumber();
|
return self->GetColumnNumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
Maybe<int> Message::GetStartColumn(Local<Context> context) const {
|
Maybe<int> Message::GetStartColumn(Local<Context> context) const {
|
||||||
@ -2896,11 +2904,11 @@ int Message::GetEndColumn() const {
|
|||||||
i::Isolate* isolate = self->GetIsolate();
|
i::Isolate* isolate = self->GetIsolate();
|
||||||
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
|
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
|
||||||
EscapableHandleScope handle_scope(reinterpret_cast<Isolate*>(isolate));
|
EscapableHandleScope handle_scope(reinterpret_cast<Isolate*>(isolate));
|
||||||
auto msg = i::Handle<i::JSMessageObject>::cast(self);
|
i::JSMessageObject::EnsureSourcePositionsAvailable(isolate, self);
|
||||||
const int column_number = msg->GetColumnNumber();
|
const int column_number = self->GetColumnNumber();
|
||||||
if (column_number == -1) return -1;
|
if (column_number == -1) return -1;
|
||||||
const int start = self->start_position();
|
const int start = self->GetStartPosition();
|
||||||
const int end = self->end_position();
|
const int end = self->GetEndPosition();
|
||||||
return column_number + (end - start);
|
return column_number + (end - start);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2930,8 +2938,8 @@ MaybeLocal<String> Message::GetSourceLine(Local<Context> context) const {
|
|||||||
i::Isolate* isolate = self->GetIsolate();
|
i::Isolate* isolate = self->GetIsolate();
|
||||||
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
|
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
|
||||||
EscapableHandleScope handle_scope(reinterpret_cast<Isolate*>(isolate));
|
EscapableHandleScope handle_scope(reinterpret_cast<Isolate*>(isolate));
|
||||||
auto msg = i::Handle<i::JSMessageObject>::cast(self);
|
i::JSMessageObject::EnsureSourcePositionsAvailable(isolate, self);
|
||||||
RETURN_ESCAPED(Utils::ToLocal(msg->GetSourceLine()));
|
RETURN_ESCAPED(Utils::ToLocal(self->GetSourceLine()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -321,8 +321,11 @@ extern class JSMessageObject extends JSObject {
|
|||||||
arguments: Object;
|
arguments: Object;
|
||||||
script: Script;
|
script: Script;
|
||||||
stack_frames: Object;
|
stack_frames: Object;
|
||||||
|
shared_info: SharedFunctionInfo | Undefined;
|
||||||
|
|
||||||
// Raw data fields.
|
// Raw data fields.
|
||||||
// TODO(ishell): store as int32 instead of Smi.
|
// TODO(ishell): store as int32 instead of Smi.
|
||||||
|
bytecode_offset: Smi;
|
||||||
start_position: Smi;
|
start_position: Smi;
|
||||||
end_position: Smi;
|
end_position: Smi;
|
||||||
error_level: Smi;
|
error_level: Smi;
|
||||||
|
@ -1338,11 +1338,23 @@ void FrameSummary::EnsureSourcePositionsAvailable() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FrameSummary::AreSourcePositionsAvailable() const {
|
||||||
|
if (IsJavaScript()) {
|
||||||
|
return java_script_summary_.AreSourcePositionsAvailable();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void FrameSummary::JavaScriptFrameSummary::EnsureSourcePositionsAvailable() {
|
void FrameSummary::JavaScriptFrameSummary::EnsureSourcePositionsAvailable() {
|
||||||
Handle<SharedFunctionInfo> shared(function()->shared(), isolate());
|
Handle<SharedFunctionInfo> shared(function()->shared(), isolate());
|
||||||
SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate(), shared);
|
SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate(), shared);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FrameSummary::JavaScriptFrameSummary::AreSourcePositionsAvailable() const {
|
||||||
|
return !FLAG_enable_lazy_source_positions ||
|
||||||
|
function()->shared()->GetBytecodeArray()->HasSourcePositionTable();
|
||||||
|
}
|
||||||
|
|
||||||
bool FrameSummary::JavaScriptFrameSummary::is_subject_to_debugging() const {
|
bool FrameSummary::JavaScriptFrameSummary::is_subject_to_debugging() const {
|
||||||
return function()->shared()->IsSubjectToDebugging();
|
return function()->shared()->IsSubjectToDebugging();
|
||||||
}
|
}
|
||||||
|
@ -483,6 +483,7 @@ class V8_EXPORT_PRIVATE FrameSummary {
|
|||||||
FixedArray parameters);
|
FixedArray parameters);
|
||||||
|
|
||||||
void EnsureSourcePositionsAvailable();
|
void EnsureSourcePositionsAvailable();
|
||||||
|
bool AreSourcePositionsAvailable() const;
|
||||||
|
|
||||||
Handle<Object> receiver() const { return receiver_; }
|
Handle<Object> receiver() const { return receiver_; }
|
||||||
Handle<JSFunction> function() const { return function_; }
|
Handle<JSFunction> function() const { return function_; }
|
||||||
@ -572,6 +573,7 @@ class V8_EXPORT_PRIVATE FrameSummary {
|
|||||||
static FrameSummary Get(const StandardFrame* frame, int index);
|
static FrameSummary Get(const StandardFrame* frame, int index);
|
||||||
|
|
||||||
void EnsureSourcePositionsAvailable();
|
void EnsureSourcePositionsAvailable();
|
||||||
|
bool AreSourcePositionsAvailable() const;
|
||||||
|
|
||||||
// Dispatched accessors.
|
// Dispatched accessors.
|
||||||
Handle<Object> receiver() const;
|
Handle<Object> receiver() const;
|
||||||
|
@ -3468,7 +3468,8 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfoForLiteral(
|
|||||||
|
|
||||||
Handle<JSMessageObject> Factory::NewJSMessageObject(
|
Handle<JSMessageObject> Factory::NewJSMessageObject(
|
||||||
MessageTemplate message, Handle<Object> argument, int start_position,
|
MessageTemplate message, Handle<Object> argument, int start_position,
|
||||||
int end_position, Handle<Script> script, Handle<Object> stack_frames) {
|
int end_position, Handle<SharedFunctionInfo> shared_info,
|
||||||
|
int bytecode_offset, Handle<Script> script, Handle<Object> stack_frames) {
|
||||||
Handle<Map> map = message_object_map();
|
Handle<Map> map = message_object_map();
|
||||||
Handle<JSMessageObject> message_obj(
|
Handle<JSMessageObject> message_obj(
|
||||||
JSMessageObject::cast(New(map, AllocationType::kYoung)), isolate());
|
JSMessageObject::cast(New(map, AllocationType::kYoung)), isolate());
|
||||||
@ -3481,6 +3482,23 @@ Handle<JSMessageObject> Factory::NewJSMessageObject(
|
|||||||
message_obj->set_start_position(start_position);
|
message_obj->set_start_position(start_position);
|
||||||
message_obj->set_end_position(end_position);
|
message_obj->set_end_position(end_position);
|
||||||
message_obj->set_script(*script);
|
message_obj->set_script(*script);
|
||||||
|
if (start_position >= 0) {
|
||||||
|
// If there's a start_position, then there's no need to store the
|
||||||
|
// SharedFunctionInfo as it will never be necessary to regenerate the
|
||||||
|
// position.
|
||||||
|
message_obj->set_shared_info(*undefined_value());
|
||||||
|
message_obj->set_bytecode_offset(Smi::FromInt(0));
|
||||||
|
} else {
|
||||||
|
message_obj->set_bytecode_offset(Smi::FromInt(bytecode_offset));
|
||||||
|
if (shared_info.is_null()) {
|
||||||
|
message_obj->set_shared_info(*undefined_value());
|
||||||
|
DCHECK_EQ(bytecode_offset, -1);
|
||||||
|
} else {
|
||||||
|
message_obj->set_shared_info(*shared_info);
|
||||||
|
DCHECK_GE(bytecode_offset, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
message_obj->set_stack_frames(*stack_frames);
|
message_obj->set_stack_frames(*stack_frames);
|
||||||
message_obj->set_error_level(v8::Isolate::kMessageError);
|
message_obj->set_error_level(v8::Isolate::kMessageError);
|
||||||
return message_obj;
|
return message_obj;
|
||||||
|
@ -885,7 +885,8 @@ class V8_EXPORT_PRIVATE Factory {
|
|||||||
// Allocates a new JSMessageObject object.
|
// Allocates a new JSMessageObject object.
|
||||||
Handle<JSMessageObject> NewJSMessageObject(
|
Handle<JSMessageObject> NewJSMessageObject(
|
||||||
MessageTemplate message, Handle<Object> argument, int start_position,
|
MessageTemplate message, Handle<Object> argument, int start_position,
|
||||||
int end_position, Handle<Script> script, Handle<Object> stack_frames);
|
int end_position, Handle<SharedFunctionInfo> shared_info,
|
||||||
|
int bytecode_offset, Handle<Script> script, Handle<Object> stack_frames);
|
||||||
|
|
||||||
Handle<ClassPositions> NewClassPositions(int start, int end);
|
Handle<ClassPositions> NewClassPositions(int start, int end);
|
||||||
Handle<DebugInfo> NewDebugInfo(Handle<SharedFunctionInfo> shared);
|
Handle<DebugInfo> NewDebugInfo(Handle<SharedFunctionInfo> shared);
|
||||||
|
@ -2069,8 +2069,6 @@ bool Isolate::ComputeLocation(MessageLocation* target) {
|
|||||||
wasm::WasmCodeRefScope code_ref_scope;
|
wasm::WasmCodeRefScope code_ref_scope;
|
||||||
frame->Summarize(&frames);
|
frame->Summarize(&frames);
|
||||||
FrameSummary& summary = frames.back();
|
FrameSummary& summary = frames.back();
|
||||||
summary.EnsureSourcePositionsAvailable();
|
|
||||||
int pos = summary.SourcePosition();
|
|
||||||
Handle<SharedFunctionInfo> shared;
|
Handle<SharedFunctionInfo> shared;
|
||||||
Handle<Object> script = summary.script();
|
Handle<Object> script = summary.script();
|
||||||
if (!script->IsScript() ||
|
if (!script->IsScript() ||
|
||||||
@ -2081,7 +2079,14 @@ bool Isolate::ComputeLocation(MessageLocation* target) {
|
|||||||
if (summary.IsJavaScript()) {
|
if (summary.IsJavaScript()) {
|
||||||
shared = handle(summary.AsJavaScript().function()->shared(), this);
|
shared = handle(summary.AsJavaScript().function()->shared(), this);
|
||||||
}
|
}
|
||||||
*target = MessageLocation(Handle<Script>::cast(script), pos, pos + 1, shared);
|
if (summary.AreSourcePositionsAvailable()) {
|
||||||
|
int pos = summary.SourcePosition();
|
||||||
|
*target =
|
||||||
|
MessageLocation(Handle<Script>::cast(script), pos, pos + 1, shared);
|
||||||
|
} else {
|
||||||
|
*target = MessageLocation(Handle<Script>::cast(script), shared,
|
||||||
|
summary.code_offset());
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2156,13 +2161,18 @@ bool Isolate::ComputeLocationFromStackTrace(MessageLocation* target,
|
|||||||
if (script->IsScript() &&
|
if (script->IsScript() &&
|
||||||
!(Script::cast(script)->source()->IsUndefined(this))) {
|
!(Script::cast(script)->source()->IsUndefined(this))) {
|
||||||
Handle<SharedFunctionInfo> shared = handle(fun->shared(), this);
|
Handle<SharedFunctionInfo> shared = handle(fun->shared(), this);
|
||||||
SharedFunctionInfo::EnsureSourcePositionsAvailable(this, shared);
|
|
||||||
AbstractCode abstract_code = elements->Code(i);
|
AbstractCode abstract_code = elements->Code(i);
|
||||||
const int code_offset = elements->Offset(i)->value();
|
const int code_offset = elements->Offset(i)->value();
|
||||||
const int pos = abstract_code->SourcePosition(code_offset);
|
|
||||||
|
|
||||||
Handle<Script> casted_script(Script::cast(script), this);
|
Handle<Script> casted_script(Script::cast(script), this);
|
||||||
*target = MessageLocation(casted_script, pos, pos + 1);
|
if (shared->HasBytecodeArray() &&
|
||||||
|
shared->GetBytecodeArray()->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 true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2278,8 +2288,13 @@ void Isolate::ReportPendingMessagesImpl(bool report_externally) {
|
|||||||
HandleScope scope(this);
|
HandleScope scope(this);
|
||||||
Handle<JSMessageObject> message(JSMessageObject::cast(message_obj), this);
|
Handle<JSMessageObject> message(JSMessageObject::cast(message_obj), this);
|
||||||
Handle<Script> script(message->script(), this);
|
Handle<Script> script(message->script(), this);
|
||||||
int start_pos = message->start_position();
|
// Clear the exception and restore it afterwards, otherwise
|
||||||
int end_pos = message->end_position();
|
// CollectSourcePositions will abort.
|
||||||
|
clear_pending_exception();
|
||||||
|
JSMessageObject::EnsureSourcePositionsAvailable(this, message);
|
||||||
|
set_pending_exception(exception);
|
||||||
|
int start_pos = message->GetStartPosition();
|
||||||
|
int end_pos = message->GetEndPosition();
|
||||||
MessageLocation location(script, start_pos, end_pos);
|
MessageLocation location(script, start_pos, end_pos);
|
||||||
MessageHandler::ReportMessage(this, &location, message);
|
MessageHandler::ReportMessage(this, &location, message);
|
||||||
}
|
}
|
||||||
|
@ -24,14 +24,30 @@ namespace internal {
|
|||||||
|
|
||||||
MessageLocation::MessageLocation(Handle<Script> script, int start_pos,
|
MessageLocation::MessageLocation(Handle<Script> script, int start_pos,
|
||||||
int end_pos)
|
int end_pos)
|
||||||
: script_(script), start_pos_(start_pos), end_pos_(end_pos) {}
|
: script_(script),
|
||||||
|
start_pos_(start_pos),
|
||||||
|
end_pos_(end_pos),
|
||||||
|
bytecode_offset_(-1) {}
|
||||||
|
|
||||||
MessageLocation::MessageLocation(Handle<Script> script, int start_pos,
|
MessageLocation::MessageLocation(Handle<Script> script, int start_pos,
|
||||||
int end_pos, Handle<SharedFunctionInfo> shared)
|
int end_pos, Handle<SharedFunctionInfo> shared)
|
||||||
: script_(script),
|
: script_(script),
|
||||||
start_pos_(start_pos),
|
start_pos_(start_pos),
|
||||||
end_pos_(end_pos),
|
end_pos_(end_pos),
|
||||||
|
bytecode_offset_(-1),
|
||||||
shared_(shared) {}
|
shared_(shared) {}
|
||||||
MessageLocation::MessageLocation() : start_pos_(-1), end_pos_(-1) {}
|
|
||||||
|
MessageLocation::MessageLocation(Handle<Script> script,
|
||||||
|
Handle<SharedFunctionInfo> shared,
|
||||||
|
int bytecode_offset)
|
||||||
|
: script_(script),
|
||||||
|
start_pos_(-1),
|
||||||
|
end_pos_(-1),
|
||||||
|
bytecode_offset_(bytecode_offset),
|
||||||
|
shared_(shared) {}
|
||||||
|
|
||||||
|
MessageLocation::MessageLocation()
|
||||||
|
: start_pos_(-1), end_pos_(-1), bytecode_offset_(-1) {}
|
||||||
|
|
||||||
// If no message listeners have been registered this one is called
|
// If no message listeners have been registered this one is called
|
||||||
// by default.
|
// by default.
|
||||||
@ -59,11 +75,15 @@ Handle<JSMessageObject> MessageHandler::MakeMessageObject(
|
|||||||
|
|
||||||
int start = -1;
|
int start = -1;
|
||||||
int end = -1;
|
int end = -1;
|
||||||
|
int bytecode_offset = -1;
|
||||||
Handle<Script> script_handle = isolate->factory()->empty_script();
|
Handle<Script> script_handle = isolate->factory()->empty_script();
|
||||||
|
Handle<SharedFunctionInfo> shared_info;
|
||||||
if (location != nullptr) {
|
if (location != nullptr) {
|
||||||
start = location->start_pos();
|
start = location->start_pos();
|
||||||
end = location->end_pos();
|
end = location->end_pos();
|
||||||
script_handle = location->script();
|
script_handle = location->script();
|
||||||
|
bytecode_offset = location->bytecode_offset();
|
||||||
|
shared_info = location->shared();
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle<Object> stack_frames_handle = stack_frames.is_null()
|
Handle<Object> stack_frames_handle = stack_frames.is_null()
|
||||||
@ -71,7 +91,8 @@ Handle<JSMessageObject> MessageHandler::MakeMessageObject(
|
|||||||
: Handle<Object>::cast(stack_frames);
|
: Handle<Object>::cast(stack_frames);
|
||||||
|
|
||||||
Handle<JSMessageObject> message_obj = factory->NewJSMessageObject(
|
Handle<JSMessageObject> message_obj = factory->NewJSMessageObject(
|
||||||
message, argument, start, end, script_handle, stack_frames_handle);
|
message, argument, start, end, shared_info, bytecode_offset,
|
||||||
|
script_handle, stack_frames_handle);
|
||||||
|
|
||||||
return message_obj;
|
return message_obj;
|
||||||
}
|
}
|
||||||
|
@ -33,20 +33,29 @@ class WasmInstanceObject;
|
|||||||
|
|
||||||
class V8_EXPORT_PRIVATE MessageLocation {
|
class V8_EXPORT_PRIVATE MessageLocation {
|
||||||
public:
|
public:
|
||||||
|
// Constructors for when source positions are already known.
|
||||||
|
// TODO(delphick): Collapse to a single constructor with a default parameter
|
||||||
|
// when we stop using the GCC that requires this separation.
|
||||||
MessageLocation(Handle<Script> script, int start_pos, int end_pos);
|
MessageLocation(Handle<Script> script, int start_pos, int end_pos);
|
||||||
MessageLocation(Handle<Script> script, int start_pos, int end_pos,
|
MessageLocation(Handle<Script> script, int start_pos, int end_pos,
|
||||||
Handle<SharedFunctionInfo> shared);
|
Handle<SharedFunctionInfo> shared);
|
||||||
|
// Constructor for when source positions were not collected but which can be
|
||||||
|
// reconstructed from the SharedFuncitonInfo and bytecode offset.
|
||||||
|
MessageLocation(Handle<Script> script, Handle<SharedFunctionInfo> shared,
|
||||||
|
int bytecode_offset);
|
||||||
MessageLocation();
|
MessageLocation();
|
||||||
|
|
||||||
Handle<Script> script() const { return script_; }
|
Handle<Script> script() const { return script_; }
|
||||||
int start_pos() const { return start_pos_; }
|
int start_pos() const { return start_pos_; }
|
||||||
int end_pos() const { return end_pos_; }
|
int end_pos() const { return end_pos_; }
|
||||||
|
int bytecode_offset() const { return bytecode_offset_; }
|
||||||
Handle<SharedFunctionInfo> shared() const { return shared_; }
|
Handle<SharedFunctionInfo> shared() const { return shared_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Handle<Script> script_;
|
Handle<Script> script_;
|
||||||
int start_pos_;
|
int start_pos_;
|
||||||
int end_pos_;
|
int end_pos_;
|
||||||
|
int bytecode_offset_;
|
||||||
Handle<SharedFunctionInfo> shared_;
|
Handle<SharedFunctionInfo> shared_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "src/ast/ast.h"
|
#include "src/ast/ast.h"
|
||||||
#include "src/ast/scopes.h"
|
#include "src/ast/scopes.h"
|
||||||
#include "src/base/bits.h"
|
#include "src/base/bits.h"
|
||||||
|
#include "src/base/debug/stack_trace.h"
|
||||||
#include "src/base/overflowing-math.h"
|
#include "src/base/overflowing-math.h"
|
||||||
#include "src/base/utils/random-number-generator.h"
|
#include "src/base/utils/random-number-generator.h"
|
||||||
#include "src/bootstrapper.h"
|
#include "src/bootstrapper.h"
|
||||||
@ -5588,6 +5589,13 @@ void SharedFunctionInfo::SetPosition(int start_position, int end_position) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SharedFunctionInfo::AreSourcePositionsAvailable() const {
|
||||||
|
if (FLAG_enable_lazy_source_positions) {
|
||||||
|
return !HasBytecodeArray() || GetBytecodeArray()->HasSourcePositionTable();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void SharedFunctionInfo::EnsureSourcePositionsAvailable(
|
void SharedFunctionInfo::EnsureSourcePositionsAvailable(
|
||||||
Isolate* isolate, Handle<SharedFunctionInfo> shared_info) {
|
Isolate* isolate, Handle<SharedFunctionInfo> shared_info) {
|
||||||
|
@ -717,16 +717,34 @@ ACCESSORS(JSDate, hour, Object, kHourOffset)
|
|||||||
ACCESSORS(JSDate, min, Object, kMinOffset)
|
ACCESSORS(JSDate, min, Object, kMinOffset)
|
||||||
ACCESSORS(JSDate, sec, Object, kSecOffset)
|
ACCESSORS(JSDate, sec, Object, kSecOffset)
|
||||||
|
|
||||||
|
bool JSMessageObject::DidEnsureSourcePositionsAvailable() const {
|
||||||
|
return shared_info()->IsUndefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
int JSMessageObject::GetStartPosition() const {
|
||||||
|
DCHECK(DidEnsureSourcePositionsAvailable());
|
||||||
|
return start_position();
|
||||||
|
}
|
||||||
|
|
||||||
|
int JSMessageObject::GetEndPosition() const {
|
||||||
|
DCHECK(DidEnsureSourcePositionsAvailable());
|
||||||
|
return end_position();
|
||||||
|
}
|
||||||
|
|
||||||
MessageTemplate JSMessageObject::type() const {
|
MessageTemplate JSMessageObject::type() const {
|
||||||
Object value = READ_FIELD(*this, kMessageTypeOffset);
|
Object value = READ_FIELD(*this, kMessageTypeOffset);
|
||||||
return MessageTemplateFromInt(Smi::ToInt(value));
|
return MessageTemplateFromInt(Smi::ToInt(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void JSMessageObject::set_type(MessageTemplate value) {
|
void JSMessageObject::set_type(MessageTemplate value) {
|
||||||
WRITE_FIELD(*this, kMessageTypeOffset, Smi::FromInt(static_cast<int>(value)));
|
WRITE_FIELD(*this, kMessageTypeOffset, Smi::FromInt(static_cast<int>(value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
ACCESSORS(JSMessageObject, argument, Object, kArgumentsOffset)
|
ACCESSORS(JSMessageObject, argument, Object, kArgumentsOffset)
|
||||||
ACCESSORS(JSMessageObject, script, Script, kScriptOffset)
|
ACCESSORS(JSMessageObject, script, Script, kScriptOffset)
|
||||||
ACCESSORS(JSMessageObject, stack_frames, Object, kStackFramesOffset)
|
ACCESSORS(JSMessageObject, stack_frames, Object, kStackFramesOffset)
|
||||||
|
ACCESSORS(JSMessageObject, shared_info, HeapObject, kSharedInfoOffset)
|
||||||
|
ACCESSORS(JSMessageObject, bytecode_offset, Smi, kBytecodeOffsetOffset)
|
||||||
SMI_ACCESSORS(JSMessageObject, start_position, kStartPositionOffset)
|
SMI_ACCESSORS(JSMessageObject, start_position, kStartPositionOffset)
|
||||||
SMI_ACCESSORS(JSMessageObject, end_position, kEndPositionOffset)
|
SMI_ACCESSORS(JSMessageObject, end_position, kEndPositionOffset)
|
||||||
SMI_ACCESSORS(JSMessageObject, error_level, kErrorLevelOffset)
|
SMI_ACCESSORS(JSMessageObject, error_level, kErrorLevelOffset)
|
||||||
|
@ -5777,7 +5777,27 @@ void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) {
|
|||||||
set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
|
set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void JSMessageObject::EnsureSourcePositionsAvailable(
|
||||||
|
Isolate* isolate, Handle<JSMessageObject> message) {
|
||||||
|
if (!message->DidEnsureSourcePositionsAvailable()) {
|
||||||
|
DCHECK_EQ(message->start_position(), -1);
|
||||||
|
DCHECK_GE(message->bytecode_offset()->value(), 0);
|
||||||
|
Handle<SharedFunctionInfo> shared_info(
|
||||||
|
SharedFunctionInfo::cast(message->shared_info()), isolate);
|
||||||
|
SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate, shared_info);
|
||||||
|
DCHECK(shared_info->HasBytecodeArray());
|
||||||
|
int position = shared_info->abstract_code()->SourcePosition(
|
||||||
|
message->bytecode_offset()->value());
|
||||||
|
DCHECK_GE(position, 0);
|
||||||
|
message->set_start_position(position);
|
||||||
|
message->set_end_position(position + 1);
|
||||||
|
message->set_shared_info(ReadOnlyRoots(isolate).undefined_value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int JSMessageObject::GetLineNumber() const {
|
int JSMessageObject::GetLineNumber() const {
|
||||||
|
DCHECK(DidEnsureSourcePositionsAvailable());
|
||||||
if (start_position() == -1) return Message::kNoLineNumberInfo;
|
if (start_position() == -1) return Message::kNoLineNumberInfo;
|
||||||
|
|
||||||
Handle<Script> the_script(script(), GetIsolate());
|
Handle<Script> the_script(script(), GetIsolate());
|
||||||
@ -5793,6 +5813,7 @@ int JSMessageObject::GetLineNumber() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int JSMessageObject::GetColumnNumber() const {
|
int JSMessageObject::GetColumnNumber() const {
|
||||||
|
DCHECK(DidEnsureSourcePositionsAvailable());
|
||||||
if (start_position() == -1) return -1;
|
if (start_position() == -1) return -1;
|
||||||
|
|
||||||
Handle<Script> the_script(script(), GetIsolate());
|
Handle<Script> the_script(script(), GetIsolate());
|
||||||
@ -5817,6 +5838,7 @@ Handle<String> JSMessageObject::GetSourceLine() const {
|
|||||||
|
|
||||||
Script::PositionInfo info;
|
Script::PositionInfo info;
|
||||||
const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
|
const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
|
||||||
|
DCHECK(DidEnsureSourcePositionsAvailable());
|
||||||
if (!Script::GetPositionInfo(the_script, start_position(), &info,
|
if (!Script::GetPositionInfo(the_script, start_position(), &info,
|
||||||
offset_flag)) {
|
offset_flag)) {
|
||||||
return isolate->factory()->empty_string();
|
return isolate->factory()->empty_string();
|
||||||
|
@ -1342,23 +1342,30 @@ class JSMessageObject : public JSObject {
|
|||||||
// [stack_frames]: an array of stack frames for this error object.
|
// [stack_frames]: an array of stack frames for this error object.
|
||||||
DECL_ACCESSORS(stack_frames, Object)
|
DECL_ACCESSORS(stack_frames, Object)
|
||||||
|
|
||||||
// [start_position]: the start position in the script for the error message.
|
// Initializes the source positions in the object if possible. Does nothing if
|
||||||
inline int start_position() const;
|
// called more than once. If called when stack space is exhausted, then the
|
||||||
inline void set_start_position(int value);
|
// source positions will be not be set and calling it again when there is more
|
||||||
|
// stack space will not have any effect.
|
||||||
|
static void EnsureSourcePositionsAvailable(Isolate* isolate,
|
||||||
|
Handle<JSMessageObject> message);
|
||||||
|
|
||||||
// [end_position]: the end position in the script for the error message.
|
// Gets the start and end positions for the message.
|
||||||
inline int end_position() const;
|
// EnsureSourcePositionsAvailable must have been called before calling these.
|
||||||
inline void set_end_position(int value);
|
inline int GetStartPosition() const;
|
||||||
|
inline int GetEndPosition() const;
|
||||||
|
|
||||||
// Returns the line number for the error message (1-based), or
|
// Returns the line number for the error message (1-based), or
|
||||||
// Message::kNoLineNumberInfo if the line cannot be determined.
|
// Message::kNoLineNumberInfo if the line cannot be determined.
|
||||||
|
// EnsureSourcePositionsAvailable must have been called before calling this.
|
||||||
V8_EXPORT_PRIVATE int GetLineNumber() const;
|
V8_EXPORT_PRIVATE int GetLineNumber() const;
|
||||||
|
|
||||||
// Returns the offset of the given position within the containing line.
|
// Returns the offset of the given position within the containing line.
|
||||||
|
// EnsureSourcePositionsAvailable must have been called before calling this.
|
||||||
V8_EXPORT_PRIVATE int GetColumnNumber() const;
|
V8_EXPORT_PRIVATE int GetColumnNumber() const;
|
||||||
|
|
||||||
// Returns the source code line containing the given source
|
// Returns the source code line containing the given source
|
||||||
// position, or the empty string if the position is invalid.
|
// position, or the empty string if the position is invalid.
|
||||||
|
// EnsureSourcePositionsAvailable must have been called before calling this.
|
||||||
Handle<String> GetSourceLine() const;
|
Handle<String> GetSourceLine() const;
|
||||||
|
|
||||||
inline int error_level() const;
|
inline int error_level() const;
|
||||||
@ -1379,6 +1386,27 @@ class JSMessageObject : public JSObject {
|
|||||||
kPointerFieldsEndOffset, kSize>;
|
kPointerFieldsEndOffset, kSize>;
|
||||||
|
|
||||||
OBJECT_CONSTRUCTORS(JSMessageObject, JSObject);
|
OBJECT_CONSTRUCTORS(JSMessageObject, JSObject);
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class Factory;
|
||||||
|
|
||||||
|
inline bool DidEnsureSourcePositionsAvailable() const;
|
||||||
|
|
||||||
|
// [shared]: optional SharedFunctionInfo that can be used to reconstruct the
|
||||||
|
// source position if not available when the message was generated.
|
||||||
|
DECL_ACCESSORS(shared_info, HeapObject)
|
||||||
|
|
||||||
|
// [bytecode_offset]: optional offset using along with |shared| to generation
|
||||||
|
// source positions.
|
||||||
|
DECL_ACCESSORS(bytecode_offset, Smi)
|
||||||
|
|
||||||
|
// [start_position]: the start position in the script for the error message.
|
||||||
|
inline int start_position() const;
|
||||||
|
inline void set_start_position(int value);
|
||||||
|
|
||||||
|
// [end_position]: the end position in the script for the error message.
|
||||||
|
inline int end_position() const;
|
||||||
|
inline void set_end_position(int value);
|
||||||
};
|
};
|
||||||
|
|
||||||
// The [Async-from-Sync Iterator] object
|
// The [Async-from-Sync Iterator] object
|
||||||
|
@ -590,6 +590,8 @@ class SharedFunctionInfo : public HeapObject {
|
|||||||
static void EnsureSourcePositionsAvailable(
|
static void EnsureSourcePositionsAvailable(
|
||||||
Isolate* isolate, Handle<SharedFunctionInfo> shared_info);
|
Isolate* isolate, Handle<SharedFunctionInfo> shared_info);
|
||||||
|
|
||||||
|
bool AreSourcePositionsAvailable() const;
|
||||||
|
|
||||||
// Hash based on function literal id and script id.
|
// Hash based on function literal id and script id.
|
||||||
V8_EXPORT_PRIVATE uint32_t Hash();
|
V8_EXPORT_PRIVATE uint32_t Hash();
|
||||||
|
|
||||||
|
@ -5131,9 +5131,7 @@ TEST(InterpreterCollectSourcePositions_StackOverflow) {
|
|||||||
CHECK_GT(source_position_table->length(), 0);
|
CHECK_GT(source_position_table->length(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(v8:8510): When an exception is thrown, the top frame still has its
|
TEST(InterpreterCollectSourcePositions_ThrowFrom1stFrame) {
|
||||||
// source positions collected. Re-enable this test when that is fixed.
|
|
||||||
DISABLED_TEST(InterpreterCollectSourcePositions_ThrowFrom1stFrame) {
|
|
||||||
FLAG_enable_lazy_source_positions = true;
|
FLAG_enable_lazy_source_positions = true;
|
||||||
HandleAndZoneScope handles;
|
HandleAndZoneScope handles;
|
||||||
Isolate* isolate = handles.main_isolate();
|
Isolate* isolate = handles.main_isolate();
|
||||||
|
@ -5048,6 +5048,81 @@ TEST(MessageHandler5) {
|
|||||||
isolate->RemoveMessageListeners(check_message_5b);
|
isolate->RemoveMessageListeners(check_message_5b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Verifies that after throwing an exception the message object is set up in
|
||||||
|
// some particular way by calling the supplied |tester| function. The tests that
|
||||||
|
// use this purposely test only a single getter as the getter updates the cached
|
||||||
|
// state of the object which could affect the results of other functions.
|
||||||
|
void CheckMessageAttributes(std::function<void(v8::Local<v8::Context> context,
|
||||||
|
v8::Local<v8::Message> message)>
|
||||||
|
tester) {
|
||||||
|
LocalContext context;
|
||||||
|
v8::HandleScope scope(context->GetIsolate());
|
||||||
|
|
||||||
|
TryCatch try_catch(context->GetIsolate());
|
||||||
|
CompileRun(
|
||||||
|
R"javascript(
|
||||||
|
(function() {
|
||||||
|
throw new Error();
|
||||||
|
})();
|
||||||
|
)javascript");
|
||||||
|
CHECK(try_catch.HasCaught());
|
||||||
|
|
||||||
|
v8::Local<v8::Value> error = try_catch.Exception();
|
||||||
|
v8::Local<v8::Message> message =
|
||||||
|
v8::Exception::CreateMessage(context->GetIsolate(), error);
|
||||||
|
CHECK(!message.IsEmpty());
|
||||||
|
|
||||||
|
tester(context.local(), message);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
TEST(MessageGetLineNumber) {
|
||||||
|
CheckMessageAttributes(
|
||||||
|
[](v8::Local<v8::Context> context, v8::Local<v8::Message> message) {
|
||||||
|
CHECK_EQ(3, message->GetLineNumber(context).FromJust());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MessageGetStartColumn) {
|
||||||
|
CheckMessageAttributes(
|
||||||
|
[](v8::Local<v8::Context> context, v8::Local<v8::Message> message) {
|
||||||
|
CHECK_EQ(14, message->GetStartColumn(context).FromJust());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MessageGetEndColumn) {
|
||||||
|
CheckMessageAttributes(
|
||||||
|
[](v8::Local<v8::Context> context, v8::Local<v8::Message> message) {
|
||||||
|
CHECK_EQ(15, message->GetEndColumn(context).FromJust());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MessageGetStartPosition) {
|
||||||
|
CheckMessageAttributes(
|
||||||
|
[](v8::Local<v8::Context> context, v8::Local<v8::Message> message) {
|
||||||
|
CHECK_EQ(35, message->GetStartPosition());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MessageGetEndPosition) {
|
||||||
|
CheckMessageAttributes(
|
||||||
|
[](v8::Local<v8::Context> context, v8::Local<v8::Message> message) {
|
||||||
|
CHECK_EQ(36, message->GetEndPosition());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MessageGetSourceLine) {
|
||||||
|
CheckMessageAttributes(
|
||||||
|
[](v8::Local<v8::Context> context, v8::Local<v8::Message> message) {
|
||||||
|
std::string result(*v8::String::Utf8Value(
|
||||||
|
context->GetIsolate(),
|
||||||
|
message->GetSourceLine(context).ToLocalChecked()));
|
||||||
|
CHECK_EQ(" throw new Error();", result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
THREADED_TEST(GetSetProperty) {
|
THREADED_TEST(GetSetProperty) {
|
||||||
LocalContext context;
|
LocalContext context;
|
||||||
|
@ -86,10 +86,10 @@ void CheckComputeLocation(v8::internal::Isolate* i_isolate, Handle<Object> exc,
|
|||||||
printf("loc start: %d, end: %d\n", loc.start_pos(), loc.end_pos());
|
printf("loc start: %d, end: %d\n", loc.start_pos(), loc.end_pos());
|
||||||
Handle<JSMessageObject> message = i_isolate->CreateMessage(exc, nullptr);
|
Handle<JSMessageObject> message = i_isolate->CreateMessage(exc, nullptr);
|
||||||
printf("msg start: %d, end: %d, line: %d, col: %d\n",
|
printf("msg start: %d, end: %d, line: %d, col: %d\n",
|
||||||
message->start_position(), message->end_position(),
|
message->GetStartPosition(), message->GetEndPosition(),
|
||||||
message->GetLineNumber(), message->GetColumnNumber());
|
message->GetLineNumber(), message->GetColumnNumber());
|
||||||
CHECK_EQ(loc.start_pos(), message->start_position());
|
CHECK_EQ(loc.start_pos(), message->GetStartPosition());
|
||||||
CHECK_EQ(loc.end_pos(), message->end_position());
|
CHECK_EQ(loc.end_pos(), message->GetEndPosition());
|
||||||
// In the message, the line is 1-based, but the column is 0-based.
|
// In the message, the line is 1-based, but the column is 0-based.
|
||||||
CHECK_EQ(topLocation.line_nr, message->GetLineNumber());
|
CHECK_EQ(topLocation.line_nr, message->GetLineNumber());
|
||||||
CHECK_LE(1, topLocation.column);
|
CHECK_LE(1, topLocation.column);
|
||||||
|
@ -400,12 +400,6 @@
|
|||||||
'regress/regress-crbug-319860': [PASS, ['pointer_compression', SLOW]],
|
'regress/regress-crbug-319860': [PASS, ['pointer_compression', SLOW]],
|
||||||
}], # 'lite_mode or variant == jitless'
|
}], # 'lite_mode or variant == jitless'
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
['lite_mode', {
|
|
||||||
# TODO(v8:8510): Tests that currently fail with lazy source positions.
|
|
||||||
'stack-traces-overflow': [SKIP],
|
|
||||||
}], # lite_mode
|
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
['is_full_debug', {
|
['is_full_debug', {
|
||||||
# Tests too slow in non-optimized debug mode.
|
# Tests too slow in non-optimized debug mode.
|
||||||
|
Loading…
Reference in New Issue
Block a user