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/runtime/runtime-utils.h" 6 7 #include <memory> 8 9 #include "src/arguments.h" 10 #include "src/assembler-inl.h" 11 #include "src/compiler-dispatcher/optimizing-compile-dispatcher.h" 12 #include "src/compiler.h" 13 #include "src/deoptimizer.h" 14 #include "src/frames-inl.h" 15 #include "src/full-codegen/full-codegen.h" 16 #include "src/isolate-inl.h" 17 #include "src/runtime-profiler.h" 18 #include "src/snapshot/code-serializer.h" 19 #include "src/snapshot/natives.h" 20 #include "src/wasm/wasm-module.h" 21 #include "src/wasm/wasm-objects.h" 22 23 namespace { 24 struct WasmCompileControls { 25 uint32_t MaxWasmBufferSize = std::numeric_limits<uint32_t>::max(); 26 bool AllowAnySizeForAsync = true; 27 }; 28 29 // We need per-isolate controls, because we sometimes run tests in multiple 30 // isolates 31 // concurrently. 32 // To avoid upsetting the static initializer count, we lazy initialize this. 33 v8::base::LazyInstance<std::map<v8::Isolate*, WasmCompileControls>>::type 34 g_PerIsolateWasmControls = LAZY_INSTANCE_INITIALIZER; 35 36 bool IsWasmCompileAllowed(v8::Isolate* isolate, v8::Local<v8::Value> value, 37 bool is_async) { 38 DCHECK_GT(g_PerIsolateWasmControls.Get().count(isolate), 0); 39 const WasmCompileControls& ctrls = g_PerIsolateWasmControls.Get().at(isolate); 40 return (is_async && ctrls.AllowAnySizeForAsync) || 41 (v8::Local<v8::ArrayBuffer>::Cast(value)->ByteLength() <= 42 ctrls.MaxWasmBufferSize); 43 } 44 45 // Use the compile controls for instantiation, too 46 bool IsWasmInstantiateAllowed(v8::Isolate* isolate, 47 v8::Local<v8::Value> module_or_bytes, 48 v8::MaybeLocal<v8::Value> ffi, bool is_async) { 49 DCHECK_GT(g_PerIsolateWasmControls.Get().count(isolate), 0); 50 const WasmCompileControls& ctrls = g_PerIsolateWasmControls.Get().at(isolate); 51 if (is_async && ctrls.AllowAnySizeForAsync) return true; 52 if (!module_or_bytes->IsWebAssemblyCompiledModule()) { 53 return IsWasmCompileAllowed(isolate, module_or_bytes, is_async); 54 } 55 v8::Local<v8::WasmCompiledModule> module = 56 v8::Local<v8::WasmCompiledModule>::Cast(module_or_bytes); 57 return static_cast<uint32_t>(module->GetWasmWireBytes()->Length()) <= 58 ctrls.MaxWasmBufferSize; 59 } 60 } // namespace 61 62 namespace v8 { 63 namespace internal { 64 65 RUNTIME_FUNCTION(Runtime_ConstructDouble) { 66 HandleScope scope(isolate); 67 DCHECK_EQ(2, args.length()); 68 CONVERT_NUMBER_CHECKED(uint32_t, hi, Uint32, args[0]); 69 CONVERT_NUMBER_CHECKED(uint32_t, lo, Uint32, args[1]); 70 uint64_t result = (static_cast<uint64_t>(hi) << 32) | lo; 71 return *isolate->factory()->NewNumber(uint64_to_double(result)); 72 } 73 74 RUNTIME_FUNCTION(Runtime_DeoptimizeFunction) { 75 HandleScope scope(isolate); 76 DCHECK_EQ(1, args.length()); 77 78 // This function is used by fuzzers to get coverage in compiler. 79 // Ignore calls on non-function objects to avoid runtime errors. 80 CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0); 81 if (!function_object->IsJSFunction()) { 82 return isolate->heap()->undefined_value(); 83 } 84 Handle<JSFunction> function = Handle<JSFunction>::cast(function_object); 85 86 // If the function is not optimized, just return. 87 if (!function->IsOptimized()) return isolate->heap()->undefined_value(); 88 89 // TODO(turbofan): Deoptimization is not supported yet. 90 if (function->code()->is_turbofanned() && 91 function->shared()->asm_function()) { 92 return isolate->heap()->undefined_value(); 93 } 94 95 Deoptimizer::DeoptimizeFunction(*function); 96 97 return isolate->heap()->undefined_value(); 98 } 99 100 101 RUNTIME_FUNCTION(Runtime_DeoptimizeNow) { 102 HandleScope scope(isolate); 103 DCHECK_EQ(0, args.length()); 104 105 Handle<JSFunction> function; 106 107 // Find the JavaScript function on the top of the stack. 108 JavaScriptFrameIterator it(isolate); 109 if (!it.done()) function = Handle<JSFunction>(it.frame()->function()); 110 if (function.is_null()) return isolate->heap()->undefined_value(); 111 112 // If the function is not optimized, just return. 113 if (!function->IsOptimized()) return isolate->heap()->undefined_value(); 114 115 // TODO(turbofan): Deoptimization is not supported yet. 116 if (function->code()->is_turbofanned() && 117 function->shared()->asm_function()) { 118 return isolate->heap()->undefined_value(); 119 } 120 121 Deoptimizer::DeoptimizeFunction(*function); 122 123 return isolate->heap()->undefined_value(); 124 } 125 126 127 RUNTIME_FUNCTION(Runtime_RunningInSimulator) { 128 SealHandleScope shs(isolate); 129 DCHECK_EQ(0, args.length()); 130 #if defined(USE_SIMULATOR) 131 return isolate->heap()->true_value(); 132 #else 133 return isolate->heap()->false_value(); 134 #endif 135 } 136 137 138 RUNTIME_FUNCTION(Runtime_IsConcurrentRecompilationSupported) { 139 SealHandleScope shs(isolate); 140 DCHECK_EQ(0, args.length()); 141 return isolate->heap()->ToBoolean( 142 isolate->concurrent_recompilation_enabled()); 143 } 144 145 146 RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) { 147 HandleScope scope(isolate); 148 149 // This function is used by fuzzers, ignore calls with bogus arguments count. 150 if (args.length() != 1 && args.length() != 2) { 151 return isolate->heap()->undefined_value(); 152 } 153 154 // This function is used by fuzzers to get coverage for optimizations 155 // in compiler. Ignore calls on non-function objects to avoid runtime errors. 156 CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0); 157 if (!function_object->IsJSFunction()) { 158 return isolate->heap()->undefined_value(); 159 } 160 Handle<JSFunction> function = Handle<JSFunction>::cast(function_object); 161 162 // The following condition was lifted from the DCHECK inside 163 // JSFunction::MarkForOptimization(). 164 if (!(function->shared()->allows_lazy_compilation() || 165 (function->code()->kind() == Code::FUNCTION && 166 !function->shared()->optimization_disabled()))) { 167 return isolate->heap()->undefined_value(); 168 } 169 170 // If function isn't compiled, compile it now. 171 if (!function->shared()->is_compiled() && 172 !Compiler::Compile(function, Compiler::CLEAR_EXCEPTION)) { 173 return isolate->heap()->undefined_value(); 174 } 175 176 // If the function is already optimized, just return. 177 if (function->IsOptimized()) return isolate->heap()->undefined_value(); 178 179 function->MarkForOptimization(); 180 181 Code* unoptimized = function->shared()->code(); 182 if (args.length() == 2 && unoptimized->kind() == Code::FUNCTION) { 183 CONVERT_ARG_HANDLE_CHECKED(String, type, 1); 184 if (type->IsOneByteEqualTo(STATIC_CHAR_VECTOR("concurrent")) && 185 isolate->concurrent_recompilation_enabled()) { 186 function->AttemptConcurrentOptimization(); 187 } 188 } 189 190 return isolate->heap()->undefined_value(); 191 } 192 193 RUNTIME_FUNCTION(Runtime_InterpretFunctionOnNextCall) { 194 HandleScope scope(isolate); 195 DCHECK_EQ(1, args.length()); 196 CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0); 197 if (!function_object->IsJSFunction()) { 198 return isolate->heap()->undefined_value(); 199 } 200 Handle<JSFunction> function = Handle<JSFunction>::cast(function_object); 201 202 // Do not tier down if we are already on optimized code. Replacing optimized 203 // code without actual deoptimization can lead to funny bugs. 204 if (function->code()->kind() != Code::OPTIMIZED_FUNCTION && 205 function->shared()->HasBytecodeArray()) { 206 function->ReplaceCode(*isolate->builtins()->InterpreterEntryTrampoline()); 207 } 208 return isolate->heap()->undefined_value(); 209 } 210 211 RUNTIME_FUNCTION(Runtime_BaselineFunctionOnNextCall) { 212 HandleScope scope(isolate); 213 DCHECK_EQ(1, args.length()); 214 CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0); 215 if (!function_object->IsJSFunction()) { 216 return isolate->heap()->undefined_value(); 217 } 218 Handle<JSFunction> function = Handle<JSFunction>::cast(function_object); 219 220 // If function isn't compiled, compile it now. 221 if (!function->shared()->is_compiled() && 222 !Compiler::Compile(function, Compiler::CLEAR_EXCEPTION)) { 223 return isolate->heap()->undefined_value(); 224 } 225 226 // Do not tier down if we are already on optimized code. Replacing optimized 227 // code without actual deoptimization can lead to funny bugs. 228 if (function->code()->kind() != Code::OPTIMIZED_FUNCTION && 229 function->code()->kind() != Code::FUNCTION) { 230 if (function->shared()->HasBaselineCode()) { 231 function->ReplaceCode(function->shared()->code()); 232 } else { 233 function->MarkForBaseline(); 234 } 235 } 236 237 return isolate->heap()->undefined_value(); 238 } 239 240 RUNTIME_FUNCTION(Runtime_OptimizeOsr) { 241 HandleScope scope(isolate); 242 DCHECK(args.length() == 0 || args.length() == 1); 243 244 Handle<JSFunction> function; 245 246 // The optional parameter determines the frame being targeted. 247 int stack_depth = args.length() == 1 ? args.smi_at(0) : 0; 248 249 // Find the JavaScript function on the top of the stack. 250 JavaScriptFrameIterator it(isolate); 251 while (!it.done() && stack_depth--) it.Advance(); 252 if (!it.done()) function = Handle<JSFunction>(it.frame()->function()); 253 if (function.is_null()) return isolate->heap()->undefined_value(); 254 255 // If the function is already optimized, just return. 256 if (function->IsOptimized()) return isolate->heap()->undefined_value(); 257 258 // Make the profiler arm all back edges in unoptimized code. 259 if (it.frame()->type() == StackFrame::JAVA_SCRIPT || 260 it.frame()->type() == StackFrame::INTERPRETED) { 261 isolate->runtime_profiler()->AttemptOnStackReplacement( 262 it.frame(), AbstractCode::kMaxLoopNestingMarker); 263 } 264 265 return isolate->heap()->undefined_value(); 266 } 267 268 269 RUNTIME_FUNCTION(Runtime_NeverOptimizeFunction) { 270 HandleScope scope(isolate); 271 DCHECK_EQ(1, args.length()); 272 CONVERT_ARG_CHECKED(JSFunction, function, 0); 273 function->shared()->set_disable_optimization_reason( 274 kOptimizationDisabledForTest); 275 function->shared()->set_optimization_disabled(true); 276 return isolate->heap()->undefined_value(); 277 } 278 279 RUNTIME_FUNCTION(Runtime_GetOptimizationStatus) { 280 HandleScope scope(isolate); 281 DCHECK(args.length() == 1 || args.length() == 2); 282 int status = 0; 283 if (!isolate->use_crankshaft()) { 284 status |= static_cast<int>(OptimizationStatus::kNeverOptimize); 285 } 286 if (FLAG_always_opt || FLAG_prepare_always_opt) { 287 status |= static_cast<int>(OptimizationStatus::kAlwaysOptimize); 288 } 289 if (FLAG_deopt_every_n_times) { 290 status |= static_cast<int>(OptimizationStatus::kMaybeDeopted); 291 } 292 293 // This function is used by fuzzers to get coverage for optimizations 294 // in compiler. Ignore calls on non-function objects to avoid runtime errors. 295 CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0); 296 if (!function_object->IsJSFunction()) { 297 return Smi::FromInt(status); 298 } 299 Handle<JSFunction> function = Handle<JSFunction>::cast(function_object); 300 status |= static_cast<int>(OptimizationStatus::kIsFunction); 301 302 bool sync_with_compiler_thread = true; 303 if (args.length() == 2) { 304 CONVERT_ARG_HANDLE_CHECKED(Object, sync_object, 1); 305 if (!sync_object->IsString()) return isolate->heap()->undefined_value(); 306 Handle<String> sync = Handle<String>::cast(sync_object); 307 if (sync->IsOneByteEqualTo(STATIC_CHAR_VECTOR("no sync"))) { 308 sync_with_compiler_thread = false; 309 } 310 } 311 312 if (isolate->concurrent_recompilation_enabled() && 313 sync_with_compiler_thread) { 314 while (function->IsInOptimizationQueue()) { 315 isolate->optimizing_compile_dispatcher()->InstallOptimizedFunctions(); 316 base::OS::Sleep(base::TimeDelta::FromMilliseconds(50)); 317 } 318 } 319 if (function->IsOptimized()) { 320 status |= static_cast<int>(OptimizationStatus::kOptimized); 321 if (function->code()->is_turbofanned()) { 322 status |= static_cast<int>(OptimizationStatus::kTurboFanned); 323 } 324 } 325 if (function->IsInterpreted()) { 326 status |= static_cast<int>(OptimizationStatus::kInterpreted); 327 } 328 return Smi::FromInt(status); 329 } 330 331 332 RUNTIME_FUNCTION(Runtime_UnblockConcurrentRecompilation) { 333 DCHECK_EQ(0, args.length()); 334 if (FLAG_block_concurrent_recompilation && 335 isolate->concurrent_recompilation_enabled()) { 336 isolate->optimizing_compile_dispatcher()->Unblock(); 337 } 338 return isolate->heap()->undefined_value(); 339 } 340 341 342 RUNTIME_FUNCTION(Runtime_GetOptimizationCount) { 343 HandleScope scope(isolate); 344 DCHECK_EQ(1, args.length()); 345 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 346 return Smi::FromInt(function->shared()->opt_count()); 347 } 348 349 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) { 350 args.GetReturnValue().Set(args.This()); 351 } 352 353 RUNTIME_FUNCTION(Runtime_GetUndetectable) { 354 HandleScope scope(isolate); 355 DCHECK_EQ(0, args.length()); 356 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); 357 358 Local<v8::ObjectTemplate> desc = v8::ObjectTemplate::New(v8_isolate); 359 desc->MarkAsUndetectable(); 360 desc->SetCallAsFunctionHandler(ReturnThis); 361 Local<v8::Object> obj; 362 if (!desc->NewInstance(v8_isolate->GetCurrentContext()).ToLocal(&obj)) { 363 return nullptr; 364 } 365 return *Utils::OpenHandle(*obj); 366 } 367 368 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) { 369 double v1 = args[0] 370 ->NumberValue(v8::Isolate::GetCurrent()->GetCurrentContext()) 371 .ToChecked(); 372 double v2 = args[1] 373 ->NumberValue(v8::Isolate::GetCurrent()->GetCurrentContext()) 374 .ToChecked(); 375 args.GetReturnValue().Set( 376 v8::Number::New(v8::Isolate::GetCurrent(), v1 - v2)); 377 } 378 379 // Returns a callable object. The object returns the difference of its two 380 // parameters when it is called. 381 RUNTIME_FUNCTION(Runtime_GetCallable) { 382 HandleScope scope(isolate); 383 DCHECK_EQ(0, args.length()); 384 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); 385 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(v8_isolate); 386 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 387 instance_template->SetCallAsFunctionHandler(call_as_function); 388 v8_isolate->GetCurrentContext(); 389 Local<v8::Object> instance = 390 t->GetFunction(v8_isolate->GetCurrentContext()) 391 .ToLocalChecked() 392 ->NewInstance(v8_isolate->GetCurrentContext()) 393 .ToLocalChecked(); 394 return *Utils::OpenHandle(*instance); 395 } 396 397 RUNTIME_FUNCTION(Runtime_ClearFunctionFeedback) { 398 HandleScope scope(isolate); 399 DCHECK_EQ(1, args.length()); 400 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 401 function->ClearTypeFeedbackInfo(); 402 Code* unoptimized = function->shared()->code(); 403 if (unoptimized->kind() == Code::FUNCTION) { 404 unoptimized->ClearInlineCaches(); 405 } 406 return isolate->heap()->undefined_value(); 407 } 408 409 RUNTIME_FUNCTION(Runtime_CheckWasmWrapperElision) { 410 // This only supports the case where the function being exported 411 // calls an intermediate function, and the intermediate function 412 // calls exactly one imported function 413 HandleScope scope(isolate); 414 CHECK(args.length() == 2); 415 // It takes two parameters, the first one is the JSFunction, 416 // The second one is the type 417 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 418 // If type is 0, it means that it is supposed to be a direct call into a WASM 419 // function 420 // If type is 1, it means that it is supposed to have wrappers 421 CONVERT_ARG_HANDLE_CHECKED(Smi, type, 1); 422 Handle<Code> export_code = handle(function->code()); 423 CHECK(export_code->kind() == Code::JS_TO_WASM_FUNCTION); 424 int const mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET); 425 // check the type of the $export_fct 426 Handle<Code> export_fct; 427 int count = 0; 428 for (RelocIterator it(*export_code, mask); !it.done(); it.next()) { 429 RelocInfo* rinfo = it.rinfo(); 430 Address target_address = rinfo->target_address(); 431 Code* target = Code::GetCodeFromTargetAddress(target_address); 432 if (target->kind() == Code::WASM_FUNCTION) { 433 ++count; 434 export_fct = handle(target); 435 } 436 } 437 CHECK(count == 1); 438 // check the type of the intermediate_fct 439 Handle<Code> intermediate_fct; 440 count = 0; 441 for (RelocIterator it(*export_fct, mask); !it.done(); it.next()) { 442 RelocInfo* rinfo = it.rinfo(); 443 Address target_address = rinfo->target_address(); 444 Code* target = Code::GetCodeFromTargetAddress(target_address); 445 if (target->kind() == Code::WASM_FUNCTION) { 446 ++count; 447 intermediate_fct = handle(target); 448 } 449 } 450 CHECK(count == 1); 451 // check the type of the imported exported function, it should be also a WASM 452 // function in our case 453 Handle<Code> imported_fct; 454 CHECK(type->value() == 0 || type->value() == 1); 455 456 Code::Kind target_kind = 457 type->value() == 0 ? Code::WASM_FUNCTION : Code::WASM_TO_JS_FUNCTION; 458 count = 0; 459 for (RelocIterator it(*intermediate_fct, mask); !it.done(); it.next()) { 460 RelocInfo* rinfo = it.rinfo(); 461 Address target_address = rinfo->target_address(); 462 Code* target = Code::GetCodeFromTargetAddress(target_address); 463 if (target->kind() == target_kind) { 464 ++count; 465 imported_fct = handle(target); 466 } 467 } 468 CHECK_LE(count, 1); 469 return isolate->heap()->ToBoolean(count == 1); 470 } 471 472 RUNTIME_FUNCTION(Runtime_SetWasmCompileControls) { 473 HandleScope scope(isolate); 474 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); 475 CHECK(args.length() == 2); 476 CONVERT_ARG_HANDLE_CHECKED(Smi, block_size, 0); 477 CONVERT_BOOLEAN_ARG_CHECKED(allow_async, 1); 478 WasmCompileControls& ctrl = (*g_PerIsolateWasmControls.Pointer())[v8_isolate]; 479 ctrl.AllowAnySizeForAsync = allow_async; 480 ctrl.MaxWasmBufferSize = static_cast<uint32_t>(block_size->value()); 481 isolate->set_allow_wasm_compile_callback(IsWasmCompileAllowed); 482 return isolate->heap()->undefined_value(); 483 } 484 485 RUNTIME_FUNCTION(Runtime_SetWasmInstantiateControls) { 486 HandleScope scope(isolate); 487 CHECK(args.length() == 0); 488 isolate->set_allow_wasm_instantiate_callback(IsWasmInstantiateAllowed); 489 return isolate->heap()->undefined_value(); 490 } 491 492 RUNTIME_FUNCTION(Runtime_NotifyContextDisposed) { 493 HandleScope scope(isolate); 494 DCHECK_EQ(0, args.length()); 495 isolate->heap()->NotifyContextDisposed(true); 496 return isolate->heap()->undefined_value(); 497 } 498 499 500 RUNTIME_FUNCTION(Runtime_SetAllocationTimeout) { 501 SealHandleScope shs(isolate); 502 DCHECK(args.length() == 2 || args.length() == 3); 503 #ifdef DEBUG 504 CONVERT_INT32_ARG_CHECKED(interval, 0); 505 CONVERT_INT32_ARG_CHECKED(timeout, 1); 506 isolate->heap()->set_allocation_timeout(timeout); 507 FLAG_gc_interval = interval; 508 if (args.length() == 3) { 509 // Enable/disable inline allocation if requested. 510 CONVERT_BOOLEAN_ARG_CHECKED(inline_allocation, 2); 511 if (inline_allocation) { 512 isolate->heap()->EnableInlineAllocation(); 513 } else { 514 isolate->heap()->DisableInlineAllocation(); 515 } 516 } 517 #endif 518 return isolate->heap()->undefined_value(); 519 } 520 521 522 RUNTIME_FUNCTION(Runtime_DebugPrint) { 523 SealHandleScope shs(isolate); 524 DCHECK_EQ(1, args.length()); 525 526 OFStream os(stdout); 527 #ifdef DEBUG 528 if (args[0]->IsString() && isolate->context() != nullptr) { 529 // If we have a string, assume it's a code "marker" 530 // and print some interesting cpu debugging info. 531 JavaScriptFrameIterator it(isolate); 532 JavaScriptFrame* frame = it.frame(); 533 os << "fp = " << static_cast<void*>(frame->fp()) 534 << ", sp = " << static_cast<void*>(frame->sp()) 535 << ", caller_sp = " << static_cast<void*>(frame->caller_sp()) << ": "; 536 } else { 537 os << "DebugPrint: "; 538 } 539 args[0]->Print(os); 540 if (args[0]->IsHeapObject()) { 541 HeapObject::cast(args[0])->map()->Print(os); 542 } 543 #else 544 // ShortPrint is available in release mode. Print is not. 545 os << Brief(args[0]); 546 #endif 547 os << std::endl; 548 549 return args[0]; // return TOS 550 } 551 552 553 RUNTIME_FUNCTION(Runtime_DebugTrace) { 554 SealHandleScope shs(isolate); 555 DCHECK_EQ(0, args.length()); 556 isolate->PrintStack(stdout); 557 return isolate->heap()->undefined_value(); 558 } 559 560 561 // This will not allocate (flatten the string), but it may run 562 // very slowly for very deeply nested ConsStrings. For debugging use only. 563 RUNTIME_FUNCTION(Runtime_GlobalPrint) { 564 SealHandleScope shs(isolate); 565 DCHECK_EQ(1, args.length()); 566 567 CONVERT_ARG_CHECKED(String, string, 0); 568 StringCharacterStream stream(string); 569 while (stream.HasMore()) { 570 uint16_t character = stream.GetNext(); 571 PrintF("%c", character); 572 } 573 return string; 574 } 575 576 577 RUNTIME_FUNCTION(Runtime_SystemBreak) { 578 // The code below doesn't create handles, but when breaking here in GDB 579 // having a handle scope might be useful. 580 HandleScope scope(isolate); 581 DCHECK_EQ(0, args.length()); 582 base::OS::DebugBreak(); 583 return isolate->heap()->undefined_value(); 584 } 585 586 587 // Sets a v8 flag. 588 RUNTIME_FUNCTION(Runtime_SetFlags) { 589 SealHandleScope shs(isolate); 590 DCHECK_EQ(1, args.length()); 591 CONVERT_ARG_CHECKED(String, arg, 0); 592 std::unique_ptr<char[]> flags = 593 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); 594 FlagList::SetFlagsFromString(flags.get(), StrLength(flags.get())); 595 return isolate->heap()->undefined_value(); 596 } 597 598 599 RUNTIME_FUNCTION(Runtime_Abort) { 600 SealHandleScope shs(isolate); 601 DCHECK_EQ(1, args.length()); 602 CONVERT_SMI_ARG_CHECKED(message_id, 0); 603 const char* message = 604 GetBailoutReason(static_cast<BailoutReason>(message_id)); 605 base::OS::PrintError("abort: %s\n", message); 606 isolate->PrintStack(stderr); 607 base::OS::Abort(); 608 UNREACHABLE(); 609 return NULL; 610 } 611 612 613 RUNTIME_FUNCTION(Runtime_AbortJS) { 614 HandleScope scope(isolate); 615 DCHECK_EQ(1, args.length()); 616 CONVERT_ARG_HANDLE_CHECKED(String, message, 0); 617 base::OS::PrintError("abort: %s\n", message->ToCString().get()); 618 isolate->PrintStack(stderr); 619 base::OS::Abort(); 620 UNREACHABLE(); 621 return NULL; 622 } 623 624 625 RUNTIME_FUNCTION(Runtime_NativeScriptsCount) { 626 DCHECK_EQ(0, args.length()); 627 return Smi::FromInt(Natives::GetBuiltinsCount()); 628 } 629 630 // TODO(5510): remove this. 631 RUNTIME_FUNCTION(Runtime_GetV8Version) { 632 HandleScope scope(isolate); 633 DCHECK_EQ(0, args.length()); 634 635 const char* version_string = v8::V8::GetVersion(); 636 637 return *isolate->factory()->NewStringFromAsciiChecked(version_string); 638 } 639 640 641 RUNTIME_FUNCTION(Runtime_DisassembleFunction) { 642 HandleScope scope(isolate); 643 #ifdef DEBUG 644 DCHECK_EQ(1, args.length()); 645 // Get the function and make sure it is compiled. 646 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0); 647 if (!Compiler::Compile(func, Compiler::KEEP_EXCEPTION)) { 648 return isolate->heap()->exception(); 649 } 650 OFStream os(stdout); 651 func->code()->Print(os); 652 os << std::endl; 653 #endif // DEBUG 654 return isolate->heap()->undefined_value(); 655 } 656 657 namespace { 658 659 int StackSize(Isolate* isolate) { 660 int n = 0; 661 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) n++; 662 return n; 663 } 664 665 void PrintIndentation(Isolate* isolate) { 666 const int nmax = 80; 667 int n = StackSize(isolate); 668 if (n <= nmax) { 669 PrintF("%4d:%*s", n, n, ""); 670 } else { 671 PrintF("%4d:%*s", n, nmax, "..."); 672 } 673 } 674 675 } // namespace 676 677 RUNTIME_FUNCTION(Runtime_TraceEnter) { 678 SealHandleScope shs(isolate); 679 DCHECK_EQ(0, args.length()); 680 PrintIndentation(isolate); 681 JavaScriptFrame::PrintTop(isolate, stdout, true, false); 682 PrintF(" {\n"); 683 return isolate->heap()->undefined_value(); 684 } 685 686 687 RUNTIME_FUNCTION(Runtime_TraceExit) { 688 SealHandleScope shs(isolate); 689 DCHECK_EQ(1, args.length()); 690 CONVERT_ARG_CHECKED(Object, obj, 0); 691 PrintIndentation(isolate); 692 PrintF("} -> "); 693 obj->ShortPrint(); 694 PrintF("\n"); 695 return obj; // return TOS 696 } 697 698 RUNTIME_FUNCTION(Runtime_TraceTailCall) { 699 SealHandleScope shs(isolate); 700 DCHECK_EQ(0, args.length()); 701 PrintIndentation(isolate); 702 PrintF("} -> tail call ->\n"); 703 return isolate->heap()->undefined_value(); 704 } 705 706 RUNTIME_FUNCTION(Runtime_GetExceptionDetails) { 707 HandleScope shs(isolate); 708 DCHECK_EQ(1, args.length()); 709 CONVERT_ARG_HANDLE_CHECKED(JSObject, exception_obj, 0); 710 711 Factory* factory = isolate->factory(); 712 Handle<JSMessageObject> message_obj = 713 isolate->CreateMessage(exception_obj, nullptr); 714 715 Handle<JSObject> message = factory->NewJSObject(isolate->object_function()); 716 717 Handle<String> key; 718 Handle<Object> value; 719 720 key = factory->NewStringFromAsciiChecked("start_pos"); 721 value = handle(Smi::FromInt(message_obj->start_position()), isolate); 722 JSObject::SetProperty(message, key, value, STRICT).Assert(); 723 724 key = factory->NewStringFromAsciiChecked("end_pos"); 725 value = handle(Smi::FromInt(message_obj->end_position()), isolate); 726 JSObject::SetProperty(message, key, value, STRICT).Assert(); 727 728 return *message; 729 } 730 731 RUNTIME_FUNCTION(Runtime_HaveSameMap) { 732 SealHandleScope shs(isolate); 733 DCHECK_EQ(2, args.length()); 734 CONVERT_ARG_CHECKED(JSObject, obj1, 0); 735 CONVERT_ARG_CHECKED(JSObject, obj2, 1); 736 return isolate->heap()->ToBoolean(obj1->map() == obj2->map()); 737 } 738 739 740 RUNTIME_FUNCTION(Runtime_InNewSpace) { 741 SealHandleScope shs(isolate); 742 DCHECK_EQ(1, args.length()); 743 CONVERT_ARG_CHECKED(Object, obj, 0); 744 return isolate->heap()->ToBoolean(isolate->heap()->InNewSpace(obj)); 745 } 746 747 RUNTIME_FUNCTION(Runtime_IsAsmWasmCode) { 748 SealHandleScope shs(isolate); 749 DCHECK_EQ(1, args.length()); 750 CONVERT_ARG_CHECKED(JSFunction, function, 0); 751 if (!function->shared()->HasAsmWasmData()) { 752 // Doesn't have wasm data. 753 return isolate->heap()->false_value(); 754 } 755 if (function->shared()->code() != 756 isolate->builtins()->builtin(Builtins::kInstantiateAsmJs)) { 757 // Hasn't been compiled yet. 758 return isolate->heap()->false_value(); 759 } 760 return isolate->heap()->true_value(); 761 } 762 763 namespace { 764 bool DisallowCodegenFromStringsCallback(v8::Local<v8::Context> context) { 765 return false; 766 } 767 } 768 769 RUNTIME_FUNCTION(Runtime_DisallowCodegenFromStrings) { 770 SealHandleScope shs(isolate); 771 DCHECK_EQ(0, args.length()); 772 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); 773 v8_isolate->SetAllowCodeGenerationFromStringsCallback( 774 DisallowCodegenFromStringsCallback); 775 return isolate->heap()->undefined_value(); 776 } 777 778 RUNTIME_FUNCTION(Runtime_IsWasmCode) { 779 SealHandleScope shs(isolate); 780 DCHECK_EQ(1, args.length()); 781 CONVERT_ARG_CHECKED(JSFunction, function, 0); 782 bool is_js_to_wasm = function->code()->kind() == Code::JS_TO_WASM_FUNCTION; 783 return isolate->heap()->ToBoolean(is_js_to_wasm); 784 } 785 786 #define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \ 787 RUNTIME_FUNCTION(Runtime_Has##Name) { \ 788 CONVERT_ARG_CHECKED(JSObject, obj, 0); \ 789 return isolate->heap()->ToBoolean(obj->Has##Name()); \ 790 } 791 792 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiElements) 793 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastObjectElements) 794 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOrObjectElements) 795 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements) 796 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastHoleyElements) 797 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements) 798 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(SloppyArgumentsElements) 799 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FixedTypedArrayElements) 800 // Properties test sitting with elements tests - not fooling anyone. 801 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastProperties) 802 803 #undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION 804 805 806 #define FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, s) \ 807 RUNTIME_FUNCTION(Runtime_HasFixed##Type##Elements) { \ 808 CONVERT_ARG_CHECKED(JSObject, obj, 0); \ 809 return isolate->heap()->ToBoolean(obj->HasFixed##Type##Elements()); \ 810 } 811 812 TYPED_ARRAYS(FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION) 813 814 #undef FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION 815 816 817 RUNTIME_FUNCTION(Runtime_SpeciesProtector) { 818 SealHandleScope shs(isolate); 819 DCHECK_EQ(0, args.length()); 820 return isolate->heap()->ToBoolean(isolate->IsArraySpeciesLookupChainIntact()); 821 } 822 823 #define CONVERT_ARG_HANDLE_CHECKED_2(Type, name, index) \ 824 CHECK(Type::Is##Type(args[index])); \ 825 Handle<Type> name = args.at<Type>(index); 826 827 // Take a compiled wasm module, serialize it and copy the buffer into an array 828 // buffer, which is then returned. 829 RUNTIME_FUNCTION(Runtime_SerializeWasmModule) { 830 HandleScope shs(isolate); 831 DCHECK_EQ(1, args.length()); 832 CONVERT_ARG_HANDLE_CHECKED_2(WasmModuleObject, module_obj, 0); 833 834 Handle<WasmCompiledModule> orig(module_obj->compiled_module()); 835 std::unique_ptr<ScriptData> data = 836 WasmCompiledModuleSerializer::SerializeWasmModule(isolate, orig); 837 void* buff = isolate->array_buffer_allocator()->Allocate(data->length()); 838 Handle<JSArrayBuffer> ret = isolate->factory()->NewJSArrayBuffer(); 839 JSArrayBuffer::Setup(ret, isolate, false, buff, data->length()); 840 memcpy(buff, data->data(), data->length()); 841 return *ret; 842 } 843 844 // Take an array buffer and attempt to reconstruct a compiled wasm module. 845 // Return undefined if unsuccessful. 846 RUNTIME_FUNCTION(Runtime_DeserializeWasmModule) { 847 HandleScope shs(isolate); 848 DCHECK_EQ(2, args.length()); 849 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 0); 850 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, wire_bytes, 1); 851 852 Address mem_start = static_cast<Address>(buffer->backing_store()); 853 int mem_size = static_cast<int>(buffer->byte_length()->Number()); 854 855 // DeserializeWasmModule will allocate. We assume JSArrayBuffer doesn't 856 // get relocated. 857 ScriptData sc(mem_start, mem_size); 858 bool already_external = wire_bytes->is_external(); 859 if (!already_external) { 860 wire_bytes->set_is_external(true); 861 isolate->heap()->UnregisterArrayBuffer(*wire_bytes); 862 } 863 MaybeHandle<FixedArray> maybe_compiled_module = 864 WasmCompiledModuleSerializer::DeserializeWasmModule( 865 isolate, &sc, 866 Vector<const uint8_t>( 867 reinterpret_cast<uint8_t*>(wire_bytes->backing_store()), 868 static_cast<int>(wire_bytes->byte_length()->Number()))); 869 if (!already_external) { 870 wire_bytes->set_is_external(false); 871 isolate->heap()->RegisterNewArrayBuffer(*wire_bytes); 872 } 873 Handle<FixedArray> compiled_module; 874 if (!maybe_compiled_module.ToHandle(&compiled_module)) { 875 return isolate->heap()->undefined_value(); 876 } 877 return *WasmModuleObject::New( 878 isolate, Handle<WasmCompiledModule>::cast(compiled_module)); 879 } 880 881 RUNTIME_FUNCTION(Runtime_ValidateWasmInstancesChain) { 882 HandleScope shs(isolate); 883 DCHECK_EQ(2, args.length()); 884 CONVERT_ARG_HANDLE_CHECKED_2(WasmModuleObject, module_obj, 0); 885 CONVERT_ARG_HANDLE_CHECKED(Smi, instance_count, 1); 886 wasm::testing::ValidateInstancesChain(isolate, module_obj, 887 instance_count->value()); 888 return isolate->heap()->ToBoolean(true); 889 } 890 891 RUNTIME_FUNCTION(Runtime_ValidateWasmModuleState) { 892 HandleScope shs(isolate); 893 DCHECK_EQ(1, args.length()); 894 CONVERT_ARG_HANDLE_CHECKED_2(WasmModuleObject, module_obj, 0); 895 wasm::testing::ValidateModuleState(isolate, module_obj); 896 return isolate->heap()->ToBoolean(true); 897 } 898 899 RUNTIME_FUNCTION(Runtime_ValidateWasmOrphanedInstance) { 900 HandleScope shs(isolate); 901 DCHECK_EQ(1, args.length()); 902 CONVERT_ARG_HANDLE_CHECKED_2(WasmInstanceObject, instance, 0); 903 wasm::testing::ValidateOrphanedInstance(isolate, instance); 904 return isolate->heap()->ToBoolean(true); 905 } 906 907 RUNTIME_FUNCTION(Runtime_Verify) { 908 HandleScope shs(isolate); 909 DCHECK_EQ(1, args.length()); 910 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 911 #ifdef VERIFY_HEAP 912 object->ObjectVerify(); 913 #else 914 CHECK(object->IsObject()); 915 if (object->IsHeapObject()) { 916 CHECK(HeapObject::cast(*object)->map()->IsMap()); 917 } else { 918 CHECK(object->IsSmi()); 919 } 920 #endif 921 return isolate->heap()->ToBoolean(true); 922 } 923 924 } // namespace internal 925 } // namespace v8 926