v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
wasm-typer.cc
Go to the documentation of this file.
1// Copyright 2022 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#include "src/base/logging.h"
14#include "src/utils/utils.h"
18
19namespace v8 {
20namespace internal {
21namespace compiler {
22
23#define TRACE(...) \
24 if (v8_flags.trace_wasm_typer) PrintF(__VA_ARGS__);
25
27 uint32_t function_index)
28 : AdvancedReducer(editor),
29 function_index_(function_index),
30 graph_zone_(mcgraph->graph()->zone()) {}
31
32namespace {
33bool AllInputsTyped(Node* node) {
34 for (int i = 0; i < node->op()->ValueInputCount(); i++) {
36 return false;
37 }
38 }
39 return true;
40}
41} // namespace
42
44 using TypeInModule = wasm::TypeInModule;
45 TypeInModule computed_type;
46 switch (node->opcode()) {
47 case IrOpcode::kTypeGuard: {
48 if (!AllInputsTyped(node)) return NoChange();
49 Type guarded_type = TypeGuardTypeOf(node->op());
50 if (!guarded_type.IsWasm()) return NoChange();
51 Type input_type =
53 if (!input_type.IsWasm()) return NoChange();
54 TypeInModule guarded_wasm_type = guarded_type.AsWasm();
55 TypeInModule input_wasm_type = input_type.AsWasm();
56 // Note: The intersection type might be bottom. In this case, we are in a
57 // dead branch: Type this node as bottom and wait for the
58 // WasmGCOperatorReducer to remove it.
59 computed_type = wasm::Intersection(guarded_wasm_type, input_wasm_type);
60 break;
61 }
62 case IrOpcode::kWasmTypeCast:
63 case IrOpcode::kWasmTypeCastAbstract: {
64 if (!AllInputsTyped(node)) return NoChange();
65 TypeInModule object_type =
67 .AsWasm();
69 // TODO(12166): Change module parameters if we have cross-module inlining.
70 computed_type = wasm::Intersection(
71 object_type.type, to_type, object_type.module, object_type.module);
72 break;
73 }
74 case IrOpcode::kAssertNotNull: {
75 if (!AllInputsTyped(node)) return NoChange();
76 TypeInModule object_type =
78 .AsWasm();
79 computed_type = {object_type.type.AsNonNull(), object_type.module};
80 break;
81 }
82 case IrOpcode::kPhi: {
83 if (!AllInputsTyped(node)) {
84 bool is_loop_phi =
85 NodeProperties::GetControlInput(node)->opcode() == IrOpcode::kLoop;
86 // For a merge phi, we need all inputs to be typed.
87 if (!is_loop_phi) return NoChange();
88 // For a loop phi, we can forward the non-recursive-input type. We can
89 // recompute the type when the rest of the inputs' types are computed.
90 Node* non_recursive_input = NodeProperties::GetValueInput(node, 0);
91 if (!NodeProperties::IsTyped(non_recursive_input) ||
92 !NodeProperties::GetType(non_recursive_input).IsWasm()) {
93 return NoChange();
94 }
95 computed_type = NodeProperties::GetType(non_recursive_input).AsWasm();
96 TRACE("function: %d, loop phi node: %d, type: %s\n", function_index_,
97 node->id(), computed_type.type.name().c_str());
98 break;
99 }
100
101 Type first_input_type =
103 if (!first_input_type.IsWasm()) return NoChange();
104 computed_type = first_input_type.AsWasm();
105 for (int i = 1; i < node->op()->ValueInputCount(); i++) {
106 Node* input = NodeProperties::GetValueInput(node, i);
107 Type input_type = NodeProperties::GetType(input);
108 if (!input_type.IsWasm()) return NoChange();
109 TypeInModule wasm_type = input_type.AsWasm();
110 if (computed_type.type.is_bottom()) {
111 // We have not found a non-bottom branch yet.
112 computed_type = wasm_type;
113 } else if (!wasm_type.type.is_bottom()) {
114 // We do not want union of types from unreachable branches.
115 computed_type = wasm::Union(computed_type, wasm_type);
116 }
117 }
118 TRACE(
119 "function: %d, phi node: %d, input#: %d, input0:%d:%s, input1:%d:%s, "
120 "type: %s\n",
121 function_index_, node->id(), node->op()->ValueInputCount(),
122 node->InputAt(0)->id(),
123 NodeProperties::GetType(node->InputAt(0))
124 .AsWasm()
125 .type.name()
126 .c_str(),
127 node->InputAt(1)->id(),
128 node->op()->ValueInputCount() > 1
129 ? NodeProperties::GetType(node->InputAt(1))
130 .AsWasm()
131 .type.name()
132 .c_str()
133 : "<control>",
134 computed_type.type.name().c_str());
135 break;
136 }
137 case IrOpcode::kWasmArrayGet: {
138 Node* object = NodeProperties::GetValueInput(node, 0);
139 // This can happen either because the object has not been typed yet, or
140 // because it is an internal VM object (e.g. the instance).
141 if (!NodeProperties::IsTyped(object)) return NoChange();
142 TypeInModule object_type = NodeProperties::GetType(object).AsWasm();
143 // {is_uninhabited} can happen in unreachable branches.
144 if (object_type.type.is_uninhabited() ||
145 object_type.type == wasm::kWasmNullRef) {
146 computed_type = {wasm::kWasmBottom, object_type.module};
147 break;
148 }
149 wasm::ModuleTypeIndex ref_index = object_type.type.ref_index();
150 DCHECK(object_type.module->has_array(ref_index));
151 const wasm::ArrayType* type_from_object =
152 object_type.module->type(ref_index).array_type;
153 computed_type = {type_from_object->element_type().Unpacked(),
154 object_type.module};
155 break;
156 }
157 case IrOpcode::kWasmStructGet: {
158 Node* object = NodeProperties::GetValueInput(node, 0);
159 // This can happen either because the object has not been typed yet.
160 if (!NodeProperties::IsTyped(object)) return NoChange();
161 TypeInModule object_type = NodeProperties::GetType(object).AsWasm();
162 // {is_uninhabited} can happen in unreachable branches.
163 if (object_type.type.is_uninhabited() ||
164 object_type.type == wasm::kWasmNullRef) {
165 computed_type = {wasm::kWasmBottom, object_type.module};
166 break;
167 }
168 WasmFieldInfo info = OpParameter<WasmFieldInfo>(node->op());
169
170 wasm::ModuleTypeIndex ref_index = object_type.type.ref_index();
171
172 DCHECK(object_type.module->has_struct(ref_index));
173
174 const wasm::StructType* struct_type_from_object =
175 object_type.module->type(ref_index).struct_type;
176
177 computed_type = {
178 struct_type_from_object->field(info.field_index).Unpacked(),
179 object_type.module};
180 break;
181 }
182 case IrOpcode::kNull: {
183 TypeInModule from_node = NodeProperties::GetType(node).AsWasm();
184 computed_type = {wasm::ToNullSentinel(from_node), from_node.module};
185 break;
186 }
187 default:
188 return NoChange();
189 }
190
191 if (NodeProperties::IsTyped(node) && NodeProperties::GetType(node).IsWasm()) {
192 TypeInModule current_type = NodeProperties::GetType(node).AsWasm();
193 if (!(current_type.type.is_bottom() || computed_type.type.is_bottom() ||
194 wasm::IsSubtypeOf(current_type.type, computed_type.type,
195 current_type.module, computed_type.module) ||
196 wasm::IsSubtypeOf(computed_type.type, current_type.type,
197 computed_type.module, current_type.module) ||
198 // Imported strings can have more precise types.
199 (current_type.type.heap_representation() == wasm::HeapType::kExtern &&
200 computed_type.type.heap_representation() ==
202 FATAL(
203 "Error - Incompatible types. function: %d, node: %d:%s, input0:%d, "
204 "current %s, computed %s\n",
205 function_index_, node->id(), node->op()->mnemonic(),
206 node->InputAt(0)->id(), current_type.type.name().c_str(),
207 computed_type.type.name().c_str());
208 }
209
210 if (wasm::EquivalentTypes(current_type.type, computed_type.type,
211 current_type.module, computed_type.module)) {
212 return NoChange();
213 }
214 }
215
216 TRACE("function: %d, node: %d:%s, from: %s, to: %s\n", function_index_,
217 node->id(), node->op()->mnemonic(),
219 ? NodeProperties::GetType(node).AsWasm().type.name().c_str()
220 : "<untyped>",
221 computed_type.type.name().c_str());
222
223 NodeProperties::SetType(node, Type::Wasm(computed_type, graph_zone_));
224 return Changed(node);
225}
226
227#undef TRACE
228
229} // namespace compiler
230} // namespace internal
231} // namespace v8
static Type GetType(const Node *node)
static bool IsTyped(const Node *node)
static Node * GetValueInput(Node *node, int index)
static void SetType(Node *node, Type type)
static Node * GetControlInput(Node *node, int index=0)
constexpr IrOpcode::Value opcode() const
Definition node.h:52
static Reduction Changed(Node *node)
WasmTyper(Editor *editor, MachineGraph *mcgraph, uint32_t function_index)
Definition wasm-typer.cc:26
Reduction Reduce(Node *node) final
Definition wasm-typer.cc:43
ValueType element_type() const
ValueType field(uint32_t index) const
constexpr ValueType Unpacked() const
Definition value-type.h:944
#define TRACE(...)
Type TypeGuardTypeOf(Operator const *op)
T const & OpParameter(const Operator *op)
Definition operator.h:214
ValueType ToNullSentinel(TypeInModule type)
constexpr IndependentHeapType kWasmNullRef
V8_NOINLINE bool EquivalentTypes(ValueType type1, ValueType type2, const WasmModule *module1, const WasmModule *module2)
TypeInModule Intersection(ValueType type1, ValueType type2, const WasmModule *module1, const WasmModule *module2)
V8_EXPORT_PRIVATE TypeInModule Union(ValueType type1, ValueType type2, const WasmModule *module1, const WasmModule *module2)
V8_INLINE bool IsSubtypeOf(ValueType subtype, ValueType supertype, const WasmModule *sub_module, const WasmModule *super_module)
constexpr IndependentHeapType kWasmBottom
#define FATAL(...)
Definition logging.h:47
#define DCHECK(condition)
Definition logging.h:482