[wasm] Introduce a WasmTableInit CSA builtin
This CL introduces a CSA builtin for the TableInit instruction. This builtin allows to generate smaller code for both TurboFan and Liftoff, and easier code generation from Liftoff. The smaller code size comes from: * Parameters are passed through registers, not the stack. * Lower number of parameters: the call target, number of parameters, and context are not passed as parameters. * No int to smi conversion in generated code. The CL also introduces a small CSA function which takes an uint32 value and a max value as parameters and returns a Smi of the minimum of these two. R=clemensb@chromium.org, ishell@chromium.org Bug: v8:10281 Change-Id: I40f248c20ec76e6ae9483a5e2907a68f42f2cb04 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2106201 Commit-Queue: Andreas Haas <ahaas@chromium.org> Reviewed-by: Clemens Backes <clemensb@chromium.org> Reviewed-by: Igor Sheludko <ishell@chromium.org> Cr-Commit-Position: refs/heads/master@{#66792}
This commit is contained in:
parent
599a6e0ae8
commit
ca5ee9d636
@ -857,6 +857,7 @@ namespace internal {
|
||||
TFC(WasmI64AtomicWait32, WasmI64AtomicWait32) \
|
||||
TFC(WasmI64AtomicWait64, WasmI64AtomicWait64) \
|
||||
TFC(WasmMemoryGrow, WasmMemoryGrow) \
|
||||
TFC(WasmTableInit, WasmTableInit) \
|
||||
TFC(WasmTableGet, WasmTableGet) \
|
||||
TFC(WasmTableSet, WasmTableSet) \
|
||||
TFC(WasmStackGuard, NoContext) \
|
||||
|
@ -28,6 +28,13 @@ class WasmBuiltinsAssembler : public CodeStubAssembler {
|
||||
IntPtrConstant(WasmInstanceObject::kNativeContextOffset -
|
||||
kHeapObjectTag)));
|
||||
}
|
||||
|
||||
TNode<Smi> SmiFromUint32WithSaturation(TNode<Uint32T> value, uint32_t max) {
|
||||
DCHECK_LE(max, static_cast<uint32_t>(Smi::kMaxValue));
|
||||
TNode<Uint32T> capped_value = SelectConstant(
|
||||
Uint32LessThan(value, Uint32Constant(max)), value, Uint32Constant(max));
|
||||
return SmiFromUint32(capped_value);
|
||||
}
|
||||
};
|
||||
|
||||
TF_BUILTIN(WasmStackGuard, WasmBuiltinsAssembler) {
|
||||
@ -214,6 +221,33 @@ TF_BUILTIN(WasmMemoryGrow, WasmBuiltinsAssembler) {
|
||||
Return(Int32Constant(-1));
|
||||
}
|
||||
|
||||
TF_BUILTIN(WasmTableInit, WasmBuiltinsAssembler) {
|
||||
TNode<Uint32T> dst_raw =
|
||||
UncheckedCast<Uint32T>(Parameter(Descriptor::kDestination));
|
||||
// We cap {dst}, {src}, and {size} by {wasm::kV8MaxWasmTableSize + 1} to make
|
||||
// sure that the values fit into a Smi.
|
||||
STATIC_ASSERT(static_cast<size_t>(Smi::kMaxValue) >=
|
||||
wasm::kV8MaxWasmTableSize + 1);
|
||||
constexpr uint32_t kCap =
|
||||
static_cast<uint32_t>(wasm::kV8MaxWasmTableSize + 1);
|
||||
TNode<Smi> dst = SmiFromUint32WithSaturation(dst_raw, kCap);
|
||||
TNode<Uint32T> src_raw =
|
||||
UncheckedCast<Uint32T>(Parameter(Descriptor::kSource));
|
||||
TNode<Smi> src = SmiFromUint32WithSaturation(src_raw, kCap);
|
||||
TNode<Uint32T> size_raw =
|
||||
UncheckedCast<Uint32T>(Parameter(Descriptor::kSize));
|
||||
TNode<Smi> size = SmiFromUint32WithSaturation(size_raw, kCap);
|
||||
TNode<Smi> table_index =
|
||||
UncheckedCast<Smi>(Parameter(Descriptor::kTableIndex));
|
||||
TNode<Smi> segment_index =
|
||||
UncheckedCast<Smi>(Parameter(Descriptor::kSegmentIndex));
|
||||
TNode<WasmInstanceObject> instance = LoadInstanceFromFrame();
|
||||
TNode<Context> context = LoadContextFromInstance(instance);
|
||||
|
||||
TailCallRuntime(Runtime::kWasmTableInit, context, instance, table_index,
|
||||
segment_index, dst, src, size);
|
||||
}
|
||||
|
||||
TF_BUILTIN(WasmTableGet, WasmBuiltinsAssembler) {
|
||||
TNode<Int32T> entry_index =
|
||||
UncheckedCast<Int32T>(Parameter(Descriptor::kEntryIndex));
|
||||
|
@ -380,6 +380,12 @@ void WasmMemoryGrowDescriptor::InitializePlatformSpecific(
|
||||
DefaultInitializePlatformSpecific(data, kParameterCount);
|
||||
}
|
||||
|
||||
void WasmTableInitDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
DefaultInitializePlatformSpecific(data,
|
||||
kParameterCount - kStackArgumentsCount);
|
||||
}
|
||||
|
||||
void WasmTableGetDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
DefaultInitializePlatformSpecific(data, kParameterCount);
|
||||
|
@ -96,6 +96,7 @@ namespace internal {
|
||||
V(WasmI64AtomicWait32) \
|
||||
V(WasmI64AtomicWait64) \
|
||||
V(WasmMemoryGrow) \
|
||||
V(WasmTableInit) \
|
||||
V(WasmTableGet) \
|
||||
V(WasmTableSet) \
|
||||
V(WasmThrow) \
|
||||
@ -1295,6 +1296,29 @@ class WasmMemoryGrowDescriptor final : public CallInterfaceDescriptor {
|
||||
DECLARE_DESCRIPTOR(WasmMemoryGrowDescriptor, CallInterfaceDescriptor)
|
||||
};
|
||||
|
||||
class WasmTableInitDescriptor final : public CallInterfaceDescriptor {
|
||||
public:
|
||||
DEFINE_PARAMETERS_NO_CONTEXT(kDestination, kSource, kSize, kTableIndex,
|
||||
kSegmentIndex)
|
||||
DEFINE_PARAMETER_TYPES(MachineType::Int32(), // kDestination
|
||||
MachineType::Int32(), // kSource
|
||||
MachineType::Int32(), // kSize
|
||||
MachineType::AnyTagged(), // kTableIndex
|
||||
MachineType::AnyTagged(), // kSegmentindex
|
||||
)
|
||||
|
||||
#if V8_TARGET_ARCH_IA32
|
||||
static constexpr bool kPassLastArgOnStack = true;
|
||||
#else
|
||||
static constexpr bool kPassLastArgOnStack = false;
|
||||
#endif
|
||||
|
||||
// Pass the last parameter through the stack.
|
||||
static constexpr int kStackArgumentsCount = kPassLastArgOnStack ? 1 : 0;
|
||||
|
||||
DECLARE_DESCRIPTOR(WasmTableInitDescriptor, CallInterfaceDescriptor)
|
||||
};
|
||||
|
||||
class WasmTableGetDescriptor final : public CallInterfaceDescriptor {
|
||||
public:
|
||||
DEFINE_PARAMETERS_NO_CONTEXT(kTableIndex, kEntryIndex)
|
||||
|
@ -4956,19 +4956,18 @@ Node* WasmGraphBuilder::TableInit(uint32_t table_index,
|
||||
uint32_t elem_segment_index, Node* dst,
|
||||
Node* src, Node* size,
|
||||
wasm::WasmCodePosition position) {
|
||||
DCHECK_LT(table_index, env_->module->tables.size());
|
||||
// The elem segment index must be in bounds since it is required by
|
||||
// validation.
|
||||
DCHECK_LT(elem_segment_index, env_->module->elem_segments.size());
|
||||
auto call_descriptor = GetBuiltinCallDescriptor<WasmTableInitDescriptor>(
|
||||
this, StubCallMode::kCallWasmRuntimeStub);
|
||||
|
||||
Node* args[] = {
|
||||
intptr_t target = wasm::WasmCode::kWasmTableInit;
|
||||
Node* call_target =
|
||||
mcgraph()->RelocatableIntPtrConstant(target, RelocInfo::WASM_STUB_CALL);
|
||||
|
||||
return gasm_->Call(
|
||||
call_descriptor, call_target, dst, src, size,
|
||||
graph()->NewNode(mcgraph()->common()->NumberConstant(table_index)),
|
||||
graph()->NewNode(mcgraph()->common()->NumberConstant(elem_segment_index)),
|
||||
BuildConvertUint32ToSmiWithSaturation(dst, FLAG_wasm_max_table_size),
|
||||
BuildConvertUint32ToSmiWithSaturation(src, FLAG_wasm_max_table_size),
|
||||
BuildConvertUint32ToSmiWithSaturation(size, FLAG_wasm_max_table_size)};
|
||||
return SetEffect(
|
||||
BuildCallToRuntime(Runtime::kWasmTableInit, args, arraysize(args)));
|
||||
graph()->NewNode(
|
||||
mcgraph()->common()->NumberConstant(elem_segment_index)));
|
||||
}
|
||||
|
||||
Node* WasmGraphBuilder::ElemDrop(uint32_t elem_segment_index,
|
||||
|
@ -498,17 +498,15 @@ RUNTIME_FUNCTION(Runtime_WasmFunctionTableSet) {
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_WasmTableInit) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(5, args.length());
|
||||
auto instance =
|
||||
Handle<WasmInstanceObject>(GetWasmInstanceOnStackTop(isolate), isolate);
|
||||
CONVERT_UINT32_ARG_CHECKED(table_index, 0);
|
||||
CONVERT_UINT32_ARG_CHECKED(elem_segment_index, 1);
|
||||
CONVERT_UINT32_ARG_CHECKED(dst, 2);
|
||||
CONVERT_UINT32_ARG_CHECKED(src, 3);
|
||||
CONVERT_UINT32_ARG_CHECKED(count, 4);
|
||||
DCHECK_EQ(6, args.length());
|
||||
CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
|
||||
CONVERT_UINT32_ARG_CHECKED(table_index, 1);
|
||||
CONVERT_UINT32_ARG_CHECKED(elem_segment_index, 2);
|
||||
CONVERT_UINT32_ARG_CHECKED(dst, 3);
|
||||
CONVERT_UINT32_ARG_CHECKED(src, 4);
|
||||
CONVERT_UINT32_ARG_CHECKED(count, 5);
|
||||
|
||||
DCHECK(isolate->context().is_null());
|
||||
isolate->set_context(instance->native_context());
|
||||
DCHECK(!isolate->context().is_null());
|
||||
|
||||
bool oob = !WasmInstanceObject::InitTableEntries(
|
||||
isolate, instance, table_index, elem_segment_index, dst, src, count);
|
||||
|
@ -569,7 +569,7 @@ namespace internal {
|
||||
F(WasmRefFunc, 1, 1) \
|
||||
F(WasmFunctionTableGet, 3, 1) \
|
||||
F(WasmFunctionTableSet, 4, 1) \
|
||||
F(WasmTableInit, 5, 1) \
|
||||
F(WasmTableInit, 6, 1) \
|
||||
F(WasmTableCopy, 5, 1) \
|
||||
F(WasmTableGrow, 3, 1) \
|
||||
F(WasmTableFill, 4, 1) \
|
||||
|
@ -55,6 +55,7 @@ struct WasmModule;
|
||||
V(WasmI64AtomicWait32) \
|
||||
V(WasmI64AtomicWait64) \
|
||||
V(WasmMemoryGrow) \
|
||||
V(WasmTableInit) \
|
||||
V(WasmTableGet) \
|
||||
V(WasmTableSet) \
|
||||
V(WasmStackGuard) \
|
||||
|
Loading…
Reference in New Issue
Block a user