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