v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
wasm-graph-assembler.cc
Go to the documentation of this file.
1// Copyright 2022 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
6
12#include "src/objects/string.h"
15
16namespace v8::internal::compiler {
17
18// static
20 StubCallMode stub_mode,
21 bool needs_frame_state,
22 Operator::Properties properties) {
23 CallInterfaceDescriptor interface_descriptor =
26 zone, // zone
27 interface_descriptor, // descriptor
28 interface_descriptor.GetStackParameterCount(), // stack parameter count
29 needs_frame_state ? CallDescriptor::kNeedsFrameState
30 : CallDescriptor::kNoFlags, // flags
31 properties, // properties
32 stub_mode); // stub call mode
33}
34
35// static
37 return ObjectAccess(
38 MachineType::TypeForRepresentation(type.machine_representation(),
39 !type.is_packed()),
40 type.is_reference() ? kFullWriteBarrier : kNoWriteBarrier);
41}
42
43// Sets {true_node} and {false_node} to their corresponding Branch outputs.
44// Returns the Branch node. Does not change control().
46 Node** false_node, BranchHint hint) {
47 DCHECK_NOT_NULL(cond);
48 Node* branch =
49 graph()->NewNode(mcgraph()->common()->Branch(hint), cond, control());
50 *true_node = graph()->NewNode(mcgraph()->common()->IfTrue(), branch);
51 *false_node = graph()->NewNode(mcgraph()->common()->IfFalse(), branch);
52 return branch;
53}
54
56 return mcgraph()->machine()->Is64() ? TruncateInt64ToInt32(value) : value;
57}
58
60 return mcgraph()->machine()->Is64() ? ChangeInt32ToInt64(value) : value;
61}
62
64 return mcgraph()->machine()->Is32() ? ChangeInt32ToInt64(value) : value;
65}
66
68 if (mcgraph()->machine()->Is32()) return node;
69 // Fold instances of ChangeUint32ToUint64(IntConstant) directly.
70 Uint32Matcher matcher(node);
71 if (matcher.HasResolvedValue()) {
72 uintptr_t value = matcher.ResolvedValue();
74 }
75 return ChangeUint32ToUint64(node);
76}
77
81
85
87 // With pointer compression, only the lower 32 bits are used.
88 return COMPRESS_POINTERS_BOOL ? BitcastWord32ToWord64(Word32Shl(
90 : WordShl(BuildChangeInt32ToIntPtr(value),
92}
93
100
107
109 Node* value, uint32_t maxval) {
110 DCHECK(Smi::IsValid(maxval));
111 Node* max = mcgraph()->Uint32Constant(maxval);
112 Node* check = Uint32LessThanOrEqual(value, max);
113 Node* valsmi = BuildChangeUint31ToSmi(value);
114 Node* maxsmi = NumberConstant(maxval);
115 Diamond d(graph(), mcgraph()->common(), check, BranchHint::kTrue);
116 d.Chain(control());
117 return d.Phi(MachineRepresentation::kTagged, valsmi, maxsmi);
118}
119
125
126// Helper functions for dealing with HeapObjects.
127// Rule of thumb: if access to a given field in an object is required in
128// at least two places, put a helper function here.
129
131 return Allocate(Int32Constant(size));
132}
133
135 return AddNode(graph()->NewNode(
137 effect(), control()));
138}
139
146
153
161
168
170 Node* offset) {
171 return AddNode(
172 graph()->NewNode(mcgraph()->machine()->LoadImmutable(rep), base, offset));
173}
174
176 Node* table_entry =
177 IntAdd(ExternalConstant(ExternalReference::wasm_code_pointer_table()),
178 IntMul(BuildChangeUint32ToUintPtr(code_pointer),
180 return AddNode(graph()->NewNode(
181 mcgraph()->machine()->Load(LoadRepresentation::UintPtr()), table_entry));
182}
183
185 Node* offset, Node* value) {
186 return AddNode(graph()->NewNode(simplified_.StoreToObject(access), base,
187 offset, value, effect(), control()));
188}
189
191 Node* base, Node* offset,
192 Node* value) {
193 return AddNode(
195 offset, value, effect(), control()));
196}
197
199 Node* handle, ExternalPointerTagRange tag_range, Node* isolate_root) {
200#if V8_ENABLE_SANDBOX
201 Node* index = Word32Shr(handle, Int32Constant(kExternalPointerIndexShift));
202 Node* offset = ChangeUint32ToUint64(
203 Word32Shl(index, Int32Constant(kExternalPointerTableEntrySizeLog2)));
204 Node* table;
205 if (IsSharedExternalPointerType(tag_range)) {
206 Node* table_address =
207 Load(MachineType::Pointer(), isolate_root,
208 IsolateData::shared_external_pointer_table_offset());
209 table = Load(MachineType::Pointer(), table_address,
211 } else {
212 table = Load(MachineType::Pointer(), isolate_root,
213 IsolateData::external_pointer_table_offset() +
215 }
216
217 // We don't expect to see empty fields here. If this is ever needed, consider
218 // using an dedicated empty value entry for those tags instead (i.e. an entry
219 // with the right tag and nullptr payload).
221
222 Node* entry = Load(MachineType::Pointer(), table, offset);
223 if (tag_range.Size() == 1) {
224 // The common and simple case: we expect exactly one tag.
225 Node* actual_tag = WordAnd(entry, UintPtrConstant(kExternalPointerTagMask));
226 actual_tag = TruncateInt64ToInt32(
227 WordShr(actual_tag, IntPtrConstant(kExternalPointerTagShift)));
228 Node* expected_tag = Int32Constant(tag_range.first);
229 Node* pointer = WordAnd(entry, IntPtrConstant(kExternalPointerPayloadMask));
230 auto ok = MakeLabel();
231 GotoIf(Word32Equal(actual_tag, expected_tag), &ok, BranchHint::kTrue);
232 RuntimeAbort(AbortReason::kExternalPointerTagMismatch);
233 Bind(&ok);
234 return pointer;
235 } else {
236 // Not currently supported. Implement once needed.
238 UNREACHABLE();
239 }
240#else
241 UNREACHABLE();
242#endif // V8_ENABLE_SANDBOX
243}
244
246 IndirectPointerTag tag) {
247#if V8_ENABLE_SANDBOX
249 Node* offset = ChangeUint32ToUint64(
252 IsolateData::trusted_pointer_table_offset() +
254 Node* decoded_ptr = Load(MachineType::Pointer(), table, offset);
255 // Untag the pointer and remove the marking bit in one operation.
256 decoded_ptr = WordAnd(decoded_ptr,
258 // We have to change the type of the result value to Tagged, so if the value
259 // gets spilled on the stack, it will get processed by the GC.
260 decoded_ptr = BitcastWordToTagged(decoded_ptr);
261 return decoded_ptr;
262#else
263 UNREACHABLE();
264#endif // V8_ENABLE_SANDBOX
265}
266
268 Node* object, int field_offset, ExternalPointerTagRange tag_range,
269 Node* isolate_root) {
270#ifdef V8_ENABLE_SANDBOX
271 DCHECK(!tag_range.IsEmpty());
273 wasm::ObjectAccess::ToTagged(field_offset));
274 return BuildDecodeSandboxedExternalPointer(handle, tag_range, isolate_root);
275#else
276 return LoadFromObject(MachineType::Pointer(), object,
277 wasm::ObjectAccess::ToTagged(field_offset));
278#endif // V8_ENABLE_SANDBOX
279}
280
283 return Word32Equal(Word32And(object, Int32Constant(kSmiTagMask)),
285 } else {
286 return WordEqual(WordAnd(object, IntPtrConstant(kSmiTagMask)),
288 }
289}
290
291// Maps and their contents.
293 Node* map_word =
296#ifdef V8_MAP_PACKING
297 return UnpackMapWord(map_word);
298#else
299 return map_word;
300#endif
301}
302
303void WasmGraphAssembler::StoreMap(Node* heap_object, Node* map) {
305#ifdef V8_MAP_PACKING
306 map = PackMapWord(TNode<Map>::UncheckedCast(map));
307#endif
308 InitializeImmutableInObject(access, heap_object,
310}
311
318 int offset = Map::kConstructorOrBackPointerOrNativeContextOffset;
321}
322
323// FixedArrays.
324
330
332 Node* index_intptr,
333 MachineType type) {
334 DCHECK(IsSubtype(type.representation(), MachineRepresentation::kTagged));
335 Node* offset = IntAdd(IntMul(index_intptr, IntPtrConstant(kTaggedSize)),
338 return LoadFromObject(type, fixed_array, offset);
339}
340
348
350 Node* index_intptr,
351 MachineType type) {
352 Node* offset = IntAdd(IntMul(index_intptr, IntPtrConstant(kTaggedSize)),
355 return LoadImmutableFromObject(type, fixed_array, offset);
356}
357
363
369
377
379 Node* index_intptr,
380 MachineType type) {
381 int element_size = ElementSizeInBytes(type.representation());
382 Node* offset = IntAdd(IntMul(index_intptr, IntPtrConstant(element_size)),
385 return LoadFromObject(type, byte_array, offset);
386}
387
389 Node* object, int field_offset, IndirectPointerTag tag) {
390 Node* offset = IntPtrConstant(field_offset);
391#ifdef V8_ENABLE_SANDBOX
394#else
396#endif
397}
398
400 int field_offset,
401 IndirectPointerTag tag) {
402 Node* offset = IntPtrConstant(field_offset);
403#ifdef V8_ENABLE_SANDBOX
406#else
408#endif
409}
410
411std::pair<Node*, Node*>
413 Node* object, int field_offset, IndirectPointerTag tag) {
414 Node* offset = IntPtrConstant(field_offset);
415#ifdef V8_ENABLE_SANDBOX
418#else
420 return {value, value};
421#endif
422}
423
425 Node* value,
426 ObjectAccess access) {
427 return StoreToObject(
429 value);
430}
431
432// Functions, SharedFunctionInfos, FunctionData.
433
443
445 Node* shared = LoadSharedFunctionInfo(js_function);
447 shared,
449 SharedFunctionInfo::kTrustedFunctionDataOffset),
450 kWasmFunctionDataIndirectPointerTag);
451}
452
454 Node* exported_function_data) {
456 MachineType::TaggedSigned(), exported_function_data,
458 WasmExportedFunctionData::kFunctionIndexOffset));
459}
461 Node* exported_function_data) {
463 exported_function_data,
465 WasmExportedFunctionData::kProtectedInstanceDataOffset));
466}
467
468// JavaScript objects.
469
471 return LoadFromObject(
472 MachineType::AnyTagged(), js_array,
473 wasm::ObjectAccess::ToTagged(JSObject::kElementsOffset));
474}
475
476// WasmGC objects.
477
479 uint32_t field_index) {
481 WasmStruct::kHeaderSize + type->field_offset(field_index)));
482}
483
485 wasm::ValueType element_type) {
486 Node* index_intptr =
487 mcgraph()->machine()->Is64() ? ChangeInt32ToInt64(index) : index;
488 return IntAdd(
489 IntPtrConstant(wasm::ObjectAccess::ToTagged(WasmArray::kHeaderSize)),
490 IntMul(index_intptr, IntPtrConstant(element_type.value_kind_size())));
491}
492
494 Node* instance_type = LoadInstanceType(map);
495 // We're going to test a range of WasmObject instance types with a single
496 // unsigned comparison.
497 Node* comparison_value =
498 Int32Sub(instance_type, Int32Constant(FIRST_WASM_OBJECT_TYPE));
499 return Uint32LessThanOrEqual(
500 comparison_value,
501 Int32Constant(LAST_WASM_OBJECT_TYPE - FIRST_WASM_OBJECT_TYPE));
502}
503
505 WasmTypeCheckConfig config) {
506 return AddNode(graph()->NewNode(simplified_.WasmTypeCheck(config), object,
507 rtt, effect(), control()));
508}
509
511 WasmTypeCheckConfig config) {
512 return AddNode(graph()->NewNode(simplified_.WasmTypeCheckAbstract(config),
513 object, effect(), control()));
514}
515
517 WasmTypeCheckConfig config) {
518 return AddNode(graph()->NewNode(simplified_.WasmTypeCast(config), object, rtt,
519 effect(), control()));
520}
521
523 WasmTypeCheckConfig config) {
524 return AddNode(graph()->NewNode(simplified_.WasmTypeCastAbstract(config),
525 object, effect(), control()));
526}
527
529 return AddNode(graph()->NewNode(simplified_.Null(type)));
530}
531
533 return AddNode(graph()->NewNode(simplified_.IsNull(type), object, control()));
534}
535
537 return AddNode(
538 graph()->NewNode(simplified_.IsNotNull(type), object, control()));
539}
540
542 TrapId trap_id) {
543 return AddNode(graph()->NewNode(simplified_.AssertNotNull(type, trap_id),
544 object, effect(), control()));
545}
546
548 return AddNode(graph()->NewNode(simplified_.WasmAnyConvertExtern(), object,
549 effect(), control()));
550}
551
553 return AddNode(graph()->NewNode(simplified_.WasmExternConvertAny(), object,
554 effect(), control()));
555}
556
558 int field_index, bool is_signed,
559 CheckForNull null_check) {
560 return AddNode(graph()->NewNode(
561 simplified_.WasmStructGet(type, field_index, is_signed, null_check),
562 object, effect(), control()));
563}
564
566 const wasm::StructType* type,
567 int field_index, CheckForNull null_check) {
568 AddNode(
569 graph()->NewNode(simplified_.WasmStructSet(type, field_index, null_check),
570 object, value, effect(), control()));
571}
572
574 const wasm::ArrayType* type,
575 bool is_signed) {
576 return AddNode(graph()->NewNode(simplified_.WasmArrayGet(type, is_signed),
577 array, index, effect(), control()));
578}
579
580void WasmGraphAssembler::ArraySet(Node* array, Node* index, Node* value,
581 const wasm::ArrayType* type) {
582 AddNode(graph()->NewNode(simplified_.WasmArraySet(type), array, index, value,
583 effect(), control()));
584}
585
587 return AddNode(graph()->NewNode(simplified_.WasmArrayLength(null_check),
588 array, effect(), control()));
589}
590
592 AddNode(graph()->NewNode(simplified_.WasmArrayInitializeLength(), array,
593 length, effect(), control()));
594}
595
601
603 return AddNode(graph()->NewNode(simplified_.StringAsWtf16(), string, effect(),
604 control()));
605}
606
608 return AddNode(graph()->NewNode(simplified_.StringPrepareForGetCodeunit(),
609 string, effect(), control()));
610}
611
616 wasm::ObjectAccess::ToTagged(WasmInstanceObject::kTrustedDataOffset),
617 kWasmTrustedInstanceDataIndirectPointerTag);
618}
619
620// Generic HeapObject helpers.
621
623 InstanceType type) {
624 Node* map = LoadMap(heap_object);
625 Node* instance_type = LoadInstanceType(map);
626 return Word32Equal(instance_type, Int32Constant(type));
627}
628
629} // namespace v8::internal::compiler
static CallInterfaceDescriptor CallInterfaceDescriptorFor(Builtin builtin)
Definition builtins.cc:189
static constexpr int kMapOffset
static const int kExternalPointerTableBasePointerOffset
static const int kTrustedPointerTableBasePointerOffset
static MachineType TypeForRepresentation(const MachineRepresentation &rep, bool isSigned=true)
static constexpr MachineType Pointer()
static constexpr MachineType Int32()
static constexpr MachineType AnyTagged()
static constexpr MachineType Uint32()
static constexpr MachineType TaggedSigned()
static constexpr MachineType Uint16()
static constexpr MachineType TaggedPointer()
static constexpr MachineType ProtectedPointer()
static constexpr MachineType UintPtr()
static bool constexpr IsValid(T value)
Definition smi.h:67
detail::GraphAssemblerLabelForReps< Reps... > MakeLabel(Reps... reps)
Node * ExternalConstant(ExternalReference ref)
MachineOperatorBuilder * machine() const
TNode< UintPtrT > UintPtrConstant(uintptr_t value)
Node * LoadTrapOnNull(MachineType type, Node *object, Node *offset)
void GotoIf(Node *condition, detail::GraphAssemblerLabelForVars< Vars... > *label, BranchHint hint, Vars...)
CommonOperatorBuilder * common() const
void Bind(GraphAssemblerLabel< VarCount > *label)
Node * Load(MachineType type, Node *object, Node *offset)
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
Node * IntPtrConstant(intptr_t value)
MachineOperatorBuilder * machine() const
Node * Uint32Constant(uint32_t value)
const Operator * LoadFromObject(ObjectAccess const &)
const Operator * LoadImmutableFromObject(ObjectAccess const &)
const Operator * StoreToObject(ObjectAccess const &)
const Operator * InitializeImmutableInObject(ObjectAccess const &)
const Operator * AllocateRaw(Type type, AllocationType allocation=AllocationType::kYoung)
Node * NewNode(const Operator *op, int input_count, Node *const *inputs, bool incomplete=false)
Node * ArrayLength(Node *array, CheckForNull null_check)
Node * WasmTypeCast(Node *object, Node *rtt, WasmTypeCheckConfig config)
Node * LoadImmutableFromObject(MachineType type, Node *base, Node *offset)
Node * WasmTypeCheck(Node *object, Node *rtt, WasmTypeCheckConfig config)
Node * LoadExportedFunctionIndexAsSmi(Node *exported_function_data)
Node * FieldOffset(const wasm::StructType *type, uint32_t field_index)
Node * BuildLoadExternalPointerFromObject(Node *object, int offset, ExternalPointerTagRange tag_range, Node *isolate_root)
Node * LoadProtectedFixedArrayElement(Node *array, int index)
void ArraySet(Node *array, Node *index, Node *value, const wasm::ArrayType *type)
Node * BuildConvertUint32ToSmiWithSaturation(Node *value, uint32_t maxval)
Node * Branch(Node *cond, Node **true_node, Node **false_node, BranchHint hint)
Node * LoadImmutableFixedArrayElement(Node *fixed_array, Node *index_intptr, MachineType type=MachineType::AnyTagged())
Node * LoadExportedFunctionInstanceData(Node *exported_function_data)
Node * LoadFromObject(MachineType type, Node *base, Node *offset)
Node * StoreToObject(ObjectAccess access, Node *base, Node *offset, Node *value)
Node * LoadTrustedDataFromInstanceObject(Node *instance_object)
Node * LoadImmutable(LoadRepresentation rep, Node *base, Node *offset)
Node * LoadWeakFixedArrayElement(Node *fixed_array, Node *index_intptr)
Node * WasmTypeCastAbstract(Node *object, WasmTypeCheckConfig config)
Node * BuildDecodeTrustedPointer(Node *handle, IndirectPointerTag tag)
Node * LoadProtectedPointerFromObject(Node *object, Node *offset)
Node * BuildDecodeSandboxedExternalPointer(Node *handle, ExternalPointerTagRange tag_range, Node *isolate_root)
Node * LoadImmutableTrustedPointerFromObject(Node *object, int offset, IndirectPointerTag tag)
Node * IsNull(Node *object, wasm::ValueType type)
Node * ArrayGet(Node *array, Node *index, const wasm::ArrayType *type, bool is_signed)
Node * WasmTypeCheckAbstract(Node *object, WasmTypeCheckConfig config)
void StoreMap(Node *heap_object, Node *map)
Node * LoadByteArrayElement(Node *byte_array, Node *index_intptr, MachineType type)
void StructSet(Node *object, Node *value, const wasm::StructType *type, int field_index, CheckForNull null_check)
Node * InitializeImmutableInObject(ObjectAccess access, Node *base, Node *offset, Node *value)
Node * LoadImmutableProtectedPointerFromObject(Node *object, Node *offset)
Node * LoadTrustedPointerFromObject(Node *object, int offset, IndirectPointerTag tag)
Node * LoadFixedArrayElement(Node *fixed_array, Node *index_intptr, MachineType type=MachineType::AnyTagged())
std::pair< Node *, Node * > LoadTrustedPointerFromObjectTrapOnNull(Node *object, int offset, IndirectPointerTag tag)
void ArrayInitializeLength(Node *array, Node *length)
Node * StructGet(Node *object, const wasm::StructType *type, int field_index, bool is_signed, CheckForNull null_check)
Node * HasInstanceType(Node *heap_object, InstanceType type)
Node * WasmArrayElementOffset(Node *index, wasm::ValueType element_type)
Node * IsNotNull(Node *object, wasm::ValueType type)
Node * StoreFixedArrayElement(Node *array, int index, Node *value, ObjectAccess access)
Node * AssertNotNull(Node *object, wasm::ValueType type, TrapId trap_id)
static constexpr int SharedFunctionInfoOffsetInTaggedJSFunction()
static constexpr int ElementOffsetInTaggedFixedArray(int index)
static constexpr int ContextOffsetInTaggedJSFunction()
static constexpr int ElementOffsetInProtectedFixedArray(int index)
static constexpr int ToTagged(int offset)
constexpr int value_kind_size() const
Definition value-type.h:485
#define COMPRESS_POINTERS_BOOL
Definition globals.h:99
#define V8_ENABLE_SANDBOX_BOOL
Definition globals.h:160
int32_t offset
Node * node
const int length_
Definition mul-fft.cc:473
V8_INLINE Dest bit_cast(Source const &source)
Definition macros.h:95
ObjectAccess ObjectAccessForGCStores(wasm::ValueType type)
CallDescriptor * GetBuiltinCallDescriptor(Builtin name, Zone *zone, StubCallMode stub_mode, bool needs_frame_state, Operator::Properties properties)
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:72
constexpr uint64_t kExternalPointerTagShift
constexpr int kTaggedSize
Definition globals.h:542
static V8_INLINE constexpr bool IsSharedExternalPointerType(ExternalPointerTagRange tag_range)
constexpr uint64_t kExternalPointerPayloadMask
const int kSmiTagSize
Definition v8-internal.h:87
constexpr ExternalPointerTagRange kAnyExternalPointerTagRange(kFirstExternalPointerTag, kLastExternalPointerTag)
constexpr uint64_t kExternalPointerTagMask
constexpr int kTrustedPointerTableEntrySizeLog2
constexpr int kTaggedSizeLog2
Definition globals.h:543
bool IsSubtype(MachineRepresentation rep1, MachineRepresentation rep2)
constexpr uint32_t kTrustedPointerHandleShift
const int kHeapObjectTag
Definition v8-internal.h:72
const int kSmiShiftSize
const intptr_t kSmiTagMask
Definition v8-internal.h:88
return value
Definition map-inl.h:893
V8_EXPORT_PRIVATE constexpr int ElementSizeInBytes(MachineRepresentation)
const int kSmiTag
Definition v8-internal.h:86
constexpr uint64_t kTrustedPointerTableMarkBit
kMemory0SizeOffset Address kNewAllocationLimitAddressOffset Address kOldAllocationLimitAddressOffset uint8_t kGlobalsStartOffset kJumpTableStartOffset std::atomic< uint32_t > kTieringBudgetArrayOffset kDataSegmentStartsOffset kElementSegmentsOffset instance_object
bool is_signed(Condition cond)
static V8_INLINE constexpr bool ExternalPointerCanBeEmpty(ExternalPointerTagRange tag_range)
#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
constexpr size_t Size() const
constexpr bool IsEmpty() const
#define OFFSET_OF_DATA_START(Type)