Home | History | Annotate | Download | only in runtime
      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