v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
wrappers.cc
Go to the documentation of this file.
1// Copyright 2024 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 <bit>
6#include <optional>
7
20#include "src/zone/zone.h"
21
22namespace v8::internal::wasm {
23
25
26using compiler::CallDescriptor;
27using compiler::Operator;
28using compiler::turboshaft::ConditionWithHint;
31using compiler::turboshaft::Label;
32using compiler::turboshaft::LoadOp;
33using compiler::turboshaft::MemoryRepresentation;
34using TSBlock = compiler::turboshaft::Block;
35using compiler::turboshaft::OpEffects;
38using compiler::turboshaft::RegisterRepresentation;
39using compiler::turboshaft::StoreOp;
40using compiler::turboshaft::TSCallDescriptor;
41using compiler::turboshaft::Tuple;
42using compiler::turboshaft::V;
46
47namespace {
48const TSCallDescriptor* GetBuiltinCallDescriptor(Builtin name, Zone* zone) {
49 CallInterfaceDescriptor interface_descriptor =
51 CallDescriptor* call_desc = compiler::Linkage::GetStubCallDescriptor(
52 zone, // zone
53 interface_descriptor, // descriptor
54 interface_descriptor.GetStackParameterCount(), // stack parameter count
57 StubCallMode::kCallBuiltinPointer); // stub call mode
60}
61} // namespace
62
64 public:
66 const CanonicalSig* sig)
67 : WasmGraphBuilderBase(zone, assembler), sig_(sig) {}
68
70 if (!v8_flags.debug_code) return;
72 V<Number> message_id =
73 __ NumberConstant(static_cast<int32_t>(abort_reason));
74 CallRuntime(__ phase_zone(), Runtime::kAbort, {message_id},
75 __ NoContextConstant());
76 }
77 }
78
109
111 return __ Load(exported_function_data,
112 LoadOp::Kind::TaggedBase().Immutable(),
114 WasmExportedFunctionData::kFunctionIndexOffset);
115 }
116
118 // With pointer compression, only the lower 32 bits are used.
120 ? __ BitcastWord32ToWord64(__ Word32ShiftLeft(
122 : __ Word64ShiftLeft(__ ChangeInt32ToInt64(value),
124 }
125
130
131 template <typename Descriptor, typename... Args>
133 Operator::Properties properties, Args... args) {
134 auto call_descriptor = compiler::Linkage::GetStubCallDescriptor(
135 __ graph_zone(), Descriptor(), 0,
139 const TSCallDescriptor* ts_call_descriptor = TSCallDescriptor::Create(
140 call_descriptor, compiler::CanThrow::kNo,
142 V<WordPtr> call_target = GetTargetForBuiltinCall(name);
143 return __ Call(call_target, frame_state, base::VectorOf({args...}),
144 ts_call_descriptor);
145 }
146
147 template <typename Descriptor, typename... Args>
149 Args... args) {
150 auto call_descriptor = compiler::Linkage::GetStubCallDescriptor(
153 const TSCallDescriptor* ts_call_descriptor = TSCallDescriptor::Create(
154 call_descriptor, compiler::CanThrow::kNo,
156 V<WordPtr> call_target = GetTargetForBuiltinCall(name);
157 return __ Call(call_target, {args...}, ts_call_descriptor);
158 }
159
161 // We expect most integers at runtime to be Smis, so it is important for
162 // wrapper performance that Smi conversion be inlined.
163 if (SmiValuesAre32Bits()) {
164 return BuildChangeInt32ToSmi(value);
165 }
167
168 // Double value to test if value can be a Smi, and if so, to convert it.
169 V<Tuple<Word32, Word32>> add = __ Int32AddCheckOverflow(value, value);
170 V<Word32> ovf = __ template Projection<1>(add);
172 IF_NOT (UNLIKELY(ovf)) {
173 // If it didn't overflow, the result is {2 * value} as pointer-sized
174 // value.
175 result = __ BitcastWordPtrToSmi(
176 __ ChangeInt32ToIntPtr(__ template Projection<0>(add)));
177 } ELSE{
178 // Otherwise, call builtin, to convert to a HeapNumber.
180 Builtin::kWasmInt32ToHeapNumber, Operator::kNoProperties, value);
181 }
182 return result;
183 }
184
187 Builtin::kWasmFloat32ToNumber, Operator::kNoProperties, value);
188 }
189
192 Builtin::kWasmFloat64ToNumber, Operator::kNoProperties, value);
193 }
194
196 switch (type.kind()) {
197 case kI32:
198 return BuildChangeInt32ToNumber(ret);
199 case kI64:
201 case kF32:
202 return BuildChangeFloat32ToNumber(ret);
203 case kF64:
204 return BuildChangeFloat64ToNumber(ret);
205 case kRef:
206 switch (type.heap_representation_non_shared()) {
207 case HeapType::kEq:
208 case HeapType::kI31:
210 case HeapType::kArray:
211 case HeapType::kAny:
214 case HeapType::kNone:
217 return ret;
218 case HeapType::kExn:
219 case HeapType::kNoExn:
221 case HeapType::kTop:
225 UNREACHABLE();
226 case HeapType::kFunc:
227 default:
228 if (type.heap_representation_non_shared() == HeapType::kFunc ||
229 GetTypeCanonicalizer()->IsFunctionSignature(type.ref_index())) {
230 // Function reference. Extract the external function.
232 V<WasmInternalFunction>::Cast(__ LoadTrustedPointerField(
234 kWasmInternalFunctionIndirectPointerTag,
235 WasmFuncRef::kTrustedInternalOffset));
236 ScopedVar<Object> maybe_external(
239 WasmInternalFunction::kExternalOffset));
240 IF (__ TaggedEqual(maybe_external, LOAD_ROOT(UndefinedValue))) {
241 maybe_external =
243 Builtin::kWasmInternalFunctionCreateExternal,
245 }
246 return maybe_external;
247 } else {
248 return ret;
249 }
250 }
251 case kRefNull:
252 switch (type.heap_representation_non_shared()) {
255 return ret;
256 case HeapType::kNone:
258 return LOAD_ROOT(NullValue);
259 case HeapType::kExn:
260 case HeapType::kNoExn:
261 UNREACHABLE();
262 case HeapType::kEq:
264 case HeapType::kArray:
266 case HeapType::kI31:
267 case HeapType::kAny: {
269 IF_NOT (__ TaggedEqual(ret, LOAD_ROOT(WasmNull))) {
270 result = ret;
271 } ELSE{
272 result = LOAD_ROOT(NullValue);
273 }
274 return result;
275 }
276 case HeapType::kFunc:
277 default: {
278 if (type.heap_representation_non_shared() == HeapType::kFunc ||
279 GetTypeCanonicalizer()->IsFunctionSignature(type.ref_index())) {
281 IF (__ TaggedEqual(ret, LOAD_ROOT(WasmNull))) {
282 result = LOAD_ROOT(NullValue);
283 } ELSE{
285 V<WasmInternalFunction>::Cast(__ LoadTrustedPointerField(
287 kWasmInternalFunctionIndirectPointerTag,
288 WasmFuncRef::kTrustedInternalOffset));
289 V<Object> maybe_external =
292 WasmInternalFunction::kExternalOffset);
293 IF (__ TaggedEqual(maybe_external, LOAD_ROOT(UndefinedValue))) {
294 V<Object> from_builtin =
296 Builtin::kWasmInternalFunctionCreateExternal,
298 result = from_builtin;
299 } ELSE{
300 result = maybe_external;
301 }
302 }
303 return result;
304 } else {
306 IF (__ TaggedEqual(ret, LOAD_ROOT(WasmNull))) {
307 result = LOAD_ROOT(NullValue);
308 } ELSE{
309 result = ret;
310 }
311 return result;
312 }
313 }
314 }
315 case kI8:
316 case kI16:
317 case kF16:
318 case kS128:
319 case kVoid:
320 case kTop:
321 case kBottom:
322 // If this is reached, then IsJSCompatibleSignature() is too permissive.
323 UNREACHABLE();
324 }
325 }
326
327 // Generate a call to the AllocateJSArray builtin.
329 V<Object> context) {
330 // Since we don't check that args will fit in an array,
331 // we make sure this is true based on statically known limits.
332 static_assert(kV8MaxWasmFunctionReturns <=
335 Builtin::kWasmAllocateJSArray, Operator::kEliminatable, array_length,
336 context);
337 }
338
340 V<Word32> callee,
341 V<HeapObject> implicit_first_arg,
343 base::Vector<OpIndex> returns) {
344 const TSCallDescriptor* descriptor = TSCallDescriptor::Create(
346 __ graph_zone(), sig,
349 __ graph_zone());
350
351 args[0] = implicit_first_arg;
353 descriptor, OpEffects().CanCallAnything());
354
355 if (sig->return_count() == 1) {
356 returns[0] = call;
357 } else if (sig->return_count() > 1) {
358 for (uint32_t i = 0; i < sig->return_count(); i++) {
359 CanonicalValueType type = sig->GetReturn(i);
360 returns[i] = __ Projection(call, i, RepresentationFor(type));
361 }
362 }
363 }
364
366 base::Vector<OpIndex> args, bool do_conversion,
367 bool set_in_wasm_flag) {
368 const int rets_count = static_cast<int>(sig_->return_count());
369 base::SmallVector<OpIndex, 1> rets(rets_count);
370
371 // Set the ThreadInWasm flag before we do the actual call.
372 {
373 std::optional<ModifyThreadInWasmFlagScope>
374 modify_thread_in_wasm_flag_builder;
375 if (set_in_wasm_flag) {
376 modify_thread_in_wasm_flag_builder.emplace(this, Asm());
377 }
378
380 V<WasmInternalFunction>::Cast(__ LoadProtectedPointerField(
381 function_data, LoadOp::Kind::TaggedBase().Immutable(),
382 WasmExportedFunctionData::kProtectedInternalOffset));
383 auto [target, implicit_arg] = BuildFunctionTargetAndImplicitArg(internal);
384 BuildCallWasmFromWrapper(__ phase_zone(), sig_, target, implicit_arg,
385 args, base::VectorOf(rets));
386 }
387
388 V<Object> jsval;
389 if (sig_->return_count() == 0) {
390 jsval = LOAD_ROOT(UndefinedValue);
391 } else if (sig_->return_count() == 1) {
392 jsval = do_conversion ? ToJS(rets[0], sig_->GetReturn(), js_context)
393 : rets[0];
394 } else {
395 int32_t return_count = static_cast<int32_t>(sig_->return_count());
396 V<Smi> size = __ SmiConstant(Smi::FromInt(return_count));
397
398 jsval = BuildCallAllocateJSArray(size, js_context);
399
400 V<FixedArray> fixed_array = __ Load(jsval, LoadOp::Kind::TaggedBase(),
402 JSObject::kElementsOffset);
403
404 for (int i = 0; i < return_count; ++i) {
405 V<Object> value = ToJS(rets[i], sig_->GetReturn(i), js_context);
406 __ StoreFixedArrayElement(fixed_array, i, value,
408 }
409 }
410 return jsval;
411 }
412
414 bool do_conversion = true,
417 bool set_in_wasm_flag = true) {
418 const int wasm_param_count = static_cast<int>(sig_->parameter_count());
419
420 __ Bind(__ NewBlock());
421
422 // Create the js_closure and js_context parameters.
423 V<JSFunction> js_closure =
426 V<Context> js_context = __ Parameter(
429 V<SharedFunctionInfo> shared =
430 __ Load(js_closure, LoadOp::Kind::TaggedBase(),
432 JSFunction::kSharedFunctionInfoOffset);
433 V<WasmFunctionData> function_data =
434 V<WasmFunctionData>::Cast(__ LoadTrustedPointerField(
435 shared, LoadOp::Kind::TaggedBase(),
436 kWasmFunctionDataIndirectPointerTag,
437 SharedFunctionInfo::kTrustedFunctionDataOffset));
438
440 // Throw a TypeError. Use the js_context of the calling javascript
441 // function (passed as a parameter), such that the generated code is
442 // js_context independent.
443 CallRuntime(__ phase_zone(), Runtime::kWasmThrowJSTypeError, {},
444 js_context);
445 __ Unreachable();
446 return;
447 }
448
449 const int args_count = wasm_param_count + 1; // +1 for wasm_code.
450
451 // Check whether the signature of the function allows for a fast
452 // transformation (if any params exist that need transformation).
453 // Create a fast transformation path, only if it does.
454 bool include_fast_path =
455 do_conversion && wasm_param_count > 0 && QualifiesForFastTransform();
456
457 // Prepare Param() nodes. Param() nodes can only be created once,
458 // so we need to use the same nodes along all possible transformation paths.
459 base::SmallVector<OpIndex, 16> params(args_count);
460 for (int i = 0; i < wasm_param_count; ++i) {
461 params[i + 1] = __ Parameter(i + 1, RegisterRepresentation::Tagged());
462 }
463
464 Label<Object> done(&Asm());
465 V<Object> jsval;
466 if (include_fast_path) {
467 TSBlock* slow_path = __ NewBlock();
468 // Check if the params received on runtime can be actually transformed
469 // using the fast transformation. When a param that cannot be transformed
470 // fast is encountered, skip checking the rest and fall back to the slow
471 // path.
472 for (int i = 0; i < wasm_param_count; ++i) {
473 CanTransformFast(params[i + 1], sig_->GetParam(i), slow_path);
474 }
475 // Convert JS parameters to wasm numbers using the fast transformation
476 // and build the call.
478 for (int i = 0; i < wasm_param_count; ++i) {
479 OpIndex wasm_param = FromJSFast(params[i + 1], sig_->GetParam(i));
480 args[i + 1] = wasm_param;
481 }
482 jsval =
483 BuildCallAndReturn(js_context, function_data, base::VectorOf(args),
484 do_conversion, set_in_wasm_flag);
485 GOTO(done, jsval);
486 __ Bind(slow_path);
487 }
488 // Convert JS parameters to wasm numbers using the default transformation
489 // and build the call.
491 for (int i = 0; i < wasm_param_count; ++i) {
492 if (do_conversion) {
493 args[i + 1] =
494 FromJS(params[i + 1], js_context, sig_->GetParam(i), frame_state);
495 } else {
496 OpIndex wasm_param = params[i + 1];
497
498 // For Float32 parameters
499 // we set UseInfo::CheckedNumberOrOddballAsFloat64 in
500 // simplified-lowering and we need to add here a conversion from Float64
501 // to Float32.
502 if (sig_->GetParam(i).kind() == kF32) {
503 wasm_param = __ TruncateFloat64ToFloat32(wasm_param);
504 }
505 args[i + 1] = wasm_param;
506 }
507 }
508
509 jsval = BuildCallAndReturn(js_context, function_data, base::VectorOf(args),
510 do_conversion, set_in_wasm_flag);
511 // If both the default and a fast transformation paths are present,
512 // get the return value based on the path used.
513 if (include_fast_path) {
514 GOTO(done, jsval);
515 BIND(done, result);
516 __ Return(result);
517 } else {
518 __ Return(jsval);
519 }
520 }
521
522 void BuildWasmToJSWrapper(ImportCallKind kind, int expected_arity,
523 Suspend suspend) {
524 int wasm_count = static_cast<int>(sig_->parameter_count());
525
526 __ Bind(__ NewBlock());
527 base::SmallVector<OpIndex, 16> wasm_params(wasm_count);
528 OpIndex ref = __ Parameter(0, RegisterRepresentation::Tagged());
529 for (int i = 0; i < wasm_count; ++i) {
531 wasm_params[i] = (__ Parameter(1 + i, rep));
532 }
533
536 WasmImportData::kNativeContextOffset);
537
539 // =======================================================================
540 // === Runtime TypeError =================================================
541 // =======================================================================
542 CallRuntime(zone_, Runtime::kWasmThrowJSTypeError, {}, native_context);
543 __ Unreachable();
544 return;
545 }
546
547 V<Undefined> undefined_node = LOAD_ROOT(UndefinedValue);
548 int pushed_count = std::max(expected_arity, wasm_count);
549 // 5 extra arguments: receiver, new target, arg count, dispatch handle and
550 // context.
551 bool has_dispatch_handle =
553 ? false
555 base::SmallVector<OpIndex, 16> args(pushed_count + 4 +
556 (has_dispatch_handle ? 1 : 0));
558 args.size(),
559 std::numeric_limits<
561 // Position of the first wasm argument in the JS arguments.
565 for (int i = wasm_count; i < expected_arity; ++i) {
566 args[pos++] = undefined_node;
567 }
568
569 V<JSFunction> callable_node = __ Load(ref, LoadOp::Kind::TaggedBase(),
571 WasmImportData::kCallableOffset);
572 auto [old_sp, old_limit] = BuildSwitchToTheCentralStackIfNeeded();
574 OpIndex call = OpIndex::Invalid();
575 switch (kind) {
576 // =======================================================================
577 // === JS Functions ======================================================
578 // =======================================================================
580 DCHECK_EQ(expected_arity, wasm_count);
581 [[fallthrough]];
583 auto call_descriptor = compiler::Linkage::GetJSCallDescriptor(
584 __ graph_zone(), false, pushed_count + 1, CallDescriptor::kNoFlags);
585 const TSCallDescriptor* ts_call_descriptor = TSCallDescriptor::Create(
586 call_descriptor, compiler::CanThrow::kYes,
588
589 // Determine receiver at runtime.
590 args[0] =
591 BuildReceiverNode(callable_node, native_context, undefined_node);
592 DCHECK_EQ(pos, pushed_count + 1);
593 args[pos++] = undefined_node; // new target
594 args[pos++] =
595 __ Word32Constant(JSParameterCount(wasm_count)); // argument count
596#ifdef V8_JS_LINKAGE_INCLUDES_DISPATCH_HANDLE
597 args[pos++] = __ Word32Constant(kPlaceholderDispatchHandle.value());
598#endif
599 args[pos++] = LoadContextFromJSFunction(callable_node);
600 call = __ Call(callable_node, OpIndex::Invalid(), base::VectorOf(args),
601 ts_call_descriptor);
602 break;
603 }
604 // =======================================================================
605 // === General case of unknown callable ==================================
606 // =======================================================================
608 DCHECK_EQ(expected_arity, wasm_count);
609 OpIndex target = GetBuiltinPointerTarget(Builtin::kCall_ReceiverIsAny);
610 args[0] = callable_node;
611 args[1] =
612 __ Word32Constant(JSParameterCount(wasm_count)); // argument count
613 args[2] = undefined_node; // receiver
614
615 auto call_descriptor = compiler::Linkage::GetStubCallDescriptor(
616 __ graph_zone(), CallTrampolineDescriptor{}, wasm_count + 1,
619 const TSCallDescriptor* ts_call_descriptor = TSCallDescriptor::Create(
620 call_descriptor, compiler::CanThrow::kYes,
622
623 // The native_context is sufficient here, because all kind of callables
624 // which depend on the context provide their own context. The context
625 // here is only needed if the target is a constructor to throw a
626 // TypeError, if the target is a native function, or if the target is a
627 // callable JSObject, which can only be constructed by the runtime.
629 call = __ Call(target, OpIndex::Invalid(), base::VectorOf(args),
630 ts_call_descriptor);
631 break;
632 }
633 default:
635 }
636 // For asm.js the error location can differ depending on whether an
637 // exception was thrown in imported JS code or an exception was thrown in
638 // the ToNumber builtin that converts the result of the JS code a
639 // WebAssembly value. The source position allows asm.js to determine the
640 // correct error location. Source position 1 encodes the call to ToNumber,
641 // source position 0 encodes the call to the imported JS code.
642 __ output_graph().source_positions()[call] = SourcePosition(0);
643 DCHECK(call.valid());
644
645 if (suspend == kSuspend) {
646 call = BuildSuspend(call, ref, &old_sp, old_limit);
647 }
648
649 // Convert the return value(s) back.
650 OpIndex val;
652 if (sig_->return_count() <= 1) {
653 val = sig_->return_count() == 0
654 ? __ Word32Constant(0)
655 : FromJS(call, native_context, sig_->GetReturn());
656 } else {
657 V<FixedArray> fixed_array =
659 wasm_values.resize(sig_->return_count());
660 for (unsigned i = 0; i < sig_->return_count(); ++i) {
661 wasm_values[i] = FromJS(__ LoadFixedArrayElement(fixed_array, i),
662 native_context, sig_->GetReturn(i));
663 }
664 }
666 BuildSwitchBackFromCentralStack(old_sp, old_limit);
667 if (sig_->return_count() <= 1) {
668 __ Return(val);
669 } else {
670 __ Return(__ Word32Constant(0), base::VectorOf(wasm_values));
671 }
672 }
673
675 __ Bind(__ NewBlock());
676 base::SmallVector<OpIndex, 8> incoming_params;
677 // Instance.
678 incoming_params.push_back(
679 __ Parameter(0, RegisterRepresentation::Tagged()));
680 // Wasm parameters.
681 for (int i = 0; i < static_cast<int>(sig_->parameter_count()); ++i) {
682 incoming_params.push_back(
683 __ Parameter(i + 1, RepresentationFor(sig_->GetParam(i))));
684 }
685 // Store arguments on our stack, then align the stack for calling to C.
686 int param_bytes = 0;
687 for (CanonicalValueType type : sig_->parameters()) {
688 param_bytes += type.value_kind_size();
689 }
690 int return_bytes = 0;
691 for (CanonicalValueType type : sig_->returns()) {
692 return_bytes += type.value_kind_size();
693 }
694
695 int stack_slot_bytes = std::max(param_bytes, return_bytes);
696 OpIndex values = stack_slot_bytes == 0
697 ? __ IntPtrConstant(0)
698 : __ StackSlot(stack_slot_bytes, kDoubleAlignment);
699
700 int offset = 0;
701 for (size_t i = 0; i < sig_->parameter_count(); ++i) {
702 CanonicalValueType type = sig_->GetParam(i);
703 // Start from the parameter with index 1 to drop the instance_node.
704 // TODO(jkummerow): When a values is a reference type, we should pass it
705 // in a GC-safe way, not just as a raw pointer.
706 SafeStore(offset, type, values, incoming_params[i + 1]);
707 offset += type.value_kind_size();
708 }
709
710 V<Object> function_node =
711 __ LoadTaggedField(incoming_params[0], WasmImportData::kCallableOffset);
712 V<HeapObject> shared = LoadSharedFunctionInfo(function_node);
713 V<WasmFunctionData> function_data =
714 V<WasmFunctionData>::Cast(__ LoadTrustedPointerField(
715 shared, LoadOp::Kind::TaggedBase(),
716 kWasmFunctionDataIndirectPointerTag,
717 SharedFunctionInfo::kTrustedFunctionDataOffset));
718 V<Object> host_data_foreign = __ LoadTaggedField(
719 function_data, WasmCapiFunctionData::kEmbedderDataOffset);
720
722 OpIndex isolate_root = __ LoadRootRegister();
723 OpIndex fp_value = __ FramePointer();
724 __ Store(isolate_root, fp_value, StoreOp::Kind::RawAligned(),
727
728 V<WordPtr> call_target =
730
731 // Parameters: Address host_data_foreign, Address arguments.
732 auto host_sig =
735 OpIndex return_value =
736 CallC(&host_sig, call_target, {host_data_foreign, values});
737
739
740 IF_NOT (__ WordPtrEqual(return_value, __ IntPtrConstant(0))) {
741 WasmRethrowExplicitContextDescriptor interface_descriptor;
742 auto call_descriptor = compiler::Linkage::GetStubCallDescriptor(
743 __ graph_zone(), interface_descriptor,
744 interface_descriptor.GetStackParameterCount(),
747 const TSCallDescriptor* ts_call_descriptor = TSCallDescriptor::Create(
748 call_descriptor, compiler::CanThrow::kYes,
750 OpIndex rethrow_call_target =
751 GetTargetForBuiltinCall(Builtin::kWasmRethrowExplicitContext);
752 V<Context> context =
753 __ Load(incoming_params[0], LoadOp::Kind::TaggedBase(),
755 WasmImportData::kNativeContextOffset);
756 __ Call(rethrow_call_target, {return_value, context}, ts_call_descriptor);
757 __ Unreachable();
758 }
759
760 DCHECK_LT(sig_->return_count(), kV8MaxWasmFunctionReturns);
761 size_t return_count = sig_->return_count();
762 if (return_count == 0) {
763 __ Return(__ Word32Constant(0));
764 } else {
765 base::SmallVector<OpIndex, 8> returns(return_count);
766 offset = 0;
767 for (size_t i = 0; i < return_count; ++i) {
768 CanonicalValueType type = sig_->GetReturn(i);
769 OpIndex val = SafeLoad(values, offset, type);
770 returns[i] = val;
771 offset += type.value_kind_size();
772 }
773 __ Return(__ Word32Constant(0), base::VectorOf(returns));
774 }
775 }
776
778 return __ Word32Constant(kSmiShiftSize + kSmiTagSize);
779 }
780
782 return __ Word32Constant(kSmiShiftSize + kSmiTagSize);
783 }
784
787 ? __ Word32ShiftRightArithmetic(value,
789 : __
790 TruncateWordPtrToWord32(__ WordPtrShiftRightArithmetic(
791 value, BuildSmiShiftBitsConstant()));
792 }
793
795 return __ template LoadField<Float64>(
797 }
798
800 switch (type.kind()) {
801 case kI32:
802 return BuildChangeSmiToInt32(input);
803 case kF32: {
805 IF (__ IsSmi(input)) {
806 result = __ ChangeInt32ToFloat32(__ UntagSmi(input));
807 } ELSE {
808 result = __ TruncateFloat64ToFloat32(HeapNumberToFloat64(input));
809 }
810 return result;
811 }
812 case kF64: {
814 IF (__ IsSmi(input)) {
815 result = __ ChangeInt32ToFloat64(__ UntagSmi(input));
816 } ELSE{
818 }
819 return result;
820 }
821 case kRef:
822 case kRefNull:
823 case kI64:
824 case kS128:
825 case kI8:
826 case kI16:
827 case kF16:
828 case kTop:
829 case kBottom:
830 case kVoid:
831 UNREACHABLE();
832 }
833 }
834
836 return __ Load(map, LoadOp::Kind::TaggedBase().Immutable(),
837 MemoryRepresentation::Uint16(), Map::kInstanceTypeOffset);
838 }
839
841 CanonicalValueType type) {
842 auto done = __ NewBlock();
843 auto type_error = __ NewBlock();
845 __ GotoIf(__ IsSmi(input), type_error, BranchHint::kFalse);
846 if (type.is_nullable()) {
847 auto not_null = __ NewBlock();
848 __ GotoIfNot(__ TaggedEqual(input, LOAD_ROOT(NullValue)), not_null);
849 __ Goto(done);
850 __ Bind(not_null);
851 }
852 V<Map> map = LoadMap(input);
853 OpIndex instance_type = LoadInstanceType(map);
854 OpIndex check = __ Uint32LessThan(instance_type,
855 __ Word32Constant(FIRST_NONSTRING_TYPE));
856 result = input;
857 __ GotoIf(check, done, BranchHint::kTrue);
858 __ Goto(type_error);
859 __ Bind(type_error);
860 CallRuntime(__ phase_zone(), Runtime::kWasmThrowJSTypeError, {},
861 js_context);
862 __ Unreachable();
863 __ Bind(done);
864 return result;
865 }
866
868 OpIndex value, OpIndex context,
870 OpIndex call = frame_state.valid()
872 Builtin::kWasmTaggedToFloat64, frame_state.value(),
873 Operator::kNoProperties, value, context)
875 Builtin::kWasmTaggedToFloat64,
876 Operator::kNoProperties, value, context);
877 // The source position here is needed for asm.js, see the comment on the
878 // source position of the call to JavaScript in the wasm-to-js wrapper.
879 __ output_graph().source_positions()[call] = SourcePosition(1);
880 return call;
881 }
882
884 OpIndex value, OpIndex context,
886 // We expect most integers at runtime to be Smis, so it is important for
887 // wrapper performance that Smi conversion be inlined.
889 IF (__ IsSmi(value)) {
891 } ELSE{
892 OpIndex call =
893 frame_state.valid()
895 Builtin::kWasmTaggedNonSmiToInt32, frame_state.value(),
896 Operator::kNoProperties, value, context)
898 Builtin::kWasmTaggedNonSmiToInt32, Operator::kNoProperties,
899 value, context);
900 result = call;
901 // The source position here is needed for asm.js, see the comment on the
902 // source position of the call to JavaScript in the wasm-to-js wrapper.
903 __ output_graph().source_positions()[call] = SourcePosition(1);
904 }
905 return result;
906 }
907
910 needs_frame_state);
911 }
912
914 OpIndex input, OpIndex context,
917 if (Is64()) {
918 target = GetTargetForBuiltinCall(Builtin::kBigIntToI64);
919 } else {
920 // On 32-bit platforms we already set the target to the
921 // BigIntToI32Pair builtin here, so that we don't have to replace the
922 // target in the int64-lowering.
923 target = GetTargetForBuiltinCall(Builtin::kBigIntToI32Pair);
924 }
925
926 CallDescriptor* call_descriptor =
927 GetBigIntToI64CallDescriptor(frame_state.valid());
928 const TSCallDescriptor* ts_call_descriptor = TSCallDescriptor::Create(
929 call_descriptor, compiler::CanThrow::kNo,
931 return frame_state.valid()
932 ? __ Call(target, frame_state.value(),
933 base::VectorOf({input, context}), ts_call_descriptor)
934 : __ Call(target, {input, context}, ts_call_descriptor);
935 }
936
938 OptionalOpIndex frame_state = {}) {
939 switch (type.kind()) {
940 case kRef:
941 case kRefNull: {
942 switch (type.heap_representation_non_shared()) {
943 // TODO(14034): Add more fast paths?
945 if (type.kind() == kRef) {
946 IF (UNLIKELY(__ TaggedEqual(input, LOAD_ROOT(NullValue)))) {
947 CallRuntime(__ phase_zone(), Runtime::kWasmThrowJSTypeError, {},
948 context);
949 __ Unreachable();
950 }
951 }
952 return input;
954 return BuildCheckString(input, context, type);
955 case HeapType::kExn:
956 case HeapType::kNoExn: {
957 UNREACHABLE();
958 }
960 case HeapType::kNone:
962 case HeapType::kI31:
963 case HeapType::kAny:
964 case HeapType::kFunc:
966 case HeapType::kArray:
967 case HeapType::kEq:
968 default: {
969 // Make sure ValueType fits in a Smi.
970 static_assert(ValueType::kLastUsedBit + 1 <= kSmiValueSize);
971
972 std::initializer_list<const OpIndex> inputs = {
973 input, __ IntPtrConstant(
974 IntToSmi(static_cast<int>(type.raw_bit_field())))};
975 return CallRuntime(__ phase_zone(), Runtime::kWasmJSToWasmObject,
976 inputs, context);
977 }
978 }
979 }
980 case kF32:
981 return __ TruncateFloat64ToFloat32(
982 BuildChangeTaggedToFloat64(input, context, frame_state));
983
984 case kF64:
985 return BuildChangeTaggedToFloat64(input, context, frame_state);
986
987 case kI32:
988 return BuildChangeTaggedToInt32(input, context, frame_state);
989
990 case kI64:
991 // i64 values can only come from BigInt.
992 return BuildChangeBigIntToInt64(input, context, frame_state);
993
994 case kS128:
995 case kI8:
996 case kI16:
997 case kF16:
998 case kTop:
999 case kBottom:
1000 case kVoid:
1001 // If this is reached, then IsJSCompatibleSignature() is too permissive.
1002 UNREACHABLE();
1003 }
1004 }
1005
1007 const int wasm_count = static_cast<int>(sig_->parameter_count());
1008 for (int i = 0; i < wasm_count; ++i) {
1009 CanonicalValueType type = sig_->GetParam(i);
1010 switch (type.kind()) {
1011 case kRef:
1012 case kRefNull:
1013 case kI64:
1014 case kS128:
1015 case kI8:
1016 case kI16:
1017 case kF16:
1018 case kTop:
1019 case kBottom:
1020 case kVoid:
1021 return false;
1022 case kI32:
1023 case kF32:
1024 case kF64:
1025 break;
1026 }
1027 }
1028 return true;
1029 }
1030
1031#ifdef V8_MAP_PACKING
1032 V<Map> UnpackMapWord(OpIndex map_word) {
1033 map_word = __ BitcastTaggedToWordPtrForTagAndSmiBits(map_word);
1034 // TODO(wenyuzhao): Clear header metadata.
1035 OpIndex map = __ WordBitwiseXor(
1036 map_word, __ IntPtrConstant(Internals::kMapWordXorMask),
1037 WordRepresentation::UintPtr());
1038 return V<Map>::Cast(__ BitcastWordPtrToTagged(map));
1039 }
1040#endif
1041
1043 // TODO(thibaudm): Handle map packing.
1044 OpIndex map_word = __ Load(object, LoadOp::Kind::TaggedBase(),
1046#ifdef V8_MAP_PACKING
1047 return UnpackMapWord(map_word);
1048#else
1049 return map_word;
1050#endif
1051 }
1052
1054 TSBlock* slow_path) {
1055 switch (type.kind()) {
1056 case kI32: {
1057 __ GotoIfNot(LIKELY(__ IsSmi(input)), slow_path);
1058 return;
1059 }
1060 case kF32:
1061 case kF64: {
1062 TSBlock* done = __ NewBlock();
1063 __ GotoIf(__ IsSmi(input), done);
1064 V<Map> map = LoadMap(input);
1065 V<Map> heap_number_map = LOAD_ROOT(HeapNumberMap);
1066 // TODO(thibaudm): Handle map packing.
1067 V<Word32> is_heap_number = __ TaggedEqual(heap_number_map, map);
1068 __ GotoIf(LIKELY(is_heap_number), done);
1069 __ Goto(slow_path);
1070 __ Bind(done);
1071 return;
1072 }
1073 case kRef:
1074 case kRefNull:
1075 case kI64:
1076 case kS128:
1077 case kI8:
1078 case kI16:
1079 case kF16:
1080 case kTop:
1081 case kBottom:
1082 case kVoid:
1083 UNREACHABLE();
1084 }
1085 }
1086
1087 // Must be called in the first block to emit the Parameter ops.
1090 const CanonicalSig* sig, V<Context> context) {
1091 // Convert wasm numbers to JS values.
1092 for (size_t i = 0; i < wasm_params.size(); ++i) {
1093 args[pos++] = ToJS(wasm_params[i], sig->GetParam(i), context);
1094 }
1095 return pos;
1096 }
1097
1099 return __ Load(js_function, LoadOp::Kind::TaggedBase(),
1101 JSFunction::kSharedFunctionInfoOffset);
1102 }
1103
1105 V<Undefined> undefined_node) {
1106 // Check function strict bit.
1107 V<SharedFunctionInfo> shared_function_info =
1108 LoadSharedFunctionInfo(callable_node);
1109 OpIndex flags = __ Load(shared_function_info, LoadOp::Kind::TaggedBase(),
1111 SharedFunctionInfo::kFlagsOffset);
1112 OpIndex strict_check = __ Word32BitwiseAnd(
1113 flags, __ Word32Constant(SharedFunctionInfo::IsNativeBit::kMask |
1114 SharedFunctionInfo::IsStrictBit::kMask));
1115
1116 // Load global receiver if sloppy else use undefined.
1117 ScopedVar<Object> strict_d(this, OpIndex::Invalid());
1118 IF (strict_check) {
1119 strict_d = undefined_node;
1120 } ELSE {
1121 strict_d =
1122 __ LoadFixedArrayElement(native_context, Context::GLOBAL_PROXY_INDEX);
1123 }
1124 return strict_d;
1125 }
1126
1128 return __ Load(js_function, LoadOp::Kind::TaggedBase(),
1130 JSFunction::kContextOffset);
1131 }
1132
1134 V<WordPtr>* old_sp, V<WordPtr> old_limit) {
1135 // If value is a promise, suspend to the js-to-wasm prompt, and resume later
1136 // with the promise's resolved value.
1137 ScopedVar<Object> result(this, value);
1138 ScopedVar<WordPtr> old_sp_var(this, *old_sp);
1139
1142 WasmImportData::kNativeContextOffset);
1143
1144 OpIndex promise_ctor = __ LoadFixedArrayElement(
1145 native_context, Context::PROMISE_FUNCTION_INDEX);
1146
1147 OpIndex promise_resolve = GetBuiltinPointerTarget(Builtin::kPromiseResolve);
1148 auto* resolve_call_desc =
1149 GetBuiltinCallDescriptor(Builtin::kPromiseResolve, __ graph_zone());
1150 base::SmallVector<OpIndex, 16> resolve_args{promise_ctor, value,
1152 OpIndex promise = __ Call(promise_resolve, OpIndex::Invalid(),
1153 base::VectorOf(resolve_args), resolve_call_desc);
1154
1155 OpIndex suspender = LOAD_ROOT(ActiveSuspender);
1156 IF (__ TaggedEqual(suspender, LOAD_ROOT(UndefinedValue))) {
1157 V<Smi> error = __ SmiConstant(Smi::FromInt(
1158 static_cast<int32_t>(MessageTemplate::kWasmSuspendError)));
1159 CallRuntime(__ phase_zone(), Runtime::kThrowWasmSuspendError, {error},
1161 __ Unreachable();
1162 }
1163 if (v8_flags.stress_wasm_stack_switching) {
1164 V<Word32> for_stress_testing = __ TaggedEqual(
1165 __ LoadTaggedField(suspender, WasmSuspenderObject::kResumeOffset),
1166 LOAD_ROOT(UndefinedValue));
1167 IF (for_stress_testing) {
1168 V<Smi> error = __ SmiConstant(Smi::FromInt(
1169 static_cast<int32_t>(MessageTemplate::kWasmSuspendJSFrames)));
1170 CallRuntime(__ phase_zone(), Runtime::kThrowWasmSuspendError, {error},
1172 __ Unreachable();
1173 }
1174 }
1175 // If {old_sp} is null, it must be that we were on the central stack
1176 // before entering the wasm-to-js wrapper, which means that there are JS
1177 // frames in the current suspender. JS frames cannot be suspended, so
1178 // trap.
1179 OpIndex has_js_frames = __ WordPtrEqual(__ IntPtrConstant(0), *old_sp);
1180 IF (has_js_frames) {
1181 V<Smi> error = __ SmiConstant(Smi::FromInt(
1182 static_cast<int32_t>(MessageTemplate::kWasmSuspendJSFrames)));
1183 CallRuntime(__ phase_zone(), Runtime::kThrowWasmSuspendError, {error},
1185 __ Unreachable();
1186 }
1187 V<Object> on_fulfilled = __ Load(suspender, LoadOp::Kind::TaggedBase(),
1189 WasmSuspenderObject::kResumeOffset);
1190 V<Object> on_rejected = __ Load(suspender, LoadOp::Kind::TaggedBase(),
1192 WasmSuspenderObject::kRejectOffset);
1193
1194 OpIndex promise_then =
1195 GetBuiltinPointerTarget(Builtin::kPerformPromiseThen);
1196 auto* then_call_desc =
1197 GetBuiltinCallDescriptor(Builtin::kPerformPromiseThen, __ graph_zone());
1198 base::SmallVector<OpIndex, 16> args{promise, on_fulfilled, on_rejected,
1199 LOAD_ROOT(UndefinedValue),
1201 __ Call(promise_then, OpIndex::Invalid(), base::VectorOf(args),
1202 then_call_desc);
1203
1204 OpIndex suspend = GetTargetForBuiltinCall(Builtin::kWasmSuspend);
1205 auto* suspend_call_descriptor =
1206 GetBuiltinCallDescriptor(Builtin::kWasmSuspend, __ graph_zone());
1207 BuildSwitchBackFromCentralStack(*old_sp, old_limit);
1208 V<Object> resolved =
1209 __ Call<Object>(suspend, {suspender}, suspend_call_descriptor);
1210 old_sp_var = BuildSwitchToTheCentralStack(old_limit);
1211 result = resolved;
1212
1213 *old_sp = old_sp_var;
1214 return result;
1215 }
1216
1218 V<Context> context) {
1219 V<Smi> length = __ SmiConstant(Smi::FromIntptr(sig_->return_count()));
1221 Builtin::kIterableToFixedArrayForWasm, Operator::kEliminatable,
1222 iterable, length, context);
1223 }
1224
1226 OpIndex value) {
1227 int alignment = offset % type.value_kind_size();
1229 type.machine_representation());
1230 if (COMPRESS_POINTERS_BOOL && rep.IsCompressibleTagged()) {
1231 // We are storing tagged value to off-heap location, so we need to store
1232 // it as a full word otherwise we will not be able to decompress it.
1234 value = __ BitcastTaggedToWordPtr(value);
1235 }
1236 StoreOp::Kind store_kind =
1241 __ Store(base, value, store_kind, rep, compiler::kNoWriteBarrier, offset);
1242 }
1243
1245 V<WasmFunctionData> function_data) {
1246 // TODO(sroettger): this code should do a signature check, but it's only
1247 // used for CAPI.
1249 V<WasmInternalFunction>::Cast(__ LoadProtectedPointerField(
1250 function_data, LoadOp::Kind::TaggedBase().Immutable(),
1251 WasmFunctionData::kProtectedInternalOffset));
1252 V<Word32> code_pointer = __ Load(
1254 WasmInternalFunction::kRawCallTargetOffset);
1255 constexpr size_t entry_size_log2 =
1256 std::bit_width(sizeof(WasmCodePointerTableEntry)) - 1;
1257 return __ Load(
1258 __ ExternalConstant(ExternalReference::wasm_code_pointer_table()),
1259 __ ChangeUint32ToUintPtr(code_pointer), LoadOp::Kind::RawAligned(),
1260 MemoryRepresentation::UintPtr(), 0, entry_size_log2);
1261 }
1262
1264 int alignment = offset % type.value_kind_size();
1266 type.machine_representation());
1267 if (COMPRESS_POINTERS_BOOL && rep.IsCompressibleTagged()) {
1268 // We are loading tagged value from off-heap location, so we need to load
1269 // it as a full word otherwise we will not be able to decompress it.
1271 }
1272 LoadOp::Kind load_kind = alignment == 0 ||
1277 return __ Load(base, load_kind, rep, offset);
1278 }
1279
1280 private:
1281 const CanonicalSig* const sig_;
1282};
1283
1285 AccountingAllocator* allocator,
1287 const CanonicalSig* sig,
1288 WrapperCompilationInfo wrapper_info) {
1289 Zone zone(allocator, ZONE_NAME);
1290 WasmGraphBuilderBase::Assembler assembler(data, graph, graph, &zone);
1291 WasmWrapperTSGraphBuilder builder(&zone, assembler, sig);
1292 if (wrapper_info.code_kind == CodeKind::JS_TO_WASM_FUNCTION) {
1293 builder.BuildJSToWasmWrapper();
1294 } else if (wrapper_info.code_kind == CodeKind::WASM_TO_JS_FUNCTION) {
1295 builder.BuildWasmToJSWrapper(wrapper_info.import_kind,
1296 wrapper_info.expected_arity,
1297 wrapper_info.suspend);
1298 } else if (wrapper_info.code_kind == CodeKind::WASM_TO_CAPI_FUNCTION) {
1299 builder.BuildCapiCallWrapper();
1300 } else {
1301 // TODO(thibaudm): Port remaining wrappers.
1302 UNREACHABLE();
1303 }
1304}
1305
1306} // namespace v8::internal::wasm
friend Zone
Definition asm-types.cc:195
#define BIND(label)
#define ELSE
#define GOTO(label,...)
#define IF_NOT(...)
#define UNLIKELY(...)
#define LIKELY(...)
#define IF(...)
Builtins::Kind kind
Definition builtins.cc:40
#define SBXCHECK_LT(lhs, rhs)
Definition check.h:66
SourcePosition pos
size_t size() const
void resize(size_t new_size)
constexpr UnderlyingType & value() &
static CallInterfaceDescriptor CallInterfaceDescriptorFor(Builtin builtin)
Definition builtins.cc:189
auto Returns(ReturnTypes... return_types) const
Definition signature.h:166
static constexpr uint32_t thread_in_wasm_flag_address_offset()
Definition isolate.h:1338
static uint32_t c_entry_fp_offset()
Definition isolate.h:898
static const int kInitialMaxFastElementArray
Definition js-array.h:144
static constexpr MachineType Pointer()
static constexpr MachineType AnyTagged()
static constexpr Tagged< Smi > FromInt(int value)
Definition smi.h:38
static constexpr Tagged< Smi > FromIntptr(intptr_t value)
Definition smi.h:43
static constexpr int GetJSCallContextParamIndex(int parameter_count)
Definition linkage.h:495
static CallDescriptor * GetStubCallDescriptor(Zone *zone, const CallInterfaceDescriptor &descriptor, int stack_parameter_count, CallDescriptor::Flags flags, Operator::Properties properties=Operator::kNoProperties, StubCallMode stub_mode=StubCallMode::kCallCodeObject)
Definition linkage.cc:587
static constexpr int kJSCallClosureParamIndex
Definition linkage.h:504
static CallDescriptor * GetJSCallDescriptor(Zone *zone, bool is_osr, int parameter_count, CallDescriptor::Flags flags, Operator::Properties properties=Operator::kNoProperties)
Definition linkage.cc:507
compiler::CallDescriptor * GetBigIntToI64Descriptor(bool needs_frame_state)
static constexpr MemoryRepresentation FromMachineRepresentation(MachineRepresentation rep)
static constexpr MemoryRepresentation AnyTagged()
static constexpr MemoryRepresentation Uint32()
static constexpr MemoryRepresentation TaggedSigned()
static constexpr MemoryRepresentation Int32()
static constexpr MemoryRepresentation Uint16()
static constexpr MemoryRepresentation TaggedPointer()
static constexpr MemoryRepresentation UintPtr()
static constexpr OpIndex Invalid()
Definition index.h:88
static constexpr OptionalOpIndex Nullopt()
Definition index.h:171
static constexpr RegisterRepresentation WordPtr()
static constexpr RegisterRepresentation Tagged()
static bool IsUnalignedStoreSupported(MemoryRepresentation repr)
static bool IsUnalignedLoadSupported(MemoryRepresentation repr)
OpIndex Load(OpIndex base, OptionalOpIndex index, LoadOp::Kind kind, MemoryRepresentation loaded_rep, RegisterRepresentation result_rep, int32_t offset=0, uint8_t element_size_log2=0)
Definition assembler.h:2726
static V< T > Cast(V< U > index)
Definition index.h:632
compiler::WasmCallDescriptors * call_descriptors()
V< BigInt > BuildChangeInt64ToBigInt(V< Word64 > input, StubCallMode stub_mode)
RegisterRepresentation RepresentationFor(ValueTypeBase type)
V< WordPtr > BuildSwitchToTheCentralStack(V< WordPtr > old_limit)
std::pair< V< WordPtr >, V< WordPtr > > BuildSwitchToTheCentralStackIfNeeded()
V< WordPtr > GetTargetForBuiltinCall(Builtin builtin, StubCallMode stub_mode)
std::pair< V< Word32 >, V< ExposedTrustedObject > > BuildFunctionTargetAndImplicitArg(V< WasmInternalFunction > internal_function)
OpIndex CallRuntime(Zone *zone, Runtime::FunctionId f, std::initializer_list< const OpIndex > args, V< Context > context)
void BuildSwitchBackFromCentralStack(V< WordPtr > old_sp, V< WordPtr > old_limit)
void BuildModifyThreadInWasmFlagHelper(Zone *zone, OpIndex thread_in_wasm_flag_address, bool new_value)
OpIndex CallC(const MachineSignature *sig, ExternalReference ref, std::initializer_list< OpIndex > args)
void BuildModifyThreadInWasmFlag(Zone *zone, bool new_value)
ModifyThreadInWasmFlagScope(WasmWrapperTSGraphBuilder *wasm_wrapper_graph_builder, Assembler &asm_)
Definition wrappers.cc:81
ModifyThreadInWasmFlagScope(const ModifyThreadInWasmFlagScope &)=delete
OpIndex BuildChangeTaggedToInt32(OpIndex value, OpIndex context, compiler::turboshaft::OptionalOpIndex frame_state)
Definition wrappers.cc:883
OpIndex LoadSharedFunctionInfo(V< Object > js_function)
Definition wrappers.cc:1098
V< Context > LoadContextFromJSFunction(V< JSFunction > js_function)
Definition wrappers.cc:1127
OpIndex BuildReceiverNode(OpIndex callable_node, OpIndex native_context, V< Undefined > undefined_node)
Definition wrappers.cc:1104
CallDescriptor * GetBigIntToI64CallDescriptor(bool needs_frame_state)
Definition wrappers.cc:908
OpIndex CallBuiltin(Builtin name, Operator::Properties properties, Args... args)
Definition wrappers.cc:148
void AbortIfNot(V< Word32 > condition, AbortReason abort_reason)
Definition wrappers.cc:69
V< WordPtr > BuildLoadCallTargetFromExportedFunctionData(V< WasmFunctionData > function_data)
Definition wrappers.cc:1244
void BuildJSToWasmWrapper(bool do_conversion=true, compiler::turboshaft::OptionalOpIndex frame_state=compiler::turboshaft::OptionalOpIndex::Nullopt(), bool set_in_wasm_flag=true)
Definition wrappers.cc:413
V< Float64 > BuildChangeTaggedToFloat64(OpIndex value, OpIndex context, compiler::turboshaft::OptionalOpIndex frame_state)
Definition wrappers.cc:867
void BuildWasmToJSWrapper(ImportCallKind kind, int expected_arity, Suspend suspend)
Definition wrappers.cc:522
OpIndex BuildCheckString(OpIndex input, OpIndex js_context, CanonicalValueType type)
Definition wrappers.cc:840
V< Number > BuildChangeFloat64ToNumber(V< Float64 > value)
Definition wrappers.cc:190
const OpIndex SafeLoad(OpIndex base, int offset, CanonicalValueType type)
Definition wrappers.cc:1263
V< Smi > BuildChangeInt32ToSmi(V< Word32 > value)
Definition wrappers.cc:117
OpIndex FromJSFast(OpIndex input, CanonicalValueType type)
Definition wrappers.cc:799
V< Word32 > BuildChangeSmiToInt32(OpIndex value)
Definition wrappers.cc:785
int AddArgumentNodes(base::Vector< OpIndex > args, int pos, base::SmallVector< OpIndex, 16 > wasm_params, const CanonicalSig *sig, V< Context > context)
Definition wrappers.cc:1088
void CanTransformFast(OpIndex input, CanonicalValueType type, TSBlock *slow_path)
Definition wrappers.cc:1053
OpIndex BuildCallAndReturn(V< Context > js_context, V< HeapObject > function_data, base::Vector< OpIndex > args, bool do_conversion, bool set_in_wasm_flag)
Definition wrappers.cc:365
V< Number > BuildChangeFloat32ToNumber(V< Float32 > value)
Definition wrappers.cc:185
WasmWrapperTSGraphBuilder(Zone *zone, Assembler &assembler, const CanonicalSig *sig)
Definition wrappers.cc:65
V< FixedArray > BuildMultiReturnFixedArrayFromIterable(OpIndex iterable, V< Context > context)
Definition wrappers.cc:1217
OpIndex CallBuiltin(Builtin name, OpIndex frame_state, Operator::Properties properties, Args... args)
Definition wrappers.cc:132
void SafeStore(int offset, CanonicalValueType type, OpIndex base, OpIndex value)
Definition wrappers.cc:1225
V< WordPtr > GetTargetForBuiltinCall(Builtin builtin)
Definition wrappers.cc:126
V< Object > ToJS(OpIndex ret, CanonicalValueType type, V< Context > context)
Definition wrappers.cc:195
V< Number > BuildChangeInt32ToNumber(V< Word32 > value)
Definition wrappers.cc:160
OpIndex BuildChangeBigIntToInt64(OpIndex input, OpIndex context, compiler::turboshaft::OptionalOpIndex frame_state)
Definition wrappers.cc:913
void BuildCallWasmFromWrapper(Zone *zone, const CanonicalSig *sig, V< Word32 > callee, V< HeapObject > implicit_first_arg, const base::Vector< OpIndex > args, base::Vector< OpIndex > returns)
Definition wrappers.cc:339
V< Map > LoadMap(V< Object > object)
Definition wrappers.cc:1042
V< Float64 > HeapNumberToFloat64(V< HeapNumber > input)
Definition wrappers.cc:794
V< JSArray > BuildCallAllocateJSArray(V< Number > array_length, V< Object > context)
Definition wrappers.cc:328
V< Object > BuildSuspend(V< Object > value, V< Object > import_data, V< WordPtr > *old_sp, V< WordPtr > old_limit)
Definition wrappers.cc:1133
V< Smi > LoadExportedFunctionIndexAsSmi(V< Object > exported_function_data)
Definition wrappers.cc:110
OpIndex FromJS(OpIndex input, OpIndex context, CanonicalValueType type, OptionalOpIndex frame_state={})
Definition wrappers.cc:937
#define COMPRESS_POINTERS_BOOL
Definition globals.h:99
#define V8_JS_LINKAGE_INCLUDES_DISPATCH_HANDLE_BOOL
Definition globals.h:161
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
AssemblerT assembler
Zone * graph_zone
int32_t offset
TNode< Context > context
TNode< Object > target
ZoneVector< RpoNumber > & result
constexpr Vector< T > VectorOf(T *start, size_t size)
Definition vector.h:360
FloatWithBits< 32 > Float32
Definition index.h:233
WordWithBits< 32 > Word32
Definition index.h:223
std::conditional_t< Is64(), Word64, Word32 > WordPtr
Definition index.h:225
SnapshotTable< OpIndex, VariableData >::Key Variable
Definition operations.h:82
FloatWithBits< 64 > Float64
Definition index.h:234
CallDescriptor * GetBuiltinCallDescriptor(Builtin name, Zone *zone, StubCallMode stub_mode, bool needs_frame_state, Operator::Properties properties)
CallDescriptor * GetWasmCallDescriptor(Zone *zone, const Signature< T > *fsig, WasmCallKind call_kind, bool need_frame_state)
void BuildWasmWrapper(compiler::turboshaft::PipelineData *data, AccountingAllocator *allocator, compiler::turboshaft::Graph &graph, const wasm::CanonicalSig *sig, WrapperCompilationInfo)
Definition wrappers.cc:1284
TypeCanonicalizer * GetTypeCanonicalizer()
bool IsJSCompatibleSignature(const CanonicalSig *sig)
compiler::turboshaft::Block TSBlock
constexpr size_t kV8MaxWasmFunctionReturns
Definition wasm-limits.h:54
WasmEngine * GetWasmEngine()
const int kSmiTagSize
Definition v8-internal.h:87
V8_INLINE constexpr bool IsSmi(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:665
kWasmInternalFunctionIndirectPointerTag kProtectedInstanceDataOffset sig
constexpr bool SmiValuesAre31Bits()
constexpr JSDispatchHandle kPlaceholderDispatchHandle(0x0)
const int kSmiShiftSize
const int kSmiValueSize
V8_EXPORT_PRIVATE FlagValues v8_flags
constexpr int JSParameterCount(int param_count_without_receiver)
Definition globals.h:2782
constexpr bool SmiValuesAre32Bits()
return value
Definition map-inl.h:893
constexpr bool Is64()
static V8_INLINE constexpr Address IntToSmi(int value)
constexpr intptr_t kDoubleAlignment
Definition globals.h:949
!IsContextMap !IsContextMap native_context
Definition map-inl.h:877
i::Address Load(i::Address address)
Definition unwinder.cc:19
#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
static const TSCallDescriptor * Create(const CallDescriptor *descriptor, CanThrow can_throw, LazyDeoptOnThrow lazy_deopt_on_throw, Zone *graph_zone, const JSWasmCallParameters *js_wasm_call_parameters=nullptr)
#define LOAD_ROOT(name)
#define ZONE_NAME
Definition zone.h:22