v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
runtime-wasm.cc
Go to the documentation of this file.
1// Copyright 2016 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 <optional>
6
12#include "src/debug/debug.h"
16#include "src/heap/factory.h"
23#include "src/wasm/value-type.h"
26#include "src/wasm/wasm-debug.h"
31#include "src/wasm/wasm-value.h"
32
33#if V8_ENABLE_WEBASSEMBLY && V8_ENABLE_DRUMBRAKE
35#endif // V8_ENABLE_WEBASSEMBLY && V8_ENABLE_DRUMBRAKE
36
37namespace v8::internal {
38
39// TODO(13036): See if we can find a way to have the stack walker visit
40// tagged values being passed from Wasm to runtime functions. In the meantime,
41// disallow access to safe-looking-but-actually-unsafe stack-backed handles
42// and thereby force manual creation of safe handles (backed by HandleScope).
44 public:
46 : RuntimeArguments(length, arguments) {}
47
48 private:
49 // Disallowing the superclass method.
50 template <class S = Object>
51 V8_INLINE DirectHandle<S> at(int index) const;
52};
53
54#define RuntimeArguments RuntimeArgumentsWithoutHandles
55
56// (End of TODO(13036)-related hackery.)
57
58namespace {
59
60template <typename FrameType>
61class FrameFinder {
62 public:
63 explicit FrameFinder(Isolate* isolate,
64 std::initializer_list<StackFrame::Type>
65 skipped_frame_types = {StackFrame::EXIT})
66 : frame_iterator_(isolate, isolate->thread_local_top(),
67 StackFrameIterator::FirstStackOnly{}) {
68 // We skip at least one frame.
69 DCHECK_LT(0, skipped_frame_types.size());
70
71 for (auto type : skipped_frame_types) {
72 DCHECK_EQ(type, frame_iterator_.frame()->type());
73 USE(type);
74 frame_iterator_.Advance();
75 }
76 // Type check the frame where the iterator stopped now.
77 DCHECK_NOT_NULL(frame());
78 }
79
80 FrameType* frame() { return FrameType::cast(frame_iterator_.frame()); }
81
82 private:
83 StackFrameIterator frame_iterator_;
84};
85
86Tagged<WasmTrustedInstanceData> GetWasmInstanceDataOnStackTop(
87 Isolate* isolate) {
88 Address fp = Isolate::c_entry_fp(isolate->thread_local_top());
89 fp = Memory<Address>(fp + ExitFrameConstants::kCallerFPOffset);
90#ifdef DEBUG
91 intptr_t marker =
93 DCHECK(StackFrame::MarkerToType(marker) == StackFrame::WASM ||
94 StackFrame::MarkerToType(marker) == StackFrame::WASM_SEGMENT_START);
95#endif
96 Tagged<Object> trusted_instance_data(
97 Memory<Address>(fp + WasmFrameConstants::kWasmInstanceDataOffset));
98 return Cast<WasmTrustedInstanceData>(trusted_instance_data);
99}
100
101Tagged<Context> GetNativeContextFromWasmInstanceOnStackTop(Isolate* isolate) {
102 return GetWasmInstanceDataOnStackTop(isolate)->native_context();
103}
104
105// TODO(jkummerow): Merge this with {SaveAndClearThreadInWasmFlag} from
106// runtime-utils.h.
107class V8_NODISCARD ClearThreadInWasmScope {
108 public:
109 explicit ClearThreadInWasmScope(Isolate* isolate)
110 : isolate_(isolate), is_thread_in_wasm_(trap_handler::IsThreadInWasm()) {
111 // In some cases we call this from Wasm code inlined into JavaScript
112 // so the flag might not be set.
113 if (is_thread_in_wasm_) {
114 trap_handler::ClearThreadInWasm();
115 }
116
117#if V8_ENABLE_DRUMBRAKE
118 if (v8_flags.wasm_enable_exec_time_histograms && v8_flags.slow_histograms &&
119 !v8_flags.wasm_jitless) {
120 isolate->wasm_execution_timer()->Stop();
121 }
122#endif // V8_ENABLE_DRUMBRAKE
123 }
124 ~ClearThreadInWasmScope() {
125 trap_handler::AssertThreadNotInWasm();
126 if (!isolate_->has_exception() && is_thread_in_wasm_) {
127 trap_handler::SetThreadInWasm();
128
129#if V8_ENABLE_DRUMBRAKE
130 if (v8_flags.wasm_enable_exec_time_histograms &&
131 v8_flags.slow_histograms && !v8_flags.wasm_jitless) {
132 isolate_->wasm_execution_timer()->Start();
133 }
134#endif // V8_ENABLE_DRUMBRAKE
135 }
136 // Otherwise we only want to set the flag if the exception is caught in
137 // wasm. This is handled by the unwinder.
138 }
139
140 private:
141 Isolate* isolate_;
143};
144
145Tagged<Object> ThrowWasmError(
146 Isolate* isolate, MessageTemplate message,
147 std::initializer_list<DirectHandle<Object>> args = {}) {
148#if V8_ENABLE_DRUMBRAKE
149 if (v8_flags.wasm_jitless) {
150 // Store the trap reason to be retrieved later when the interpreter will
151 // trap while detecting the thrown exception.
153 }
154#endif // V8_ENABLE_DRUMBRAKE
155
156 DirectHandle<JSObject> error_obj =
157 isolate->factory()->NewWasmRuntimeError(message, base::VectorOf(args));
158 JSObject::AddProperty(isolate, error_obj,
159 isolate->factory()->wasm_uncatchable_symbol(),
160 isolate->factory()->true_value(), NONE);
161 return isolate->Throw(*error_obj);
162}
163
164Tagged<Object> ThrowWasmSuspendError(Isolate* isolate,
165 MessageTemplate message) {
166 DirectHandle<JSObject> error_obj =
167 isolate->factory()->NewWasmSuspendError(message);
168 return isolate->Throw(*error_obj);
169}
170} // namespace
171
172RUNTIME_FUNCTION(Runtime_WasmGenericWasmToJSObject) {
173 SealHandleScope seal_handle_scope(isolate);
174 DCHECK_EQ(1, args.length());
175 Tagged<Object> value = args[0];
176 if (IsWasmFuncRef(value)) {
178 Cast<WasmFuncRef>(value)->internal(isolate);
179 Tagged<JSFunction> external;
180 if (internal->try_get_external(&external)) return external;
181 // Slow path:
182 HandleScope handle_scope(isolate);
184 direct_handle(internal, isolate));
185 }
186 if (IsWasmNull(value)) return ReadOnlyRoots(isolate).null_value();
187 return value;
188}
189
190// Takes a JS object and a wasm type as Smi. Type checks the object against the
191// type; if the check succeeds, returns the object in its wasm representation;
192// otherwise throws a type error.
193RUNTIME_FUNCTION(Runtime_WasmGenericJSToWasmObject) {
194 HandleScope scope(isolate);
195 DCHECK_EQ(2, args.length());
196 DirectHandle<Object> value(args[0], isolate);
197 // Make sure CanonicalValueType fits properly in a Smi.
199 int raw_type = args.smi_value_at(1);
200
203 const char* error_message;
205 if (!JSToWasmObject(isolate, value, type, &error_message).ToHandle(&result)) {
206 return isolate->Throw(*isolate->factory()->NewTypeError(
207 MessageTemplate::kWasmTrapJSTypeError));
208 }
209 return *result;
210}
211
212// Parameters:
213// args[0]: the object, any JS value.
214// args[1]: the expected canonicalized ValueType, Smi-tagged.
215// Type checks the object against the type; if the check succeeds, returns the
216// object in its wasm representation; otherwise throws a type error.
217RUNTIME_FUNCTION(Runtime_WasmJSToWasmObject) {
218 SaveAndClearThreadInWasmFlag non_wasm_scope(isolate);
219 HandleScope scope(isolate);
220 DCHECK_EQ(2, args.length());
221 DirectHandle<Object> value(args[0], isolate);
222 // Make sure ValueType fits properly in a Smi.
224 int raw_type = args.smi_value_at(1);
225
226 wasm::CanonicalValueType expected =
228 const char* error_message;
230 bool success = JSToWasmObject(isolate, value, expected, &error_message)
231 .ToHandle(&result);
232 Tagged<Object> ret = success
233 ? *result
234 : isolate->Throw(*isolate->factory()->NewTypeError(
235 MessageTemplate::kWasmTrapJSTypeError));
236 return ret;
237}
238
239RUNTIME_FUNCTION(Runtime_WasmMemoryGrow) {
240 ClearThreadInWasmScope flag_scope(isolate);
241 HandleScope scope(isolate);
242 DCHECK_EQ(3, args.length());
243 Tagged<WasmTrustedInstanceData> trusted_instance_data =
245 // {memory_index} and {delta_pages} are checked to be positive Smis in the
246 // WasmMemoryGrow builtin which calls this runtime function.
247 uint32_t memory_index = args.positive_smi_value_at(1);
248 uint32_t delta_pages = args.positive_smi_value_at(2);
249
250 DirectHandle<WasmMemoryObject> memory_object{
251 trusted_instance_data->memory_object(memory_index), isolate};
252 int ret = WasmMemoryObject::Grow(isolate, memory_object, delta_pages);
253 // The WasmMemoryGrow builtin which calls this runtime function expects us to
254 // always return a Smi.
255 DCHECK(!isolate->has_exception());
256 return Smi::FromInt(ret);
257}
258
259RUNTIME_FUNCTION(Runtime_TrapHandlerThrowWasmError) {
260 ClearThreadInWasmScope flag_scope(isolate);
261 CHECK(isolate->IsOnCentralStack());
262 HandleScope scope(isolate);
263 FrameFinder<WasmFrame> frame_finder(isolate, {StackFrame::EXIT});
264 WasmFrame* frame = frame_finder.frame();
265 // TODO(ahaas): We cannot use frame->position() here because for inlined
266 // function it does not return the correct source position. We should remove
267 // frame->position() to avoid problems in the future.
268 FrameSummaries summaries = frame->Summarize();
269 DCHECK(summaries.frames.back().IsWasm());
270 int pos = summaries.frames.back().AsWasm().SourcePosition();
271
272 wasm::WasmCodeRefScope code_ref_scope;
273 auto wire_bytes = frame->wasm_code()->native_module()->wire_bytes();
274 wasm::WasmOpcode op = static_cast<wasm::WasmOpcode>(wire_bytes.at(pos));
275 MessageTemplate message = MessageTemplate::kWasmTrapMemOutOfBounds;
276 if (op == wasm::kGCPrefix || op == wasm::kExprRefAsNonNull ||
277 op == wasm::kExprCallRef || op == wasm::kExprReturnCallRef ||
278 // Calling imported string function with null can trigger a signal.
279 op == wasm::kExprCallFunction || op == wasm::kExprReturnCall) {
280 message = MessageTemplate::kWasmTrapNullDereference;
281#if DEBUG
282 } else {
284 op = wasm::Decoder{wire_bytes}
286 &wire_bytes.begin()[pos])
287 .first;
288 }
289#endif // DEBUG
290 }
291 return ThrowWasmError(isolate, message);
292}
293
294RUNTIME_FUNCTION(Runtime_ThrowWasmError) {
295 ClearThreadInWasmScope flag_scope(isolate);
296 DCHECK(isolate->IsOnCentralStack());
297 HandleScope scope(isolate);
298 DCHECK_EQ(1, args.length());
299 int message_id = args.smi_value_at(0);
300 return ThrowWasmError(isolate, MessageTemplateFromInt(message_id));
301}
302
303RUNTIME_FUNCTION(Runtime_ThrowWasmStackOverflow) {
304 ClearThreadInWasmScope clear_wasm_flag(isolate);
305 SealHandleScope shs(isolate);
306 DCHECK_LE(0, args.length());
307 return isolate->StackOverflow();
308}
309
310RUNTIME_FUNCTION(Runtime_WasmThrowJSTypeError) {
311 // The caller may be wasm or JS. Only clear the thread_in_wasm flag if the
312 // caller is wasm, and let the unwinder set it back depending on the handler.
314#if V8_ENABLE_DRUMBRAKE
315 // Transitioning from Wasm To JS.
316 if (v8_flags.wasm_enable_exec_time_histograms && v8_flags.slow_histograms &&
317 !v8_flags.wasm_jitless) {
318 // Stop measuring the time spent running jitted Wasm.
319 isolate->wasm_execution_timer()->Stop();
320 }
321#endif // V8_ENABLE_DRUMBRAKE
322
324 }
325 HandleScope scope(isolate);
326 DCHECK_EQ(0, args.length());
328 isolate, NewTypeError(MessageTemplate::kWasmTrapJSTypeError));
329}
330
331RUNTIME_FUNCTION(Runtime_ThrowWasmSuspendError) {
332 HandleScope scope(isolate);
333 DCHECK_EQ(1, args.length());
334
335 MessageTemplate message_id = MessageTemplateFromInt(args.smi_value_at(0));
336
337 return ThrowWasmSuspendError(isolate, message_id);
338}
339
340RUNTIME_FUNCTION(Runtime_WasmThrowRangeError) {
341 ClearThreadInWasmScope clear_wasm_flag(isolate);
342 HandleScope scope(isolate);
343 DCHECK_EQ(1, args.length());
344 MessageTemplate message_id = MessageTemplateFromInt(args.smi_value_at(0));
345 THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewRangeError(message_id));
346}
347
348RUNTIME_FUNCTION(Runtime_WasmThrowDataViewTypeError) {
349 ClearThreadInWasmScope clear_wasm_flag(isolate);
350 HandleScope scope(isolate);
351 DCHECK_EQ(2, args.length());
352 MessageTemplate message_id = MessageTemplateFromInt(args.smi_value_at(0));
353 DataViewOp op = static_cast<DataViewOp>(isolate->error_message_param());
354 DirectHandle<String> op_name =
355 isolate->factory()->NewStringFromAsciiChecked(ToString(op));
356 DirectHandle<Object> value(args[1], isolate);
357
359 NewTypeError(message_id, op_name, value));
360}
361
362RUNTIME_FUNCTION(Runtime_WasmThrowDataViewDetachedError) {
363 ClearThreadInWasmScope clear_wasm_flag(isolate);
364 HandleScope scope(isolate);
365 DCHECK_EQ(1, args.length());
366 MessageTemplate message_id = MessageTemplateFromInt(args.smi_value_at(0));
367 DataViewOp op = static_cast<DataViewOp>(isolate->error_message_param());
368 DirectHandle<String> op_name =
369 isolate->factory()->NewStringFromAsciiChecked(ToString(op));
370
371 THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(message_id, op_name));
372}
373
374RUNTIME_FUNCTION(Runtime_WasmThrowTypeError) {
375 ClearThreadInWasmScope clear_wasm_flag(isolate);
376 HandleScope scope(isolate);
377 DCHECK_EQ(2, args.length());
378 MessageTemplate message_id = MessageTemplateFromInt(args.smi_value_at(0));
379 DirectHandle<Object> arg(args[1], isolate);
380 if (IsSmi(*arg)) {
381 THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(message_id));
382 } else {
383 THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(message_id, arg));
384 }
385}
386
387RUNTIME_FUNCTION(Runtime_WasmThrow) {
388 ClearThreadInWasmScope clear_wasm_flag(isolate);
389 HandleScope scope(isolate);
390 DCHECK_EQ(2, args.length());
391 Tagged<Context> context = GetNativeContextFromWasmInstanceOnStackTop(isolate);
392 isolate->set_context(context);
395 auto js_tag = Cast<WasmTagObject>(context->wasm_js_tag());
396 if (*tag == js_tag->tag()) {
397 return isolate->Throw(values->get(0));
398 } else {
400 WasmExceptionPackage::New(isolate, tag, values);
401 return isolate->Throw(*exception);
402 }
403}
404
405RUNTIME_FUNCTION(Runtime_WasmReThrow) {
406 ClearThreadInWasmScope clear_wasm_flag(isolate);
407 HandleScope scope(isolate);
408 DCHECK_EQ(1, args.length());
409 return isolate->ReThrow(args[0]);
410}
411
412RUNTIME_FUNCTION(Runtime_WasmStackGuard) {
413 ClearThreadInWasmScope wasm_flag(isolate);
414 SealHandleScope shs(isolate);
415 DCHECK_EQ(1, args.length());
416
417 uint32_t gap = args.positive_smi_value_at(0);
418
419 // Check if this is a real stack overflow.
420 StackLimitCheck check(isolate);
421 if (check.WasmHasOverflowed(gap)) return isolate->StackOverflow();
422
423 return isolate->stack_guard()->HandleInterrupts(
425}
426
427RUNTIME_FUNCTION(Runtime_WasmCompileLazy) {
428 ClearThreadInWasmScope wasm_flag(isolate);
429 DCHECK_EQ(2, args.length());
430 Tagged<WasmTrustedInstanceData> trusted_instance_data =
432 int func_index = args.smi_value_at(1);
433
434 TRACE_EVENT1("v8.wasm", "wasm.CompileLazy", "func_index", func_index);
436 SealHandleScope scope(isolate);
437
438 DCHECK(isolate->context().is_null());
439 isolate->set_context(trusted_instance_data->native_context());
440 bool success = wasm::CompileLazy(isolate, trusted_instance_data, func_index);
441 if (!success) {
442 DCHECK(v8_flags.wasm_lazy_validation);
443 AllowHeapAllocation throwing_unwinds_the_stack;
445 isolate, trusted_instance_data->native_module(), func_index);
446 DCHECK(isolate->has_exception());
447 return ReadOnlyRoots{isolate}.exception();
448 }
449
450 return Smi::FromInt(
451 wasm::JumpTableOffset(trusted_instance_data->module(), func_index));
452}
453
454namespace {
455Tagged<FixedArray> AllocateFeedbackVector(
456 Isolate* isolate,
457 DirectHandle<WasmTrustedInstanceData> trusted_instance_data,
458 int declared_func_index) {
459 DCHECK(isolate->context().is_null());
460 isolate->set_context(trusted_instance_data->native_context());
461 const wasm::WasmModule* module =
462 trusted_instance_data->native_module()->module();
463
464 int func_index = declared_func_index + module->num_imported_functions;
465 int num_slots = NumFeedbackSlots(module, func_index);
466 DirectHandle<FixedArray> vector =
467 isolate->factory()->NewFixedArrayWithZeroes(num_slots);
468 DCHECK_EQ(trusted_instance_data->feedback_vectors()->get(declared_func_index),
469 Smi::zero());
470 trusted_instance_data->feedback_vectors()->set(declared_func_index, *vector);
471 isolate->set_context(Tagged<Context>());
472 return *vector;
473}
474} // namespace
475
476RUNTIME_FUNCTION(Runtime_WasmAllocateFeedbackVector) {
477 ClearThreadInWasmScope wasm_flag(isolate);
478 DCHECK(isolate->IsOnCentralStack());
479 HandleScope scope(isolate);
480 DCHECK_EQ(3, args.length());
481 DCHECK(v8_flags.wasm_inlining);
482 DirectHandle<WasmTrustedInstanceData> trusted_instance_data(
484 int declared_func_index = args.smi_value_at(1);
485 wasm::NativeModule** native_module_stack_slot =
486 reinterpret_cast<wasm::NativeModule**>(args.address_of_arg_at(2));
487 wasm::NativeModule* native_module = trusted_instance_data->native_module();
488 // We have to save the native_module on the stack, in case the allocation
489 // triggers a GC and we need the module to scan LiftoffSetupFrame stack frame.
490 *native_module_stack_slot = native_module;
491 return AllocateFeedbackVector(isolate, trusted_instance_data,
492 declared_func_index);
493}
494
495RUNTIME_FUNCTION(Runtime_WasmLiftoffDeoptFinish) {
496 ClearThreadInWasmScope wasm_flag(isolate);
497 HandleScope scope(isolate);
498 DCHECK_EQ(1, args.length());
499 DirectHandle<WasmTrustedInstanceData> trusted_instance_data(
501 // Destroy the Deoptimizer object stored on the isolate.
502 size_t deopt_frame_count = Deoptimizer::DeleteForWasm(isolate);
503 size_t i = 0;
504
505 // For each liftoff frame, check if the feedback vector is already present.
506 // If it is not, allocate a new feedback vector for it.
507 for (StackFrameIterator it(isolate); !it.done(); it.Advance()) {
508 StackFrame* frame = it.frame();
509 if (frame->is_wasm() && WasmFrame::cast(frame)->wasm_code()->is_liftoff()) {
510 Address vector_address =
512 Tagged<Object> vector_or_smi(Memory<intptr_t>(vector_address));
513 if (vector_or_smi.IsSmi()) {
514 int declared_func_index = Cast<Smi>(vector_or_smi).value();
515 Tagged<Object> vector =
516 trusted_instance_data->feedback_vectors()->get(declared_func_index);
517 // The vector can already exist if the same function appears multiple
518 // times in the deopted frames (i.e. it was inlined recursively).
519 if (vector == Smi::zero()) {
520 vector = AllocateFeedbackVector(isolate, trusted_instance_data,
521 declared_func_index);
522 }
523 memcpy(reinterpret_cast<void*>(vector_address), &vector,
524 sizeof(intptr_t));
525 }
526 if (++i == deopt_frame_count) {
527 break; // All deopt frames have been visited.
528 }
529 }
530 }
531 return ReadOnlyRoots(isolate).undefined_value();
532}
533
534namespace {
535void ReplaceJSToWasmWrapper(
536 Isolate* isolate, Tagged<WasmTrustedInstanceData> trusted_instance_data,
537 int function_index, Tagged<Code> wrapper_code) {
538 Tagged<WasmFuncRef> func_ref;
539 // Always expect a func_ref. If this fails, we are maybe compiling a wrapper
540 // for the start function. This function is only called once, so this should
541 // not happen.
542 CHECK(trusted_instance_data->try_get_func_ref(function_index, &func_ref));
543 Tagged<JSFunction> external_function;
544 CHECK(func_ref->internal(isolate)->try_get_external(&external_function));
545 if (external_function->shared()->HasWasmJSFunctionData()) return;
546 CHECK(external_function->shared()->HasWasmExportedFunctionData());
547 external_function->UpdateCode(wrapper_code);
549 external_function->shared()->wasm_exported_function_data();
550 function_data->set_wrapper_code(wrapper_code);
551}
552} // namespace
553
554RUNTIME_FUNCTION(Runtime_TierUpJSToWasmWrapper) {
555 DCHECK_EQ(1, args.length());
556
557 // Avoid allocating a HandleScope and handles on the fast path.
560 Tagged<WasmTrustedInstanceData> trusted_data = function_data->instance_data();
561
562 const wasm::WasmModule* module = trusted_data->module();
563 const int function_index = function_data->function_index();
564 const wasm::WasmFunction& function = module->functions[function_index];
565 const wasm::CanonicalTypeIndex sig_id =
566 module->canonical_sig_id(function.sig_index);
567 const wasm::CanonicalSig* sig =
569
570 Tagged<MaybeObject> maybe_cached_wrapper =
571 isolate->heap()->js_to_wasm_wrappers()->get(sig_id.index);
572 Tagged<Code> wrapper_code;
573 DCHECK(maybe_cached_wrapper.IsWeakOrCleared());
574 if (!maybe_cached_wrapper.IsCleared()) {
575 wrapper_code =
576 Cast<CodeWrapper>(maybe_cached_wrapper.GetHeapObjectAssumeWeak())
577 ->code(isolate);
578 } else {
579 // Set the context on the isolate and open a handle scope for allocation of
580 // new objects. Wrap {trusted_data} in a handle so it survives GCs.
581 DCHECK(isolate->context().is_null());
582 isolate->set_context(trusted_data->native_context());
583 HandleScope scope(isolate);
585 isolate};
586 DirectHandle<Code> new_wrapper_code =
588 isolate, sig, sig_id);
589
590 // Compilation must have installed the wrapper into the cache.
591 DCHECK_EQ(MakeWeak(new_wrapper_code->wrapper()),
592 isolate->heap()->js_to_wasm_wrappers()->get(sig_id.index));
593
594 // Reset raw pointers still needed outside the slow path.
595 wrapper_code = *new_wrapper_code;
596 trusted_data = *trusted_data_handle;
597 function_data = {};
598 }
599
600 // Replace the wrapper for the function that triggered the tier-up.
601 // This is to ensure that the wrapper is replaced, even if the function
602 // is implicitly exported and is not part of the export_table.
603 ReplaceJSToWasmWrapper(isolate, trusted_data, function_index, wrapper_code);
604
605 // Iterate over all exports to replace eagerly the wrapper for all functions
606 // that share the signature of the function that tiered up.
607 for (wasm::WasmExport exp : module->export_table) {
608 if (exp.kind != wasm::kExternalFunction) continue;
609 int index = static_cast<int>(exp.index);
610 if (index == function_index) continue; // Already replaced.
611 const wasm::WasmFunction& exp_function = module->functions[index];
612 if (module->canonical_sig_id(exp_function.sig_index) != sig_id) {
613 continue; // Different signature.
614 }
615 ReplaceJSToWasmWrapper(isolate, trusted_data, index, wrapper_code);
616 }
617
618 return ReadOnlyRoots(isolate).undefined_value();
619}
620
621RUNTIME_FUNCTION(Runtime_IsWasmExternalFunction) {
622 DCHECK_EQ(1, args.length());
623 return isolate->heap()->ToBoolean(
625}
626
627RUNTIME_FUNCTION(Runtime_TierUpWasmToJSWrapper) {
628 HandleScope scope(isolate);
629 DCHECK_EQ(1, args.length());
631 isolate);
632
633 DCHECK(isolate->context().is_null());
634 isolate->set_context(import_data->native_context());
635
636 const wasm::CanonicalSig* sig = import_data->sig();
637 DirectHandle<Object> origin(import_data->call_origin(), isolate);
638 wasm::WasmCodeRefScope code_ref_scope;
639
640 if (IsWasmInternalFunction(*origin)) {
641 // The tierup for `WasmInternalFunction` is special, as there may not be an
642 // instance.
643 size_t expected_arity = sig->parameter_count();
645 if (IsJSFunction(import_data->callable())) {
647 Cast<JSFunction>(import_data->callable())->shared();
648 expected_arity =
649 shared->internal_formal_parameter_count_without_receiver();
650 if (expected_arity == sig->parameter_count()) {
652 } else {
654 }
655 } else {
657 }
659 wasm::CanonicalTypeIndex canonical_sig_index =
661 int arity = static_cast<int>(expected_arity);
662 wasm::Suspend suspend = import_data->suspend();
663 wasm::WasmCode* wrapper =
664 cache->MaybeGet(kind, canonical_sig_index, arity, suspend);
665 bool source_positions = false;
666 if (!wrapper) {
667 wrapper = cache->CompileWasmImportCallWrapper(
668 isolate, kind, sig, canonical_sig_index, source_positions, arity,
669 suspend);
670 }
672
673 Tagged<JSFunction> existing_external;
675 if (internal->try_get_external(&existing_external)) {
676 Tagged<Object> func_data = existing_external->shared()->GetTrustedData();
677 // WasmJSFunctions set their external function at creation.
678 if (IsWasmJSFunctionData(func_data)) {
679 WasmCodePointer code_pointer = Cast<WasmJSFunctionData>(func_data)
680 ->offheap_data()
681 ->set_compiled_wrapper(wrapper);
682 USE(code_pointer);
683 // We're reusing the CPT entries for the wrapper, so the call target
684 // should stay the same.
685 DCHECK_EQ(code_pointer, internal->call_target());
686 return ReadOnlyRoots(isolate).undefined_value();
687 }
688 // Other functions could have had their external JSFunction created
689 // lazily before.
690 DCHECK(IsWasmExportedFunctionData(func_data));
692 Cast<WasmExportedFunctionData>(func_data)->instance_data();
693 // Fall through.
694 } else {
695 // We're tiering up a WasmToJS wrapper, so the function must be an
696 // imported JS function.
697 DCHECK(IsWasmImportData(internal->implicit_arg()));
699 Cast<WasmImportData>(internal->implicit_arg())->instance_data();
700 }
701 // For imported JS functions, we don't really care about updating the call
702 // target in the table, but we do need the table to manage the lifetime
703 // of the wrapper we just compiled.
705 instance_data->dispatch_table_for_imports();
706 // We're reusing the CPT entries for the wrapper, so the call target should
707 // stay the same.
708 DCHECK_EQ(internal->call_target(),
709 table->offheap_data()->WrapperCodePointerForDebugging(
710 internal->function_index()));
711 table->InstallCompiledWrapper(internal->function_index(), wrapper);
712 return ReadOnlyRoots(isolate).undefined_value();
713 }
714
715 CHECK(IsWasmDispatchTable(*origin));
716 DirectHandle<WasmDispatchTable> dispatch_table =
718 int table_slot = import_data->table_slot();
719 wasm::CanonicalTypeIndex sig_index = dispatch_table->sig(table_slot);
721 wasm::GetTypeCanonicalizer()->LookupFunctionSignature(sig_index));
722
723 // Compile a wrapper for the target callable.
724 DirectHandle<JSReceiver> callable(Cast<JSReceiver>(import_data->callable()),
725 isolate);
726 wasm::Suspend suspend = import_data->suspend();
727
728 wasm::ResolvedWasmImport resolved({}, -1, callable, sig, sig_index,
730 wasm::ImportCallKind kind = resolved.kind();
731 callable = resolved.callable(); // Update to ultimate target.
733 // {expected_arity} should only be used if kind != kJSFunctionArityMismatch.
734 int expected_arity = static_cast<int>(sig->parameter_count());
735 if (kind == wasm::ImportCallKind ::kJSFunctionArityMismatch) {
736 expected_arity = Cast<JSFunction>(callable)
737 ->shared()
738 ->internal_formal_parameter_count_without_receiver();
739 }
740
742 wasm::WasmCode* wasm_code =
743 cache->MaybeGet(kind, sig_index, expected_arity, suspend);
744 if (!wasm_code) {
745 wasm_code = cache->CompileWasmImportCallWrapper(
746 isolate, kind, sig, sig_index, false, expected_arity, suspend);
747 }
748 // Note: we don't need to decrement any refcounts here, because tier-up
749 // doesn't overwrite an existing compiled wrapper, and the generic wrapper
750 // isn't refcounted.
751 dispatch_table->InstallCompiledWrapper(table_slot, wasm_code);
752
753 return ReadOnlyRoots(isolate).undefined_value();
754}
755
756RUNTIME_FUNCTION(Runtime_WasmTriggerTierUp) {
757 ClearThreadInWasmScope clear_wasm_flag(isolate);
758 SealHandleScope shs(isolate);
759
760 {
762 DCHECK_EQ(1, args.length());
765
766 FrameFinder<WasmFrame> frame_finder(isolate);
767 int func_index = frame_finder.frame()->function_index();
768 DCHECK_EQ(trusted_data, frame_finder.frame()->trusted_instance_data());
769
770 if (V8_UNLIKELY(v8_flags.wasm_sync_tier_up)) {
771 if (!trusted_data->native_module()->HasCodeWithTier(
772 func_index, wasm::ExecutionTier::kTurbofan)) {
773 wasm::TierUpNowForTesting(isolate, trusted_data, func_index);
774 }
775 // We call this function when the tiering budget runs out, so reset that
776 // budget to appropriately delay the next call.
777 int array_index =
778 wasm::declared_function_index(trusted_data->module(), func_index);
779 trusted_data->tiering_budget_array()[array_index].store(
780 v8_flags.wasm_tiering_budget, std::memory_order_relaxed);
781 } else {
782 wasm::TriggerTierUp(isolate, trusted_data, func_index);
783 }
784 }
785
786 // We're reusing this interrupt mechanism to interrupt long-running loops.
787 StackLimitCheck check(isolate);
788 // We don't need to handle stack overflows here, because the function that
789 // performed this runtime call did its own stack check at its beginning.
790 // However, we can't DCHECK(!check.JsHasOverflowed()) here, because the
791 // additional stack space used by the CEntryStub and this runtime function
792 // itself might have pushed us above the limit where a stack check would
793 // fail.
794 if (check.InterruptRequested()) {
795 // Note: This might trigger a GC, which invalidates the {args} object (see
796 // https://crbug.com/v8/13036#2).
797 Tagged<Object> result = isolate->stack_guard()->HandleInterrupts();
798 if (IsException(result)) return result;
799 }
800
801 return ReadOnlyRoots(isolate).undefined_value();
802}
803
804RUNTIME_FUNCTION(Runtime_WasmI32AtomicWait) {
805 ClearThreadInWasmScope clear_wasm_flag(isolate);
806 HandleScope scope(isolate);
807 DCHECK_EQ(5, args.length());
808 Tagged<WasmTrustedInstanceData> trusted_instance_data =
810 int memory_index = args.smi_value_at(1);
811 double offset_double = args.number_value_at(2);
812 uintptr_t offset = static_cast<uintptr_t>(offset_double);
813 int32_t expected_value = NumberToInt32(args[3]);
814 Tagged<BigInt> timeout_ns = Cast<BigInt>(args[4]);
815
816 DirectHandle<JSArrayBuffer> array_buffer{
817 trusted_instance_data->memory_object(memory_index)->array_buffer(),
818 isolate};
819 // Should have trapped if address was OOB.
820 DCHECK_LT(offset, array_buffer->byte_length());
821
822 // Trap if memory is not shared, or wait is not allowed on the isolate
823 if (!array_buffer->is_shared() || !isolate->allow_atomics_wait()) {
824 return ThrowWasmError(
825 isolate, MessageTemplate::kAtomicsOperationNotAllowed,
826 {isolate->factory()->NewStringFromAsciiChecked("Atomics.wait")});
827 }
828 return FutexEmulation::WaitWasm32(isolate, array_buffer, offset,
829 expected_value, timeout_ns->AsInt64());
830}
831
832RUNTIME_FUNCTION(Runtime_WasmI64AtomicWait) {
833 ClearThreadInWasmScope clear_wasm_flag(isolate);
834 HandleScope scope(isolate);
835 DCHECK_EQ(5, args.length());
836 Tagged<WasmTrustedInstanceData> trusted_instance_data =
838 int memory_index = args.smi_value_at(1);
839 double offset_double = args.number_value_at(2);
840 uintptr_t offset = static_cast<uintptr_t>(offset_double);
841 Tagged<BigInt> expected_value = Cast<BigInt>(args[3]);
842 Tagged<BigInt> timeout_ns = Cast<BigInt>(args[4]);
843
844 DirectHandle<JSArrayBuffer> array_buffer{
845 trusted_instance_data->memory_object(memory_index)->array_buffer(),
846 isolate};
847 // Should have trapped if address was OOB.
848 DCHECK_LT(offset, array_buffer->byte_length());
849
850 // Trap if memory is not shared, or if wait is not allowed on the isolate
851 if (!array_buffer->is_shared() || !isolate->allow_atomics_wait()) {
852 return ThrowWasmError(
853 isolate, MessageTemplate::kAtomicsOperationNotAllowed,
854 {isolate->factory()->NewStringFromAsciiChecked("Atomics.wait")});
855 }
856 return FutexEmulation::WaitWasm64(isolate, array_buffer, offset,
857 expected_value->AsInt64(),
858 timeout_ns->AsInt64());
859}
860
861namespace {
862Tagged<Object> ThrowTableOutOfBounds(
863 Isolate* isolate,
864 DirectHandle<WasmTrustedInstanceData> trusted_instance_data) {
865 // Handle out-of-bounds access here in the runtime call, rather
866 // than having the lower-level layers deal with JS exceptions.
867 if (isolate->context().is_null()) {
868 isolate->set_context(trusted_instance_data->native_context());
869 }
870 return ThrowWasmError(isolate, MessageTemplate::kWasmTrapTableOutOfBounds);
871}
872} // namespace
873
874RUNTIME_FUNCTION(Runtime_WasmRefFunc) {
875 ClearThreadInWasmScope flag_scope(isolate);
876 HandleScope scope(isolate);
877 DCHECK_EQ(2, args.length());
878 DirectHandle<WasmTrustedInstanceData> trusted_instance_data(
880 uint32_t function_index = args.positive_smi_value_at(1);
881
883 isolate, trusted_instance_data, function_index);
884}
885
886RUNTIME_FUNCTION(Runtime_WasmInternalFunctionCreateExternal) {
887 ClearThreadInWasmScope flag_scope(isolate);
888 HandleScope scope(isolate);
889 DCHECK_EQ(1, args.length());
890 // TODO(14564): Pass WasmFuncRef here instead of WasmInternalFunction.
892 Cast<WasmInternalFunction>(args[0]), isolate);
894}
895
896RUNTIME_FUNCTION(Runtime_WasmFunctionTableGet) {
897 ClearThreadInWasmScope flag_scope(isolate);
898 HandleScope scope(isolate);
899 DCHECK_EQ(3, args.length());
900 Tagged<WasmTrustedInstanceData> trusted_instance_data =
902 uint32_t table_index = args.positive_smi_value_at(1);
903 uint32_t entry_index = args.positive_smi_value_at(2);
904 DCHECK_LT(table_index, trusted_instance_data->tables()->length());
905 auto table = direct_handle(
906 Cast<WasmTableObject>(trusted_instance_data->tables()->get(table_index)),
907 isolate);
908 // We only use the runtime call for lazily initialized function references.
909 DCHECK(table->unsafe_type().ref_type_kind() == wasm::RefTypeKind::kFunction);
910
911 if (!table->is_in_bounds(entry_index)) {
912 return ThrowWasmError(isolate, MessageTemplate::kWasmTrapTableOutOfBounds);
913 }
914
915 return *WasmTableObject::Get(isolate, table, entry_index);
916}
917
918RUNTIME_FUNCTION(Runtime_WasmFunctionTableSet) {
919 ClearThreadInWasmScope flag_scope(isolate);
920 HandleScope scope(isolate);
921 DCHECK_EQ(4, args.length());
922 Tagged<WasmTrustedInstanceData> trusted_instance_data =
924 uint32_t table_index = args.positive_smi_value_at(1);
925 uint32_t entry_index = args.positive_smi_value_at(2);
926 DirectHandle<Object> element(args[3], isolate);
927 DCHECK_LT(table_index, trusted_instance_data->tables()->length());
928 auto table = direct_handle(
929 Cast<WasmTableObject>(trusted_instance_data->tables()->get(table_index)),
930 isolate);
931 // We only use the runtime call for lazily initialized function references.
932 DCHECK(table->unsafe_type().ref_type_kind() == wasm::RefTypeKind::kFunction);
933
934 if (!table->is_in_bounds(entry_index)) {
935 return ThrowWasmError(isolate, MessageTemplate::kWasmTrapTableOutOfBounds);
936 }
937 WasmTableObject::Set(isolate, table, entry_index, element);
938 return ReadOnlyRoots(isolate).undefined_value();
939}
940
941RUNTIME_FUNCTION(Runtime_WasmTableInit) {
942 ClearThreadInWasmScope flag_scope(isolate);
943 HandleScope scope(isolate);
944 DCHECK_EQ(6, args.length());
945 DirectHandle<WasmTrustedInstanceData> trusted_instance_data(
947 uint32_t table_index = args.positive_smi_value_at(1);
948 uint32_t elem_segment_index = args.positive_smi_value_at(2);
949 static_assert(
951 "Make sure clamping to Smi range doesn't make an invalid call valid");
952 uint32_t dst = args.positive_smi_value_at(3);
953 uint32_t src = args.positive_smi_value_at(4);
954 uint32_t count = args.positive_smi_value_at(5);
955
956 DCHECK(!isolate->context().is_null());
957
958 // TODO(14616): Pass the correct instance data.
959 std::optional<MessageTemplate> opt_error =
961 isolate, trusted_instance_data, trusted_instance_data, table_index,
962 elem_segment_index, dst, src, count);
963 if (opt_error.has_value()) {
964 return ThrowWasmError(isolate, opt_error.value());
965 }
966 return ReadOnlyRoots(isolate).undefined_value();
967}
968
969RUNTIME_FUNCTION(Runtime_WasmTableCopy) {
970 ClearThreadInWasmScope flag_scope(isolate);
971 HandleScope scope(isolate);
972 DCHECK_EQ(6, args.length());
973 DirectHandle<WasmTrustedInstanceData> trusted_instance_data(
975 uint32_t table_dst_index = args.positive_smi_value_at(1);
976 uint32_t table_src_index = args.positive_smi_value_at(2);
977 static_assert(
979 "Make sure clamping to Smi range doesn't make an invalid call valid");
980 uint32_t dst = args.positive_smi_value_at(3);
981 uint32_t src = args.positive_smi_value_at(4);
982 uint32_t count = args.positive_smi_value_at(5);
983
984 DCHECK(!isolate->context().is_null());
985
987 isolate, trusted_instance_data, table_dst_index, table_src_index, dst,
988 src, count);
989 if (oob) return ThrowTableOutOfBounds(isolate, trusted_instance_data);
990 return ReadOnlyRoots(isolate).undefined_value();
991}
992
993RUNTIME_FUNCTION(Runtime_WasmTableGrow) {
994 ClearThreadInWasmScope flag_scope(isolate);
995 DCHECK(isolate->IsOnCentralStack());
996 HandleScope scope(isolate);
997 DCHECK_EQ(4, args.length());
998 Tagged<WasmTrustedInstanceData> trusted_instance_data =
1000 uint32_t table_index = args.positive_smi_value_at(1);
1001 DirectHandle<Object> value(args[2], isolate);
1002 uint32_t delta = args.positive_smi_value_at(3);
1003
1005 Cast<WasmTableObject>(trusted_instance_data->tables()->get(table_index)),
1006 isolate);
1007 int result = WasmTableObject::Grow(isolate, table, delta, value);
1008
1009 return Smi::FromInt(result);
1010}
1011
1012RUNTIME_FUNCTION(Runtime_WasmTableFill) {
1013 ClearThreadInWasmScope flag_scope(isolate);
1014 HandleScope scope(isolate);
1015 DCHECK_EQ(5, args.length());
1016 DirectHandle<WasmTrustedInstanceData> trusted_instance_data(
1017 Cast<WasmTrustedInstanceData>(args[0]), isolate);
1018 uint32_t table_index = args.positive_smi_value_at(1);
1019 uint32_t start = args.positive_smi_value_at(2);
1020 DirectHandle<Object> value(args[3], isolate);
1021 uint32_t count = args.positive_smi_value_at(4);
1022
1024 Cast<WasmTableObject>(trusted_instance_data->tables()->get(table_index)),
1025 isolate);
1026
1027 uint32_t table_size = table->current_length();
1028
1029 if (start > table_size) {
1030 return ThrowTableOutOfBounds(isolate, trusted_instance_data);
1031 }
1032
1033 // Even when table.fill goes out-of-bounds, as many entries as possible are
1034 // put into the table. Only afterwards we trap.
1035 uint32_t fill_count = std::min(count, table_size - start);
1036 if (fill_count < count) {
1037 return ThrowTableOutOfBounds(isolate, trusted_instance_data);
1038 }
1039 WasmTableObject::Fill(isolate, table, start, value, fill_count);
1040
1041 return ReadOnlyRoots(isolate).undefined_value();
1042}
1043
1044namespace {
1045// Returns true if any breakpoint was hit, false otherwise.
1046bool ExecuteWasmDebugBreaks(
1047 Isolate* isolate,
1048 DirectHandle<WasmTrustedInstanceData> trusted_instance_data,
1049 WasmFrame* frame) {
1050 DirectHandle<Script> script{trusted_instance_data->module_object()->script(),
1051 isolate};
1052 auto* debug_info = trusted_instance_data->native_module()->GetDebugInfo();
1053
1054 // Enter the debugger.
1055 DebugScope debug_scope(isolate->debug());
1056
1057 // Check for instrumentation breakpoints first, but still execute regular
1058 // breakpoints afterwards.
1059 bool paused_on_instrumentation = false;
1060 DCHECK_EQ(script->break_on_entry(),
1061 !!trusted_instance_data->break_on_entry());
1062 if (script->break_on_entry()) {
1063 MaybeDirectHandle<FixedArray> maybe_on_entry_breakpoints =
1064 WasmScript::CheckBreakPoints(isolate, script,
1066 frame->id());
1067 script->set_break_on_entry(false);
1068 // Update the "break_on_entry" flag on all live instances.
1069 i::Tagged<i::WeakArrayList> weak_instance_list =
1070 script->wasm_weak_instance_list();
1071 for (int i = 0; i < weak_instance_list->length(); ++i) {
1072 if (weak_instance_list->Get(i).IsCleared()) continue;
1073 i::Cast<i::WasmInstanceObject>(weak_instance_list->Get(i).GetHeapObject())
1074 ->trusted_data(isolate)
1075 ->set_break_on_entry(false);
1076 }
1077 DCHECK(!trusted_instance_data->break_on_entry());
1078 if (!maybe_on_entry_breakpoints.is_null()) {
1079 isolate->debug()->OnInstrumentationBreak();
1080 paused_on_instrumentation = true;
1081 }
1082 }
1083
1084 if (debug_info->IsStepping(frame) && !debug_info->IsFrameBlackboxed(frame)) {
1085 debug_info->ClearStepping(isolate);
1086 StepAction step_action = isolate->debug()->last_step_action();
1087 isolate->debug()->ClearStepping();
1088 isolate->debug()->OnDebugBreak(isolate->factory()->empty_fixed_array(),
1089 step_action);
1090 return true;
1091 }
1092
1093 // Check whether we hit a breakpoint.
1094 DirectHandle<FixedArray> breakpoints;
1095 if (WasmScript::CheckBreakPoints(isolate, script, frame->position(),
1096 frame->id())
1097 .ToHandle(&breakpoints)) {
1098 debug_info->ClearStepping(isolate);
1099 StepAction step_action = isolate->debug()->last_step_action();
1100 isolate->debug()->ClearStepping();
1101 if (isolate->debug()->break_points_active()) {
1102 // We hit one or several breakpoints. Notify the debug listeners.
1103 isolate->debug()->OnDebugBreak(breakpoints, step_action);
1104 }
1105 return true;
1106 }
1107
1108 return paused_on_instrumentation;
1109}
1110} // namespace
1111
1112RUNTIME_FUNCTION(Runtime_WasmDebugBreak) {
1113 ClearThreadInWasmScope flag_scope(isolate);
1114 HandleScope scope(isolate);
1115 DCHECK_EQ(0, args.length());
1116 FrameFinder<WasmFrame> frame_finder(
1117 isolate, {StackFrame::EXIT, StackFrame::WASM_DEBUG_BREAK});
1118 WasmFrame* frame = frame_finder.frame();
1120 frame->trusted_instance_data(), isolate};
1121 isolate->set_context(trusted_data->native_context());
1122
1123 if (!ExecuteWasmDebugBreaks(isolate, trusted_data, frame)) {
1124 // We did not hit a breakpoint. If we are in stepping code, but the user did
1125 // not request stepping, clear this (to save further calls into this runtime
1126 // function).
1127 auto* debug_info = trusted_data->native_module()->GetDebugInfo();
1128 debug_info->ClearStepping(frame);
1129 }
1130
1131 // Execute a stack check before leaving this function. This is to handle any
1132 // interrupts set by the debugger (e.g. termination), but also to execute Wasm
1133 // code GC to get rid of temporarily created Wasm code.
1134 StackLimitCheck check(isolate);
1135 if (check.InterruptRequested()) {
1136 Tagged<Object> interrupt_object =
1137 isolate->stack_guard()->HandleInterrupts();
1138 // Interrupt handling can create an exception, including the
1139 // termination exception.
1140 if (IsException(interrupt_object, isolate)) return interrupt_object;
1141 DCHECK(IsUndefined(interrupt_object, isolate));
1142 }
1143
1144 return ReadOnlyRoots(isolate).undefined_value();
1145}
1146
1147// Assumes copy ranges are in-bounds and copy length > 0.
1148// TODO(manoskouk): Unify part of this with the implementation in
1149// wasm-extern-refs.cc
1150RUNTIME_FUNCTION(Runtime_WasmArrayCopy) {
1151 ClearThreadInWasmScope flag_scope(isolate);
1152 HandleScope scope(isolate);
1154 DCHECK_EQ(5, args.length());
1155 Tagged<WasmArray> dst_array = Cast<WasmArray>(args[0]);
1156 uint32_t dst_index = args.positive_smi_value_at(1);
1157 Tagged<WasmArray> src_array = Cast<WasmArray>(args[2]);
1158 uint32_t src_index = args.positive_smi_value_at(3);
1159 uint32_t length = args.positive_smi_value_at(4);
1160 DCHECK_GT(length, 0);
1161 bool overlapping_ranges =
1162 dst_array.ptr() == src_array.ptr() &&
1163 (dst_index < src_index ? dst_index + length > src_index
1164 : src_index + length > dst_index);
1165 wasm::CanonicalValueType element_type =
1166 src_array->map()->wasm_type_info()->element_type();
1167 if (element_type.is_reference()) {
1168 ObjectSlot dst_slot = dst_array->ElementSlot(dst_index);
1169 ObjectSlot src_slot = src_array->ElementSlot(src_index);
1170 if (overlapping_ranges) {
1171 isolate->heap()->MoveRange(dst_array, dst_slot, src_slot, length,
1173 } else {
1174 isolate->heap()->CopyRange(dst_array, dst_slot, src_slot, length,
1176 }
1177 } else {
1178 void* dst = reinterpret_cast<void*>(dst_array->ElementAddress(dst_index));
1179 void* src = reinterpret_cast<void*>(src_array->ElementAddress(src_index));
1180 size_t copy_size = length * element_type.value_kind_size();
1181 if (overlapping_ranges) {
1182 MemMove(dst, src, copy_size);
1183 } else {
1184 MemCopy(dst, src, copy_size);
1185 }
1186 }
1187 return ReadOnlyRoots(isolate).undefined_value();
1188}
1189
1190RUNTIME_FUNCTION(Runtime_WasmAllocateDescriptorStruct) {
1191 ClearThreadInWasmScope flag_scope(isolate);
1192 HandleScope scope(isolate);
1193 DCHECK_EQ(3, args.length());
1195 Cast<WasmTrustedInstanceData>(args[0]), isolate};
1196 DirectHandle<Map> map{Cast<Map>(args[1]), isolate};
1197 wasm::ModuleTypeIndex type_index{args.positive_smi_value_at(2)};
1199 type_index, map);
1200}
1201
1202RUNTIME_FUNCTION(Runtime_WasmArrayNewSegment) {
1203 ClearThreadInWasmScope flag_scope(isolate);
1204 HandleScope scope(isolate);
1205 DCHECK_EQ(5, args.length());
1206 DirectHandle<WasmTrustedInstanceData> trusted_instance_data(
1207 Cast<WasmTrustedInstanceData>(args[0]), isolate);
1208 uint32_t segment_index = args.positive_smi_value_at(1);
1209 uint32_t offset = args.positive_smi_value_at(2);
1210 uint32_t length = args.positive_smi_value_at(3);
1211 DirectHandle<Map> rtt(Cast<Map>(args[4]), isolate);
1212
1213 wasm::CanonicalValueType element_type = rtt->wasm_type_info()->element_type();
1214
1215 uint32_t element_size = element_type.value_kind_size();
1216 // This check also implies no overflow.
1217 if (length > static_cast<uint32_t>(WasmArray::MaxLength(element_size))) {
1218 return ThrowWasmError(isolate, MessageTemplate::kWasmTrapArrayTooLarge);
1219 }
1220
1221 if (element_type.is_numeric()) {
1222 // No chance of overflow due to the check above.
1223 uint32_t length_in_bytes = length * element_size;
1224
1226 offset, length_in_bytes,
1227 trusted_instance_data->data_segment_sizes()->get(segment_index))) {
1228 return ThrowWasmError(isolate,
1229 MessageTemplate::kWasmTrapDataSegmentOutOfBounds);
1230 }
1231
1232 Address source =
1233 trusted_instance_data->data_segment_starts()->get(segment_index) +
1234 offset;
1235 return *isolate->factory()->NewWasmArrayFromMemory(length, rtt,
1236 element_type, source);
1237 } else {
1238 DirectHandle<Object> elem_segment_raw(
1239 trusted_instance_data->element_segments()->get(segment_index), isolate);
1240 const wasm::WasmElemSegment* module_elem_segment =
1241 &trusted_instance_data->module()->elem_segments[segment_index];
1242 // If the segment is initialized in the instance, we have to get its length
1243 // from there, as it might have been dropped. If the segment is
1244 // uninitialized, we need to fetch its length from the module.
1245 int segment_length = IsFixedArray(*elem_segment_raw)
1246 ? Cast<FixedArray>(elem_segment_raw)->length()
1247 : module_elem_segment->element_count;
1248 if (!base::IsInBounds<size_t>(offset, length, segment_length)) {
1249 return ThrowWasmError(
1250 isolate, MessageTemplate::kWasmTrapElementSegmentOutOfBounds);
1251 }
1252 // TODO(14616): Pass the correct instance data.
1254 isolate->factory()->NewWasmArrayFromElementSegment(
1255 trusted_instance_data, trusted_instance_data, segment_index, offset,
1256 length, rtt, element_type);
1257 if (IsSmi(*result)) {
1258 return ThrowWasmError(
1259 isolate, static_cast<MessageTemplate>(Cast<Smi>(*result).value()));
1260 } else {
1261 return *result;
1262 }
1263 }
1264}
1265
1266RUNTIME_FUNCTION(Runtime_WasmArrayInitSegment) {
1267 ClearThreadInWasmScope flag_scope(isolate);
1268 HandleScope scope(isolate);
1269 DCHECK_EQ(6, args.length());
1270 DirectHandle<WasmTrustedInstanceData> trusted_instance_data(
1271 Cast<WasmTrustedInstanceData>(args[0]), isolate);
1272 uint32_t segment_index = args.positive_smi_value_at(1);
1273 DirectHandle<WasmArray> array(Cast<WasmArray>(args[2]), isolate);
1274 uint32_t array_index = args.positive_smi_value_at(3);
1275 uint32_t segment_offset = args.positive_smi_value_at(4);
1276 uint32_t length = args.positive_smi_value_at(5);
1277
1278 wasm::CanonicalValueType element_type =
1279 array->map()->wasm_type_info()->element_type();
1280
1281 if (element_type.is_numeric()) {
1282 if (!base::IsInBounds<uint32_t>(array_index, length, array->length())) {
1283 return ThrowWasmError(isolate,
1284 MessageTemplate::kWasmTrapArrayOutOfBounds);
1285 }
1286
1287 // No chance of overflow, due to the check above and the limit in array
1288 // length.
1289 uint32_t length_in_bytes = length * element_type.value_kind_size();
1290
1292 segment_offset, length_in_bytes,
1293 trusted_instance_data->data_segment_sizes()->get(segment_index))) {
1294 return ThrowWasmError(isolate,
1295 MessageTemplate::kWasmTrapDataSegmentOutOfBounds);
1296 }
1297
1298 Address source =
1299 trusted_instance_data->data_segment_starts()->get(segment_index) +
1301 Address dest = array->ElementAddress(array_index);
1302#if V8_TARGET_BIG_ENDIAN
1303 MemCopyAndSwitchEndianness(reinterpret_cast<void*>(dest),
1304 reinterpret_cast<void*>(source), length,
1305 element_type.value_kind_size());
1306#else
1307 MemCopy(reinterpret_cast<void*>(dest), reinterpret_cast<void*>(source),
1308 length_in_bytes);
1309#endif
1310 return *isolate->factory()->undefined_value();
1311 } else {
1312 DirectHandle<Object> elem_segment_raw(
1313 trusted_instance_data->element_segments()->get(segment_index), isolate);
1314 const wasm::WasmElemSegment* module_elem_segment =
1315 &trusted_instance_data->module()->elem_segments[segment_index];
1316 // If the segment is initialized in the instance, we have to get its length
1317 // from there, as it might have been dropped. If the segment is
1318 // uninitialized, we need to fetch its length from the module.
1319 int segment_length = IsFixedArray(*elem_segment_raw)
1320 ? Cast<FixedArray>(elem_segment_raw)->length()
1321 : module_elem_segment->element_count;
1322 if (!base::IsInBounds<size_t>(segment_offset, length, segment_length)) {
1323 return ThrowWasmError(
1324 isolate, MessageTemplate::kWasmTrapElementSegmentOutOfBounds);
1325 }
1326 if (!base::IsInBounds(array_index, length, array->length())) {
1327 return ThrowWasmError(isolate,
1328 MessageTemplate::kWasmTrapArrayOutOfBounds);
1329 }
1330
1331 // If the element segment has not been initialized yet, lazily initialize it
1332 // now.
1333 AccountingAllocator allocator;
1334 Zone zone(&allocator, ZONE_NAME);
1335 // TODO(14616): Fix the instance data.
1336 std::optional<MessageTemplate> opt_error =
1337 wasm::InitializeElementSegment(&zone, isolate, trusted_instance_data,
1338 trusted_instance_data, segment_index);
1339 if (opt_error.has_value()) {
1340 return ThrowWasmError(isolate, opt_error.value());
1341 }
1342
1343 auto elements = direct_handle(
1345 trusted_instance_data->element_segments()->get(segment_index)),
1346 isolate);
1347 if (length > 0) {
1348 isolate->heap()->CopyRange(*array, array->ElementSlot(array_index),
1349 elements->RawFieldOfElementAt(segment_offset),
1350 length, UPDATE_WRITE_BARRIER);
1351 }
1352 return *isolate->factory()->undefined_value();
1353 }
1354}
1355
1356// Allocate a new suspender, and prepare for stack switching by updating the
1357// active continuation, active suspender and stack limit.
1358RUNTIME_FUNCTION(Runtime_WasmAllocateSuspender) {
1359 HandleScope scope(isolate);
1361 isolate->factory()->NewWasmSuspenderObject();
1362
1363 // Update the stack state.
1364 wasm::StackMemory* active_stack = isolate->isolate_data()->active_stack();
1365 std::unique_ptr<wasm::StackMemory> target_stack =
1366 isolate->stack_pool().GetOrAllocate();
1367 target_stack->jmpbuf()->parent = active_stack;
1368 target_stack->jmpbuf()->stack_limit = target_stack->jslimit();
1369 target_stack->jmpbuf()->sp = target_stack->base();
1370 target_stack->jmpbuf()->fp = kNullAddress;
1371 target_stack->jmpbuf()->state = wasm::JumpBuffer::Suspended;
1372 isolate->isolate_data()->set_active_stack(target_stack.get());
1373
1374 // Update the suspender state.
1375 FullObjectSlot active_suspender_slot =
1376 isolate->roots_table().slot(RootIndex::kActiveSuspender);
1377 suspender->set_parent(
1378 Cast<UnionOf<Undefined, WasmSuspenderObject>>(*active_suspender_slot));
1379 suspender->set_stack(isolate, target_stack.get());
1380 active_suspender_slot.store(*suspender);
1381
1382 target_stack->set_index(isolate->wasm_stacks().size());
1383 isolate->wasm_stacks().emplace_back(std::move(target_stack));
1384 for (size_t i = 0; i < isolate->wasm_stacks().size(); ++i) {
1385 SLOW_DCHECK(isolate->wasm_stacks()[i]->index() == i);
1386 }
1387
1388 // Stack limit will be updated in WasmReturnPromiseOnSuspendAsm builtin.
1390 active_stack->jmpbuf()->state = wasm::JumpBuffer::Inactive;
1391
1392 return *suspender;
1393}
1394
1395#define RETURN_RESULT_OR_TRAP(call) \
1396 do { \
1397 DirectHandle<Object> result; \
1398 if (!(call).ToHandle(&result)) { \
1399 DCHECK(isolate->has_exception()); \
1400 /* Mark any exception as uncatchable by Wasm. */ \
1401 DirectHandle<JSObject> exception(Cast<JSObject>(isolate->exception()), \
1402 isolate); \
1403 DirectHandle<Name> uncatchable = \
1404 isolate->factory()->wasm_uncatchable_symbol(); \
1405 LookupIterator it(isolate, exception, uncatchable, LookupIterator::OWN); \
1406 if (!JSReceiver::HasProperty(&it).FromJust()) { \
1407 JSObject::AddProperty(isolate, exception, uncatchable, \
1408 isolate->factory()->true_value(), NONE); \
1409 } \
1410 return ReadOnlyRoots(isolate).exception(); \
1411 } \
1412 DCHECK(!isolate->has_exception() || \
1413 IsTerminationException(isolate->exception())); \
1414 return *result; \
1415 } while (false)
1416
1417// "Special" because the type must be in a recgroup of its own.
1418// Used by "JS String Builtins".
1419RUNTIME_FUNCTION(Runtime_WasmCastToSpecialPrimitiveArray) {
1420 ClearThreadInWasmScope flag_scope(isolate);
1421 HandleScope scope(isolate);
1422 DCHECK_EQ(2, args.length());
1423
1424 int bits = args.smi_value_at(1);
1425 DCHECK(bits == 8 || bits == 16);
1426
1427 if (args[0] == ReadOnlyRoots(isolate).null_value()) {
1428 return ThrowWasmError(isolate, MessageTemplate::kWasmTrapNullDereference);
1429 }
1430 MessageTemplate illegal_cast = MessageTemplate::kWasmTrapIllegalCast;
1431 if (!IsWasmArray(args[0])) return ThrowWasmError(isolate, illegal_cast);
1433 wasm::CanonicalTypeIndex expected =
1436 Tagged<Object> expected_map =
1437 MakeStrong(isolate->heap()->wasm_canonical_rtts()->get(expected.index));
1438 // If the expected_map has been cleared or never even created, then there's
1439 // no chance of a match anyway.
1440 if (obj->map() != expected_map) {
1441 return ThrowWasmError(isolate, illegal_cast);
1442 }
1443 return obj;
1444}
1445
1446// Returns the new string if the operation succeeds. Otherwise throws an
1447// exception and returns an empty result.
1448RUNTIME_FUNCTION(Runtime_WasmStringNewWtf8) {
1449 ClearThreadInWasmScope flag_scope(isolate);
1450 DCHECK_EQ(5, args.length());
1451 HandleScope scope(isolate);
1452 Tagged<WasmTrustedInstanceData> trusted_instance_data =
1454 uint32_t memory = args.positive_smi_value_at(1);
1455 uint32_t utf8_variant_value = args.positive_smi_value_at(2);
1456 double offset_double = args.number_value_at(3);
1457 uintptr_t offset = static_cast<uintptr_t>(offset_double);
1458 uint32_t size = NumberToUint32(args[4]);
1459
1460 DCHECK(utf8_variant_value <=
1461 static_cast<uint32_t>(unibrow::Utf8Variant::kLastUtf8Variant));
1462
1463 auto utf8_variant = static_cast<unibrow::Utf8Variant>(utf8_variant_value);
1464
1465 uint64_t mem_size = trusted_instance_data->memory_size(memory);
1466 if (!base::IsInBounds<uint64_t>(offset, size, mem_size)) {
1467 return ThrowWasmError(isolate, MessageTemplate::kWasmTrapMemOutOfBounds);
1468 }
1469
1470 const base::Vector<const uint8_t> bytes{
1471 trusted_instance_data->memory_base(memory) + offset, size};
1473 isolate->factory()->NewStringFromUtf8(bytes, utf8_variant);
1474 if (utf8_variant == unibrow::Utf8Variant::kUtf8NoTrap) {
1475 // If the input was invalid, then the decoder has failed silently, and
1476 // the string.new_utf8_try instruction should return null.
1477 if (result_string.is_null() && !isolate->has_exception()) {
1478 return *isolate->factory()->wasm_null();
1479 }
1480 // Fall through in case of a valid result, and in case of a pending
1481 // exception because the requested string was too large.
1482 }
1483 RETURN_RESULT_OR_TRAP(result_string);
1484}
1485
1486RUNTIME_FUNCTION(Runtime_WasmStringNewWtf8Array) {
1487 ClearThreadInWasmScope flag_scope(isolate);
1488 DCHECK_EQ(4, args.length());
1489 HandleScope scope(isolate);
1490 uint32_t utf8_variant_value = args.positive_smi_value_at(0);
1491 DirectHandle<WasmArray> array(Cast<WasmArray>(args[1]), isolate);
1492 uint32_t start = NumberToUint32(args[2]);
1493 uint32_t end = NumberToUint32(args[3]);
1494
1495 DCHECK(utf8_variant_value <=
1496 static_cast<uint32_t>(unibrow::Utf8Variant::kLastUtf8Variant));
1497 auto utf8_variant = static_cast<unibrow::Utf8Variant>(utf8_variant_value);
1498
1500 isolate->factory()->NewStringFromUtf8(array, start, end, utf8_variant);
1501 if (utf8_variant == unibrow::Utf8Variant::kUtf8NoTrap) {
1502 DCHECK(!isolate->has_exception());
1503 if (result_string.is_null()) {
1504 return *isolate->factory()->wasm_null();
1505 }
1506 return *result_string.ToHandleChecked();
1507 }
1508 RETURN_RESULT_OR_TRAP(result_string);
1509}
1510
1511RUNTIME_FUNCTION(Runtime_WasmStringNewWtf16) {
1512 ClearThreadInWasmScope flag_scope(isolate);
1513 DCHECK_EQ(4, args.length());
1514 HandleScope scope(isolate);
1515 Tagged<WasmTrustedInstanceData> trusted_instance_data =
1517 uint32_t memory = args.positive_smi_value_at(1);
1518 double offset_double = args.number_value_at(2);
1519 uintptr_t offset = static_cast<uintptr_t>(offset_double);
1520 uint32_t size_in_codeunits = NumberToUint32(args[3]);
1521
1522 uint64_t mem_size = trusted_instance_data->memory_size(memory);
1523 if (size_in_codeunits > kMaxUInt32 / 2 ||
1524 !base::IsInBounds<uint64_t>(offset, size_in_codeunits * 2, mem_size)) {
1525 return ThrowWasmError(isolate, MessageTemplate::kWasmTrapMemOutOfBounds);
1526 }
1527 if (offset & 1) {
1528 return ThrowWasmError(isolate, MessageTemplate::kWasmTrapUnalignedAccess);
1529 }
1530
1531 const uint8_t* bytes = trusted_instance_data->memory_base(memory) + offset;
1532 const base::uc16* codeunits = reinterpret_cast<const base::uc16*>(bytes);
1533 RETURN_RESULT_OR_TRAP(isolate->factory()->NewStringFromTwoByteLittleEndian(
1534 {codeunits, size_in_codeunits}));
1535}
1536
1537RUNTIME_FUNCTION(Runtime_WasmStringNewWtf16Array) {
1538 ClearThreadInWasmScope flag_scope(isolate);
1539 DCHECK_EQ(3, args.length());
1540 HandleScope scope(isolate);
1541 DirectHandle<WasmArray> array(Cast<WasmArray>(args[0]), isolate);
1542 uint32_t start = NumberToUint32(args[1]);
1543 uint32_t end = NumberToUint32(args[2]);
1544
1546 isolate->factory()->NewStringFromUtf16(array, start, end));
1547}
1548
1549RUNTIME_FUNCTION(Runtime_WasmSubstring) {
1550 ClearThreadInWasmScope flag_scope(isolate);
1551 DCHECK_EQ(3, args.length());
1552 HandleScope scope(isolate);
1554 int start = args.positive_smi_value_at(1);
1555 int length = args.positive_smi_value_at(2);
1556
1557 string = String::Flatten(isolate, string);
1558 return *isolate->factory()->NewCopiedSubstring(string, start, length);
1559}
1560
1561// Returns the new string if the operation succeeds. Otherwise traps.
1562RUNTIME_FUNCTION(Runtime_WasmStringConst) {
1563 ClearThreadInWasmScope flag_scope(isolate);
1564 DCHECK_EQ(2, args.length());
1565 HandleScope scope(isolate);
1566 Tagged<WasmTrustedInstanceData> trusted_instance_data =
1568 static_assert(
1570 uint32_t index = args.positive_smi_value_at(1);
1571
1572 DCHECK_LT(index, trusted_instance_data->module()->stringref_literals.size());
1573
1575 trusted_instance_data->module()->stringref_literals[index];
1576 const base::Vector<const uint8_t> module_bytes =
1577 trusted_instance_data->native_module()->wire_bytes();
1578 const base::Vector<const uint8_t> string_bytes = module_bytes.SubVector(
1579 literal.source.offset(), literal.source.end_offset());
1580 // TODO(12868): No need to re-validate WTF-8. Also, result should be cached.
1581 return *isolate->factory()
1582 ->NewStringFromUtf8(string_bytes, unibrow::Utf8Variant::kWtf8)
1583 .ToHandleChecked();
1584}
1585
1586RUNTIME_FUNCTION(Runtime_WasmStringNewSegmentWtf8) {
1587 ClearThreadInWasmScope flag_scope(isolate);
1588 DCHECK_EQ(5, args.length());
1589 HandleScope scope(isolate);
1590 DirectHandle<WasmTrustedInstanceData> trusted_instance_data(
1591 Cast<WasmTrustedInstanceData>(args[0]), isolate);
1592 uint32_t segment_index = args.positive_smi_value_at(1);
1593 uint32_t offset = args.positive_smi_value_at(2);
1594 uint32_t length = args.positive_smi_value_at(3);
1595 unibrow::Utf8Variant variant =
1596 static_cast<unibrow::Utf8Variant>(args.positive_smi_value_at(4));
1597
1599 offset, length,
1600 trusted_instance_data->data_segment_sizes()->get(segment_index))) {
1601 return ThrowWasmError(isolate,
1602 MessageTemplate::kWasmTrapDataSegmentOutOfBounds);
1603 }
1604
1605 Address source =
1606 trusted_instance_data->data_segment_starts()->get(segment_index) + offset;
1607 MaybeDirectHandle<String> result = isolate->factory()->NewStringFromUtf8(
1608 {reinterpret_cast<const uint8_t*>(source), length}, variant);
1609 if (variant == unibrow::Utf8Variant::kUtf8NoTrap) {
1610 DCHECK(!isolate->has_exception());
1611 // Only instructions from the stringref proposal can set variant
1612 // kUtf8NoTrap, so WasmNull is appropriate here.
1613 if (result.is_null()) return *isolate->factory()->wasm_null();
1614 return *result.ToHandleChecked();
1615 }
1617}
1618
1619namespace {
1620// TODO(12868): Consider unifying with api.cc:String::Utf8Length.
1621template <typename T>
1622int MeasureWtf8(base::Vector<const T> wtf16) {
1624 int length = 0;
1625 DCHECK(wtf16.size() <= String::kMaxLength);
1626 static_assert(String::kMaxLength <=
1628 for (size_t i = 0; i < wtf16.size(); i++) {
1629 int current = wtf16[i];
1630 length += unibrow::Utf8::Length(current, previous);
1631 previous = current;
1632 }
1633 return length;
1634}
1635int MeasureWtf8(Isolate* isolate, DirectHandle<String> string) {
1636 string = String::Flatten(isolate, string);
1638 String::FlatContent content = string->GetFlatContent(no_gc);
1639 DCHECK(content.IsFlat());
1640 return content.IsOneByte() ? MeasureWtf8(content.ToOneByteVector())
1641 : MeasureWtf8(content.ToUC16Vector());
1642}
1643size_t MaxEncodedSize(base::Vector<const uint8_t> wtf16) {
1644 DCHECK(wtf16.size() < std::numeric_limits<size_t>::max() /
1646 return wtf16.size() * unibrow::Utf8::kMax8BitCodeUnitSize;
1647}
1648size_t MaxEncodedSize(base::Vector<const base::uc16> wtf16) {
1649 DCHECK(wtf16.size() < std::numeric_limits<size_t>::max() /
1651 return wtf16.size() * unibrow::Utf8::kMax16BitCodeUnitSize;
1652}
1653bool HasUnpairedSurrogate(base::Vector<const uint8_t> wtf16) { return false; }
1654bool HasUnpairedSurrogate(base::Vector<const base::uc16> wtf16) {
1655 return unibrow::Utf16::HasUnpairedSurrogate(wtf16.begin(), wtf16.size());
1656}
1657template <typename T>
1658int EncodeWtf8(base::Vector<char> bytes, size_t offset,
1659 base::Vector<const T> wtf16, unibrow::Utf8Variant variant,
1660 MessageTemplate* message, MessageTemplate out_of_bounds) {
1661 // The first check is a quick estimate to decide whether the second check
1662 // is worth the computation.
1663 if (!base::IsInBounds<size_t>(offset, MaxEncodedSize(wtf16), bytes.size()) &&
1664 !base::IsInBounds<size_t>(offset, MeasureWtf8(wtf16), bytes.size())) {
1665 *message = out_of_bounds;
1666 return -1;
1667 }
1668
1669 bool replace_invalid = false;
1670 switch (variant) {
1671 case unibrow::Utf8Variant::kWtf8:
1672 break;
1673 case unibrow::Utf8Variant::kUtf8:
1674 if (HasUnpairedSurrogate(wtf16)) {
1675 *message = MessageTemplate::kWasmTrapStringIsolatedSurrogate;
1676 return -1;
1677 }
1678 break;
1680 replace_invalid = true;
1681 break;
1682 default:
1683 UNREACHABLE();
1684 }
1685
1686 bool write_null = false;
1688 unibrow::Utf8::Encode(wtf16, bytes.begin() + offset,
1689 bytes.size() - offset, write_null, replace_invalid);
1690 DCHECK_EQ(result.characters_processed, wtf16.size());
1691 DCHECK_LE(result.bytes_written, kMaxInt);
1692 return static_cast<int>(result.bytes_written);
1693}
1694template <typename GetWritableBytes>
1695Tagged<Object> EncodeWtf8(Isolate* isolate, unibrow::Utf8Variant variant,
1696 DirectHandle<String> string,
1697 GetWritableBytes get_writable_bytes, size_t offset,
1698 MessageTemplate out_of_bounds_message) {
1699 string = String::Flatten(isolate, string);
1700 MessageTemplate message;
1701 int written;
1702 {
1704 String::FlatContent content = string->GetFlatContent(no_gc);
1705 base::Vector<char> dst = get_writable_bytes(no_gc);
1706 written = content.IsOneByte()
1707 ? EncodeWtf8(dst, offset, content.ToOneByteVector(), variant,
1708 &message, out_of_bounds_message)
1709 : EncodeWtf8(dst, offset, content.ToUC16Vector(), variant,
1710 &message, out_of_bounds_message);
1711 }
1712 if (written < 0) {
1713 DCHECK_NE(message, MessageTemplate::kNone);
1714 return ThrowWasmError(isolate, message);
1715 }
1716 return *isolate->factory()->NewNumberFromInt(written);
1717}
1718} // namespace
1719
1720// Used for storing the name of a string-constants imports module off the heap.
1721// Defined here to be able to make use of the helper functions above.
1723 std::string& out) {
1724 int utf8_length = MeasureWtf8(isolate, string);
1726 out.resize(utf8_length);
1727 String::FlatContent content = string->GetFlatContent(no_gc);
1728 DCHECK(content.IsFlat());
1729 static constexpr unibrow::Utf8Variant variant =
1731 MessageTemplate* error_cant_happen = nullptr;
1732 MessageTemplate oob_cant_happen = MessageTemplate::kInvalid;
1733 if (content.IsOneByte()) {
1734 EncodeWtf8({out.data(), out.size()}, 0, content.ToOneByteVector(), variant,
1735 error_cant_happen, oob_cant_happen);
1736 } else {
1737 EncodeWtf8({out.data(), out.size()}, 0, content.ToUC16Vector(), variant,
1738 error_cant_happen, oob_cant_happen);
1739 }
1740}
1741
1742RUNTIME_FUNCTION(Runtime_WasmStringMeasureUtf8) {
1743 ClearThreadInWasmScope flag_scope(isolate);
1744 DCHECK_EQ(1, args.length());
1745 HandleScope scope(isolate);
1747
1748 string = String::Flatten(isolate, string);
1749 int length;
1750 {
1752 String::FlatContent content = string->GetFlatContent(no_gc);
1753 DCHECK(content.IsFlat());
1754 if (content.IsOneByte()) {
1755 length = MeasureWtf8(content.ToOneByteVector());
1756 } else {
1757 base::Vector<const base::uc16> code_units = content.ToUC16Vector();
1759 code_units.size())) {
1760 length = -1;
1761 } else {
1762 length = MeasureWtf8(code_units);
1763 }
1764 }
1765 }
1766 return *isolate->factory()->NewNumberFromInt(length);
1767}
1768
1769RUNTIME_FUNCTION(Runtime_WasmStringMeasureWtf8) {
1770 ClearThreadInWasmScope flag_scope(isolate);
1771 DCHECK_EQ(1, args.length());
1772 HandleScope scope(isolate);
1774
1775 int length = MeasureWtf8(isolate, string);
1776 return *isolate->factory()->NewNumberFromInt(length);
1777}
1778
1779RUNTIME_FUNCTION(Runtime_WasmStringEncodeWtf8) {
1780 ClearThreadInWasmScope flag_scope(isolate);
1781 DCHECK_EQ(5, args.length());
1782 HandleScope scope(isolate);
1783 Tagged<WasmTrustedInstanceData> trusted_instance_data =
1785 uint32_t memory = args.positive_smi_value_at(1);
1786 uint32_t utf8_variant_value = args.positive_smi_value_at(2);
1788 double offset_double = args.number_value_at(4);
1789 uintptr_t offset = static_cast<uintptr_t>(offset_double);
1790
1791 DCHECK(utf8_variant_value <=
1792 static_cast<uint32_t>(unibrow::Utf8Variant::kLastUtf8Variant));
1793
1794 char* memory_start =
1795 reinterpret_cast<char*>(trusted_instance_data->memory_base(memory));
1796 auto utf8_variant = static_cast<unibrow::Utf8Variant>(utf8_variant_value);
1797 auto get_writable_bytes =
1799 return {memory_start, trusted_instance_data->memory_size(memory)};
1800 };
1801 return EncodeWtf8(isolate, utf8_variant, string, get_writable_bytes, offset,
1802 MessageTemplate::kWasmTrapMemOutOfBounds);
1803}
1804
1805RUNTIME_FUNCTION(Runtime_WasmStringEncodeWtf8Array) {
1806 ClearThreadInWasmScope flag_scope(isolate);
1807 DCHECK_EQ(4, args.length());
1808 HandleScope scope(isolate);
1809 uint32_t utf8_variant_value = args.positive_smi_value_at(0);
1811 DirectHandle<WasmArray> array(Cast<WasmArray>(args[2]), isolate);
1812 uint32_t start = NumberToUint32(args[3]);
1813
1814 DCHECK(utf8_variant_value <=
1815 static_cast<uint32_t>(unibrow::Utf8Variant::kLastUtf8Variant));
1816 auto utf8_variant = static_cast<unibrow::Utf8Variant>(utf8_variant_value);
1817 auto get_writable_bytes =
1819 return {reinterpret_cast<char*>(array->ElementAddress(0)), array->length()};
1820 };
1821 return EncodeWtf8(isolate, utf8_variant, string, get_writable_bytes, start,
1822 MessageTemplate::kWasmTrapArrayOutOfBounds);
1823}
1824
1825RUNTIME_FUNCTION(Runtime_WasmStringToUtf8Array) {
1826 ClearThreadInWasmScope flag_scope(isolate);
1827 DCHECK_EQ(1, args.length());
1828 HandleScope scope(isolate);
1830 uint32_t length = MeasureWtf8(isolate, string);
1831 wasm::WasmValue initial_value(int8_t{0});
1832 Tagged<WeakFixedArray> rtts = isolate->heap()->wasm_canonical_rtts();
1833 // This function can only get called from Wasm code, so we can safely assume
1834 // that the canonical RTT is still around.
1836 Cast<Map>(
1838 .GetHeapObjectAssumeWeak()),
1839 isolate);
1840 DirectHandle<WasmArray> array = isolate->factory()->NewWasmArray(
1841 wasm::kWasmI8, length, initial_value, map);
1842 auto get_writable_bytes =
1844 return {reinterpret_cast<char*>(array->ElementAddress(0)), length};
1845 };
1846 Tagged<Object> write_result =
1847 EncodeWtf8(isolate, unibrow::Utf8Variant::kLossyUtf8, string,
1848 get_writable_bytes, 0, MessageTemplate::kNone);
1849 DCHECK(IsNumber(write_result) && Object::NumberValue(write_result) == length);
1850 USE(write_result);
1851 return *array;
1852}
1853
1854RUNTIME_FUNCTION(Runtime_WasmStringEncodeWtf16) {
1855 ClearThreadInWasmScope flag_scope(isolate);
1856 DCHECK_EQ(6, args.length());
1857 HandleScope scope(isolate);
1858 Tagged<WasmTrustedInstanceData> trusted_instance_data =
1860 uint32_t memory = args.positive_smi_value_at(1);
1861 Tagged<String> string = Cast<String>(args[2]);
1862 double offset_double = args.number_value_at(3);
1863 uintptr_t offset = static_cast<uintptr_t>(offset_double);
1864 uint32_t start = args.positive_smi_value_at(4);
1865 uint32_t length = args.positive_smi_value_at(5);
1866
1867 DCHECK(base::IsInBounds<uint32_t>(start, length, string->length()));
1868
1869 size_t mem_size = trusted_instance_data->memory_size(memory);
1870 static_assert(String::kMaxLength <=
1871 (std::numeric_limits<size_t>::max() / sizeof(base::uc16)));
1872 if (!base::IsInBounds<size_t>(offset, length * sizeof(base::uc16),
1873 mem_size)) {
1874 return ThrowWasmError(isolate, MessageTemplate::kWasmTrapMemOutOfBounds);
1875 }
1876 if (offset & 1) {
1877 return ThrowWasmError(isolate, MessageTemplate::kWasmTrapUnalignedAccess);
1878 }
1879
1880#if defined(V8_TARGET_LITTLE_ENDIAN)
1881 uint16_t* dst = reinterpret_cast<uint16_t*>(
1882 trusted_instance_data->memory_base(memory) + offset);
1883 String::WriteToFlat(string, dst, start, length);
1884#elif defined(V8_TARGET_BIG_ENDIAN)
1885 // TODO(12868): The host is big-endian but we need to write the string
1886 // contents as little-endian.
1887 USE(string);
1888 USE(start);
1889 UNIMPLEMENTED();
1890#else
1891#error Unknown endianness
1892#endif
1893
1894 return Smi::zero(); // Unused.
1895}
1896
1897RUNTIME_FUNCTION(Runtime_WasmStringAsWtf8) {
1898 ClearThreadInWasmScope flag_scope(isolate);
1899 DCHECK_EQ(1, args.length());
1900 HandleScope scope(isolate);
1902 int wtf8_length = MeasureWtf8(isolate, string);
1903 DirectHandle<ByteArray> array = isolate->factory()->NewByteArray(wtf8_length);
1904
1905 auto utf8_variant = unibrow::Utf8Variant::kWtf8;
1906 auto get_writable_bytes =
1908 return {reinterpret_cast<char*>(array->begin()),
1909 static_cast<size_t>(wtf8_length)};
1910 };
1911 EncodeWtf8(isolate, utf8_variant, string, get_writable_bytes, 0,
1912 MessageTemplate::kWasmTrapArrayOutOfBounds);
1913 return *array;
1914}
1915
1916RUNTIME_FUNCTION(Runtime_WasmStringViewWtf8Encode) {
1917 ClearThreadInWasmScope flag_scope(isolate);
1918 DCHECK_EQ(7, args.length());
1919 HandleScope scope(isolate);
1920 Tagged<WasmTrustedInstanceData> trusted_instance_data =
1922 uint32_t utf8_variant_value = args.positive_smi_value_at(1);
1923 DirectHandle<ByteArray> array(Cast<ByteArray>(args[2]), isolate);
1924 double addr_double = args.number_value_at(3);
1925 uintptr_t addr = static_cast<uintptr_t>(addr_double);
1926 uint32_t start = NumberToUint32(args[4]);
1927 uint32_t end = NumberToUint32(args[5]);
1928 uint32_t memory = args.positive_smi_value_at(6);
1929
1930 DCHECK(utf8_variant_value <=
1931 static_cast<uint32_t>(unibrow::Utf8Variant::kLastUtf8Variant));
1933 DCHECK(base::IsInBounds<size_t>(start, end - start, array->length()));
1934
1935 auto utf8_variant = static_cast<unibrow::Utf8Variant>(utf8_variant_value);
1936 size_t length = end - start;
1937
1938 if (!base::IsInBounds<size_t>(addr, length,
1939 trusted_instance_data->memory_size(memory))) {
1940 return ThrowWasmError(isolate, MessageTemplate::kWasmTrapMemOutOfBounds);
1941 }
1942
1943 uint8_t* memory_start = trusted_instance_data->memory_base(memory);
1944 const uint8_t* src = reinterpret_cast<const uint8_t*>(array->begin() + start);
1945 uint8_t* dst = memory_start + addr;
1946
1947 std::vector<size_t> surrogates;
1948 if (utf8_variant != unibrow::Utf8Variant::kWtf8) {
1949 unibrow::Wtf8::ScanForSurrogates({src, length}, &surrogates);
1950 if (utf8_variant == unibrow::Utf8Variant::kUtf8 && !surrogates.empty()) {
1951 return ThrowWasmError(isolate,
1952 MessageTemplate::kWasmTrapStringIsolatedSurrogate);
1953 }
1954 }
1955
1956 MemCopy(dst, src, length);
1957
1958 for (size_t surrogate : surrogates) {
1959 DCHECK_LT(surrogate, length);
1961 unibrow::Utf8::Encode(reinterpret_cast<char*>(dst + surrogate),
1962 unibrow::Utf8::kBadChar, 0, false);
1963 }
1964
1965 // Unused.
1966 return Tagged<Smi>(0);
1967}
1968
1969RUNTIME_FUNCTION(Runtime_WasmStringViewWtf8Slice) {
1970 ClearThreadInWasmScope flag_scope(isolate);
1971 DCHECK_EQ(3, args.length());
1972 HandleScope scope(isolate);
1973 DirectHandle<ByteArray> array(Cast<ByteArray>(args[0]), isolate);
1974 uint32_t start = NumberToUint32(args[1]);
1975 uint32_t end = NumberToUint32(args[2]);
1976
1978 DCHECK(base::IsInBounds<size_t>(start, end - start, array->length()));
1979
1980 // This can't throw because the result can't be too long if the input wasn't,
1981 // and encoding failures are ruled out too because {start}/{end} are aligned.
1982 return *isolate->factory()
1983 ->NewStringFromUtf8(array, start, end,
1984 unibrow::Utf8Variant::kWtf8)
1985 .ToHandleChecked();
1986}
1987
1988#ifdef V8_ENABLE_DRUMBRAKE
1989RUNTIME_FUNCTION(Runtime_WasmTraceBeginExecution) {
1990 DCHECK(v8_flags.slow_histograms && !v8_flags.wasm_jitless &&
1991 v8_flags.wasm_enable_exec_time_histograms);
1992 DCHECK_EQ(0, args.length());
1993 HandleScope scope(isolate);
1994
1995 wasm::WasmExecutionTimer* timer = isolate->wasm_execution_timer();
1996 timer->Start();
1997
1998 return ReadOnlyRoots(isolate).undefined_value();
1999}
2000
2001RUNTIME_FUNCTION(Runtime_WasmTraceEndExecution) {
2002 DCHECK(v8_flags.slow_histograms && !v8_flags.wasm_jitless &&
2003 v8_flags.wasm_enable_exec_time_histograms);
2004 DCHECK_EQ(0, args.length());
2005 HandleScope scope(isolate);
2006
2007 wasm::WasmExecutionTimer* timer = isolate->wasm_execution_timer();
2008 timer->Stop();
2009
2010 return ReadOnlyRoots(isolate).undefined_value();
2011}
2012#endif // V8_ENABLE_DRUMBRAKE
2013
2014RUNTIME_FUNCTION(Runtime_WasmStringFromCodePoint) {
2015 ClearThreadInWasmScope flag_scope(isolate);
2016 DCHECK_EQ(1, args.length());
2017 HandleScope scope(isolate);
2018
2019 uint32_t code_point = NumberToUint32(args[0]);
2020 if (code_point <= unibrow::Utf16::kMaxNonSurrogateCharCode) {
2021 return *isolate->factory()->LookupSingleCharacterStringFromCode(code_point);
2022 }
2023 if (code_point > 0x10FFFF) {
2024 // Allocate a new number to preserve the to-uint conversion (e.g. if
2025 // args[0] == -1, we want the error message to report 4294967295).
2026 return ThrowWasmError(isolate, MessageTemplate::kInvalidCodePoint,
2027 {isolate->factory()->NewNumberFromUint(code_point)});
2028 }
2029
2030 base::uc16 char_buffer[] = {
2033 };
2035 isolate->factory()
2036 ->NewRawTwoByteString(arraysize(char_buffer))
2037 .ToHandleChecked();
2039 CopyChars(result->GetChars(no_gc), char_buffer, arraysize(char_buffer));
2040 return *result;
2041}
2042
2043RUNTIME_FUNCTION(Runtime_WasmStringHash) {
2044 ClearThreadInWasmScope flag_scope(isolate);
2045 DCHECK_EQ(1, args.length());
2047 uint32_t hash = string->EnsureHash();
2048 return Smi::FromInt(static_cast<int>(hash));
2049}
2050
2051} // namespace v8::internal
Isolate * isolate_
Builtins::Kind kind
Definition builtins.cc:40
#define SLOW_DCHECK(condition)
Definition checks.h:21
SourcePosition pos
static uint16_t LeadSurrogate(uint32_t char_code)
Definition unicode.h:126
static const int kNoPreviousCharacter
Definition unicode.h:102
static const uchar kMaxNonSurrogateCharCode
Definition unicode.h:116
static uint16_t TrailSurrogate(uint32_t char_code)
Definition unicode.h:129
static bool HasUnpairedSurrogate(const uint16_t *code_units, size_t length)
Definition unicode-inl.h:64
static const uchar kBadChar
Definition unicode.h:175
static unsigned Length(uchar chr, int previous)
static const unsigned kMaxEncodedSize
Definition unicode.h:178
static const unsigned kMax8BitCodeUnitSize
Definition unicode.h:193
static const unsigned kMax16BitCodeUnitSize
Definition unicode.h:190
static unsigned Encode(char *out, uchar c, int previous, bool replace_invalid=false)
Vector< T > SubVector(size_t from, size_t to) const
Definition vector.h:41
constexpr size_t size() const
Definition vector.h:70
constexpr T * begin() const
Definition vector.h:96
static constexpr int kContextOrFrameTypeOffset
static size_t DeleteForWasm(Isolate *isolate)
void store(Tagged< Object > value) const
Definition slots-inl.h:54
static V8_EXPORT_PRIVATE Tagged< Object > WaitWasm64(Isolate *isolate, DirectHandle< JSArrayBuffer > array_buffer, size_t addr, int64_t value, int64_t rel_timeout_ns)
static V8_EXPORT_PRIVATE Tagged< Object > WaitWasm32(Isolate *isolate, DirectHandle< JSArrayBuffer > array_buffer, size_t addr, int32_t value, int64_t rel_timeout_ns)
static Address c_entry_fp(ThreadLocalTop *thread)
Definition isolate.h:889
static V8_EXPORT_PRIVATE void AddProperty(Isolate *isolate, DirectHandle< JSObject > object, DirectHandle< Name > name, DirectHandle< Object > value, PropertyAttributes attributes)
V8_INLINE DirectHandle< T > ToHandleChecked() const
V8_INLINE bool is_null() const
static double NumberValue(Tagged< Number > obj)
RuntimeArgumentsWithoutHandles(int length, Address *arguments)
V8_INLINE DirectHandle< S > at(int index) const
static constexpr Tagged< Smi > FromInt(int value)
Definition smi.h:38
static constexpr Tagged< Smi > zero()
Definition smi.h:99
static constexpr int kMaxValue
Definition smi.h:101
static constexpr Type MarkerToType(intptr_t marker)
Definition frames.h:205
Address fp() const
Definition frames.h:297
base::Vector< const uint8_t > ToOneByteVector() const
Definition string.h:139
base::Vector< const base::uc16 > ToUC16Vector() const
Definition string.h:145
static void WriteToFlat(Tagged< String > source, SinkCharT *sink, uint32_t start, uint32_t length)
Definition string.cc:772
static const uint32_t kMaxLength
Definition string.h:511
static V8_INLINE HandleType< String > Flatten(Isolate *isolate, HandleType< T > string, AllocationType allocation=AllocationType::kYoung)
V8_INLINE constexpr StorageType ptr() const
constexpr bool IsCleared() const
bool GetHeapObject(Tagged< HeapObject > *result) const
constexpr bool IsWeakOrCleared() const
Tagged< HeapObject > GetHeapObjectAssumeWeak() const
constexpr V8_INLINE bool IsSmi() const
Definition tagged.h:508
static constexpr int MaxLength(uint32_t element_size_bytes)
static DirectHandle< WasmExceptionPackage > New(Isolate *isolate, DirectHandle< WasmExceptionTag > exception_tag, int encoded_size)
static bool IsWasmExternalFunction(Tagged< Object > object)
static V8_EXPORT_PRIVATE DirectHandle< JSFunction > GetOrCreateExternal(DirectHandle< WasmInternalFunction > internal)
static V8_EXPORT_PRIVATE int32_t Grow(Isolate *, DirectHandle< WasmMemoryObject >, uint32_t pages)
static MaybeDirectHandle< FixedArray > CheckBreakPoints(Isolate *, DirectHandle< Script >, int position, StackFrameId stack_frame_id)
static constexpr int kOnEntryBreakpointPosition
static DirectHandle< WasmStruct > AllocateDescriptorUninitialized(Isolate *isolate, DirectHandle< WasmTrustedInstanceData > trusted_data, wasm::ModuleTypeIndex index, DirectHandle< Map > map)
static V8_EXPORT_PRIVATE DirectHandle< Object > Get(Isolate *isolate, DirectHandle< WasmTableObject > table, uint32_t index)
static V8_EXPORT_PRIVATE void Fill(Isolate *isolate, DirectHandle< WasmTableObject > table, uint32_t start, DirectHandle< Object > entry, uint32_t count)
static V8_EXPORT_PRIVATE void Set(Isolate *isolate, DirectHandle< WasmTableObject > table, uint32_t index, DirectHandle< Object > entry)
static V8_EXPORT_PRIVATE int Grow(Isolate *isolate, DirectHandle< WasmTableObject > table, uint32_t count, DirectHandle< Object > init_value)
static DirectHandle< WasmFuncRef > GetOrCreateFuncRef(Isolate *isolate, DirectHandle< WasmTrustedInstanceData > trusted_instance_data, int function_index)
static std::optional< MessageTemplate > InitTableEntries(Isolate *isolate, DirectHandle< WasmTrustedInstanceData > trusted_instance_data, DirectHandle< WasmTrustedInstanceData > shared_trusted_instance_data, uint32_t table_index, uint32_t segment_index, uint32_t dst, uint32_t src, uint32_t count) V8_WARN_UNUSED_RESULT
static bool CopyTableEntries(Isolate *isolate, DirectHandle< WasmTrustedInstanceData > trusted_instance_data, uint32_t table_dst_index, uint32_t table_src_index, uint32_t dst, uint32_t src, uint32_t count) V8_WARN_UNUSED_RESULT
static constexpr CanonicalValueType FromRawBitField(uint32_t bits)
std::pair< WasmOpcode, uint32_t > read_prefixed_opcode(const uint8_t *pc, Name< ValidationTag > name="prefixed opcode")
Definition decoder.h:202
static DirectHandle< Code > CompileJSToWasmWrapper(Isolate *isolate, const CanonicalSig *sig, CanonicalTypeIndex sig_index)
CanonicalTypeIndex FindIndex_Slow(const CanonicalSig *sig) const
static constexpr CanonicalTypeIndex kPredefinedArrayI16Index
V8_EXPORT_PRIVATE const CanonicalSig * LookupFunctionSignature(CanonicalTypeIndex index) const
static constexpr CanonicalTypeIndex kPredefinedArrayI8Index
constexpr int value_kind_size() const
Definition value-type.h:485
constexpr bool is_reference() const
Definition value-type.h:600
constexpr bool is_numeric() const
Definition value-type.h:373
static void SetRuntimeLastWasmError(Isolate *isolate, MessageTemplate message)
static constexpr bool IsPrefixOpcode(WasmOpcode)
DataViewOp
int start
int end
LineAndColumn current
LineAndColumn previous
#define RUNTIME_FUNCTION(Name)
Definition arguments.h:162
#define THROW_NEW_ERROR_RETURN_FAILURE(isolate, call)
Definition isolate.h:294
#define RETURN_RESULT_OR_FAILURE(isolate, call)
Definition isolate.h:264
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
SourcePositionTable * source_positions
int32_t offset
std::map< const std::string, const std::string > map
ZoneVector< RpoNumber > & result
FunctionLiteral * literal
Definition liveedit.cc:294
InstructionOperand source
Utf8Variant
Definition unicode.h:145
constexpr bool IsInBounds(T index, T length, T max)
Definition bounds.h:49
constexpr bool IsInRange(T value, U lower_limit, U higher_limit)
Definition bounds.h:20
uint16_t uc16
Definition strings.h:18
constexpr Vector< T > VectorOf(T *start, size_t size)
Definition vector.h:360
TH_DISABLE_ASAN bool IsThreadInWasm()
void TierUpNowForTesting(Isolate *isolate, Tagged< WasmTrustedInstanceData > trusted_instance_data, int func_index)
WasmImportWrapperCache * GetWasmImportWrapperCache()
std::optional< MessageTemplate > InitializeElementSegment(Zone *zone, Isolate *isolate, DirectHandle< WasmTrustedInstanceData > trusted_instance_data, DirectHandle< WasmTrustedInstanceData > shared_trusted_instance_data, uint32_t segment_index)
void TriggerTierUp(Isolate *isolate, Tagged< WasmTrustedInstanceData > trusted_instance_data, int func_index)
constexpr IndependentValueType kWasmI8
int JumpTableOffset(const WasmModule *module, int func_index)
TypeCanonicalizer * GetTypeCanonicalizer()
void ThrowLazyCompilationError(Isolate *isolate, const NativeModule *native_module, int func_index)
int declared_function_index(const WasmModule *module, int func_index)
constexpr size_t kV8MaxWasmTableSize
Definition wasm-limits.h:58
constexpr size_t kV8MaxWasmStringLiterals
Definition wasm-limits.h:69
bool CompileLazy(Isolate *isolate, Tagged< WasmTrustedInstanceData > trusted_instance_data, int func_index)
MessageTemplate MessageTemplateFromInt(int message_id)
constexpr const char * ToString(DeoptimizeKind kind)
Definition globals.h:880
PerThreadAssertScopeDebugOnly< false, SAFEPOINTS_ASSERT, HEAP_ALLOCATION_ASSERT > DisallowGarbageCollection
@ UPDATE_WRITE_BARRIER
Definition objects.h:55
Tagged< T > MakeStrong(Tagged< T > value)
Definition tagged.h:903
bool IsNumber(Tagged< Object > obj)
Tagged(T object) -> Tagged< T >
kWasmInternalFunctionIndirectPointerTag instance_data
V8_INLINE constexpr bool IsSmi(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:665
kStaticElementsTemplateOffset kInstancePropertiesTemplateOffset Tagged< FixedArray >
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
kWasmInternalFunctionIndirectPointerTag kProtectedInstanceDataOffset sig
V8_EXPORT_PRIVATE void MemMove(void *dest, const void *src, size_t size)
Definition memcopy.h:189
uint32_t NumberToUint32(Tagged< Object > number)
typename detail::FlattenUnionHelper< Union<>, Ts... >::type UnionOf
Definition union.h:123
int32_t NumberToInt32(Tagged< Object > number)
Tagged< MaybeWeak< T > > MakeWeak(Tagged< T > value)
Definition tagged.h:893
void CopyChars(DstType *dst, const SrcType *src, size_t count) V8_NONNULL(1
const int kSmiValueSize
V8_EXPORT_PRIVATE FlagValues v8_flags
void ToUtf8Lossy(Isolate *isolate, DirectHandle< String > string, std::string &out)
return value
Definition map-inl.h:893
const int kSmiMaxValue
static constexpr Address kNullAddress
Definition v8-internal.h:53
constexpr int kMaxInt
Definition globals.h:374
void MemCopy(void *dest, const void *src, size_t size)
Definition memcopy.h:124
constexpr uint32_t kMaxUInt32
Definition globals.h:387
template const char * string
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
const size_t segment_offset
StackFrameIterator frame_iterator_
#define RETURN_RESULT_OR_TRAP(call)
const bool is_thread_in_wasm_
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define DCHECK_GT(v1, v2)
Definition logging.h:487
#define USE(...)
Definition macros.h:293
#define arraysize(array)
Definition macros.h:67
std::vector< FrameSummary > frames
Definition frames.h:631
std::vector< WasmExport > export_table
CanonicalTypeIndex canonical_sig_id(ModuleTypeIndex index) const
#define TRACE_EVENT1(category_group, name, arg1_name, arg1_val)
#define V8_INLINE
Definition v8config.h:500
#define V8_UNLIKELY(condition)
Definition v8config.h:660
#define V8_NODISCARD
Definition v8config.h:693
#define ZONE_NAME
Definition zone.h:22