[wasm][refactor] Move WasmGraphAssembler to separate file

This way we can use it later in the pipeline for optimizations.

Change-Id: I0e97d061fd3d474ca7033ed2b68f43b52617d3e8
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3634961
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80437}
This commit is contained in:
Manos Koukoutos 2022-05-10 06:41:06 +00:00 committed by V8 LUCI CQ
parent 253d03dcb3
commit eac584cda3
5 changed files with 527 additions and 381 deletions

View File

@ -2432,6 +2432,7 @@ filegroup(
"src/compiler/int64-lowering.h",
"src/compiler/wasm-compiler.h",
"src/compiler/wasm-escape-analysis.h",
"src/compiler/wasm-graph-assembler.h",
"src/compiler/wasm-inlining.h",
"src/compiler/wasm-loop-peeling.h",
"src/debug/debug-wasm-objects.cc",
@ -2843,6 +2844,7 @@ filegroup(
"src/compiler/wasm-compiler.cc",
"src/compiler/wasm-loop-peeling.cc",
"src/compiler/wasm-escape-analysis.cc",
"src/compiler/wasm-graph-assembler.cc",
"src/compiler/wasm-inlining.cc",
],
"//conditions:default": [],

View File

@ -3518,6 +3518,7 @@ v8_header_set("v8_internal_headers") {
"src/compiler/int64-lowering.h",
"src/compiler/wasm-compiler.h",
"src/compiler/wasm-escape-analysis.h",
"src/compiler/wasm-graph-assembler.h",
"src/compiler/wasm-inlining.h",
"src/compiler/wasm-loop-peeling.h",
"src/debug/debug-wasm-objects-inl.h",
@ -4012,6 +4013,7 @@ if (v8_enable_webassembly) {
"src/compiler/int64-lowering.cc",
"src/compiler/wasm-compiler.cc",
"src/compiler/wasm-escape-analysis.cc",
"src/compiler/wasm-graph-assembler.cc",
"src/compiler/wasm-inlining.cc",
"src/compiler/wasm-loop-peeling.cc",
]

View File

@ -37,6 +37,7 @@
#include "src/compiler/node-origin-table.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/pipeline.h"
#include "src/compiler/wasm-graph-assembler.h"
#include "src/compiler/zone-stats.h"
#include "src/execution/isolate-inl.h"
#include "src/execution/simulator.h"
@ -122,43 +123,6 @@ bool ContainsInt64(const wasm::FunctionSig* sig) {
return false;
}
constexpr Builtin WasmRuntimeStubIdToBuiltinName(
wasm::WasmCode::RuntimeStubId runtime_stub_id) {
switch (runtime_stub_id) {
#define DEF_CASE(name) \
case wasm::WasmCode::k##name: \
return Builtin::k##name;
#define DEF_TRAP_CASE(name) DEF_CASE(ThrowWasm##name)
WASM_RUNTIME_STUB_LIST(DEF_CASE, DEF_TRAP_CASE)
#undef DEF_CASE
#undef DEF_TRAP_CASE
default:
UNREACHABLE();
}
}
CallDescriptor* GetBuiltinCallDescriptor(
Builtin name, Zone* zone, StubCallMode stub_mode,
bool needs_frame_state = false,
Operator::Properties properties = Operator::kNoProperties) {
CallInterfaceDescriptor interface_descriptor =
Builtins::CallInterfaceDescriptorFor(name);
return Linkage::GetStubCallDescriptor(
zone, // zone
interface_descriptor, // descriptor
interface_descriptor.GetStackParameterCount(), // stack parameter count
needs_frame_state ? CallDescriptor::kNeedsFrameState
: CallDescriptor::kNoFlags, // flags
properties, // properties
stub_mode); // stub call mode
}
ObjectAccess ObjectAccessForGCStores(wasm::ValueType type) {
return ObjectAccess(
MachineType::TypeForRepresentation(type.machine_representation(),
!type.is_packed()),
type.is_reference() ? kFullWriteBarrier : kNoWriteBarrier);
}
} // namespace
JSWasmCallData::JSWasmCallData(const wasm::FunctionSig* wasm_signature)
@ -172,350 +136,6 @@ JSWasmCallData::JSWasmCallData(const wasm::FunctionSig* wasm_signature)
}
}
class WasmGraphAssembler : public GraphAssembler {
public:
WasmGraphAssembler(MachineGraph* mcgraph, Zone* zone)
: GraphAssembler(mcgraph, zone), simplified_(zone) {}
template <typename... Args>
Node* CallRuntimeStub(wasm::WasmCode::RuntimeStubId stub_id,
Operator::Properties properties, Args*... args) {
auto* call_descriptor = GetBuiltinCallDescriptor(
WasmRuntimeStubIdToBuiltinName(stub_id), temp_zone(),
StubCallMode::kCallWasmRuntimeStub, false, properties);
// A direct call to a wasm runtime stub defined in this module.
// Just encode the stub index. This will be patched at relocation.
Node* call_target = mcgraph()->RelocatableIntPtrConstant(
stub_id, RelocInfo::WASM_STUB_CALL);
return Call(call_descriptor, call_target, args...);
}
template <typename... Args>
Node* CallBuiltin(Builtin name, Operator::Properties properties,
Args*... args) {
auto* call_descriptor = GetBuiltinCallDescriptor(
name, temp_zone(), StubCallMode::kCallBuiltinPointer, false,
properties);
Node* call_target = GetBuiltinPointerTarget(name);
return Call(call_descriptor, call_target, args...);
}
void MergeControlToEnd(Node* node) {
NodeProperties::MergeControlToEnd(graph(), mcgraph()->common(), node);
}
void AssertFalse(Node* condition) {
#if DEBUG
if (FLAG_debug_code) {
auto ok = MakeLabel();
GotoIfNot(condition, &ok);
Unreachable();
Bind(&ok);
}
#endif
}
Node* GetBuiltinPointerTarget(Builtin builtin) {
static_assert(std::is_same<Smi, BuiltinPtr>(), "BuiltinPtr must be Smi");
return NumberConstant(static_cast<int>(builtin));
}
// Sets {true_node} and {false_node} to their corresponding Branch outputs.
// Returns the Branch node. Does not change control().
Node* Branch(Node* cond, Node** true_node, Node** false_node,
BranchHint hint) {
DCHECK_NOT_NULL(cond);
Node* branch =
graph()->NewNode(mcgraph()->common()->Branch(hint), cond, control());
*true_node = graph()->NewNode(mcgraph()->common()->IfTrue(), branch);
*false_node = graph()->NewNode(mcgraph()->common()->IfFalse(), branch);
return branch;
}
Node* NumberConstant(double value) {
return graph()->NewNode(mcgraph()->common()->NumberConstant(value));
}
// Helper functions for dealing with HeapObjects.
// Rule of thumb: if access to a given field in an object is required in
// at least two places, put a helper function here.
Node* Allocate(int size) {
AllowLargeObjects allow_large = size < kMaxRegularHeapObjectSize
? AllowLargeObjects::kFalse
: AllowLargeObjects::kTrue;
return Allocate(Int32Constant(size), allow_large);
}
Node* Allocate(Node* size,
AllowLargeObjects allow_large = AllowLargeObjects::kTrue) {
return AddNode(
graph()->NewNode(simplified_.AllocateRaw(
Type::Any(), AllocationType::kYoung, allow_large),
size, effect(), control()));
}
Node* LoadFromObject(MachineType type, Node* base, Node* offset) {
return AddNode(graph()->NewNode(
simplified_.LoadFromObject(ObjectAccess(type, kNoWriteBarrier)), base,
offset, effect(), control()));
}
Node* LoadFromObject(MachineType type, Node* base, int offset) {
return LoadFromObject(type, base, IntPtrConstant(offset));
}
Node* LoadImmutableFromObject(MachineType type, Node* base, Node* offset) {
return AddNode(graph()->NewNode(simplified_.LoadImmutableFromObject(
ObjectAccess(type, kNoWriteBarrier)),
base, offset, effect(), control()));
}
Node* LoadImmutableFromObject(MachineType type, Node* base, int offset) {
return LoadImmutableFromObject(type, base, IntPtrConstant(offset));
}
Node* LoadImmutable(LoadRepresentation rep, Node* base, Node* offset) {
return AddNode(graph()->NewNode(mcgraph()->machine()->LoadImmutable(rep),
base, offset));
}
Node* LoadImmutable(LoadRepresentation rep, Node* base, int offset) {
return LoadImmutable(rep, base, IntPtrConstant(offset));
}
Node* StoreToObject(ObjectAccess access, Node* base, Node* offset,
Node* value) {
return AddNode(graph()->NewNode(simplified_.StoreToObject(access), base,
offset, value, effect(), control()));
}
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) {
return AddNode(
graph()->NewNode(simplified_.InitializeImmutableInObject(access), base,
offset, value, effect(), control()));
}
Node* InitializeImmutableInObject(ObjectAccess access, Node* base, int offset,
Node* value) {
return InitializeImmutableInObject(access, base, IntPtrConstant(offset),
value);
}
Node* IsI31(Node* object) {
if (COMPRESS_POINTERS_BOOL) {
return Word32Equal(Word32And(object, Int32Constant(kSmiTagMask)),
Int32Constant(kSmiTag));
} else {
return WordEqual(WordAnd(object, IntPtrConstant(kSmiTagMask)),
IntPtrConstant(kSmiTag));
}
}
// Maps and their contents.
Node* LoadMap(Node* object) {
Node* map_word =
LoadImmutableFromObject(MachineType::TaggedPointer(), object,
HeapObject::kMapOffset - kHeapObjectTag);
#ifdef V8_MAP_PACKING
return UnpackMapWord(map_word);
#else
return map_word;
#endif
}
void StoreMap(Node* heap_object, Node* map) {
ObjectAccess access(MachineType::TaggedPointer(), kMapWriteBarrier);
#ifdef V8_MAP_PACKING
map = PackMapWord(TNode<Map>::UncheckedCast(map));
#endif
InitializeImmutableInObject(access, heap_object,
HeapObject::kMapOffset - kHeapObjectTag, map);
}
Node* LoadInstanceType(Node* map) {
return LoadImmutableFromObject(
MachineType::Uint16(), map,
wasm::ObjectAccess::ToTagged(Map::kInstanceTypeOffset));
}
Node* LoadWasmTypeInfo(Node* map) {
int offset = Map::kConstructorOrBackPointerOrNativeContextOffset;
return LoadImmutableFromObject(MachineType::TaggedPointer(), map,
wasm::ObjectAccess::ToTagged(offset));
}
Node* LoadSupertypes(Node* wasm_type_info) {
return LoadImmutableFromObject(
MachineType::TaggedPointer(), wasm_type_info,
wasm::ObjectAccess::ToTagged(WasmTypeInfo::kSupertypesOffset));
}
// FixedArrays.
Node* LoadFixedArrayLengthAsSmi(Node* fixed_array) {
return LoadImmutableFromObject(
MachineType::TaggedSigned(), fixed_array,
wasm::ObjectAccess::ToTagged(FixedArray::kLengthOffset));
}
Node* LoadFixedArrayElement(Node* fixed_array, Node* index_intptr,
MachineType type = MachineType::AnyTagged()) {
Node* offset = IntAdd(
IntMul(index_intptr, IntPtrConstant(kTaggedSize)),
IntPtrConstant(wasm::ObjectAccess::ToTagged(FixedArray::kHeaderSize)));
return LoadFromObject(type, fixed_array, offset);
}
Node* LoadImmutableFixedArrayElement(
Node* fixed_array, Node* index_intptr,
MachineType type = MachineType::AnyTagged()) {
Node* offset = IntAdd(
IntMul(index_intptr, IntPtrConstant(kTaggedSize)),
IntPtrConstant(wasm::ObjectAccess::ToTagged(FixedArray::kHeaderSize)));
return LoadImmutableFromObject(type, fixed_array, offset);
}
Node* LoadFixedArrayElement(Node* array, int index, MachineType type) {
return LoadFromObject(
type, array,
wasm::ObjectAccess::ElementOffsetInTaggedFixedArray(index));
}
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* StoreFixedArrayElement(Node* array, int index, Node* value,
ObjectAccess access) {
return StoreToObject(
access, array,
wasm::ObjectAccess::ElementOffsetInTaggedFixedArray(index), value);
}
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));
}
// Functions, SharedFunctionInfos, FunctionData.
Node* LoadSharedFunctionInfo(Node* js_function) {
return LoadFromObject(
MachineType::TaggedPointer(), js_function,
wasm::ObjectAccess::SharedFunctionInfoOffsetInTaggedJSFunction());
}
Node* LoadContextFromJSFunction(Node* js_function) {
return LoadFromObject(
MachineType::TaggedPointer(), js_function,
wasm::ObjectAccess::ContextOffsetInTaggedJSFunction());
}
Node* LoadFunctionDataFromJSFunction(Node* js_function) {
Node* shared = LoadSharedFunctionInfo(js_function);
return LoadFromObject(
MachineType::TaggedPointer(), shared,
wasm::ObjectAccess::ToTagged(SharedFunctionInfo::kFunctionDataOffset));
}
Node* LoadExportedFunctionIndexAsSmi(Node* exported_function_data) {
return LoadImmutableFromObject(
MachineType::TaggedSigned(), exported_function_data,
wasm::ObjectAccess::ToTagged(
WasmExportedFunctionData::kFunctionIndexOffset));
}
Node* LoadExportedFunctionInstance(Node* exported_function_data) {
return LoadImmutableFromObject(
MachineType::TaggedPointer(), exported_function_data,
wasm::ObjectAccess::ToTagged(
WasmExportedFunctionData::kInstanceOffset));
}
// JavaScript objects.
Node* LoadJSArrayElements(Node* js_array) {
return LoadFromObject(
MachineType::AnyTagged(), js_array,
wasm::ObjectAccess::ToTagged(JSObject::kElementsOffset));
}
// WasmGC objects.
Node* FieldOffset(const wasm::StructType* type, uint32_t field_index) {
return IntPtrConstant(wasm::ObjectAccess::ToTagged(
WasmStruct::kHeaderSize + type->field_offset(field_index)));
}
Node* StoreStructField(Node* struct_object, const wasm::StructType* type,
uint32_t field_index, Node* value) {
ObjectAccess access = ObjectAccessForGCStores(type->field(field_index));
return type->mutability(field_index)
? StoreToObject(access, struct_object,
FieldOffset(type, field_index), value)
: InitializeImmutableInObject(access, struct_object,
FieldOffset(type, field_index),
value);
}
Node* WasmArrayElementOffset(Node* index, wasm::ValueType element_type) {
Node* index_intptr =
mcgraph()->machine()->Is64() ? ChangeUint32ToUint64(index) : index;
return IntAdd(
IntPtrConstant(wasm::ObjectAccess::ToTagged(WasmArray::kHeaderSize)),
IntMul(index_intptr, IntPtrConstant(element_type.value_kind_size())));
}
Node* LoadWasmArrayLength(Node* array) {
return LoadImmutableFromObject(
MachineType::Uint32(), array,
wasm::ObjectAccess::ToTagged(WasmArray::kLengthOffset));
}
Node* IsDataRefMap(Node* map) {
Node* instance_type = LoadInstanceType(map);
// We're going to test a range of WasmObject instance types with a single
// unsigned comparison.
Node* comparison_value =
Int32Sub(instance_type, Int32Constant(FIRST_WASM_OBJECT_TYPE));
return Uint32LessThanOrEqual(
comparison_value,
Int32Constant(LAST_WASM_OBJECT_TYPE - FIRST_WASM_OBJECT_TYPE));
}
// Generic HeapObject helpers.
Node* HasInstanceType(Node* heap_object, InstanceType type) {
Node* map = LoadMap(heap_object);
Node* instance_type = LoadInstanceType(map);
return Word32Equal(instance_type, Int32Constant(type));
}
SimplifiedOperatorBuilder* simplified() { return &simplified_; }
private:
SimplifiedOperatorBuilder simplified_;
};
WasmGraphBuilder::WasmGraphBuilder(
wasm::CompilationEnv* env, Zone* zone, MachineGraph* mcgraph,
const wasm::FunctionSig* sig,

View File

@ -0,0 +1,288 @@
// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/compiler/wasm-graph-assembler.h"
#include "src/wasm/object-access.h"
#include "src/wasm/wasm-objects.h"
namespace v8 {
namespace internal {
namespace compiler {
// static
CallDescriptor* GetBuiltinCallDescriptor(Builtin name, Zone* zone,
StubCallMode stub_mode,
bool needs_frame_state,
Operator::Properties properties) {
CallInterfaceDescriptor interface_descriptor =
Builtins::CallInterfaceDescriptorFor(name);
return Linkage::GetStubCallDescriptor(
zone, // zone
interface_descriptor, // descriptor
interface_descriptor.GetStackParameterCount(), // stack parameter count
needs_frame_state ? CallDescriptor::kNeedsFrameState
: CallDescriptor::kNoFlags, // flags
properties, // properties
stub_mode); // stub call mode
}
// static
ObjectAccess ObjectAccessForGCStores(wasm::ValueType type) {
return ObjectAccess(
MachineType::TypeForRepresentation(type.machine_representation(),
!type.is_packed()),
type.is_reference() ? kFullWriteBarrier : kNoWriteBarrier);
}
// Sets {true_node} and {false_node} to their corresponding Branch outputs.
// Returns the Branch node. Does not change control().
Node* WasmGraphAssembler::Branch(Node* cond, Node** true_node,
Node** false_node, BranchHint hint) {
DCHECK_NOT_NULL(cond);
Node* branch =
graph()->NewNode(mcgraph()->common()->Branch(hint), cond, control());
*true_node = graph()->NewNode(mcgraph()->common()->IfTrue(), branch);
*false_node = graph()->NewNode(mcgraph()->common()->IfFalse(), branch);
return branch;
}
// Helper functions for dealing with HeapObjects.
// Rule of thumb: if access to a given field in an object is required in
// at least two places, put a helper function here.
Node* WasmGraphAssembler::Allocate(int size) {
AllowLargeObjects allow_large = size < kMaxRegularHeapObjectSize
? AllowLargeObjects::kFalse
: AllowLargeObjects::kTrue;
return Allocate(Int32Constant(size), allow_large);
}
Node* WasmGraphAssembler::Allocate(Node* size, AllowLargeObjects allow_large) {
return AddNode(graph()->NewNode(
simplified_.AllocateRaw(Type::Any(), AllocationType::kYoung, allow_large),
size, effect(), control()));
}
Node* WasmGraphAssembler::LoadFromObject(MachineType type, Node* base,
Node* offset) {
return AddNode(graph()->NewNode(
simplified_.LoadFromObject(ObjectAccess(type, kNoWriteBarrier)), base,
offset, effect(), control()));
}
Node* WasmGraphAssembler::LoadImmutableFromObject(MachineType type, Node* base,
Node* offset) {
return AddNode(graph()->NewNode(
simplified_.LoadImmutableFromObject(ObjectAccess(type, kNoWriteBarrier)),
base, offset, effect(), control()));
}
Node* WasmGraphAssembler::LoadImmutable(LoadRepresentation rep, Node* base,
Node* offset) {
return AddNode(
graph()->NewNode(mcgraph()->machine()->LoadImmutable(rep), base, offset));
}
Node* WasmGraphAssembler::StoreToObject(ObjectAccess access, Node* base,
Node* offset, Node* value) {
return AddNode(graph()->NewNode(simplified_.StoreToObject(access), base,
offset, value, effect(), control()));
}
Node* WasmGraphAssembler::InitializeImmutableInObject(ObjectAccess access,
Node* base, Node* offset,
Node* value) {
return AddNode(
graph()->NewNode(simplified_.InitializeImmutableInObject(access), base,
offset, value, effect(), control()));
}
Node* WasmGraphAssembler::IsI31(Node* object) {
if (COMPRESS_POINTERS_BOOL) {
return Word32Equal(Word32And(object, Int32Constant(kSmiTagMask)),
Int32Constant(kSmiTag));
} else {
return WordEqual(WordAnd(object, IntPtrConstant(kSmiTagMask)),
IntPtrConstant(kSmiTag));
}
}
// Maps and their contents.
Node* WasmGraphAssembler::LoadMap(Node* object) {
Node* map_word =
LoadImmutableFromObject(MachineType::TaggedPointer(), object,
HeapObject::kMapOffset - kHeapObjectTag);
#ifdef V8_MAP_PACKING
return UnpackMapWord(map_word);
#else
return map_word;
#endif
}
void WasmGraphAssembler::StoreMap(Node* heap_object, Node* map) {
ObjectAccess access(MachineType::TaggedPointer(), kMapWriteBarrier);
#ifdef V8_MAP_PACKING
map = PackMapWord(TNode<Map>::UncheckedCast(map));
#endif
InitializeImmutableInObject(access, heap_object,
HeapObject::kMapOffset - kHeapObjectTag, map);
}
Node* WasmGraphAssembler::LoadInstanceType(Node* map) {
return LoadImmutableFromObject(
MachineType::Uint16(), map,
wasm::ObjectAccess::ToTagged(Map::kInstanceTypeOffset));
}
Node* WasmGraphAssembler::LoadWasmTypeInfo(Node* map) {
int offset = Map::kConstructorOrBackPointerOrNativeContextOffset;
return LoadImmutableFromObject(MachineType::TaggedPointer(), map,
wasm::ObjectAccess::ToTagged(offset));
}
Node* WasmGraphAssembler::LoadSupertypes(Node* wasm_type_info) {
return LoadImmutableFromObject(
MachineType::TaggedPointer(), wasm_type_info,
wasm::ObjectAccess::ToTagged(WasmTypeInfo::kSupertypesOffset));
}
// FixedArrays.
Node* WasmGraphAssembler::LoadFixedArrayLengthAsSmi(Node* fixed_array) {
return LoadImmutableFromObject(
MachineType::TaggedSigned(), fixed_array,
wasm::ObjectAccess::ToTagged(FixedArray::kLengthOffset));
}
Node* WasmGraphAssembler::LoadFixedArrayElement(Node* fixed_array,
Node* index_intptr,
MachineType type) {
Node* offset = IntAdd(
IntMul(index_intptr, IntPtrConstant(kTaggedSize)),
IntPtrConstant(wasm::ObjectAccess::ToTagged(FixedArray::kHeaderSize)));
return LoadFromObject(type, fixed_array, offset);
}
Node* WasmGraphAssembler::LoadImmutableFixedArrayElement(Node* fixed_array,
Node* index_intptr,
MachineType type) {
Node* offset = IntAdd(
IntMul(index_intptr, IntPtrConstant(kTaggedSize)),
IntPtrConstant(wasm::ObjectAccess::ToTagged(FixedArray::kHeaderSize)));
return LoadImmutableFromObject(type, fixed_array, offset);
}
Node* WasmGraphAssembler::LoadFixedArrayElement(Node* array, int index,
MachineType type) {
return LoadFromObject(
type, array, wasm::ObjectAccess::ElementOffsetInTaggedFixedArray(index));
}
Node* WasmGraphAssembler::StoreFixedArrayElement(Node* array, int index,
Node* value,
ObjectAccess access) {
return StoreToObject(
access, array, wasm::ObjectAccess::ElementOffsetInTaggedFixedArray(index),
value);
}
// Functions, SharedFunctionInfos, FunctionData.
Node* WasmGraphAssembler::LoadSharedFunctionInfo(Node* js_function) {
return LoadFromObject(
MachineType::TaggedPointer(), js_function,
wasm::ObjectAccess::SharedFunctionInfoOffsetInTaggedJSFunction());
}
Node* WasmGraphAssembler::LoadContextFromJSFunction(Node* js_function) {
return LoadFromObject(MachineType::TaggedPointer(), js_function,
wasm::ObjectAccess::ContextOffsetInTaggedJSFunction());
}
Node* WasmGraphAssembler::LoadFunctionDataFromJSFunction(Node* js_function) {
Node* shared = LoadSharedFunctionInfo(js_function);
return LoadFromObject(
MachineType::TaggedPointer(), shared,
wasm::ObjectAccess::ToTagged(SharedFunctionInfo::kFunctionDataOffset));
}
Node* WasmGraphAssembler::LoadExportedFunctionIndexAsSmi(
Node* exported_function_data) {
return LoadImmutableFromObject(
MachineType::TaggedSigned(), exported_function_data,
wasm::ObjectAccess::ToTagged(
WasmExportedFunctionData::kFunctionIndexOffset));
}
Node* WasmGraphAssembler::LoadExportedFunctionInstance(
Node* exported_function_data) {
return LoadImmutableFromObject(
MachineType::TaggedPointer(), exported_function_data,
wasm::ObjectAccess::ToTagged(WasmExportedFunctionData::kInstanceOffset));
}
// JavaScript objects.
Node* WasmGraphAssembler::LoadJSArrayElements(Node* js_array) {
return LoadFromObject(
MachineType::AnyTagged(), js_array,
wasm::ObjectAccess::ToTagged(JSObject::kElementsOffset));
}
// WasmGC objects.
Node* WasmGraphAssembler::FieldOffset(const wasm::StructType* type,
uint32_t field_index) {
return IntPtrConstant(wasm::ObjectAccess::ToTagged(
WasmStruct::kHeaderSize + type->field_offset(field_index)));
}
Node* WasmGraphAssembler::StoreStructField(Node* struct_object,
const wasm::StructType* type,
uint32_t field_index, Node* value) {
ObjectAccess access = ObjectAccessForGCStores(type->field(field_index));
return type->mutability(field_index)
? StoreToObject(access, struct_object,
FieldOffset(type, field_index), value)
: InitializeImmutableInObject(access, struct_object,
FieldOffset(type, field_index),
value);
}
Node* WasmGraphAssembler::WasmArrayElementOffset(Node* index,
wasm::ValueType element_type) {
Node* index_intptr =
mcgraph()->machine()->Is64() ? ChangeInt32ToInt64(index) : index;
return IntAdd(
IntPtrConstant(wasm::ObjectAccess::ToTagged(WasmArray::kHeaderSize)),
IntMul(index_intptr, IntPtrConstant(element_type.value_kind_size())));
}
Node* WasmGraphAssembler::LoadWasmArrayLength(Node* array) {
return LoadImmutableFromObject(
MachineType::Uint32(), array,
wasm::ObjectAccess::ToTagged(WasmArray::kLengthOffset));
}
Node* WasmGraphAssembler::IsDataRefMap(Node* map) {
Node* instance_type = LoadInstanceType(map);
// We're going to test a range of WasmObject instance types with a single
// unsigned comparison.
Node* comparison_value =
Int32Sub(instance_type, Int32Constant(FIRST_WASM_OBJECT_TYPE));
return Uint32LessThanOrEqual(
comparison_value,
Int32Constant(LAST_WASM_OBJECT_TYPE - FIRST_WASM_OBJECT_TYPE));
}
// Generic HeapObject helpers.
Node* WasmGraphAssembler::HasInstanceType(Node* heap_object,
InstanceType type) {
Node* map = LoadMap(heap_object);
Node* instance_type = LoadInstanceType(map);
return Word32Equal(instance_type, Int32Constant(type));
}
} // namespace compiler
} // namespace internal
} // namespace v8

View File

@ -0,0 +1,234 @@
// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#if !V8_ENABLE_WEBASSEMBLY
#error This header should only be included if WebAssembly is enabled.
#endif // !V8_ENABLE_WEBASSEMBLY
#ifndef V8_COMPILER_WASM_GRAPH_ASSEMBLER_H_
#define V8_COMPILER_WASM_GRAPH_ASSEMBLER_H_
#include "src/compiler/graph-assembler.h"
#include "src/wasm/wasm-code-manager.h"
namespace v8 {
namespace internal {
namespace compiler {
constexpr Builtin WasmRuntimeStubIdToBuiltinName(
wasm::WasmCode::RuntimeStubId runtime_stub_id) {
switch (runtime_stub_id) {
#define DEF_CASE(name) \
case wasm::WasmCode::k##name: \
return Builtin::k##name;
#define DEF_TRAP_CASE(name) DEF_CASE(ThrowWasm##name)
WASM_RUNTIME_STUB_LIST(DEF_CASE, DEF_TRAP_CASE)
#undef DEF_CASE
#undef DEF_TRAP_CASE
default:
UNREACHABLE();
}
}
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), simplified_(zone) {}
template <typename... Args>
Node* CallRuntimeStub(wasm::WasmCode::RuntimeStubId stub_id,
Operator::Properties properties, Args*... args) {
auto* call_descriptor = GetBuiltinCallDescriptor(
WasmRuntimeStubIdToBuiltinName(stub_id), temp_zone(),
StubCallMode::kCallWasmRuntimeStub, false, properties);
// A direct call to a wasm runtime stub defined in this module.
// Just encode the stub index. This will be patched at relocation.
Node* call_target = mcgraph()->RelocatableIntPtrConstant(
stub_id, RelocInfo::WASM_STUB_CALL);
return Call(call_descriptor, call_target, args...);
}
Node* GetBuiltinPointerTarget(Builtin builtin) {
static_assert(std::is_same<Smi, BuiltinPtr>(), "BuiltinPtr must be Smi");
return NumberConstant(static_cast<int>(builtin));
}
template <typename... Args>
Node* CallBuiltin(Builtin name, Operator::Properties properties,
Args*... args) {
auto* call_descriptor = GetBuiltinCallDescriptor(
name, temp_zone(), StubCallMode::kCallBuiltinPointer, false,
properties);
Node* call_target = GetBuiltinPointerTarget(name);
return Call(call_descriptor, call_target, args...);
}
// Sets {true_node} and {false_node} to their corresponding Branch outputs.
// Returns the Branch node. Does not change control().
Node* Branch(Node* cond, Node** true_node, Node** false_node,
BranchHint hint);
Node* NumberConstant(volatile double value) {
return graph()->NewNode(mcgraph()->common()->NumberConstant(value));
}
Node* SmiConstant(Tagged_t value) {
Address tagged_value = Internals::IntToSmi(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);
}
// Helper functions for dealing with HeapObjects.
// Rule of thumb: if access to a given field in an object is required in
// at least two places, put a helper function here.
Node* Allocate(int size);
Node* Allocate(Node* size,
AllowLargeObjects allow_large = AllowLargeObjects::kTrue);
Node* LoadFromObject(MachineType type, Node* base, Node* offset);
Node* LoadFromObject(MachineType type, Node* base, int offset) {
return LoadFromObject(type, base, 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* 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* IsI31(Node* object);
// Maps and their contents.
Node* LoadMap(Node* object);
void StoreMap(Node* heap_object, Node* map);
Node* LoadInstanceType(Node* map);
Node* LoadWasmTypeInfo(Node* map);
Node* LoadSupertypes(Node* wasm_type_info);
// FixedArrays.
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* 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));
}
// Functions, SharedFunctionInfos, FunctionData.
Node* LoadSharedFunctionInfo(Node* js_function);
Node* LoadContextFromJSFunction(Node* js_function);
Node* LoadFunctionDataFromJSFunction(Node* js_function);
Node* LoadExportedFunctionIndexAsSmi(Node* exported_function_data);
Node* LoadExportedFunctionInstance(Node* exported_function_data);
// JavaScript objects.
Node* LoadJSArrayElements(Node* js_array);
// WasmGC objects.
Node* FieldOffset(const wasm::StructType* type, uint32_t field_index);
Node* StoreStructField(Node* struct_object, const wasm::StructType* type,
uint32_t field_index, Node* value);
Node* WasmArrayElementOffset(Node* index, wasm::ValueType element_type);
Node* LoadWasmArrayLength(Node* array);
Node* IsDataRefMap(Node* map);
// Generic HeapObject helpers.
Node* HasInstanceType(Node* heap_object, InstanceType type);
SimplifiedOperatorBuilder* simplified() { return &simplified_; }
private:
SimplifiedOperatorBuilder simplified_;
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_WASM_GRAPH_ASSEMBLER_H_