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