#ifndef V8_COMPILER_WASM_GRAPH_ASSEMBLER_H_
#define V8_COMPILER_WASM_GRAPH_ASSEMBLER_H_
#if !V8_ENABLE_WEBASSEMBLY
#error This header should only be included if WebAssembly is enabled.
#endif
#include "src/compiler/graph-assembler.h"
#include "src/wasm/wasm-code-manager.h"
namespace v8 {
namespace internal {
namespace compiler {
CallDescriptor* GetBuiltinCallDescriptor(
Builtin name, Zone* zone, StubCallMode stub_mode,
bool needs_frame_state = false,
Operator::Properties properties = Operator::kNoProperties);
ObjectAccess ObjectAccessForGCStores(wasm::ValueType type);
class WasmGraphAssembler : public GraphAssembler {
public:
WasmGraphAssembler(MachineGraph* mcgraph, Zone* zone)
: GraphAssembler(mcgraph, zone, BranchSemantics::kMachine),
simplified_(zone) {}
template <typename... Args>
Node* CallBuiltinThroughJumptable(Builtin builtin,
Operator::Properties properties,
Args... args) {
auto* call_descriptor = GetBuiltinCallDescriptor(
builtin, temp_zone(), StubCallMode::kCallWasmRuntimeStub, false,
properties);
Node* call_target = mcgraph()->RelocatableWasmBuiltinCallTarget(builtin);
return Call(call_descriptor, call_target, args...);
}
Node* GetBuiltinPointerTarget(Builtin builtin) {
static_assert(std::is_same_v<Smi, BuiltinPtr>, "BuiltinPtr must be Smi");
return NumberConstant(static_cast<int>(builtin));
}
template <typename... Args>
Node* CallBuiltin(Builtin name, Operator::Properties properties,
Args... args) {
return CallBuiltinImpl(name, false, properties, args...);
}
template <typename... Args>
Node* CallBuiltinWithFrameState(Builtin name, Operator::Properties properties,
Node* frame_state, Args... args) {
DCHECK_EQ(frame_state->opcode(), IrOpcode::kFrameState);
return CallBuiltinImpl(name, true, properties, frame_state, args...);
}
Node* Branch(Node* cond, Node** true_node, Node** false_node,
BranchHint hint);
Node* NumberConstant(double value) {
return graph()->NewNode(mcgraph()->common()->NumberConstant(value));
}
Node* SmiConstant(Tagged_t value) {
Address tagged_value = Internals::IntegralToSmi(static_cast<int>(value));
return kTaggedSize == kInt32Size
? Int32Constant(static_cast<int32_t>(tagged_value))
: Int64Constant(static_cast<int64_t>(tagged_value));
}
void MergeControlToEnd(Node* control) {
NodeProperties::MergeControlToEnd(graph(), common(), control);
}
Node* BuildTruncateIntPtrToInt32(Node* value);
Node* BuildChangeInt32ToIntPtr(Node* value);
Node* BuildChangeIntPtrToInt64(Node* value);
Node* BuildChangeUint32ToUintPtr(Node* node);
Node* BuildSmiShiftBitsConstant();
Node* BuildSmiShiftBitsConstant32();
Node* BuildChangeInt32ToSmi(Node* value);
Node* BuildChangeUint31ToSmi(Node* value);
Node* BuildChangeSmiToInt32(Node* value);
Node* BuildConvertUint32ToSmiWithSaturation(Node* value, uint32_t maxval);
Node* BuildChangeSmiToIntPtr(Node* value);
Node* Allocate(int size);
Node* Allocate(Node* size);
Node* LoadFromObject(MachineType type, Node* base, Node* offset);
Node* LoadFromObject(MachineType type, Node* base, int offset) {
return LoadFromObject(type, base, IntPtrConstant(offset));
}
Node* LoadProtectedPointerFromObject(Node* object, Node* offset);
Node* LoadProtectedPointerFromObject(Node* object, int offset) {
return LoadProtectedPointerFromObject(object, IntPtrConstant(offset));
}
Node* LoadImmutableProtectedPointerFromObject(Node* object, Node* offset);
Node* LoadImmutableProtectedPointerFromObject(Node* object, int offset) {
return LoadImmutableProtectedPointerFromObject(object,
IntPtrConstant(offset));
}
Node* LoadImmutableFromObject(MachineType type, Node* base, Node* offset);
Node* LoadImmutableFromObject(MachineType type, Node* base, int offset) {
return LoadImmutableFromObject(type, base, IntPtrConstant(offset));
}
Node* LoadImmutable(LoadRepresentation rep, Node* base, Node* offset);
Node* LoadImmutable(LoadRepresentation rep, Node* base, int offset) {
return LoadImmutable(rep, base, IntPtrConstant(offset));
}
Node* LoadWasmCodePointer(Node* code_pointer);
Node* StoreToObject(ObjectAccess access, Node* base, Node* offset,
Node* value);
Node* StoreToObject(ObjectAccess access, Node* base, int offset,
Node* value) {
return StoreToObject(access, base, IntPtrConstant(offset), value);
}
Node* InitializeImmutableInObject(ObjectAccess access, Node* base,
Node* offset, Node* value);
Node* InitializeImmutableInObject(ObjectAccess access, Node* base, int offset,
Node* value) {
return InitializeImmutableInObject(access, base, IntPtrConstant(offset),
value);
}
Node* BuildDecodeSandboxedExternalPointer(Node* handle,
ExternalPointerTagRange tag_range,
Node* isolate_root);
Node* BuildLoadExternalPointerFromObject(Node* object, int offset,
ExternalPointerTagRange tag_range,
Node* isolate_root);
Node* BuildLoadExternalPointerFromObject(Node* object, int offset,
Node* index,
ExternalPointerTagRange tag_range,
Node* isolate_root);
Node* LoadImmutableTrustedPointerFromObject(Node* object, int offset,
IndirectPointerTag tag);
Node* LoadTrustedPointerFromObject(Node* object, int offset,
IndirectPointerTag tag);
std::pair<Node*, Node*> LoadTrustedPointerFromObjectTrapOnNull(
Node* object, int offset, IndirectPointerTag tag);
Node* BuildDecodeTrustedPointer(Node* handle, IndirectPointerTag tag);
Node* IsSmi(Node* object);
Node* LoadMap(Node* object);
void StoreMap(Node* heap_object, Node* map);
Node* LoadInstanceType(Node* map);
Node* LoadWasmTypeInfo(Node* map);
Node* LoadFixedArrayLengthAsSmi(Node* fixed_array);
Node* LoadFixedArrayElement(Node* fixed_array, Node* index_intptr,
MachineType type = MachineType::AnyTagged());
Node* LoadImmutableFixedArrayElement(
Node* fixed_array, Node* index_intptr,
MachineType type = MachineType::AnyTagged());
Node* LoadFixedArrayElement(Node* array, int index, MachineType type);
Node* LoadFixedArrayElementSmi(Node* array, int index) {
return LoadFixedArrayElement(array, index, MachineType::TaggedSigned());
}
Node* LoadFixedArrayElementPtr(Node* array, int index) {
return LoadFixedArrayElement(array, index, MachineType::TaggedPointer());
}
Node* LoadFixedArrayElementAny(Node* array, int index) {
return LoadFixedArrayElement(array, index, MachineType::AnyTagged());
}
Node* LoadProtectedFixedArrayElement(Node* array, int index);
Node* LoadProtectedFixedArrayElement(Node* array, Node* index_intptr);
Node* LoadByteArrayElement(Node* byte_array, Node* index_intptr,
MachineType type);
Node* StoreFixedArrayElement(Node* array, int index, Node* value,
ObjectAccess access);
Node* StoreFixedArrayElementSmi(Node* array, int index, Node* value) {
return StoreFixedArrayElement(
array, index, value,
ObjectAccess(MachineType::TaggedSigned(), kNoWriteBarrier));
}
Node* StoreFixedArrayElementAny(Node* array, int index, Node* value) {
return StoreFixedArrayElement(
array, index, value,
ObjectAccess(MachineType::AnyTagged(), kFullWriteBarrier));
}
Node* LoadWeakFixedArrayElement(Node* fixed_array, Node* index_intptr);
Node* LoadSharedFunctionInfo(Node* js_function);
Node* LoadContextNoCellFromJSFunction(Node* js_function);
Node* LoadFunctionDataFromJSFunction(Node* js_function);
Node* LoadExportedFunctionIndexAsSmi(Node* exported_function_data);
Node* LoadExportedFunctionInstanceData(Node* exported_function_data);
Node* LoadJSArrayElements(Node* js_array);
Node* FieldOffset(const wasm::StructType* type, uint32_t field_index);
Node* WasmArrayElementOffset(Node* index, wasm::ValueType element_type);
Node* IsDataRefMap(Node* map);
Node* WasmTypeCheck(Node* object, Node* rtt, WasmTypeCheckConfig config);
Node* WasmTypeCheckAbstract(Node* object, WasmTypeCheckConfig config);
Node* WasmTypeCast(Node* object, Node* rtt, WasmTypeCheckConfig config);
Node* WasmTypeCastAbstract(Node* object, WasmTypeCheckConfig config);
Node* Null(wasm::ValueType type);
Node* IsNull(Node* object, wasm::ValueType type);
Node* IsNotNull(Node* object, wasm::ValueType type);
Node* AssertNotNull(Node* object, wasm::ValueType type, TrapId trap_id);
Node* WasmAnyConvertExtern(Node* object);
Node* WasmExternConvertAny(Node* object);
Node* StructGet(Node* object, const wasm::StructType* type, int field_index,
bool is_signed, CheckForNull null_check);
void StructSet(Node* object, Node* value, const wasm::StructType* type,
int field_index, CheckForNull null_check);
Node* ArrayGet(Node* array, Node* index, const wasm::ArrayType* type,
bool is_signed);
void ArraySet(Node* array, Node* index, Node* value,
const wasm::ArrayType* type);
Node* ArrayLength(Node* array, CheckForNull null_check);
void ArrayInitializeLength(Node* array, Node* length);
Node* LoadStringLength(Node* string);
Node* StringAsWtf16(Node* string);
Node* StringPrepareForGetCodeunit(Node* string);
Node* HasInstanceType(Node* heap_object, InstanceType type);
void TrapIf(Node* condition, TrapId reason) {
const bool has_frame_state = false;
AddNode(
graph()->NewNode(mcgraph()->common()->TrapIf(reason, has_frame_state),
condition, effect(), control()));
}
void TrapUnless(Node* condition, TrapId reason) {
const bool has_frame_state = false;
AddNode(graph()->NewNode(
mcgraph()->common()->TrapUnless(reason, has_frame_state), condition,
effect(), control()));
}
Node* LoadTrustedDataFromInstanceObject(Node* instance_object);
SimplifiedOperatorBuilder* simplified() override { return &simplified_; }
private:
template <typename... Args>
Node* CallBuiltinImpl(Builtin name, bool needs_frame_state,
Operator::Properties properties, Args... args) {
auto* call_descriptor = GetBuiltinCallDescriptor(
name, temp_zone(), StubCallMode::kCallBuiltinPointer, needs_frame_state,
properties);
Node* call_target = GetBuiltinPointerTarget(name);
return Call(call_descriptor, call_target, args...);
}
SimplifiedOperatorBuilder simplified_;
};
}
}
}
#endif