[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:
Andreas Haas 2020-03-19 14:49:52 +01:00 committed by Commit Bot
parent 599a6e0ae8
commit ca5ee9d636
8 changed files with 85 additions and 22 deletions

View File

@ -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) \

View File

@ -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));

View File

@ -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);

View File

@ -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)

View File

@ -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,

View File

@ -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);

View File

@ -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) \

View File

@ -55,6 +55,7 @@ struct WasmModule;
V(WasmI64AtomicWait32) \
V(WasmI64AtomicWait64) \
V(WasmMemoryGrow) \
V(WasmTableInit) \
V(WasmTableGet) \
V(WasmTableSet) \
V(WasmStackGuard) \