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