Commit 8d4027d4 authored by Jakob Kummerow's avatar Jakob Kummerow Committed by Commit Bot

[wasm-gc] Parse struct.new/struct.get

The former is backed by a runtime function for now.
No Liftoff or interpreter implementation yet.

Bug: v8:7748
Change-Id: If2e1bf6e7a5267c5e64529bb5a686e548682e80a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2154199Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67276}
parent 33ea5e55
......@@ -5054,6 +5054,47 @@ Node* WasmGraphBuilder::TableFill(uint32_t table_index, Node* start,
return BuildCallToRuntime(Runtime::kWasmTableFill, args, arraysize(args));
}
MachineType FieldType(const wasm::StructType* type, uint32_t field_index) {
return MachineType::TypeForRepresentation(
type->field(field_index).machine_representation());
}
Node* FieldOffset(MachineGraph* graph, const wasm::StructType* type,
uint32_t field_index) {
int offset = WasmStruct::kHeaderSize + type->field_offset(field_index) -
kHeapObjectTag;
return graph->IntPtrConstant(offset);
}
Node* WasmGraphBuilder::StructNew(uint32_t struct_index,
const wasm::StructType* type,
Vector<Node*> fields) {
Node* runtime_args[] = {
graph()->NewNode(mcgraph()->common()->NumberConstant(struct_index))};
// TODO(7748): Make this more efficient: ideally an inline allocation,
// or at least go through a builtin to save code size.
Node* s = BuildCallToRuntime(Runtime::kWasmStructNew, runtime_args,
arraysize(runtime_args));
for (uint32_t i = 0; i < type->field_count(); i++) {
wasm::ValueType field_type = type->field(i);
WriteBarrierKind write_barrier = type->field(i).IsReferenceType()
? kPointerWriteBarrier
: kNoWriteBarrier;
StoreRepresentation rep(field_type.machine_representation(), write_barrier);
Node* offset = FieldOffset(mcgraph(), type, i);
gasm_->Store(rep, s, offset, fields[i]);
}
return s;
}
Node* WasmGraphBuilder::StructGet(Node* struct_object,
const wasm::StructType* type,
uint32_t field_index) {
MachineType machine_type = FieldType(type, field_index);
Node* offset = FieldOffset(mcgraph(), type, field_index);
return gasm_->Load(machine_type, struct_object, offset);
}
class WasmDecorator final : public GraphDecorator {
public:
explicit WasmDecorator(NodeOriginTable* origins, wasm::Decoder* decoder)
......
......@@ -385,6 +385,11 @@ class WasmGraphBuilder {
Node* TableSize(uint32_t table_index);
Node* TableFill(uint32_t table_index, Node* start, Node* value, Node* count);
Node* StructNew(uint32_t struct_index, const wasm::StructType* type,
Vector<Node*> fields);
Node* StructGet(Node* struct_object, const wasm::StructType* type,
uint32_t field_index);
bool has_simd() const { return has_simd_; }
wasm::UseTrapHandler use_trap_handler() const {
......
......@@ -461,6 +461,22 @@ RUNTIME_FUNCTION(Runtime_WasmRefFunc) {
return *function;
}
RUNTIME_FUNCTION(Runtime_WasmStructNew) {
ClearThreadInWasmScope flag_scope;
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
Handle<WasmInstanceObject> instance =
handle(GetWasmInstanceOnStackTop(isolate), isolate);
DCHECK(isolate->context().is_null());
isolate->set_context(instance->native_context());
CONVERT_UINT32_ARG_CHECKED(struct_index, 0);
Handle<Map> map =
WasmInstanceObject::GetOrCreateStructMap(isolate, instance, struct_index);
Handle<Object> obj = isolate->factory()->NewWasmStruct(map);
return *obj;
}
RUNTIME_FUNCTION(Runtime_WasmFunctionTableGet) {
ClearThreadInWasmScope flag_scope;
HandleScope scope(isolate);
......
......@@ -577,7 +577,8 @@ namespace internal {
F(WasmCompileLazy, 2, 1) \
F(WasmNewMultiReturnFixedArray, 1, 1) \
F(WasmNewMultiReturnJSArray, 1, 1) \
F(WasmDebugBreak, 0, 1)
F(WasmDebugBreak, 0, 1) \
F(WasmStructNew, 1, 1)
#define FOR_EACH_INTRINSIC_WEAKREF(F, I) \
F(ShrinkFinalizationRegistryUnregisterTokenMap, 1, 1)
......
......@@ -3234,6 +3234,18 @@ class LiftoffCompiler {
unsupported(decoder, kAnyRef, "table.fill");
}
void StructNew(FullDecoder* decoder,
const StructIndexImmediate<validate>& imm, const Value args[],
Value* result) {
// TODO(7748): Implement.
unsupported(decoder, kGC, "struct.new");
}
void StructGet(FullDecoder* decoder, const Value& struct_obj,
const FieldIndexImmediate<validate>& field, Value* result) {
// TODO(7748): Implement.
unsupported(decoder, kGC, "struct.get");
}
private:
// Emit additional source positions for return addresses. Used by debugging to
// OSR frames with different sets of breakpoints.
......
......@@ -45,6 +45,7 @@ enum LiftoffBailoutReason : int8_t {
kAtomics = 10,
kBulkMemory = 11,
kNonTrappingFloatToInt = 12,
kGC = 13,
// A little gap, for forward compatibility.
// Any other reason (use rarely; introduce new reasons if this spikes).
kOtherReason = 20,
......
......@@ -373,6 +373,29 @@ struct TableIndexImmediate {
}
};
template <Decoder::ValidateFlag validate>
struct StructIndexImmediate {
uint32_t index = 0;
uint32_t length = 0;
const StructType* struct_type = nullptr;
inline StructIndexImmediate(Decoder* decoder, const byte* pc) {
index = decoder->read_u32v<validate>(pc, &length, "struct index");
}
};
template <Decoder::ValidateFlag validate>
struct FieldIndexImmediate {
StructIndexImmediate<validate> struct_index;
uint32_t index = 0;
uint32_t length = 0;
inline FieldIndexImmediate(Decoder* decoder, const byte* pc)
: struct_index(decoder, pc) {
index = decoder->read_u32v<validate>(pc + struct_index.length, &length,
"field index");
length += struct_index.length;
}
};
template <Decoder::ValidateFlag validate>
struct CallIndirectImmediate {
uint32_t table_index;
......@@ -774,7 +797,11 @@ enum class LoadTransformationKind : uint8_t {
const Value& delta, Value* result) \
F(TableSize, const TableIndexImmediate<validate>& imm, Value* result) \
F(TableFill, const TableIndexImmediate<validate>& imm, const Value& start, \
const Value& value, const Value& count)
const Value& value, const Value& count) \
F(StructNew, const StructIndexImmediate<validate>& imm, const Value args[], \
Value* result) \
F(StructGet, const Value& struct_object, \
const FieldIndexImmediate<validate>& field, Value* result)
// Generic Wasm bytecode decoder with utilities for decoding immediates,
// lengths, etc.
......@@ -989,6 +1016,27 @@ class WasmDecoder : public Decoder {
return true;
}
inline bool Complete(const byte* pc, StructIndexImmediate<validate>& imm) {
if (!VALIDATE(module_ != nullptr && module_->has_struct(imm.index))) {
return false;
}
imm.struct_type = module_->struct_type(imm.index);
return true;
}
inline bool Validate(const byte* pc, StructIndexImmediate<validate>& imm) {
if (Complete(pc, imm)) return true;
errorf(pc, "invalid struct index: %u", imm.index);
return false;
}
inline bool Validate(const byte* pc, FieldIndexImmediate<validate>& imm) {
if (!Validate(pc, imm.struct_index)) return false;
if (imm.index < imm.struct_index.struct_type->field_count()) return true;
errorf(pc + imm.struct_index.length, "invalid field index: %u", imm.index);
return false;
}
inline bool CanReturnCall(const FunctionSig* target_sig) {
if (target_sig == nullptr) return false;
size_t num_returns = sig_->return_count();
......@@ -2371,6 +2419,16 @@ class WasmFullDecoder : public WasmDecoder<validate> {
len += DecodeAtomicOpcode(opcode);
break;
}
case kGCPrefix: {
CHECK_PROTOTYPE_OPCODE(gc);
byte gc_index =
this->template read_u8<validate>(this->pc_ + 1, "gc index");
opcode = static_cast<WasmOpcode>(opcode << 8 | gc_index);
TRACE_PART(TRACE_INST_FORMAT, startrel(this->pc_),
WasmOpcodes::OpcodeName(opcode));
len = DecodeGCOpcode(opcode);
break;
}
// Note that prototype opcodes are not handled in the fastpath
// above this switch, to avoid checking a feature flag.
#define SIMPLE_PROTOTYPE_CASE(name, opc, sig) \
......@@ -2504,6 +2562,15 @@ class WasmFullDecoder : public WasmDecoder<validate> {
return args;
}
V8_INLINE ArgVector PopArgs(const StructType* type) {
int count = static_cast<int>(type->field_count());
ArgVector args(count);
for (int i = count - 1; i >= 0; i--) {
args[i] = Pop(i, type->field(i));
}
return args;
}
ValueType GetReturnType(const FunctionSig* sig) {
DCHECK_GE(1, sig->return_count());
return sig->return_count() == 0 ? kWasmStmt : sig->GetReturn();
......@@ -2812,6 +2879,49 @@ class WasmFullDecoder : public WasmDecoder<validate> {
return len;
}
uint32_t DecodeGCOpcode(WasmOpcode opcode) {
uint32_t len = 2;
switch (opcode) {
case kExprStructNew: {
StructIndexImmediate<validate> imm(this, this->pc_ + len);
len += imm.length;
if (!this->Validate(this->pc_, imm)) break;
auto args = PopArgs(imm.struct_type);
auto* value = Push(ValueType(ValueType::kEqRef, imm.index));
CALL_INTERFACE_IF_REACHABLE(StructNew, imm, args.begin(), value);
break;
}
case kExprStructGet: {
FieldIndexImmediate<validate> field(this, this->pc_ + len);
if (!this->Validate(this->pc_ + len, field)) break;
len += field.length;
auto struct_obj = Pop(0, kWasmEqRef);
auto* value = Push(field.struct_index.struct_type->field(field.index));
CALL_INTERFACE_IF_REACHABLE(StructGet, struct_obj, field, value);
break;
}
case kExprStructSet:
UNIMPLEMENTED(); // TODO(7748): Implement.
break;
case kExprArrayNew:
UNIMPLEMENTED(); // TODO(7748): Implement.
break;
case kExprArrayGet:
UNIMPLEMENTED(); // TODO(7748): Implement.
break;
case kExprArraySet:
UNIMPLEMENTED(); // TODO(7748): Implement.
break;
case kExprArrayLen:
UNIMPLEMENTED(); // TODO(7748): Implement.
break;
default:
this->error("invalid gc opcode");
return 0;
}
return len;
}
uint32_t DecodeAtomicOpcode(WasmOpcode opcode) {
uint32_t len = 0;
ValueType ret_type;
......@@ -3222,6 +3332,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
if (WasmOpcodes::IsAnyRefOpcode(opcode)) {
RET_ON_PROTOTYPE_OPCODE(anyref);
}
// TODO(7748): Add RefEq support here.
const FunctionSig* sig = WasmOpcodes::Signature(opcode);
BuildSimpleOperator(opcode, sig);
}
......
......@@ -600,6 +600,24 @@ class WasmGraphBuildingInterface {
BUILD(TableFill, imm.index, start.node, value.node, count.node);
}
void StructNew(FullDecoder* decoder,
const StructIndexImmediate<validate>& imm, const Value args[],
Value* result) {
uint32_t field_count = imm.struct_type->field_count();
base::SmallVector<TFNode*, 16> arg_nodes(field_count);
for (uint32_t i = 0; i < field_count; i++) {
arg_nodes[i] = args[i].node;
}
result->node =
BUILD(StructNew, imm.index, imm.struct_type, VectorOf(arg_nodes));
}
void StructGet(FullDecoder* decoder, const Value& struct_object,
const FieldIndexImmediate<validate>& field, Value* result) {
result->node = BUILD(StructGet, struct_object.node,
field.struct_index.struct_type, field.index);
}
private:
SsaEnv* ssa_env_ = nullptr;
compiler::WasmGraphBuilder* builder_;
......
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