Commit cab9ad05 authored by Manos Koukoutos's avatar Manos Koukoutos Committed by V8 LUCI CQ

[wasm] Documentation and small cleanups

Change-Id: Ia3ef956926b54add138936e3e7d03a0faa457ff9
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3913127Reviewed-by: 's avatarSimon Zünd <szuend@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#83422}
parent 6eb99796
......@@ -17,9 +17,8 @@ namespace compiler {
class MachineGraph;
// Eliminate allocated objects which are only assigned to.
// Current restrictions: Does not work for arrays (until they are also allocated
// with AllocateRaw). Does not work if the allocated object is passed to a phi.
// Eliminate allocated objects with no uses other than as store targets.
// Future work: Also exclude phis and renamings from uses.
class WasmEscapeAnalysis final : public AdvancedReducer {
public:
WasmEscapeAnalysis(Editor* editor, MachineGraph* mcgraph)
......
......@@ -117,6 +117,9 @@ wasm::TypeInModule WasmGCOperatorReducer::ObjectTypeFromContext(Node* object,
: type_from_node;
}
// If the condition of this node's branch is a type check or a null check,
// add the additional information about the type-checked node to the path
// state.
Reduction WasmGCOperatorReducer::ReduceIf(Node* node, bool condition) {
DCHECK(node->opcode() == IrOpcode::kIfTrue ||
node->opcode() == IrOpcode::kIfFalse);
......@@ -184,7 +187,7 @@ Reduction WasmGCOperatorReducer::ReduceMerge(Node* node) {
// Change the current type block list to a longest common prefix of this
// state list and the other list. (The common prefix should correspond to
// the state of the common dominator.)
// TODO(manoskouk): Consider computing intersections for some types.
// TODO(manoskouk): Consider computing unions for some types.
types.ResetToCommonAncestor(GetState(*input_it));
}
return UpdateStates(node, types);
......
......@@ -35,9 +35,11 @@ struct NodeWithType {
wasm::TypeInModule type;
};
// This class optimizes away wasm-gc nodes based on the types of their
// arguments. Although types have been assigned to nodes already, this class
// also tracks additional type information along control paths.
// This class optimizes away wasm-gc type checks and casts. Two types of
// information are used:
// - Types already marked on graph nodes.
// - Path-dependent type information that is inferred when a type check is used
// as a branch condition.
class WasmGCOperatorReducer final
: public AdvancedReducerWithControlPathState<NodeWithType,
kMultipleInstances> {
......@@ -61,6 +63,8 @@ class WasmGCOperatorReducer final
Reduction ReduceStart(Node* node);
Node* SetType(Node* node, wasm::ValueType type);
// Returns the intersection of the type marked on {object} and the type
// information about object tracked on {control}'s control path (if present).
wasm::TypeInModule ObjectTypeFromContext(Node* object, Node* control);
Reduction UpdateNodeAndAliasesTypes(Node* state_owner,
ControlPathTypes parent_state, Node* node,
......
......@@ -55,7 +55,12 @@ class WasmInliner final : public AdvancedReducer {
const char* reducer_name() const override { return "WasmInliner"; }
// Registers (tail) calls to possibly be inlined, prioritized by inlining
// heuristics provided by {LexicographicOrdering}.
// Only locally defined functions are inlinable, and a limited number of
// inlinings of a specific function is allowed.
Reduction Reduce(Node* node) final;
// Inlines calls registered by {Reduce}, until an inlining budget is exceeded.
void Finalize() final;
static bool graph_size_allows_inlining(size_t graph_size) {
......
......@@ -18,6 +18,11 @@ namespace compiler {
class MachineGraph;
// Recomputes wasm-gc types along the graph to assign the narrowest possible
// type to each node.
// Specifically, struct field accesses, array element accesses, phis, type
// casts, and type guards are retyped.
// Types in loops are computed to a fixed point.
class WasmTyper final : public AdvancedReducer {
public:
WasmTyper(Editor* editor, MachineGraph* mcgraph, uint32_t function_index);
......
......@@ -964,13 +964,7 @@ Handle<WasmValueObject> WasmValueObject::New(
}
break;
}
case wasm::kRtt: {
// TODO(7748): Expose RTTs to DevTools.
t = isolate->factory()->InternalizeString(base::StaticCharVector("rtt"));
v = isolate->factory()->InternalizeString(
base::StaticCharVector("(unimplemented)"));
break;
}
case wasm::kRtt:
case wasm::kVoid:
case wasm::kBottom:
UNREACHABLE();
......
......@@ -1880,7 +1880,6 @@ void AsmWasmData::AsmWasmDataPrint(std::ostream& os) {
void WasmTypeInfo::WasmTypeInfoPrint(std::ostream& os) {
PrintHeader(os, "WasmTypeInfo");
os << "\n - type address: " << reinterpret_cast<void*>(native_type());
// TODO(manoskouk): Print supertype info.
os << "\n - supertypes: ";
for (int i = 0; i < supertypes_length(); i++) {
os << "\n - " << Brief(supertypes(i));
......
......@@ -1562,10 +1562,10 @@ void PushArgs(const i::wasm::FunctionSig* sig, const Val args[],
// TODO(7748): Make sure this works for all heap types.
packer->Push(WasmRefToV8(store->i_isolate(), args[i].ref())->ptr());
break;
case i::wasm::kRtt:
case i::wasm::kS128:
// TODO(7748): Implement.
UNIMPLEMENTED();
case i::wasm::kRtt:
case i::wasm::kI8:
case i::wasm::kI16:
case i::wasm::kVoid:
......@@ -1601,10 +1601,10 @@ void PopArgs(const i::wasm::FunctionSig* sig, Val results[],
results[i] = Val(V8RefValueToWasm(store, obj));
break;
}
case i::wasm::kRtt:
case i::wasm::kS128:
// TODO(7748): Implement.
UNIMPLEMENTED();
case i::wasm::kRtt:
case i::wasm::kI8:
case i::wasm::kI16:
case i::wasm::kVoid:
......@@ -1869,10 +1869,10 @@ auto Global::get() const -> Val {
}
return Val(V8RefValueToWasm(store, result));
}
case i::wasm::kRtt:
case i::wasm::kS128:
// TODO(7748): Implement these.
UNIMPLEMENTED();
case i::wasm::kRtt:
case i::wasm::kI8:
case i::wasm::kI16:
case i::wasm::kVoid:
......
......@@ -83,8 +83,6 @@ uint32_t TypeCanonicalizer::AddRecursiveGroup(const FunctionSig* sig) {
return canonical_index;
}
// An index in a type gets mapped to a relative index if it is inside the new
// canonical group, or the canonical representative if it is not.
ValueType TypeCanonicalizer::CanonicalizeValueType(
const WasmModule* module, ValueType type,
uint32_t recursive_group_start) const {
......@@ -116,8 +114,6 @@ bool TypeCanonicalizer::IsCanonicalSubtype(uint32_t sub_index,
return false;
}
// Map all type indices (including supertype) inside {type} to indices
// relative to {recursive_group_start}.
TypeCanonicalizer::CanonicalType TypeCanonicalizer::CanonicalizeTypeDef(
const WasmModule* module, TypeDefinition type,
uint32_t recursive_group_start) {
......
......@@ -21,8 +21,8 @@ namespace wasm {
// types.
// A recursive group is a subsequence of types explicitly marked in the type
// section of a wasm module. Identical recursive groups have to be canonicalized
// to a single canonical group and are considered identical. Respective
// types in two identical groups are considered identical for all purposes.
// to a single canonical group. Respective types in two identical groups are
// considered identical for all purposes.
// Two groups are considered identical if they have the same shape, and all
// type indices referenced in the same position in both groups reference:
// - identical types, if those do not belong to the rec. group,
......@@ -105,9 +105,15 @@ class TypeCanonicalizer {
int FindCanonicalGroup(CanonicalGroup&) const;
// Canonicalize all types present in {type} (including supertype) according to
// {CanonicalizeValueType}.
CanonicalType CanonicalizeTypeDef(const WasmModule* module,
TypeDefinition type,
uint32_t recursive_group_start);
// An indexed type gets mapped to a {ValueType::CanonicalWithRelativeIndex}
// if its index points inside the new canonical group; otherwise, the index
// gets mapped to its canonical representative.
ValueType CanonicalizeValueType(const WasmModule* module, ValueType type,
uint32_t recursive_group_start) const;
......
......@@ -21,12 +21,13 @@ class JSArrayBuffer;
namespace wasm {
// An interface for WasmFullDecoder used to decode constant expressions. This
// interface has two modes: only validation (when {isolate_ == nullptr}), which
// is used in module-decoder, and code-generation (when {isolate_ != nullptr}),
// which is used in module-instantiate. We merge two distinct functionalities
// in one class to reduce the number of WasmFullDecoder instantiations, and thus
// V8 binary code size.
// An interface for WasmFullDecoder used to decode constant expressions.
// This interface has two modes: only validation (when {isolate_ == nullptr}),
// and code-generation (when {isolate_ != nullptr}). We merge two distinct
// functionalities in one class to reduce the number of WasmFullDecoder
// instantiations, and thus V8 binary code size.
// In code-generation mode, the result can be retrieved with {computed_value()}
// if {!has_error()}, or with {error()} otherwise.
class V8_EXPORT_PRIVATE ConstantExpressionInterface {
public:
static constexpr Decoder::ValidateFlag validate = Decoder::kFullValidation;
......
......@@ -924,8 +924,7 @@ struct ControlBase : public PcForErrors<validate> {
F(StartFunctionBody, Control* block) \
F(FinishFunction) \
F(OnFirstError) \
F(NextInstruction, WasmOpcode) \
F(Forward, const Value& from, Value* to)
F(NextInstruction, WasmOpcode)
#define INTERFACE_CONSTANT_FUNCTIONS(F) /* force 80 columns */ \
F(I32Const, Value* result, int32_t value) \
......@@ -979,6 +978,7 @@ struct ControlBase : public PcForErrors<validate> {
const IndexImmediate<validate>& imm) \
F(Trap, TrapReason reason) \
F(NopForTestingUnsupportedInLiftoff) \
F(Forward, const Value& from, Value* to) \
F(Select, const Value& cond, const Value& fval, const Value& tval, \
Value* result) \
F(BrOrRet, uint32_t depth, uint32_t drop_values) \
......
......@@ -44,7 +44,7 @@ struct WasmCompilationResult {
bool succeeded() const { return code_desc.buffer != nullptr; }
bool failed() const { return !succeeded(); }
operator bool() const { return succeeded(); }
explicit operator bool() const { return succeeded(); }
CodeDesc code_desc;
std::unique_ptr<AssemblerBuffer> instr_buffer;
......
......@@ -1685,7 +1685,6 @@ class WasmGraphBuildingInterface {
TFNode* if_success = nullptr;
TFNode* if_exception = nullptr;
// TODO(manoskouk): Can we assign a wasm type to the exception value?
if (!builder_->ThrowsException(node, &if_success, &if_exception)) {
return node;
}
......@@ -2073,7 +2072,6 @@ class WasmGraphBuildingInterface {
}
}
if (exception_value != nullptr) {
// TODO(manoskouk): Can we assign a wasm type to the exception value?
*exception_value = builder_->LoopExitValue(
*exception_value, MachineRepresentation::kWord32);
}
......
......@@ -1345,7 +1345,7 @@ class ModuleDecoderTemplate : public Decoder {
int64_t last_func_idx = -1;
for (uint32_t i = 0; i < func_count; i++) {
uint32_t func_idx = inner.consume_u32v("function index");
if (int64_t(func_idx) <= last_func_idx) {
if (int64_t{func_idx} <= last_func_idx) {
inner.errorf("Invalid function index: %d", func_idx);
break;
}
......@@ -1365,7 +1365,7 @@ class ModuleDecoderTemplate : public Decoder {
for (uint32_t k = 0; k < mark_size; k++) {
trace_mark_id |= inner.consume_u8("trace mark id") << k * 8;
}
if (int64_t(func_off) <= last_func_off) {
if (int64_t{func_off} <= last_func_off) {
inner.errorf("Invalid branch offset: %d", func_off);
break;
}
......@@ -1504,7 +1504,7 @@ class ModuleDecoderTemplate : public Decoder {
int64_t last_func_idx = -1;
for (uint32_t i = 0; i < func_count; i++) {
uint32_t func_idx = inner.consume_u32v("function index");
if (int64_t(func_idx) <= last_func_idx) {
if (int64_t{func_idx} <= last_func_idx) {
inner.errorf("Invalid function index: %d", func_idx);
break;
}
......@@ -1517,7 +1517,7 @@ class ModuleDecoderTemplate : public Decoder {
int64_t last_br_off = -1;
for (uint32_t j = 0; j < num_hints; ++j) {
uint32_t br_off = inner.consume_u32v("branch instruction offset");
if (int64_t(br_off) <= last_br_off) {
if (int64_t{br_off} <= last_br_off) {
inner.errorf("Invalid branch offset: %d", br_off);
break;
}
......
......@@ -24,6 +24,7 @@ class WasmFeatures;
// Representation of an constant expression. Unlike {ConstantExpression}, this
// does not use {WireBytesRef}, i.e., it does not depend on a wasm module's
// bytecode representation.
// TODO(manoskouk): Add missing kinds of expressions.
class WasmInitExpr : public ZoneObject {
public:
enum Operator {
......
......@@ -1565,8 +1565,6 @@ void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
break;
}
case i::wasm::kRtt:
// TODO(7748): Implement.
UNIMPLEMENTED();
case i::wasm::kI8:
case i::wasm::kI16:
case i::wasm::kVoid:
......@@ -2725,7 +2723,6 @@ void WebAssemblyGlobalGetValueCommon(
break;
}
case i::wasm::kRtt:
UNIMPLEMENTED(); // TODO(7748): Implement.
case i::wasm::kI8:
case i::wasm::kI16:
case i::wasm::kBottom:
......
......@@ -1554,8 +1554,6 @@ wasm::WasmValue WasmStruct::GetFieldValue(uint32_t index) {
return wasm::WasmValue(ref, field_type);
}
case wasm::kRtt:
// TODO(7748): Expose RTTs to DevTools.
UNIMPLEMENTED();
case wasm::kVoid:
case wasm::kBottom:
UNREACHABLE();
......@@ -1583,8 +1581,6 @@ wasm::WasmValue WasmArray::GetElement(uint32_t index) {
return wasm::WasmValue(ref, element_type);
}
case wasm::kRtt:
// TODO(7748): Expose RTTs to DevTools.
UNIMPLEMENTED();
case wasm::kVoid:
case wasm::kBottom:
UNREACHABLE();
......
......@@ -3668,8 +3668,7 @@ class WasmInterpreterInternals {
FOREACH_WASMVALUE_CTYPES(CASE_TYPE)
#undef CASE_TYPE
case kRef:
case kRefNull:
case kRtt: {
case kRefNull: {
// TODO(7748): Type checks or DCHECKs for ref types?
HandleScope handle_scope(isolate_); // Avoid leaking handles.
Handle<FixedArray> global_buffer; // The buffer of the global.
......@@ -3681,6 +3680,7 @@ class WasmInterpreterInternals {
global_buffer->set(global_index, *ref);
break;
}
case kRtt:
case kI8:
case kI16:
case kVoid:
......
......@@ -842,7 +842,7 @@ class WasmGenerator {
Var local = GetRandomLocal(data);
// TODO(manoskouk): Ideally we would check for subtyping here over type
// equality, but we don't have a module.
// TODO(7748): Remove this condition if non-nullable locals are allowed.
// TODO(7748): Allow initialized non-nullable locals.
if (nullable == kNullable && local.is_valid() &&
local.type.is_object_reference() && type == local.type.heap_type()) {
builder_->EmitWithU32V(kExprLocalGet, local.index);
......@@ -2522,8 +2522,8 @@ class WasmCompileFuzzer : public WasmExecutionFuzzer {
// performed by adding a function by {FunctionSig}, because we emit
// everything in one recursive group which blocks signature
// canonicalization.
// TODO(7748): Relax this when we implement type canonicalization and
// proper recursive-group support.
// TODO(7748): Relax this when we implement proper recursive-group
// support.
functions.push_back(liftoff_as_reference
? builder.AddFunction(function_signatures[i])
: builder.AddFunction(sig));
......
......@@ -380,3 +380,18 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
assertThrows(() => builder.instantiate(), WebAssembly.CompileError,
/i31.new\[0\] expected type i32, found i64.const of type i64/);
})();
(function TestConstantExprFuncIndexOutOfBounds() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let struct_index = builder.addStruct([makeField(kWasmFuncRef, true)]);
let func = builder.addFunction("element", kSig_i_i)
.addBody([kExprLocalGet, 0])
.exportFunc()
builder.addGlobal(wasmRefType(struct_index), false,
[kExprRefFunc, func.index + 1, kExprStructNew, struct_index]);
assertThrows(() => builder.instantiate(), WebAssembly.CompileError,
/function index #1 is out of bounds/);
})();
......@@ -36,8 +36,8 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
kExprLocalGet, 2, kGCPrefix, kExprRefTest, bottom1,
kExprIf, kWasmVoid,
// counter += ((bottom1) temp).field_2;
// TODO(manoskouk): Implement path-based type tracking so we can
// eliminate this check.
// Note: This cast should get optimized away with path-based type
// tracking.
kExprLocalGet, 2, kGCPrefix, kExprRefCast, bottom1,
kGCPrefix, kExprStructGet, bottom1, 2,
kExprLocalGet, 3, kExprI32Add, kExprLocalSet, 3,
......
......@@ -1053,9 +1053,6 @@ class Binary {
}
emit_init_expr(expr) {
// TODO(manoskouk): This is redundant, remove it once we are confident we
// check everything.
checkExpr(expr);
this.emit_bytes(expr);
this.emit_u8(kExprEnd);
}
......
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