1 // Copyright 2014 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/execution/execution.h"
6 
7 #include "src/api/api-inl.h"
8 #include "src/debug/debug.h"
9 #include "src/execution/frames.h"
10 #include "src/execution/isolate-inl.h"
11 #include "src/execution/vm-state-inl.h"
12 #include "src/logging/runtime-call-stats-scope.h"
13 
14 #if V8_ENABLE_WEBASSEMBLY
15 #include "src/compiler/wasm-compiler.h"  // Only for static asserts.
16 #include "src/wasm/wasm-engine.h"
17 #endif  // V8_ENABLE_WEBASSEMBLY
18 
19 namespace v8 {
20 namespace internal {
21 
22 namespace {
23 
NormalizeReceiver(Isolate * isolate,Handle<Object> receiver)24 Handle<Object> NormalizeReceiver(Isolate* isolate, Handle<Object> receiver) {
25   // Convert calls on global objects to be calls on the global
26   // receiver instead to avoid having a 'this' pointer which refers
27   // directly to a global object.
28   if (receiver->IsJSGlobalObject()) {
29     return handle(Handle<JSGlobalObject>::cast(receiver)->global_proxy(),
30                   isolate);
31   }
32   return receiver;
33 }
34 
35 struct InvokeParams {
36   static InvokeParams SetUpForNew(Isolate* isolate, Handle<Object> constructor,
37                                   Handle<Object> new_target, int argc,
38                                   Handle<Object>* argv);
39 
40   static InvokeParams SetUpForCall(Isolate* isolate, Handle<Object> callable,
41                                    Handle<Object> receiver, int argc,
42                                    Handle<Object>* argv);
43 
44   static InvokeParams SetUpForTryCall(
45       Isolate* isolate, Handle<Object> callable, Handle<Object> receiver,
46       int argc, Handle<Object>* argv,
47       Execution::MessageHandling message_handling,
48       MaybeHandle<Object>* exception_out, bool reschedule_terminate);
49 
50   static InvokeParams SetUpForRunMicrotasks(Isolate* isolate,
51                                             MicrotaskQueue* microtask_queue,
52                                             MaybeHandle<Object>* exception_out);
53 
54   Handle<Object> target;
55   Handle<Object> receiver;
56   int argc;
57   Handle<Object>* argv;
58   Handle<Object> new_target;
59 
60   MicrotaskQueue* microtask_queue;
61 
62   Execution::MessageHandling message_handling;
63   MaybeHandle<Object>* exception_out;
64 
65   bool is_construct;
66   Execution::Target execution_target;
67   bool reschedule_terminate;
68 };
69 
70 // static
SetUpForNew(Isolate * isolate,Handle<Object> constructor,Handle<Object> new_target,int argc,Handle<Object> * argv)71 InvokeParams InvokeParams::SetUpForNew(Isolate* isolate,
72                                        Handle<Object> constructor,
73                                        Handle<Object> new_target, int argc,
74                                        Handle<Object>* argv) {
75   InvokeParams params;
76   params.target = constructor;
77   params.receiver = isolate->factory()->undefined_value();
78   params.argc = argc;
79   params.argv = argv;
80   params.new_target = new_target;
81   params.microtask_queue = nullptr;
82   params.message_handling = Execution::MessageHandling::kReport;
83   params.exception_out = nullptr;
84   params.is_construct = true;
85   params.execution_target = Execution::Target::kCallable;
86   params.reschedule_terminate = true;
87   return params;
88 }
89 
90 // static
SetUpForCall(Isolate * isolate,Handle<Object> callable,Handle<Object> receiver,int argc,Handle<Object> * argv)91 InvokeParams InvokeParams::SetUpForCall(Isolate* isolate,
92                                         Handle<Object> callable,
93                                         Handle<Object> receiver, int argc,
94                                         Handle<Object>* argv) {
95   InvokeParams params;
96   params.target = callable;
97   params.receiver = NormalizeReceiver(isolate, receiver);
98   params.argc = argc;
99   params.argv = argv;
100   params.new_target = isolate->factory()->undefined_value();
101   params.microtask_queue = nullptr;
102   params.message_handling = Execution::MessageHandling::kReport;
103   params.exception_out = nullptr;
104   params.is_construct = false;
105   params.execution_target = Execution::Target::kCallable;
106   params.reschedule_terminate = true;
107   return params;
108 }
109 
110 // static
SetUpForTryCall(Isolate * isolate,Handle<Object> callable,Handle<Object> receiver,int argc,Handle<Object> * argv,Execution::MessageHandling message_handling,MaybeHandle<Object> * exception_out,bool reschedule_terminate)111 InvokeParams InvokeParams::SetUpForTryCall(
112     Isolate* isolate, Handle<Object> callable, Handle<Object> receiver,
113     int argc, Handle<Object>* argv, Execution::MessageHandling message_handling,
114     MaybeHandle<Object>* exception_out, bool reschedule_terminate) {
115   InvokeParams params;
116   params.target = callable;
117   params.receiver = NormalizeReceiver(isolate, receiver);
118   params.argc = argc;
119   params.argv = argv;
120   params.new_target = isolate->factory()->undefined_value();
121   params.microtask_queue = nullptr;
122   params.message_handling = message_handling;
123   params.exception_out = exception_out;
124   params.is_construct = false;
125   params.execution_target = Execution::Target::kCallable;
126   params.reschedule_terminate = reschedule_terminate;
127   return params;
128 }
129 
130 // static
SetUpForRunMicrotasks(Isolate * isolate,MicrotaskQueue * microtask_queue,MaybeHandle<Object> * exception_out)131 InvokeParams InvokeParams::SetUpForRunMicrotasks(
132     Isolate* isolate, MicrotaskQueue* microtask_queue,
133     MaybeHandle<Object>* exception_out) {
134   auto undefined = isolate->factory()->undefined_value();
135   InvokeParams params;
136   params.target = undefined;
137   params.receiver = undefined;
138   params.argc = 0;
139   params.argv = nullptr;
140   params.new_target = undefined;
141   params.microtask_queue = microtask_queue;
142   params.message_handling = Execution::MessageHandling::kReport;
143   params.exception_out = exception_out;
144   params.is_construct = false;
145   params.execution_target = Execution::Target::kRunMicrotasks;
146   params.reschedule_terminate = true;
147   return params;
148 }
149 
JSEntry(Isolate * isolate,Execution::Target execution_target,bool is_construct)150 Handle<Code> JSEntry(Isolate* isolate, Execution::Target execution_target,
151                      bool is_construct) {
152   if (is_construct) {
153     DCHECK_EQ(Execution::Target::kCallable, execution_target);
154     return BUILTIN_CODE(isolate, JSConstructEntry);
155   } else if (execution_target == Execution::Target::kCallable) {
156     DCHECK(!is_construct);
157     return BUILTIN_CODE(isolate, JSEntry);
158   } else if (execution_target == Execution::Target::kRunMicrotasks) {
159     DCHECK(!is_construct);
160     return BUILTIN_CODE(isolate, JSRunMicrotasksEntry);
161   }
162   UNREACHABLE();
163 }
164 
NewScriptContext(Isolate * isolate,Handle<JSFunction> function)165 MaybeHandle<Context> NewScriptContext(Isolate* isolate,
166                                       Handle<JSFunction> function) {
167   // Creating a script context is a side effect, so abort if that's not
168   // allowed.
169   if (isolate->debug_execution_mode() == DebugInfo::kSideEffects) {
170     isolate->Throw(*isolate->factory()->NewEvalError(
171         MessageTemplate::kNoSideEffectDebugEvaluate));
172     return MaybeHandle<Context>();
173   }
174   SaveAndSwitchContext save(isolate, function->context());
175   SharedFunctionInfo sfi = function->shared();
176   Handle<Script> script(Script::cast(sfi.script()), isolate);
177   Handle<ScopeInfo> scope_info(sfi.scope_info(), isolate);
178   Handle<NativeContext> native_context(NativeContext::cast(function->context()),
179                                        isolate);
180   Handle<JSGlobalObject> global_object(native_context->global_object(),
181                                        isolate);
182   Handle<ScriptContextTable> script_context(
183       native_context->script_context_table(), isolate);
184 
185   // Find name clashes.
186   for (int var = 0; var < scope_info->ContextLocalCount(); var++) {
187     Handle<String> name(scope_info->ContextLocalName(var), isolate);
188     VariableMode mode = scope_info->ContextLocalMode(var);
189     VariableLookupResult lookup;
190     if (ScriptContextTable::Lookup(isolate, *script_context, *name, &lookup)) {
191       if (IsLexicalVariableMode(mode) || IsLexicalVariableMode(lookup.mode)) {
192         Handle<Context> context = ScriptContextTable::GetContext(
193             isolate, script_context, lookup.context_index);
194         // If we are trying to re-declare a REPL-mode let as a let or REPL-mode
195         // const as a const, allow it.
196         if (!(((mode == VariableMode::kLet &&
197                 lookup.mode == VariableMode::kLet) ||
198                (mode == VariableMode::kConst &&
199                 lookup.mode == VariableMode::kConst)) &&
200               scope_info->IsReplModeScope() &&
201               context->scope_info().IsReplModeScope())) {
202           // ES#sec-globaldeclarationinstantiation 5.b:
203           // If envRec.HasLexicalDeclaration(name) is true, throw a SyntaxError
204           // exception.
205           MessageLocation location(script, 0, 1);
206           return isolate->ThrowAt<Context>(
207               isolate->factory()->NewSyntaxError(
208                   MessageTemplate::kVarRedeclaration, name),
209               &location);
210         }
211       }
212     }
213 
214     if (IsLexicalVariableMode(mode)) {
215       LookupIterator it(isolate, global_object, name, global_object,
216                         LookupIterator::OWN_SKIP_INTERCEPTOR);
217       Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
218       // Can't fail since the we looking up own properties on the global object
219       // skipping interceptors.
220       CHECK(!maybe.IsNothing());
221       if ((maybe.FromJust() & DONT_DELETE) != 0) {
222         // ES#sec-globaldeclarationinstantiation 5.a:
223         // If envRec.HasVarDeclaration(name) is true, throw a SyntaxError
224         // exception.
225         // ES#sec-globaldeclarationinstantiation 5.d:
226         // If hasRestrictedGlobal is true, throw a SyntaxError exception.
227         MessageLocation location(script, 0, 1);
228         return isolate->ThrowAt<Context>(
229             isolate->factory()->NewSyntaxError(
230                 MessageTemplate::kVarRedeclaration, name),
231             &location);
232       }
233 
234       JSGlobalObject::InvalidatePropertyCell(global_object, name);
235     }
236   }
237 
238   Handle<Context> result =
239       isolate->factory()->NewScriptContext(native_context, scope_info);
240 
241   result->Initialize(isolate);
242 
243   Handle<ScriptContextTable> new_script_context_table =
244       ScriptContextTable::Extend(script_context, result);
245   native_context->synchronized_set_script_context_table(
246       *new_script_context_table);
247   return result;
248 }
249 
Invoke(Isolate * isolate,const InvokeParams & params)250 V8_WARN_UNUSED_RESULT MaybeHandle<Object> Invoke(Isolate* isolate,
251                                                  const InvokeParams& params) {
252   RCS_SCOPE(isolate, RuntimeCallCounterId::kInvoke);
253   DCHECK(!params.receiver->IsJSGlobalObject());
254   DCHECK_LE(params.argc, FixedArray::kMaxLength);
255 
256 #if V8_ENABLE_WEBASSEMBLY
257   // If we have PKU support for Wasm, ensure that code is currently write
258   // protected for this thread.
259   DCHECK_IMPLIES(wasm::GetWasmCodeManager()->HasMemoryProtectionKeySupport(),
260                  !wasm::GetWasmCodeManager()->MemoryProtectionKeyWritable());
261 #endif  // V8_ENABLE_WEBASSEMBLY
262 
263 #ifdef USE_SIMULATOR
264   // Simulators use separate stacks for C++ and JS. JS stack overflow checks
265   // are performed whenever a JS function is called. However, it can be the case
266   // that the C++ stack grows faster than the JS stack, resulting in an overflow
267   // there. Add a check here to make that less likely.
268   StackLimitCheck check(isolate);
269   if (check.HasOverflowed()) {
270     isolate->StackOverflow();
271     if (params.message_handling == Execution::MessageHandling::kReport) {
272       isolate->ReportPendingMessages();
273     }
274     return MaybeHandle<Object>();
275   }
276 #endif
277 
278   // api callbacks can be called directly, unless we want to take the detour
279   // through JS to set up a frame for break-at-entry.
280   if (params.target->IsJSFunction()) {
281     Handle<JSFunction> function = Handle<JSFunction>::cast(params.target);
282     if ((!params.is_construct || function->IsConstructor()) &&
283         function->shared().IsApiFunction() &&
284         !function->shared().BreakAtEntry()) {
285       SaveAndSwitchContext save(isolate, function->context());
286       DCHECK(function->context().global_object().IsJSGlobalObject());
287 
288       Handle<Object> receiver = params.is_construct
289                                     ? isolate->factory()->the_hole_value()
290                                     : params.receiver;
291       auto value = Builtins::InvokeApiFunction(
292           isolate, params.is_construct, function, receiver, params.argc,
293           params.argv, Handle<HeapObject>::cast(params.new_target));
294       bool has_exception = value.is_null();
295       DCHECK(has_exception == isolate->has_pending_exception());
296       if (has_exception) {
297         if (params.message_handling == Execution::MessageHandling::kReport) {
298           isolate->ReportPendingMessages();
299         }
300         return MaybeHandle<Object>();
301       } else {
302         isolate->clear_pending_message();
303       }
304       return value;
305     }
306 
307     // Set up a ScriptContext when running scripts that need it.
308     if (function->shared().needs_script_context()) {
309       Handle<Context> context;
310       if (!NewScriptContext(isolate, function).ToHandle(&context)) {
311         if (params.message_handling == Execution::MessageHandling::kReport) {
312           isolate->ReportPendingMessages();
313         }
314         return MaybeHandle<Object>();
315       }
316 
317       // We mutate the context if we allocate a script context. This is
318       // guaranteed to only happen once in a native context since scripts will
319       // always produce name clashes with themselves.
320       function->set_context(*context);
321     }
322   }
323 
324   // Entering JavaScript.
325   VMState<JS> state(isolate);
326   CHECK(AllowJavascriptExecution::IsAllowed(isolate));
327   if (!ThrowOnJavascriptExecution::IsAllowed(isolate)) {
328     isolate->ThrowIllegalOperation();
329     if (params.message_handling == Execution::MessageHandling::kReport) {
330       isolate->ReportPendingMessages();
331     }
332     return MaybeHandle<Object>();
333   }
334   if (!DumpOnJavascriptExecution::IsAllowed(isolate)) {
335     V8::GetCurrentPlatform()->DumpWithoutCrashing();
336     return isolate->factory()->undefined_value();
337   }
338 
339   if (params.execution_target == Execution::Target::kCallable) {
340     Handle<Context> context = isolate->native_context();
341     if (!context->script_execution_callback().IsUndefined(isolate)) {
342       v8::Context::AbortScriptExecutionCallback callback =
343           v8::ToCData<v8::Context::AbortScriptExecutionCallback>(
344               context->script_execution_callback());
345       v8::Isolate* api_isolate = reinterpret_cast<v8::Isolate*>(isolate);
346       v8::Local<v8::Context> api_context = v8::Utils::ToLocal(context);
347       callback(api_isolate, api_context);
348       DCHECK(!isolate->has_scheduled_exception());
349       // Always throw an exception to abort execution, if callback exists.
350       isolate->ThrowIllegalOperation();
351       return MaybeHandle<Object>();
352     }
353   }
354 
355   // Placeholder for return value.
356   Object value;
357   Handle<Code> code =
358       JSEntry(isolate, params.execution_target, params.is_construct);
359   {
360     // Save and restore context around invocation and block the
361     // allocation of handles without explicit handle scopes.
362     SaveContext save(isolate);
363     SealHandleScope shs(isolate);
364 
365     if (FLAG_clear_exceptions_on_js_entry) isolate->clear_pending_exception();
366 
367     if (params.execution_target == Execution::Target::kCallable) {
368       // clang-format off
369       // {new_target}, {target}, {receiver}, return value: tagged pointers
370       // {argv}: pointer to array of tagged pointers
371       using JSEntryFunction = GeneratedCode<Address(
372           Address root_register_value, Address new_target, Address target,
373           Address receiver, intptr_t argc, Address** argv)>;
374       // clang-format on
375       JSEntryFunction stub_entry =
376           JSEntryFunction::FromAddress(isolate, code->InstructionStart());
377 
378       Address orig_func = params.new_target->ptr();
379       Address func = params.target->ptr();
380       Address recv = params.receiver->ptr();
381       Address** argv = reinterpret_cast<Address**>(params.argv);
382       RCS_SCOPE(isolate, RuntimeCallCounterId::kJS_Execution);
383       value = Object(stub_entry.Call(isolate->isolate_data()->isolate_root(),
384                                      orig_func, func, recv,
385                                      JSParameterCount(params.argc), argv));
386     } else {
387       DCHECK_EQ(Execution::Target::kRunMicrotasks, params.execution_target);
388 
389       // clang-format off
390       // return value: tagged pointers
391       // {microtask_queue}: pointer to a C++ object
392       using JSEntryFunction = GeneratedCode<Address(
393           Address root_register_value, MicrotaskQueue* microtask_queue)>;
394       // clang-format on
395       JSEntryFunction stub_entry =
396           JSEntryFunction::FromAddress(isolate, code->InstructionStart());
397 
398       RCS_SCOPE(isolate, RuntimeCallCounterId::kJS_Execution);
399       value = Object(stub_entry.Call(isolate->isolate_data()->isolate_root(),
400                                      params.microtask_queue));
401     }
402   }
403 
404 #ifdef VERIFY_HEAP
405   if (FLAG_verify_heap) {
406     value.ObjectVerify(isolate);
407   }
408 #endif
409 
410   // Update the pending exception flag and return the value.
411   bool has_exception = value.IsException(isolate);
412   DCHECK(has_exception == isolate->has_pending_exception());
413   if (has_exception) {
414     if (params.message_handling == Execution::MessageHandling::kReport) {
415       isolate->ReportPendingMessages();
416     }
417     return MaybeHandle<Object>();
418   } else {
419     isolate->clear_pending_message();
420   }
421 
422   return Handle<Object>(value, isolate);
423 }
424 
InvokeWithTryCatch(Isolate * isolate,const InvokeParams & params)425 MaybeHandle<Object> InvokeWithTryCatch(Isolate* isolate,
426                                        const InvokeParams& params) {
427   bool is_termination = false;
428   MaybeHandle<Object> maybe_result;
429   if (params.exception_out != nullptr) {
430     *params.exception_out = MaybeHandle<Object>();
431   }
432   DCHECK_IMPLIES(
433       params.message_handling == Execution::MessageHandling::kKeepPending,
434       params.exception_out == nullptr);
435   // Enter a try-block while executing the JavaScript code. To avoid
436   // duplicate error printing it must be non-verbose.  Also, to avoid
437   // creating message objects during stack overflow we shouldn't
438   // capture messages.
439   {
440     v8::TryCatch catcher(reinterpret_cast<v8::Isolate*>(isolate));
441     catcher.SetVerbose(false);
442     catcher.SetCaptureMessage(false);
443 
444     maybe_result = Invoke(isolate, params);
445 
446     if (maybe_result.is_null()) {
447       DCHECK(isolate->has_pending_exception());
448       if (isolate->pending_exception() ==
449           ReadOnlyRoots(isolate).termination_exception()) {
450         is_termination = true;
451       } else {
452         if (params.exception_out != nullptr) {
453           DCHECK(catcher.HasCaught());
454           DCHECK(isolate->external_caught_exception());
455           *params.exception_out = v8::Utils::OpenHandle(*catcher.Exception());
456         }
457         if (params.message_handling == Execution::MessageHandling::kReport) {
458           isolate->OptionalRescheduleException(true);
459         }
460       }
461     }
462   }
463 
464   if (is_termination && params.reschedule_terminate) {
465     // Reschedule terminate execution exception.
466     isolate->OptionalRescheduleException(false);
467   }
468 
469   return maybe_result;
470 }
471 
472 }  // namespace
473 
474 // static
Call(Isolate * isolate,Handle<Object> callable,Handle<Object> receiver,int argc,Handle<Object> argv[])475 MaybeHandle<Object> Execution::Call(Isolate* isolate, Handle<Object> callable,
476                                     Handle<Object> receiver, int argc,
477                                     Handle<Object> argv[]) {
478   return Invoke(isolate, InvokeParams::SetUpForCall(isolate, callable, receiver,
479                                                     argc, argv));
480 }
481 
CallBuiltin(Isolate * isolate,Handle<JSFunction> builtin,Handle<Object> receiver,int argc,Handle<Object> argv[])482 MaybeHandle<Object> Execution::CallBuiltin(Isolate* isolate,
483                                            Handle<JSFunction> builtin,
484                                            Handle<Object> receiver, int argc,
485                                            Handle<Object> argv[]) {
486   DCHECK(builtin->code().is_builtin());
487   DisableBreak no_break(isolate->debug());
488   return Invoke(isolate, InvokeParams::SetUpForCall(isolate, builtin, receiver,
489                                                     argc, argv));
490 }
491 
492 // static
New(Isolate * isolate,Handle<Object> constructor,int argc,Handle<Object> argv[])493 MaybeHandle<Object> Execution::New(Isolate* isolate, Handle<Object> constructor,
494                                    int argc, Handle<Object> argv[]) {
495   return New(isolate, constructor, constructor, argc, argv);
496 }
497 
498 // static
New(Isolate * isolate,Handle<Object> constructor,Handle<Object> new_target,int argc,Handle<Object> argv[])499 MaybeHandle<Object> Execution::New(Isolate* isolate, Handle<Object> constructor,
500                                    Handle<Object> new_target, int argc,
501                                    Handle<Object> argv[]) {
502   return Invoke(isolate, InvokeParams::SetUpForNew(isolate, constructor,
503                                                    new_target, argc, argv));
504 }
505 
506 // static
TryCall(Isolate * isolate,Handle<Object> callable,Handle<Object> receiver,int argc,Handle<Object> argv[],MessageHandling message_handling,MaybeHandle<Object> * exception_out,bool reschedule_terminate)507 MaybeHandle<Object> Execution::TryCall(
508     Isolate* isolate, Handle<Object> callable, Handle<Object> receiver,
509     int argc, Handle<Object> argv[], MessageHandling message_handling,
510     MaybeHandle<Object>* exception_out, bool reschedule_terminate) {
511   return InvokeWithTryCatch(
512       isolate, InvokeParams::SetUpForTryCall(
513                    isolate, callable, receiver, argc, argv, message_handling,
514                    exception_out, reschedule_terminate));
515 }
516 
517 // static
TryRunMicrotasks(Isolate * isolate,MicrotaskQueue * microtask_queue,MaybeHandle<Object> * exception_out)518 MaybeHandle<Object> Execution::TryRunMicrotasks(
519     Isolate* isolate, MicrotaskQueue* microtask_queue,
520     MaybeHandle<Object>* exception_out) {
521   return InvokeWithTryCatch(
522       isolate, InvokeParams::SetUpForRunMicrotasks(isolate, microtask_queue,
523                                                    exception_out));
524 }
525 
526 struct StackHandlerMarker {
527   Address next;
528   Address padding;
529 };
530 STATIC_ASSERT(offsetof(StackHandlerMarker, next) ==
531               StackHandlerConstants::kNextOffset);
532 STATIC_ASSERT(offsetof(StackHandlerMarker, padding) ==
533               StackHandlerConstants::kPaddingOffset);
534 STATIC_ASSERT(sizeof(StackHandlerMarker) == StackHandlerConstants::kSize);
535 
536 #if V8_ENABLE_WEBASSEMBLY
CallWasm(Isolate * isolate,Handle<CodeT> wrapper_code,Address wasm_call_target,Handle<Object> object_ref,Address packed_args)537 void Execution::CallWasm(Isolate* isolate, Handle<CodeT> wrapper_code,
538                          Address wasm_call_target, Handle<Object> object_ref,
539                          Address packed_args) {
540   using WasmEntryStub = GeneratedCode<Address(
541       Address target, Address object_ref, Address argv, Address c_entry_fp)>;
542   WasmEntryStub stub_entry =
543       WasmEntryStub::FromAddress(isolate, wrapper_code->InstructionStart());
544 
545   // Save and restore context around invocation and block the
546   // allocation of handles without explicit handle scopes.
547   SaveContext save(isolate);
548   SealHandleScope shs(isolate);
549 
550   Address saved_c_entry_fp = *isolate->c_entry_fp_address();
551   Address saved_js_entry_sp = *isolate->js_entry_sp_address();
552   if (saved_js_entry_sp == kNullAddress) {
553     *isolate->js_entry_sp_address() = GetCurrentStackPosition();
554   }
555   StackHandlerMarker stack_handler;
556   stack_handler.next = isolate->thread_local_top()->handler_;
557 #ifdef V8_USE_ADDRESS_SANITIZER
558   stack_handler.padding = GetCurrentStackPosition();
559 #else
560   stack_handler.padding = 0;
561 #endif
562   isolate->thread_local_top()->handler_ =
563       reinterpret_cast<Address>(&stack_handler);
564   trap_handler::SetThreadInWasm();
565 
566   {
567     RCS_SCOPE(isolate, RuntimeCallCounterId::kJS_Execution);
568     STATIC_ASSERT(compiler::CWasmEntryParameters::kCodeEntry == 0);
569     STATIC_ASSERT(compiler::CWasmEntryParameters::kObjectRef == 1);
570     STATIC_ASSERT(compiler::CWasmEntryParameters::kArgumentsBuffer == 2);
571     STATIC_ASSERT(compiler::CWasmEntryParameters::kCEntryFp == 3);
572     Address result = stub_entry.Call(wasm_call_target, object_ref->ptr(),
573                                      packed_args, saved_c_entry_fp);
574     if (result != kNullAddress) {
575       isolate->set_pending_exception(Object(result));
576     }
577   }
578 
579   // If there was an exception, then the thread-in-wasm flag is cleared
580   // already.
581   if (trap_handler::IsThreadInWasm()) {
582     trap_handler::ClearThreadInWasm();
583   }
584   isolate->thread_local_top()->handler_ = stack_handler.next;
585   if (saved_js_entry_sp == kNullAddress) {
586     *isolate->js_entry_sp_address() = saved_js_entry_sp;
587   }
588   *isolate->c_entry_fp_address() = saved_c_entry_fp;
589 }
590 #endif  // V8_ENABLE_WEBASSEMBLY
591 
592 }  // namespace internal
593 }  // namespace v8
594