execution.cc 26.1 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/runtime-call-stats-scope.h"
13

14 15
#if V8_ENABLE_WEBASSEMBLY
#include "src/compiler/wasm-compiler.h"  // Only for static asserts.
16
#include "src/wasm/code-space-access.h"
17 18
#include "src/wasm/wasm-engine.h"
#endif  // V8_ENABLE_WEBASSEMBLY
19

20 21
namespace v8 {
namespace internal {
22

23 24
namespace {

25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
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,
49
      MaybeHandle<Object>* exception_out, bool reschedule_terminate);
50 51 52 53 54

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

55 56 57 58 59 60
  bool IsScript() const {
    if (!target->IsJSFunction()) return false;
    Handle<JSFunction> function = Handle<JSFunction>::cast(target);
    return function->shared().is_script();
  }

61 62 63 64 65 66 67 68 69
  Handle<FixedArray> GetAndResetHostDefinedOptions() {
    DCHECK(IsScript());
    DCHECK_EQ(argc, 1);
    auto options = Handle<FixedArray>::cast(argv[0]);
    argv = nullptr;
    argc = 0;
    return options;
  }

70 71 72 73 74 75 76 77 78 79 80 81 82
  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;
83
  bool reschedule_terminate;
84 85 86 87 88 89 90 91 92 93
};

// 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();
94
  DCHECK(!params.IsScript());
95 96 97 98 99 100 101 102
  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;
103
  params.reschedule_terminate = true;
104 105 106 107 108 109 110 111 112 113 114
  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);
115 116 117
  // Check for host-defined options argument for scripts.
  DCHECK_IMPLIES(params.IsScript(), argc == 1);
  DCHECK_IMPLIES(params.IsScript(), argv[0]->IsFixedArray());
118 119 120 121 122 123 124 125
  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;
126
  params.reschedule_terminate = true;
127 128 129 130 131 132 133
  return params;
}

// static
InvokeParams InvokeParams::SetUpForTryCall(
    Isolate* isolate, Handle<Object> callable, Handle<Object> receiver,
    int argc, Handle<Object>* argv, Execution::MessageHandling message_handling,
134
    MaybeHandle<Object>* exception_out, bool reschedule_terminate) {
135 136 137
  InvokeParams params;
  params.target = callable;
  params.receiver = NormalizeReceiver(isolate, receiver);
138 139 140
  // Check for host-defined options argument for scripts.
  DCHECK_IMPLIES(params.IsScript(), argc == 1);
  DCHECK_IMPLIES(params.IsScript(), argv[0]->IsFixedArray());
141 142 143 144 145 146 147 148
  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;
149
  params.reschedule_terminate = reschedule_terminate;
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
  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;
169
  params.reschedule_terminate = true;
170 171 172
  return params;
}

173 174
Handle<CodeT> JSEntry(Isolate* isolate, Execution::Target execution_target,
                      bool is_construct) {
175 176 177 178 179 180 181 182 183 184 185 186 187
  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();
}

188
MaybeHandle<Context> NewScriptContext(Isolate* isolate,
189 190 191
                                      Handle<JSFunction> function,
                                      Handle<FixedArray> host_defined_options) {
  // TODO(cbruni, 1244145): Use passed in host_defined_options.
192 193 194 195 196 197 198
  // 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>();
  }
199 200 201 202 203 204 205 206 207 208 209 210
  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.
211 212 213
  for (auto it : ScopeInfo::IterateLocalNames(scope_info)) {
    Handle<String> name(it->name(), isolate);
    VariableMode mode = scope_info->ContextLocalMode(it->index());
214
    VariableLookupResult lookup;
215
    if (script_context->Lookup(name, &lookup)) {
216 217 218
      if (IsLexicalVariableMode(mode) || IsLexicalVariableMode(lookup.mode)) {
        Handle<Context> context = ScriptContextTable::GetContext(
            isolate, script_context, lookup.context_index);
219 220 221 222 223 224
        // If we are trying to re-declare a REPL-mode let as a let or REPL-mode
        // const as a const, allow it.
        if (!(((mode == VariableMode::kLet &&
                lookup.mode == VariableMode::kLet) ||
               (mode == VariableMode::kConst &&
                lookup.mode == VariableMode::kConst)) &&
225 226 227 228 229 230
              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);
231 232 233 234
          return isolate->ThrowAt<Context>(
              isolate->factory()->NewSyntaxError(
                  MessageTemplate::kVarRedeclaration, name),
              &location);
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
        }
      }
    }

    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);
253 254 255 256
        return isolate->ThrowAt<Context>(
            isolate->factory()->NewSyntaxError(
                MessageTemplate::kVarRedeclaration, name),
            &location);
257 258 259 260 261 262 263 264 265
      }

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

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

266
  result->Initialize(isolate);
267 268 269
  // In REPL mode, we are allowed to add/modify let/const variables.
  // We use the previous defined script context for those.
  const bool ignore_duplicates = scope_info->IsReplModeScope();
270
  Handle<ScriptContextTable> new_script_context_table =
271 272
      ScriptContextTable::Extend(isolate, script_context, result,
                                 ignore_duplicates);
273 274
  native_context->synchronized_set_script_context_table(
      *new_script_context_table);
275 276 277
  return result;
}

278 279
V8_WARN_UNUSED_RESULT MaybeHandle<Object> Invoke(Isolate* isolate,
                                                 const InvokeParams& params) {
280
  RCS_SCOPE(isolate, RuntimeCallCounterId::kInvoke);
281 282
  DCHECK(!params.receiver->IsJSGlobalObject());
  DCHECK_LE(params.argc, FixedArray::kMaxLength);
283

284
#if V8_ENABLE_WEBASSEMBLY
285 286
  // When executing JS code, there should be no {CodeSpaceWriteScope} open.
  DCHECK(!wasm::CodeSpaceWriteScope::IsInScope());
287 288 289
  // If we have PKU support for Wasm, ensure that code is currently write
  // protected for this thread.
  DCHECK_IMPLIES(wasm::GetWasmCodeManager()->HasMemoryProtectionKeySupport(),
290
                 !wasm::GetWasmCodeManager()->MemoryProtectionKeyWritable());
291
#endif  // V8_ENABLE_WEBASSEMBLY
292

293 294 295 296 297 298 299 300
#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();
301
    if (params.message_handling == Execution::MessageHandling::kReport) {
302 303
      isolate->ReportPendingMessages();
    }
304 305 306 307
    return MaybeHandle<Object>();
  }
#endif

308 309
  // api callbacks can be called directly, unless we want to take the detour
  // through JS to set up a frame for break-at-entry.
310 311 312
  if (params.target->IsJSFunction()) {
    Handle<JSFunction> function = Handle<JSFunction>::cast(params.target);
    if ((!params.is_construct || function->IsConstructor()) &&
313 314
        function->shared().IsApiFunction() &&
        !function->shared().BreakAtEntry()) {
315
      SaveAndSwitchContext save(isolate, function->context());
316
      DCHECK(function->context().global_object().IsJSGlobalObject());
317 318 319 320

      Handle<Object> receiver = params.is_construct
                                    ? isolate->factory()->the_hole_value()
                                    : params.receiver;
321
      auto value = Builtins::InvokeApiFunction(
322 323
          isolate, params.is_construct, function, receiver, params.argc,
          params.argv, Handle<HeapObject>::cast(params.new_target));
324 325 326
      bool has_exception = value.is_null();
      DCHECK(has_exception == isolate->has_pending_exception());
      if (has_exception) {
327
        if (params.message_handling == Execution::MessageHandling::kReport) {
328 329
          isolate->ReportPendingMessages();
        }
330 331 332 333 334 335
        return MaybeHandle<Object>();
      } else {
        isolate->clear_pending_message();
      }
      return value;
    }
336 337 338 339 340 341 342 343 344 345
#ifdef DEBUG
    if (function->shared().is_script()) {
      DCHECK(params.IsScript());
      DCHECK(params.receiver->IsJSGlobalProxy());
      DCHECK_EQ(params.argc, 1);
      DCHECK(params.argv[0]->IsFixedArray());
    } else {
      DCHECK(!params.IsScript());
    }
#endif
346 347 348
    // Set up a ScriptContext when running scripts that need it.
    if (function->shared().needs_script_context()) {
      Handle<Context> context;
349
      Handle<FixedArray> host_defined_options =
350
          const_cast<InvokeParams&>(params).GetAndResetHostDefinedOptions();
351 352
      if (!NewScriptContext(isolate, function, host_defined_options)
               .ToHandle(&context)) {
353 354 355 356 357 358 359 360 361 362 363
        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);
    }
364 365
  }

366
  // Entering JavaScript.
367
  VMState<JS> state(isolate);
368
  CHECK(AllowJavascriptExecution::IsAllowed(isolate));
369 370
  if (!ThrowOnJavascriptExecution::IsAllowed(isolate)) {
    isolate->ThrowIllegalOperation();
371
    if (params.message_handling == Execution::MessageHandling::kReport) {
372 373
      isolate->ReportPendingMessages();
    }
374
    return MaybeHandle<Object>();
375
  }
376 377 378 379
  if (!DumpOnJavascriptExecution::IsAllowed(isolate)) {
    V8::GetCurrentPlatform()->DumpWithoutCrashing();
    return isolate->factory()->undefined_value();
  }
380
  isolate->IncrementJavascriptExecutionCounter();
381

382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
  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>();
    }
  }

398
  // Placeholder for return value.
399
  Object value;
400
  Handle<CodeT> code =
401
      JSEntry(isolate, params.execution_target, params.is_construct);
402 403
  {
    // Save and restore context around invocation and block the
404
    // allocation of handles without explicit handle scopes.
405
    SaveContext save(isolate);
406
    SealHandleScope shs(isolate);
407

408 409
    if (FLAG_clear_exceptions_on_js_entry) isolate->clear_pending_exception();

410 411 412 413 414 415 416 417 418 419 420 421 422 423 424
    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);
425
      RCS_SCOPE(isolate, RuntimeCallCounterId::kJS_Execution);
426
      value = Object(stub_entry.Call(isolate->isolate_data()->isolate_root(),
427 428
                                     orig_func, func, recv,
                                     JSParameterCount(params.argc), argv));
429 430 431 432 433 434 435 436 437 438 439 440
    } 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());

441
      RCS_SCOPE(isolate, RuntimeCallCounterId::kJS_Execution);
442 443
      value = Object(stub_entry.Call(isolate->isolate_data()->isolate_root(),
                                     params.microtask_queue));
444
    }
445 446
  }

447
#ifdef VERIFY_HEAP
448
  if (FLAG_verify_heap) {
449
    value.ObjectVerify(isolate);
450
  }
451 452
#endif

453
  // Update the pending exception flag and return the value.
454
  bool has_exception = value.IsException(isolate);
455
  DCHECK(has_exception == isolate->has_pending_exception());
456
  if (has_exception) {
457
    if (params.message_handling == Execution::MessageHandling::kReport) {
458 459
      isolate->ReportPendingMessages();
    }
460
    return MaybeHandle<Object>();
461
  } else {
462
    isolate->clear_pending_message();
463 464
  }

465
  return Handle<Object>(value, isolate);
466 467
}

468 469
MaybeHandle<Object> InvokeWithTryCatch(Isolate* isolate,
                                       const InvokeParams& params) {
470 471
  bool is_termination = false;
  MaybeHandle<Object> maybe_result;
472 473 474 475 476 477
  if (params.exception_out != nullptr) {
    *params.exception_out = MaybeHandle<Object>();
  }
  DCHECK_IMPLIES(
      params.message_handling == Execution::MessageHandling::kKeepPending,
      params.exception_out == nullptr);
478
  // Enter a try-block while executing the JavaScript code. To avoid
479 480 481
  // duplicate error printing it must be non-verbose.  Also, to avoid
  // creating message objects during stack overflow we shouldn't
  // capture messages.
482
  {
483
    v8::TryCatch catcher(reinterpret_cast<v8::Isolate*>(isolate));
484 485 486
    catcher.SetVerbose(false);
    catcher.SetCaptureMessage(false);

487
    maybe_result = Invoke(isolate, params);
488 489 490

    if (maybe_result.is_null()) {
      DCHECK(isolate->has_pending_exception());
491
      if (isolate->pending_exception() ==
492
          ReadOnlyRoots(isolate).termination_exception()) {
493 494
        is_termination = true;
      } else {
495
        if (params.exception_out != nullptr) {
496 497
          DCHECK(catcher.HasCaught());
          DCHECK(isolate->external_caught_exception());
498
          *params.exception_out = v8::Utils::OpenHandle(*catcher.Exception());
499
        }
500 501 502
        if (params.message_handling == Execution::MessageHandling::kReport) {
          isolate->OptionalRescheduleException(true);
        }
503
      }
504
    }
505
  }
506

507
  if (is_termination && params.reschedule_terminate) {
508 509 510
    // Reschedule terminate execution exception.
    isolate->OptionalRescheduleException(false);
  }
511

512
  return maybe_result;
513 514
}

515 516 517 518 519 520
}  // namespace

// static
MaybeHandle<Object> Execution::Call(Isolate* isolate, Handle<Object> callable,
                                    Handle<Object> receiver, int argc,
                                    Handle<Object> argv[]) {
521 522 523
  // Use Execution::CallScript instead for scripts:
  DCHECK_IMPLIES(callable->IsJSFunction(),
                 !JSFunction::cast(*callable).shared().is_script());
524 525 526 527
  return Invoke(isolate, InvokeParams::SetUpForCall(isolate, callable, receiver,
                                                    argc, argv));
}

528
// static
529 530 531 532
MaybeHandle<Object> Execution::CallScript(Isolate* isolate,
                                          Handle<JSFunction> script_function,
                                          Handle<Object> receiver,
                                          Handle<Object> host_defined_options) {
533 534
  DCHECK(script_function->shared().is_script());
  DCHECK(receiver->IsJSGlobalProxy() || receiver->IsJSGlobalObject());
535 536 537
  return Invoke(
      isolate, InvokeParams::SetUpForCall(isolate, script_function, receiver, 1,
                                          &host_defined_options));
538 539
}

540 541 542 543 544 545 546 547 548 549
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));
}

550 551 552 553 554 555 556 557 558 559 560 561 562 563
// 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));
}

564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
// static
MaybeHandle<Object> Execution::TryCallScript(
    Isolate* isolate, Handle<JSFunction> script_function,
    Handle<Object> receiver, Handle<FixedArray> host_defined_options,
    MessageHandling message_handling, MaybeHandle<Object>* exception_out,
    bool reschedule_terminate) {
  DCHECK(script_function->shared().is_script());
  DCHECK(receiver->IsJSGlobalProxy() || receiver->IsJSGlobalObject());
  Handle<Object> argument = host_defined_options;
  return InvokeWithTryCatch(
      isolate, InvokeParams::SetUpForTryCall(
                   isolate, script_function, receiver, 1, &argument,
                   message_handling, exception_out, reschedule_terminate));
}

579
// static
580 581 582 583
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) {
584 585 586
  // Use Execution::TryCallScript instead for scripts:
  DCHECK_IMPLIES(callable->IsJSFunction(),
                 !JSFunction::cast(*callable).shared().is_script());
587
  return InvokeWithTryCatch(
588 589 590
      isolate, InvokeParams::SetUpForTryCall(
                   isolate, callable, receiver, argc, argv, message_handling,
                   exception_out, reschedule_terminate));
591 592 593 594 595
}

// static
MaybeHandle<Object> Execution::TryRunMicrotasks(
    Isolate* isolate, MicrotaskQueue* microtask_queue,
596
    MaybeHandle<Object>* exception_out) {
597 598 599
  return InvokeWithTryCatch(
      isolate, InvokeParams::SetUpForRunMicrotasks(isolate, microtask_queue,
                                                   exception_out));
600
}
601

602 603 604 605
struct StackHandlerMarker {
  Address next;
  Address padding;
};
606
static_assert(offsetof(StackHandlerMarker, next) ==
607
              StackHandlerConstants::kNextOffset);
608
static_assert(offsetof(StackHandlerMarker, padding) ==
609
              StackHandlerConstants::kPaddingOffset);
610
static_assert(sizeof(StackHandlerMarker) == StackHandlerConstants::kSize);
611

612
#if V8_ENABLE_WEBASSEMBLY
613
void Execution::CallWasm(Isolate* isolate, Handle<CodeT> wrapper_code,
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628
                         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) {
629
    *isolate->js_entry_sp_address() = GetCurrentStackPosition();
630 631 632 633
  }
  StackHandlerMarker stack_handler;
  stack_handler.next = isolate->thread_local_top()->handler_;
#ifdef V8_USE_ADDRESS_SANITIZER
634
  stack_handler.padding = GetCurrentStackPosition();
635 636 637 638 639 640 641 642
#else
  stack_handler.padding = 0;
#endif
  isolate->thread_local_top()->handler_ =
      reinterpret_cast<Address>(&stack_handler);
  trap_handler::SetThreadInWasm();

  {
643
    RCS_SCOPE(isolate, RuntimeCallCounterId::kJS_Execution);
644 645 646 647
    static_assert(compiler::CWasmEntryParameters::kCodeEntry == 0);
    static_assert(compiler::CWasmEntryParameters::kObjectRef == 1);
    static_assert(compiler::CWasmEntryParameters::kArgumentsBuffer == 2);
    static_assert(compiler::CWasmEntryParameters::kCEntryFp == 3);
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665
    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;
}
666
#endif  // V8_ENABLE_WEBASSEMBLY
667

668 669
}  // namespace internal
}  // namespace v8