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 "src/arguments.h" 8 #include "src/deoptimizer.h" 9 #include "src/frames-inl.h" 10 #include "src/full-codegen/full-codegen.h" 11 #include "src/snapshot/natives.h" 12 13 namespace v8 { 14 namespace internal { 15 16 RUNTIME_FUNCTION(Runtime_DeoptimizeFunction) { 17 HandleScope scope(isolate); 18 DCHECK(args.length() == 1); 19 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 20 if (!function->IsOptimized()) return isolate->heap()->undefined_value(); 21 22 // TODO(turbofan): Deoptimization is not supported yet. 23 if (function->code()->is_turbofanned() && 24 function->shared()->asm_function() && !FLAG_turbo_asm_deoptimization) { 25 return isolate->heap()->undefined_value(); 26 } 27 28 Deoptimizer::DeoptimizeFunction(*function); 29 30 return isolate->heap()->undefined_value(); 31 } 32 33 34 RUNTIME_FUNCTION(Runtime_DeoptimizeNow) { 35 HandleScope scope(isolate); 36 DCHECK(args.length() == 0); 37 38 Handle<JSFunction> function; 39 40 // If the argument is 'undefined', deoptimize the topmost 41 // function. 42 JavaScriptFrameIterator it(isolate); 43 while (!it.done()) { 44 if (it.frame()->is_java_script()) { 45 function = Handle<JSFunction>(it.frame()->function()); 46 break; 47 } 48 } 49 if (function.is_null()) return isolate->heap()->undefined_value(); 50 51 if (!function->IsOptimized()) return isolate->heap()->undefined_value(); 52 53 // TODO(turbofan): Deoptimization is not supported yet. 54 if (function->code()->is_turbofanned() && 55 function->shared()->asm_function() && !FLAG_turbo_asm_deoptimization) { 56 return isolate->heap()->undefined_value(); 57 } 58 59 Deoptimizer::DeoptimizeFunction(*function); 60 61 return isolate->heap()->undefined_value(); 62 } 63 64 65 RUNTIME_FUNCTION(Runtime_RunningInSimulator) { 66 SealHandleScope shs(isolate); 67 DCHECK(args.length() == 0); 68 #if defined(USE_SIMULATOR) 69 return isolate->heap()->true_value(); 70 #else 71 return isolate->heap()->false_value(); 72 #endif 73 } 74 75 76 RUNTIME_FUNCTION(Runtime_IsConcurrentRecompilationSupported) { 77 SealHandleScope shs(isolate); 78 DCHECK(args.length() == 0); 79 return isolate->heap()->ToBoolean( 80 isolate->concurrent_recompilation_enabled()); 81 } 82 83 84 RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) { 85 HandleScope scope(isolate); 86 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2); 87 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 88 // The following assertion was lifted from the DCHECK inside 89 // JSFunction::MarkForOptimization(). 90 RUNTIME_ASSERT(function->shared()->allows_lazy_compilation() || 91 (function->code()->kind() == Code::FUNCTION && 92 !function->shared()->optimization_disabled())); 93 94 // If the function is already optimized, just return. 95 if (function->IsOptimized()) return isolate->heap()->undefined_value(); 96 97 function->MarkForOptimization(); 98 99 Code* unoptimized = function->shared()->code(); 100 if (args.length() == 2 && unoptimized->kind() == Code::FUNCTION) { 101 CONVERT_ARG_HANDLE_CHECKED(String, type, 1); 102 if (type->IsOneByteEqualTo(STATIC_CHAR_VECTOR("concurrent")) && 103 isolate->concurrent_recompilation_enabled()) { 104 function->AttemptConcurrentOptimization(); 105 } 106 } 107 108 return isolate->heap()->undefined_value(); 109 } 110 111 112 RUNTIME_FUNCTION(Runtime_OptimizeOsr) { 113 HandleScope scope(isolate); 114 RUNTIME_ASSERT(args.length() == 0 || args.length() == 1); 115 Handle<JSFunction> function = Handle<JSFunction>::null(); 116 117 if (args.length() == 0) { 118 // Find the JavaScript function on the top of the stack. 119 JavaScriptFrameIterator it(isolate); 120 while (!it.done()) { 121 if (it.frame()->is_java_script()) { 122 function = Handle<JSFunction>(it.frame()->function()); 123 break; 124 } 125 } 126 if (function.is_null()) return isolate->heap()->undefined_value(); 127 } else { 128 // Function was passed as an argument. 129 CONVERT_ARG_HANDLE_CHECKED(JSFunction, arg, 0); 130 function = arg; 131 } 132 133 // The following assertion was lifted from the DCHECK inside 134 // JSFunction::MarkForOptimization(). 135 RUNTIME_ASSERT(function->shared()->allows_lazy_compilation() || 136 !function->shared()->optimization_disabled()); 137 138 // If the function is already optimized, just return. 139 if (function->IsOptimized()) return isolate->heap()->undefined_value(); 140 141 Code* unoptimized = function->shared()->code(); 142 if (unoptimized->kind() == Code::FUNCTION) { 143 DCHECK(BackEdgeTable::Verify(isolate, unoptimized)); 144 isolate->runtime_profiler()->AttemptOnStackReplacement( 145 *function, Code::kMaxLoopNestingMarker); 146 } 147 148 return isolate->heap()->undefined_value(); 149 } 150 151 152 RUNTIME_FUNCTION(Runtime_NeverOptimizeFunction) { 153 HandleScope scope(isolate); 154 DCHECK(args.length() == 1); 155 CONVERT_ARG_CHECKED(JSFunction, function, 0); 156 function->shared()->set_disable_optimization_reason(kOptimizationDisabled); 157 function->shared()->set_optimization_disabled(true); 158 return isolate->heap()->undefined_value(); 159 } 160 161 162 RUNTIME_FUNCTION(Runtime_GetOptimizationStatus) { 163 HandleScope scope(isolate); 164 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2); 165 if (!isolate->use_crankshaft()) { 166 return Smi::FromInt(4); // 4 == "never". 167 } 168 bool sync_with_compiler_thread = true; 169 if (args.length() == 2) { 170 CONVERT_ARG_HANDLE_CHECKED(String, sync, 1); 171 if (sync->IsOneByteEqualTo(STATIC_CHAR_VECTOR("no sync"))) { 172 sync_with_compiler_thread = false; 173 } 174 } 175 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 176 if (isolate->concurrent_recompilation_enabled() && 177 sync_with_compiler_thread) { 178 while (function->IsInOptimizationQueue()) { 179 isolate->optimizing_compile_dispatcher()->InstallOptimizedFunctions(); 180 base::OS::Sleep(base::TimeDelta::FromMilliseconds(50)); 181 } 182 } 183 if (FLAG_always_opt || FLAG_prepare_always_opt) { 184 // With --always-opt, optimization status expectations might not 185 // match up, so just return a sentinel. 186 return Smi::FromInt(3); // 3 == "always". 187 } 188 if (FLAG_deopt_every_n_times) { 189 return Smi::FromInt(6); // 6 == "maybe deopted". 190 } 191 if (function->IsOptimized() && function->code()->is_turbofanned()) { 192 return Smi::FromInt(7); // 7 == "TurboFan compiler". 193 } 194 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes". 195 : Smi::FromInt(2); // 2 == "no". 196 } 197 198 199 RUNTIME_FUNCTION(Runtime_UnblockConcurrentRecompilation) { 200 DCHECK(args.length() == 0); 201 RUNTIME_ASSERT(FLAG_block_concurrent_recompilation); 202 RUNTIME_ASSERT(isolate->concurrent_recompilation_enabled()); 203 isolate->optimizing_compile_dispatcher()->Unblock(); 204 return isolate->heap()->undefined_value(); 205 } 206 207 208 RUNTIME_FUNCTION(Runtime_GetOptimizationCount) { 209 HandleScope scope(isolate); 210 DCHECK(args.length() == 1); 211 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 212 return Smi::FromInt(function->shared()->opt_count()); 213 } 214 215 216 RUNTIME_FUNCTION(Runtime_GetUndetectable) { 217 HandleScope scope(isolate); 218 DCHECK(args.length() == 0); 219 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); 220 221 Local<v8::ObjectTemplate> desc = v8::ObjectTemplate::New(v8_isolate); 222 desc->MarkAsUndetectable(); 223 Local<v8::Object> obj; 224 if (!desc->NewInstance(v8_isolate->GetCurrentContext()).ToLocal(&obj)) { 225 return nullptr; 226 } 227 return *Utils::OpenHandle(*obj); 228 } 229 230 231 RUNTIME_FUNCTION(Runtime_ClearFunctionTypeFeedback) { 232 HandleScope scope(isolate); 233 DCHECK(args.length() == 1); 234 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 235 function->shared()->ClearTypeFeedbackInfo(); 236 Code* unoptimized = function->shared()->code(); 237 if (unoptimized->kind() == Code::FUNCTION) { 238 unoptimized->ClearInlineCaches(); 239 } 240 return isolate->heap()->undefined_value(); 241 } 242 243 244 RUNTIME_FUNCTION(Runtime_NotifyContextDisposed) { 245 HandleScope scope(isolate); 246 DCHECK(args.length() == 0); 247 isolate->heap()->NotifyContextDisposed(true); 248 return isolate->heap()->undefined_value(); 249 } 250 251 252 RUNTIME_FUNCTION(Runtime_SetAllocationTimeout) { 253 SealHandleScope shs(isolate); 254 DCHECK(args.length() == 2 || args.length() == 3); 255 #ifdef DEBUG 256 CONVERT_SMI_ARG_CHECKED(interval, 0); 257 CONVERT_SMI_ARG_CHECKED(timeout, 1); 258 isolate->heap()->set_allocation_timeout(timeout); 259 FLAG_gc_interval = interval; 260 if (args.length() == 3) { 261 // Enable/disable inline allocation if requested. 262 CONVERT_BOOLEAN_ARG_CHECKED(inline_allocation, 2); 263 if (inline_allocation) { 264 isolate->heap()->EnableInlineAllocation(); 265 } else { 266 isolate->heap()->DisableInlineAllocation(); 267 } 268 } 269 #endif 270 return isolate->heap()->undefined_value(); 271 } 272 273 274 RUNTIME_FUNCTION(Runtime_DebugPrint) { 275 SealHandleScope shs(isolate); 276 DCHECK(args.length() == 1); 277 278 OFStream os(stdout); 279 #ifdef DEBUG 280 if (args[0]->IsString()) { 281 // If we have a string, assume it's a code "marker" 282 // and print some interesting cpu debugging info. 283 JavaScriptFrameIterator it(isolate); 284 JavaScriptFrame* frame = it.frame(); 285 os << "fp = " << static_cast<void*>(frame->fp()) 286 << ", sp = " << static_cast<void*>(frame->sp()) 287 << ", caller_sp = " << static_cast<void*>(frame->caller_sp()) << ": "; 288 } else { 289 os << "DebugPrint: "; 290 } 291 args[0]->Print(os); 292 if (args[0]->IsHeapObject()) { 293 os << "\n"; 294 HeapObject::cast(args[0])->map()->Print(os); 295 } 296 #else 297 // ShortPrint is available in release mode. Print is not. 298 os << Brief(args[0]); 299 #endif 300 os << std::endl; 301 302 return args[0]; // return TOS 303 } 304 305 306 RUNTIME_FUNCTION(Runtime_DebugTrace) { 307 SealHandleScope shs(isolate); 308 DCHECK(args.length() == 0); 309 isolate->PrintStack(stdout); 310 return isolate->heap()->undefined_value(); 311 } 312 313 314 // This will not allocate (flatten the string), but it may run 315 // very slowly for very deeply nested ConsStrings. For debugging use only. 316 RUNTIME_FUNCTION(Runtime_GlobalPrint) { 317 SealHandleScope shs(isolate); 318 DCHECK(args.length() == 1); 319 320 CONVERT_ARG_CHECKED(String, string, 0); 321 StringCharacterStream stream(string); 322 while (stream.HasMore()) { 323 uint16_t character = stream.GetNext(); 324 PrintF("%c", character); 325 } 326 return string; 327 } 328 329 330 RUNTIME_FUNCTION(Runtime_SystemBreak) { 331 // The code below doesn't create handles, but when breaking here in GDB 332 // having a handle scope might be useful. 333 HandleScope scope(isolate); 334 DCHECK(args.length() == 0); 335 base::OS::DebugBreak(); 336 return isolate->heap()->undefined_value(); 337 } 338 339 340 // Sets a v8 flag. 341 RUNTIME_FUNCTION(Runtime_SetFlags) { 342 SealHandleScope shs(isolate); 343 DCHECK(args.length() == 1); 344 CONVERT_ARG_CHECKED(String, arg, 0); 345 base::SmartArrayPointer<char> flags = 346 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); 347 FlagList::SetFlagsFromString(flags.get(), StrLength(flags.get())); 348 return isolate->heap()->undefined_value(); 349 } 350 351 352 RUNTIME_FUNCTION(Runtime_Abort) { 353 SealHandleScope shs(isolate); 354 DCHECK(args.length() == 1); 355 CONVERT_SMI_ARG_CHECKED(message_id, 0); 356 const char* message = 357 GetBailoutReason(static_cast<BailoutReason>(message_id)); 358 base::OS::PrintError("abort: %s\n", message); 359 isolate->PrintStack(stderr); 360 base::OS::Abort(); 361 UNREACHABLE(); 362 return NULL; 363 } 364 365 366 RUNTIME_FUNCTION(Runtime_AbortJS) { 367 HandleScope scope(isolate); 368 DCHECK(args.length() == 1); 369 CONVERT_ARG_HANDLE_CHECKED(String, message, 0); 370 base::OS::PrintError("abort: %s\n", message->ToCString().get()); 371 isolate->PrintStack(stderr); 372 base::OS::Abort(); 373 UNREACHABLE(); 374 return NULL; 375 } 376 377 378 RUNTIME_FUNCTION(Runtime_NativeScriptsCount) { 379 DCHECK(args.length() == 0); 380 return Smi::FromInt(Natives::GetBuiltinsCount() + 381 ExtraNatives::GetBuiltinsCount()); 382 } 383 384 385 // Returns V8 version as a string. 386 RUNTIME_FUNCTION(Runtime_GetV8Version) { 387 HandleScope scope(isolate); 388 DCHECK(args.length() == 0); 389 390 const char* version_string = v8::V8::GetVersion(); 391 392 return *isolate->factory()->NewStringFromAsciiChecked(version_string); 393 } 394 395 396 RUNTIME_FUNCTION(Runtime_DisassembleFunction) { 397 HandleScope scope(isolate); 398 #ifdef DEBUG 399 DCHECK(args.length() == 1); 400 // Get the function and make sure it is compiled. 401 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0); 402 if (!Compiler::Compile(func, KEEP_EXCEPTION)) { 403 return isolate->heap()->exception(); 404 } 405 OFStream os(stdout); 406 func->code()->Print(os); 407 os << std::endl; 408 #endif // DEBUG 409 return isolate->heap()->undefined_value(); 410 } 411 412 413 static int StackSize(Isolate* isolate) { 414 int n = 0; 415 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) n++; 416 return n; 417 } 418 419 420 static void PrintTransition(Isolate* isolate, Object* result) { 421 // indentation 422 { 423 const int nmax = 80; 424 int n = StackSize(isolate); 425 if (n <= nmax) 426 PrintF("%4d:%*s", n, n, ""); 427 else 428 PrintF("%4d:%*s", n, nmax, "..."); 429 } 430 431 if (result == NULL) { 432 JavaScriptFrame::PrintTop(isolate, stdout, true, false); 433 PrintF(" {\n"); 434 } else { 435 // function result 436 PrintF("} -> "); 437 result->ShortPrint(); 438 PrintF("\n"); 439 } 440 } 441 442 443 RUNTIME_FUNCTION(Runtime_TraceEnter) { 444 SealHandleScope shs(isolate); 445 DCHECK(args.length() == 0); 446 PrintTransition(isolate, NULL); 447 return isolate->heap()->undefined_value(); 448 } 449 450 451 RUNTIME_FUNCTION(Runtime_TraceExit) { 452 SealHandleScope shs(isolate); 453 DCHECK(args.length() == 1); 454 CONVERT_ARG_CHECKED(Object, obj, 0); 455 PrintTransition(isolate, obj); 456 return obj; // return TOS 457 } 458 459 460 RUNTIME_FUNCTION(Runtime_HaveSameMap) { 461 SealHandleScope shs(isolate); 462 DCHECK(args.length() == 2); 463 CONVERT_ARG_CHECKED(JSObject, obj1, 0); 464 CONVERT_ARG_CHECKED(JSObject, obj2, 1); 465 return isolate->heap()->ToBoolean(obj1->map() == obj2->map()); 466 } 467 468 469 RUNTIME_FUNCTION(Runtime_InNewSpace) { 470 SealHandleScope shs(isolate); 471 DCHECK(args.length() == 1); 472 CONVERT_ARG_CHECKED(Object, obj, 0); 473 return isolate->heap()->ToBoolean(isolate->heap()->InNewSpace(obj)); 474 } 475 476 477 #define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \ 478 RUNTIME_FUNCTION(Runtime_Has##Name) { \ 479 CONVERT_ARG_CHECKED(JSObject, obj, 0); \ 480 return isolate->heap()->ToBoolean(obj->Has##Name()); \ 481 } 482 483 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiElements) 484 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastObjectElements) 485 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOrObjectElements) 486 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements) 487 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastHoleyElements) 488 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements) 489 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(SloppyArgumentsElements) 490 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FixedTypedArrayElements) 491 // Properties test sitting with elements tests - not fooling anyone. 492 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastProperties) 493 494 #undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION 495 496 497 #define FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, s) \ 498 RUNTIME_FUNCTION(Runtime_HasFixed##Type##Elements) { \ 499 CONVERT_ARG_CHECKED(JSObject, obj, 0); \ 500 return isolate->heap()->ToBoolean(obj->HasFixed##Type##Elements()); \ 501 } 502 503 TYPED_ARRAYS(FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION) 504 505 #undef FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION 506 } // namespace internal 507 } // namespace v8 508