Reland "Reland "[compiler] Don't collect source positions for the top frame""

This is a reland of f2e652264dd05c4d834191686f48a1afb0747131

Nothing has changed but
https://chromium-review.googlesource.com/c/v8/v8/+/1585269 has been rolled
back due to v8:9234.

Original change's description:
> 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}

TBR=ulan@chromium.org

Bug: v8:8510
Change-Id: Iaa9e376f90d10c0f25d1bcc352808363e4ea8b4d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1605946
Reviewed-by: Dan Elphick <delphick@chromium.org>
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Commit-Queue: Dan Elphick <delphick@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61418}
diff --git a/src/api.cc b/src/api.cc
index 17839f6..fac25e9 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -2857,20 +2857,28 @@
   i::Isolate* isolate = self->GetIsolate();
   ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
   EscapableHandleScope handle_scope(reinterpret_cast<Isolate*>(isolate));
-  auto msg = i::Handle<i::JSMessageObject>::cast(self);
-  return Just(msg->GetLineNumber());
+  i::JSMessageObject::EnsureSourcePositionsAvailable(isolate, self);
+  return Just(self->GetLineNumber());
 }
 
 
 int Message::GetStartPosition() const {
   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 {
   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 {
@@ -2883,8 +2891,8 @@
   i::Isolate* isolate = self->GetIsolate();
   ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
   EscapableHandleScope handle_scope(reinterpret_cast<Isolate*>(isolate));
-  auto msg = i::Handle<i::JSMessageObject>::cast(self);
-  return msg->GetColumnNumber();
+  i::JSMessageObject::EnsureSourcePositionsAvailable(isolate, self);
+  return self->GetColumnNumber();
 }
 
 Maybe<int> Message::GetStartColumn(Local<Context> context) const {
@@ -2896,11 +2904,11 @@
   i::Isolate* isolate = self->GetIsolate();
   ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
   EscapableHandleScope handle_scope(reinterpret_cast<Isolate*>(isolate));
-  auto msg = i::Handle<i::JSMessageObject>::cast(self);
-  const int column_number = msg->GetColumnNumber();
+  i::JSMessageObject::EnsureSourcePositionsAvailable(isolate, self);
+  const int column_number = self->GetColumnNumber();
   if (column_number == -1) return -1;
-  const int start = self->start_position();
-  const int end = self->end_position();
+  const int start = self->GetStartPosition();
+  const int end = self->GetEndPosition();
   return column_number + (end - start);
 }
 
@@ -2930,8 +2938,8 @@
   i::Isolate* isolate = self->GetIsolate();
   ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
   EscapableHandleScope handle_scope(reinterpret_cast<Isolate*>(isolate));
-  auto msg = i::Handle<i::JSMessageObject>::cast(self);
-  RETURN_ESCAPED(Utils::ToLocal(msg->GetSourceLine()));
+  i::JSMessageObject::EnsureSourcePositionsAvailable(isolate, self);
+  RETURN_ESCAPED(Utils::ToLocal(self->GetSourceLine()));
 }
 
 
diff --git a/src/builtins/base.tq b/src/builtins/base.tq
index 8ae6979..77b9a36 100644
--- a/src/builtins/base.tq
+++ b/src/builtins/base.tq
@@ -321,8 +321,11 @@
   arguments: Object;
   script: Script;
   stack_frames: Object;
+  shared_info: SharedFunctionInfo | Undefined;
+
   // Raw data fields.
   // TODO(ishell): store as int32 instead of Smi.
+  bytecode_offset: Smi;
   start_position: Smi;
   end_position: Smi;
   error_level: Smi;
diff --git a/src/frames.cc b/src/frames.cc
index ed585d7..b1117d3 100644
--- a/src/frames.cc
+++ b/src/frames.cc
@@ -1338,11 +1338,23 @@
   }
 }
 
+bool FrameSummary::AreSourcePositionsAvailable() const {
+  if (IsJavaScript()) {
+    return java_script_summary_.AreSourcePositionsAvailable();
+  }
+  return true;
+}
+
 void FrameSummary::JavaScriptFrameSummary::EnsureSourcePositionsAvailable() {
   Handle<SharedFunctionInfo> shared(function()->shared(), isolate());
   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 {
   return function()->shared()->IsSubjectToDebugging();
 }
diff --git a/src/frames.h b/src/frames.h
index 5a2e71f..d3c22e4 100644
--- a/src/frames.h
+++ b/src/frames.h
@@ -483,6 +483,7 @@
                            FixedArray parameters);
 
     void EnsureSourcePositionsAvailable();
+    bool AreSourcePositionsAvailable() const;
 
     Handle<Object> receiver() const { return receiver_; }
     Handle<JSFunction> function() const { return function_; }
@@ -572,6 +573,7 @@
   static FrameSummary Get(const StandardFrame* frame, int index);
 
   void EnsureSourcePositionsAvailable();
+  bool AreSourcePositionsAvailable() const;
 
   // Dispatched accessors.
   Handle<Object> receiver() const;
diff --git a/src/heap/factory.cc b/src/heap/factory.cc
index 094ab75..9fb066e 100644
--- a/src/heap/factory.cc
+++ b/src/heap/factory.cc
@@ -3468,7 +3468,8 @@
 
 Handle<JSMessageObject> Factory::NewJSMessageObject(
     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<JSMessageObject> message_obj(
       JSMessageObject::cast(New(map, AllocationType::kYoung)), isolate());
@@ -3481,6 +3482,23 @@
   message_obj->set_start_position(start_position);
   message_obj->set_end_position(end_position);
   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_error_level(v8::Isolate::kMessageError);
   return message_obj;
diff --git a/src/heap/factory.h b/src/heap/factory.h
index c485f1a..d587b70 100644
--- a/src/heap/factory.h
+++ b/src/heap/factory.h
@@ -885,7 +885,8 @@
   // Allocates a new JSMessageObject object.
   Handle<JSMessageObject> NewJSMessageObject(
       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<DebugInfo> NewDebugInfo(Handle<SharedFunctionInfo> shared);
diff --git a/src/isolate.cc b/src/isolate.cc
index 2d649c7..56efd34 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -2069,8 +2069,6 @@
   wasm::WasmCodeRefScope code_ref_scope;
   frame->Summarize(&frames);
   FrameSummary& summary = frames.back();
-  summary.EnsureSourcePositionsAvailable();
-  int pos = summary.SourcePosition();
   Handle<SharedFunctionInfo> shared;
   Handle<Object> script = summary.script();
   if (!script->IsScript() ||
@@ -2081,7 +2079,14 @@
   if (summary.IsJavaScript()) {
     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;
 }
 
@@ -2156,13 +2161,18 @@
     if (script->IsScript() &&
         !(Script::cast(script)->source()->IsUndefined(this))) {
       Handle<SharedFunctionInfo> shared = handle(fun->shared(), this);
-      SharedFunctionInfo::EnsureSourcePositionsAvailable(this, shared);
+
       AbstractCode abstract_code = elements->Code(i);
       const int code_offset = elements->Offset(i)->value();
-      const int pos = abstract_code->SourcePosition(code_offset);
-
       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;
     }
   }
@@ -2278,8 +2288,13 @@
     HandleScope scope(this);
     Handle<JSMessageObject> message(JSMessageObject::cast(message_obj), this);
     Handle<Script> script(message->script(), this);
-    int start_pos = message->start_position();
-    int end_pos = message->end_position();
+    // Clear the exception and restore it afterwards, otherwise
+    // 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);
     MessageHandler::ReportMessage(this, &location, message);
   }
diff --git a/src/messages.cc b/src/messages.cc
index cf63346..b7ee1d2 100644
--- a/src/messages.cc
+++ b/src/messages.cc
@@ -24,14 +24,30 @@
 
 MessageLocation::MessageLocation(Handle<Script> script, int start_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,
                                  int end_pos, Handle<SharedFunctionInfo> shared)
     : script_(script),
       start_pos_(start_pos),
       end_pos_(end_pos),
+      bytecode_offset_(-1),
       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
 // by default.
@@ -59,11 +75,15 @@
 
   int start = -1;
   int end = -1;
+  int bytecode_offset = -1;
   Handle<Script> script_handle = isolate->factory()->empty_script();
+  Handle<SharedFunctionInfo> shared_info;
   if (location != nullptr) {
     start = location->start_pos();
     end = location->end_pos();
     script_handle = location->script();
+    bytecode_offset = location->bytecode_offset();
+    shared_info = location->shared();
   }
 
   Handle<Object> stack_frames_handle = stack_frames.is_null()
@@ -71,7 +91,8 @@
       : Handle<Object>::cast(stack_frames);
 
   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;
 }
diff --git a/src/messages.h b/src/messages.h
index af45b16..386104f 100644
--- a/src/messages.h
+++ b/src/messages.h
@@ -33,20 +33,29 @@
 
 class V8_EXPORT_PRIVATE MessageLocation {
  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,
                   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();
 
   Handle<Script> script() const { return script_; }
   int start_pos() const { return start_pos_; }
   int end_pos() const { return end_pos_; }
+  int bytecode_offset() const { return bytecode_offset_; }
   Handle<SharedFunctionInfo> shared() const { return shared_; }
 
  private:
   Handle<Script> script_;
   int start_pos_;
   int end_pos_;
+  int bytecode_offset_;
   Handle<SharedFunctionInfo> shared_;
 };
 
diff --git a/src/objects.cc b/src/objects.cc
index b3c7fbf..634f8e2 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -21,6 +21,7 @@
 #include "src/ast/ast.h"
 #include "src/ast/scopes.h"
 #include "src/base/bits.h"
+#include "src/base/debug/stack_trace.h"
 #include "src/base/overflowing-math.h"
 #include "src/base/utils/random-number-generator.h"
 #include "src/bootstrapper.h"
@@ -5571,6 +5572,13 @@
   }
 }
 
+bool SharedFunctionInfo::AreSourcePositionsAvailable() const {
+  if (FLAG_enable_lazy_source_positions) {
+    return !HasBytecodeArray() || GetBytecodeArray()->HasSourcePositionTable();
+  }
+  return true;
+}
+
 // static
 void SharedFunctionInfo::EnsureSourcePositionsAvailable(
     Isolate* isolate, Handle<SharedFunctionInfo> shared_info) {
diff --git a/src/objects/js-objects-inl.h b/src/objects/js-objects-inl.h
index 096a84c..1018565 100644
--- a/src/objects/js-objects-inl.h
+++ b/src/objects/js-objects-inl.h
@@ -717,16 +717,34 @@
 ACCESSORS(JSDate, min, Object, kMinOffset)
 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 {
   Object value = READ_FIELD(*this, kMessageTypeOffset);
   return MessageTemplateFromInt(Smi::ToInt(value));
 }
+
 void JSMessageObject::set_type(MessageTemplate value) {
   WRITE_FIELD(*this, kMessageTypeOffset, Smi::FromInt(static_cast<int>(value)));
 }
+
 ACCESSORS(JSMessageObject, argument, Object, kArgumentsOffset)
 ACCESSORS(JSMessageObject, script, Script, kScriptOffset)
 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, end_position, kEndPositionOffset)
 SMI_ACCESSORS(JSMessageObject, error_level, kErrorLevelOffset)
diff --git a/src/objects/js-objects.cc b/src/objects/js-objects.cc
index cae2d82..b54ba92 100644
--- a/src/objects/js-objects.cc
+++ b/src/objects/js-objects.cc
@@ -5786,7 +5786,27 @@
   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 {
+  DCHECK(DidEnsureSourcePositionsAvailable());
   if (start_position() == -1) return Message::kNoLineNumberInfo;
 
   Handle<Script> the_script(script(), GetIsolate());
@@ -5802,6 +5822,7 @@
 }
 
 int JSMessageObject::GetColumnNumber() const {
+  DCHECK(DidEnsureSourcePositionsAvailable());
   if (start_position() == -1) return -1;
 
   Handle<Script> the_script(script(), GetIsolate());
@@ -5826,6 +5847,7 @@
 
   Script::PositionInfo info;
   const Script::OffsetFlag offset_flag = Script::WITH_OFFSET;
+  DCHECK(DidEnsureSourcePositionsAvailable());
   if (!Script::GetPositionInfo(the_script, start_position(), &info,
                                offset_flag)) {
     return isolate->factory()->empty_string();
diff --git a/src/objects/js-objects.h b/src/objects/js-objects.h
index ece2991..d3d7c0e 100644
--- a/src/objects/js-objects.h
+++ b/src/objects/js-objects.h
@@ -1342,23 +1342,30 @@
   // [stack_frames]: an array of stack frames for this error object.
   DECL_ACCESSORS(stack_frames, Object)
 
-  // [start_position]: the start position in the script for the error message.
-  inline int start_position() const;
-  inline void set_start_position(int value);
+  // Initializes the source positions in the object if possible. Does nothing if
+  // called more than once. If called when stack space is exhausted, then the
+  // 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.
-  inline int end_position() const;
-  inline void set_end_position(int value);
+  // Gets the start and end positions for the message.
+  // EnsureSourcePositionsAvailable must have been called before calling these.
+  inline int GetStartPosition() const;
+  inline int GetEndPosition() const;
 
   // Returns the line number for the error message (1-based), or
   // Message::kNoLineNumberInfo if the line cannot be determined.
+  // EnsureSourcePositionsAvailable must have been called before calling this.
   V8_EXPORT_PRIVATE int GetLineNumber() const;
 
   // 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;
 
   // Returns the source code line containing the given source
   // position, or the empty string if the position is invalid.
+  // EnsureSourcePositionsAvailable must have been called before calling this.
   Handle<String> GetSourceLine() const;
 
   inline int error_level() const;
@@ -1379,6 +1386,27 @@
                                              kPointerFieldsEndOffset, kSize>;
 
   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
diff --git a/src/objects/shared-function-info.h b/src/objects/shared-function-info.h
index 5d7363d..947bbc7 100644
--- a/src/objects/shared-function-info.h
+++ b/src/objects/shared-function-info.h
@@ -590,6 +590,8 @@
   static void EnsureSourcePositionsAvailable(
       Isolate* isolate, Handle<SharedFunctionInfo> shared_info);
 
+  bool AreSourcePositionsAvailable() const;
+
   // Hash based on function literal id and script id.
   V8_EXPORT_PRIVATE uint32_t Hash();
 
diff --git a/test/cctest/interpreter/test-interpreter.cc b/test/cctest/interpreter/test-interpreter.cc
index ba247dd..83ca163 100644
--- a/test/cctest/interpreter/test-interpreter.cc
+++ b/test/cctest/interpreter/test-interpreter.cc
@@ -5131,9 +5131,7 @@
   CHECK_GT(source_position_table->length(), 0);
 }
 
-// TODO(v8:8510): When an exception is thrown, the top frame still has its
-// source positions collected. Re-enable this test when that is fixed.
-DISABLED_TEST(InterpreterCollectSourcePositions_ThrowFrom1stFrame) {
+TEST(InterpreterCollectSourcePositions_ThrowFrom1stFrame) {
   FLAG_enable_lazy_source_positions = true;
   HandleAndZoneScope handles;
   Isolate* isolate = handles.main_isolate();
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 8f8ffab..fbf0677 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -5048,6 +5048,81 @@
   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) {
   LocalContext context;
diff --git a/test/cctest/wasm/test-wasm-stack.cc b/test/cctest/wasm/test-wasm-stack.cc
index 303fb75..68c2d8e 100644
--- a/test/cctest/wasm/test-wasm-stack.cc
+++ b/test/cctest/wasm/test-wasm-stack.cc
@@ -86,10 +86,10 @@
   printf("loc start: %d, end: %d\n", loc.start_pos(), loc.end_pos());
   Handle<JSMessageObject> message = i_isolate->CreateMessage(exc, nullptr);
   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());
-  CHECK_EQ(loc.start_pos(), message->start_position());
-  CHECK_EQ(loc.end_pos(), message->end_position());
+  CHECK_EQ(loc.start_pos(), message->GetStartPosition());
+  CHECK_EQ(loc.end_pos(), message->GetEndPosition());
   // In the message, the line is 1-based, but the column is 0-based.
   CHECK_EQ(topLocation.line_nr, message->GetLineNumber());
   CHECK_LE(1, topLocation.column);
diff --git a/test/mjsunit/mjsunit.status b/test/mjsunit/mjsunit.status
index dd26605..29a8133 100644
--- a/test/mjsunit/mjsunit.status
+++ b/test/mjsunit/mjsunit.status
@@ -401,12 +401,6 @@
 }],  # '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', {
   # Tests too slow in non-optimized debug mode.
   'compiler/regress-9017': [SKIP],