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