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 <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