v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
wasm-gc-operator-reducer.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
12
13namespace v8 {
14namespace internal {
15namespace compiler {
16
18 Editor* editor, Zone* temp_zone_, MachineGraph* mcgraph,
19 const wasm::WasmModule* module, SourcePositionTable* source_position_table)
20 : AdvancedReducerWithControlPathState(editor, temp_zone_, mcgraph->graph()),
21 mcgraph_(mcgraph),
22 gasm_(mcgraph, mcgraph->zone()),
23 module_(module),
24 source_position_table_(source_position_table) {}
25
27 switch (node->opcode()) {
28 case IrOpcode::kStart:
29 return ReduceStart(node);
30 case IrOpcode::kWasmStructGet:
31 case IrOpcode::kWasmStructSet:
32 return ReduceWasmStructOperation(node);
33 case IrOpcode::kWasmArrayLength:
34 return ReduceWasmArrayLength(node);
35 case IrOpcode::kAssertNotNull:
36 return ReduceAssertNotNull(node);
37 case IrOpcode::kIsNull:
38 case IrOpcode::kIsNotNull:
39 return ReduceCheckNull(node);
40 case IrOpcode::kWasmTypeCheck:
41 return ReduceWasmTypeCheck(node);
42 case IrOpcode::kWasmTypeCheckAbstract:
43 return ReduceWasmTypeCheckAbstract(node);
44 case IrOpcode::kWasmTypeCast:
45 return ReduceWasmTypeCast(node);
46 case IrOpcode::kWasmTypeCastAbstract:
47 return ReduceWasmTypeCastAbstract(node);
48 case IrOpcode::kTypeGuard:
49 return ReduceTypeGuard(node);
50 case IrOpcode::kWasmAnyConvertExtern:
51 return ReduceWasmAnyConvertExtern(node);
52 case IrOpcode::kMerge:
53 return ReduceMerge(node);
54 case IrOpcode::kIfTrue:
55 return ReduceIf(node, true);
56 case IrOpcode::kIfFalse:
57 return ReduceIf(node, false);
58 case IrOpcode::kDead:
59 return NoChange();
60 case IrOpcode::kLoop:
61 return TakeStatesFromFirstControl(node);
62 default:
63 if (node->op()->ControlOutputCount() > 0) {
64 DCHECK_EQ(1, node->op()->ControlInputCount());
65 return TakeStatesFromFirstControl(node);
66 } else {
67 return NoChange();
68 }
69 }
70}
71
72namespace {
73bool InDeadBranch(Node* node) {
74 return node->opcode() == IrOpcode::kDead ||
75 node->opcode() == IrOpcode::kDeadValue ||
76 NodeProperties::GetType(node).AsWasm().type.is_uninhabited();
77}
78
79Node* GetAlias(Node* node) {
80 switch (node->opcode()) {
81 case IrOpcode::kWasmTypeCast:
82 case IrOpcode::kWasmTypeCastAbstract:
83 case IrOpcode::kTypeGuard:
84 case IrOpcode::kAssertNotNull:
85 return NodeProperties::GetValueInput(node, 0);
86 default:
87 return nullptr;
88 }
89}
90
91} // namespace
92
94 NodeProperties::SetType(node, Type::Wasm(type, module_, graph()->zone()));
95 return node;
96}
97
99 Node* state_owner, ControlPathTypes parent_state, Node* node,
100 wasm::TypeInModule type, bool in_new_block) {
101 ControlPathTypes previous_knowledge = GetState(state_owner);
102 if (!previous_knowledge.IsEmpty()) {
103 NodeWithType current_info = previous_knowledge.LookupState(node);
104 if (current_info.IsSet() && current_info.type == type) return NoChange();
105 }
106 Node* current = node;
107 ControlPathTypes current_state = parent_state;
108 while (current != nullptr) {
109 UpdateStates(state_owner, current_state, current, {current, type},
110 in_new_block);
111 current = GetAlias(current);
112 current_state = GetState(state_owner);
113 in_new_block = false;
114 }
115 return Changed(state_owner);
116}
117
121
123 Node* object, Node* control, bool allow_non_wasm) {
124 if (object->opcode() == IrOpcode::kDead ||
125 object->opcode() == IrOpcode::kDeadValue) {
126 return {};
127 }
128 if (!IsReduced(control)) return {};
129 if (allow_non_wasm && !NodeProperties::IsTyped(object)) return {};
130 Type raw_type = NodeProperties::GetType(object);
131 if (allow_non_wasm && !raw_type.IsWasm()) return {};
132 wasm::TypeInModule type_from_node = raw_type.AsWasm();
133 ControlPathTypes state = GetState(control);
134 NodeWithType type_from_state = state.LookupState(object);
135 // We manually resolve TypeGuard aliases in the state.
136 while (object->opcode() == IrOpcode::kTypeGuard && !type_from_state.IsSet()) {
137 object = NodeProperties::GetValueInput(object, 0);
138 type_from_state = state.LookupState(object);
139 }
140 if (!type_from_state.IsSet()) return type_from_node;
141 return wasm::Intersection(type_from_node, type_from_state.type);
142}
143
145 DCHECK(node->opcode() == IrOpcode::kWasmStructGet ||
146 node->opcode() == IrOpcode::kWasmStructSet);
147 Node* control = NodeProperties::GetControlInput(node);
148 if (!IsReduced(control)) return NoChange();
149 Node* object = NodeProperties::GetValueInput(node, 0);
150
151 wasm::TypeInModule object_type = ObjectTypeFromContext(object, control);
152 if (object_type.type.is_uninhabited()) return NoChange();
153
154 if (object_type.type.is_non_nullable()) {
155 // If the object is known to be non-nullable in the context, remove the null
156 // check.
157 auto op_params = OpParameter<WasmFieldInfo>(node->op());
158 const Operator* new_op =
159 node->opcode() == IrOpcode::kWasmStructGet
160 ? simplified()->WasmStructGet(op_params.type, op_params.field_index,
161 op_params.is_signed,
163 : simplified()->WasmStructSet(op_params.type, op_params.field_index,
165 NodeProperties::ChangeOp(node, new_op);
166 }
167
168 object_type.type = object_type.type.AsNonNull();
169
170 return UpdateNodeAndAliasesTypes(node, GetState(control), object, object_type,
171 false);
172}
173
175 DCHECK_EQ(node->opcode(), IrOpcode::kWasmArrayLength);
176 Node* control = NodeProperties::GetControlInput(node);
177 if (!IsReduced(control)) return NoChange();
178 Node* object = NodeProperties::GetValueInput(node, 0);
179
180 wasm::TypeInModule object_type = ObjectTypeFromContext(object, control);
181 if (object_type.type.is_uninhabited()) return NoChange();
182
183 if (object_type.type.is_non_nullable()) {
184 // If the object is known to be non-nullable in the context, remove the null
185 // check.
186 const Operator* new_op = simplified()->WasmArrayLength(kWithoutNullCheck);
187 NodeProperties::ChangeOp(node, new_op);
188 }
189
190 object_type.type = object_type.type.AsNonNull();
191
192 return UpdateNodeAndAliasesTypes(node, GetState(control), object, object_type,
193 false);
194}
195
196// If the condition of this node's branch is a type check or a null check,
197// add the additional information about the type-checked node to the path
198// state.
200 DCHECK(node->opcode() == IrOpcode::kIfTrue ||
201 node->opcode() == IrOpcode::kIfFalse);
203 if (branch->opcode() == IrOpcode::kDead) return NoChange();
204 DCHECK_EQ(branch->opcode(), IrOpcode::kBranch);
205 if (!IsReduced(branch)) return NoChange();
206 ControlPathTypes parent_state = GetState(branch);
207 Node* condition_node = NodeProperties::GetValueInput(branch, 0);
208 switch (condition_node->opcode()) {
209 case IrOpcode::kWasmTypeCheck:
210 case IrOpcode::kWasmTypeCheckAbstract: {
211 if (!condition) break;
212 Node* object = NodeProperties::GetValueInput(condition_node, 0);
213 wasm::TypeInModule object_type = ObjectTypeFromContext(object, branch);
214 if (object_type.type.is_uninhabited()) return NoChange();
215
216 wasm::ValueType to_type =
217 OpParameter<WasmTypeCheckConfig>(condition_node->op()).to;
218
219 // TODO(12166): Think about {module_} below if we have cross-module
220 // inlining.
221 wasm::TypeInModule new_type =
222 wasm::Intersection(object_type, {to_type, module_});
223 return UpdateNodeAndAliasesTypes(node, parent_state, object, new_type,
224 true);
225 }
226 case IrOpcode::kIsNull:
227 case IrOpcode::kIsNotNull: {
228 Node* object = NodeProperties::GetValueInput(condition_node, 0);
229 Node* control = NodeProperties::GetControlInput(condition_node);
230 wasm::TypeInModule object_type = ObjectTypeFromContext(object, control);
231 if (object_type.type.is_uninhabited()) return NoChange();
232 // If the checked value is null, narrow the type to the corresponding
233 // null type, otherwise to a non-null reference.
234 bool is_null =
235 condition == (condition_node->opcode() == IrOpcode::kIsNull);
236 object_type.type = is_null ? wasm::ToNullSentinel(object_type)
237 : object_type.type.AsNonNull();
238 return UpdateNodeAndAliasesTypes(node, parent_state, object, object_type,
239 true);
240 }
241 default:
242 break;
243 }
244 return TakeStatesFromFirstControl(node);
245}
246
248 // Shortcut for the case when we do not know anything about some
249 // input.
250 Node::Inputs inputs = node->inputs();
251 for (Node* input : inputs) {
252 if (!IsReduced(input)) return NoChange();
253 }
254
255 auto input_it = inputs.begin();
256
257 DCHECK_GT(inputs.count(), 0);
258
259 ControlPathTypes types = GetState(*input_it);
260 ++input_it;
261
262 auto input_end = inputs.end();
263 for (; input_it != input_end; ++input_it) {
264 // Change the current type block list to a longest common prefix of this
265 // state list and the other list. (The common prefix should correspond to
266 // the state of the common dominator.)
267 // TODO(manoskouk): Consider computing unions for some types.
268 types.ResetToCommonAncestor(GetState(*input_it));
269 }
270 return UpdateStates(node, types);
271}
272
274 DCHECK_EQ(node->opcode(), IrOpcode::kAssertNotNull);
275 Node* object = NodeProperties::GetValueInput(node, 0);
276 Node* control = NodeProperties::GetControlInput(node);
277
278 wasm::TypeInModule object_type = ObjectTypeFromContext(object, control);
279 if (object_type.type.is_uninhabited()) return NoChange();
280
281 // Optimize the check away if the argument is known to be non-null.
282 if (object_type.type.is_non_nullable()) {
283 // First, relax control.
284 ReplaceWithValue(node, node, node, control);
285 // Use a TypeGuard node to not lose any type information.
287 node, common()->TypeGuard(NodeProperties::GetType(node)));
288 return Changed(node);
289 }
290
291 object_type.type = object_type.type.AsNonNull();
292 return UpdateNodeAndAliasesTypes(node, GetState(control), node, object_type,
293 false);
294}
295
297 DCHECK(node->opcode() == IrOpcode::kIsNull ||
298 node->opcode() == IrOpcode::kIsNotNull);
299 Node* object = NodeProperties::GetValueInput(node, 0);
300 Node* control = NodeProperties::GetControlInput(node);
301
302 wasm::TypeInModule object_type = ObjectTypeFromContext(object, control);
303 if (object_type.type.is_uninhabited()) return NoChange();
304
305 // Optimize the check away if the argument is known to be non-null.
306 if (object_type.type.is_non_nullable()) {
307 ReplaceWithValue(node,
309 node->opcode() == IrOpcode::kIsNull ? 0 : 1),
311 node->Kill();
312 return Replace(object); // Irrelevant replacement.
313 }
314
315 // Optimize the check away if the argument is known to be null.
316 if (object->opcode() == IrOpcode::kNull) {
317 ReplaceWithValue(node,
319 node->opcode() == IrOpcode::kIsNull ? 1 : 0),
321 node->Kill();
322 return Replace(object); // Irrelevant replacement.
323 }
324
325 return NoChange();
326}
327
329 DCHECK_EQ(node->opcode(), IrOpcode::kWasmAnyConvertExtern);
330 // Remove redundant any.convert_extern(extern.convert_any(...)) pattern.
331 Node* input = NodeProperties::GetValueInput(node, 0);
332 while (input->opcode() == IrOpcode::kTypeGuard) {
333 input = NodeProperties::GetValueInput(input, 0);
334 }
335 if (input->opcode() == IrOpcode::kDead ||
336 input->opcode() == IrOpcode::kDeadValue) {
337 return NoChange();
338 }
339 if (input->opcode() == IrOpcode::kWasmExternConvertAny) {
340 // "Skip" the extern.convert_any which doesn't have an effect on the value.
341 input = NodeProperties::GetValueInput(input, 0);
342 ReplaceWithValue(node, input);
343 node->Kill();
344 return Replace(input);
345 }
346 return TakeStatesFromFirstControl(node);
347}
348
350 DCHECK_EQ(node->opcode(), IrOpcode::kTypeGuard);
351 Node* control = NodeProperties::GetControlInput(node);
352 Node* object = NodeProperties::GetValueInput(node, 0);
353
354 // Since TypeGuards can be generated for JavaScript, and this phase is run
355 // for wasm-into-JS inlining, we cannot assume the object has a wasm type.
356 wasm::TypeInModule object_type =
357 ObjectTypeFromContext(object, control, /* allow_non_wasm = */ true);
358 if (object_type.type.is_uninhabited()) return NoChange();
359 Type guarded_type = TypeGuardTypeOf(node->op());
360 if (!guarded_type.IsWasm()) return NoChange();
361
362 wasm::TypeInModule new_type =
363 wasm::Intersection(object_type, guarded_type.AsWasm());
364
365 return UpdateNodeAndAliasesTypes(node, GetState(control), node, new_type,
366 false);
367}
368
370 DCHECK_EQ(node->opcode(), IrOpcode::kWasmTypeCast);
371 Node* effect = NodeProperties::GetEffectInput(node);
372 Node* control = NodeProperties::GetControlInput(node);
373 Node* object = NodeProperties::GetValueInput(node, 0);
374 Node* rtt = NodeProperties::GetValueInput(node, 1);
375
376 wasm::TypeInModule object_type = ObjectTypeFromContext(object, control);
377 if (object_type.type.is_uninhabited()) return NoChange();
378 if (InDeadBranch(rtt)) return NoChange();
379 wasm::TypeInModule rtt_type = NodeProperties::GetType(rtt).AsWasm();
380 bool to_nullable =
381 OpParameter<WasmTypeCheckConfig>(node->op()).to.is_nullable();
382
383 if (wasm::IsHeapSubtypeOf(object_type.type.heap_type(),
384 rtt_type.type.heap_type(), object_type.module,
385 rtt_type.module)) {
386 if (to_nullable) {
387 // Type cast will always succeed. Turn it into a TypeGuard to not lose any
388 // type information.
389 // First, relax control.
390 ReplaceWithValue(node, node, node, control);
391 // Remove rtt input.
392 node->RemoveInput(1);
394 node, common()->TypeGuard(NodeProperties::GetType(node)));
395 return Changed(node);
396 } else {
397 gasm_.InitializeEffectControl(effect, control);
398 Node* assert_not_null = gasm_.AssertNotNull(object, object_type.type,
399 TrapId::kTrapIllegalCast);
400 UpdateSourcePosition(assert_not_null, node);
401 return Replace(SetType(assert_not_null, object_type.type.AsNonNull()));
402 }
403 }
404
405 if (wasm::HeapTypesUnrelated(object_type.type.heap_type(),
406 rtt_type.type.heap_type(), object_type.module,
407 rtt_type.module)) {
408 gasm_.InitializeEffectControl(effect, control);
409 // A cast between unrelated types can only succeed if the argument is null.
410 // Otherwise, it always fails.
411 Node* non_trapping_condition = object_type.type.is_nullable() && to_nullable
412 ? gasm_.IsNull(object, object_type.type)
413 : gasm_.Int32Constant(0);
414 gasm_.TrapUnless(SetType(non_trapping_condition, wasm::kWasmI32),
415 TrapId::kTrapIllegalCast);
417 Node* null_node = SetType(gasm_.Null(object_type.type),
418 wasm::ToNullSentinel(object_type));
419 ReplaceWithValue(node, null_node, gasm_.effect(), gasm_.control());
420 node->Kill();
421 return Replace(null_node);
422 }
423
424 // TODO(12166): Think about modules below if we have cross-module inlining.
425
426 // Update the from-type in the type cast.
427 WasmTypeCheckConfig current_config =
429 NodeProperties::ChangeOp(node, gasm_.simplified()->WasmTypeCast(
430 {object_type.type, current_config.to,
431 current_config.exactness}));
432
433 wasm::TypeInModule new_type =
434 wasm::Intersection(object_type, {rtt_type.type.AsNullable(), module_});
435
436 return UpdateNodeAndAliasesTypes(node, GetState(control), node, new_type,
437 false);
438}
439
441 DCHECK_EQ(node->opcode(), IrOpcode::kWasmTypeCastAbstract);
442 Node* effect = NodeProperties::GetEffectInput(node);
443 Node* control = NodeProperties::GetControlInput(node);
444 Node* object = NodeProperties::GetValueInput(node, 0);
446
447 wasm::TypeInModule object_type = ObjectTypeFromContext(object, control);
448 if (object_type.type.is_uninhabited()) return NoChange();
449 const bool to_nullable = config.to.is_nullable();
450
451 if (wasm::IsHeapSubtypeOf(object_type.type.heap_type(), config.to.heap_type(),
452 object_type.module)) {
453 if (to_nullable || object_type.type.is_non_nullable()) {
454 // Type cast will always succeed. Turn it into a TypeGuard to not lose any
455 // type information.
456 // First, relax control.
457 ReplaceWithValue(node, node, node, control);
459 node, common()->TypeGuard(NodeProperties::GetType(node)));
460 return Changed(node);
461 } else {
462 gasm_.InitializeEffectControl(effect, control);
463 Node* assert_not_null = gasm_.AssertNotNull(object, object_type.type,
464 TrapId::kTrapIllegalCast);
465 UpdateSourcePosition(assert_not_null, node);
466 return Replace(SetType(assert_not_null, object_type.type.AsNonNull()));
467 }
468 }
469
470 if (wasm::HeapTypesUnrelated(object_type.type.heap_type(),
471 config.to.heap_type(), object_type.module,
472 object_type.module)) {
473 gasm_.InitializeEffectControl(effect, control);
474 // A cast between unrelated types can only succeed if the argument is null.
475 // Otherwise, it always fails.
476 Node* non_trapping_condition = object_type.type.is_nullable() && to_nullable
477 ? gasm_.IsNull(object, object_type.type)
478 : gasm_.Int32Constant(0);
479 gasm_.TrapUnless(SetType(non_trapping_condition, wasm::kWasmI32),
480 TrapId::kTrapIllegalCast);
482 Node* null_node = SetType(gasm_.Null(object_type.type),
483 wasm::ToNullSentinel(object_type));
484 ReplaceWithValue(node, null_node, gasm_.effect(), gasm_.control());
485 node->Kill();
486 return Replace(null_node);
487 }
488
489 // Update the from-type in the type cast.
491 node, gasm_.simplified()->WasmTypeCastAbstract(
492 {object_type.type, config.to, config.exactness}));
493
494 wasm::TypeInModule new_type =
495 wasm::Intersection(object_type, {config.to, module_});
496
497 return UpdateNodeAndAliasesTypes(node, GetState(control), node, new_type,
498 false);
499}
500
502 DCHECK_EQ(node->opcode(), IrOpcode::kWasmTypeCheck);
503 Node* object = NodeProperties::GetValueInput(node, 0);
504 Node* rtt = NodeProperties::GetValueInput(node, 1);
505 Node* effect = NodeProperties::GetEffectInput(node);
506 Node* control = NodeProperties::GetControlInput(node);
507
508 wasm::TypeInModule object_type = ObjectTypeFromContext(object, control);
509 if (object_type.type.is_uninhabited()) return NoChange();
510 if (InDeadBranch(rtt)) return NoChange();
511 wasm::TypeInModule rtt_type = NodeProperties::GetType(rtt).AsWasm();
512
513 if (wasm::IsHeapSubtypeOf(object_type.type.heap_type(),
514 rtt_type.type.heap_type(), object_type.module,
515 rtt_type.module)) {
516 bool null_succeeds =
517 OpParameter<WasmTypeCheckConfig>(node->op()).to.is_nullable();
518 // Type cast will fail only on null.
519 gasm_.InitializeEffectControl(effect, control);
521 ? gasm_.IsNotNull(object, object_type.type)
522 : gasm_.Int32Constant(1),
525 node->Kill();
526 return Replace(condition);
527 }
528
529 if (wasm::HeapTypesUnrelated(object_type.type.heap_type(),
530 rtt_type.type.heap_type(), object_type.module,
531 rtt_type.module)) {
532 bool null_succeeds =
533 OpParameter<WasmTypeCheckConfig>(node->op()).to.is_nullable();
534 Node* condition = nullptr;
535 if (null_succeeds && object_type.type.is_nullable()) {
536 // The cast only succeeds in case of null.
537 gasm_.InitializeEffectControl(effect, control);
538 condition =
539 SetType(gasm_.IsNull(object, object_type.type), wasm::kWasmI32);
540 } else {
541 // The cast never succeeds.
543 }
545 node->Kill();
546 return Replace(condition);
547 }
548
549 // TODO(12166): Think about modules below if we have cross-module inlining.
550
551 // Update the from-type in the type cast.
552 WasmTypeCheckConfig current_config =
554 NodeProperties::ChangeOp(node, gasm_.simplified()->WasmTypeCheck(
555 {object_type.type, current_config.to,
556 current_config.exactness}));
557
558 return TakeStatesFromFirstControl(node);
559}
560
562 DCHECK_EQ(node->opcode(), IrOpcode::kWasmTypeCheckAbstract);
563 Node* object = NodeProperties::GetValueInput(node, 0);
564 Node* effect = NodeProperties::GetEffectInput(node);
565 Node* control = NodeProperties::GetControlInput(node);
567
568 wasm::TypeInModule object_type = ObjectTypeFromContext(object, control);
569 if (object_type.type.is_uninhabited()) return NoChange();
570 const bool null_succeeds = config.to.is_nullable();
571
572 if (wasm::IsHeapSubtypeOf(object_type.type.heap_type(), config.to.heap_type(),
573 object_type.module)) {
574 // Type cast will fail only on null.
575 gasm_.InitializeEffectControl(effect, control);
577 ? gasm_.IsNotNull(object, object_type.type)
578 : gasm_.Int32Constant(1),
581 node->Kill();
582 return Replace(condition);
583 }
584
585 // This can never result from user code, only from internal shortcuts,
586 // e.g. when using externrefs as strings.
587 const bool implicit_internalize =
589 wasm::IsHeapSubtypeOf(config.to.heap_type(), wasm::kWasmAnyRef,
590 object_type.module);
591 if (!implicit_internalize &&
593 config.to.heap_type(), object_type.module,
594 object_type.module)) {
595 Node* condition = nullptr;
596 if (null_succeeds && object_type.type.is_nullable()) {
597 // The cast only succeeds in case of null.
598 gasm_.InitializeEffectControl(effect, control);
599 condition =
600 SetType(gasm_.IsNull(object, object_type.type), wasm::kWasmI32);
601 } else {
602 // The cast never succeeds.
604 }
606 node->Kill();
607 return Replace(condition);
608 }
609
610 // Update the from-type in the type cast.
612 node, gasm_.simplified()->WasmTypeCheckAbstract(
613 {object_type.type, config.to, config.exactness}));
614
615 return TakeStatesFromFirstControl(node);
616}
617
627
628} // namespace compiler
629} // namespace internal
630} // namespace v8
Reduction UpdateStates(Node *state_owner, ControlPathState< NodeWithType, node_uniqueness > new_state)
void ReplaceWithValue(Node *node, Node *value, Node *effect=nullptr, Node *control=nullptr)
static Reduction Replace(Node *node)
void ResetToCommonAncestor(ControlPathState other)
void InitializeEffectControl(Node *effect, Node *control)
static void ChangeOp(Node *node, const Operator *new_op)
static Type GetType(const Node *node)
static bool IsTyped(const Node *node)
static Node * GetEffectInput(Node *node, int index=0)
static Node * GetValueInput(Node *node, int index)
static void SetType(Node *node, Type type)
static Node * GetControlInput(Node *node, int index=0)
const_iterator begin() const
Definition node.h:600
const_iterator end() const
Definition node.h:605
constexpr IrOpcode::Value opcode() const
Definition node.h:52
const Operator * op() const
Definition node.h:50
constexpr Opcode opcode() const
Definition operator.h:75
static Reduction Changed(Node *node)
void SetSourcePosition(Node *node, SourcePosition position)
void UpdateSourcePosition(Node *new_node, Node *old_node)
WasmGCOperatorReducer(Editor *editor, Zone *temp_zone_, MachineGraph *mcgraph, const wasm::WasmModule *module, SourcePositionTable *source_position_table)
Node * SetType(Node *node, wasm::ValueType type)
wasm::TypeInModule ObjectTypeFromContext(Node *object, Node *control, bool allow_non_wasm=false)
Reduction UpdateNodeAndAliasesTypes(Node *state_owner, ControlPathTypes parent_state, Node *node, wasm::TypeInModule type, bool in_new_block)
ControlPathState< NodeWithType, kMultipleInstances > ControlPathTypes
void TrapUnless(Node *condition, TrapId reason)
SimplifiedOperatorBuilder * simplified() override
Node * IsNull(Node *object, wasm::ValueType type)
Node * IsNotNull(Node *object, wasm::ValueType type)
Node * AssertNotNull(Node *object, wasm::ValueType type, TrapId trap_id)
constexpr bool is_non_nullable() const
Definition value-type.h:396
constexpr bool is_nullable() const
Definition value-type.h:393
constexpr bool is_uninhabited() const
Definition value-type.h:455
constexpr HeapType heap_type() const
constexpr ValueType AsNonNull() const
Definition value-type.h:917
constexpr ValueType AsNullable(Nullability nullable=kNullable) const
Definition value-type.h:918
LineAndColumn current
Node * node
bool null_succeeds
int position
Definition liveedit.cc:290
Type TypeGuardTypeOf(Operator const *op)
T const & OpParameter(const Operator *op)
Definition operator.h:214
ValueType ToNullSentinel(TypeInModule type)
constexpr IndependentHeapType kWasmAnyRef
V8_INLINE bool IsHeapSubtypeOf(HeapType subtype, HeapType supertype, const WasmModule *sub_module, const WasmModule *super_module)
TypeInModule Intersection(ValueType type1, ValueType type2, const WasmModule *module1, const WasmModule *module2)
constexpr IndependentHeapType kWasmExternRef
constexpr IndependentValueType kWasmI32
V8_INLINE bool HeapTypesUnrelated(HeapType heap1, HeapType heap2, const WasmModule *module1, const WasmModule *module2)
constexpr int kNoSourcePosition
Definition globals.h:850
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define DCHECK_GT(v1, v2)
Definition logging.h:487
MachineGraph * mcgraph_
SourcePositionTable * source_position_table_
WasmGraphAssembler gasm_
const wasm::WasmModule * module_