• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
IsWasmCompileAllowed(v8::Isolate * isolate,v8::Local<v8::Value> value,bool is_async)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
IsWasmInstantiateAllowed(v8::Isolate * isolate,v8::Local<v8::Value> module_or_bytes,v8::MaybeLocal<v8::Value> ffi,bool is_async)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 
RUNTIME_FUNCTION(Runtime_ConstructDouble)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 
RUNTIME_FUNCTION(Runtime_DeoptimizeFunction)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 
RUNTIME_FUNCTION(Runtime_DeoptimizeNow)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 
RUNTIME_FUNCTION(Runtime_RunningInSimulator)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 
RUNTIME_FUNCTION(Runtime_IsConcurrentRecompilationSupported)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 
RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall)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 
RUNTIME_FUNCTION(Runtime_InterpretFunctionOnNextCall)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 
RUNTIME_FUNCTION(Runtime_BaselineFunctionOnNextCall)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 
RUNTIME_FUNCTION(Runtime_OptimizeOsr)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 
RUNTIME_FUNCTION(Runtime_NeverOptimizeFunction)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 
RUNTIME_FUNCTION(Runtime_GetOptimizationStatus)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 
RUNTIME_FUNCTION(Runtime_UnblockConcurrentRecompilation)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 
RUNTIME_FUNCTION(Runtime_GetOptimizationCount)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 
ReturnThis(const v8::FunctionCallbackInfo<v8::Value> & args)349 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
350   args.GetReturnValue().Set(args.This());
351 }
352 
RUNTIME_FUNCTION(Runtime_GetUndetectable)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 
call_as_function(const v8::FunctionCallbackInfo<v8::Value> & args)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.
RUNTIME_FUNCTION(Runtime_GetCallable)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 
RUNTIME_FUNCTION(Runtime_ClearFunctionFeedback)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 
RUNTIME_FUNCTION(Runtime_CheckWasmWrapperElision)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 
RUNTIME_FUNCTION(Runtime_SetWasmCompileControls)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 
RUNTIME_FUNCTION(Runtime_SetWasmInstantiateControls)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 
RUNTIME_FUNCTION(Runtime_NotifyContextDisposed)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 
RUNTIME_FUNCTION(Runtime_SetAllocationTimeout)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 
RUNTIME_FUNCTION(Runtime_DebugPrint)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 
RUNTIME_FUNCTION(Runtime_DebugTrace)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.
RUNTIME_FUNCTION(Runtime_GlobalPrint)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 
RUNTIME_FUNCTION(Runtime_SystemBreak)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.
RUNTIME_FUNCTION(Runtime_SetFlags)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 
RUNTIME_FUNCTION(Runtime_Abort)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 
RUNTIME_FUNCTION(Runtime_AbortJS)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 
RUNTIME_FUNCTION(Runtime_NativeScriptsCount)625 RUNTIME_FUNCTION(Runtime_NativeScriptsCount) {
626   DCHECK_EQ(0, args.length());
627   return Smi::FromInt(Natives::GetBuiltinsCount());
628 }
629 
630 // TODO(5510): remove this.
RUNTIME_FUNCTION(Runtime_GetV8Version)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 
RUNTIME_FUNCTION(Runtime_DisassembleFunction)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 
StackSize(Isolate * isolate)659 int StackSize(Isolate* isolate) {
660   int n = 0;
661   for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) n++;
662   return n;
663 }
664 
PrintIndentation(Isolate * isolate)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 
RUNTIME_FUNCTION(Runtime_TraceEnter)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 
RUNTIME_FUNCTION(Runtime_TraceExit)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 
RUNTIME_FUNCTION(Runtime_TraceTailCall)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 
RUNTIME_FUNCTION(Runtime_GetExceptionDetails)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 
RUNTIME_FUNCTION(Runtime_HaveSameMap)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 
RUNTIME_FUNCTION(Runtime_InNewSpace)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 
RUNTIME_FUNCTION(Runtime_IsAsmWasmCode)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 {
DisallowCodegenFromStringsCallback(v8::Local<v8::Context> context)764 bool DisallowCodegenFromStringsCallback(v8::Local<v8::Context> context) {
765   return false;
766 }
767 }
768 
RUNTIME_FUNCTION(Runtime_DisallowCodegenFromStrings)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 
RUNTIME_FUNCTION(Runtime_IsWasmCode)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)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastObjectElements)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.
RUNTIME_FUNCTION(Runtime_SerializeWasmModule)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.
RUNTIME_FUNCTION(Runtime_DeserializeWasmModule)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 
RUNTIME_FUNCTION(Runtime_ValidateWasmInstancesChain)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 
RUNTIME_FUNCTION(Runtime_ValidateWasmModuleState)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 
RUNTIME_FUNCTION(Runtime_ValidateWasmOrphanedInstance)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 
RUNTIME_FUNCTION(Runtime_Verify)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