Commit b8a769ca authored by Manos Koukoutos's avatar Manos Koukoutos Committed by Commit Bot

[wasm-gc] Preparation for call_ref

Changes:
- Move some helper functions into WasmGraphBuilder.
- Introduce call_mode and null_check as additional arguments to
  WasmGraphBuilderInterface::DoCall/DoReturnCall.
- Introduce ValueType::is_strict_reference_type.
- Improve usage of ValueType API.

Bug: v8:9495
Change-Id: Id3fb9f0d7a4770475ac895b03b38bfa7f2fec252
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2343083
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69372}
parent ca41b837
......@@ -2895,7 +2895,7 @@ Node* WasmGraphBuilder::BuildIndirectCall(uint32_t table_index,
// Check that the dynamic type of the function is a subtype of its static
// (table) type. Currently, the only subtyping between function types is
// (ref null $t) <: funcref for all $t: function_type.
// $t <: funcref for all $t: function_type.
// TODO(7748): Expand this with function subtyping.
if (env_->module->tables[table_index].type == wasm::kWasmFuncRef) {
int32_t expected_sig_id = env_->module->signature_ids[sig_index];
......@@ -2950,6 +2950,32 @@ Node* WasmGraphBuilder::BuildIndirectCall(uint32_t table_index,
}
}
Node* WasmGraphBuilder::BuildLoadFunctionDataFromExportedFunction(
Node* closure) {
Node* shared = gasm_->Load(
MachineType::AnyTagged(), closure,
wasm::ObjectAccess::SharedFunctionInfoOffsetInTaggedJSFunction());
return gasm_->Load(MachineType::AnyTagged(), shared,
SharedFunctionInfo::kFunctionDataOffset - kHeapObjectTag);
}
Node* WasmGraphBuilder::BuildLoadJumpTableOffsetFromExportedFunctionData(
Node* function_data) {
Node* jump_table_offset_smi = gasm_->Load(
MachineType::TaggedSigned(), function_data,
WasmExportedFunctionData::kJumpTableOffsetOffset - kHeapObjectTag);
return BuildChangeSmiToIntPtr(jump_table_offset_smi);
}
Node* WasmGraphBuilder::BuildLoadFunctionIndexFromExportedFunctionData(
Node* function_data) {
Node* function_index_smi = gasm_->Load(
MachineType::TaggedSigned(), function_data,
WasmExportedFunctionData::kFunctionIndexOffset - kHeapObjectTag);
Node* function_index = BuildChangeSmiToInt32(function_index_smi);
return function_index;
}
Node* WasmGraphBuilder::ReturnCall(uint32_t index, Vector<Node*> args,
wasm::WasmCodePosition position) {
DCHECK_NULL(args[0]);
......@@ -6073,37 +6099,12 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
mcgraph()->Int32Constant(new_value ? 1 : 0), effect(), control()));
}
Node* BuildLoadFunctionDataFromExportedFunction(Node* closure) {
Node* shared = gasm_->Load(
MachineType::AnyTagged(), closure,
wasm::ObjectAccess::SharedFunctionInfoOffsetInTaggedJSFunction());
return gasm_->Load(
MachineType::AnyTagged(), shared,
SharedFunctionInfo::kFunctionDataOffset - kHeapObjectTag);
}
Node* BuildLoadInstanceFromExportedFunctionData(Node* function_data) {
return gasm_->Load(
MachineType::AnyTagged(), function_data,
WasmExportedFunctionData::kInstanceOffset - kHeapObjectTag);
}
Node* BuildLoadFunctionIndexFromExportedFunctionData(Node* function_data) {
Node* function_index_smi = gasm_->Load(
MachineType::TaggedSigned(), function_data,
WasmExportedFunctionData::kFunctionIndexOffset - kHeapObjectTag);
Node* function_index = BuildChangeSmiToInt32(function_index_smi);
return function_index;
}
Node* BuildLoadJumpTableOffsetFromExportedFunctionData(Node* function_data) {
Node* jump_table_offset_smi = gasm_->Load(
MachineType::TaggedSigned(), function_data,
WasmExportedFunctionData::kJumpTableOffsetOffset - kHeapObjectTag);
Node* jump_table_offset = BuildChangeSmiToIntPtr(jump_table_offset_smi);
return jump_table_offset;
}
Node* BuildMultiReturnFixedArrayFromIterable(const wasm::FunctionSig* sig,
Node* iterable, Node* context) {
Node* length = BuildChangeUint31ToSmi(
......
......@@ -599,6 +599,10 @@ class WasmGraphBuilder {
Node* BuildMultiReturnFixedArrayFromIterable(const wasm::FunctionSig* sig,
Node* iterable, Node* context);
Node* BuildLoadFunctionDataFromExportedFunction(Node* closure);
Node* BuildLoadJumpTableOffsetFromExportedFunctionData(Node* function_data);
Node* BuildLoadFunctionIndexFromExportedFunctionData(Node* function_data);
//-----------------------------------------------------------------------
// Operations involving the CEntry, a dependency we want to remove
// to get off the GC heap.
......
......@@ -2916,7 +2916,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
DECODE(UnknownOrAsmJs) {
// Deal with special asmjs opcodes.
if (!VALIDATE(is_asmjs_module(this->module_))) {
this->error("Invalid opcode");
this->errorf(this->pc(), "Invalid opcode 0x%x", opcode);
return 0;
}
const FunctionSig* sig = WasmOpcodes::AsmjsSignature(opcode);
......@@ -3759,8 +3759,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
return 0;
}
Value obj = Pop(0);
if (!VALIDATE(obj.type.kind() == ValueType::kRef ||
obj.type.kind() == ValueType::kOptRef)) {
if (!VALIDATE(obj.type.is_object_reference_type())) {
this->error(this->pc_, "br_on_cast[0]: expected reference on stack");
return 0;
}
......
......@@ -76,6 +76,7 @@ class WasmGraphBuildingInterface {
public:
static constexpr Decoder::ValidateFlag validate = Decoder::kValidate;
using FullDecoder = WasmFullDecoder<validate, WasmGraphBuildingInterface>;
using CheckForNull = compiler::WasmGraphBuilder::CheckForNull;
struct Value : public ValueBase {
TFNode* node = nullptr;
......@@ -452,30 +453,35 @@ class WasmGraphBuildingInterface {
LoadContextIntoSsa(ssa_env_);
}
enum CallMode { kDirect, kIndirect, kRef };
void CallDirect(FullDecoder* decoder,
const CallFunctionImmediate<validate>& imm,
const Value args[], Value returns[]) {
DoCall(decoder, 0, nullptr, imm.sig, imm.index, args, returns);
DoCall(decoder, kDirect, 0, CheckForNull::kWithoutNullCheck, nullptr,
imm.sig, imm.index, args, returns);
}
void ReturnCall(FullDecoder* decoder,
const CallFunctionImmediate<validate>& imm,
const Value args[]) {
DoReturnCall(decoder, 0, nullptr, imm.sig, imm.index, args);
DoReturnCall(decoder, kDirect, 0, CheckForNull::kWithoutNullCheck, nullptr,
imm.sig, imm.index, args);
}
void CallIndirect(FullDecoder* decoder, const Value& index,
const CallIndirectImmediate<validate>& imm,
const Value args[], Value returns[]) {
DoCall(decoder, imm.table_index, index.node, imm.sig, imm.sig_index, args,
returns);
DoCall(decoder, kIndirect, imm.table_index, CheckForNull::kWithoutNullCheck,
index.node, imm.sig, imm.sig_index, args, returns);
}
void ReturnCallIndirect(FullDecoder* decoder, const Value& index,
const CallIndirectImmediate<validate>& imm,
const Value args[]) {
DoReturnCall(decoder, imm.table_index, index.node, imm.sig, imm.sig_index,
args);
DoReturnCall(decoder, kIndirect, imm.table_index,
CheckForNull::kWithoutNullCheck, index.node, imm.sig,
imm.sig_index, args);
}
void BrOnNull(FullDecoder* decoder, const Value& ref_object, uint32_t depth) {
......@@ -672,7 +678,6 @@ class WasmGraphBuildingInterface {
void StructGet(FullDecoder* decoder, const Value& struct_object,
const FieldIndexImmediate<validate>& field, bool is_signed,
Value* result) {
using CheckForNull = compiler::WasmGraphBuilder::CheckForNull;
CheckForNull null_check = struct_object.type.is_nullable()
? CheckForNull::kWithNullCheck
: CheckForNull::kWithoutNullCheck;
......@@ -684,7 +689,6 @@ class WasmGraphBuildingInterface {
void StructSet(FullDecoder* decoder, const Value& struct_object,
const FieldIndexImmediate<validate>& field,
const Value& field_value) {
using CheckForNull = compiler::WasmGraphBuilder::CheckForNull;
CheckForNull null_check = struct_object.type.is_nullable()
? CheckForNull::kWithNullCheck
: CheckForNull::kWithoutNullCheck;
......@@ -711,7 +715,6 @@ class WasmGraphBuildingInterface {
void ArrayGet(FullDecoder* decoder, const Value& array_obj,
const ArrayIndexImmediate<validate>& imm, const Value& index,
bool is_signed, Value* result) {
using CheckForNull = compiler::WasmGraphBuilder::CheckForNull;
CheckForNull null_check = array_obj.type.is_nullable()
? CheckForNull::kWithNullCheck
: CheckForNull::kWithoutNullCheck;
......@@ -722,7 +725,6 @@ class WasmGraphBuildingInterface {
void ArraySet(FullDecoder* decoder, const Value& array_obj,
const ArrayIndexImmediate<validate>& imm, const Value& index,
const Value& value) {
using CheckForNull = compiler::WasmGraphBuilder::CheckForNull;
CheckForNull null_check = array_obj.type.is_nullable()
? CheckForNull::kWithNullCheck
: CheckForNull::kWithoutNullCheck;
......@@ -758,7 +760,6 @@ class WasmGraphBuildingInterface {
void RefTest(FullDecoder* decoder, const Value& object, const Value& rtt,
Value* result) {
using CheckForNull = compiler::WasmGraphBuilder::CheckForNull;
using CheckForI31 = compiler::WasmGraphBuilder::CheckForI31;
using RttIsI31 = compiler::WasmGraphBuilder::RttIsI31;
CheckForNull null_check = object.type.is_nullable()
......@@ -777,7 +778,6 @@ class WasmGraphBuildingInterface {
void RefCast(FullDecoder* decoder, const Value& object, const Value& rtt,
Value* result) {
using CheckForNull = compiler::WasmGraphBuilder::CheckForNull;
using CheckForI31 = compiler::WasmGraphBuilder::CheckForI31;
using RttIsI31 = compiler::WasmGraphBuilder::RttIsI31;
CheckForNull null_check = object.type.is_nullable()
......@@ -796,7 +796,6 @@ class WasmGraphBuildingInterface {
void BrOnCast(FullDecoder* decoder, const Value& object, const Value& rtt,
Value* value_on_branch, uint32_t depth) {
using CheckForNull = compiler::WasmGraphBuilder::CheckForNull;
using CheckForI31 = compiler::WasmGraphBuilder::CheckForI31;
using RttIsI31 = compiler::WasmGraphBuilder::RttIsI31;
CheckForNull null_check = object.type.is_nullable()
......@@ -1113,23 +1112,29 @@ class WasmGraphBuildingInterface {
return zone->New<SsaEnv>(zone, SsaEnv::kUnreachable, nullptr, nullptr, 0);
}
void DoCall(FullDecoder* decoder, uint32_t table_index, TFNode* index_node,
void DoCall(FullDecoder* decoder, CallMode call_mode, uint32_t table_index,
CheckForNull null_check, TFNode* caller_node,
const FunctionSig* sig, uint32_t sig_index, const Value args[],
Value returns[]) {
size_t param_count = sig->parameter_count();
size_t return_count = sig->return_count();
base::SmallVector<TFNode*, 16> arg_nodes(param_count + 1);
base::SmallVector<TFNode*, 1> return_nodes(return_count);
arg_nodes[0] = index_node;
arg_nodes[0] = caller_node;
for (size_t i = 0; i < param_count; ++i) {
arg_nodes[i + 1] = args[i].node;
}
if (index_node) {
BUILD(CallIndirect, table_index, sig_index, VectorOf(arg_nodes),
VectorOf(return_nodes), decoder->position());
} else {
BUILD(CallDirect, sig_index, VectorOf(arg_nodes), VectorOf(return_nodes),
decoder->position());
switch (call_mode) {
case kIndirect:
BUILD(CallIndirect, table_index, sig_index, VectorOf(arg_nodes),
VectorOf(return_nodes), decoder->position());
break;
case kDirect:
BUILD(CallDirect, sig_index, VectorOf(arg_nodes),
VectorOf(return_nodes), decoder->position());
break;
case kRef:
UNREACHABLE();
}
for (size_t i = 0; i < return_count; ++i) {
returns[i].node = return_nodes[i];
......@@ -1139,7 +1144,8 @@ class WasmGraphBuildingInterface {
LoadContextIntoSsa(ssa_env_);
}
void DoReturnCall(FullDecoder* decoder, uint32_t table_index,
void DoReturnCall(FullDecoder* decoder, CallMode call_mode,
uint32_t table_index, CheckForNull null_check,
TFNode* index_node, const FunctionSig* sig,
uint32_t sig_index, const Value args[]) {
size_t arg_count = sig->parameter_count();
......@@ -1148,11 +1154,16 @@ class WasmGraphBuildingInterface {
for (size_t i = 0; i < arg_count; ++i) {
arg_nodes[i + 1] = args[i].node;
}
if (index_node) {
BUILD(ReturnCallIndirect, table_index, sig_index, VectorOf(arg_nodes),
decoder->position());
} else {
BUILD(ReturnCall, sig_index, VectorOf(arg_nodes), decoder->position());
switch (call_mode) {
case kIndirect:
BUILD(ReturnCallIndirect, table_index, sig_index, VectorOf(arg_nodes),
decoder->position());
break;
case kDirect:
BUILD(ReturnCall, sig_index, VectorOf(arg_nodes), decoder->position());
break;
case kRef:
UNREACHABLE();
}
}
};
......
......@@ -703,7 +703,7 @@ class ModuleDecoderImpl : public Decoder {
WasmTable* table = &module_->tables.back();
const byte* type_position = pc();
table->type = consume_reference_type();
if (table->type.kind() != ValueType::kOptRef) {
if (!table->type.is_nullable()) {
// TODO(7748): Implement other table types.
error(type_position,
"Currently, only nullable references are allowed as table types");
......
......@@ -1878,6 +1878,7 @@ bool LoadElemSegmentImpl(Isolate* isolate, Handle<WasmInstanceObject> instance,
const WasmFunction* function = &module->functions[func_index];
// Update the local dispatch table first if necessary.
// TODO(9495): Make sure tables work with all function types.
if (table_object->type().is_reference_to(HeapType::kFunc)) {
uint32_t sig_id = module->signature_ids[function->sig_index];
IndirectFunctionTableEntry(instance, table_index, entry_index)
......
......@@ -163,6 +163,10 @@ class ValueType {
return kind() == kRef || kind() == kOptRef || kind() == kRtt;
}
constexpr bool is_object_reference_type() const {
return kind() == kRef || kind() == kOptRef;
}
constexpr bool is_packed() const { return kind() == kI8 || kind() == kI16; }
constexpr bool is_nullable() const { return kind() == kOptRef; }
......
......@@ -118,7 +118,7 @@ struct WasmElemSegment {
// Construct an active segment.
WasmElemSegment(uint32_t table_index, WasmInitExpr offset)
: type(ValueType::Ref(HeapType::kFunc, kNullable)),
: type(kWasmFuncRef),
table_index(table_index),
offset(std::move(offset)),
status(kStatusActive) {}
......@@ -126,7 +126,7 @@ struct WasmElemSegment {
// Construct a passive or declarative segment, which has no table index or
// offset.
explicit WasmElemSegment(bool declarative)
: type(ValueType::Ref(HeapType::kFunc, kNullable)),
: type(kWasmFuncRef),
table_index(0),
status(declarative ? kStatusDeclarative : kStatusPassive) {}
......
......@@ -39,8 +39,7 @@ bool IsJSCompatibleSignature(const FunctionSig* sig,
if (type == kWasmS128) return false;
if (type.kind() == wasm::ValueType::kRef ||
type.kind() == wasm::ValueType::kOptRef) {
if (type.is_object_reference_type()) {
uint32_t representation = type.heap_representation();
// TODO(7748): Once there's a story for JS interop for struct/array types,
// allow them here.
......
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