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:
Dan Elphick 2019-05-09 10:26:56 +01:00 committed by Commit Bot
parent 7dc6afd498
commit f2e652264d
18 changed files with 278 additions and 44 deletions

View File

@ -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()));
} }

View File

@ -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;

View File

@ -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();
} }

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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);
} }

View File

@ -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;
} }

View File

@ -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_;
}; };

View File

@ -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) {

View File

@ -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)

View File

@ -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();

View File

@ -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

View File

@ -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();

View File

@ -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();

View File

@ -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;

View File

@ -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);

View File

@ -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.