Line data Source code
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 : #include <sstream>
9 :
10 : #include "src/api-inl.h"
11 : #include "src/arguments-inl.h"
12 : #include "src/assembler-inl.h"
13 : #include "src/base/platform/mutex.h"
14 : #include "src/compiler-dispatcher/optimizing-compile-dispatcher.h"
15 : #include "src/compiler.h"
16 : #include "src/counters.h"
17 : #include "src/deoptimizer.h"
18 : #include "src/frames-inl.h"
19 : #include "src/heap/heap-inl.h" // For ToBoolean. TODO(jkummerow): Drop.
20 : #include "src/heap/heap-write-barrier-inl.h"
21 : #include "src/ic/stub-cache.h"
22 : #include "src/isolate-inl.h"
23 : #include "src/objects/heap-object-inl.h"
24 : #include "src/objects/smi.h"
25 : #include "src/ostreams.h"
26 : #include "src/runtime-profiler.h"
27 : #include "src/snapshot/natives.h"
28 : #include "src/trap-handler/trap-handler.h"
29 : #include "src/wasm/memory-tracing.h"
30 : #include "src/wasm/module-compiler.h"
31 : #include "src/wasm/wasm-engine.h"
32 : #include "src/wasm/wasm-module.h"
33 : #include "src/wasm/wasm-objects-inl.h"
34 : #include "src/wasm/wasm-serialization.h"
35 :
36 : namespace v8 {
37 : namespace internal {
38 :
39 : namespace {
40 8 : struct WasmCompileControls {
41 : uint32_t MaxWasmBufferSize = std::numeric_limits<uint32_t>::max();
42 : bool AllowAnySizeForAsync = true;
43 : };
44 : using WasmCompileControlsMap = std::map<v8::Isolate*, WasmCompileControls>;
45 :
46 : // We need per-isolate controls, because we sometimes run tests in multiple
47 : // isolates concurrently. Methods need to hold the accompanying mutex on access.
48 : // To avoid upsetting the static initializer count, we lazy initialize this.
49 100 : DEFINE_LAZY_LEAKY_OBJECT_GETTER(WasmCompileControlsMap,
50 : GetPerIsolateWasmControls)
51 : base::LazyMutex g_PerIsolateWasmControlsMutex = LAZY_MUTEX_INITIALIZER;
52 :
53 24 : bool IsWasmCompileAllowed(v8::Isolate* isolate, v8::Local<v8::Value> value,
54 : bool is_async) {
55 : base::MutexGuard guard(g_PerIsolateWasmControlsMutex.Pointer());
56 : DCHECK_GT(GetPerIsolateWasmControls()->count(isolate), 0);
57 24 : const WasmCompileControls& ctrls = GetPerIsolateWasmControls()->at(isolate);
58 24 : return (is_async && ctrls.AllowAnySizeForAsync) ||
59 24 : (value->IsArrayBuffer() &&
60 0 : v8::Local<v8::ArrayBuffer>::Cast(value)->ByteLength() <=
61 48 : ctrls.MaxWasmBufferSize) ||
62 48 : (value->IsArrayBufferView() &&
63 48 : v8::Local<v8::ArrayBufferView>::Cast(value)->ByteLength() <=
64 48 : ctrls.MaxWasmBufferSize);
65 : }
66 :
67 : // Use the compile controls for instantiation, too
68 20 : bool IsWasmInstantiateAllowed(v8::Isolate* isolate,
69 : v8::Local<v8::Value> module_or_bytes,
70 : bool is_async) {
71 : base::MutexGuard guard(g_PerIsolateWasmControlsMutex.Pointer());
72 : DCHECK_GT(GetPerIsolateWasmControls()->count(isolate), 0);
73 20 : const WasmCompileControls& ctrls = GetPerIsolateWasmControls()->at(isolate);
74 20 : if (is_async && ctrls.AllowAnySizeForAsync) return true;
75 20 : if (!module_or_bytes->IsWebAssemblyCompiledModule()) {
76 0 : return IsWasmCompileAllowed(isolate, module_or_bytes, is_async);
77 : }
78 : v8::Local<v8::WasmModuleObject> module =
79 : v8::Local<v8::WasmModuleObject>::Cast(module_or_bytes);
80 : return static_cast<uint32_t>(
81 60 : module->GetCompiledModule().GetWireBytesRef().size()) <=
82 20 : ctrls.MaxWasmBufferSize;
83 : }
84 :
85 16 : v8::Local<v8::Value> NewRangeException(v8::Isolate* isolate,
86 : const char* message) {
87 : return v8::Exception::RangeError(
88 16 : v8::String::NewFromOneByte(isolate,
89 : reinterpret_cast<const uint8_t*>(message),
90 : v8::NewStringType::kNormal)
91 16 : .ToLocalChecked());
92 : }
93 :
94 16 : void ThrowRangeException(v8::Isolate* isolate, const char* message) {
95 16 : isolate->ThrowException(NewRangeException(isolate, message));
96 16 : }
97 :
98 24 : bool WasmModuleOverride(const v8::FunctionCallbackInfo<v8::Value>& args) {
99 24 : if (IsWasmCompileAllowed(args.GetIsolate(), args[0], false)) return false;
100 8 : ThrowRangeException(args.GetIsolate(), "Sync compile not allowed");
101 8 : return true;
102 : }
103 :
104 20 : bool WasmInstanceOverride(const v8::FunctionCallbackInfo<v8::Value>& args) {
105 20 : if (IsWasmInstantiateAllowed(args.GetIsolate(), args[0], false)) return false;
106 8 : ThrowRangeException(args.GetIsolate(), "Sync instantiate not allowed");
107 8 : return true;
108 : }
109 :
110 : } // namespace
111 :
112 0 : RUNTIME_FUNCTION(Runtime_ClearMegamorphicStubCache) {
113 : HandleScope scope(isolate);
114 : DCHECK_EQ(0, args.length());
115 0 : isolate->load_stub_cache()->Clear();
116 0 : isolate->store_stub_cache()->Clear();
117 : return ReadOnlyRoots(isolate).undefined_value();
118 : }
119 :
120 936 : RUNTIME_FUNCTION(Runtime_ConstructDouble) {
121 : HandleScope scope(isolate);
122 : DCHECK_EQ(2, args.length());
123 936 : CONVERT_NUMBER_CHECKED(uint32_t, hi, Uint32, args[0]);
124 936 : CONVERT_NUMBER_CHECKED(uint32_t, lo, Uint32, args[1]);
125 468 : uint64_t result = (static_cast<uint64_t>(hi) << 32) | lo;
126 936 : return *isolate->factory()->NewNumber(uint64_to_double(result));
127 : }
128 :
129 18 : RUNTIME_FUNCTION(Runtime_ConstructConsString) {
130 : HandleScope scope(isolate);
131 : DCHECK_EQ(2, args.length());
132 9 : CONVERT_ARG_HANDLE_CHECKED(String, left, 0);
133 9 : CONVERT_ARG_HANDLE_CHECKED(String, right, 1);
134 :
135 9 : CHECK(left->IsOneByteRepresentation());
136 9 : CHECK(right->IsOneByteRepresentation());
137 :
138 : const bool kIsOneByte = true;
139 9 : const int length = left->length() + right->length();
140 18 : return *isolate->factory()->NewConsString(left, right, length, kIsOneByte);
141 : }
142 :
143 18 : RUNTIME_FUNCTION(Runtime_ConstructSlicedString) {
144 : HandleScope scope(isolate);
145 : DCHECK_EQ(2, args.length());
146 9 : CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
147 9 : CONVERT_ARG_HANDLE_CHECKED(Smi, index, 1);
148 :
149 9 : CHECK(string->IsOneByteRepresentation());
150 9 : CHECK_LT(index->value(), string->length());
151 :
152 : Handle<String> sliced_string = isolate->factory()->NewSubString(
153 9 : string, index->value(), string->length());
154 9 : CHECK(sliced_string->IsSlicedString());
155 : return *sliced_string;
156 : }
157 :
158 116554 : RUNTIME_FUNCTION(Runtime_DeoptimizeFunction) {
159 : HandleScope scope(isolate);
160 : DCHECK_EQ(1, args.length());
161 :
162 : // This function is used by fuzzers to get coverage in compiler.
163 : // Ignore calls on non-function objects to avoid runtime errors.
164 : CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0);
165 58277 : if (!function_object->IsJSFunction()) {
166 : return ReadOnlyRoots(isolate).undefined_value();
167 : }
168 58277 : Handle<JSFunction> function = Handle<JSFunction>::cast(function_object);
169 :
170 : // If the function is not optimized, just return.
171 58277 : if (!function->IsOptimized()) return ReadOnlyRoots(isolate).undefined_value();
172 :
173 14881 : Deoptimizer::DeoptimizeFunction(*function);
174 :
175 : return ReadOnlyRoots(isolate).undefined_value();
176 : }
177 :
178 8330 : RUNTIME_FUNCTION(Runtime_DeoptimizeNow) {
179 : HandleScope scope(isolate);
180 : DCHECK_EQ(0, args.length());
181 :
182 : Handle<JSFunction> function;
183 :
184 : // Find the JavaScript function on the top of the stack.
185 4165 : JavaScriptFrameIterator it(isolate);
186 4165 : if (!it.done()) function = handle(it.frame()->function(), isolate);
187 4165 : if (function.is_null()) return ReadOnlyRoots(isolate).undefined_value();
188 :
189 : // If the function is not optimized, just return.
190 4165 : if (!function->IsOptimized()) return ReadOnlyRoots(isolate).undefined_value();
191 :
192 639 : Deoptimizer::DeoptimizeFunction(*function);
193 :
194 : return ReadOnlyRoots(isolate).undefined_value();
195 : }
196 :
197 18 : RUNTIME_FUNCTION(Runtime_RunningInSimulator) {
198 : SealHandleScope shs(isolate);
199 : DCHECK_EQ(0, args.length());
200 : #if defined(USE_SIMULATOR)
201 : return ReadOnlyRoots(isolate).true_value();
202 : #else
203 : return ReadOnlyRoots(isolate).false_value();
204 : #endif
205 : }
206 :
207 70 : RUNTIME_FUNCTION(Runtime_ICsAreEnabled) {
208 : SealHandleScope shs(isolate);
209 : DCHECK_EQ(0, args.length());
210 35 : return isolate->heap()->ToBoolean(FLAG_use_ic);
211 : }
212 :
213 94 : RUNTIME_FUNCTION(Runtime_IsConcurrentRecompilationSupported) {
214 : SealHandleScope shs(isolate);
215 : DCHECK_EQ(0, args.length());
216 : return isolate->heap()->ToBoolean(
217 : isolate->concurrent_recompilation_enabled());
218 : }
219 :
220 566922 : RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) {
221 : HandleScope scope(isolate);
222 :
223 : // This function is used by fuzzers, ignore calls with bogus arguments count.
224 283461 : if (args.length() != 1 && args.length() != 2) {
225 : return ReadOnlyRoots(isolate).undefined_value();
226 : }
227 :
228 : // This function is used by fuzzers to get coverage for optimizations
229 : // in compiler. Ignore calls on non-function objects to avoid runtime errors.
230 : CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0);
231 283461 : if (!function_object->IsJSFunction()) {
232 : return ReadOnlyRoots(isolate).undefined_value();
233 : }
234 283461 : Handle<JSFunction> function = Handle<JSFunction>::cast(function_object);
235 :
236 : // Check we called PrepareFunctionForOptimization and hold the bytecode
237 : // array to prevent it from getting flushed.
238 : // TODO(mythria): Enable this check once we add PrepareForOptimization in all
239 : // tests before calling OptimizeFunctionOnNextCall.
240 : // CHECK(!ObjectHashTable::cast(
241 : // isolate->heap()->pending_optimize_for_test_bytecode())
242 : // ->Lookup(handle(function->shared(), isolate))
243 : // ->IsTheHole());
244 :
245 : // The following conditions were lifted (in part) from the DCHECK inside
246 : // JSFunction::MarkForOptimization().
247 :
248 566922 : if (!function->shared()->allows_lazy_compilation()) {
249 : return ReadOnlyRoots(isolate).undefined_value();
250 : }
251 :
252 : // If function isn't compiled, compile it now.
253 283409 : IsCompiledScope is_compiled_scope(function->shared()->is_compiled_scope());
254 284265 : if (!is_compiled_scope.is_compiled() &&
255 856 : !Compiler::Compile(function, Compiler::CLEAR_EXCEPTION,
256 : &is_compiled_scope)) {
257 : return ReadOnlyRoots(isolate).undefined_value();
258 : }
259 :
260 857218 : if (function->shared()->optimization_disabled() &&
261 290810 : function->shared()->disable_optimization_reason() ==
262 : BailoutReason::kNeverOptimize) {
263 : return ReadOnlyRoots(isolate).undefined_value();
264 : }
265 :
266 : // If the function is already optimized, just return.
267 528543 : if (function->IsOptimized() || function->shared()->HasAsmWasmData()) {
268 : return ReadOnlyRoots(isolate).undefined_value();
269 : }
270 :
271 : // If the function has optimized code, ensure that we check for it and return.
272 245339 : if (function->HasOptimizedCode()) {
273 : DCHECK(function->ChecksOptimizationMarker());
274 : return ReadOnlyRoots(isolate).undefined_value();
275 : }
276 :
277 : ConcurrencyMode concurrency_mode = ConcurrencyMode::kNotConcurrent;
278 245315 : if (args.length() == 2) {
279 : // Ignore invalid inputs produced by fuzzers.
280 : CONVERT_ARG_HANDLE_CHECKED(Object, type, 1);
281 105 : if (!type->IsString()) {
282 : return ReadOnlyRoots(isolate).undefined_value();
283 : }
284 315 : if (Handle<String>::cast(type)->IsOneByteEqualTo(
285 105 : StaticCharVector("concurrent")) &&
286 : isolate->concurrent_recompilation_enabled()) {
287 : concurrency_mode = ConcurrencyMode::kConcurrent;
288 : }
289 : }
290 245315 : if (FLAG_trace_opt) {
291 672 : PrintF("[manually marking ");
292 1344 : function->ShortPrint();
293 672 : PrintF(" for %s optimization]\n",
294 : concurrency_mode == ConcurrencyMode::kConcurrent ? "concurrent"
295 672 : : "non-concurrent");
296 : }
297 :
298 : // This function may not have been lazily compiled yet, even though its shared
299 : // function has.
300 245315 : if (!function->is_compiled()) {
301 : DCHECK(function->shared()->IsInterpreted());
302 140734 : function->set_code(*BUILTIN_CODE(isolate, InterpreterEntryTrampoline));
303 : }
304 :
305 245315 : JSFunction::EnsureFeedbackVector(function);
306 245315 : function->MarkForOptimization(concurrency_mode);
307 :
308 : return ReadOnlyRoots(isolate).undefined_value();
309 : }
310 :
311 : namespace {
312 :
313 50114 : bool EnsureFeedbackVector(Handle<JSFunction> function) {
314 : // Check function allows lazy compilation.
315 50114 : if (!function->shared()->allows_lazy_compilation()) {
316 : return false;
317 : }
318 :
319 : // If function isn't compiled, compile it now.
320 50114 : IsCompiledScope is_compiled_scope(function->shared()->is_compiled_scope());
321 59365 : if (!is_compiled_scope.is_compiled() &&
322 9251 : !Compiler::Compile(function, Compiler::CLEAR_EXCEPTION,
323 : &is_compiled_scope)) {
324 : return false;
325 : }
326 :
327 : // Ensure function has a feedback vector to hold type feedback for
328 : // optimization.
329 50114 : JSFunction::EnsureFeedbackVector(function);
330 50114 : return true;
331 : }
332 :
333 : } // namespace
334 :
335 412 : RUNTIME_FUNCTION(Runtime_EnsureFeedbackVectorForFunction) {
336 : HandleScope scope(isolate);
337 : DCHECK_EQ(1, args.length());
338 206 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
339 :
340 206 : EnsureFeedbackVector(function);
341 : return ReadOnlyRoots(isolate).undefined_value();
342 : }
343 :
344 99816 : RUNTIME_FUNCTION(Runtime_PrepareFunctionForOptimization) {
345 : HandleScope scope(isolate);
346 : DCHECK_EQ(1, args.length());
347 49908 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
348 :
349 49908 : if (!EnsureFeedbackVector(function)) {
350 : return ReadOnlyRoots(isolate).undefined_value();
351 : }
352 :
353 : // If optimization is disabled for the function, return without making it
354 : // pending optimize for test.
355 51706 : if (function->shared()->optimization_disabled() &&
356 : function->shared()->disable_optimization_reason() ==
357 : BailoutReason::kNeverOptimize) {
358 : return ReadOnlyRoots(isolate).undefined_value();
359 : }
360 :
361 : // If the function is already optimized, return without making it pending
362 : // optimize for test.
363 87565 : if (function->IsOptimized() || function->shared()->HasAsmWasmData()) {
364 : return ReadOnlyRoots(isolate).undefined_value();
365 : }
366 :
367 : // If the function has optimized code, ensure that we check for it and then
368 : // return without making it pending optimize for test.
369 37657 : if (function->HasOptimizedCode()) {
370 : DCHECK(function->ChecksOptimizationMarker());
371 : return ReadOnlyRoots(isolate).undefined_value();
372 : }
373 :
374 : // Hold onto the bytecode array between marking and optimization to ensure
375 : // it's not flushed.
376 : Handle<ObjectHashTable> table =
377 : isolate->heap()->pending_optimize_for_test_bytecode()->IsUndefined()
378 : ? ObjectHashTable::New(isolate, 1)
379 : : handle(ObjectHashTable::cast(
380 : isolate->heap()->pending_optimize_for_test_bytecode()),
381 37193 : isolate);
382 : table = ObjectHashTable::Put(
383 : table, handle(function->shared(), isolate),
384 74386 : handle(function->shared()->GetBytecodeArray(), isolate));
385 : isolate->heap()->SetPendingOptimizeForTestBytecode(*table);
386 :
387 : return ReadOnlyRoots(isolate).undefined_value();
388 : }
389 :
390 46946 : RUNTIME_FUNCTION(Runtime_OptimizeOsr) {
391 : HandleScope scope(isolate);
392 : DCHECK(args.length() == 0 || args.length() == 1);
393 :
394 : Handle<JSFunction> function;
395 :
396 : // The optional parameter determines the frame being targeted.
397 23473 : int stack_depth = args.length() == 1 ? args.smi_at(0) : 0;
398 :
399 : // Find the JavaScript function on the top of the stack.
400 23473 : JavaScriptFrameIterator it(isolate);
401 23662 : while (!it.done() && stack_depth--) it.Advance();
402 23473 : if (!it.done()) function = handle(it.frame()->function(), isolate);
403 23473 : if (function.is_null()) return ReadOnlyRoots(isolate).undefined_value();
404 :
405 : // If the function is already optimized, just return.
406 23473 : if (function->IsOptimized()) return ReadOnlyRoots(isolate).undefined_value();
407 :
408 44284 : if (function->shared()->optimization_disabled() &&
409 17750 : function->shared()->disable_optimization_reason() ==
410 : BailoutReason::kNeverOptimize) {
411 : return ReadOnlyRoots(isolate).undefined_value();
412 : }
413 :
414 : // Ensure that the function is marked for non-concurrent optimization, so that
415 : // subsequent runs don't also optimize.
416 13267 : if (!function->HasOptimizedCode()) {
417 13267 : if (FLAG_trace_osr) {
418 0 : PrintF("[OSR - OptimizeOsr marking ");
419 0 : function->ShortPrint();
420 0 : PrintF(" for non-concurrent optimization]\n");
421 : }
422 13267 : function->MarkForOptimization(ConcurrencyMode::kNotConcurrent);
423 : }
424 :
425 : // Make the profiler arm all back edges in unoptimized code.
426 13267 : if (it.frame()->type() == StackFrame::INTERPRETED) {
427 : isolate->runtime_profiler()->AttemptOnStackReplacement(
428 : InterpretedFrame::cast(it.frame()),
429 6605 : AbstractCode::kMaxLoopNestingMarker);
430 : }
431 :
432 : return ReadOnlyRoots(isolate).undefined_value();
433 : }
434 :
435 :
436 3674 : RUNTIME_FUNCTION(Runtime_NeverOptimizeFunction) {
437 : HandleScope scope(isolate);
438 : DCHECK_EQ(1, args.length());
439 : // This function is used by fuzzers to get coverage for optimizations
440 : // in compiler. Ignore calls on non-function objects to avoid runtime errors.
441 : CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0);
442 1837 : if (!function_object->IsJSFunction()) {
443 : return ReadOnlyRoots(isolate).undefined_value();
444 : }
445 1801 : Handle<JSFunction> function = Handle<JSFunction>::cast(function_object);
446 1801 : function->shared()->DisableOptimization(BailoutReason::kNeverOptimize);
447 : return ReadOnlyRoots(isolate).undefined_value();
448 : }
449 :
450 12016 : RUNTIME_FUNCTION(Runtime_GetOptimizationStatus) {
451 : HandleScope scope(isolate);
452 : DCHECK(args.length() == 1 || args.length() == 2);
453 : int status = 0;
454 6008 : if (FLAG_lite_mode || FLAG_jitless) {
455 : // Both jitless and lite modes cannot optimize. Unit tests should handle
456 : // these the same way. In the future, the two flags may become synonyms.
457 : status |= static_cast<int>(OptimizationStatus::kLiteMode);
458 : }
459 6008 : if (!isolate->use_optimizer()) {
460 43 : status |= static_cast<int>(OptimizationStatus::kNeverOptimize);
461 : }
462 6008 : if (FLAG_always_opt || FLAG_prepare_always_opt) {
463 1655 : status |= static_cast<int>(OptimizationStatus::kAlwaysOptimize);
464 : }
465 6008 : if (FLAG_deopt_every_n_times) {
466 24 : status |= static_cast<int>(OptimizationStatus::kMaybeDeopted);
467 : }
468 :
469 : // This function is used by fuzzers to get coverage for optimizations
470 : // in compiler. Ignore calls on non-function objects to avoid runtime errors.
471 : CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0);
472 6008 : if (!function_object->IsJSFunction()) {
473 : return Smi::FromInt(status);
474 : }
475 5979 : Handle<JSFunction> function = Handle<JSFunction>::cast(function_object);
476 5979 : status |= static_cast<int>(OptimizationStatus::kIsFunction);
477 :
478 : bool sync_with_compiler_thread = true;
479 5979 : if (args.length() == 2) {
480 : CONVERT_ARG_HANDLE_CHECKED(Object, sync_object, 1);
481 5938 : if (!sync_object->IsString())
482 : return ReadOnlyRoots(isolate).undefined_value();
483 5938 : Handle<String> sync = Handle<String>::cast(sync_object);
484 11876 : if (sync->IsOneByteEqualTo(StaticCharVector("no sync"))) {
485 : sync_with_compiler_thread = false;
486 : }
487 : }
488 :
489 5979 : if (isolate->concurrent_recompilation_enabled() &&
490 : sync_with_compiler_thread) {
491 6020 : while (function->IsInOptimizationQueue()) {
492 86 : isolate->optimizing_compile_dispatcher()->InstallOptimizedFunctions();
493 86 : base::OS::Sleep(base::TimeDelta::FromMilliseconds(50));
494 : }
495 : }
496 :
497 5979 : if (function->IsMarkedForOptimization()) {
498 8 : status |= static_cast<int>(OptimizationStatus::kMarkedForOptimization);
499 5971 : } else if (function->IsInOptimizationQueue()) {
500 : status |=
501 32 : static_cast<int>(OptimizationStatus::kMarkedForConcurrentOptimization);
502 5939 : } else if (function->IsInOptimizationQueue()) {
503 0 : status |= static_cast<int>(OptimizationStatus::kOptimizingConcurrently);
504 : }
505 :
506 5979 : if (function->IsOptimized()) {
507 4873 : status |= static_cast<int>(OptimizationStatus::kOptimized);
508 9746 : if (function->code()->is_turbofanned()) {
509 4873 : status |= static_cast<int>(OptimizationStatus::kTurboFanned);
510 : }
511 : }
512 5979 : if (function->IsInterpreted()) {
513 1098 : status |= static_cast<int>(OptimizationStatus::kInterpreted);
514 : }
515 :
516 : // Additionally, detect activations of this frame on the stack, and report the
517 : // status of the topmost frame.
518 : JavaScriptFrame* frame = nullptr;
519 5979 : JavaScriptFrameIterator it(isolate);
520 36541 : while (!it.done()) {
521 61152 : if (it.frame()->function() == *function) {
522 : frame = it.frame();
523 : break;
524 : }
525 30562 : it.Advance();
526 : }
527 5979 : if (frame != nullptr) {
528 14 : status |= static_cast<int>(OptimizationStatus::kIsExecuting);
529 28 : if (frame->is_optimized()) {
530 : status |=
531 10 : static_cast<int>(OptimizationStatus::kTopmostFrameIsTurboFanned);
532 : }
533 : }
534 :
535 : return Smi::FromInt(status);
536 : }
537 :
538 148 : RUNTIME_FUNCTION(Runtime_UnblockConcurrentRecompilation) {
539 : DCHECK_EQ(0, args.length());
540 74 : if (FLAG_block_concurrent_recompilation &&
541 : isolate->concurrent_recompilation_enabled()) {
542 74 : isolate->optimizing_compile_dispatcher()->Unblock();
543 : }
544 : return ReadOnlyRoots(isolate).undefined_value();
545 : }
546 :
547 130 : RUNTIME_FUNCTION(Runtime_GetDeoptCount) {
548 : HandleScope scope(isolate);
549 : DCHECK_EQ(1, args.length());
550 65 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
551 : // Functions without a feedback vector have never deoptimized.
552 65 : if (!function->has_feedback_vector()) return Smi::kZero;
553 : return Smi::FromInt(function->feedback_vector()->deopt_count());
554 : }
555 :
556 45 : static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
557 : args.GetReturnValue().Set(args.This());
558 45 : }
559 :
560 238 : RUNTIME_FUNCTION(Runtime_GetUndetectable) {
561 : HandleScope scope(isolate);
562 : DCHECK_EQ(0, args.length());
563 : v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
564 :
565 119 : Local<v8::ObjectTemplate> desc = v8::ObjectTemplate::New(v8_isolate);
566 119 : desc->MarkAsUndetectable();
567 119 : desc->SetCallAsFunctionHandler(ReturnThis);
568 : Local<v8::Object> obj;
569 238 : if (!desc->NewInstance(v8_isolate->GetCurrentContext()).ToLocal(&obj)) {
570 : return Object();
571 : }
572 : return *Utils::OpenHandle(*obj);
573 : }
574 :
575 80 : static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
576 : double v1 = args[0]
577 240 : ->NumberValue(v8::Isolate::GetCurrent()->GetCurrentContext())
578 : .ToChecked();
579 : double v2 = args[1]
580 240 : ->NumberValue(v8::Isolate::GetCurrent()->GetCurrentContext())
581 : .ToChecked();
582 80 : args.GetReturnValue().Set(
583 : v8::Number::New(v8::Isolate::GetCurrent(), v1 - v2));
584 80 : }
585 :
586 : // Returns a callable object. The object returns the difference of its two
587 : // parameters when it is called.
588 16 : RUNTIME_FUNCTION(Runtime_GetCallable) {
589 : HandleScope scope(isolate);
590 : DCHECK_EQ(0, args.length());
591 : v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
592 8 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(v8_isolate);
593 8 : Local<ObjectTemplate> instance_template = t->InstanceTemplate();
594 8 : instance_template->SetCallAsFunctionHandler(call_as_function);
595 8 : v8_isolate->GetCurrentContext();
596 : Local<v8::Object> instance =
597 8 : t->GetFunction(v8_isolate->GetCurrentContext())
598 : .ToLocalChecked()
599 8 : ->NewInstance(v8_isolate->GetCurrentContext())
600 : .ToLocalChecked();
601 : return *Utils::OpenHandle(*instance);
602 : }
603 :
604 104796 : RUNTIME_FUNCTION(Runtime_ClearFunctionFeedback) {
605 : HandleScope scope(isolate);
606 : DCHECK_EQ(1, args.length());
607 52398 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
608 52398 : function->ClearTypeFeedbackInfo();
609 : return ReadOnlyRoots(isolate).undefined_value();
610 : }
611 :
612 96 : RUNTIME_FUNCTION(Runtime_SetWasmCompileControls) {
613 : HandleScope scope(isolate);
614 48 : v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
615 48 : CHECK_EQ(args.length(), 2);
616 48 : CONVERT_ARG_HANDLE_CHECKED(Smi, block_size, 0);
617 48 : CONVERT_BOOLEAN_ARG_CHECKED(allow_async, 1);
618 48 : base::MutexGuard guard(g_PerIsolateWasmControlsMutex.Pointer());
619 48 : WasmCompileControls& ctrl = (*GetPerIsolateWasmControls())[v8_isolate];
620 48 : ctrl.AllowAnySizeForAsync = allow_async;
621 48 : ctrl.MaxWasmBufferSize = static_cast<uint32_t>(block_size->value());
622 48 : v8_isolate->SetWasmModuleCallback(WasmModuleOverride);
623 : return ReadOnlyRoots(isolate).undefined_value();
624 : }
625 :
626 16 : RUNTIME_FUNCTION(Runtime_SetWasmInstantiateControls) {
627 : HandleScope scope(isolate);
628 : v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
629 8 : CHECK_EQ(args.length(), 0);
630 8 : v8_isolate->SetWasmInstanceCallback(WasmInstanceOverride);
631 : return ReadOnlyRoots(isolate).undefined_value();
632 : }
633 :
634 108 : RUNTIME_FUNCTION(Runtime_NotifyContextDisposed) {
635 : HandleScope scope(isolate);
636 : DCHECK_EQ(0, args.length());
637 54 : isolate->heap()->NotifyContextDisposed(true);
638 : return ReadOnlyRoots(isolate).undefined_value();
639 : }
640 :
641 :
642 604 : RUNTIME_FUNCTION(Runtime_SetAllocationTimeout) {
643 : SealHandleScope shs(isolate);
644 : DCHECK(args.length() == 2 || args.length() == 3);
645 : #ifdef V8_ENABLE_ALLOCATION_TIMEOUT
646 : CONVERT_INT32_ARG_CHECKED(timeout, 1);
647 : isolate->heap()->set_allocation_timeout(timeout);
648 : #endif
649 : #ifdef DEBUG
650 : CONVERT_INT32_ARG_CHECKED(interval, 0);
651 : FLAG_gc_interval = interval;
652 : if (args.length() == 3) {
653 : // Enable/disable inline allocation if requested.
654 : CONVERT_BOOLEAN_ARG_CHECKED(inline_allocation, 2);
655 : if (inline_allocation) {
656 : isolate->heap()->EnableInlineAllocation();
657 : } else {
658 : isolate->heap()->DisableInlineAllocation();
659 : }
660 : }
661 : #endif
662 : return ReadOnlyRoots(isolate).undefined_value();
663 : }
664 :
665 :
666 1556 : RUNTIME_FUNCTION(Runtime_DebugPrint) {
667 : SealHandleScope shs(isolate);
668 : DCHECK_EQ(1, args.length());
669 :
670 778 : MaybeObject maybe_object(*args.address_of_arg_at(0));
671 :
672 1556 : StdoutStream os;
673 778 : if (maybe_object->IsCleared()) {
674 0 : os << "[weak cleared]";
675 : } else {
676 : Object object = maybe_object.GetHeapObjectOrSmi();
677 : bool weak = maybe_object.IsWeak();
678 :
679 : #ifdef DEBUG
680 : if (object->IsString() && !isolate->context().is_null()) {
681 : DCHECK(!weak);
682 : // If we have a string, assume it's a code "marker"
683 : // and print some interesting cpu debugging info.
684 : object->Print(os);
685 : JavaScriptFrameIterator it(isolate);
686 : JavaScriptFrame* frame = it.frame();
687 : os << "fp = " << reinterpret_cast<void*>(frame->fp())
688 : << ", sp = " << reinterpret_cast<void*>(frame->sp())
689 : << ", caller_sp = " << reinterpret_cast<void*>(frame->caller_sp())
690 : << ": ";
691 : } else {
692 : os << "DebugPrint: ";
693 : if (weak) {
694 : os << "[weak] ";
695 : }
696 : object->Print(os);
697 : }
698 : if (object->IsHeapObject()) {
699 : HeapObject::cast(object)->map()->Print(os);
700 : }
701 : #else
702 778 : if (weak) {
703 0 : os << "[weak] ";
704 : }
705 : // ShortPrint is available in release mode. Print is not.
706 778 : os << Brief(object);
707 : #endif
708 : }
709 : os << std::endl;
710 :
711 : return args[0]; // return TOS
712 : }
713 :
714 0 : RUNTIME_FUNCTION(Runtime_PrintWithNameForAssert) {
715 : SealHandleScope shs(isolate);
716 : DCHECK_EQ(2, args.length());
717 :
718 0 : CONVERT_ARG_CHECKED(String, name, 0);
719 :
720 0 : PrintF(" * ");
721 0 : StringCharacterStream stream(name);
722 0 : while (stream.HasMore()) {
723 0 : uint16_t character = stream.GetNext();
724 0 : PrintF("%c", character);
725 : }
726 0 : PrintF(": ");
727 0 : args[1]->ShortPrint();
728 0 : PrintF("\n");
729 :
730 : return ReadOnlyRoots(isolate).undefined_value();
731 : }
732 :
733 16 : RUNTIME_FUNCTION(Runtime_DebugTrace) {
734 : SealHandleScope shs(isolate);
735 : DCHECK_EQ(0, args.length());
736 8 : isolate->PrintStack(stdout);
737 : return ReadOnlyRoots(isolate).undefined_value();
738 : }
739 :
740 0 : RUNTIME_FUNCTION(Runtime_DebugTrackRetainingPath) {
741 : HandleScope scope(isolate);
742 : DCHECK_LE(1, args.length());
743 : DCHECK_GE(2, args.length());
744 0 : if (!FLAG_track_retaining_path) {
745 0 : PrintF("DebugTrackRetainingPath requires --track-retaining-path flag.\n");
746 : } else {
747 0 : CONVERT_ARG_HANDLE_CHECKED(HeapObject, object, 0);
748 : RetainingPathOption option = RetainingPathOption::kDefault;
749 0 : if (args.length() == 2) {
750 0 : CONVERT_ARG_HANDLE_CHECKED(String, str, 1);
751 0 : const char track_ephemeron_path[] = "track-ephemeron-path";
752 0 : if (str->IsOneByteEqualTo(StaticCharVector(track_ephemeron_path))) {
753 : option = RetainingPathOption::kTrackEphemeronPath;
754 0 : } else if (str->length() != 0) {
755 0 : PrintF("Unexpected second argument of DebugTrackRetainingPath.\n");
756 : PrintF("Expected an empty string or '%s', got '%s'.\n",
757 0 : track_ephemeron_path, str->ToCString().get());
758 : }
759 : }
760 0 : isolate->heap()->AddRetainingPathTarget(object, option);
761 : }
762 : return ReadOnlyRoots(isolate).undefined_value();
763 : }
764 :
765 : // This will not allocate (flatten the string), but it may run
766 : // very slowly for very deeply nested ConsStrings. For debugging use only.
767 0 : RUNTIME_FUNCTION(Runtime_GlobalPrint) {
768 : SealHandleScope shs(isolate);
769 : DCHECK_EQ(1, args.length());
770 :
771 0 : CONVERT_ARG_CHECKED(String, string, 0);
772 0 : StringCharacterStream stream(string);
773 0 : while (stream.HasMore()) {
774 0 : uint16_t character = stream.GetNext();
775 0 : PrintF("%c", character);
776 : }
777 : return string;
778 : }
779 :
780 :
781 0 : RUNTIME_FUNCTION(Runtime_SystemBreak) {
782 : // The code below doesn't create handles, but when breaking here in GDB
783 : // having a handle scope might be useful.
784 : HandleScope scope(isolate);
785 : DCHECK_EQ(0, args.length());
786 0 : base::OS::DebugBreak();
787 : return ReadOnlyRoots(isolate).undefined_value();
788 : }
789 :
790 :
791 84 : RUNTIME_FUNCTION(Runtime_SetForceSlowPath) {
792 : SealHandleScope shs(isolate);
793 : DCHECK_EQ(1, args.length());
794 : CONVERT_ARG_CHECKED(Object, arg, 0);
795 42 : if (arg->IsTrue(isolate)) {
796 : isolate->set_force_slow_path(true);
797 : } else {
798 : DCHECK(arg->IsFalse(isolate));
799 : isolate->set_force_slow_path(false);
800 : }
801 : return ReadOnlyRoots(isolate).undefined_value();
802 : }
803 :
804 0 : RUNTIME_FUNCTION(Runtime_Abort) {
805 : SealHandleScope shs(isolate);
806 : DCHECK_EQ(1, args.length());
807 0 : CONVERT_SMI_ARG_CHECKED(message_id, 0);
808 0 : const char* message = GetAbortReason(static_cast<AbortReason>(message_id));
809 0 : base::OS::PrintError("abort: %s\n", message);
810 0 : isolate->PrintStack(stderr);
811 0 : base::OS::Abort();
812 : UNREACHABLE();
813 : }
814 :
815 :
816 0 : RUNTIME_FUNCTION(Runtime_AbortJS) {
817 : HandleScope scope(isolate);
818 : DCHECK_EQ(1, args.length());
819 0 : CONVERT_ARG_HANDLE_CHECKED(String, message, 0);
820 0 : if (FLAG_disable_abortjs) {
821 0 : base::OS::PrintError("[disabled] abort: %s\n", message->ToCString().get());
822 : return Object();
823 : }
824 0 : base::OS::PrintError("abort: %s\n", message->ToCString().get());
825 0 : isolate->PrintStack(stderr);
826 0 : base::OS::Abort();
827 : UNREACHABLE();
828 : }
829 :
830 :
831 36 : RUNTIME_FUNCTION(Runtime_DisassembleFunction) {
832 : HandleScope scope(isolate);
833 : #ifdef DEBUG
834 : DCHECK_EQ(1, args.length());
835 : // Get the function and make sure it is compiled.
836 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
837 : IsCompiledScope is_compiled_scope;
838 : if (!func->is_compiled() &&
839 : !Compiler::Compile(func, Compiler::KEEP_EXCEPTION, &is_compiled_scope)) {
840 : return ReadOnlyRoots(isolate).exception();
841 : }
842 : StdoutStream os;
843 : func->code()->Print(os);
844 : os << std::endl;
845 : #endif // DEBUG
846 : return ReadOnlyRoots(isolate).undefined_value();
847 : }
848 :
849 : namespace {
850 :
851 0 : int StackSize(Isolate* isolate) {
852 : int n = 0;
853 0 : for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) n++;
854 0 : return n;
855 : }
856 :
857 0 : void PrintIndentation(Isolate* isolate) {
858 : const int nmax = 80;
859 0 : int n = StackSize(isolate);
860 0 : if (n <= nmax) {
861 0 : PrintF("%4d:%*s", n, n, "");
862 : } else {
863 0 : PrintF("%4d:%*s", n, nmax, "...");
864 : }
865 0 : }
866 :
867 : } // namespace
868 :
869 0 : RUNTIME_FUNCTION(Runtime_TraceEnter) {
870 : SealHandleScope shs(isolate);
871 : DCHECK_EQ(0, args.length());
872 0 : PrintIndentation(isolate);
873 0 : JavaScriptFrame::PrintTop(isolate, stdout, true, false);
874 0 : PrintF(" {\n");
875 : return ReadOnlyRoots(isolate).undefined_value();
876 : }
877 :
878 :
879 0 : RUNTIME_FUNCTION(Runtime_TraceExit) {
880 : SealHandleScope shs(isolate);
881 : DCHECK_EQ(1, args.length());
882 0 : CONVERT_ARG_CHECKED(Object, obj, 0);
883 0 : PrintIndentation(isolate);
884 0 : PrintF("} -> ");
885 0 : obj->ShortPrint();
886 0 : PrintF("\n");
887 0 : return obj; // return TOS
888 : }
889 :
890 3574 : RUNTIME_FUNCTION(Runtime_HaveSameMap) {
891 : SealHandleScope shs(isolate);
892 : DCHECK_EQ(2, args.length());
893 3574 : CONVERT_ARG_CHECKED(JSObject, obj1, 0);
894 3574 : CONVERT_ARG_CHECKED(JSObject, obj2, 1);
895 3574 : return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
896 : }
897 :
898 :
899 152 : RUNTIME_FUNCTION(Runtime_InNewSpace) {
900 : SealHandleScope shs(isolate);
901 : DCHECK_EQ(1, args.length());
902 : CONVERT_ARG_CHECKED(Object, obj, 0);
903 : return isolate->heap()->ToBoolean(ObjectInYoungGeneration(obj));
904 : }
905 :
906 8444 : RUNTIME_FUNCTION(Runtime_IsAsmWasmCode) {
907 : SealHandleScope shs(isolate);
908 : DCHECK_EQ(1, args.length());
909 8444 : CONVERT_ARG_CHECKED(JSFunction, function, 0);
910 4222 : if (!function->shared()->HasAsmWasmData()) {
911 : // Doesn't have wasm data.
912 : return ReadOnlyRoots(isolate).false_value();
913 : }
914 6060 : if (function->shared()->HasBuiltinId() &&
915 3030 : function->shared()->builtin_id() == Builtins::kInstantiateAsmJs) {
916 : // Hasn't been compiled yet.
917 : return ReadOnlyRoots(isolate).false_value();
918 : }
919 : return ReadOnlyRoots(isolate).true_value();
920 : }
921 :
922 : namespace {
923 72 : bool DisallowCodegenFromStringsCallback(v8::Local<v8::Context> context,
924 : v8::Local<v8::String> source) {
925 72 : return false;
926 : }
927 : }
928 :
929 288 : RUNTIME_FUNCTION(Runtime_DisallowCodegenFromStrings) {
930 : SealHandleScope shs(isolate);
931 : DCHECK_EQ(1, args.length());
932 144 : CONVERT_BOOLEAN_ARG_CHECKED(flag, 0);
933 : v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
934 144 : v8_isolate->SetAllowCodeGenerationFromStringsCallback(
935 144 : flag ? DisallowCodegenFromStringsCallback : nullptr);
936 : return ReadOnlyRoots(isolate).undefined_value();
937 : }
938 :
939 272 : RUNTIME_FUNCTION(Runtime_DisallowWasmCodegen) {
940 : SealHandleScope shs(isolate);
941 : DCHECK_EQ(1, args.length());
942 136 : CONVERT_BOOLEAN_ARG_CHECKED(flag, 0);
943 : v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
944 136 : v8_isolate->SetAllowWasmCodeGenerationCallback(
945 136 : flag ? DisallowCodegenFromStringsCallback : nullptr);
946 : return ReadOnlyRoots(isolate).undefined_value();
947 : }
948 :
949 80 : RUNTIME_FUNCTION(Runtime_IsWasmCode) {
950 : SealHandleScope shs(isolate);
951 : DCHECK_EQ(1, args.length());
952 80 : CONVERT_ARG_CHECKED(JSFunction, function, 0);
953 80 : bool is_js_to_wasm = function->code()->kind() == Code::JS_TO_WASM_FUNCTION;
954 : return isolate->heap()->ToBoolean(is_js_to_wasm);
955 : }
956 :
957 16064 : RUNTIME_FUNCTION(Runtime_IsWasmTrapHandlerEnabled) {
958 : DisallowHeapAllocation no_gc;
959 : DCHECK_EQ(0, args.length());
960 : return isolate->heap()->ToBoolean(trap_handler::IsTrapHandlerEnabled());
961 : }
962 :
963 1616 : RUNTIME_FUNCTION(Runtime_IsThreadInWasm) {
964 : DisallowHeapAllocation no_gc;
965 : DCHECK_EQ(0, args.length());
966 : return isolate->heap()->ToBoolean(trap_handler::IsThreadInWasm());
967 : }
968 :
969 32064 : RUNTIME_FUNCTION(Runtime_GetWasmRecoveredTrapCount) {
970 : HandleScope scope(isolate);
971 : DCHECK_EQ(0, args.length());
972 16032 : size_t trap_count = trap_handler::GetRecoveredTrapCount();
973 32064 : return *isolate->factory()->NewNumberFromSize(trap_count);
974 : }
975 :
976 832 : RUNTIME_FUNCTION(Runtime_GetWasmExceptionId) {
977 : HandleScope scope(isolate);
978 : DCHECK_EQ(2, args.length());
979 416 : CONVERT_ARG_HANDLE_CHECKED(JSReceiver, exception, 0);
980 416 : CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 1);
981 : Handle<Object> tag =
982 416 : WasmExceptionPackage::GetExceptionTag(isolate, exception);
983 416 : if (tag->IsWasmExceptionTag()) {
984 : Handle<FixedArray> exceptions_table(instance->exceptions_table(), isolate);
985 576 : for (int index = 0; index < exceptions_table->length(); ++index) {
986 496 : if (exceptions_table->get(index) == *tag) return Smi::FromInt(index);
987 : }
988 : }
989 : return ReadOnlyRoots(isolate).undefined_value();
990 : }
991 :
992 800 : RUNTIME_FUNCTION(Runtime_GetWasmExceptionValues) {
993 : HandleScope scope(isolate);
994 : DCHECK_EQ(1, args.length());
995 400 : CONVERT_ARG_HANDLE_CHECKED(JSReceiver, exception, 0);
996 : Handle<Object> values_obj =
997 400 : WasmExceptionPackage::GetExceptionValues(isolate, exception);
998 400 : CHECK(values_obj->IsFixedArray()); // Only called with correct input.
999 400 : Handle<FixedArray> values = Handle<FixedArray>::cast(values_obj);
1000 : return *isolate->factory()->NewJSArrayWithElements(values);
1001 : }
1002 :
1003 : namespace {
1004 16 : bool EnableWasmThreads(v8::Local<v8::Context> context) { return true; }
1005 :
1006 16 : bool DisableWasmThreads(v8::Local<v8::Context> context) { return false; }
1007 : } // namespace
1008 :
1009 : // This runtime function enables WebAssembly threads through an embedder
1010 : // callback and thereby bypasses the value in FLAG_experimental_wasm_threads.
1011 48 : RUNTIME_FUNCTION(Runtime_SetWasmThreadsEnabled) {
1012 : DCHECK_EQ(1, args.length());
1013 24 : CONVERT_BOOLEAN_ARG_CHECKED(flag, 0);
1014 : v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
1015 24 : v8_isolate->SetWasmThreadsEnabledCallback(flag ? EnableWasmThreads
1016 24 : : DisableWasmThreads);
1017 : return ReadOnlyRoots(isolate).undefined_value();
1018 : }
1019 :
1020 : #define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
1021 : RUNTIME_FUNCTION(Runtime_Has##Name) { \
1022 : CONVERT_ARG_CHECKED(JSObject, obj, 0); \
1023 : return isolate->heap()->ToBoolean(obj->Has##Name()); \
1024 : }
1025 :
1026 252 : ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
1027 3608776 : ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(SmiElements)
1028 5409056 : ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ObjectElements)
1029 5400000 : ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(SmiOrObjectElements)
1030 5412188 : ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DoubleElements)
1031 19806760 : ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(HoleyElements)
1032 2452 : ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
1033 420 : ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(PackedElements)
1034 252 : ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(SloppyArgumentsElements)
1035 : // Properties test sitting with elements tests - not fooling anyone.
1036 34556 : ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastProperties)
1037 :
1038 : #undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
1039 :
1040 : #define FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype) \
1041 : RUNTIME_FUNCTION(Runtime_HasFixed##Type##Elements) { \
1042 : CONVERT_ARG_CHECKED(JSObject, obj, 0); \
1043 : return isolate->heap()->ToBoolean(obj->HasFixed##Type##Elements()); \
1044 : }
1045 :
1046 1800 : TYPED_ARRAYS(FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION)
1047 :
1048 : #undef FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION
1049 :
1050 344 : RUNTIME_FUNCTION(Runtime_ArraySpeciesProtector) {
1051 : SealHandleScope shs(isolate);
1052 : DCHECK_EQ(0, args.length());
1053 : return isolate->heap()->ToBoolean(isolate->IsArraySpeciesLookupChainIntact());
1054 : }
1055 :
1056 400 : RUNTIME_FUNCTION(Runtime_MapIteratorProtector) {
1057 : SealHandleScope shs(isolate);
1058 : DCHECK_EQ(0, args.length());
1059 : return isolate->heap()->ToBoolean(isolate->IsMapIteratorLookupChainIntact());
1060 : }
1061 :
1062 400 : RUNTIME_FUNCTION(Runtime_SetIteratorProtector) {
1063 : SealHandleScope shs(isolate);
1064 : DCHECK_EQ(0, args.length());
1065 : return isolate->heap()->ToBoolean(isolate->IsSetIteratorLookupChainIntact());
1066 : }
1067 :
1068 208 : RUNTIME_FUNCTION(Runtime_StringIteratorProtector) {
1069 : SealHandleScope shs(isolate);
1070 : DCHECK_EQ(0, args.length());
1071 : return isolate->heap()->ToBoolean(
1072 : isolate->IsStringIteratorLookupChainIntact());
1073 : }
1074 :
1075 : // Take a compiled wasm module and serialize it into an array buffer, which is
1076 : // then returned.
1077 336 : RUNTIME_FUNCTION(Runtime_SerializeWasmModule) {
1078 : HandleScope scope(isolate);
1079 : DCHECK_EQ(1, args.length());
1080 168 : CONVERT_ARG_HANDLE_CHECKED(WasmModuleObject, module_obj, 0);
1081 :
1082 168 : wasm::NativeModule* native_module = module_obj->native_module();
1083 336 : wasm::WasmSerializer wasm_serializer(native_module);
1084 168 : size_t compiled_size = wasm_serializer.GetSerializedNativeModuleSize();
1085 168 : void* array_data = isolate->array_buffer_allocator()->Allocate(compiled_size);
1086 : Handle<JSArrayBuffer> array_buffer =
1087 168 : isolate->factory()->NewJSArrayBuffer(SharedFlag::kNotShared);
1088 168 : JSArrayBuffer::Setup(array_buffer, isolate, false, array_data, compiled_size);
1089 336 : if (!array_data ||
1090 168 : !wasm_serializer.SerializeNativeModule(
1091 : {reinterpret_cast<uint8_t*>(array_data), compiled_size})) {
1092 : return ReadOnlyRoots(isolate).undefined_value();
1093 : }
1094 : return *array_buffer;
1095 : }
1096 :
1097 : // Take an array buffer and attempt to reconstruct a compiled wasm module.
1098 : // Return undefined if unsuccessful.
1099 352 : RUNTIME_FUNCTION(Runtime_DeserializeWasmModule) {
1100 : HandleScope scope(isolate);
1101 : DCHECK_EQ(2, args.length());
1102 176 : CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 0);
1103 176 : CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, wire_bytes, 1);
1104 176 : CHECK(!buffer->was_detached());
1105 176 : CHECK(!wire_bytes->WasDetached());
1106 :
1107 176 : Handle<JSArrayBuffer> wire_bytes_buffer = wire_bytes->GetBuffer();
1108 : Vector<const uint8_t> wire_bytes_vec{
1109 : reinterpret_cast<const uint8_t*>(wire_bytes_buffer->backing_store()) +
1110 : wire_bytes->byte_offset(),
1111 176 : wire_bytes->byte_length()};
1112 : Vector<uint8_t> buffer_vec{
1113 : reinterpret_cast<uint8_t*>(buffer->backing_store()),
1114 : buffer->byte_length()};
1115 :
1116 : // Note that {wasm::DeserializeNativeModule} will allocate. We assume the
1117 : // JSArrayBuffer backing store doesn't get relocated.
1118 : MaybeHandle<WasmModuleObject> maybe_module_object =
1119 176 : wasm::DeserializeNativeModule(isolate, buffer_vec, wire_bytes_vec);
1120 : Handle<WasmModuleObject> module_object;
1121 176 : if (!maybe_module_object.ToHandle(&module_object)) {
1122 : return ReadOnlyRoots(isolate).undefined_value();
1123 : }
1124 : return *module_object;
1125 : }
1126 :
1127 17658 : RUNTIME_FUNCTION(Runtime_HeapObjectVerify) {
1128 : HandleScope shs(isolate);
1129 : DCHECK_EQ(1, args.length());
1130 : CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
1131 : #ifdef VERIFY_HEAP
1132 : object->ObjectVerify(isolate);
1133 : #else
1134 : CHECK(object->IsObject());
1135 8829 : if (object->IsHeapObject()) {
1136 17604 : CHECK(HeapObject::cast(*object)->map()->IsMap());
1137 : } else {
1138 27 : CHECK(object->IsSmi());
1139 : }
1140 : #endif
1141 : return isolate->heap()->ToBoolean(true);
1142 : }
1143 :
1144 112 : RUNTIME_FUNCTION(Runtime_WasmGetNumberOfInstances) {
1145 : SealHandleScope shs(isolate);
1146 : DCHECK_EQ(1, args.length());
1147 56 : CONVERT_ARG_HANDLE_CHECKED(WasmModuleObject, module_obj, 0);
1148 : int instance_count = 0;
1149 56 : WeakArrayList weak_instance_list = module_obj->weak_instance_list();
1150 296 : for (int i = 0; i < weak_instance_list->length(); ++i) {
1151 240 : if (weak_instance_list->Get(i)->IsWeak()) instance_count++;
1152 : }
1153 : return Smi::FromInt(instance_count);
1154 : }
1155 :
1156 960 : RUNTIME_FUNCTION(Runtime_WasmNumInterpretedCalls) {
1157 : DCHECK_EQ(1, args.length());
1158 : HandleScope scope(isolate);
1159 480 : CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
1160 480 : if (!instance->has_debug_info()) return Object();
1161 280 : uint64_t num = instance->debug_info()->NumInterpretedCalls();
1162 560 : return *isolate->factory()->NewNumberFromSize(static_cast<size_t>(num));
1163 : }
1164 :
1165 208 : RUNTIME_FUNCTION(Runtime_RedirectToWasmInterpreter) {
1166 : DCHECK_EQ(2, args.length());
1167 : HandleScope scope(isolate);
1168 104 : CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
1169 208 : CONVERT_SMI_ARG_CHECKED(function_index, 1);
1170 : Handle<WasmDebugInfo> debug_info =
1171 104 : WasmInstanceObject::GetOrCreateDebugInfo(instance);
1172 208 : WasmDebugInfo::RedirectToInterpreter(debug_info,
1173 104 : Vector<int>(&function_index, 1));
1174 : return ReadOnlyRoots(isolate).undefined_value();
1175 : }
1176 :
1177 144 : RUNTIME_FUNCTION(Runtime_WasmTraceMemory) {
1178 : HandleScope scope(isolate);
1179 : DCHECK_EQ(1, args.length());
1180 72 : CONVERT_ARG_CHECKED(Smi, info_addr, 0);
1181 :
1182 : wasm::MemoryTracingInfo* info =
1183 72 : reinterpret_cast<wasm::MemoryTracingInfo*>(info_addr.ptr());
1184 :
1185 : // Find the caller wasm frame.
1186 144 : wasm::WasmCodeRefScope wasm_code_ref_scope;
1187 72 : StackTraceFrameIterator it(isolate);
1188 : DCHECK(!it.done());
1189 : DCHECK(it.is_wasm());
1190 : WasmCompiledFrame* frame = WasmCompiledFrame::cast(it.frame());
1191 :
1192 : uint8_t* mem_start = reinterpret_cast<uint8_t*>(
1193 144 : frame->wasm_instance()->memory_object()->array_buffer()->backing_store());
1194 72 : int func_index = frame->function_index();
1195 72 : int pos = frame->position();
1196 : // TODO(titzer): eliminate dependency on WasmModule definition here.
1197 : int func_start =
1198 72 : frame->wasm_instance()->module()->functions[func_index].code.offset();
1199 72 : wasm::ExecutionTier tier = frame->wasm_code()->is_liftoff()
1200 : ? wasm::ExecutionTier::kLiftoff
1201 72 : : wasm::ExecutionTier::kTurbofan;
1202 72 : wasm::TraceMemoryOperation(tier, info, func_index, pos - func_start,
1203 72 : mem_start);
1204 : return ReadOnlyRoots(isolate).undefined_value();
1205 : }
1206 :
1207 32 : RUNTIME_FUNCTION(Runtime_WasmTierUpFunction) {
1208 : HandleScope scope(isolate);
1209 : DCHECK_EQ(2, args.length());
1210 16 : CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
1211 16 : CONVERT_SMI_ARG_CHECKED(function_index, 1);
1212 16 : auto* native_module = instance->module_object()->native_module();
1213 16 : isolate->wasm_engine()->CompileFunction(
1214 16 : isolate, native_module, function_index, wasm::ExecutionTier::kTurbofan);
1215 16 : CHECK(!native_module->compilation_state()->failed());
1216 : return ReadOnlyRoots(isolate).undefined_value();
1217 : }
1218 :
1219 224 : RUNTIME_FUNCTION(Runtime_IsLiftoffFunction) {
1220 : HandleScope scope(isolate);
1221 : DCHECK_EQ(1, args.length());
1222 112 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
1223 112 : CHECK(WasmExportedFunction::IsWasmExportedFunction(*function));
1224 : Handle<WasmExportedFunction> exp_fun =
1225 : Handle<WasmExportedFunction>::cast(function);
1226 : wasm::NativeModule* native_module =
1227 224 : exp_fun->instance()->module_object()->native_module();
1228 112 : uint32_t func_index = exp_fun->function_index();
1229 224 : wasm::WasmCodeRefScope code_ref_scope;
1230 112 : wasm::WasmCode* code = native_module->GetCode(func_index);
1231 112 : return isolate->heap()->ToBoolean(code && code->is_liftoff());
1232 : }
1233 :
1234 36 : RUNTIME_FUNCTION(Runtime_CompleteInobjectSlackTracking) {
1235 : HandleScope scope(isolate);
1236 : DCHECK_EQ(1, args.length());
1237 :
1238 18 : CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
1239 18 : object->map()->CompleteInobjectSlackTracking(isolate);
1240 :
1241 : return ReadOnlyRoots(isolate).undefined_value();
1242 : }
1243 :
1244 96 : RUNTIME_FUNCTION(Runtime_FreezeWasmLazyCompilation) {
1245 : DCHECK_EQ(1, args.length());
1246 : DisallowHeapAllocation no_gc;
1247 48 : CONVERT_ARG_CHECKED(WasmInstanceObject, instance, 0);
1248 :
1249 96 : instance->module_object()->native_module()->set_lazy_compile_frozen(true);
1250 : return ReadOnlyRoots(isolate).undefined_value();
1251 : }
1252 :
1253 : } // namespace internal
1254 122036 : } // namespace v8
|