[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:
parent
253d03dcb3
commit
eac584cda3
@ -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": [],
|
||||
|
2
BUILD.gn
2
BUILD.gn
@ -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",
|
||||
]
|
||||
|
@ -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,
|
||||
|
288
src/compiler/wasm-graph-assembler.cc
Normal file
288
src/compiler/wasm-graph-assembler.cc
Normal 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
|
234
src/compiler/wasm-graph-assembler.h
Normal file
234
src/compiler/wasm-graph-assembler.h
Normal 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_
|
Loading…
Reference in New Issue
Block a user