execution.cc 22.2 KB
Newer Older
1 2 3 4
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

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 11
#include "src/execution/isolate-inl.h"
#include "src/execution/vm-state-inl.h"
12
#include "src/logging/counters.h"
13

14 15 16 17
#if V8_ENABLE_WEBASSEMBLY
#include "src/compiler/wasm-compiler.h"  // Only for static asserts.
#endif                                   // V8_ENABLE_WEBASSEMBLY

18 19
namespace v8 {
namespace internal {
20

21 22
namespace {

23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
Handle<Object> NormalizeReceiver(Isolate* isolate, Handle<Object> receiver) {
  // Convert calls on global objects to be calls on the global
  // receiver instead to avoid having a 'this' pointer which refers
  // directly to a global object.
  if (receiver->IsJSGlobalObject()) {
    return handle(Handle<JSGlobalObject>::cast(receiver)->global_proxy(),
                  isolate);
  }
  return receiver;
}

struct InvokeParams {
  static InvokeParams SetUpForNew(Isolate* isolate, Handle<Object> constructor,
                                  Handle<Object> new_target, int argc,
                                  Handle<Object>* argv);

  static InvokeParams SetUpForCall(Isolate* isolate, Handle<Object> callable,
                                   Handle<Object> receiver, int argc,
                                   Handle<Object>* argv);

  static InvokeParams SetUpForTryCall(
      Isolate* isolate, Handle<Object> callable, Handle<Object> receiver,
      int argc, Handle<Object>* argv,
      Execution::MessageHandling message_handling,
47
      MaybeHandle<Object>* exception_out, bool reschedule_terminate);
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65

  static InvokeParams SetUpForRunMicrotasks(Isolate* isolate,
                                            MicrotaskQueue* microtask_queue,
                                            MaybeHandle<Object>* exception_out);

  Handle<Object> target;
  Handle<Object> receiver;
  int argc;
  Handle<Object>* argv;
  Handle<Object> new_target;

  MicrotaskQueue* microtask_queue;

  Execution::MessageHandling message_handling;
  MaybeHandle<Object>* exception_out;

  bool is_construct;
  Execution::Target execution_target;
66
  bool reschedule_terminate;
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
};

// static
InvokeParams InvokeParams::SetUpForNew(Isolate* isolate,
                                       Handle<Object> constructor,
                                       Handle<Object> new_target, int argc,
                                       Handle<Object>* argv) {
  InvokeParams params;
  params.target = constructor;
  params.receiver = isolate->factory()->undefined_value();
  params.argc = argc;
  params.argv = argv;
  params.new_target = new_target;
  params.microtask_queue = nullptr;
  params.message_handling = Execution::MessageHandling::kReport;
  params.exception_out = nullptr;
  params.is_construct = true;
  params.execution_target = Execution::Target::kCallable;
85
  params.reschedule_terminate = true;
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
  return params;
}

// static
InvokeParams InvokeParams::SetUpForCall(Isolate* isolate,
                                        Handle<Object> callable,
                                        Handle<Object> receiver, int argc,
                                        Handle<Object>* argv) {
  InvokeParams params;
  params.target = callable;
  params.receiver = NormalizeReceiver(isolate, receiver);
  params.argc = argc;
  params.argv = argv;
  params.new_target = isolate->factory()->undefined_value();
  params.microtask_queue = nullptr;
  params.message_handling = Execution::MessageHandling::kReport;
  params.exception_out = nullptr;
  params.is_construct = false;
  params.execution_target = Execution::Target::kCallable;
105
  params.reschedule_terminate = true;
106 107 108 109 110 111 112
  return params;
}

// static
InvokeParams InvokeParams::SetUpForTryCall(
    Isolate* isolate, Handle<Object> callable, Handle<Object> receiver,
    int argc, Handle<Object>* argv, Execution::MessageHandling message_handling,
113
    MaybeHandle<Object>* exception_out, bool reschedule_terminate) {
114 115 116 117 118 119 120 121 122 123 124
  InvokeParams params;
  params.target = callable;
  params.receiver = NormalizeReceiver(isolate, receiver);
  params.argc = argc;
  params.argv = argv;
  params.new_target = isolate->factory()->undefined_value();
  params.microtask_queue = nullptr;
  params.message_handling = message_handling;
  params.exception_out = exception_out;
  params.is_construct = false;
  params.execution_target = Execution::Target::kCallable;
125
  params.reschedule_terminate = reschedule_terminate;
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
  return params;
}

// static
InvokeParams InvokeParams::SetUpForRunMicrotasks(
    Isolate* isolate, MicrotaskQueue* microtask_queue,
    MaybeHandle<Object>* exception_out) {
  auto undefined = isolate->factory()->undefined_value();
  InvokeParams params;
  params.target = undefined;
  params.receiver = undefined;
  params.argc = 0;
  params.argv = nullptr;
  params.new_target = undefined;
  params.microtask_queue = microtask_queue;
  params.message_handling = Execution::MessageHandling::kReport;
  params.exception_out = exception_out;
  params.is_construct = false;
  params.execution_target = Execution::Target::kRunMicrotasks;
145
  params.reschedule_terminate = true;
146 147 148
  return params;
}

149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
Handle<Code> JSEntry(Isolate* isolate, Execution::Target execution_target,
                     bool is_construct) {
  if (is_construct) {
    DCHECK_EQ(Execution::Target::kCallable, execution_target);
    return BUILTIN_CODE(isolate, JSConstructEntry);
  } else if (execution_target == Execution::Target::kCallable) {
    DCHECK(!is_construct);
    return BUILTIN_CODE(isolate, JSEntry);
  } else if (execution_target == Execution::Target::kRunMicrotasks) {
    DCHECK(!is_construct);
    return BUILTIN_CODE(isolate, JSRunMicrotasksEntry);
  }
  UNREACHABLE();
}

164 165
MaybeHandle<Context> NewScriptContext(Isolate* isolate,
                                      Handle<JSFunction> function) {
166 167 168 169 170 171 172
  // Creating a script context is a side effect, so abort if that's not
  // allowed.
  if (isolate->debug_execution_mode() == DebugInfo::kSideEffects) {
    isolate->Throw(*isolate->factory()->NewEvalError(
        MessageTemplate::kNoSideEffectDebugEvaluate));
    return MaybeHandle<Context>();
  }
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
  SaveAndSwitchContext save(isolate, function->context());
  SharedFunctionInfo sfi = function->shared();
  Handle<Script> script(Script::cast(sfi.script()), isolate);
  Handle<ScopeInfo> scope_info(sfi.scope_info(), isolate);
  Handle<NativeContext> native_context(NativeContext::cast(function->context()),
                                       isolate);
  Handle<JSGlobalObject> global_object(native_context->global_object(),
                                       isolate);
  Handle<ScriptContextTable> script_context(
      native_context->script_context_table(), isolate);

  // Find name clashes.
  for (int var = 0; var < scope_info->ContextLocalCount(); var++) {
    Handle<String> name(scope_info->ContextLocalName(var), isolate);
    VariableMode mode = scope_info->ContextLocalMode(var);
    ScriptContextTable::LookupResult lookup;
    if (ScriptContextTable::Lookup(isolate, *script_context, *name, &lookup)) {
      if (IsLexicalVariableMode(mode) || IsLexicalVariableMode(lookup.mode)) {
        Handle<Context> context = ScriptContextTable::GetContext(
            isolate, script_context, lookup.context_index);
        // If we are trying to re-declare a REPL-mode let as a let, allow it.
        if (!(mode == VariableMode::kLet && lookup.mode == VariableMode::kLet &&
              scope_info->IsReplModeScope() &&
              context->scope_info().IsReplModeScope())) {
          // ES#sec-globaldeclarationinstantiation 5.b:
          // If envRec.HasLexicalDeclaration(name) is true, throw a SyntaxError
          // exception.
          MessageLocation location(script, 0, 1);
201 202 203 204
          return isolate->ThrowAt<Context>(
              isolate->factory()->NewSyntaxError(
                  MessageTemplate::kVarRedeclaration, name),
              &location);
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
        }
      }
    }

    if (IsLexicalVariableMode(mode)) {
      LookupIterator it(isolate, global_object, name, global_object,
                        LookupIterator::OWN_SKIP_INTERCEPTOR);
      Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
      // Can't fail since the we looking up own properties on the global object
      // skipping interceptors.
      CHECK(!maybe.IsNothing());
      if ((maybe.FromJust() & DONT_DELETE) != 0) {
        // ES#sec-globaldeclarationinstantiation 5.a:
        // If envRec.HasVarDeclaration(name) is true, throw a SyntaxError
        // exception.
        // ES#sec-globaldeclarationinstantiation 5.d:
        // If hasRestrictedGlobal is true, throw a SyntaxError exception.
        MessageLocation location(script, 0, 1);
223 224 225 226
        return isolate->ThrowAt<Context>(
            isolate->factory()->NewSyntaxError(
                MessageTemplate::kVarRedeclaration, name),
            &location);
227 228 229 230 231 232 233 234 235
      }

      JSGlobalObject::InvalidatePropertyCell(global_object, name);
    }
  }

  Handle<Context> result =
      isolate->factory()->NewScriptContext(native_context, scope_info);

236
  result->Initialize(isolate);
237 238 239

  Handle<ScriptContextTable> new_script_context_table =
      ScriptContextTable::Extend(script_context, result);
240 241
  native_context->synchronized_set_script_context_table(
      *new_script_context_table);
242 243 244
  return result;
}

245 246
V8_WARN_UNUSED_RESULT MaybeHandle<Object> Invoke(Isolate* isolate,
                                                 const InvokeParams& params) {
247
  RCS_SCOPE(isolate, RuntimeCallCounterId::kInvoke);
248 249
  DCHECK(!params.receiver->IsJSGlobalObject());
  DCHECK_LE(params.argc, FixedArray::kMaxLength);
250

251 252 253 254 255 256 257 258
#ifdef USE_SIMULATOR
  // Simulators use separate stacks for C++ and JS. JS stack overflow checks
  // are performed whenever a JS function is called. However, it can be the case
  // that the C++ stack grows faster than the JS stack, resulting in an overflow
  // there. Add a check here to make that less likely.
  StackLimitCheck check(isolate);
  if (check.HasOverflowed()) {
    isolate->StackOverflow();
259
    if (params.message_handling == Execution::MessageHandling::kReport) {
260 261
      isolate->ReportPendingMessages();
    }
262 263 264 265
    return MaybeHandle<Object>();
  }
#endif

266 267
  // api callbacks can be called directly, unless we want to take the detour
  // through JS to set up a frame for break-at-entry.
268 269 270
  if (params.target->IsJSFunction()) {
    Handle<JSFunction> function = Handle<JSFunction>::cast(params.target);
    if ((!params.is_construct || function->IsConstructor()) &&
271 272
        function->shared().IsApiFunction() &&
        !function->shared().BreakAtEntry()) {
273
      SaveAndSwitchContext save(isolate, function->context());
274
      DCHECK(function->context().global_object().IsJSGlobalObject());
275 276 277 278

      Handle<Object> receiver = params.is_construct
                                    ? isolate->factory()->the_hole_value()
                                    : params.receiver;
279
      auto value = Builtins::InvokeApiFunction(
280 281
          isolate, params.is_construct, function, receiver, params.argc,
          params.argv, Handle<HeapObject>::cast(params.new_target));
282 283 284
      bool has_exception = value.is_null();
      DCHECK(has_exception == isolate->has_pending_exception());
      if (has_exception) {
285
        if (params.message_handling == Execution::MessageHandling::kReport) {
286 287
          isolate->ReportPendingMessages();
        }
288 289 290 291 292 293
        return MaybeHandle<Object>();
      } else {
        isolate->clear_pending_message();
      }
      return value;
    }
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309

    // Set up a ScriptContext when running scripts that need it.
    if (function->shared().needs_script_context()) {
      Handle<Context> context;
      if (!NewScriptContext(isolate, function).ToHandle(&context)) {
        if (params.message_handling == Execution::MessageHandling::kReport) {
          isolate->ReportPendingMessages();
        }
        return MaybeHandle<Object>();
      }

      // We mutate the context if we allocate a script context. This is
      // guaranteed to only happen once in a native context since scripts will
      // always produce name clashes with themselves.
      function->set_context(*context);
    }
310 311
  }

312
  // Entering JavaScript.
313
  VMState<JS> state(isolate);
314
  CHECK(AllowJavascriptExecution::IsAllowed(isolate));
315 316
  if (!ThrowOnJavascriptExecution::IsAllowed(isolate)) {
    isolate->ThrowIllegalOperation();
317
    if (params.message_handling == Execution::MessageHandling::kReport) {
318 319
      isolate->ReportPendingMessages();
    }
320
    return MaybeHandle<Object>();
321
  }
322 323 324 325
  if (!DumpOnJavascriptExecution::IsAllowed(isolate)) {
    V8::GetCurrentPlatform()->DumpWithoutCrashing();
    return isolate->factory()->undefined_value();
  }
326

327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
  if (params.execution_target == Execution::Target::kCallable) {
    Handle<Context> context = isolate->native_context();
    if (!context->script_execution_callback().IsUndefined(isolate)) {
      v8::Context::AbortScriptExecutionCallback callback =
          v8::ToCData<v8::Context::AbortScriptExecutionCallback>(
              context->script_execution_callback());
      v8::Isolate* api_isolate = reinterpret_cast<v8::Isolate*>(isolate);
      v8::Local<v8::Context> api_context = v8::Utils::ToLocal(context);
      callback(api_isolate, api_context);
      DCHECK(!isolate->has_scheduled_exception());
      // Always throw an exception to abort execution, if callback exists.
      isolate->ThrowIllegalOperation();
      return MaybeHandle<Object>();
    }
  }

343
  // Placeholder for return value.
344
  Object value;
345

346 347
  Handle<Code> code =
      JSEntry(isolate, params.execution_target, params.is_construct);
348 349
  {
    // Save and restore context around invocation and block the
350
    // allocation of handles without explicit handle scopes.
351
    SaveContext save(isolate);
352
    SealHandleScope shs(isolate);
353

354 355
    if (FLAG_clear_exceptions_on_js_entry) isolate->clear_pending_exception();

356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
    if (params.execution_target == Execution::Target::kCallable) {
      // clang-format off
      // {new_target}, {target}, {receiver}, return value: tagged pointers
      // {argv}: pointer to array of tagged pointers
      using JSEntryFunction = GeneratedCode<Address(
          Address root_register_value, Address new_target, Address target,
          Address receiver, intptr_t argc, Address** argv)>;
      // clang-format on
      JSEntryFunction stub_entry =
          JSEntryFunction::FromAddress(isolate, code->InstructionStart());

      Address orig_func = params.new_target->ptr();
      Address func = params.target->ptr();
      Address recv = params.receiver->ptr();
      Address** argv = reinterpret_cast<Address**>(params.argv);
371
      RCS_SCOPE(isolate, RuntimeCallCounterId::kJS_Execution);
372 373 374 375 376 377 378 379 380 381 382 383 384 385
      value = Object(stub_entry.Call(isolate->isolate_data()->isolate_root(),
                                     orig_func, func, recv, params.argc, argv));
    } else {
      DCHECK_EQ(Execution::Target::kRunMicrotasks, params.execution_target);

      // clang-format off
      // return value: tagged pointers
      // {microtask_queue}: pointer to a C++ object
      using JSEntryFunction = GeneratedCode<Address(
          Address root_register_value, MicrotaskQueue* microtask_queue)>;
      // clang-format on
      JSEntryFunction stub_entry =
          JSEntryFunction::FromAddress(isolate, code->InstructionStart());

386
      RCS_SCOPE(isolate, RuntimeCallCounterId::kJS_Execution);
387 388
      value = Object(stub_entry.Call(isolate->isolate_data()->isolate_root(),
                                     params.microtask_queue));
389
    }
390 391
  }

392
#ifdef VERIFY_HEAP
393
  if (FLAG_verify_heap) {
394
    value.ObjectVerify(isolate);
395
  }
396 397
#endif

398
  // Update the pending exception flag and return the value.
399
  bool has_exception = value.IsException(isolate);
400
  DCHECK(has_exception == isolate->has_pending_exception());
401
  if (has_exception) {
402
    if (params.message_handling == Execution::MessageHandling::kReport) {
403 404
      isolate->ReportPendingMessages();
    }
405
    return MaybeHandle<Object>();
406
  } else {
407
    isolate->clear_pending_message();
408 409
  }

410
  return Handle<Object>(value, isolate);
411 412
}

413 414
MaybeHandle<Object> InvokeWithTryCatch(Isolate* isolate,
                                       const InvokeParams& params) {
415 416
  bool is_termination = false;
  MaybeHandle<Object> maybe_result;
417 418 419 420 421 422
  if (params.exception_out != nullptr) {
    *params.exception_out = MaybeHandle<Object>();
  }
  DCHECK_IMPLIES(
      params.message_handling == Execution::MessageHandling::kKeepPending,
      params.exception_out == nullptr);
423
  // Enter a try-block while executing the JavaScript code. To avoid
424 425 426
  // duplicate error printing it must be non-verbose.  Also, to avoid
  // creating message objects during stack overflow we shouldn't
  // capture messages.
427
  {
428
    v8::TryCatch catcher(reinterpret_cast<v8::Isolate*>(isolate));
429 430 431
    catcher.SetVerbose(false);
    catcher.SetCaptureMessage(false);

432
    maybe_result = Invoke(isolate, params);
433 434 435

    if (maybe_result.is_null()) {
      DCHECK(isolate->has_pending_exception());
436
      if (isolate->pending_exception() ==
437
          ReadOnlyRoots(isolate).termination_exception()) {
438 439
        is_termination = true;
      } else {
440
        if (params.exception_out != nullptr) {
441 442
          DCHECK(catcher.HasCaught());
          DCHECK(isolate->external_caught_exception());
443
          *params.exception_out = v8::Utils::OpenHandle(*catcher.Exception());
444
        }
445 446 447
        if (params.message_handling == Execution::MessageHandling::kReport) {
          isolate->OptionalRescheduleException(true);
        }
448
      }
449
    }
450
  }
451

452
  if (is_termination && params.reschedule_terminate) {
453 454 455
    // Reschedule terminate execution exception.
    isolate->OptionalRescheduleException(false);
  }
456

457
  return maybe_result;
458 459
}

460 461 462 463 464 465 466 467 468 469
}  // namespace

// static
MaybeHandle<Object> Execution::Call(Isolate* isolate, Handle<Object> callable,
                                    Handle<Object> receiver, int argc,
                                    Handle<Object> argv[]) {
  return Invoke(isolate, InvokeParams::SetUpForCall(isolate, callable, receiver,
                                                    argc, argv));
}

470 471 472 473 474 475 476 477 478 479
MaybeHandle<Object> Execution::CallBuiltin(Isolate* isolate,
                                           Handle<JSFunction> builtin,
                                           Handle<Object> receiver, int argc,
                                           Handle<Object> argv[]) {
  DCHECK(builtin->code().is_builtin());
  DisableBreak no_break(isolate->debug());
  return Invoke(isolate, InvokeParams::SetUpForCall(isolate, builtin, receiver,
                                                    argc, argv));
}

480 481 482 483 484 485 486 487 488 489 490 491 492 493 494
// static
MaybeHandle<Object> Execution::New(Isolate* isolate, Handle<Object> constructor,
                                   int argc, Handle<Object> argv[]) {
  return New(isolate, constructor, constructor, argc, argv);
}

// static
MaybeHandle<Object> Execution::New(Isolate* isolate, Handle<Object> constructor,
                                   Handle<Object> new_target, int argc,
                                   Handle<Object> argv[]) {
  return Invoke(isolate, InvokeParams::SetUpForNew(isolate, constructor,
                                                   new_target, argc, argv));
}

// static
495 496 497 498
MaybeHandle<Object> Execution::TryCall(
    Isolate* isolate, Handle<Object> callable, Handle<Object> receiver,
    int argc, Handle<Object> argv[], MessageHandling message_handling,
    MaybeHandle<Object>* exception_out, bool reschedule_terminate) {
499
  return InvokeWithTryCatch(
500 501 502
      isolate, InvokeParams::SetUpForTryCall(
                   isolate, callable, receiver, argc, argv, message_handling,
                   exception_out, reschedule_terminate));
503 504 505 506 507
}

// static
MaybeHandle<Object> Execution::TryRunMicrotasks(
    Isolate* isolate, MicrotaskQueue* microtask_queue,
508
    MaybeHandle<Object>* exception_out) {
509 510 511
  return InvokeWithTryCatch(
      isolate, InvokeParams::SetUpForRunMicrotasks(isolate, microtask_queue,
                                                   exception_out));
512
}
513

514 515 516 517 518 519 520 521 522 523
struct StackHandlerMarker {
  Address next;
  Address padding;
};
STATIC_ASSERT(offsetof(StackHandlerMarker, next) ==
              StackHandlerConstants::kNextOffset);
STATIC_ASSERT(offsetof(StackHandlerMarker, padding) ==
              StackHandlerConstants::kPaddingOffset);
STATIC_ASSERT(sizeof(StackHandlerMarker) == StackHandlerConstants::kSize);

524
#if V8_ENABLE_WEBASSEMBLY
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
void Execution::CallWasm(Isolate* isolate, Handle<Code> wrapper_code,
                         Address wasm_call_target, Handle<Object> object_ref,
                         Address packed_args) {
  using WasmEntryStub = GeneratedCode<Address(
      Address target, Address object_ref, Address argv, Address c_entry_fp)>;
  WasmEntryStub stub_entry =
      WasmEntryStub::FromAddress(isolate, wrapper_code->InstructionStart());

  // Save and restore context around invocation and block the
  // allocation of handles without explicit handle scopes.
  SaveContext save(isolate);
  SealHandleScope shs(isolate);

  Address saved_c_entry_fp = *isolate->c_entry_fp_address();
  Address saved_js_entry_sp = *isolate->js_entry_sp_address();
  if (saved_js_entry_sp == kNullAddress) {
541
    *isolate->js_entry_sp_address() = GetCurrentStackPosition();
542 543 544 545
  }
  StackHandlerMarker stack_handler;
  stack_handler.next = isolate->thread_local_top()->handler_;
#ifdef V8_USE_ADDRESS_SANITIZER
546
  stack_handler.padding = GetCurrentStackPosition();
547 548 549 550 551 552 553 554
#else
  stack_handler.padding = 0;
#endif
  isolate->thread_local_top()->handler_ =
      reinterpret_cast<Address>(&stack_handler);
  trap_handler::SetThreadInWasm();

  {
555
    RCS_SCOPE(isolate, RuntimeCallCounterId::kJS_Execution);
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577
    STATIC_ASSERT(compiler::CWasmEntryParameters::kCodeEntry == 0);
    STATIC_ASSERT(compiler::CWasmEntryParameters::kObjectRef == 1);
    STATIC_ASSERT(compiler::CWasmEntryParameters::kArgumentsBuffer == 2);
    STATIC_ASSERT(compiler::CWasmEntryParameters::kCEntryFp == 3);
    Address result = stub_entry.Call(wasm_call_target, object_ref->ptr(),
                                     packed_args, saved_c_entry_fp);
    if (result != kNullAddress) {
      isolate->set_pending_exception(Object(result));
    }
  }

  // If there was an exception, then the thread-in-wasm flag is cleared
  // already.
  if (trap_handler::IsThreadInWasm()) {
    trap_handler::ClearThreadInWasm();
  }
  isolate->thread_local_top()->handler_ = stack_handler.next;
  if (saved_js_entry_sp == kNullAddress) {
    *isolate->js_entry_sp_address() = saved_js_entry_sp;
  }
  *isolate->c_entry_fp_address() = saved_c_entry_fp;
}
578
#endif  // V8_ENABLE_WEBASSEMBLY
579

580 581
}  // namespace internal
}  // namespace v8