1// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/isolate.h"
6
7#include <stdlib.h>
8
9#include <atomic>
10#include <fstream> // NOLINT(readability/streams)
11#include <memory>
12#include <sstream>
13#include <unordered_map>
14
15#include "src/api-inl.h"
16#include "src/assembler-inl.h"
17#include "src/ast/ast-value-factory.h"
18#include "src/ast/scopes.h"
19#include "src/base/adapters.h"
20#include "src/base/hashmap.h"
21#include "src/base/platform/platform.h"
22#include "src/base/sys-info.h"
23#include "src/base/utils/random-number-generator.h"
24#include "src/bootstrapper.h"
25#include "src/builtins/builtins-promise.h"
26#include "src/builtins/constants-table-builder.h"
27#include "src/cancelable-task.h"
28#include "src/compilation-cache.h"
29#include "src/compilation-statistics.h"
30#include "src/compiler-dispatcher/compiler-dispatcher.h"
31#include "src/compiler-dispatcher/optimizing-compile-dispatcher.h"
32#include "src/date.h"
33#include "src/debug/debug-frames.h"
34#include "src/debug/debug.h"
35#include "src/deoptimizer.h"
36#include "src/elements.h"
37#include "src/frames-inl.h"
38#include "src/hash-seed-inl.h"
39#include "src/heap/heap-inl.h"
40#include "src/heap/read-only-heap.h"
41#include "src/ic/stub-cache.h"
42#include "src/interpreter/interpreter.h"
43#include "src/isolate-inl.h"
44#include "src/libsampler/sampler.h"
45#include "src/log.h"
46#include "src/messages.h"
47#include "src/microtask-queue.h"
48#include "src/objects/frame-array-inl.h"
49#include "src/objects/hash-table-inl.h"
50#include "src/objects/js-array-inl.h"
51#include "src/objects/js-generator-inl.h"
52#include "src/objects/module-inl.h"
53#include "src/objects/promise-inl.h"
54#include "src/objects/slots.h"
55#include "src/objects/smi.h"
56#include "src/objects/stack-frame-info-inl.h"
57#include "src/ostreams.h"
58#include "src/profiler/heap-profiler.h"
59#include "src/profiler/tracing-cpu-profiler.h"
60#include "src/prototype.h"
61#include "src/ptr-compr.h"
62#include "src/regexp/regexp-stack.h"
63#include "src/runtime-profiler.h"
64#include "src/setup-isolate.h"
65#include "src/simulator.h"
66#include "src/snapshot/embedded-data.h"
67#include "src/snapshot/embedded-file-writer.h"
68#include "src/snapshot/read-only-deserializer.h"
69#include "src/snapshot/startup-deserializer.h"
70#include "src/string-builder-inl.h"
71#include "src/string-stream.h"
72#include "src/tracing/tracing-category-observer.h"
73#include "src/trap-handler/trap-handler.h"
74#include "src/unicode-cache.h"
75#include "src/v8.h"
76#include "src/v8threads.h"
77#include "src/version.h"
78#include "src/visitors.h"
79#include "src/vm-state-inl.h"
80#include "src/wasm/wasm-code-manager.h"
81#include "src/wasm/wasm-engine.h"
82#include "src/wasm/wasm-objects.h"
83#include "src/zone/accounting-allocator.h"
84#ifdef V8_INTL_SUPPORT
85#include "unicode/uobject.h"
86#endif // V8_INTL_SUPPORT
87
88#if defined(V8_OS_WIN_X64)
89#include "src/unwinding-info-win64.h"
90#endif
91
92extern "C" const uint8_t* v8_Default_embedded_blob_;
93extern "C" uint32_t v8_Default_embedded_blob_size_;
94
95namespace v8 {
96namespace internal {
97
98#ifdef DEBUG
99#define TRACE_ISOLATE(tag) \
100 do { \
101 if (FLAG_trace_isolates) { \
102 PrintF("Isolate %p (id %d)" #tag "\n", reinterpret_cast<void*>(this), \
103 id()); \
104 } \
105 } while (false)
106#else
107#define TRACE_ISOLATE(tag)
108#endif
109
110const uint8_t* DefaultEmbeddedBlob() { return v8_Default_embedded_blob_; }
111uint32_t DefaultEmbeddedBlobSize() { return v8_Default_embedded_blob_size_; }
112
113#ifdef V8_MULTI_SNAPSHOTS
114extern "C" const uint8_t* v8_Trusted_embedded_blob_;
115extern "C" uint32_t v8_Trusted_embedded_blob_size_;
116
117const uint8_t* TrustedEmbeddedBlob() { return v8_Trusted_embedded_blob_; }
118uint32_t TrustedEmbeddedBlobSize() { return v8_Trusted_embedded_blob_size_; }
119#endif
120
121namespace {
122// These variables provide access to the current embedded blob without requiring
123// an isolate instance. This is needed e.g. by Code::InstructionStart, which may
124// not have access to an isolate but still needs to access the embedded blob.
125// The variables are initialized by each isolate in Init(). Writes and reads are
126// relaxed since we can guarantee that the current thread has initialized these
127// variables before accessing them. Different threads may race, but this is fine
128// since they all attempt to set the same values of the blob pointer and size.
129
130std::atomic<const uint8_t*> current_embedded_blob_(nullptr);
131std::atomic<uint32_t> current_embedded_blob_size_(0);
132
133// The various workflows around embedded snapshots are fairly complex. We need
134// to support plain old snapshot builds, nosnap builds, and the requirements of
135// subtly different serialization tests. There's two related knobs to twiddle:
136//
137// - The default embedded blob may be overridden by setting the sticky embedded
138// blob. This is set automatically whenever we create a new embedded blob.
139//
140// - Lifecycle management can be either manual or set to refcounting.
141//
142// A few situations to demonstrate their use:
143//
144// - A plain old snapshot build neither overrides the default blob nor
145// refcounts.
146//
147// - mksnapshot sets the sticky blob and manually frees the embedded
148// blob once done.
149//
150// - Most serializer tests do the same.
151//
152// - Nosnapshot builds set the sticky blob and enable refcounting.
153
154// This mutex protects access to the following variables:
155// - sticky_embedded_blob_
156// - sticky_embedded_blob_size_
157// - enable_embedded_blob_refcounting_
158// - current_embedded_blob_refs_
159base::LazyMutex current_embedded_blob_refcount_mutex_ = LAZY_MUTEX_INITIALIZER;
160
161const uint8_t* sticky_embedded_blob_ = nullptr;
162uint32_t sticky_embedded_blob_size_ = 0;
163
164bool enable_embedded_blob_refcounting_ = true;
165int current_embedded_blob_refs_ = 0;
166
167const uint8_t* StickyEmbeddedBlob() { return sticky_embedded_blob_; }
168uint32_t StickyEmbeddedBlobSize() { return sticky_embedded_blob_size_; }
169
170void SetStickyEmbeddedBlob(const uint8_t* blob, uint32_t blob_size) {
171 sticky_embedded_blob_ = blob;
172 sticky_embedded_blob_size_ = blob_size;
173}
174
175} // namespace
176
177void DisableEmbeddedBlobRefcounting() {
178 base::MutexGuard guard(current_embedded_blob_refcount_mutex_.Pointer());
179 enable_embedded_blob_refcounting_ = false;
180}
181
182void FreeCurrentEmbeddedBlob() {
183 CHECK(!enable_embedded_blob_refcounting_);
184 base::MutexGuard guard(current_embedded_blob_refcount_mutex_.Pointer());
185
186 if (StickyEmbeddedBlob() == nullptr) return;
187
188 CHECK_EQ(StickyEmbeddedBlob(), Isolate::CurrentEmbeddedBlob());
189
190 InstructionStream::FreeOffHeapInstructionStream(
191 const_cast<uint8_t*>(Isolate::CurrentEmbeddedBlob()),
192 Isolate::CurrentEmbeddedBlobSize());
193
194 current_embedded_blob_.store(nullptr, std::memory_order_relaxed);
195 current_embedded_blob_size_.store(0, std::memory_order_relaxed);
196 sticky_embedded_blob_ = nullptr;
197 sticky_embedded_blob_size_ = 0;
198}
199
200// static
201bool Isolate::CurrentEmbeddedBlobIsBinaryEmbedded() {
202 // In some situations, we must be able to rely on the embedded blob being
203 // immortal immovable. This is the case if the blob is binary-embedded.
204 // See blob lifecycle controls above for descriptions of when the current
205 // embedded blob may change (e.g. in tests or mksnapshot). If the blob is
206 // binary-embedded, it is immortal immovable.
207 const uint8_t* blob =
208 current_embedded_blob_.load(std::memory_order::memory_order_relaxed);
209 if (blob == nullptr) return false;
210#ifdef V8_MULTI_SNAPSHOTS
211 if (blob == TrustedEmbeddedBlob()) return true;
212#endif
213 return blob == DefaultEmbeddedBlob();
214}
215
216void Isolate::SetEmbeddedBlob(const uint8_t* blob, uint32_t blob_size) {
217 CHECK_NOT_NULL(blob);
218
219 embedded_blob_ = blob;
220 embedded_blob_size_ = blob_size;
221 current_embedded_blob_.store(blob, std::memory_order_relaxed);
222 current_embedded_blob_size_.store(blob_size, std::memory_order_relaxed);
223
224#ifdef DEBUG
225 // Verify that the contents of the embedded blob are unchanged from
226 // serialization-time, just to ensure the compiler isn't messing with us.
227 EmbeddedData d = EmbeddedData::FromBlob();
228 if (d.EmbeddedBlobHash() != d.CreateEmbeddedBlobHash()) {
229 FATAL(
230 "Embedded blob checksum verification failed. This indicates that the "
231 "embedded blob has been modified since compilation time. A common "
232 "cause is a debugging breakpoint set within builtin code.");
233 }
234#endif // DEBUG
235}
236
237void Isolate::ClearEmbeddedBlob() {
238 CHECK(enable_embedded_blob_refcounting_);
239 CHECK_EQ(embedded_blob_, CurrentEmbeddedBlob());
240 CHECK_EQ(embedded_blob_, StickyEmbeddedBlob());
241
242 embedded_blob_ = nullptr;
243 embedded_blob_size_ = 0;
244 current_embedded_blob_.store(nullptr, std::memory_order_relaxed);
245 current_embedded_blob_size_.store(0, std::memory_order_relaxed);
246 sticky_embedded_blob_ = nullptr;
247 sticky_embedded_blob_size_ = 0;
248}
249
250const uint8_t* Isolate::embedded_blob() const { return embedded_blob_; }
251uint32_t Isolate::embedded_blob_size() const { return embedded_blob_size_; }
252
253// static
254const uint8_t* Isolate::CurrentEmbeddedBlob() {
255 return current_embedded_blob_.load(std::memory_order::memory_order_relaxed);
256}
257
258// static
259uint32_t Isolate::CurrentEmbeddedBlobSize() {
260 return current_embedded_blob_size_.load(
261 std::memory_order::memory_order_relaxed);
262}
263
264size_t Isolate::HashIsolateForEmbeddedBlob() {
265 DCHECK(builtins_.is_initialized());
266 DCHECK(FLAG_embedded_builtins);
267 DCHECK(Builtins::AllBuiltinsAreIsolateIndependent());
268
269 DisallowHeapAllocation no_gc;
270
271 static constexpr size_t kSeed = 0;
272 size_t hash = kSeed;
273
274 // Hash data sections of builtin code objects.
275 for (int i = 0; i < Builtins::builtin_count; i++) {
276 Code code = heap_.builtin(i);
277
278 DCHECK(Internals::HasHeapObjectTag(code.ptr()));
279 uint8_t* const code_ptr =
280 reinterpret_cast<uint8_t*>(code.ptr() - kHeapObjectTag);
281
282 // These static asserts ensure we don't miss relevant fields. We don't hash
283 // instruction size and flags since they change when creating the off-heap
284 // trampolines. Other data fields must remain the same.
285 STATIC_ASSERT(Code::kInstructionSizeOffset == Code::kDataStart);
286 STATIC_ASSERT(Code::kFlagsOffset == Code::kInstructionSizeOffsetEnd + 1);
287 STATIC_ASSERT(Code::kSafepointTableOffsetOffset ==
288 Code::kFlagsOffsetEnd + 1);
289 static constexpr int kStartOffset = Code::kSafepointTableOffsetOffset;
290
291 for (int j = kStartOffset; j < Code::kUnalignedHeaderSize; j++) {
292 hash = base::hash_combine(hash, size_t{code_ptr[j]});
293 }
294 }
295
296 // The builtins constants table is also tightly tied to embedded builtins.
297 hash = base::hash_combine(
298 hash, static_cast<size_t>(heap_.builtins_constants_table()->length()));
299
300 return hash;
301}
302
303
304base::Thread::LocalStorageKey Isolate::isolate_key_;
305base::Thread::LocalStorageKey Isolate::per_isolate_thread_data_key_;
306#if DEBUG
307std::atomic<bool> Isolate::isolate_key_created_{false};
308#endif
309
310namespace {
311// A global counter for all generated Isolates, might overflow.
312std::atomic<int> isolate_counter{0};
313} // namespace
314
315Isolate::PerIsolateThreadData*
316 Isolate::FindOrAllocatePerThreadDataForThisThread() {
317 ThreadId thread_id = ThreadId::Current();
318 PerIsolateThreadData* per_thread = nullptr;
319 {
320 base::MutexGuard lock_guard(&thread_data_table_mutex_);
321 per_thread = thread_data_table_.Lookup(thread_id);
322 if (per_thread == nullptr) {
323 per_thread = new PerIsolateThreadData(this, thread_id);
324 thread_data_table_.Insert(per_thread);
325 }
326 DCHECK(thread_data_table_.Lookup(thread_id) == per_thread);
327 }
328 return per_thread;
329}
330
331
332void Isolate::DiscardPerThreadDataForThisThread() {
333 ThreadId thread_id = ThreadId::TryGetCurrent();
334 if (thread_id.IsValid()) {
335 DCHECK_NE(thread_manager_->mutex_owner_.load(std::memory_order_relaxed),
336 thread_id);
337 base::MutexGuard lock_guard(&thread_data_table_mutex_);
338 PerIsolateThreadData* per_thread = thread_data_table_.Lookup(thread_id);
339 if (per_thread) {
340 DCHECK(!per_thread->thread_state_);
341 thread_data_table_.Remove(per_thread);
342 }
343 }
344}
345
346
347Isolate::PerIsolateThreadData* Isolate::FindPerThreadDataForThisThread() {
348 ThreadId thread_id = ThreadId::Current();
349 return FindPerThreadDataForThread(thread_id);
350}
351
352
353Isolate::PerIsolateThreadData* Isolate::FindPerThreadDataForThread(
354 ThreadId thread_id) {
355 PerIsolateThreadData* per_thread = nullptr;
356 {
357 base::MutexGuard lock_guard(&thread_data_table_mutex_);
358 per_thread = thread_data_table_.Lookup(thread_id);
359 }
360 return per_thread;
361}
362
363
364void Isolate::InitializeOncePerProcess() {
365 isolate_key_ = base::Thread::CreateThreadLocalKey();
366#if DEBUG
367 bool expected = false;
368 DCHECK_EQ(true, isolate_key_created_.compare_exchange_strong(
369 expected, true, std::memory_order_relaxed));
370#endif
371 per_isolate_thread_data_key_ = base::Thread::CreateThreadLocalKey();
372}
373
374Address Isolate::get_address_from_id(IsolateAddressId id) {
375 return isolate_addresses_[id];
376}
377
378char* Isolate::Iterate(RootVisitor* v, char* thread_storage) {
379 ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(thread_storage);
380 Iterate(v, thread);
381 return thread_storage + sizeof(ThreadLocalTop);
382}
383
384
385void Isolate::IterateThread(ThreadVisitor* v, char* t) {
386 ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(t);
387 v->VisitThread(this, thread);
388}
389
390void Isolate::Iterate(RootVisitor* v, ThreadLocalTop* thread) {
391 // Visit the roots from the top for a given thread.
392 v->VisitRootPointer(Root::kTop, nullptr,
393 FullObjectSlot(&thread->pending_exception_));
394 v->VisitRootPointer(Root::kTop, nullptr,
395 FullObjectSlot(&thread->pending_message_obj_));
396 v->VisitRootPointer(Root::kTop, nullptr, FullObjectSlot(&thread->context_));
397 v->VisitRootPointer(Root::kTop, nullptr,
398 FullObjectSlot(&thread->scheduled_exception_));
399
400 for (v8::TryCatch* block = thread->try_catch_handler_; block != nullptr;
401 block = block->next_) {
402 // TODO(3770): Make TryCatch::exception_ an Address (and message_obj_ too).
403 v->VisitRootPointer(
404 Root::kTop, nullptr,
405 FullObjectSlot(reinterpret_cast<Address>(&(block->exception_))));
406 v->VisitRootPointer(
407 Root::kTop, nullptr,
408 FullObjectSlot(reinterpret_cast<Address>(&(block->message_obj_))));
409 }
410
411 // Iterate over pointers on native execution stack.
412 wasm::WasmCodeRefScope wasm_code_ref_scope;
413 for (StackFrameIterator it(this, thread); !it.done(); it.Advance()) {
414 it.frame()->Iterate(v);
415 }
416}
417
418void Isolate::Iterate(RootVisitor* v) {
419 ThreadLocalTop* current_t = thread_local_top();
420 Iterate(v, current_t);
421}
422
423void Isolate::IterateDeferredHandles(RootVisitor* visitor) {
424 for (DeferredHandles* deferred = deferred_handles_head_; deferred != nullptr;
425 deferred = deferred->next_) {
426 deferred->Iterate(visitor);
427 }
428}
429
430
431#ifdef DEBUG
432bool Isolate::IsDeferredHandle(Address* handle) {
433 // Comparing unrelated pointers (not from the same array) is undefined
434 // behavior, so cast to Address before making arbitrary comparisons.
435 Address handle_as_address = reinterpret_cast<Address>(handle);
436 // Each DeferredHandles instance keeps the handles to one job in the
437 // concurrent recompilation queue, containing a list of blocks. Each block
438 // contains kHandleBlockSize handles except for the first block, which may
439 // not be fully filled.
440 // We iterate through all the blocks to see whether the argument handle
441 // belongs to one of the blocks. If so, it is deferred.
442 for (DeferredHandles* deferred = deferred_handles_head_; deferred != nullptr;
443 deferred = deferred->next_) {
444 std::vector<Address*>* blocks = &deferred->blocks_;
445 for (size_t i = 0; i < blocks->size(); i++) {
446 Address* block_limit = (i == 0) ? deferred->first_block_limit_
447 : blocks->at(i) + kHandleBlockSize;
448 if (reinterpret_cast<Address>(blocks->at(i)) <= handle_as_address &&
449 handle_as_address < reinterpret_cast<Address>(block_limit)) {
450 return true;
451 }
452 }
453 }
454 return false;
455}
456#endif // DEBUG
457
458
459void Isolate::RegisterTryCatchHandler(v8::TryCatch* that) {
460 thread_local_top()->try_catch_handler_ = that;
461}
462
463
464void Isolate::UnregisterTryCatchHandler(v8::TryCatch* that) {
465 DCHECK(thread_local_top()->try_catch_handler_ == that);
466 thread_local_top()->try_catch_handler_ = that->next_;
467}
468
469
470Handle<String> Isolate::StackTraceString() {
471 if (stack_trace_nesting_level_ == 0) {
472 stack_trace_nesting_level_++;
473 HeapStringAllocator allocator;
474 StringStream::ClearMentionedObjectCache(this);
475 StringStream accumulator(&allocator);
476 incomplete_message_ = &accumulator;
477 PrintStack(&accumulator);
478 Handle<String> stack_trace = accumulator.ToString(this);
479 incomplete_message_ = nullptr;
480 stack_trace_nesting_level_ = 0;
481 return stack_trace;
482 } else if (stack_trace_nesting_level_ == 1) {
483 stack_trace_nesting_level_++;
484 base::OS::PrintError(
485 "\n\nAttempt to print stack while printing stack (double fault)\n");
486 base::OS::PrintError(
487 "If you are lucky you may find a partial stack dump on stdout.\n\n");
488 incomplete_message_->OutputToStdOut();
489 return factory()->empty_string();
490 } else {
491 base::OS::Abort();
492 // Unreachable
493 return factory()->empty_string();
494 }
495}
496
497void Isolate::PushStackTraceAndDie(void* ptr1, void* ptr2, void* ptr3,
498 void* ptr4) {
499 StackTraceFailureMessage message(this, ptr1, ptr2, ptr3, ptr4);
500 message.Print();
501 base::OS::Abort();
502}
503
504void StackTraceFailureMessage::Print() volatile {
505 // Print the details of this failure message object, including its own address
506 // to force stack allocation.
507 base::OS::PrintError(
508 "Stacktrace:\n ptr1=%p\n ptr2=%p\n ptr3=%p\n ptr4=%p\n "
509 "failure_message_object=%p\n%s",
510 ptr1_, ptr2_, ptr3_, ptr4_, this, &js_stack_trace_[0]);
511}
512
513StackTraceFailureMessage::StackTraceFailureMessage(Isolate* isolate, void* ptr1,
514 void* ptr2, void* ptr3,
515 void* ptr4) {
516 isolate_ = isolate;
517 ptr1_ = ptr1;
518 ptr2_ = ptr2;
519 ptr3_ = ptr3;
520 ptr4_ = ptr4;
521 // Write a stracktrace into the {js_stack_trace_} buffer.
522 const size_t buffer_length = arraysize(js_stack_trace_);
523 memset(&js_stack_trace_, 0, buffer_length);
524 FixedStringAllocator fixed(&js_stack_trace_[0], buffer_length - 1);
525 StringStream accumulator(&fixed, StringStream::kPrintObjectConcise);
526 isolate->PrintStack(&accumulator, Isolate::kPrintStackVerbose);
527 // Keeping a reference to the last code objects to increase likelyhood that
528 // they get included in the minidump.
529 const size_t code_objects_length = arraysize(code_objects_);
530 size_t i = 0;
531 StackFrameIterator it(isolate);
532 for (; !it.done() && i < code_objects_length; it.Advance()) {
533 code_objects_[i++] =
534 reinterpret_cast<void*>(it.frame()->unchecked_code().ptr());
535 }
536}
537
538namespace {
539
540class StackFrameCacheHelper : public AllStatic {
541 public:
542 static MaybeHandle<StackTraceFrame> LookupCachedFrame(
543 Isolate* isolate, Handle<AbstractCode> code, int code_offset) {
544 if (FLAG_optimize_for_size) return MaybeHandle<StackTraceFrame>();
545
546 const auto maybe_cache = handle(code->stack_frame_cache(), isolate);
547 if (!maybe_cache->IsSimpleNumberDictionary())
548 return MaybeHandle<StackTraceFrame>();
549
550 const auto cache = Handle<SimpleNumberDictionary>::cast(maybe_cache);
551 const int entry = cache->FindEntry(isolate, code_offset);
552 if (entry != NumberDictionary::kNotFound) {
553 return handle(StackTraceFrame::cast(cache->ValueAt(entry)), isolate);
554 }
555 return MaybeHandle<StackTraceFrame>();
556 }
557
558 static void CacheFrameAndUpdateCache(Isolate* isolate,
559 Handle<AbstractCode> code,
560 int code_offset,
561 Handle<StackTraceFrame> frame) {
562 if (FLAG_optimize_for_size) return;
563
564 const auto maybe_cache = handle(code->stack_frame_cache(), isolate);
565 const auto cache = maybe_cache->IsSimpleNumberDictionary()
566 ? Handle<SimpleNumberDictionary>::cast(maybe_cache)
567 : SimpleNumberDictionary::New(isolate, 1);
568 Handle<SimpleNumberDictionary> new_cache =
569 SimpleNumberDictionary::Set(isolate, cache, code_offset, frame);
570 if (*new_cache != *cache || !maybe_cache->IsSimpleNumberDictionary()) {
571 AbstractCode::SetStackFrameCache(code, new_cache);
572 }
573 }
574};
575
576} // anonymous namespace
577
578class FrameArrayBuilder {
579 public:
580 enum FrameFilterMode { ALL, CURRENT_SECURITY_CONTEXT };
581
582 FrameArrayBuilder(Isolate* isolate, FrameSkipMode mode, int limit,
583 Handle<Object> caller, FrameFilterMode filter_mode)
584 : isolate_(isolate),
585 mode_(mode),
586 limit_(limit),
587 caller_(caller),
588 check_security_context_(filter_mode == CURRENT_SECURITY_CONTEXT) {
589 switch (mode_) {
590 case SKIP_FIRST:
591 skip_next_frame_ = true;
592 break;
593 case SKIP_UNTIL_SEEN:
594 DCHECK(caller_->IsJSFunction());
595 skip_next_frame_ = true;
596 break;
597 case SKIP_NONE:
598 skip_next_frame_ = false;
599 break;
600 }
601
602 elements_ = isolate->factory()->NewFrameArray(Min(limit, 10));
603 }
604
605 void AppendAsyncFrame(Handle<JSGeneratorObject> generator_object) {
606 if (full()) return;
607 Handle<JSFunction> function(generator_object->function(), isolate_);
608 if (!IsVisibleInStackTrace(function)) return;
609 int flags = FrameArray::kIsAsync;
610 if (IsStrictFrame(function)) flags |= FrameArray::kIsStrict;
611
612 Handle<Object> receiver(generator_object->receiver(), isolate_);
613 Handle<AbstractCode> code(
614 AbstractCode::cast(function->shared()->GetBytecodeArray()), isolate_);
615 int offset = Smi::ToInt(generator_object->input_or_debug_pos());
616 // The stored bytecode offset is relative to a different base than what
617 // is used in the source position table, hence the subtraction.
618 offset -= BytecodeArray::kHeaderSize - kHeapObjectTag;
619
620 Handle<FixedArray> parameters = isolate_->factory()->empty_fixed_array();
621 if (V8_UNLIKELY(FLAG_detailed_error_stack_trace)) {
622 int param_count = function->shared()->internal_formal_parameter_count();
623 parameters = isolate_->factory()->NewFixedArray(param_count);
624 for (int i = 0; i < param_count; i++) {
625 parameters->set(i,
626 generator_object->parameters_and_registers()->get(i));
627 }
628 }
629
630 elements_ = FrameArray::AppendJSFrame(elements_, receiver, function, code,
631 offset, flags, parameters);
632 }
633
634 void AppendPromiseAllFrame(Handle<Context> context, int offset) {
635 if (full()) return;
636 int flags = FrameArray::kIsAsync | FrameArray::kIsPromiseAll;
637
638 Handle<Context> native_context(context->native_context(), isolate_);
639 Handle<JSFunction> function(native_context->promise_all(), isolate_);
640 if (!IsVisibleInStackTrace(function)) return;
641
642 Handle<Object> receiver(native_context->promise_function(), isolate_);
643 Handle<AbstractCode> code(AbstractCode::cast(function->code()), isolate_);
644
645 // TODO(mmarchini) save Promises list from Promise.all()
646 Handle<FixedArray> parameters = isolate_->factory()->empty_fixed_array();
647
648 elements_ = FrameArray::AppendJSFrame(elements_, receiver, function, code,
649 offset, flags, parameters);
650 }
651
652 void AppendJavaScriptFrame(
653 FrameSummary::JavaScriptFrameSummary const& summary) {
654 // Filter out internal frames that we do not want to show.
655 if (!IsVisibleInStackTrace(summary.function())) return;
656
657 Handle<AbstractCode> abstract_code = summary.abstract_code();
658 const int offset = summary.code_offset();
659
660 const bool is_constructor = summary.is_constructor();
661
662 int flags = 0;
663 Handle<JSFunction> function = summary.function();
664 if (IsStrictFrame(function)) flags |= FrameArray::kIsStrict;
665 if (is_constructor) flags |= FrameArray::kIsConstructor;
666
667 Handle<FixedArray> parameters = isolate_->factory()->empty_fixed_array();
668 if (V8_UNLIKELY(FLAG_detailed_error_stack_trace))
669 parameters = summary.parameters();
670
671 elements_ = FrameArray::AppendJSFrame(
672 elements_, TheHoleToUndefined(isolate_, summary.receiver()), function,
673 abstract_code, offset, flags, parameters);
674 }
675
676 void AppendWasmCompiledFrame(
677 FrameSummary::WasmCompiledFrameSummary const& summary) {
678 if (summary.code()->kind() != wasm::WasmCode::kFunction) return;
679 Handle<WasmInstanceObject> instance = summary.wasm_instance();
680 int flags = 0;
681 if (instance->module_object()->is_asm_js()) {
682 flags |= FrameArray::kIsAsmJsWasmFrame;
683 if (summary.at_to_number_conversion()) {
684 flags |= FrameArray::kAsmJsAtNumberConversion;
685 }
686 } else {
687 flags |= FrameArray::kIsWasmFrame;
688 }
689
690 elements_ = FrameArray::AppendWasmFrame(
691 elements_, instance, summary.function_index(), summary.code(),
692 summary.code_offset(), flags);
693 }
694
695 void AppendWasmInterpretedFrame(
696 FrameSummary::WasmInterpretedFrameSummary const& summary) {
697 Handle<WasmInstanceObject> instance = summary.wasm_instance();
698 int flags = FrameArray::kIsWasmInterpretedFrame;
699 DCHECK(!instance->module_object()->is_asm_js());
700 elements_ = FrameArray::AppendWasmFrame(elements_, instance,
701 summary.function_index(), {},
702 summary.byte_offset(), flags);
703 }
704
705 void AppendBuiltinExitFrame(BuiltinExitFrame* exit_frame) {
706 Handle<JSFunction> function = handle(exit_frame->function(), isolate_);
707
708 // Filter out internal frames that we do not want to show.
709 if (!IsVisibleInStackTrace(function)) return;
710
711 Handle<Object> receiver(exit_frame->receiver(), isolate_);
712 Handle<Code> code(exit_frame->LookupCode(), isolate_);
713 const int offset =
714 static_cast<int>(exit_frame->pc() - code->InstructionStart());
715
716 int flags = 0;
717 if (IsStrictFrame(function)) flags |= FrameArray::kIsStrict;
718 if (exit_frame->IsConstructor()) flags |= FrameArray::kIsConstructor;
719
720 Handle<FixedArray> parameters = isolate_->factory()->empty_fixed_array();
721 if (V8_UNLIKELY(FLAG_detailed_error_stack_trace)) {
722 int param_count = exit_frame->ComputeParametersCount();
723 parameters = isolate_->factory()->NewFixedArray(param_count);
724 for (int i = 0; i < param_count; i++) {
725 parameters->set(i, exit_frame->GetParameter(i));
726 }
727 }
728
729 elements_ = FrameArray::AppendJSFrame(elements_, receiver, function,
730 Handle<AbstractCode>::cast(code),
731 offset, flags, parameters);
732 }
733
734 bool full() { return elements_->FrameCount() >= limit_; }
735
736 Handle<FrameArray> GetElements() {
737 elements_->ShrinkToFit(isolate_);
738 return elements_;
739 }
740
741 // Creates a StackTraceFrame object for each frame in the FrameArray.
742 Handle<FixedArray> GetElementsAsStackTraceFrameArray() {
743 elements_->ShrinkToFit(isolate_);
744 const int frame_count = elements_->FrameCount();
745 Handle<FixedArray> stack_trace =
746 isolate_->factory()->NewFixedArray(frame_count);
747
748 for (int i = 0; i < frame_count; ++i) {
749 // Caching stack frames only happens for non-Wasm frames.
750 if (!elements_->IsAnyWasmFrame(i)) {
751 MaybeHandle<StackTraceFrame> maybe_frame =
752 StackFrameCacheHelper::LookupCachedFrame(
753 isolate_, handle(elements_->Code(i), isolate_),
754 Smi::ToInt(elements_->Offset(i)));
755 if (!maybe_frame.is_null()) {
756 Handle<StackTraceFrame> frame = maybe_frame.ToHandleChecked();
757 stack_trace->set(i, *frame);
758 continue;
759 }
760 }
761
762 Handle<StackTraceFrame> frame =
763 isolate_->factory()->NewStackTraceFrame(elements_, i);
764 stack_trace->set(i, *frame);
765
766 if (!elements_->IsAnyWasmFrame(i)) {
767 StackFrameCacheHelper::CacheFrameAndUpdateCache(
768 isolate_, handle(elements_->Code(i), isolate_),
769 Smi::ToInt(elements_->Offset(i)), frame);
770 }
771 }
772 return stack_trace;
773 }
774
775 private:
776 // Poison stack frames below the first strict mode frame.
777 // The stack trace API should not expose receivers and function
778 // objects on frames deeper than the top-most one with a strict mode
779 // function.
780 bool IsStrictFrame(Handle<JSFunction> function) {
781 if (!encountered_strict_function_) {
782 encountered_strict_function_ =
783 is_strict(function->shared()->language_mode());
784 }
785 return encountered_strict_function_;
786 }
787
788 // Determines whether the given stack frame should be displayed in a stack
789 // trace.
790 bool IsVisibleInStackTrace(Handle<JSFunction> function) {
791 return ShouldIncludeFrame(function) && IsNotHidden(function) &&
792 IsInSameSecurityContext(function);
793 }
794
795 // This mechanism excludes a number of uninteresting frames from the stack
796 // trace. This can be be the first frame (which will be a builtin-exit frame
797 // for the error constructor builtin) or every frame until encountering a
798 // user-specified function.
799 bool ShouldIncludeFrame(Handle<JSFunction> function) {
800 switch (mode_) {
801 case SKIP_NONE:
802 return true;
803 case SKIP_FIRST:
804 if (!skip_next_frame_) return true;
805 skip_next_frame_ = false;
806 return false;
807 case SKIP_UNTIL_SEEN:
808 if (skip_next_frame_ && (*function == *caller_)) {
809 skip_next_frame_ = false;
810 return false;
811 }
812 return !skip_next_frame_;
813 }
814 UNREACHABLE();
815 }
816
817 bool IsNotHidden(Handle<JSFunction> function) {
818 // Functions defined not in user scripts are not visible unless directly
819 // exposed, in which case the native flag is set.
820 // The --builtins-in-stack-traces command line flag allows including
821 // internal call sites in the stack trace for debugging purposes.
822 if (!FLAG_builtins_in_stack_traces &&
823 !function->shared()->IsUserJavaScript()) {
824 return function->shared()->native();
825 }
826 return true;
827 }
828
829 bool IsInSameSecurityContext(Handle<JSFunction> function) {
830 if (!check_security_context_) return true;
831 return isolate_->context()->HasSameSecurityTokenAs(function->context());
832 }
833
834 // TODO(jgruber): Fix all cases in which frames give us a hole value (e.g. the
835 // receiver in RegExp constructor frames.
836 Handle<Object> TheHoleToUndefined(Isolate* isolate, Handle<Object> in) {
837 return (in->IsTheHole(isolate))
838 ? Handle<Object>::cast(isolate->factory()->undefined_value())
839 : in;
840 }
841
842 Isolate* isolate_;
843 const FrameSkipMode mode_;
844 int limit_;
845 const Handle<Object> caller_;
846 bool skip_next_frame_ = true;
847 bool encountered_strict_function_ = false;
848 const bool check_security_context_;
849 Handle<FrameArray> elements_;
850};
851
852bool GetStackTraceLimit(Isolate* isolate, int* result) {
853 Handle<JSObject> error = isolate->error_function();
854
855 Handle<String> key = isolate->factory()->stackTraceLimit_string();
856 Handle<Object> stack_trace_limit = JSReceiver::GetDataProperty(error, key);
857 if (!stack_trace_limit->IsNumber()) return false;
858
859 // Ensure that limit is not negative.
860 *result = Max(FastD2IChecked(stack_trace_limit->Number()), 0);
861
862 if (*result != FLAG_stack_trace_limit) {
863 isolate->CountUsage(v8::Isolate::kErrorStackTraceLimit);
864 }
865
866 return true;
867}
868
869bool NoExtension(const v8::FunctionCallbackInfo<v8::Value>&) { return false; }
870
871bool IsBuiltinFunction(Isolate* isolate, HeapObject object,
872 Builtins::Name builtin_index) {
873 if (!object->IsJSFunction()) return false;
874 JSFunction const function = JSFunction::cast(object);
875 return function->code() == isolate->builtins()->builtin(builtin_index);
876}
877
878void CaptureAsyncStackTrace(Isolate* isolate, Handle<JSPromise> promise,
879 FrameArrayBuilder* builder) {
880 while (!builder->full()) {
881 // Check that the {promise} is not settled.
882 if (promise->status() != Promise::kPending) return;
883
884 // Check that we have exactly one PromiseReaction on the {promise}.
885 if (!promise->reactions()->IsPromiseReaction()) return;
886 Handle<PromiseReaction> reaction(
887 PromiseReaction::cast(promise->reactions()), isolate);
888 if (!reaction->next()->IsSmi()) return;
889
890 // Check if the {reaction} has one of the known async function or
891 // async generator continuations as its fulfill handler.
892 if (IsBuiltinFunction(isolate, reaction->fulfill_handler(),
893 Builtins::kAsyncFunctionAwaitResolveClosure) ||
894 IsBuiltinFunction(isolate, reaction->fulfill_handler(),
895 Builtins::kAsyncGeneratorAwaitResolveClosure) ||
896 IsBuiltinFunction(isolate, reaction->fulfill_handler(),
897 Builtins::kAsyncGeneratorYieldResolveClosure)) {
898 // Now peak into the handlers' AwaitContext to get to
899 // the JSGeneratorObject for the async function.
900 Handle<Context> context(
901 JSFunction::cast(reaction->fulfill_handler())->context(), isolate);
902 Handle<JSGeneratorObject> generator_object(
903 JSGeneratorObject::cast(context->extension()), isolate);
904 CHECK(generator_object->is_suspended());
905
906 // Append async frame corresponding to the {generator_object}.
907 builder->AppendAsyncFrame(generator_object);
908
909 // Try to continue from here.
910 if (generator_object->IsJSAsyncFunctionObject()) {
911 Handle<JSAsyncFunctionObject> async_function_object =
912 Handle<JSAsyncFunctionObject>::cast(generator_object);
913 promise = handle(async_function_object->promise(), isolate);
914 } else {
915 Handle<JSAsyncGeneratorObject> async_generator_object =
916 Handle<JSAsyncGeneratorObject>::cast(generator_object);
917 if (async_generator_object->queue()->IsUndefined(isolate)) return;
918 Handle<AsyncGeneratorRequest> async_generator_request(
919 AsyncGeneratorRequest::cast(async_generator_object->queue()),
920 isolate);
921 promise = handle(JSPromise::cast(async_generator_request->promise()),
922 isolate);
923 }
924 } else if (IsBuiltinFunction(isolate, reaction->fulfill_handler(),
925 Builtins::kPromiseAllResolveElementClosure)) {
926 Handle<JSFunction> function(JSFunction::cast(reaction->fulfill_handler()),
927 isolate);
928 Handle<Context> context(function->context(), isolate);
929
930 // We store the offset of the promise into the {function}'s
931 // hash field for promise resolve element callbacks.
932 int const offset = Smi::ToInt(Smi::cast(function->GetIdentityHash())) - 1;
933 builder->AppendPromiseAllFrame(context, offset);
934
935 // Now peak into the Promise.all() resolve element context to
936 // find the promise capability that's being resolved when all
937 // the concurrent promises resolve.
938 int const index =
939 PromiseBuiltins::kPromiseAllResolveElementCapabilitySlot;
940 Handle<PromiseCapability> capability(
941 PromiseCapability::cast(context->get(index)), isolate);
942 if (!capability->promise()->IsJSPromise()) return;
943 promise = handle(JSPromise::cast(capability->promise()), isolate);
944 } else {
945 // We have some generic promise chain here, so try to
946 // continue with the chained promise on the reaction
947 // (only works for native promise chains).
948 Handle<HeapObject> promise_or_capability(
949 reaction->promise_or_capability(), isolate);
950 if (promise_or_capability->IsJSPromise()) {
951 promise = Handle<JSPromise>::cast(promise_or_capability);
952 } else if (promise_or_capability->IsPromiseCapability()) {
953 Handle<PromiseCapability> capability =
954 Handle<PromiseCapability>::cast(promise_or_capability);
955 if (!capability->promise()->IsJSPromise()) return;
956 promise = handle(JSPromise::cast(capability->promise()), isolate);
957 } else {
958 // Otherwise the {promise_or_capability} must be undefined here.
959 CHECK(promise_or_capability->IsUndefined(isolate));
960 return;
961 }
962 }
963 }
964}
965
966namespace {
967
968struct CaptureStackTraceOptions {
969 int limit;
970 // 'filter_mode' and 'skip_mode' are somewhat orthogonal. 'filter_mode'
971 // specifies whether to capture all frames, or just frames in the same
972 // security context. While 'skip_mode' allows skipping the first frame.
973 FrameSkipMode skip_mode;
974 FrameArrayBuilder::FrameFilterMode filter_mode;
975
976 bool capture_builtin_exit_frames;
977 bool capture_only_frames_subject_to_debugging;
978 bool async_stack_trace;
979
980 enum CaptureResult { RAW_FRAME_ARRAY, STACK_TRACE_FRAME_ARRAY };
981 CaptureResult capture_result;
982};
983
984Handle<Object> CaptureStackTrace(Isolate* isolate, Handle<Object> caller,
985 CaptureStackTraceOptions options) {
986 DisallowJavascriptExecution no_js(isolate);
987
988 wasm::WasmCodeRefScope code_ref_scope;
989 FrameArrayBuilder builder(isolate, options.skip_mode, options.limit, caller,
990 options.filter_mode);
991
992 // Build the regular stack trace, and remember the last relevant
993 // frame ID and inlined index (for the async stack trace handling
994 // below, which starts from this last frame).
995 for (StackFrameIterator it(isolate); !it.done() && !builder.full();
996 it.Advance()) {
997 StackFrame* const frame = it.frame();
998 switch (frame->type()) {
999 case StackFrame::JAVA_SCRIPT_BUILTIN_CONTINUATION:
1000 case StackFrame::JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH:
1001 case StackFrame::OPTIMIZED:
1002 case StackFrame::INTERPRETED:
1003 case StackFrame::BUILTIN:
1004 case StackFrame::WASM_COMPILED:
1005 case StackFrame::WASM_INTERPRETER_ENTRY: {
1006 // A standard frame may include many summarized frames (due to
1007 // inlining).
1008 std::vector<FrameSummary> frames;
1009 StandardFrame::cast(frame)->Summarize(&frames);
1010 for (size_t i = frames.size(); i-- != 0 && !builder.full();) {
1011 auto& summary = frames[i];
1012 if (options.capture_only_frames_subject_to_debugging &&
1013 !summary.is_subject_to_debugging()) {
1014 continue;
1015 }
1016
1017 if (summary.IsJavaScript()) {
1018 //=========================================================
1019 // Handle a JavaScript frame.
1020 //=========================================================
1021 auto const& java_script = summary.AsJavaScript();
1022 builder.AppendJavaScriptFrame(java_script);
1023 } else if (summary.IsWasmCompiled()) {
1024 //=========================================================
1025 // Handle a WASM compiled frame.
1026 //=========================================================
1027 auto const& wasm_compiled = summary.AsWasmCompiled();
1028 builder.AppendWasmCompiledFrame(wasm_compiled);
1029 } else if (summary.IsWasmInterpreted()) {
1030 //=========================================================
1031 // Handle a WASM interpreted frame.
1032 //=========================================================
1033 auto const& wasm_interpreted = summary.AsWasmInterpreted();
1034 builder.AppendWasmInterpretedFrame(wasm_interpreted);
1035 }
1036 }
1037 break;
1038 }
1039
1040 case StackFrame::BUILTIN_EXIT:
1041 if (!options.capture_builtin_exit_frames) continue;
1042
1043 // BuiltinExitFrames are not standard frames, so they do not have
1044 // Summarize(). However, they may have one JS frame worth showing.
1045 builder.AppendBuiltinExitFrame(BuiltinExitFrame::cast(frame));
1046 break;
1047
1048 default:
1049 break;
1050 }
1051 }
1052
1053 // If --async-stack-traces are enabled and the "current microtask" is a
1054 // PromiseReactionJobTask, we try to enrich the stack trace with async
1055 // frames.
1056 if (options.async_stack_trace) {
1057 Handle<Object> current_microtask = isolate->factory()->current_microtask();
1058 if (current_microtask->IsPromiseReactionJobTask()) {
1059 Handle<PromiseReactionJobTask> promise_reaction_job_task =
1060 Handle<PromiseReactionJobTask>::cast(current_microtask);
1061 // Check if the {reaction} has one of the known async function or
1062 // async generator continuations as its fulfill handler.
1063 if (IsBuiltinFunction(isolate, promise_reaction_job_task->handler(),
1064 Builtins::kAsyncFunctionAwaitResolveClosure) ||
1065 IsBuiltinFunction(isolate, promise_reaction_job_task->handler(),
1066 Builtins::kAsyncGeneratorAwaitResolveClosure) ||
1067 IsBuiltinFunction(isolate, promise_reaction_job_task->handler(),
1068 Builtins::kAsyncGeneratorYieldResolveClosure)) {
1069 // Now peak into the handlers' AwaitContext to get to
1070 // the JSGeneratorObject for the async function.
1071 Handle<Context> context(
1072 JSFunction::cast(promise_reaction_job_task->handler())->context(),
1073 isolate);
1074 Handle<JSGeneratorObject> generator_object(
1075 JSGeneratorObject::cast(context->extension()), isolate);
1076 if (generator_object->is_executing()) {
1077 if (generator_object->IsJSAsyncFunctionObject()) {
1078 Handle<JSAsyncFunctionObject> async_function_object =
1079 Handle<JSAsyncFunctionObject>::cast(generator_object);
1080 Handle<JSPromise> promise(async_function_object->promise(),
1081 isolate);
1082 CaptureAsyncStackTrace(isolate, promise, &builder);
1083 } else {
1084 Handle<JSAsyncGeneratorObject> async_generator_object =
1085 Handle<JSAsyncGeneratorObject>::cast(generator_object);
1086 Handle<AsyncGeneratorRequest> async_generator_request(
1087 AsyncGeneratorRequest::cast(async_generator_object->queue()),
1088 isolate);
1089 Handle<JSPromise> promise(
1090 JSPromise::cast(async_generator_request->promise()), isolate);
1091 CaptureAsyncStackTrace(isolate, promise, &builder);
1092 }
1093 }
1094 } else {
1095 // The {promise_reaction_job_task} doesn't belong to an await (or
1096 // yield inside an async generator), but we might still be able to
1097 // find an async frame if we follow along the chain of promises on
1098 // the {promise_reaction_job_task}.
1099 Handle<HeapObject> promise_or_capability(
1100 promise_reaction_job_task->promise_or_capability(), isolate);
1101 if (promise_or_capability->IsJSPromise()) {
1102 Handle<JSPromise> promise =
1103 Handle<JSPromise>::cast(promise_or_capability);
1104 CaptureAsyncStackTrace(isolate, promise, &builder);
1105 }
1106 }
1107 }
1108 }
1109
1110 // TODO(yangguo): Queue this structured stack trace for preprocessing on GC.
1111 if (options.capture_result == CaptureStackTraceOptions::RAW_FRAME_ARRAY) {
1112 return builder.GetElements();
1113 }
1114 return builder.GetElementsAsStackTraceFrameArray();
1115}
1116
1117} // namespace
1118
1119Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object,
1120 FrameSkipMode mode,
1121 Handle<Object> caller) {
1122 int limit;
1123 if (!GetStackTraceLimit(this, &limit)) return factory()->undefined_value();
1124
1125 CaptureStackTraceOptions options;
1126 options.limit = limit;
1127 options.skip_mode = mode;
1128 options.capture_builtin_exit_frames = true;
1129 options.async_stack_trace = FLAG_async_stack_traces;
1130 options.filter_mode = FrameArrayBuilder::CURRENT_SECURITY_CONTEXT;
1131 options.capture_only_frames_subject_to_debugging = false;
1132 options.capture_result = CaptureStackTraceOptions::RAW_FRAME_ARRAY;
1133
1134 return CaptureStackTrace(this, caller, options);
1135}
1136
1137MaybeHandle<JSReceiver> Isolate::CaptureAndSetDetailedStackTrace(
1138 Handle<JSReceiver> error_object) {
1139 if (capture_stack_trace_for_uncaught_exceptions_) {
1140 // Capture stack trace for a detailed exception message.
1141 Handle<Name> key = factory()->detailed_stack_trace_symbol();
1142 Handle<FixedArray> stack_trace = CaptureCurrentStackTrace(
1143 stack_trace_for_uncaught_exceptions_frame_limit_,
1144 stack_trace_for_uncaught_exceptions_options_);
1145 RETURN_ON_EXCEPTION(
1146 this,
1147 Object::SetProperty(this, error_object, key, stack_trace,
1148 StoreOrigin::kMaybeKeyed,
1149 Just(ShouldThrow::kThrowOnError)),
1150 JSReceiver);
1151 }
1152 return error_object;
1153}
1154
1155MaybeHandle<JSReceiver> Isolate::CaptureAndSetSimpleStackTrace(
1156 Handle<JSReceiver> error_object, FrameSkipMode mode,
1157 Handle<Object> caller) {
1158 // Capture stack trace for simple stack trace string formatting.
1159 Handle<Name> key = factory()->stack_trace_symbol();
1160 Handle<Object> stack_trace =
1161 CaptureSimpleStackTrace(error_object, mode, caller);
1162 RETURN_ON_EXCEPTION(this,
1163 Object::SetProperty(this, error_object, key, stack_trace,
1164 StoreOrigin::kMaybeKeyed,
1165 Just(ShouldThrow::kThrowOnError)),
1166 JSReceiver);
1167 return error_object;
1168}
1169
1170Handle<FixedArray> Isolate::GetDetailedStackTrace(
1171 Handle<JSObject> error_object) {
1172 Handle<Name> key_detailed = factory()->detailed_stack_trace_symbol();
1173 Handle<Object> stack_trace =
1174 JSReceiver::GetDataProperty(error_object, key_detailed);
1175 if (stack_trace->IsFixedArray()) return Handle<FixedArray>::cast(stack_trace);
1176 return Handle<FixedArray>();
1177}
1178
1179Address Isolate::GetAbstractPC(int* line, int* column) {
1180 JavaScriptFrameIterator it(this);
1181
1182 if (it.done()) {
1183 *line = -1;
1184 *column = -1;
1185 return kNullAddress;
1186 }
1187 JavaScriptFrame* frame = it.frame();
1188 DCHECK(!frame->is_builtin());
1189
1190 Handle<SharedFunctionInfo> shared = handle(frame->function()->shared(), this);
1191 SharedFunctionInfo::EnsureSourcePositionsAvailable(this, shared);
1192 int position = frame->position();
1193
1194 Object maybe_script = frame->function()->shared()->script();
1195 if (maybe_script->IsScript()) {
1196 Handle<Script> script(Script::cast(maybe_script), this);
1197 Script::PositionInfo info;
1198 Script::GetPositionInfo(script, position, &info, Script::WITH_OFFSET);
1199 *line = info.line + 1;
1200 *column = info.column + 1;
1201 } else {
1202 *line = position;
1203 *column = -1;
1204 }
1205
1206 if (frame->is_interpreted()) {
1207 InterpretedFrame* iframe = static_cast<InterpretedFrame*>(frame);
1208 Address bytecode_start =
1209 iframe->GetBytecodeArray()->GetFirstBytecodeAddress();
1210 return bytecode_start + iframe->GetBytecodeOffset();
1211 }
1212
1213 return frame->pc();
1214}
1215
1216Handle<FixedArray> Isolate::CaptureCurrentStackTrace(
1217 int frame_limit, StackTrace::StackTraceOptions stack_trace_options) {
1218 CaptureStackTraceOptions options;
1219 options.limit = Max(frame_limit, 0); // Ensure no negative values.
1220 options.skip_mode = SKIP_NONE;
1221 options.capture_builtin_exit_frames = false;
1222 options.async_stack_trace = false;
1223 options.filter_mode =
1224 (stack_trace_options & StackTrace::kExposeFramesAcrossSecurityOrigins)
1225 ? FrameArrayBuilder::ALL
1226 : FrameArrayBuilder::CURRENT_SECURITY_CONTEXT;
1227 options.capture_only_frames_subject_to_debugging = true;
1228 options.capture_result = CaptureStackTraceOptions::STACK_TRACE_FRAME_ARRAY;
1229
1230 return Handle<FixedArray>::cast(
1231 CaptureStackTrace(this, factory()->undefined_value(), options));
1232}
1233
1234void Isolate::PrintStack(FILE* out, PrintStackMode mode) {
1235 if (stack_trace_nesting_level_ == 0) {
1236 stack_trace_nesting_level_++;
1237 StringStream::ClearMentionedObjectCache(this);
1238 HeapStringAllocator allocator;
1239 StringStream accumulator(&allocator);
1240 incomplete_message_ = &accumulator;
1241 PrintStack(&accumulator, mode);
1242 accumulator.OutputToFile(out);
1243 InitializeLoggingAndCounters();
1244 accumulator.Log(this);
1245 incomplete_message_ = nullptr;
1246 stack_trace_nesting_level_ = 0;
1247 } else if (stack_trace_nesting_level_ == 1) {
1248 stack_trace_nesting_level_++;
1249 base::OS::PrintError(
1250 "\n\nAttempt to print stack while printing stack (double fault)\n");
1251 base::OS::PrintError(
1252 "If you are lucky you may find a partial stack dump on stdout.\n\n");
1253 incomplete_message_->OutputToFile(out);
1254 }
1255}
1256
1257
1258static void PrintFrames(Isolate* isolate,
1259 StringStream* accumulator,
1260 StackFrame::PrintMode mode) {
1261 StackFrameIterator it(isolate);
1262 for (int i = 0; !it.done(); it.Advance()) {
1263 it.frame()->Print(accumulator, mode, i++);
1264 }
1265}
1266
1267void Isolate::PrintStack(StringStream* accumulator, PrintStackMode mode) {
1268 HandleScope scope(this);
1269 wasm::WasmCodeRefScope wasm_code_ref_scope;
1270 DCHECK(accumulator->IsMentionedObjectCacheClear(this));
1271
1272 // Avoid printing anything if there are no frames.
1273 if (c_entry_fp(thread_local_top()) == 0) return;
1274
1275 accumulator->Add(
1276 "\n==== JS stack trace =========================================\n\n");
1277 PrintFrames(this, accumulator, StackFrame::OVERVIEW);
1278 if (mode == kPrintStackVerbose) {
1279 accumulator->Add(
1280 "\n==== Details ================================================\n\n");
1281 PrintFrames(this, accumulator, StackFrame::DETAILS);
1282 accumulator->PrintMentionedObjectCache(this);
1283 }
1284 accumulator->Add("=====================\n\n");
1285}
1286
1287
1288void Isolate::SetFailedAccessCheckCallback(
1289 v8::FailedAccessCheckCallback callback) {
1290 thread_local_top()->failed_access_check_callback_ = callback;
1291}
1292
1293
1294void Isolate::ReportFailedAccessCheck(Handle<JSObject> receiver) {
1295 if (!thread_local_top()->failed_access_check_callback_) {
1296 return ScheduleThrow(*factory()->NewTypeError(MessageTemplate::kNoAccess));
1297 }
1298
1299 DCHECK(receiver->IsAccessCheckNeeded());
1300 DCHECK(!context().is_null());
1301
1302 // Get the data object from access check info.
1303 HandleScope scope(this);
1304 Handle<Object> data;
1305 { DisallowHeapAllocation no_gc;
1306 AccessCheckInfo access_check_info = AccessCheckInfo::Get(this, receiver);
1307 if (access_check_info.is_null()) {
1308 AllowHeapAllocation doesnt_matter_anymore;
1309 return ScheduleThrow(
1310 *factory()->NewTypeError(MessageTemplate::kNoAccess));
1311 }
1312 data = handle(access_check_info->data(), this);
1313 }
1314
1315 // Leaving JavaScript.
1316 VMState<EXTERNAL> state(this);
1317 thread_local_top()->failed_access_check_callback_(
1318 v8::Utils::ToLocal(receiver), v8::ACCESS_HAS, v8::Utils::ToLocal(data));
1319}
1320
1321
1322bool Isolate::MayAccess(Handle<Context> accessing_context,
1323 Handle<JSObject> receiver) {
1324 DCHECK(receiver->IsJSGlobalProxy() || receiver->IsAccessCheckNeeded());
1325
1326 // Check for compatibility between the security tokens in the
1327 // current lexical context and the accessed object.
1328
1329 // During bootstrapping, callback functions are not enabled yet.
1330 if (bootstrapper()->IsActive()) return true;
1331 {
1332 DisallowHeapAllocation no_gc;
1333
1334 if (receiver->IsJSGlobalProxy()) {
1335 Object receiver_context =
1336 JSGlobalProxy::cast(*receiver)->native_context();
1337 if (!receiver_context->IsContext()) return false;
1338
1339 // Get the native context of current top context.
1340 // avoid using Isolate::native_context() because it uses Handle.
1341 Context native_context =
1342 accessing_context->global_object()->native_context();
1343 if (receiver_context == native_context) return true;
1344
1345 if (Context::cast(receiver_context)->security_token() ==
1346 native_context->security_token())
1347 return true;
1348 }
1349 }
1350
1351 HandleScope scope(this);
1352 Handle<Object> data;
1353 v8::AccessCheckCallback callback = nullptr;
1354 { DisallowHeapAllocation no_gc;
1355 AccessCheckInfo access_check_info = AccessCheckInfo::Get(this, receiver);
1356 if (access_check_info.is_null()) return false;
1357 Object fun_obj = access_check_info->callback();
1358 callback = v8::ToCData<v8::AccessCheckCallback>(fun_obj);
1359 data = handle(access_check_info->data(), this);
1360 }
1361
1362 LOG(this, ApiSecurityCheck());
1363
1364 {
1365 // Leaving JavaScript.
1366 VMState<EXTERNAL> state(this);
1367 return callback(v8::Utils::ToLocal(accessing_context),
1368 v8::Utils::ToLocal(receiver), v8::Utils::ToLocal(data));
1369 }
1370}
1371
1372Object Isolate::StackOverflow() {
1373 if (FLAG_abort_on_stack_or_string_length_overflow) {
1374 FATAL("Aborting on stack overflow");
1375 }
1376
1377 DisallowJavascriptExecution no_js(this);
1378 HandleScope scope(this);
1379
1380 Handle<JSFunction> fun = range_error_function();
1381 Handle<Object> msg = factory()->NewStringFromAsciiChecked(
1382 MessageFormatter::TemplateString(MessageTemplate::kStackOverflow));
1383 Handle<Object> no_caller;
1384 Handle<Object> exception;
1385 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1386 this, exception,
1387 ErrorUtils::Construct(this, fun, fun, msg, SKIP_NONE, no_caller, true));
1388
1389 Throw(*exception, nullptr);
1390
1391#ifdef VERIFY_HEAP
1392 if (FLAG_verify_heap && FLAG_stress_compaction) {
1393 heap()->CollectAllGarbage(Heap::kNoGCFlags,
1394 GarbageCollectionReason::kTesting);
1395 }
1396#endif // VERIFY_HEAP
1397
1398 return ReadOnlyRoots(heap()).exception();
1399}
1400
1401Object Isolate::TerminateExecution() {
1402 return Throw(ReadOnlyRoots(this).termination_exception(), nullptr);
1403}
1404
1405void Isolate::CancelTerminateExecution() {
1406 if (try_catch_handler()) {
1407 try_catch_handler()->has_terminated_ = false;
1408 }
1409 if (has_pending_exception() &&
1410 pending_exception() == ReadOnlyRoots(this).termination_exception()) {
1411 thread_local_top()->external_caught_exception_ = false;
1412 clear_pending_exception();
1413 }
1414 if (has_scheduled_exception() &&
1415 scheduled_exception() == ReadOnlyRoots(this).termination_exception()) {
1416 thread_local_top()->external_caught_exception_ = false;
1417 clear_scheduled_exception();
1418 }
1419}
1420
1421
1422void Isolate::RequestInterrupt(InterruptCallback callback, void* data) {
1423 ExecutionAccess access(this);
1424 api_interrupts_queue_.push(InterruptEntry(callback, data));
1425 stack_guard()->RequestApiInterrupt();
1426}
1427
1428
1429void Isolate::InvokeApiInterruptCallbacks() {
1430 RuntimeCallTimerScope runtimeTimer(
1431 this, RuntimeCallCounterId::kInvokeApiInterruptCallbacks);
1432 // Note: callback below should be called outside of execution access lock.
1433 while (true) {
1434 InterruptEntry entry;
1435 {
1436 ExecutionAccess access(this);
1437 if (api_interrupts_queue_.empty()) return;
1438 entry = api_interrupts_queue_.front();
1439 api_interrupts_queue_.pop();
1440 }
1441 VMState<EXTERNAL> state(this);
1442 HandleScope handle_scope(this);
1443 entry.first(reinterpret_cast<v8::Isolate*>(this), entry.second);
1444 }
1445}
1446
1447
1448void ReportBootstrappingException(Handle<Object> exception,
1449 MessageLocation* location) {
1450 base::OS::PrintError("Exception thrown during bootstrapping\n");
1451 if (location == nullptr || location->script().is_null()) return;
1452 // We are bootstrapping and caught an error where the location is set
1453 // and we have a script for the location.
1454 // In this case we could have an extension (or an internal error
1455 // somewhere) and we print out the line number at which the error occurred
1456 // to the console for easier debugging.
1457 int line_number =
1458 location->script()->GetLineNumber(location->start_pos()) + 1;
1459 if (exception->IsString() && location->script()->name()->IsString()) {
1460 base::OS::PrintError(
1461 "Extension or internal compilation error: %s in %s at line %d.\n",
1462 String::cast(*exception)->ToCString().get(),
1463 String::cast(location->script()->name())->ToCString().get(),
1464 line_number);
1465 } else if (location->script()->name()->IsString()) {
1466 base::OS::PrintError(
1467 "Extension or internal compilation error in %s at line %d.\n",
1468 String::cast(location->script()->name())->ToCString().get(),
1469 line_number);
1470 } else if (exception->IsString()) {
1471 base::OS::PrintError("Extension or internal compilation error: %s.\n",
1472 String::cast(*exception)->ToCString().get());
1473 } else {
1474 base::OS::PrintError("Extension or internal compilation error.\n");
1475 }
1476#ifdef OBJECT_PRINT
1477 // Since comments and empty lines have been stripped from the source of
1478 // builtins, print the actual source here so that line numbers match.
1479 if (location->script()->source()->IsString()) {
1480 Handle<String> src(String::cast(location->script()->source()),
1481 location->script()->GetIsolate());
1482 PrintF("Failing script:");
1483 int len = src->length();
1484 if (len == 0) {
1485 PrintF(" <not available>\n");
1486 } else {
1487 PrintF("\n");
1488 int line_number = 1;
1489 PrintF("%5d: ", line_number);
1490 for (int i = 0; i < len; i++) {
1491 uint16_t character = src->Get(i);
1492 PrintF("%c", character);
1493 if (character == '\n' && i < len - 2) {
1494 PrintF("%5d: ", ++line_number);
1495 }
1496 }
1497 PrintF("\n");
1498 }
1499 }
1500#endif
1501}
1502
1503Object Isolate::Throw(Object raw_exception, MessageLocation* location) {
1504 DCHECK(!has_pending_exception());
1505
1506 HandleScope scope(this);
1507 Handle<Object> exception(raw_exception, this);
1508
1509 if (FLAG_print_all_exceptions) {
1510 printf("=========================================================\n");
1511 printf("Exception thrown:\n");
1512 if (location) {
1513 Handle<Script> script = location->script();
1514 Handle<Object> name(script->GetNameOrSourceURL(), this);
1515 printf("at ");
1516 if (name->IsString() && String::cast(*name)->length() > 0)
1517 String::cast(*name)->PrintOn(stdout);
1518 else
1519 printf("<anonymous>");
1520// Script::GetLineNumber and Script::GetColumnNumber can allocate on the heap to
1521// initialize the line_ends array, so be careful when calling them.
1522#ifdef DEBUG
1523 if (AllowHeapAllocation::IsAllowed()) {
1524#else
1525 if ((false)) {
1526#endif
1527 printf(", %d:%d - %d:%d\n",
1528 Script::GetLineNumber(script, location->start_pos()) + 1,
1529 Script::GetColumnNumber(script, location->start_pos()),
1530 Script::GetLineNumber(script, location->end_pos()) + 1,
1531 Script::GetColumnNumber(script, location->end_pos()));
1532 // Make sure to update the raw exception pointer in case it moved.
1533 raw_exception = *exception;
1534 } else {
1535 printf(", line %d\n", script->GetLineNumber(location->start_pos()) + 1);
1536 }
1537 }
1538 raw_exception->Print();
1539 printf("Stack Trace:\n");
1540 PrintStack(stdout);
1541 printf("=========================================================\n");
1542 }
1543
1544 // Determine whether a message needs to be created for the given exception
1545 // depending on the following criteria:
1546 // 1) External v8::TryCatch missing: Always create a message because any
1547 // JavaScript handler for a finally-block might re-throw to top-level.
1548 // 2) External v8::TryCatch exists: Only create a message if the handler
1549 // captures messages or is verbose (which reports despite the catch).
1550 // 3) ReThrow from v8::TryCatch: The message from a previous throw still
1551 // exists and we preserve it instead of creating a new message.
1552 bool requires_message = try_catch_handler() == nullptr ||
1553 try_catch_handler()->is_verbose_ ||
1554 try_catch_handler()->capture_message_;
1555 bool rethrowing_message = thread_local_top()->rethrowing_message_;
1556
1557 thread_local_top()->rethrowing_message_ = false;
1558
1559 // Notify debugger of exception.
1560 if (is_catchable_by_javascript(raw_exception)) {
1561 debug()->OnThrow(exception);
1562 }
1563
1564 // Generate the message if required.
1565 if (requires_message && !rethrowing_message) {
1566 MessageLocation computed_location;
1567 // If no location was specified we try to use a computed one instead.
1568 if (location == nullptr && ComputeLocation(&computed_location)) {
1569 location = &computed_location;
1570 }
1571
1572 if (bootstrapper()->IsActive()) {
1573 // It's not safe to try to make message objects or collect stack traces
1574 // while the bootstrapper is active since the infrastructure may not have
1575 // been properly initialized.
1576 ReportBootstrappingException(exception, location);
1577 } else {
1578 Handle<Object> message_obj = CreateMessage(exception, location);
1579 thread_local_top()->pending_message_obj_ = *message_obj;
1580
1581 // For any exception not caught by JavaScript, even when an external
1582 // handler is present:
1583 // If the abort-on-uncaught-exception flag is specified, and if the
1584 // embedder didn't specify a custom uncaught exception callback,
1585 // or if the custom callback determined that V8 should abort, then
1586 // abort.
1587 if (FLAG_abort_on_uncaught_exception) {
1588 CatchType prediction = PredictExceptionCatcher();
1589 if ((prediction == NOT_CAUGHT || prediction == CAUGHT_BY_EXTERNAL) &&
1590 (!abort_on_uncaught_exception_callback_ ||
1591 abort_on_uncaught_exception_callback_(
1592 reinterpret_cast<v8::Isolate*>(this)))) {
1593 // Prevent endless recursion.
1594 FLAG_abort_on_uncaught_exception = false;
1595 // This flag is intended for use by JavaScript developers, so
1596 // print a user-friendly stack trace (not an internal one).
1597 PrintF(stderr, "%s\n\nFROM\n",
1598 MessageHandler::GetLocalizedMessage(this, message_obj).get());
1599 PrintCurrentStackTrace(stderr);
1600 base::OS::Abort();
1601 }
1602 }
1603 }
1604 }
1605
1606 // Set the exception being thrown.
1607 set_pending_exception(*exception);
1608 return ReadOnlyRoots(heap()).exception();
1609}
1610
1611Object Isolate::ReThrow(Object exception) {
1612 DCHECK(!has_pending_exception());
1613
1614 // Set the exception being re-thrown.
1615 set_pending_exception(exception);
1616 return ReadOnlyRoots(heap()).exception();
1617}
1618
1619Object Isolate::UnwindAndFindHandler() {
1620 Object exception = pending_exception();
1621
1622 auto FoundHandler = [&](Context context, Address instruction_start,
1623 intptr_t handler_offset,
1624 Address constant_pool_address, Address handler_sp,
1625 Address handler_fp) {
1626 // Store information to be consumed by the CEntry.
1627 thread_local_top()->pending_handler_context_ = context;
1628 thread_local_top()->pending_handler_entrypoint_ =
1629 instruction_start + handler_offset;
1630 thread_local_top()->pending_handler_constant_pool_ = constant_pool_address;
1631 thread_local_top()->pending_handler_fp_ = handler_fp;
1632 thread_local_top()->pending_handler_sp_ = handler_sp;
1633
1634 // Return and clear pending exception.
1635 clear_pending_exception();
1636 return exception;
1637 };
1638
1639 // Special handling of termination exceptions, uncatchable by JavaScript and
1640 // Wasm code, we unwind the handlers until the top ENTRY handler is found.
1641 bool catchable_by_js = is_catchable_by_javascript(exception);
1642
1643 // Compute handler and stack unwinding information by performing a full walk
1644 // over the stack and dispatching according to the frame type.
1645 for (StackFrameIterator iter(this);; iter.Advance()) {
1646 // Handler must exist.
1647 DCHECK(!iter.done());
1648
1649 StackFrame* frame = iter.frame();
1650
1651 switch (frame->type()) {
1652 case StackFrame::ENTRY:
1653 case StackFrame::CONSTRUCT_ENTRY: {
1654 // For JSEntry frames we always have a handler.
1655 StackHandler* handler = frame->top_handler();
1656
1657 // Restore the next handler.
1658 thread_local_top()->handler_ = handler->next_address();
1659
1660 // Gather information from the handler.
1661 Code code = frame->LookupCode();
1662 HandlerTable table(code);
1663 return FoundHandler(Context(), code->InstructionStart(),
1664 table.LookupReturn(0), code->constant_pool(),
1665 handler->address() + StackHandlerConstants::kSize,
1666 0);
1667 }
1668
1669 case StackFrame::WASM_COMPILED: {
1670 if (trap_handler::IsThreadInWasm()) {
1671 trap_handler::ClearThreadInWasm();
1672 }
1673
1674 // For WebAssembly frames we perform a lookup in the handler table.
1675 if (!catchable_by_js) break;
1676 // This code ref scope is here to avoid a check failure when looking up
1677 // the code. It's not actually necessary to keep the code alive as it's
1678 // currently being executed.
1679 wasm::WasmCodeRefScope code_ref_scope;
1680 WasmCompiledFrame* wasm_frame = static_cast<WasmCompiledFrame*>(frame);
1681 int stack_slots = 0; // Will contain stack slot count of frame.
1682 int offset = wasm_frame->LookupExceptionHandlerInTable(&stack_slots);
1683 if (offset < 0) break;
1684 // Compute the stack pointer from the frame pointer. This ensures that
1685 // argument slots on the stack are dropped as returning would.
1686 Address return_sp = frame->fp() +
1687 StandardFrameConstants::kFixedFrameSizeAboveFp -
1688 stack_slots * kSystemPointerSize;
1689
1690 // This is going to be handled by Wasm, so we need to set the TLS flag
1691 // again. It was cleared above assuming the frame would be unwound.
1692 trap_handler::SetThreadInWasm();
1693
1694 // Gather information from the frame.
1695 wasm::WasmCode* wasm_code =
1696 wasm_engine()->code_manager()->LookupCode(frame->pc());
1697 return FoundHandler(Context(), wasm_code->instruction_start(), offset,
1698 wasm_code->constant_pool(), return_sp, frame->fp());
1699 }
1700
1701 case StackFrame::OPTIMIZED: {
1702 // For optimized frames we perform a lookup in the handler table.
1703 if (!catchable_by_js) break;
1704 OptimizedFrame* js_frame = static_cast<OptimizedFrame*>(frame);
1705 int stack_slots = 0; // Will contain stack slot count of frame.
1706 int offset =
1707 js_frame->LookupExceptionHandlerInTable(&stack_slots, nullptr);
1708 if (offset < 0) break;
1709 // Compute the stack pointer from the frame pointer. This ensures
1710 // that argument slots on the stack are dropped as returning would.
1711 Address return_sp = frame->fp() +
1712 StandardFrameConstants::kFixedFrameSizeAboveFp -
1713 stack_slots * kSystemPointerSize;
1714
1715 // Gather information from the frame.
1716 Code code = frame->LookupCode();
1717
1718 // TODO(bmeurer): Turbofanned BUILTIN frames appear as OPTIMIZED,
1719 // but do not have a code kind of OPTIMIZED_FUNCTION.
1720 if (code->kind() == Code::OPTIMIZED_FUNCTION &&
1721 code->marked_for_deoptimization()) {
1722 // If the target code is lazy deoptimized, we jump to the original
1723 // return address, but we make a note that we are throwing, so
1724 // that the deoptimizer can do the right thing.
1725 offset = static_cast<int>(frame->pc() - code->entry());
1726 set_deoptimizer_lazy_throw(true);
1727 }
1728
1729 return FoundHandler(Context(), code->InstructionStart(), offset,
1730 code->constant_pool(), return_sp, frame->fp());
1731 }
1732
1733 case StackFrame::STUB: {
1734 // Some stubs are able to handle exceptions.
1735 if (!catchable_by_js) break;
1736 StubFrame* stub_frame = static_cast<StubFrame*>(frame);
1737 wasm::WasmCodeRefScope code_ref_scope;
1738 wasm::WasmCode* wasm_code =
1739 wasm_engine()->code_manager()->LookupCode(frame->pc());
1740 if (wasm_code != nullptr) {
1741 // It is safe to skip Wasm runtime stubs as none of them contain local
1742 // exception handlers.
1743 CHECK_EQ(wasm::WasmCode::kRuntimeStub, wasm_code->kind());
1744 CHECK_EQ(0, wasm_code->handler_table_offset());
1745 break;
1746 }
1747 Code code = stub_frame->LookupCode();
1748 if (!code->IsCode() || code->kind() != Code::BUILTIN ||
1749 !code->has_handler_table() || !code->is_turbofanned()) {
1750 break;
1751 }
1752
1753 int stack_slots = 0; // Will contain stack slot count of frame.
1754 int offset = stub_frame->LookupExceptionHandlerInTable(&stack_slots);
1755 if (offset < 0) break;
1756
1757 // Compute the stack pointer from the frame pointer. This ensures
1758 // that argument slots on the stack are dropped as returning would.
1759 Address return_sp = frame->fp() +
1760 StandardFrameConstants::kFixedFrameSizeAboveFp -
1761 stack_slots * kSystemPointerSize;
1762
1763 return FoundHandler(Context(), code->InstructionStart(), offset,
1764 code->constant_pool(), return_sp, frame->fp());
1765 }
1766
1767 case StackFrame::INTERPRETED: {
1768 // For interpreted frame we perform a range lookup in the handler table.
1769 if (!catchable_by_js) break;
1770 InterpretedFrame* js_frame = static_cast<InterpretedFrame*>(frame);
1771 int register_slots = InterpreterFrameConstants::RegisterStackSlotCount(
1772 js_frame->GetBytecodeArray()->register_count());
1773 int context_reg = 0; // Will contain register index holding context.
1774 int offset =
1775 js_frame->LookupExceptionHandlerInTable(&context_reg, nullptr);
1776 if (offset < 0) break;
1777 // Compute the stack pointer from the frame pointer. This ensures that
1778 // argument slots on the stack are dropped as returning would.
1779 // Note: This is only needed for interpreted frames that have been
1780 // materialized by the deoptimizer. If there is a handler frame
1781 // in between then {frame->sp()} would already be correct.
1782 Address return_sp = frame->fp() -
1783 InterpreterFrameConstants::kFixedFrameSizeFromFp -
1784 register_slots * kSystemPointerSize;
1785
1786 // Patch the bytecode offset in the interpreted frame to reflect the
1787 // position of the exception handler. The special builtin below will
1788 // take care of continuing to dispatch at that position. Also restore
1789 // the correct context for the handler from the interpreter register.
1790 Context context =
1791 Context::cast(js_frame->ReadInterpreterRegister(context_reg));
1792 js_frame->PatchBytecodeOffset(static_cast<int>(offset));
1793
1794 Code code =
1795 builtins()->builtin(Builtins::kInterpreterEnterBytecodeDispatch);
1796 return FoundHandler(context, code->InstructionStart(), 0,
1797 code->constant_pool(), return_sp, frame->fp());
1798 }
1799
1800 case StackFrame::BUILTIN:
1801 // For builtin frames we are guaranteed not to find a handler.
1802 if (catchable_by_js) {
1803 CHECK_EQ(-1,
1804 JavaScriptFrame::cast(frame)->LookupExceptionHandlerInTable(
1805 nullptr, nullptr));
1806 }
1807 break;
1808
1809 case StackFrame::WASM_INTERPRETER_ENTRY: {
1810 if (trap_handler::IsThreadInWasm()) {
1811 trap_handler::ClearThreadInWasm();
1812 }
1813 } break;
1814
1815 case StackFrame::JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH: {
1816 // Builtin continuation frames with catch can handle exceptions.
1817 if (!catchable_by_js) break;
1818 JavaScriptBuiltinContinuationWithCatchFrame* js_frame =
1819 JavaScriptBuiltinContinuationWithCatchFrame::cast(frame);
1820 js_frame->SetException(exception);
1821
1822 // Reconstruct the stack pointer from the frame pointer.
1823 Address return_sp = js_frame->fp() - js_frame->GetSPToFPDelta();
1824 Code code = js_frame->LookupCode();
1825 return FoundHandler(Context(), code->InstructionStart(), 0,
1826 code->constant_pool(), return_sp, frame->fp());
1827 } break;
1828
1829 default:
1830 // All other types can not handle exception.
1831 break;
1832 }
1833
1834 if (frame->is_optimized()) {
1835 // Remove per-frame stored materialized objects.
1836 bool removed = materialized_object_store_->Remove(frame->fp());
1837 USE(removed);
1838 // If there were any materialized objects, the code should be
1839 // marked for deopt.
1840 DCHECK_IMPLIES(removed, frame->LookupCode()->marked_for_deoptimization());
1841 }
1842 }
1843
1844 UNREACHABLE();
1845}
1846
1847namespace {
1848HandlerTable::CatchPrediction PredictException(JavaScriptFrame* frame) {
1849 HandlerTable::CatchPrediction prediction;
1850 if (frame->is_optimized()) {
1851 if (frame->LookupExceptionHandlerInTable(nullptr, nullptr) > 0) {
1852 // This optimized frame will catch. It's handler table does not include
1853 // exception prediction, and we need to use the corresponding handler
1854 // tables on the unoptimized code objects.
1855 std::vector<FrameSummary> summaries;
1856 frame->Summarize(&summaries);
1857 for (size_t i = summaries.size(); i != 0; i--) {
1858 const FrameSummary& summary = summaries[i - 1];
1859 Handle<AbstractCode> code = summary.AsJavaScript().abstract_code();
1860 if (code->IsCode() && code->kind() == AbstractCode::BUILTIN) {
1861 prediction = code->GetCode()->GetBuiltinCatchPrediction();
1862 if (prediction == HandlerTable::UNCAUGHT) continue;
1863 return prediction;
1864 }
1865
1866 // Must have been constructed from a bytecode array.
1867 CHECK_EQ(AbstractCode::INTERPRETED_FUNCTION, code->kind());
1868 int code_offset = summary.code_offset();
1869 HandlerTable table(code->GetBytecodeArray());
1870 int index = table.LookupRange(code_offset, nullptr, &prediction);
1871 if (index <= 0) continue;
1872 if (prediction == HandlerTable::UNCAUGHT) continue;
1873 return prediction;
1874 }
1875 }
1876 } else if (frame->LookupExceptionHandlerInTable(nullptr, &prediction) > 0) {
1877 return prediction;
1878 }
1879 return HandlerTable::UNCAUGHT;
1880}
1881
1882Isolate::CatchType ToCatchType(HandlerTable::CatchPrediction prediction) {
1883 switch (prediction) {
1884 case HandlerTable::UNCAUGHT:
1885 return Isolate::NOT_CAUGHT;
1886 case HandlerTable::CAUGHT:
1887 return Isolate::CAUGHT_BY_JAVASCRIPT;
1888 case HandlerTable::PROMISE:
1889 return Isolate::CAUGHT_BY_PROMISE;
1890 case HandlerTable::DESUGARING:
1891 return Isolate::CAUGHT_BY_DESUGARING;
1892 case HandlerTable::ASYNC_AWAIT:
1893 return Isolate::CAUGHT_BY_ASYNC_AWAIT;
1894 default:
1895 UNREACHABLE();
1896 }
1897}
1898} // anonymous namespace
1899
1900Isolate::CatchType Isolate::PredictExceptionCatcher() {
1901 Address external_handler = thread_local_top()->try_catch_handler_address();
1902 if (IsExternalHandlerOnTop(Object())) return CAUGHT_BY_EXTERNAL;
1903
1904 // Search for an exception handler by performing a full walk over the stack.
1905 for (StackFrameIterator iter(this); !iter.done(); iter.Advance()) {
1906 StackFrame* frame = iter.frame();
1907
1908 switch (frame->type()) {
1909 case StackFrame::ENTRY:
1910 case StackFrame::CONSTRUCT_ENTRY: {
1911 Address entry_handler = frame->top_handler()->next_address();
1912 // The exception has been externally caught if and only if there is an
1913 // external handler which is on top of the top-most JS_ENTRY handler.
1914 if (external_handler != kNullAddress &&
1915 !try_catch_handler()->is_verbose_) {
1916 if (entry_handler == kNullAddress ||
1917 entry_handler > external_handler) {
1918 return CAUGHT_BY_EXTERNAL;
1919 }
1920 }
1921 } break;
1922
1923 // For JavaScript frames we perform a lookup in the handler table.
1924 case StackFrame::OPTIMIZED:
1925 case StackFrame::INTERPRETED:
1926 case StackFrame::BUILTIN: {
1927 JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame);
1928 Isolate::CatchType prediction = ToCatchType(PredictException(js_frame));
1929 if (prediction == NOT_CAUGHT) break;
1930 return prediction;
1931 } break;
1932
1933 case StackFrame::STUB: {
1934 Handle<Code> code(frame->LookupCode(), this);
1935 if (!code->IsCode() || code->kind() != Code::BUILTIN ||
1936 !code->has_handler_table() || !code->is_turbofanned()) {
1937 break;
1938 }
1939
1940 CatchType prediction = ToCatchType(code->GetBuiltinCatchPrediction());
1941 if (prediction != NOT_CAUGHT) return prediction;
1942 } break;
1943
1944 case StackFrame::JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH: {
1945 Handle<Code> code(frame->LookupCode(), this);
1946 CatchType prediction = ToCatchType(code->GetBuiltinCatchPrediction());
1947 if (prediction != NOT_CAUGHT) return prediction;
1948 } break;
1949
1950 default:
1951 // All other types can not handle exception.
1952 break;
1953 }
1954 }
1955
1956 // Handler not found.
1957 return NOT_CAUGHT;
1958}
1959
1960Object Isolate::ThrowIllegalOperation() {
1961 if (FLAG_stack_trace_on_illegal) PrintStack(stdout);
1962 return Throw(ReadOnlyRoots(heap()).illegal_access_string());
1963}
1964
1965void Isolate::ScheduleThrow(Object exception) {
1966 // When scheduling a throw we first throw the exception to get the
1967 // error reporting if it is uncaught before rescheduling it.
1968 Throw(exception);
1969 PropagatePendingExceptionToExternalTryCatch();
1970 if (has_pending_exception()) {
1971 thread_local_top()->scheduled_exception_ = pending_exception();
1972 thread_local_top()->external_caught_exception_ = false;
1973 clear_pending_exception();
1974 }
1975}
1976
1977void Isolate::RestorePendingMessageFromTryCatch(v8::TryCatch* handler) {
1978 DCHECK(handler == try_catch_handler());
1979 DCHECK(handler->HasCaught());
1980 DCHECK(handler->rethrow_);
1981 DCHECK(handler->capture_message_);
1982 Object message(reinterpret_cast<Address>(handler->message_obj_));
1983 DCHECK(message->IsJSMessageObject() || message->IsTheHole(this));
1984 thread_local_top()->pending_message_obj_ = message;
1985}
1986
1987
1988void Isolate::CancelScheduledExceptionFromTryCatch(v8::TryCatch* handler) {
1989 DCHECK(has_scheduled_exception());
1990 if (reinterpret_cast<void*>(scheduled_exception().ptr()) ==
1991 handler->exception_) {
1992 DCHECK_NE(scheduled_exception(),
1993 ReadOnlyRoots(heap()).termination_exception());
1994 clear_scheduled_exception();
1995 } else {
1996 DCHECK_EQ(scheduled_exception(),
1997 ReadOnlyRoots(heap()).termination_exception());
1998 // Clear termination once we returned from all V8 frames.
1999 if (handle_scope_implementer()->CallDepthIsZero()) {
2000 thread_local_top()->external_caught_exception_ = false;
2001 clear_scheduled_exception();
2002 }
2003 }
2004 if (reinterpret_cast<void*>(thread_local_top()->pending_message_obj_.ptr()) ==
2005 handler->message_obj_) {
2006 clear_pending_message();
2007 }
2008}
2009
2010Object Isolate::PromoteScheduledException() {
2011 Object thrown = scheduled_exception();
2012 clear_scheduled_exception();
2013 // Re-throw the exception to avoid getting repeated error reporting.
2014 return ReThrow(thrown);
2015}
2016
2017void Isolate::PrintCurrentStackTrace(FILE* out) {
2018 IncrementalStringBuilder builder(this);
2019 for (StackTraceFrameIterator it(this); !it.done(); it.Advance()) {
2020 if (!it.is_javascript()) continue;
2021
2022 HandleScope scope(this);
2023 JavaScriptFrame* frame = it.javascript_frame();
2024
2025 Handle<Object> receiver(frame->receiver(), this);
2026 Handle<JSFunction> function(frame->function(), this);
2027 Handle<AbstractCode> code;
2028 int offset;
2029 if (frame->is_interpreted()) {
2030 InterpretedFrame* interpreted_frame = InterpretedFrame::cast(frame);
2031 code = handle(AbstractCode::cast(interpreted_frame->GetBytecodeArray()),
2032 this);
2033 offset = interpreted_frame->GetBytecodeOffset();
2034 } else {
2035 code = handle(AbstractCode::cast(frame->LookupCode()), this);
2036 offset = static_cast<int>(frame->pc() - code->InstructionStart());
2037 }
2038
2039 // To preserve backwards compatiblity, only append a newline when
2040 // the current stringified frame actually has characters.
2041 const int old_length = builder.Length();
2042 JSStackFrame site(this, receiver, function, code, offset);
2043 site.ToString(builder);
2044 if (old_length != builder.Length()) builder.AppendCharacter('\n');
2045 }
2046
2047 Handle<String> stack_trace = builder.Finish().ToHandleChecked();
2048 stack_trace->PrintOn(out);
2049}
2050
2051bool Isolate::ComputeLocation(MessageLocation* target) {
2052 StackTraceFrameIterator it(this);
2053 if (it.done()) return false;
2054 StandardFrame* frame = it.frame();
2055 // Compute the location from the function and the relocation info of the
2056 // baseline code. For optimized code this will use the deoptimization
2057 // information to get canonical location information.
2058 std::vector<FrameSummary> frames;
2059 wasm::WasmCodeRefScope code_ref_scope;
2060 frame->Summarize(&frames);
2061 FrameSummary& summary = frames.back();
2062 summary.EnsureSourcePositionsAvailable();
2063 int pos = summary.SourcePosition();
2064 Handle<SharedFunctionInfo> shared;
2065 Handle<Object> script = summary.script();
2066 if (!script->IsScript() ||
2067 (Script::cast(*script)->source()->IsUndefined(this))) {
2068 return false;
2069 }
2070
2071 if (summary.IsJavaScript()) {
2072 shared = handle(summary.AsJavaScript().function()->shared(), this);
2073 }
2074 *target = MessageLocation(Handle<Script>::cast(script), pos, pos + 1, shared);
2075 return true;
2076}
2077
2078bool Isolate::ComputeLocationFromException(MessageLocation* target,
2079 Handle<Object> exception) {
2080 if (!exception->IsJSObject()) return false;
2081
2082 Handle<Name> start_pos_symbol = factory()->error_start_pos_symbol();
2083 Handle<Object> start_pos = JSReceiver::GetDataProperty(
2084 Handle<JSObject>::cast(exception), start_pos_symbol);
2085 if (!start_pos->IsSmi()) return false;
2086 int start_pos_value = Handle<Smi>::cast(start_pos)->value();
2087
2088 Handle<Name> end_pos_symbol = factory()->error_end_pos_symbol();
2089 Handle<Object> end_pos = JSReceiver::GetDataProperty(
2090 Handle<JSObject>::cast(exception), end_pos_symbol);
2091 if (!end_pos->IsSmi()) return false;
2092 int end_pos_value = Handle<Smi>::cast(end_pos)->value();
2093
2094 Handle<Name> script_symbol = factory()->error_script_symbol();
2095 Handle<Object> script = JSReceiver::GetDataProperty(
2096 Handle<JSObject>::cast(exception), script_symbol);
2097 if (!script->IsScript()) return false;
2098
2099 Handle<Script> cast_script(Script::cast(*script), this);
2100 *target = MessageLocation(cast_script, start_pos_value, end_pos_value);
2101 return true;
2102}
2103
2104
2105bool Isolate::ComputeLocationFromStackTrace(MessageLocation* target,
2106 Handle<Object> exception) {
2107 if (!exception->IsJSObject()) return false;
2108 Handle<Name> key = factory()->stack_trace_symbol();
2109 Handle<Object> property =
2110 JSReceiver::GetDataProperty(Handle<JSObject>::cast(exception), key);
2111 if (!property->IsFixedArray()) return false;
2112
2113 Handle<FrameArray> elements = Handle<FrameArray>::cast(property);
2114
2115 const int frame_count = elements->FrameCount();
2116 for (int i = 0; i < frame_count; i++) {
2117 if (elements->IsWasmFrame(i) || elements->IsAsmJsWasmFrame(i)) {
2118 Handle<WasmInstanceObject> instance(elements->WasmInstance(i), this);
2119 uint32_t func_index =
2120 static_cast<uint32_t>(elements->WasmFunctionIndex(i)->value());
2121 int code_offset = elements->Offset(i)->value();
2122 bool is_at_number_conversion =
2123 elements->IsAsmJsWasmFrame(i) &&
2124 elements->Flags(i)->value() & FrameArray::kAsmJsAtNumberConversion;
2125 // WasmCode* held alive by the {GlobalWasmCodeRef}.
2126 wasm::WasmCode* code =
2127 Managed<wasm::GlobalWasmCodeRef>::cast(elements->WasmCodeObject(i))
2128 ->get()
2129 ->code();
2130 int byte_offset =
2131 FrameSummary::WasmCompiledFrameSummary::GetWasmSourcePosition(
2132 code, code_offset);
2133 int pos = WasmModuleObject::GetSourcePosition(
2134 handle(instance->module_object(), this), func_index, byte_offset,
2135 is_at_number_conversion);
2136 Handle<Script> script(instance->module_object()->script(), this);
2137
2138 *target = MessageLocation(script, pos, pos + 1);
2139 return true;
2140 }
2141
2142 Handle<JSFunction> fun = handle(elements->Function(i), this);
2143 if (!fun->shared()->IsSubjectToDebugging()) continue;
2144
2145 Object script = fun->shared()->script();
2146 if (script->IsScript() &&
2147 !(Script::cast(script)->source()->IsUndefined(this))) {
2148 Handle<SharedFunctionInfo> shared = handle(fun->shared(), this);
2149 SharedFunctionInfo::EnsureSourcePositionsAvailable(this, shared);
2150 AbstractCode abstract_code = elements->Code(i);
2151 const int code_offset = elements->Offset(i)->value();
2152 const int pos = abstract_code->SourcePosition(code_offset);
2153
2154 Handle<Script> casted_script(Script::cast(script), this);
2155 *target = MessageLocation(casted_script, pos, pos + 1);
2156 return true;
2157 }
2158 }
2159 return false;
2160}
2161
2162
2163Handle<JSMessageObject> Isolate::CreateMessage(Handle<Object> exception,
2164 MessageLocation* location) {
2165 Handle<FixedArray> stack_trace_object;
2166 if (capture_stack_trace_for_uncaught_exceptions_) {
2167 if (exception->IsJSError()) {
2168 // We fetch the stack trace that corresponds to this error object.
2169 // If the lookup fails, the exception is probably not a valid Error
2170 // object. In that case, we fall through and capture the stack trace
2171 // at this throw site.
2172 stack_trace_object =
2173 GetDetailedStackTrace(Handle<JSObject>::cast(exception));
2174 }
2175 if (stack_trace_object.is_null()) {
2176 // Not an error object, we capture stack and location at throw site.
2177 stack_trace_object = CaptureCurrentStackTrace(
2178 stack_trace_for_uncaught_exceptions_frame_limit_,
2179 stack_trace_for_uncaught_exceptions_options_);
2180 }
2181 }
2182 MessageLocation computed_location;
2183 if (location == nullptr &&
2184 (ComputeLocationFromException(&computed_location, exception) ||
2185 ComputeLocationFromStackTrace(&computed_location, exception) ||
2186 ComputeLocation(&computed_location))) {
2187 location = &computed_location;
2188 }
2189
2190 return MessageHandler::MakeMessageObject(
2191 this, MessageTemplate::kUncaughtException, location, exception,
2192 stack_trace_object);
2193}
2194
2195bool Isolate::IsJavaScriptHandlerOnTop(Object exception) {
2196 DCHECK_NE(ReadOnlyRoots(heap()).the_hole_value(), exception);
2197
2198 // For uncatchable exceptions, the JavaScript handler cannot be on top.
2199 if (!is_catchable_by_javascript(exception)) return false;
2200
2201 // Get the top-most JS_ENTRY handler, cannot be on top if it doesn't exist.
2202 Address entry_handler = Isolate::handler(thread_local_top());
2203 if (entry_handler == kNullAddress) return false;
2204
2205 // Get the address of the external handler so we can compare the address to
2206 // determine which one is closer to the top of the stack.
2207 Address external_handler = thread_local_top()->try_catch_handler_address();
2208 if (external_handler == kNullAddress) return true;
2209
2210 // The exception has been externally caught if and only if there is an
2211 // external handler which is on top of the top-most JS_ENTRY handler.
2212 //
2213 // Note, that finally clauses would re-throw an exception unless it's aborted
2214 // by jumps in control flow (like return, break, etc.) and we'll have another
2215 // chance to set proper v8::TryCatch later.
2216 return (entry_handler < external_handler);
2217}
2218
2219bool Isolate::IsExternalHandlerOnTop(Object exception) {
2220 DCHECK_NE(ReadOnlyRoots(heap()).the_hole_value(), exception);
2221
2222 // Get the address of the external handler so we can compare the address to
2223 // determine which one is closer to the top of the stack.
2224 Address external_handler = thread_local_top()->try_catch_handler_address();
2225 if (external_handler == kNullAddress) return false;
2226
2227 // For uncatchable exceptions, the external handler is always on top.
2228 if (!is_catchable_by_javascript(exception)) return true;
2229
2230 // Get the top-most JS_ENTRY handler, cannot be on top if it doesn't exist.
2231 Address entry_handler = Isolate::handler(thread_local_top());
2232 if (entry_handler == kNullAddress) return true;
2233
2234 // The exception has been externally caught if and only if there is an
2235 // external handler which is on top of the top-most JS_ENTRY handler.
2236 //
2237 // Note, that finally clauses would re-throw an exception unless it's aborted
2238 // by jumps in control flow (like return, break, etc.) and we'll have another
2239 // chance to set proper v8::TryCatch later.
2240 return (entry_handler > external_handler);
2241}
2242
2243void Isolate::ReportPendingMessagesImpl(bool report_externally) {
2244 Object exception = pending_exception();
2245
2246 // Clear the pending message object early to avoid endless recursion.
2247 Object message_obj = thread_local_top()->pending_message_obj_;
2248 clear_pending_message();
2249
2250 // For uncatchable exceptions we do nothing. If needed, the exception and the
2251 // message have already been propagated to v8::TryCatch.
2252 if (!is_catchable_by_javascript(exception)) return;
2253
2254 // Determine whether the message needs to be reported to all message handlers
2255 // depending on whether and external v8::TryCatch or an internal JavaScript
2256 // handler is on top.
2257 bool should_report_exception;
2258 if (report_externally) {
2259 // Only report the exception if the external handler is verbose.
2260 should_report_exception = try_catch_handler()->is_verbose_;
2261 } else {
2262 // Report the exception if it isn't caught by JavaScript code.
2263 should_report_exception = !IsJavaScriptHandlerOnTop(exception);
2264 }
2265
2266 // Actually report the pending message to all message handlers.
2267 if (!message_obj->IsTheHole(this) && should_report_exception) {
2268 HandleScope scope(this);
2269 Handle<JSMessageObject> message(JSMessageObject::cast(message_obj), this);
2270 Handle<Script> script(message->script(), this);
2271 int start_pos = message->start_position();
2272 int end_pos = message->end_position();
2273 MessageLocation location(script, start_pos, end_pos);
2274 MessageHandler::ReportMessage(this, &location, message);
2275 }
2276}
2277
2278void Isolate::ReportPendingMessages() {
2279 DCHECK(AllowExceptions::IsAllowed(this));
2280
2281 // The embedder might run script in response to an exception.
2282 AllowJavascriptExecutionDebugOnly allow_script(this);
2283
2284 Object exception = pending_exception();
2285
2286 // Try to propagate the exception to an external v8::TryCatch handler. If
2287 // propagation was unsuccessful, then we will get another chance at reporting
2288 // the pending message if the exception is re-thrown.
2289 bool has_been_propagated = PropagatePendingExceptionToExternalTryCatch();
2290 if (!has_been_propagated) return;
2291
2292 ReportPendingMessagesImpl(IsExternalHandlerOnTop(exception));
2293}
2294
2295void Isolate::ReportPendingMessagesFromJavaScript() {
2296 DCHECK(AllowExceptions::IsAllowed(this));
2297
2298 auto IsHandledByJavaScript = [=]() {
2299 // In this situation, the exception is always a non-terminating exception.
2300
2301 // Get the top-most JS_ENTRY handler, cannot be on top if it doesn't exist.
2302 Address entry_handler = Isolate::handler(thread_local_top());
2303 DCHECK_NE(entry_handler, kNullAddress);
2304 entry_handler = StackHandler::FromAddress(entry_handler)->next_address();
2305
2306 // Get the address of the external handler so we can compare the address to
2307 // determine which one is closer to the top of the stack.
2308 Address external_handler = thread_local_top()->try_catch_handler_address();
2309 if (external_handler == kNullAddress) return true;
2310
2311 return (entry_handler < external_handler);
2312 };
2313
2314 auto IsHandledExternally = [=]() {
2315 Address external_handler = thread_local_top()->try_catch_handler_address();
2316 if (external_handler == kNullAddress) return false;
2317
2318 // Get the top-most JS_ENTRY handler, cannot be on top if it doesn't exist.
2319 Address entry_handler = Isolate::handler(thread_local_top());
2320 DCHECK_NE(entry_handler, kNullAddress);
2321 entry_handler = StackHandler::FromAddress(entry_handler)->next_address();
2322 return (entry_handler > external_handler);
2323 };
2324
2325 auto PropagateToExternalHandler = [=]() {
2326 if (IsHandledByJavaScript()) {
2327 thread_local_top()->external_caught_exception_ = false;
2328 return false;
2329 }
2330
2331 if (!IsHandledExternally()) {
2332 thread_local_top()->external_caught_exception_ = false;
2333 return true;
2334 }
2335
2336 thread_local_top()->external_caught_exception_ = true;
2337 v8::TryCatch* handler = try_catch_handler();
2338 DCHECK(thread_local_top()->pending_message_obj_->IsJSMessageObject() ||
2339 thread_local_top()->pending_message_obj_->IsTheHole(this));
2340 handler->can_continue_ = true;
2341 handler->has_terminated_ = false;
2342 handler->exception_ = reinterpret_cast<void*>(pending_exception().ptr());
2343 // Propagate to the external try-catch only if we got an actual message.
2344 if (thread_local_top()->pending_message_obj_->IsTheHole(this)) return true;
2345
2346 handler->message_obj_ =
2347 reinterpret_cast<void*>(thread_local_top()->pending_message_obj_.ptr());
2348 return true;
2349 };
2350
2351 // Try to propagate to an external v8::TryCatch handler.
2352 if (!PropagateToExternalHandler()) return;
2353
2354 ReportPendingMessagesImpl(true);
2355}
2356
2357MessageLocation Isolate::GetMessageLocation() {
2358 DCHECK(has_pending_exception());
2359
2360 if (thread_local_top()->pending_exception_ !=
2361 ReadOnlyRoots(heap()).termination_exception() &&
2362 !thread_local_top()->pending_message_obj_->IsTheHole(this)) {
2363 Handle<JSMessageObject> message_obj(
2364 JSMessageObject::cast(thread_local_top()->pending_message_obj_), this);
2365 Handle<Script> script(message_obj->script(), this);
2366 int start_pos = message_obj->start_position();
2367 int end_pos = message_obj->end_position();
2368 return MessageLocation(script, start_pos, end_pos);
2369 }
2370
2371 return MessageLocation();
2372}
2373
2374bool Isolate::OptionalRescheduleException(bool clear_exception) {
2375 DCHECK(has_pending_exception());
2376 PropagatePendingExceptionToExternalTryCatch();
2377
2378 bool is_termination_exception =
2379 pending_exception() == ReadOnlyRoots(this).termination_exception();
2380
2381 if (is_termination_exception) {
2382 if (clear_exception) {
2383 thread_local_top()->external_caught_exception_ = false;
2384 clear_pending_exception();
2385 return false;
2386 }
2387 } else if (thread_local_top()->external_caught_exception_) {
2388 // If the exception is externally caught, clear it if there are no
2389 // JavaScript frames on the way to the C++ frame that has the
2390 // external handler.
2391 DCHECK_NE(thread_local_top()->try_catch_handler_address(), kNullAddress);
2392 Address external_handler_address =
2393 thread_local_top()->try_catch_handler_address();
2394 JavaScriptFrameIterator it(this);
2395 if (it.done() || (it.frame()->sp() > external_handler_address)) {
2396 clear_exception = true;
2397 }
2398 }
2399
2400 // Clear the exception if needed.
2401 if (clear_exception) {
2402 thread_local_top()->external_caught_exception_ = false;
2403 clear_pending_exception();
2404 return false;
2405 }
2406
2407 // Reschedule the exception.
2408 thread_local_top()->scheduled_exception_ = pending_exception();
2409 clear_pending_exception();
2410 return true;
2411}
2412
2413void Isolate::PushPromise(Handle<JSObject> promise) {
2414 ThreadLocalTop* tltop = thread_local_top();
2415 PromiseOnStack* prev = tltop->promise_on_stack_;
2416 Handle<JSObject> global_promise = global_handles()->Create(*promise);
2417 tltop->promise_on_stack_ = new PromiseOnStack(global_promise, prev);
2418}
2419
2420
2421void Isolate::PopPromise() {
2422 ThreadLocalTop* tltop = thread_local_top();
2423 if (tltop->promise_on_stack_ == nullptr) return;
2424 PromiseOnStack* prev = tltop->promise_on_stack_->prev();
2425 Handle<Object> global_promise = tltop->promise_on_stack_->promise();
2426 delete tltop->promise_on_stack_;
2427 tltop->promise_on_stack_ = prev;
2428 global_handles()->Destroy(global_promise.location());
2429}
2430
2431namespace {
2432bool InternalPromiseHasUserDefinedRejectHandler(Isolate* isolate,
2433 Handle<JSPromise> promise);
2434
2435bool PromiseHandlerCheck(Isolate* isolate, Handle<JSReceiver> handler,
2436 Handle<JSReceiver> deferred_promise) {
2437 // Recurse to the forwarding Promise, if any. This may be due to
2438 // - await reaction forwarding to the throwaway Promise, which has
2439 // a dependency edge to the outer Promise.
2440 // - PromiseIdResolveHandler forwarding to the output of .then
2441 // - Promise.all/Promise.race forwarding to a throwaway Promise, which
2442 // has a dependency edge to the generated outer Promise.
2443 // Otherwise, this is a real reject handler for the Promise.
2444 Handle<Symbol> key = isolate->factory()->promise_forwarding_handler_symbol();
2445 Handle<Object> forwarding_handler = JSReceiver::GetDataProperty(handler, key);
2446 if (forwarding_handler->IsUndefined(isolate)) {
2447 return true;
2448 }
2449
2450 if (!deferred_promise->IsJSPromise()) {
2451 return true;
2452 }
2453
2454 return InternalPromiseHasUserDefinedRejectHandler(
2455 isolate, Handle<JSPromise>::cast(deferred_promise));
2456}
2457
2458bool InternalPromiseHasUserDefinedRejectHandler(Isolate* isolate,
2459 Handle<JSPromise> promise) {
2460 // If this promise was marked as being handled by a catch block
2461 // in an async function, then it has a user-defined reject handler.
2462 if (promise->handled_hint()) return true;
2463
2464 // If this Promise is subsumed by another Promise (a Promise resolved
2465 // with another Promise, or an intermediate, hidden, throwaway Promise
2466 // within async/await), then recurse on the outer Promise.
2467 // In this case, the dependency is one possible way that the Promise
2468 // could be resolved, so it does not subsume the other following cases.
2469 Handle<Symbol> key = isolate->factory()->promise_handled_by_symbol();
2470 Handle<Object> outer_promise_obj = JSObject::GetDataProperty(promise, key);
2471 if (outer_promise_obj->IsJSPromise() &&
2472 InternalPromiseHasUserDefinedRejectHandler(
2473 isolate, Handle<JSPromise>::cast(outer_promise_obj))) {
2474 return true;
2475 }
2476
2477 if (promise->status() == Promise::kPending) {
2478 for (Handle<Object> current(promise->reactions(), isolate);
2479 !current->IsSmi();) {
2480 Handle<PromiseReaction> reaction = Handle<PromiseReaction>::cast(current);
2481 Handle<HeapObject> promise_or_capability(
2482 reaction->promise_or_capability(), isolate);
2483 if (!promise_or_capability->IsUndefined(isolate)) {
2484 Handle<JSPromise> promise = Handle<JSPromise>::cast(
2485 promise_or_capability->IsJSPromise()
2486 ? promise_or_capability
2487 : handle(Handle<PromiseCapability>::cast(promise_or_capability)
2488 ->promise(),
2489 isolate));
2490 if (reaction->reject_handler()->IsUndefined(isolate)) {
2491 if (InternalPromiseHasUserDefinedRejectHandler(isolate, promise)) {
2492 return true;
2493 }
2494 } else {
2495 Handle<JSReceiver> current_handler(
2496 JSReceiver::cast(reaction->reject_handler()), isolate);
2497 if (PromiseHandlerCheck(isolate, current_handler, promise)) {
2498 return true;
2499 }
2500 }
2501 }
2502 current = handle(reaction->next(), isolate);
2503 }
2504 }
2505
2506 return false;
2507}
2508
2509} // namespace
2510
2511bool Isolate::PromiseHasUserDefinedRejectHandler(Handle<Object> promise) {
2512 if (!promise->IsJSPromise()) return false;
2513 return InternalPromiseHasUserDefinedRejectHandler(
2514 this, Handle<JSPromise>::cast(promise));
2515}
2516
2517Handle<Object> Isolate::GetPromiseOnStackOnThrow() {
2518 Handle<Object> undefined = factory()->undefined_value();
2519 ThreadLocalTop* tltop = thread_local_top();
2520 if (tltop->promise_on_stack_ == nullptr) return undefined;
2521 // Find the top-most try-catch or try-finally handler.
2522 CatchType prediction = PredictExceptionCatcher();
2523 if (prediction == NOT_CAUGHT || prediction == CAUGHT_BY_EXTERNAL) {
2524 return undefined;
2525 }
2526 Handle<Object> retval = undefined;
2527 PromiseOnStack* promise_on_stack = tltop->promise_on_stack_;
2528 for (StackFrameIterator it(this); !it.done(); it.Advance()) {
2529 StackFrame* frame = it.frame();
2530 HandlerTable::CatchPrediction catch_prediction;
2531 if (frame->is_java_script()) {
2532 catch_prediction = PredictException(JavaScriptFrame::cast(frame));
2533 } else if (frame->type() == StackFrame::STUB) {
2534 Code code = frame->LookupCode();
2535 if (!code->IsCode() || code->kind() != Code::BUILTIN ||
2536 !code->has_handler_table() || !code->is_turbofanned()) {
2537 continue;
2538 }
2539 catch_prediction = code->GetBuiltinCatchPrediction();
2540 } else {
2541 continue;
2542 }
2543
2544 switch (catch_prediction) {
2545 case HandlerTable::UNCAUGHT:
2546 continue;
2547 case HandlerTable::CAUGHT:
2548 case HandlerTable::DESUGARING:
2549 if (retval->IsJSPromise()) {
2550 // Caught the result of an inner async/await invocation.
2551