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 <memory>
6 #include <sstream>
7
8 #include "src/api/api-inl.h"
9 #include "src/base/platform/mutex.h"
10 #include "src/codegen/assembler-inl.h"
11 #include "src/codegen/compiler.h"
12 #include "src/codegen/pending-optimization-table.h"
13 #include "src/compiler-dispatcher/optimizing-compile-dispatcher.h"
14 #include "src/debug/debug-evaluate.h"
15 #include "src/deoptimizer/deoptimizer.h"
16 #include "src/execution/arguments-inl.h"
17 #include "src/execution/frames-inl.h"
18 #include "src/execution/isolate-inl.h"
19 #include "src/execution/protectors-inl.h"
20 #include "src/execution/runtime-profiler.h"
21 #include "src/heap/heap-inl.h" // For ToBoolean. TODO(jkummerow): Drop.
22 #include "src/heap/heap-write-barrier-inl.h"
23 #include "src/ic/stub-cache.h"
24 #include "src/logging/counters.h"
25 #include "src/objects/heap-object-inl.h"
26 #include "src/objects/js-array-inl.h"
27 #include "src/objects/js-function-inl.h"
28 #include "src/objects/js-regexp-inl.h"
29 #include "src/objects/smi.h"
30 #include "src/regexp/regexp.h"
31 #include "src/runtime/runtime-utils.h"
32 #include "src/snapshot/snapshot.h"
33 #include "src/trap-handler/trap-handler.h"
34 #include "src/utils/ostreams.h"
35 #include "src/wasm/memory-tracing.h"
36 #include "src/wasm/module-compiler.h"
37 #include "src/wasm/wasm-code-manager.h"
38 #include "src/wasm/wasm-engine.h"
39 #include "src/wasm/wasm-module.h"
40 #include "src/wasm/wasm-objects-inl.h"
41 #include "src/wasm/wasm-serialization.h"
42
43 namespace v8 {
44 namespace internal {
45
46 namespace {
47 struct WasmCompileControls {
48 uint32_t MaxWasmBufferSize = std::numeric_limits<uint32_t>::max();
49 bool AllowAnySizeForAsync = true;
50 };
51 using WasmCompileControlsMap = std::map<v8::Isolate*, WasmCompileControls>;
52
53 // We need per-isolate controls, because we sometimes run tests in multiple
54 // isolates concurrently. Methods need to hold the accompanying mutex on access.
55 // To avoid upsetting the static initializer count, we lazy initialize this.
56 DEFINE_LAZY_LEAKY_OBJECT_GETTER(WasmCompileControlsMap,
57 GetPerIsolateWasmControls)
58 base::LazyMutex g_PerIsolateWasmControlsMutex = LAZY_MUTEX_INITIALIZER;
59
IsWasmCompileAllowed(v8::Isolate * isolate,v8::Local<v8::Value> value,bool is_async)60 bool IsWasmCompileAllowed(v8::Isolate* isolate, v8::Local<v8::Value> value,
61 bool is_async) {
62 base::MutexGuard guard(g_PerIsolateWasmControlsMutex.Pointer());
63 DCHECK_GT(GetPerIsolateWasmControls()->count(isolate), 0);
64 const WasmCompileControls& ctrls = GetPerIsolateWasmControls()->at(isolate);
65 return (is_async && ctrls.AllowAnySizeForAsync) ||
66 (value->IsArrayBuffer() &&
67 v8::Local<v8::ArrayBuffer>::Cast(value)->ByteLength() <=
68 ctrls.MaxWasmBufferSize) ||
69 (value->IsArrayBufferView() &&
70 v8::Local<v8::ArrayBufferView>::Cast(value)->ByteLength() <=
71 ctrls.MaxWasmBufferSize);
72 }
73
74 // Use the compile controls for instantiation, too
IsWasmInstantiateAllowed(v8::Isolate * isolate,v8::Local<v8::Value> module_or_bytes,bool is_async)75 bool IsWasmInstantiateAllowed(v8::Isolate* isolate,
76 v8::Local<v8::Value> module_or_bytes,
77 bool is_async) {
78 base::MutexGuard guard(g_PerIsolateWasmControlsMutex.Pointer());
79 DCHECK_GT(GetPerIsolateWasmControls()->count(isolate), 0);
80 const WasmCompileControls& ctrls = GetPerIsolateWasmControls()->at(isolate);
81 if (is_async && ctrls.AllowAnySizeForAsync) return true;
82 if (!module_or_bytes->IsWasmModuleObject()) {
83 return IsWasmCompileAllowed(isolate, module_or_bytes, is_async);
84 }
85 v8::Local<v8::WasmModuleObject> module =
86 v8::Local<v8::WasmModuleObject>::Cast(module_or_bytes);
87 return static_cast<uint32_t>(
88 module->GetCompiledModule().GetWireBytesRef().size()) <=
89 ctrls.MaxWasmBufferSize;
90 }
91
NewRangeException(v8::Isolate * isolate,const char * message)92 v8::Local<v8::Value> NewRangeException(v8::Isolate* isolate,
93 const char* message) {
94 return v8::Exception::RangeError(
95 v8::String::NewFromOneByte(isolate,
96 reinterpret_cast<const uint8_t*>(message))
97 .ToLocalChecked());
98 }
99
ThrowRangeException(v8::Isolate * isolate,const char * message)100 void ThrowRangeException(v8::Isolate* isolate, const char* message) {
101 isolate->ThrowException(NewRangeException(isolate, message));
102 }
103
WasmModuleOverride(const v8::FunctionCallbackInfo<v8::Value> & args)104 bool WasmModuleOverride(const v8::FunctionCallbackInfo<v8::Value>& args) {
105 if (IsWasmCompileAllowed(args.GetIsolate(), args[0], false)) return false;
106 ThrowRangeException(args.GetIsolate(), "Sync compile not allowed");
107 return true;
108 }
109
WasmInstanceOverride(const v8::FunctionCallbackInfo<v8::Value> & args)110 bool WasmInstanceOverride(const v8::FunctionCallbackInfo<v8::Value>& args) {
111 if (IsWasmInstantiateAllowed(args.GetIsolate(), args[0], false)) return false;
112 ThrowRangeException(args.GetIsolate(), "Sync instantiate not allowed");
113 return true;
114 }
115
CrashUnlessFuzzing(Isolate * isolate)116 V8_WARN_UNUSED_RESULT Object CrashUnlessFuzzing(Isolate* isolate) {
117 CHECK(FLAG_fuzzing);
118 return ReadOnlyRoots(isolate).undefined_value();
119 }
120
121 // Assert that the given argument is a number within the Int32 range
122 // and convert it to int32_t. If the argument is not an Int32 we crash if not
123 // in fuzzing mode.
124 #define CONVERT_INT32_ARG_FUZZ_SAFE(name, index) \
125 if (!args[index].IsNumber()) return CrashUnlessFuzzing(isolate); \
126 int32_t name = 0; \
127 if (!args[index].ToInt32(&name)) return CrashUnlessFuzzing(isolate);
128
129 // Cast the given object to a boolean and store it in a variable with
130 // the given name. If the object is not a boolean we crash if not in
131 // fuzzing mode.
132 #define CONVERT_BOOLEAN_ARG_FUZZ_SAFE(name, index) \
133 if (!args[index].IsBoolean()) return CrashUnlessFuzzing(isolate); \
134 bool name = args[index].IsTrue(isolate);
135
136 } // namespace
137
RUNTIME_FUNCTION(Runtime_ClearMegamorphicStubCache)138 RUNTIME_FUNCTION(Runtime_ClearMegamorphicStubCache) {
139 HandleScope scope(isolate);
140 DCHECK_EQ(0, args.length());
141 isolate->load_stub_cache()->Clear();
142 isolate->store_stub_cache()->Clear();
143 return ReadOnlyRoots(isolate).undefined_value();
144 }
145
RUNTIME_FUNCTION(Runtime_ConstructDouble)146 RUNTIME_FUNCTION(Runtime_ConstructDouble) {
147 HandleScope scope(isolate);
148 DCHECK_EQ(2, args.length());
149 CONVERT_NUMBER_CHECKED(uint32_t, hi, Uint32, args[0]);
150 CONVERT_NUMBER_CHECKED(uint32_t, lo, Uint32, args[1]);
151 uint64_t result = (static_cast<uint64_t>(hi) << 32) | lo;
152 return *isolate->factory()->NewNumber(uint64_to_double(result));
153 }
154
RUNTIME_FUNCTION(Runtime_ConstructConsString)155 RUNTIME_FUNCTION(Runtime_ConstructConsString) {
156 HandleScope scope(isolate);
157 DCHECK_EQ(2, args.length());
158 CONVERT_ARG_HANDLE_CHECKED(String, left, 0);
159 CONVERT_ARG_HANDLE_CHECKED(String, right, 1);
160
161 CHECK(left->IsOneByteRepresentation());
162 CHECK(right->IsOneByteRepresentation());
163
164 const bool kIsOneByte = true;
165 const int length = left->length() + right->length();
166 return *isolate->factory()->NewConsString(left, right, length, kIsOneByte);
167 }
168
RUNTIME_FUNCTION(Runtime_ConstructSlicedString)169 RUNTIME_FUNCTION(Runtime_ConstructSlicedString) {
170 HandleScope scope(isolate);
171 DCHECK_EQ(2, args.length());
172 CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
173 CONVERT_ARG_HANDLE_CHECKED(Smi, index, 1);
174
175 CHECK(string->IsOneByteRepresentation());
176 CHECK_LT(index->value(), string->length());
177
178 Handle<String> sliced_string = isolate->factory()->NewSubString(
179 string, index->value(), string->length());
180 CHECK(sliced_string->IsSlicedString());
181 return *sliced_string;
182 }
183
RUNTIME_FUNCTION(Runtime_DeoptimizeFunction)184 RUNTIME_FUNCTION(Runtime_DeoptimizeFunction) {
185 HandleScope scope(isolate);
186 DCHECK_EQ(1, args.length());
187
188 CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0);
189 if (!function_object->IsJSFunction()) return CrashUnlessFuzzing(isolate);
190 Handle<JSFunction> function = Handle<JSFunction>::cast(function_object);
191
192 if (function->HasAttachedOptimizedCode()) {
193 Deoptimizer::DeoptimizeFunction(*function);
194 }
195
196 return ReadOnlyRoots(isolate).undefined_value();
197 }
198
RUNTIME_FUNCTION(Runtime_DeoptimizeNow)199 RUNTIME_FUNCTION(Runtime_DeoptimizeNow) {
200 HandleScope scope(isolate);
201 DCHECK_EQ(0, args.length());
202
203 Handle<JSFunction> function;
204
205 // Find the JavaScript function on the top of the stack.
206 JavaScriptFrameIterator it(isolate);
207 if (!it.done()) function = handle(it.frame()->function(), isolate);
208 if (function.is_null()) return CrashUnlessFuzzing(isolate);
209
210 if (function->HasAttachedOptimizedCode()) {
211 Deoptimizer::DeoptimizeFunction(*function);
212 }
213
214 return ReadOnlyRoots(isolate).undefined_value();
215 }
216
RUNTIME_FUNCTION(Runtime_RunningInSimulator)217 RUNTIME_FUNCTION(Runtime_RunningInSimulator) {
218 SealHandleScope shs(isolate);
219 DCHECK_EQ(0, args.length());
220 #if defined(USE_SIMULATOR)
221 return ReadOnlyRoots(isolate).true_value();
222 #else
223 return ReadOnlyRoots(isolate).false_value();
224 #endif
225 }
226
RUNTIME_FUNCTION(Runtime_RuntimeEvaluateREPL)227 RUNTIME_FUNCTION(Runtime_RuntimeEvaluateREPL) {
228 HandleScope scope(isolate);
229 DCHECK_EQ(1, args.length());
230 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
231 Handle<Object> result;
232 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
233 isolate, result,
234 DebugEvaluate::Global(isolate, source,
235 debug::EvaluateGlobalMode::kDefault,
236 REPLMode::kYes));
237
238 return *result;
239 }
240
RUNTIME_FUNCTION(Runtime_ICsAreEnabled)241 RUNTIME_FUNCTION(Runtime_ICsAreEnabled) {
242 SealHandleScope shs(isolate);
243 DCHECK_EQ(0, args.length());
244 return isolate->heap()->ToBoolean(FLAG_use_ic);
245 }
246
RUNTIME_FUNCTION(Runtime_IsConcurrentRecompilationSupported)247 RUNTIME_FUNCTION(Runtime_IsConcurrentRecompilationSupported) {
248 SealHandleScope shs(isolate);
249 DCHECK_EQ(0, args.length());
250 return isolate->heap()->ToBoolean(
251 isolate->concurrent_recompilation_enabled());
252 }
253
RUNTIME_FUNCTION(Runtime_DynamicMapChecksEnabled)254 RUNTIME_FUNCTION(Runtime_DynamicMapChecksEnabled) {
255 SealHandleScope shs(isolate);
256 DCHECK_EQ(0, args.length());
257 return isolate->heap()->ToBoolean(FLAG_turboprop_dynamic_map_checks);
258 }
259
RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall)260 RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) {
261 HandleScope scope(isolate);
262
263 if (args.length() != 1 && args.length() != 2) {
264 return CrashUnlessFuzzing(isolate);
265 }
266
267 CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0);
268 if (!function_object->IsJSFunction()) return CrashUnlessFuzzing(isolate);
269 Handle<JSFunction> function = Handle<JSFunction>::cast(function_object);
270
271 // The following conditions were lifted (in part) from the DCHECK inside
272 // JSFunction::MarkForOptimization().
273
274 if (!function->shared().allows_lazy_compilation()) {
275 return CrashUnlessFuzzing(isolate);
276 }
277
278 // If function isn't compiled, compile it now.
279 IsCompiledScope is_compiled_scope(
280 function->shared().is_compiled_scope(isolate));
281 if (!is_compiled_scope.is_compiled() &&
282 !Compiler::Compile(function, Compiler::CLEAR_EXCEPTION,
283 &is_compiled_scope)) {
284 return CrashUnlessFuzzing(isolate);
285 }
286
287 if (!FLAG_opt) return ReadOnlyRoots(isolate).undefined_value();
288
289 if (function->shared().optimization_disabled() &&
290 function->shared().disable_optimization_reason() ==
291 BailoutReason::kNeverOptimize) {
292 return CrashUnlessFuzzing(isolate);
293 }
294
295 if (function->shared().HasAsmWasmData()) return CrashUnlessFuzzing(isolate);
296
297 if (FLAG_testing_d8_test_runner) {
298 PendingOptimizationTable::MarkedForOptimization(isolate, function);
299 }
300
301 if (function->HasAvailableOptimizedCode()) {
302 DCHECK(function->HasAttachedOptimizedCode() ||
303 function->ChecksOptimizationMarker());
304 if (FLAG_testing_d8_test_runner) {
305 PendingOptimizationTable::FunctionWasOptimized(isolate, function);
306 }
307 return ReadOnlyRoots(isolate).undefined_value();
308 }
309
310 ConcurrencyMode concurrency_mode = ConcurrencyMode::kNotConcurrent;
311 if (args.length() == 2) {
312 CONVERT_ARG_HANDLE_CHECKED(Object, type, 1);
313 if (!type->IsString()) return CrashUnlessFuzzing(isolate);
314 if (Handle<String>::cast(type)->IsOneByteEqualTo(
315 StaticCharVector("concurrent")) &&
316 isolate->concurrent_recompilation_enabled()) {
317 concurrency_mode = ConcurrencyMode::kConcurrent;
318 }
319 }
320 if (FLAG_trace_opt) {
321 PrintF("[manually marking ");
322 function->ShortPrint();
323 PrintF(" for %s optimization]\n",
324 concurrency_mode == ConcurrencyMode::kConcurrent ? "concurrent"
325 : "non-concurrent");
326 }
327
328 // This function may not have been lazily compiled yet, even though its shared
329 // function has.
330 if (!function->is_compiled()) {
331 DCHECK(function->shared().IsInterpreted());
332 function->set_code(*BUILTIN_CODE(isolate, InterpreterEntryTrampoline));
333 }
334
335 JSFunction::EnsureFeedbackVector(function, &is_compiled_scope);
336 function->MarkForOptimization(concurrency_mode);
337
338 return ReadOnlyRoots(isolate).undefined_value();
339 }
340
341 namespace {
342
EnsureFeedbackVector(Handle<JSFunction> function)343 bool EnsureFeedbackVector(Handle<JSFunction> function) {
344 // Check function allows lazy compilation.
345 if (!function->shared().allows_lazy_compilation()) return false;
346
347 if (function->has_feedback_vector()) return true;
348
349 // If function isn't compiled, compile it now.
350 IsCompiledScope is_compiled_scope(
351 function->shared().is_compiled_scope(function->GetIsolate()));
352 // If the JSFunction isn't compiled but it has a initialized feedback cell
353 // then no need to compile. CompileLazy builtin would handle these cases by
354 // installing the code from SFI. Calling compile here may cause another
355 // optimization if FLAG_always_opt is set.
356 bool needs_compilation =
357 !function->is_compiled() && !function->has_closure_feedback_cell_array();
358 if (needs_compilation &&
359 !Compiler::Compile(function, Compiler::CLEAR_EXCEPTION,
360 &is_compiled_scope)) {
361 return false;
362 }
363
364 // Ensure function has a feedback vector to hold type feedback for
365 // optimization.
366 JSFunction::EnsureFeedbackVector(function, &is_compiled_scope);
367 return true;
368 }
369
370 } // namespace
371
RUNTIME_FUNCTION(Runtime_EnsureFeedbackVectorForFunction)372 RUNTIME_FUNCTION(Runtime_EnsureFeedbackVectorForFunction) {
373 HandleScope scope(isolate);
374 DCHECK_EQ(1, args.length());
375 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
376 EnsureFeedbackVector(function);
377 return ReadOnlyRoots(isolate).undefined_value();
378 }
379
RUNTIME_FUNCTION(Runtime_PrepareFunctionForOptimization)380 RUNTIME_FUNCTION(Runtime_PrepareFunctionForOptimization) {
381 HandleScope scope(isolate);
382 if ((args.length() != 1 && args.length() != 2) || !args[0].IsJSFunction()) {
383 return CrashUnlessFuzzing(isolate);
384 }
385 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
386
387 bool allow_heuristic_optimization = false;
388 if (args.length() == 2) {
389 CONVERT_ARG_HANDLE_CHECKED(Object, sync_object, 1);
390 if (!sync_object->IsString()) return CrashUnlessFuzzing(isolate);
391 Handle<String> sync = Handle<String>::cast(sync_object);
392 if (sync->IsOneByteEqualTo(
393 StaticCharVector("allow heuristic optimization"))) {
394 allow_heuristic_optimization = true;
395 }
396 }
397
398 if (!EnsureFeedbackVector(function)) {
399 return CrashUnlessFuzzing(isolate);
400 }
401
402 // If optimization is disabled for the function, return without making it
403 // pending optimize for test.
404 if (function->shared().optimization_disabled() &&
405 function->shared().disable_optimization_reason() ==
406 BailoutReason::kNeverOptimize) {
407 return CrashUnlessFuzzing(isolate);
408 }
409
410 if (function->shared().HasAsmWasmData()) return CrashUnlessFuzzing(isolate);
411
412 // Hold onto the bytecode array between marking and optimization to ensure
413 // it's not flushed.
414 if (FLAG_testing_d8_test_runner) {
415 PendingOptimizationTable::PreparedForOptimization(
416 isolate, function, allow_heuristic_optimization);
417 }
418
419 return ReadOnlyRoots(isolate).undefined_value();
420 }
421
RUNTIME_FUNCTION(Runtime_OptimizeOsr)422 RUNTIME_FUNCTION(Runtime_OptimizeOsr) {
423 HandleScope scope(isolate);
424 DCHECK(args.length() == 0 || args.length() == 1);
425
426 Handle<JSFunction> function;
427
428 // The optional parameter determines the frame being targeted.
429 int stack_depth = 0;
430 if (args.length() == 1) {
431 if (!args[0].IsSmi()) return CrashUnlessFuzzing(isolate);
432 stack_depth = args.smi_at(0);
433 }
434
435 // Find the JavaScript function on the top of the stack.
436 JavaScriptFrameIterator it(isolate);
437 while (!it.done() && stack_depth--) it.Advance();
438 if (!it.done()) function = handle(it.frame()->function(), isolate);
439 if (function.is_null()) return CrashUnlessFuzzing(isolate);
440
441 if (!FLAG_opt) return ReadOnlyRoots(isolate).undefined_value();
442
443 if (function->shared().optimization_disabled() &&
444 function->shared().disable_optimization_reason() ==
445 BailoutReason::kNeverOptimize) {
446 return CrashUnlessFuzzing(isolate);
447 }
448
449 if (FLAG_testing_d8_test_runner) {
450 PendingOptimizationTable::MarkedForOptimization(isolate, function);
451 }
452
453 if (function->HasAvailableOptimizedCode()) {
454 DCHECK(function->HasAttachedOptimizedCode() ||
455 function->ChecksOptimizationMarker());
456 // If function is already optimized, remove the bytecode array from the
457 // pending optimize for test table and return.
458 if (FLAG_testing_d8_test_runner) {
459 PendingOptimizationTable::FunctionWasOptimized(isolate, function);
460 }
461 return ReadOnlyRoots(isolate).undefined_value();
462 }
463
464 // Ensure that the function is marked for non-concurrent optimization, so that
465 // subsequent runs don't also optimize.
466 if (FLAG_trace_osr) {
467 CodeTracer::Scope scope(isolate->GetCodeTracer());
468 PrintF(scope.file(), "[OSR - OptimizeOsr marking ");
469 function->ShortPrint(scope.file());
470 PrintF(scope.file(), " for non-concurrent optimization]\n");
471 }
472 IsCompiledScope is_compiled_scope(
473 function->shared().is_compiled_scope(isolate));
474 JSFunction::EnsureFeedbackVector(function, &is_compiled_scope);
475 function->MarkForOptimization(ConcurrencyMode::kNotConcurrent);
476
477 // Make the profiler arm all back edges in unoptimized code.
478 if (it.frame()->type() == StackFrame::INTERPRETED) {
479 isolate->runtime_profiler()->AttemptOnStackReplacement(
480 InterpretedFrame::cast(it.frame()),
481 AbstractCode::kMaxLoopNestingMarker);
482 }
483
484 return ReadOnlyRoots(isolate).undefined_value();
485 }
486
487
RUNTIME_FUNCTION(Runtime_NeverOptimizeFunction)488 RUNTIME_FUNCTION(Runtime_NeverOptimizeFunction) {
489 HandleScope scope(isolate);
490 DCHECK_EQ(1, args.length());
491 CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0);
492 if (!function_object->IsJSFunction()) return CrashUnlessFuzzing(isolate);
493 Handle<JSFunction> function = Handle<JSFunction>::cast(function_object);
494 SharedFunctionInfo sfi = function->shared();
495 if (sfi.abstract_code().kind() != CodeKind::INTERPRETED_FUNCTION &&
496 sfi.abstract_code().kind() != CodeKind::BUILTIN) {
497 return CrashUnlessFuzzing(isolate);
498 }
499 sfi.DisableOptimization(BailoutReason::kNeverOptimize);
500 return ReadOnlyRoots(isolate).undefined_value();
501 }
502
RUNTIME_FUNCTION(Runtime_GetOptimizationStatus)503 RUNTIME_FUNCTION(Runtime_GetOptimizationStatus) {
504 HandleScope scope(isolate);
505 DCHECK(args.length() == 1 || args.length() == 2);
506 int status = 0;
507 if (FLAG_lite_mode || FLAG_jitless) {
508 // Both jitless and lite modes cannot optimize. Unit tests should handle
509 // these the same way. In the future, the two flags may become synonyms.
510 status |= static_cast<int>(OptimizationStatus::kLiteMode);
511 }
512 if (!isolate->use_optimizer()) {
513 status |= static_cast<int>(OptimizationStatus::kNeverOptimize);
514 }
515 if (FLAG_always_opt || FLAG_prepare_always_opt) {
516 status |= static_cast<int>(OptimizationStatus::kAlwaysOptimize);
517 }
518 if (FLAG_deopt_every_n_times) {
519 status |= static_cast<int>(OptimizationStatus::kMaybeDeopted);
520 }
521
522 CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0);
523 if (function_object->IsUndefined()) return Smi::FromInt(status);
524 if (!function_object->IsJSFunction()) return CrashUnlessFuzzing(isolate);
525 Handle<JSFunction> function = Handle<JSFunction>::cast(function_object);
526
527 status |= static_cast<int>(OptimizationStatus::kIsFunction);
528
529 bool sync_with_compiler_thread = true;
530 if (args.length() == 2) {
531 CONVERT_ARG_HANDLE_CHECKED(Object, sync_object, 1);
532 if (!sync_object->IsString()) return CrashUnlessFuzzing(isolate);
533 Handle<String> sync = Handle<String>::cast(sync_object);
534 if (sync->IsOneByteEqualTo(StaticCharVector("no sync"))) {
535 sync_with_compiler_thread = false;
536 } else if (sync->IsOneByteEqualTo(StaticCharVector("sync")) ||
537 sync->length() == 0) {
538 DCHECK(sync_with_compiler_thread);
539 } else {
540 return CrashUnlessFuzzing(isolate);
541 }
542 }
543
544 if (isolate->concurrent_recompilation_enabled() &&
545 sync_with_compiler_thread) {
546 while (function->IsInOptimizationQueue()) {
547 isolate->optimizing_compile_dispatcher()->InstallOptimizedFunctions();
548 base::OS::Sleep(base::TimeDelta::FromMilliseconds(50));
549 }
550 }
551
552 if (function->IsMarkedForOptimization()) {
553 status |= static_cast<int>(OptimizationStatus::kMarkedForOptimization);
554 } else if (function->IsMarkedForConcurrentOptimization()) {
555 status |=
556 static_cast<int>(OptimizationStatus::kMarkedForConcurrentOptimization);
557 } else if (function->IsInOptimizationQueue()) {
558 status |= static_cast<int>(OptimizationStatus::kOptimizingConcurrently);
559 }
560
561 if (function->HasAttachedOptimizedCode()) {
562 if (function->code().marked_for_deoptimization()) {
563 status |= static_cast<int>(OptimizationStatus::kMarkedForDeoptimization);
564 } else {
565 status |= static_cast<int>(OptimizationStatus::kOptimized);
566 }
567 if (function->code().is_turbofanned()) {
568 status |= static_cast<int>(OptimizationStatus::kTurboFanned);
569 }
570 }
571 if (function->ActiveTierIsIgnition()) {
572 status |= static_cast<int>(OptimizationStatus::kInterpreted);
573 }
574
575 // Additionally, detect activations of this frame on the stack, and report the
576 // status of the topmost frame.
577 JavaScriptFrame* frame = nullptr;
578 JavaScriptFrameIterator it(isolate);
579 while (!it.done()) {
580 if (it.frame()->function() == *function) {
581 frame = it.frame();
582 break;
583 }
584 it.Advance();
585 }
586 if (frame != nullptr) {
587 status |= static_cast<int>(OptimizationStatus::kIsExecuting);
588 if (frame->is_optimized()) {
589 status |=
590 static_cast<int>(OptimizationStatus::kTopmostFrameIsTurboFanned);
591 }
592 }
593
594 return Smi::FromInt(status);
595 }
596
RUNTIME_FUNCTION(Runtime_UnblockConcurrentRecompilation)597 RUNTIME_FUNCTION(Runtime_UnblockConcurrentRecompilation) {
598 DCHECK_EQ(0, args.length());
599 CHECK(FLAG_block_concurrent_recompilation);
600 CHECK(isolate->concurrent_recompilation_enabled());
601 isolate->optimizing_compile_dispatcher()->Unblock();
602 return ReadOnlyRoots(isolate).undefined_value();
603 }
604
ReturnNull(const v8::FunctionCallbackInfo<v8::Value> & args)605 static void ReturnNull(const v8::FunctionCallbackInfo<v8::Value>& args) {
606 args.GetReturnValue().SetNull();
607 }
608
RUNTIME_FUNCTION(Runtime_GetUndetectable)609 RUNTIME_FUNCTION(Runtime_GetUndetectable) {
610 HandleScope scope(isolate);
611 DCHECK_EQ(0, args.length());
612 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
613 Local<v8::ObjectTemplate> desc = v8::ObjectTemplate::New(v8_isolate);
614 desc->MarkAsUndetectable();
615 desc->SetCallAsFunctionHandler(ReturnNull);
616 Local<v8::Object> obj =
617 desc->NewInstance(v8_isolate->GetCurrentContext()).ToLocalChecked();
618 return *Utils::OpenHandle(*obj);
619 }
620
call_as_function(const v8::FunctionCallbackInfo<v8::Value> & args)621 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
622 double v1 =
623 args[0]->NumberValue(args.GetIsolate()->GetCurrentContext()).ToChecked();
624 double v2 =
625 args[1]->NumberValue(args.GetIsolate()->GetCurrentContext()).ToChecked();
626 args.GetReturnValue().Set(v8::Number::New(args.GetIsolate(), v1 - v2));
627 }
628
629 // Returns a callable object. The object returns the difference of its two
630 // parameters when it is called.
RUNTIME_FUNCTION(Runtime_GetCallable)631 RUNTIME_FUNCTION(Runtime_GetCallable) {
632 HandleScope scope(isolate);
633 DCHECK_EQ(0, args.length());
634 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
635 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(v8_isolate);
636 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
637 instance_template->SetCallAsFunctionHandler(call_as_function);
638 v8_isolate->GetCurrentContext();
639 Local<v8::Object> instance =
640 t->GetFunction(v8_isolate->GetCurrentContext())
641 .ToLocalChecked()
642 ->NewInstance(v8_isolate->GetCurrentContext())
643 .ToLocalChecked();
644 return *Utils::OpenHandle(*instance);
645 }
646
RUNTIME_FUNCTION(Runtime_ClearFunctionFeedback)647 RUNTIME_FUNCTION(Runtime_ClearFunctionFeedback) {
648 HandleScope scope(isolate);
649 DCHECK_EQ(1, args.length());
650 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
651 function->ClearTypeFeedbackInfo();
652 return ReadOnlyRoots(isolate).undefined_value();
653 }
654
RUNTIME_FUNCTION(Runtime_SetWasmCompileControls)655 RUNTIME_FUNCTION(Runtime_SetWasmCompileControls) {
656 HandleScope scope(isolate);
657 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
658 CHECK_EQ(args.length(), 2);
659 CONVERT_ARG_HANDLE_CHECKED(Smi, block_size, 0);
660 CONVERT_BOOLEAN_ARG_CHECKED(allow_async, 1);
661 base::MutexGuard guard(g_PerIsolateWasmControlsMutex.Pointer());
662 WasmCompileControls& ctrl = (*GetPerIsolateWasmControls())[v8_isolate];
663 ctrl.AllowAnySizeForAsync = allow_async;
664 ctrl.MaxWasmBufferSize = static_cast<uint32_t>(block_size->value());
665 v8_isolate->SetWasmModuleCallback(WasmModuleOverride);
666 return ReadOnlyRoots(isolate).undefined_value();
667 }
668
RUNTIME_FUNCTION(Runtime_SetWasmInstantiateControls)669 RUNTIME_FUNCTION(Runtime_SetWasmInstantiateControls) {
670 HandleScope scope(isolate);
671 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
672 CHECK_EQ(args.length(), 0);
673 v8_isolate->SetWasmInstanceCallback(WasmInstanceOverride);
674 return ReadOnlyRoots(isolate).undefined_value();
675 }
676
RUNTIME_FUNCTION(Runtime_NotifyContextDisposed)677 RUNTIME_FUNCTION(Runtime_NotifyContextDisposed) {
678 HandleScope scope(isolate);
679 DCHECK_EQ(0, args.length());
680 isolate->heap()->NotifyContextDisposed(true);
681 return ReadOnlyRoots(isolate).undefined_value();
682 }
683
684
RUNTIME_FUNCTION(Runtime_SetAllocationTimeout)685 RUNTIME_FUNCTION(Runtime_SetAllocationTimeout) {
686 SealHandleScope shs(isolate);
687 DCHECK(args.length() == 2 || args.length() == 3);
688 #ifdef V8_ENABLE_ALLOCATION_TIMEOUT
689 CONVERT_INT32_ARG_FUZZ_SAFE(timeout, 1);
690 isolate->heap()->set_allocation_timeout(timeout);
691 #endif
692 #ifdef DEBUG
693 CONVERT_INT32_ARG_FUZZ_SAFE(interval, 0);
694 FLAG_gc_interval = interval;
695 if (args.length() == 3) {
696 // Enable/disable inline allocation if requested.
697 CONVERT_BOOLEAN_ARG_FUZZ_SAFE(inline_allocation, 2);
698 if (inline_allocation) {
699 isolate->heap()->EnableInlineAllocation();
700 } else {
701 isolate->heap()->DisableInlineAllocation();
702 }
703 }
704 #endif
705 return ReadOnlyRoots(isolate).undefined_value();
706 }
707
708 namespace {
709
FixedArrayLenFromSize(int size)710 int FixedArrayLenFromSize(int size) {
711 return Min((size - FixedArray::kHeaderSize) / kTaggedSize,
712 FixedArray::kMaxRegularLength);
713 }
714
FillUpOneNewSpacePage(Isolate * isolate,Heap * heap)715 void FillUpOneNewSpacePage(Isolate* isolate, Heap* heap) {
716 PauseAllocationObserversScope pause_observers(heap);
717 NewSpace* space = heap->new_space();
718 // We cannot rely on `space->limit()` to point to the end of the current page
719 // in the case where inline allocations are disabled, it actually points to
720 // the current allocation pointer.
721 DCHECK_IMPLIES(space->heap()->inline_allocation_disabled(),
722 space->limit() == space->top());
723 int space_remaining =
724 static_cast<int>(space->to_space().page_high() - space->top());
725 while (space_remaining > 0) {
726 int length = FixedArrayLenFromSize(space_remaining);
727 if (length > 0) {
728 Handle<FixedArray> padding =
729 isolate->factory()->NewFixedArray(length, AllocationType::kYoung);
730 DCHECK(heap->new_space()->Contains(*padding));
731 space_remaining -= padding->Size();
732 } else {
733 // Not enough room to create another fixed array. Create a filler.
734 heap->CreateFillerObjectAt(*heap->new_space()->allocation_top_address(),
735 space_remaining, ClearRecordedSlots::kNo);
736 break;
737 }
738 }
739 }
740
741 } // namespace
742
RUNTIME_FUNCTION(Runtime_SimulateNewspaceFull)743 RUNTIME_FUNCTION(Runtime_SimulateNewspaceFull) {
744 HandleScope scope(isolate);
745 Heap* heap = isolate->heap();
746 NewSpace* space = heap->new_space();
747 AlwaysAllocateScopeForTesting always_allocate(heap);
748 do {
749 FillUpOneNewSpacePage(isolate, heap);
750 } while (space->AddFreshPage());
751
752 return ReadOnlyRoots(isolate).undefined_value();
753 }
754
DebugPrintImpl(MaybeObject maybe_object)755 static void DebugPrintImpl(MaybeObject maybe_object) {
756 StdoutStream os;
757 if (maybe_object->IsCleared()) {
758 os << "[weak cleared]";
759 } else {
760 Object object = maybe_object.GetHeapObjectOrSmi();
761 bool weak = maybe_object.IsWeak();
762
763 #ifdef OBJECT_PRINT
764 os << "DebugPrint: ";
765 if (weak) os << "[weak] ";
766 object.Print(os);
767 if (object.IsHeapObject()) {
768 HeapObject::cast(object).map().Print(os);
769 }
770 #else
771 if (weak) os << "[weak] ";
772 // ShortPrint is available in release mode. Print is not.
773 os << Brief(object);
774 #endif
775 }
776 os << std::endl;
777 }
778
RUNTIME_FUNCTION(Runtime_DebugPrint)779 RUNTIME_FUNCTION(Runtime_DebugPrint) {
780 SealHandleScope shs(isolate);
781 DCHECK_EQ(1, args.length());
782
783 MaybeObject maybe_object(*args.address_of_arg_at(0));
784 DebugPrintImpl(maybe_object);
785 return args[0];
786 }
787
RUNTIME_FUNCTION(Runtime_DebugPrintPtr)788 RUNTIME_FUNCTION(Runtime_DebugPrintPtr) {
789 SealHandleScope shs(isolate);
790 StdoutStream os;
791 DCHECK_EQ(1, args.length());
792
793 MaybeObject maybe_object(*args.address_of_arg_at(0));
794 if (!maybe_object.IsCleared()) {
795 Object object = maybe_object.GetHeapObjectOrSmi();
796 size_t pointer;
797 if (object.ToIntegerIndex(&pointer)) {
798 MaybeObject from_pointer(static_cast<Address>(pointer));
799 DebugPrintImpl(from_pointer);
800 }
801 }
802 // We don't allow the converted pointer to leak out to JavaScript.
803 return args[0];
804 }
805
RUNTIME_FUNCTION(Runtime_PrintWithNameForAssert)806 RUNTIME_FUNCTION(Runtime_PrintWithNameForAssert) {
807 SealHandleScope shs(isolate);
808 DCHECK_EQ(2, args.length());
809
810 CONVERT_ARG_CHECKED(String, name, 0);
811
812 PrintF(" * ");
813 StringCharacterStream stream(name);
814 while (stream.HasMore()) {
815 uint16_t character = stream.GetNext();
816 PrintF("%c", character);
817 }
818 PrintF(": ");
819 args[1].ShortPrint();
820 PrintF("\n");
821
822 return ReadOnlyRoots(isolate).undefined_value();
823 }
824
RUNTIME_FUNCTION(Runtime_DebugTrace)825 RUNTIME_FUNCTION(Runtime_DebugTrace) {
826 SealHandleScope shs(isolate);
827 DCHECK_EQ(0, args.length());
828 isolate->PrintStack(stdout);
829 return ReadOnlyRoots(isolate).undefined_value();
830 }
831
RUNTIME_FUNCTION(Runtime_DebugTrackRetainingPath)832 RUNTIME_FUNCTION(Runtime_DebugTrackRetainingPath) {
833 HandleScope scope(isolate);
834 DCHECK_LE(1, args.length());
835 DCHECK_GE(2, args.length());
836 CHECK(FLAG_track_retaining_path);
837 CONVERT_ARG_HANDLE_CHECKED(HeapObject, object, 0);
838 RetainingPathOption option = RetainingPathOption::kDefault;
839 if (args.length() == 2) {
840 CONVERT_ARG_HANDLE_CHECKED(String, str, 1);
841 const char track_ephemeron_path[] = "track-ephemeron-path";
842 if (str->IsOneByteEqualTo(StaticCharVector(track_ephemeron_path))) {
843 option = RetainingPathOption::kTrackEphemeronPath;
844 } else {
845 CHECK_EQ(str->length(), 0);
846 }
847 }
848 isolate->heap()->AddRetainingPathTarget(object, option);
849 return ReadOnlyRoots(isolate).undefined_value();
850 }
851
852 // This will not allocate (flatten the string), but it may run
853 // very slowly for very deeply nested ConsStrings. For debugging use only.
RUNTIME_FUNCTION(Runtime_GlobalPrint)854 RUNTIME_FUNCTION(Runtime_GlobalPrint) {
855 SealHandleScope shs(isolate);
856 DCHECK_EQ(1, args.length());
857
858 CONVERT_ARG_CHECKED(String, string, 0);
859 StringCharacterStream stream(string);
860 while (stream.HasMore()) {
861 uint16_t character = stream.GetNext();
862 PrintF("%c", character);
863 }
864 return string;
865 }
866
867
RUNTIME_FUNCTION(Runtime_SystemBreak)868 RUNTIME_FUNCTION(Runtime_SystemBreak) {
869 // The code below doesn't create handles, but when breaking here in GDB
870 // having a handle scope might be useful.
871 HandleScope scope(isolate);
872 DCHECK_EQ(0, args.length());
873 base::OS::DebugBreak();
874 return ReadOnlyRoots(isolate).undefined_value();
875 }
876
877
RUNTIME_FUNCTION(Runtime_SetForceSlowPath)878 RUNTIME_FUNCTION(Runtime_SetForceSlowPath) {
879 SealHandleScope shs(isolate);
880 DCHECK_EQ(1, args.length());
881 CONVERT_ARG_CHECKED(Object, arg, 0);
882 if (arg.IsTrue(isolate)) {
883 isolate->set_force_slow_path(true);
884 } else {
885 DCHECK(arg.IsFalse(isolate));
886 isolate->set_force_slow_path(false);
887 }
888 return ReadOnlyRoots(isolate).undefined_value();
889 }
890
RUNTIME_FUNCTION(Runtime_Abort)891 RUNTIME_FUNCTION(Runtime_Abort) {
892 SealHandleScope shs(isolate);
893 DCHECK_EQ(1, args.length());
894 CONVERT_SMI_ARG_CHECKED(message_id, 0);
895 const char* message = GetAbortReason(static_cast<AbortReason>(message_id));
896 base::OS::PrintError("abort: %s\n", message);
897 isolate->PrintStack(stderr);
898 base::OS::Abort();
899 UNREACHABLE();
900 }
901
RUNTIME_FUNCTION(Runtime_AbortJS)902 RUNTIME_FUNCTION(Runtime_AbortJS) {
903 HandleScope scope(isolate);
904 DCHECK_EQ(1, args.length());
905 CONVERT_ARG_HANDLE_CHECKED(String, message, 0);
906 if (FLAG_disable_abortjs) {
907 base::OS::PrintError("[disabled] abort: %s\n", message->ToCString().get());
908 return Object();
909 }
910 base::OS::PrintError("abort: %s\n", message->ToCString().get());
911 isolate->PrintStack(stderr);
912 base::OS::Abort();
913 UNREACHABLE();
914 }
915
RUNTIME_FUNCTION(Runtime_AbortCSAAssert)916 RUNTIME_FUNCTION(Runtime_AbortCSAAssert) {
917 HandleScope scope(isolate);
918 DCHECK_EQ(1, args.length());
919 CONVERT_ARG_HANDLE_CHECKED(String, message, 0);
920 base::OS::PrintError("abort: CSA_ASSERT failed: %s\n",
921 message->ToCString().get());
922 isolate->PrintStack(stderr);
923 base::OS::Abort();
924 UNREACHABLE();
925 }
926
RUNTIME_FUNCTION(Runtime_DisassembleFunction)927 RUNTIME_FUNCTION(Runtime_DisassembleFunction) {
928 HandleScope scope(isolate);
929 #ifdef DEBUG
930 DCHECK_EQ(1, args.length());
931 // Get the function and make sure it is compiled.
932 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
933 IsCompiledScope is_compiled_scope;
934 CHECK(func->is_compiled() ||
935 Compiler::Compile(func, Compiler::KEEP_EXCEPTION, &is_compiled_scope));
936 StdoutStream os;
937 func->code().Print(os);
938 os << std::endl;
939 #endif // DEBUG
940 return ReadOnlyRoots(isolate).undefined_value();
941 }
942
943 namespace {
944
StackSize(Isolate * isolate)945 int StackSize(Isolate* isolate) {
946 int n = 0;
947 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) n++;
948 return n;
949 }
950
PrintIndentation(int stack_size)951 void PrintIndentation(int stack_size) {
952 const int max_display = 80;
953 if (stack_size <= max_display) {
954 PrintF("%4d:%*s", stack_size, stack_size, "");
955 } else {
956 PrintF("%4d:%*s", stack_size, max_display, "...");
957 }
958 }
959
960 } // namespace
961
RUNTIME_FUNCTION(Runtime_TraceEnter)962 RUNTIME_FUNCTION(Runtime_TraceEnter) {
963 SealHandleScope shs(isolate);
964 DCHECK_EQ(0, args.length());
965 PrintIndentation(StackSize(isolate));
966 JavaScriptFrame::PrintTop(isolate, stdout, true, false);
967 PrintF(" {\n");
968 return ReadOnlyRoots(isolate).undefined_value();
969 }
970
RUNTIME_FUNCTION(Runtime_TraceExit)971 RUNTIME_FUNCTION(Runtime_TraceExit) {
972 SealHandleScope shs(isolate);
973 DCHECK_EQ(1, args.length());
974 CONVERT_ARG_CHECKED(Object, obj, 0);
975 PrintIndentation(StackSize(isolate));
976 PrintF("} -> ");
977 obj.ShortPrint();
978 PrintF("\n");
979 return obj; // return TOS
980 }
981
982 namespace {
983
WasmStackSize(Isolate * isolate)984 int WasmStackSize(Isolate* isolate) {
985 // TODO(wasm): Fix this for mixed JS/Wasm stacks with both --trace and
986 // --trace-wasm.
987 int n = 0;
988 for (StackTraceFrameIterator it(isolate); !it.done(); it.Advance()) {
989 if (it.is_wasm()) n++;
990 }
991 return n;
992 }
993
994 } // namespace
995
RUNTIME_FUNCTION(Runtime_WasmTraceEnter)996 RUNTIME_FUNCTION(Runtime_WasmTraceEnter) {
997 HandleScope shs(isolate);
998 DCHECK_EQ(0, args.length());
999 PrintIndentation(WasmStackSize(isolate));
1000
1001 // Find the caller wasm frame.
1002 wasm::WasmCodeRefScope wasm_code_ref_scope;
1003 StackTraceFrameIterator it(isolate);
1004 DCHECK(!it.done());
1005 DCHECK(it.is_wasm());
1006 WasmFrame* frame = WasmFrame::cast(it.frame());
1007
1008 // Find the function name.
1009 int func_index = frame->function_index();
1010 const wasm::WasmModule* module = frame->wasm_instance().module();
1011 wasm::ModuleWireBytes wire_bytes =
1012 wasm::ModuleWireBytes(frame->native_module()->wire_bytes());
1013 wasm::WireBytesRef name_ref =
1014 module->lazily_generated_names.LookupFunctionName(
1015 wire_bytes, func_index, VectorOf(module->export_table));
1016 wasm::WasmName name = wire_bytes.GetNameOrNull(name_ref);
1017
1018 wasm::WasmCode* code = frame->wasm_code();
1019 PrintF(code->is_liftoff() ? "~" : "*");
1020
1021 if (name.empty()) {
1022 PrintF("wasm-function[%d] {\n", func_index);
1023 } else {
1024 PrintF("wasm-function[%d] \"%.*s\" {\n", func_index, name.length(),
1025 name.begin());
1026 }
1027
1028 return ReadOnlyRoots(isolate).undefined_value();
1029 }
1030
RUNTIME_FUNCTION(Runtime_WasmTraceExit)1031 RUNTIME_FUNCTION(Runtime_WasmTraceExit) {
1032 HandleScope shs(isolate);
1033 DCHECK_EQ(1, args.length());
1034 CONVERT_ARG_CHECKED(Smi, value_addr_smi, 0);
1035
1036 PrintIndentation(WasmStackSize(isolate));
1037 PrintF("}");
1038
1039 // Find the caller wasm frame.
1040 wasm::WasmCodeRefScope wasm_code_ref_scope;
1041 StackTraceFrameIterator it(isolate);
1042 DCHECK(!it.done());
1043 DCHECK(it.is_wasm());
1044 WasmFrame* frame = WasmFrame::cast(it.frame());
1045 int func_index = frame->function_index();
1046 const wasm::FunctionSig* sig =
1047 frame->wasm_instance().module()->functions[func_index].sig;
1048
1049 size_t num_returns = sig->return_count();
1050 if (num_returns == 1) {
1051 wasm::ValueType return_type = sig->GetReturn(0);
1052 switch (return_type.kind()) {
1053 case wasm::ValueType::kI32: {
1054 int32_t value = ReadUnalignedValue<int32_t>(value_addr_smi.ptr());
1055 PrintF(" -> %d\n", value);
1056 break;
1057 }
1058 case wasm::ValueType::kI64: {
1059 int64_t value = ReadUnalignedValue<int64_t>(value_addr_smi.ptr());
1060 PrintF(" -> %" PRId64 "\n", value);
1061 break;
1062 }
1063 case wasm::ValueType::kF32: {
1064 float_t value = ReadUnalignedValue<float_t>(value_addr_smi.ptr());
1065 PrintF(" -> %f\n", value);
1066 break;
1067 }
1068 case wasm::ValueType::kF64: {
1069 double_t value = ReadUnalignedValue<double_t>(value_addr_smi.ptr());
1070 PrintF(" -> %f\n", value);
1071 break;
1072 }
1073 default:
1074 PrintF(" -> Unsupported type\n");
1075 break;
1076 }
1077 } else {
1078 // TODO(wasm) Handle multiple return values.
1079 PrintF("\n");
1080 }
1081
1082 return ReadOnlyRoots(isolate).undefined_value();
1083 }
1084
RUNTIME_FUNCTION(Runtime_HaveSameMap)1085 RUNTIME_FUNCTION(Runtime_HaveSameMap) {
1086 SealHandleScope shs(isolate);
1087 DCHECK_EQ(2, args.length());
1088 CONVERT_ARG_CHECKED(JSObject, obj1, 0);
1089 CONVERT_ARG_CHECKED(JSObject, obj2, 1);
1090 return isolate->heap()->ToBoolean(obj1.map() == obj2.map());
1091 }
1092
RUNTIME_FUNCTION(Runtime_InLargeObjectSpace)1093 RUNTIME_FUNCTION(Runtime_InLargeObjectSpace) {
1094 SealHandleScope shs(isolate);
1095 DCHECK_EQ(1, args.length());
1096 CONVERT_ARG_CHECKED(HeapObject, obj, 0);
1097 return isolate->heap()->ToBoolean(
1098 isolate->heap()->new_lo_space()->Contains(obj) ||
1099 isolate->heap()->code_lo_space()->Contains(obj) ||
1100 isolate->heap()->lo_space()->Contains(obj));
1101 }
1102
RUNTIME_FUNCTION(Runtime_HasElementsInALargeObjectSpace)1103 RUNTIME_FUNCTION(Runtime_HasElementsInALargeObjectSpace) {
1104 SealHandleScope shs(isolate);
1105 DCHECK_EQ(1, args.length());
1106 CONVERT_ARG_CHECKED(JSArray, array, 0);
1107 FixedArrayBase elements = array.elements();
1108 return isolate->heap()->ToBoolean(
1109 isolate->heap()->new_lo_space()->Contains(elements) ||
1110 isolate->heap()->lo_space()->Contains(elements));
1111 }
1112
RUNTIME_FUNCTION(Runtime_InYoungGeneration)1113 RUNTIME_FUNCTION(Runtime_InYoungGeneration) {
1114 SealHandleScope shs(isolate);
1115 DCHECK_EQ(1, args.length());
1116 CONVERT_ARG_CHECKED(Object, obj, 0);
1117 return isolate->heap()->ToBoolean(ObjectInYoungGeneration(obj));
1118 }
1119
RUNTIME_FUNCTION(Runtime_IsAsmWasmCode)1120 RUNTIME_FUNCTION(Runtime_IsAsmWasmCode) {
1121 SealHandleScope shs(isolate);
1122 DCHECK_EQ(1, args.length());
1123 CONVERT_ARG_CHECKED(JSFunction, function, 0);
1124 if (!function.shared().HasAsmWasmData()) {
1125 return ReadOnlyRoots(isolate).false_value();
1126 }
1127 if (function.shared().HasBuiltinId() &&
1128 function.shared().builtin_id() == Builtins::kInstantiateAsmJs) {
1129 // Hasn't been compiled yet.
1130 return ReadOnlyRoots(isolate).false_value();
1131 }
1132 return ReadOnlyRoots(isolate).true_value();
1133 }
1134
1135 namespace {
1136
DisallowCodegenFromStringsCallback(v8::Local<v8::Context> context,v8::Local<v8::Value> source,bool is_code_kind)1137 v8::ModifyCodeGenerationFromStringsResult DisallowCodegenFromStringsCallback(
1138 v8::Local<v8::Context> context, v8::Local<v8::Value> source,
1139 bool is_code_kind) {
1140 return {false, {}};
1141 }
1142
DisallowWasmCodegenFromStringsCallback(v8::Local<v8::Context> context,v8::Local<v8::String> source)1143 bool DisallowWasmCodegenFromStringsCallback(v8::Local<v8::Context> context,
1144 v8::Local<v8::String> source) {
1145 return false;
1146 }
1147
1148 } // namespace
1149
RUNTIME_FUNCTION(Runtime_DisallowCodegenFromStrings)1150 RUNTIME_FUNCTION(Runtime_DisallowCodegenFromStrings) {
1151 SealHandleScope shs(isolate);
1152 DCHECK_EQ(1, args.length());
1153 CONVERT_BOOLEAN_ARG_CHECKED(flag, 0);
1154 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
1155 v8_isolate->SetModifyCodeGenerationFromStringsCallback(
1156 flag ? DisallowCodegenFromStringsCallback : nullptr);
1157 return ReadOnlyRoots(isolate).undefined_value();
1158 }
1159
RUNTIME_FUNCTION(Runtime_DisallowWasmCodegen)1160 RUNTIME_FUNCTION(Runtime_DisallowWasmCodegen) {
1161 SealHandleScope shs(isolate);
1162 DCHECK_EQ(1, args.length());
1163 CONVERT_BOOLEAN_ARG_CHECKED(flag, 0);
1164 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
1165 v8_isolate->SetAllowWasmCodeGenerationCallback(
1166 flag ? DisallowWasmCodegenFromStringsCallback : nullptr);
1167 return ReadOnlyRoots(isolate).undefined_value();
1168 }
1169
RUNTIME_FUNCTION(Runtime_IsWasmCode)1170 RUNTIME_FUNCTION(Runtime_IsWasmCode) {
1171 SealHandleScope shs(isolate);
1172 DCHECK_EQ(1, args.length());
1173 CONVERT_ARG_CHECKED(JSFunction, function, 0);
1174 bool is_js_to_wasm =
1175 function.code().kind() == CodeKind::JS_TO_WASM_FUNCTION ||
1176 (function.code().is_builtin() &&
1177 function.code().builtin_index() == Builtins::kGenericJSToWasmWrapper);
1178 return isolate->heap()->ToBoolean(is_js_to_wasm);
1179 }
1180
RUNTIME_FUNCTION(Runtime_IsWasmTrapHandlerEnabled)1181 RUNTIME_FUNCTION(Runtime_IsWasmTrapHandlerEnabled) {
1182 DisallowHeapAllocation no_gc;
1183 DCHECK_EQ(0, args.length());
1184 return isolate->heap()->ToBoolean(trap_handler::IsTrapHandlerEnabled());
1185 }
1186
RUNTIME_FUNCTION(Runtime_IsThreadInWasm)1187 RUNTIME_FUNCTION(Runtime_IsThreadInWasm) {
1188 DisallowHeapAllocation no_gc;
1189 DCHECK_EQ(0, args.length());
1190 return isolate->heap()->ToBoolean(trap_handler::IsThreadInWasm());
1191 }
1192
RUNTIME_FUNCTION(Runtime_GetWasmRecoveredTrapCount)1193 RUNTIME_FUNCTION(Runtime_GetWasmRecoveredTrapCount) {
1194 HandleScope scope(isolate);
1195 DCHECK_EQ(0, args.length());
1196 size_t trap_count = trap_handler::GetRecoveredTrapCount();
1197 return *isolate->factory()->NewNumberFromSize(trap_count);
1198 }
1199
RUNTIME_FUNCTION(Runtime_GetWasmExceptionId)1200 RUNTIME_FUNCTION(Runtime_GetWasmExceptionId) {
1201 HandleScope scope(isolate);
1202 DCHECK_EQ(2, args.length());
1203 CONVERT_ARG_HANDLE_CHECKED(WasmExceptionPackage, exception, 0);
1204 CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 1);
1205 Handle<Object> tag =
1206 WasmExceptionPackage::GetExceptionTag(isolate, exception);
1207 CHECK(tag->IsWasmExceptionTag());
1208 Handle<FixedArray> exceptions_table(instance->exceptions_table(), isolate);
1209 for (int index = 0; index < exceptions_table->length(); ++index) {
1210 if (exceptions_table->get(index) == *tag) return Smi::FromInt(index);
1211 }
1212 UNREACHABLE();
1213 }
1214
RUNTIME_FUNCTION(Runtime_GetWasmExceptionValues)1215 RUNTIME_FUNCTION(Runtime_GetWasmExceptionValues) {
1216 HandleScope scope(isolate);
1217 DCHECK_EQ(1, args.length());
1218 CONVERT_ARG_HANDLE_CHECKED(WasmExceptionPackage, exception, 0);
1219 Handle<Object> values_obj =
1220 WasmExceptionPackage::GetExceptionValues(isolate, exception);
1221 CHECK(values_obj->IsFixedArray()); // Only called with correct input.
1222 Handle<FixedArray> values = Handle<FixedArray>::cast(values_obj);
1223 return *isolate->factory()->NewJSArrayWithElements(values);
1224 }
1225
1226 namespace {
EnableWasmThreads(v8::Local<v8::Context> context)1227 bool EnableWasmThreads(v8::Local<v8::Context> context) { return true; }
DisableWasmThreads(v8::Local<v8::Context> context)1228 bool DisableWasmThreads(v8::Local<v8::Context> context) { return false; }
1229 } // namespace
1230
1231 // This runtime function enables WebAssembly threads through an embedder
1232 // callback and thereby bypasses the value in FLAG_experimental_wasm_threads.
RUNTIME_FUNCTION(Runtime_SetWasmThreadsEnabled)1233 RUNTIME_FUNCTION(Runtime_SetWasmThreadsEnabled) {
1234 DCHECK_EQ(1, args.length());
1235 CONVERT_BOOLEAN_ARG_CHECKED(flag, 0);
1236 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
1237 v8_isolate->SetWasmThreadsEnabledCallback(flag ? EnableWasmThreads
1238 : DisableWasmThreads);
1239 return ReadOnlyRoots(isolate).undefined_value();
1240 }
1241
RUNTIME_FUNCTION(Runtime_RegexpHasBytecode)1242 RUNTIME_FUNCTION(Runtime_RegexpHasBytecode) {
1243 SealHandleScope shs(isolate);
1244 DCHECK_EQ(2, args.length());
1245 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1246 CONVERT_BOOLEAN_ARG_CHECKED(is_latin1, 1);
1247 bool result;
1248 if (regexp.TypeTag() == JSRegExp::IRREGEXP) {
1249 result = regexp.Bytecode(is_latin1).IsByteArray();
1250 } else {
1251 result = false;
1252 }
1253 return isolate->heap()->ToBoolean(result);
1254 }
1255
RUNTIME_FUNCTION(Runtime_RegexpHasNativeCode)1256 RUNTIME_FUNCTION(Runtime_RegexpHasNativeCode) {
1257 SealHandleScope shs(isolate);
1258 DCHECK_EQ(2, args.length());
1259 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1260 CONVERT_BOOLEAN_ARG_CHECKED(is_latin1, 1);
1261 bool result;
1262 if (regexp.TypeTag() == JSRegExp::IRREGEXP) {
1263 result = regexp.Code(is_latin1).IsCode();
1264 } else {
1265 result = false;
1266 }
1267 return isolate->heap()->ToBoolean(result);
1268 }
1269
RUNTIME_FUNCTION(Runtime_RegexpTypeTag)1270 RUNTIME_FUNCTION(Runtime_RegexpTypeTag) {
1271 HandleScope shs(isolate);
1272 DCHECK_EQ(1, args.length());
1273 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1274 const char* type_str;
1275 switch (regexp.TypeTag()) {
1276 case JSRegExp::NOT_COMPILED:
1277 type_str = "NOT_COMPILED";
1278 break;
1279 case JSRegExp::ATOM:
1280 type_str = "ATOM";
1281 break;
1282 case JSRegExp::IRREGEXP:
1283 type_str = "IRREGEXP";
1284 break;
1285 case JSRegExp::EXPERIMENTAL:
1286 type_str = "EXPERIMENTAL";
1287 break;
1288 }
1289 return *isolate->factory()->NewStringFromAsciiChecked(type_str);
1290 }
1291
RUNTIME_FUNCTION(Runtime_RegexpIsUnmodified)1292 RUNTIME_FUNCTION(Runtime_RegexpIsUnmodified) {
1293 HandleScope shs(isolate);
1294 DCHECK_EQ(1, args.length());
1295 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
1296 return isolate->heap()->ToBoolean(
1297 RegExp::IsUnmodifiedRegExp(isolate, regexp));
1298 }
1299
1300 #define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
1301 RUNTIME_FUNCTION(Runtime_Has##Name) { \
1302 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
1303 return isolate->heap()->ToBoolean(obj.Has##Name()); \
1304 }
1305
1306 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(SmiElements)1307 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(SmiElements)
1308 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ObjectElements)
1309 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(SmiOrObjectElements)
1310 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DoubleElements)
1311 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(HoleyElements)
1312 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
1313 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(PackedElements)
1314 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(SloppyArgumentsElements)
1315 // Properties test sitting with elements tests - not fooling anyone.
1316 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastProperties)
1317
1318 #undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
1319
1320 #define FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype) \
1321 RUNTIME_FUNCTION(Runtime_HasFixed##Type##Elements) { \
1322 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
1323 return isolate->heap()->ToBoolean(obj.HasFixed##Type##Elements()); \
1324 }
1325
1326 TYPED_ARRAYS(FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION)
1327
1328 #undef FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION
1329
1330 RUNTIME_FUNCTION(Runtime_ArraySpeciesProtector) {
1331 SealHandleScope shs(isolate);
1332 DCHECK_EQ(0, args.length());
1333 return isolate->heap()->ToBoolean(
1334 Protectors::IsArraySpeciesLookupChainIntact(isolate));
1335 }
1336
RUNTIME_FUNCTION(Runtime_MapIteratorProtector)1337 RUNTIME_FUNCTION(Runtime_MapIteratorProtector) {
1338 SealHandleScope shs(isolate);
1339 DCHECK_EQ(0, args.length());
1340 return isolate->heap()->ToBoolean(
1341 Protectors::IsMapIteratorLookupChainIntact(isolate));
1342 }
1343
RUNTIME_FUNCTION(Runtime_SetIteratorProtector)1344 RUNTIME_FUNCTION(Runtime_SetIteratorProtector) {
1345 SealHandleScope shs(isolate);
1346 DCHECK_EQ(0, args.length());
1347 return isolate->heap()->ToBoolean(
1348 Protectors::IsSetIteratorLookupChainIntact(isolate));
1349 }
1350
RUNTIME_FUNCTION(Runtime_StringIteratorProtector)1351 RUNTIME_FUNCTION(Runtime_StringIteratorProtector) {
1352 SealHandleScope shs(isolate);
1353 DCHECK_EQ(0, args.length());
1354 return isolate->heap()->ToBoolean(
1355 Protectors::IsStringIteratorLookupChainIntact(isolate));
1356 }
1357
1358 // For use by tests and fuzzers. It
1359 //
1360 // 1. serializes a snapshot of the current isolate,
1361 // 2. deserializes the snapshot,
1362 // 3. and runs VerifyHeap on the resulting isolate.
1363 //
1364 // The current isolate should not be modified by this call and can keep running
1365 // once it completes.
RUNTIME_FUNCTION(Runtime_SerializeDeserializeNow)1366 RUNTIME_FUNCTION(Runtime_SerializeDeserializeNow) {
1367 HandleScope scope(isolate);
1368 DCHECK_EQ(0, args.length());
1369 Snapshot::SerializeDeserializeAndVerifyForTesting(isolate,
1370 isolate->native_context());
1371 return ReadOnlyRoots(isolate).undefined_value();
1372 }
1373
1374 // Wait until the given module is fully tiered up, then serialize it into an
1375 // array buffer.
RUNTIME_FUNCTION(Runtime_SerializeWasmModule)1376 RUNTIME_FUNCTION(Runtime_SerializeWasmModule) {
1377 HandleScope scope(isolate);
1378 DCHECK_EQ(1, args.length());
1379 CONVERT_ARG_HANDLE_CHECKED(WasmModuleObject, module_obj, 0);
1380
1381 wasm::NativeModule* native_module = module_obj->native_module();
1382 native_module->compilation_state()->WaitForTopTierFinished();
1383 DCHECK(!native_module->compilation_state()->failed());
1384
1385 wasm::WasmSerializer wasm_serializer(native_module);
1386 size_t byte_length = wasm_serializer.GetSerializedNativeModuleSize();
1387
1388 Handle<JSArrayBuffer> array_buffer =
1389 isolate->factory()
1390 ->NewJSArrayBufferAndBackingStore(byte_length,
1391 InitializedFlag::kUninitialized)
1392 .ToHandleChecked();
1393
1394 CHECK(wasm_serializer.SerializeNativeModule(
1395 {static_cast<uint8_t*>(array_buffer->backing_store()), byte_length}));
1396 return *array_buffer;
1397 }
1398
1399 // Take an array buffer and attempt to reconstruct a compiled wasm module.
1400 // Return undefined if unsuccessful.
RUNTIME_FUNCTION(Runtime_DeserializeWasmModule)1401 RUNTIME_FUNCTION(Runtime_DeserializeWasmModule) {
1402 HandleScope scope(isolate);
1403 DCHECK_EQ(2, args.length());
1404 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 0);
1405 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, wire_bytes, 1);
1406 CHECK(!buffer->was_detached());
1407 CHECK(!wire_bytes->WasDetached());
1408
1409 Handle<JSArrayBuffer> wire_bytes_buffer = wire_bytes->GetBuffer();
1410 Vector<const uint8_t> wire_bytes_vec{
1411 reinterpret_cast<const uint8_t*>(wire_bytes_buffer->backing_store()) +
1412 wire_bytes->byte_offset(),
1413 wire_bytes->byte_length()};
1414 Vector<uint8_t> buffer_vec{
1415 reinterpret_cast<uint8_t*>(buffer->backing_store()),
1416 buffer->byte_length()};
1417
1418 // Note that {wasm::DeserializeNativeModule} will allocate. We assume the
1419 // JSArrayBuffer backing store doesn't get relocated.
1420 MaybeHandle<WasmModuleObject> maybe_module_object =
1421 wasm::DeserializeNativeModule(isolate, buffer_vec, wire_bytes_vec, {});
1422 Handle<WasmModuleObject> module_object;
1423 if (!maybe_module_object.ToHandle(&module_object)) {
1424 return ReadOnlyRoots(isolate).undefined_value();
1425 }
1426 return *module_object;
1427 }
1428
RUNTIME_FUNCTION(Runtime_HeapObjectVerify)1429 RUNTIME_FUNCTION(Runtime_HeapObjectVerify) {
1430 HandleScope shs(isolate);
1431 DCHECK_EQ(1, args.length());
1432 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
1433 #ifdef VERIFY_HEAP
1434 object->ObjectVerify(isolate);
1435 #else
1436 CHECK(object->IsObject());
1437 if (object->IsHeapObject()) {
1438 CHECK(HeapObject::cast(*object).map().IsMap());
1439 } else {
1440 CHECK(object->IsSmi());
1441 }
1442 #endif
1443 return isolate->heap()->ToBoolean(true);
1444 }
1445
RUNTIME_FUNCTION(Runtime_ArrayBufferMaxByteLength)1446 RUNTIME_FUNCTION(Runtime_ArrayBufferMaxByteLength) {
1447 HandleScope shs(isolate);
1448 DCHECK_EQ(0, args.length());
1449 return *isolate->factory()->NewNumber(JSArrayBuffer::kMaxByteLength);
1450 }
1451
RUNTIME_FUNCTION(Runtime_TypedArrayMaxLength)1452 RUNTIME_FUNCTION(Runtime_TypedArrayMaxLength) {
1453 HandleScope shs(isolate);
1454 DCHECK_EQ(0, args.length());
1455 return *isolate->factory()->NewNumber(JSTypedArray::kMaxLength);
1456 }
1457
RUNTIME_FUNCTION(Runtime_WasmGetNumberOfInstances)1458 RUNTIME_FUNCTION(Runtime_WasmGetNumberOfInstances) {
1459 SealHandleScope shs(isolate);
1460 DCHECK_EQ(1, args.length());
1461 CONVERT_ARG_HANDLE_CHECKED(WasmModuleObject, module_obj, 0);
1462 int instance_count = 0;
1463 WeakArrayList weak_instance_list =
1464 module_obj->script().wasm_weak_instance_list();
1465 for (int i = 0; i < weak_instance_list.length(); ++i) {
1466 if (weak_instance_list.Get(i)->IsWeak()) instance_count++;
1467 }
1468 return Smi::FromInt(instance_count);
1469 }
1470
RUNTIME_FUNCTION(Runtime_WasmNumCodeSpaces)1471 RUNTIME_FUNCTION(Runtime_WasmNumCodeSpaces) {
1472 DCHECK_EQ(1, args.length());
1473 HandleScope scope(isolate);
1474 CONVERT_ARG_HANDLE_CHECKED(JSObject, argument, 0);
1475 Handle<WasmModuleObject> module;
1476 if (argument->IsWasmInstanceObject()) {
1477 module = handle(Handle<WasmInstanceObject>::cast(argument)->module_object(),
1478 isolate);
1479 } else if (argument->IsWasmModuleObject()) {
1480 module = Handle<WasmModuleObject>::cast(argument);
1481 }
1482 size_t num_spaces =
1483 module->native_module()->GetNumberOfCodeSpacesForTesting();
1484 return *isolate->factory()->NewNumberFromSize(num_spaces);
1485 }
1486
RUNTIME_FUNCTION(Runtime_WasmTraceMemory)1487 RUNTIME_FUNCTION(Runtime_WasmTraceMemory) {
1488 HandleScope scope(isolate);
1489 DCHECK_EQ(1, args.length());
1490 CONVERT_ARG_CHECKED(Smi, info_addr, 0);
1491
1492 wasm::MemoryTracingInfo* info =
1493 reinterpret_cast<wasm::MemoryTracingInfo*>(info_addr.ptr());
1494
1495 // Find the caller wasm frame.
1496 wasm::WasmCodeRefScope wasm_code_ref_scope;
1497 StackTraceFrameIterator it(isolate);
1498 DCHECK(!it.done());
1499 DCHECK(it.is_wasm());
1500 WasmFrame* frame = WasmFrame::cast(it.frame());
1501
1502 uint8_t* mem_start = reinterpret_cast<uint8_t*>(
1503 frame->wasm_instance().memory_object().array_buffer().backing_store());
1504 int func_index = frame->function_index();
1505 int pos = frame->position();
1506 // TODO(titzer): eliminate dependency on WasmModule definition here.
1507 int func_start =
1508 frame->wasm_instance().module()->functions[func_index].code.offset();
1509 wasm::ExecutionTier tier = frame->wasm_code()->is_liftoff()
1510 ? wasm::ExecutionTier::kLiftoff
1511 : wasm::ExecutionTier::kTurbofan;
1512 wasm::TraceMemoryOperation(tier, info, func_index, pos - func_start,
1513 mem_start);
1514 return ReadOnlyRoots(isolate).undefined_value();
1515 }
1516
RUNTIME_FUNCTION(Runtime_WasmTierUpFunction)1517 RUNTIME_FUNCTION(Runtime_WasmTierUpFunction) {
1518 HandleScope scope(isolate);
1519 DCHECK_EQ(2, args.length());
1520 CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
1521 CONVERT_SMI_ARG_CHECKED(function_index, 1);
1522 auto* native_module = instance->module_object().native_module();
1523 isolate->wasm_engine()->CompileFunction(
1524 isolate, native_module, function_index, wasm::ExecutionTier::kTurbofan);
1525 CHECK(!native_module->compilation_state()->failed());
1526 return ReadOnlyRoots(isolate).undefined_value();
1527 }
1528
RUNTIME_FUNCTION(Runtime_WasmTierDownModule)1529 RUNTIME_FUNCTION(Runtime_WasmTierDownModule) {
1530 HandleScope scope(isolate);
1531 DCHECK_EQ(1, args.length());
1532 CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
1533 auto* native_module = instance->module_object().native_module();
1534 native_module->SetTieringState(wasm::kTieredDown);
1535 native_module->RecompileForTiering();
1536 CHECK(!native_module->compilation_state()->failed());
1537 return ReadOnlyRoots(isolate).undefined_value();
1538 }
1539
RUNTIME_FUNCTION(Runtime_WasmTierUpModule)1540 RUNTIME_FUNCTION(Runtime_WasmTierUpModule) {
1541 HandleScope scope(isolate);
1542 DCHECK_EQ(1, args.length());
1543 CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
1544 auto* native_module = instance->module_object().native_module();
1545 native_module->SetTieringState(wasm::kTieredUp);
1546 native_module->RecompileForTiering();
1547 CHECK(!native_module->compilation_state()->failed());
1548 return ReadOnlyRoots(isolate).undefined_value();
1549 }
1550
RUNTIME_FUNCTION(Runtime_IsLiftoffFunction)1551 RUNTIME_FUNCTION(Runtime_IsLiftoffFunction) {
1552 HandleScope scope(isolate);
1553 DCHECK_EQ(1, args.length());
1554 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
1555 CHECK(WasmExportedFunction::IsWasmExportedFunction(*function));
1556 Handle<WasmExportedFunction> exp_fun =
1557 Handle<WasmExportedFunction>::cast(function);
1558 wasm::NativeModule* native_module =
1559 exp_fun->instance().module_object().native_module();
1560 uint32_t func_index = exp_fun->function_index();
1561 wasm::WasmCodeRefScope code_ref_scope;
1562 wasm::WasmCode* code = native_module->GetCode(func_index);
1563 return isolate->heap()->ToBoolean(code && code->is_liftoff());
1564 }
1565
RUNTIME_FUNCTION(Runtime_CompleteInobjectSlackTracking)1566 RUNTIME_FUNCTION(Runtime_CompleteInobjectSlackTracking) {
1567 HandleScope scope(isolate);
1568 DCHECK_EQ(1, args.length());
1569
1570 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
1571 object->map().CompleteInobjectSlackTracking(isolate);
1572
1573 return ReadOnlyRoots(isolate).undefined_value();
1574 }
1575
RUNTIME_FUNCTION(Runtime_FreezeWasmLazyCompilation)1576 RUNTIME_FUNCTION(Runtime_FreezeWasmLazyCompilation) {
1577 DCHECK_EQ(1, args.length());
1578 DisallowHeapAllocation no_gc;
1579 CONVERT_ARG_CHECKED(WasmInstanceObject, instance, 0);
1580
1581 instance.module_object().native_module()->set_lazy_compile_frozen(true);
1582 return ReadOnlyRoots(isolate).undefined_value();
1583 }
1584
RUNTIME_FUNCTION(Runtime_TurbofanStaticAssert)1585 RUNTIME_FUNCTION(Runtime_TurbofanStaticAssert) {
1586 SealHandleScope shs(isolate);
1587 // Always lowered to StaticAssert node in Turbofan, so we never get here in
1588 // compiled code.
1589 return ReadOnlyRoots(isolate).undefined_value();
1590 }
1591
RUNTIME_FUNCTION(Runtime_IsBeingInterpreted)1592 RUNTIME_FUNCTION(Runtime_IsBeingInterpreted) {
1593 SealHandleScope shs(isolate);
1594 // Always lowered to false in Turbofan, so we never get here in compiled code.
1595 return ReadOnlyRoots(isolate).true_value();
1596 }
1597
RUNTIME_FUNCTION(Runtime_EnableCodeLoggingForTesting)1598 RUNTIME_FUNCTION(Runtime_EnableCodeLoggingForTesting) {
1599 // The {NoopListener} currently does nothing on any callback, but reports
1600 // {true} on {is_listening_to_code_events()}. Feel free to add assertions to
1601 // any method to further test the code logging callbacks.
1602 class NoopListener final : public CodeEventListener {
1603 void CodeCreateEvent(LogEventsAndTags tag, Handle<AbstractCode> code,
1604 const char* name) final {}
1605 void CodeCreateEvent(LogEventsAndTags tag, Handle<AbstractCode> code,
1606 Handle<Name> name) final {}
1607 void CodeCreateEvent(LogEventsAndTags tag, Handle<AbstractCode> code,
1608 Handle<SharedFunctionInfo> shared,
1609 Handle<Name> script_name) final {}
1610 void CodeCreateEvent(LogEventsAndTags tag, Handle<AbstractCode> code,
1611 Handle<SharedFunctionInfo> shared,
1612 Handle<Name> script_name, int line, int column) final {
1613 }
1614 void CodeCreateEvent(LogEventsAndTags tag, const wasm::WasmCode* code,
1615 wasm::WasmName name) final {}
1616
1617 void CallbackEvent(Handle<Name> name, Address entry_point) final {}
1618 void GetterCallbackEvent(Handle<Name> name, Address entry_point) final {}
1619 void SetterCallbackEvent(Handle<Name> name, Address entry_point) final {}
1620 void RegExpCodeCreateEvent(Handle<AbstractCode> code,
1621 Handle<String> source) final {}
1622 void CodeMoveEvent(AbstractCode from, AbstractCode to) final {}
1623 void SharedFunctionInfoMoveEvent(Address from, Address to) final {}
1624 void CodeMovingGCEvent() final {}
1625 void CodeDisableOptEvent(Handle<AbstractCode> code,
1626 Handle<SharedFunctionInfo> shared) final {}
1627 void CodeDeoptEvent(Handle<Code> code, DeoptimizeKind kind, Address pc,
1628 int fp_to_sp_delta, bool reuse_code) final {}
1629 void CodeDependencyChangeEvent(Handle<Code> code,
1630 Handle<SharedFunctionInfo> shared,
1631 const char* reason) final {}
1632
1633 bool is_listening_to_code_events() final { return true; }
1634 };
1635 static base::LeakyObject<NoopListener> noop_listener;
1636 isolate->wasm_engine()->EnableCodeLogging(isolate);
1637 isolate->code_event_dispatcher()->AddListener(noop_listener.get());
1638 return ReadOnlyRoots(isolate).undefined_value();
1639 }
1640
RUNTIME_FUNCTION(Runtime_NewRegExpWithBacktrackLimit)1641 RUNTIME_FUNCTION(Runtime_NewRegExpWithBacktrackLimit) {
1642 HandleScope scope(isolate);
1643 DCHECK_EQ(3, args.length());
1644
1645 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 0);
1646 CONVERT_ARG_HANDLE_CHECKED(String, flags_string, 1);
1647 CONVERT_UINT32_ARG_CHECKED(backtrack_limit, 2);
1648
1649 bool success = false;
1650 JSRegExp::Flags flags =
1651 JSRegExp::FlagsFromString(isolate, flags_string, &success);
1652 CHECK(success);
1653
1654 RETURN_RESULT_OR_FAILURE(
1655 isolate, JSRegExp::New(isolate, pattern, flags, backtrack_limit));
1656 }
1657
1658 } // namespace internal
1659 } // namespace v8
1660