Commit 1e1d4d82 authored by Andreas Haas's avatar Andreas Haas Committed by Commit Bot

[wasm] Introduce a TableCopy builtin

This CL introduces a CSA builtin for the TableCopy 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.

R=clemensb@chromium.org

Bug: v8:10281
Change-Id: I4734b94c8a2aff08a5938504e3e36d0d2424f8ca
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2110010
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66797}
parent d1253ae9
......@@ -858,6 +858,7 @@ namespace internal {
TFC(WasmI64AtomicWait64, WasmI64AtomicWait64) \
TFC(WasmMemoryGrow, WasmMemoryGrow) \
TFC(WasmTableInit, WasmTableInit) \
TFC(WasmTableCopy, WasmTableCopy) \
TFC(WasmTableGet, WasmTableGet) \
TFC(WasmTableSet, WasmTableSet) \
TFC(WasmStackGuard, NoContext) \
......
......@@ -248,6 +248,39 @@ TF_BUILTIN(WasmTableInit, WasmBuiltinsAssembler) {
segment_index, dst, src, size);
}
TF_BUILTIN(WasmTableCopy, WasmBuiltinsAssembler) {
// 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<Uint32T> dst_raw =
UncheckedCast<Uint32T>(Parameter(Descriptor::kDestination));
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> dst_table =
UncheckedCast<Smi>(Parameter(Descriptor::kDestinationTable));
TNode<Smi> src_table =
UncheckedCast<Smi>(Parameter(Descriptor::kSourceTable));
TNode<WasmInstanceObject> instance = LoadInstanceFromFrame();
TNode<Context> context = LoadContextFromInstance(instance);
TailCallRuntime(Runtime::kWasmTableCopy, context, instance, dst_table,
src_table, dst, src, size);
}
TF_BUILTIN(WasmTableGet, WasmBuiltinsAssembler) {
TNode<Int32T> entry_index =
UncheckedCast<Int32T>(Parameter(Descriptor::kEntryIndex));
......
......@@ -386,6 +386,12 @@ void WasmTableInitDescriptor::InitializePlatformSpecific(
kParameterCount - kStackArgumentsCount);
}
void WasmTableCopyDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
DefaultInitializePlatformSpecific(data,
kParameterCount - kStackArgumentsCount);
}
void WasmTableGetDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
DefaultInitializePlatformSpecific(data, kParameterCount);
......
......@@ -97,6 +97,7 @@ namespace internal {
V(WasmI64AtomicWait64) \
V(WasmMemoryGrow) \
V(WasmTableInit) \
V(WasmTableCopy) \
V(WasmTableGet) \
V(WasmTableSet) \
V(WasmThrow) \
......@@ -1319,6 +1320,29 @@ class WasmTableInitDescriptor final : public CallInterfaceDescriptor {
DECLARE_DESCRIPTOR(WasmTableInitDescriptor, CallInterfaceDescriptor)
};
class WasmTableCopyDescriptor final : public CallInterfaceDescriptor {
public:
DEFINE_PARAMETERS_NO_CONTEXT(kDestination, kSource, kSize, kDestinationTable,
kSourceTable)
DEFINE_PARAMETER_TYPES(MachineType::Int32(), // kDestination
MachineType::Int32(), // kSource
MachineType::Int32(), // kSize
MachineType::AnyTagged(), // kDestinationTable
MachineType::AnyTagged(), // kSourceTable
)
#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(WasmTableCopyDescriptor, CallInterfaceDescriptor)
};
class WasmTableGetDescriptor final : public CallInterfaceDescriptor {
public:
DEFINE_PARAMETERS_NO_CONTEXT(kTableIndex, kEntryIndex)
......
......@@ -4996,16 +4996,17 @@ Node* WasmGraphBuilder::TableCopy(uint32_t table_dst_index,
uint32_t table_src_index, Node* dst,
Node* src, Node* size,
wasm::WasmCodePosition position) {
Node* args[] = {
graph()->NewNode(mcgraph()->common()->NumberConstant(table_dst_index)),
graph()->NewNode(mcgraph()->common()->NumberConstant(table_src_index)),
BuildConvertUint32ToSmiWithSaturation(dst, FLAG_wasm_max_table_size),
BuildConvertUint32ToSmiWithSaturation(src, FLAG_wasm_max_table_size),
BuildConvertUint32ToSmiWithSaturation(size, FLAG_wasm_max_table_size)};
Node* result =
BuildCallToRuntime(Runtime::kWasmTableCopy, args, arraysize(args));
auto call_descriptor = GetBuiltinCallDescriptor<WasmTableCopyDescriptor>(
this, StubCallMode::kCallWasmRuntimeStub);
return result;
intptr_t target = wasm::WasmCode::kWasmTableCopy;
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_dst_index)),
graph()->NewNode(mcgraph()->common()->NumberConstant(table_src_index)));
}
Node* WasmGraphBuilder::TableGrow(uint32_t table_index, Node* value,
......
......@@ -516,16 +516,15 @@ RUNTIME_FUNCTION(Runtime_WasmTableInit) {
RUNTIME_FUNCTION(Runtime_WasmTableCopy) {
HandleScope scope(isolate);
DCHECK_EQ(5, args.length());
DCHECK(isolate->context().is_null());
isolate->set_context(GetNativeContextFromWasmInstanceOnStackTop(isolate));
auto instance =
Handle<WasmInstanceObject>(GetWasmInstanceOnStackTop(isolate), isolate);
CONVERT_UINT32_ARG_CHECKED(table_dst_index, 0);
CONVERT_UINT32_ARG_CHECKED(table_src_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_dst_index, 1);
CONVERT_UINT32_ARG_CHECKED(table_src_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());
bool oob = !WasmInstanceObject::CopyTableEntries(
isolate, instance, table_dst_index, table_src_index, dst, src, count);
......
......@@ -570,7 +570,7 @@ namespace internal {
F(WasmFunctionTableGet, 3, 1) \
F(WasmFunctionTableSet, 4, 1) \
F(WasmTableInit, 6, 1) \
F(WasmTableCopy, 5, 1) \
F(WasmTableCopy, 6, 1) \
F(WasmTableGrow, 3, 1) \
F(WasmTableFill, 4, 1) \
F(WasmIsValidFuncRefValue, 1, 1) \
......
......@@ -56,6 +56,7 @@ struct WasmModule;
V(WasmI64AtomicWait64) \
V(WasmMemoryGrow) \
V(WasmTableInit) \
V(WasmTableCopy) \
V(WasmTableGet) \
V(WasmTableSet) \
V(WasmStackGuard) \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment