Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
il.h
Go to the documentation of this file.
1// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_VM_COMPILER_BACKEND_IL_H_
6#define RUNTIME_VM_COMPILER_BACKEND_IL_H_
7
8#if defined(DART_PRECOMPILED_RUNTIME)
9#error "AOT runtime should not use compiler sources (including header files)"
10#endif // defined(DART_PRECOMPILED_RUNTIME)
11
12#include <memory>
13#include <tuple>
14#include <type_traits>
15#include <utility>
16
17#include "vm/allocation.h"
18#include "vm/code_descriptors.h"
30#include "vm/dart_entry.h"
31#include "vm/flags.h"
32#include "vm/growable_array.h"
33#include "vm/native_entry.h"
34#include "vm/object.h"
35#include "vm/parser.h"
36#include "vm/runtime_entry.h"
38#include "vm/token_position.h"
39
40namespace dart {
41
42class BaseTextBuffer;
43class BinaryFeedback;
44class BitVector;
45class BlockEntryInstr;
46class BlockEntryWithInitialDefs;
47class BoxIntegerInstr;
48class CallTargets;
49class CatchBlockEntryInstr;
50class CheckBoundBaseInstr;
51class ComparisonInstr;
52class Definition;
53class Environment;
54class FlowGraph;
55class FlowGraphCompiler;
56class FlowGraphVisitor;
57class ForwardInstructionIterator;
58class Instruction;
59class InstructionVisitor;
60class LocalVariable;
61class LoopInfo;
62class MoveSchedule;
63class ParsedFunction;
64class Range;
65class RangeAnalysis;
66class RangeBoundary;
67class TypeUsageInfo;
68class UnboxIntegerInstr;
69
70namespace compiler {
71class BlockBuilder;
72struct TableSelector;
73} // namespace compiler
74
75class Value : public ZoneAllocated {
76 public:
77 // A forward iterator that allows removing the current value from the
78 // underlying use list during iteration.
79 class Iterator {
80 public:
81 explicit Iterator(Value* head) : next_(head) { Advance(); }
82 Value* Current() const { return current_; }
83 bool Done() const { return current_ == nullptr; }
84 void Advance() {
85 // Pre-fetch next on advance and cache it.
86 current_ = next_;
87 if (next_ != nullptr) next_ = next_->next_use();
88 }
89
90 private:
91 Value* current_;
92 Value* next_;
93 };
94
96 : definition_(definition),
97 previous_use_(nullptr),
98 next_use_(nullptr),
99 instruction_(nullptr),
100 use_index_(-1),
101 reaching_type_(nullptr) {}
102
103 Definition* definition() const { return definition_; }
105 definition_ = definition;
106 // Clone the reaching type if there was one and the owner no longer matches
107 // this value's definition.
108 SetReachingType(reaching_type_);
109 }
110
111 Value* previous_use() const { return previous_use_; }
112 void set_previous_use(Value* previous) { previous_use_ = previous; }
113
114 Value* next_use() const { return next_use_; }
115 void set_next_use(Value* next) { next_use_ = next; }
116
117 bool IsSingleUse() const {
118 return (next_use_ == nullptr) && (previous_use_ == nullptr);
119 }
120
121 Instruction* instruction() const { return instruction_; }
123
124 intptr_t use_index() const { return use_index_; }
125 void set_use_index(intptr_t index) { use_index_ = index; }
126
127 static void AddToList(Value* value, Value** list);
128 void RemoveFromUseList();
129
130 // Change the definition after use lists have been computed.
131 inline void BindTo(Definition* definition);
133
134 Value* Copy(Zone* zone) { return new (zone) Value(definition_); }
135
136 // CopyWithType() must only be used when the new Value is dominated by
137 // the original Value.
139 Value* copy = new (zone) Value(definition_);
140 copy->reaching_type_ = reaching_type_;
141 return copy;
142 }
144
145 CompileType* Type();
146
147 CompileType* reaching_type() const { return reaching_type_; }
150
151#if defined(INCLUDE_IL_PRINTER)
152 void PrintTo(BaseTextBuffer* f) const;
153#endif // defined(INCLUDE_IL_PRINTER)
154
155 const char* ToCString() const;
156
157 bool IsSmiValue() { return Type()->ToCid() == kSmiCid; }
158
159 // Return true if the value represents a constant.
160 bool BindsToConstant() const;
161 bool BindsToConstant(ConstantInstr** constant_defn) const;
162
163 // Return true if the value represents the constant null.
164 bool BindsToConstantNull() const;
165
166 // Assert if BindsToConstant() is false, otherwise returns the constant value.
167 const Object& BoundConstant() const;
168
169 // Return true if the value represents Smi constant.
170 bool BindsToSmiConstant() const;
171
172 // Return value of represented Smi constant.
173 intptr_t BoundSmiConstant() const;
174
175 // Return true if storing the value into a heap object requires applying the
176 // write barrier. Can change the reaching type of the Value or other Values
177 // in the same chain of redefinitions.
178 bool NeedsWriteBarrier();
179
180 bool Equals(const Value& other) const;
181
182 // Returns true if this |Value| can evaluate to the given |value| during
183 // execution.
184 inline bool CanBe(const Object& value);
185
186 private:
187 friend class FlowGraphPrinter;
188
189 Definition* definition_;
190 Value* previous_use_;
191 Value* next_use_;
192 Instruction* instruction_;
193 intptr_t use_index_;
194
195 CompileType* reaching_type_;
196
198};
199
200// Represents a range of class-ids for use in class checks and polymorphic
201// dispatches. The range includes both ends, i.e. it is [cid_start, cid_end].
202struct CidRange : public ZoneAllocated {
203 CidRange(intptr_t cid_start_arg, intptr_t cid_end_arg)
204 : cid_start(cid_start_arg), cid_end(cid_end_arg) {}
206
207 bool IsSingleCid() const { return cid_start == cid_end; }
208 bool Contains(intptr_t cid) const {
209 return cid_start <= cid && cid <= cid_end;
210 }
211 int32_t Extent() const { return cid_end - cid_start; }
212
213 // The number of class ids this range covers.
214 intptr_t size() const { return cid_end - cid_start + 1; }
215
216 bool IsIllegalRange() const {
218 }
219
220 intptr_t cid_start;
221 intptr_t cid_end;
222
224};
225
227 CidRangeValue(intptr_t cid_start_arg, intptr_t cid_end_arg)
228 : cid_start(cid_start_arg), cid_end(cid_end_arg) {}
229 CidRangeValue(const CidRange& other) // NOLINT
230 : cid_start(other.cid_start), cid_end(other.cid_end) {}
231
232 bool IsSingleCid() const { return cid_start == cid_end; }
233 bool Contains(intptr_t cid) const {
234 return cid_start <= cid && cid <= cid_end;
235 }
236 int32_t Extent() const { return cid_end - cid_start; }
237
238 // The number of class ids this range covers.
239 intptr_t size() const { return cid_end - cid_start + 1; }
240
241 bool IsIllegalRange() const {
243 }
244
245 bool Equals(const CidRangeValue& other) const {
246 return cid_start == other.cid_start && cid_end == other.cid_end;
247 }
248
249 intptr_t cid_start;
250 intptr_t cid_end;
251};
252
254
256 public:
257 static bool ContainsCid(const CidRangeVector& ranges, intptr_t cid) {
258 for (const CidRangeValue& range : ranges) {
259 if (range.Contains(cid)) {
260 return true;
261 }
262 }
263 return false;
264 }
265};
266
268 public:
271 cid_subtype_ranges_nullable_(),
272 cid_subtype_ranges_abstract_nullable_(),
273 cid_subtype_ranges_nonnullable_(),
274 cid_subtype_ranges_abstract_nonnullable_() {
276 }
277
279
280 // Returned from FindBestTAVOffset and SplitOnConsistentTypeArguments
281 // to denote a failure to find a compatible concrete, finalized class.
282 static constexpr intptr_t kNoCompatibleTAVOffset = 0;
283
284 const CidRangeVector& SubtypeRangesForClass(const Class& klass,
285 bool include_abstract,
286 bool exclude_null);
287
289 intptr_t* lower_limit,
290 intptr_t* upper_limit);
291
292 // Returns `true` if a simple [CidRange]-based subtype-check can be used to
293 // determine if a given instance's type is a subtype of [type].
294 //
295 // This is the case for [type]s without type arguments or where the type
296 // arguments are all dynamic (known as "rare type").
298
299 // Returns `true` if a combination of [CidRange]-based checks can be used to
300 // determine if a given instance's type is a subtype of [type].
301 //
302 // This is the case for [type]s with type arguments where we are able to do a
303 // [CidRange]-based subclass-check against the class and [CidRange]-based
304 // subtype-checks against the type arguments.
305 //
306 // This method should only be called if [CanUseSubtypeRangecheckFor] returned
307 // false.
309
310 // Returns `true` if [type] is a record type which fields can be tested using
311 // simple [CidRange]-based subtype-check.
313
314 private:
315 // Does not use any hierarchy information available in the system but computes
316 // it via O(n) class table traversal.
317 //
318 // The boolean parameters denote:
319 // include_abstract : if set, include abstract types (don't care otherwise)
320 // exclude_null : if set, exclude null types (don't care otherwise)
321 void BuildRangesUsingClassTableFor(ClassTable* table,
322 CidRangeVector* ranges,
323 const Class& klass,
324 bool include_abstract,
325 bool exclude_null);
326
327 // Uses hierarchy information stored in the [Class]'s direct_subclasses() and
328 // direct_implementors() arrays, unless that information is not available
329 // in which case we fall back to the class table.
330 //
331 // The boolean parameters denote:
332 // include_abstract : if set, include abstract types (don't care otherwise)
333 // exclude_null : if set, exclude null types (don't care otherwise)
334 void BuildRangesFor(ClassTable* table,
335 CidRangeVector* ranges,
336 const Class& klass,
337 bool include_abstract,
338 bool exclude_null);
339
340 std::unique_ptr<CidRangeVector[]> cid_subtype_ranges_nullable_;
341 std::unique_ptr<CidRangeVector[]> cid_subtype_ranges_abstract_nullable_;
342 std::unique_ptr<CidRangeVector[]> cid_subtype_ranges_nonnullable_;
343 std::unique_ptr<CidRangeVector[]> cid_subtype_ranges_abstract_nonnullable_;
344};
345
346// An embedded container with N elements of type T. Used (with partial
347// specialization for N=0) because embedded arrays cannot have size 0.
348template <typename T, intptr_t N>
350 public:
351 EmbeddedArray() : elements_() {}
352
353 intptr_t length() const { return N; }
354
355 const T& operator[](intptr_t i) const {
356 ASSERT(i < length());
357 return elements_[i];
358 }
359
360 T& operator[](intptr_t i) {
361 ASSERT(i < length());
362 return elements_[i];
363 }
364
365 const T& At(intptr_t i) const { return (*this)[i]; }
366
367 void SetAt(intptr_t i, const T& val) { (*this)[i] = val; }
368
369 private:
370 T elements_[N];
371};
372
373template <typename T>
374class EmbeddedArray<T, 0> {
375 public:
376 intptr_t length() const { return 0; }
377 const T& operator[](intptr_t i) const {
378 UNREACHABLE();
379 static T sentinel = nullptr;
380 return sentinel;
381 }
382 T& operator[](intptr_t i) {
383 UNREACHABLE();
384 static T sentinel = nullptr;
385 return sentinel;
386 }
387};
388
389// Instructions.
390
391// M is a two argument macro. It is applied to each concrete instruction type
392// name. The concrete instruction classes are the name with Instr concatenated.
393
396 _ = 0, // No special attributes.
397 //
398 // The instruction is guaranteed to not trigger GC on a non-exceptional
399 // path. If the conditions depend on parameters of the instruction, do not
400 // use this attribute but overload CanTriggerGC() instead.
401 kNoGC = 1,
402 };
403};
404
405#define FOR_EACH_INSTRUCTION(M) \
406 M(GraphEntry, kNoGC) \
407 M(JoinEntry, kNoGC) \
408 M(TargetEntry, kNoGC) \
409 M(FunctionEntry, kNoGC) \
410 M(NativeEntry, kNoGC) \
411 M(OsrEntry, kNoGC) \
412 M(IndirectEntry, kNoGC) \
413 M(CatchBlockEntry, kNoGC) \
414 M(Phi, kNoGC) \
415 M(Redefinition, kNoGC) \
416 M(ReachabilityFence, kNoGC) \
417 M(Parameter, kNoGC) \
418 M(NativeParameter, kNoGC) \
419 M(LoadIndexedUnsafe, kNoGC) \
420 M(StoreIndexedUnsafe, kNoGC) \
421 M(MemoryCopy, kNoGC) \
422 M(TailCall, kNoGC) \
423 M(ParallelMove, kNoGC) \
424 M(MoveArgument, kNoGC) \
425 M(DartReturn, kNoGC) \
426 M(NativeReturn, kNoGC) \
427 M(Throw, kNoGC) \
428 M(ReThrow, kNoGC) \
429 M(Stop, kNoGC) \
430 M(Goto, kNoGC) \
431 M(IndirectGoto, kNoGC) \
432 M(Branch, kNoGC) \
433 M(AssertAssignable, _) \
434 M(AssertSubtype, _) \
435 M(AssertBoolean, _) \
436 M(ClosureCall, _) \
437 M(FfiCall, _) \
438 M(LeafRuntimeCall, kNoGC) \
439 M(InstanceCall, _) \
440 M(PolymorphicInstanceCall, _) \
441 M(DispatchTableCall, _) \
442 M(StaticCall, _) \
443 M(CachableIdempotentCall, _) \
444 M(LoadLocal, kNoGC) \
445 M(DropTemps, kNoGC) \
446 M(MakeTemp, kNoGC) \
447 M(StoreLocal, kNoGC) \
448 M(StrictCompare, kNoGC) \
449 M(EqualityCompare, kNoGC) \
450 M(RelationalOp, kNoGC) \
451 M(NativeCall, _) \
452 M(DebugStepCheck, _) \
453 M(RecordCoverage, kNoGC) \
454 M(LoadIndexed, kNoGC) \
455 M(LoadCodeUnits, _) \
456 M(StoreIndexed, kNoGC) \
457 M(StoreField, _) \
458 M(LoadStaticField, _) \
459 M(StoreStaticField, kNoGC) \
460 M(BooleanNegate, kNoGC) \
461 M(BoolToInt, kNoGC) \
462 M(IntToBool, kNoGC) \
463 M(InstanceOf, _) \
464 M(CreateArray, _) \
465 M(AllocateObject, _) \
466 M(AllocateClosure, _) \
467 M(AllocateRecord, _) \
468 M(AllocateSmallRecord, _) \
469 M(AllocateTypedData, _) \
470 M(LoadField, _) \
471 M(LoadUntagged, kNoGC) \
472 M(CalculateElementAddress, kNoGC) \
473 M(LoadClassId, kNoGC) \
474 M(InstantiateType, _) \
475 M(InstantiateTypeArguments, _) \
476 M(AllocateContext, _) \
477 M(AllocateUninitializedContext, _) \
478 M(CloneContext, _) \
479 M(BinarySmiOp, kNoGC) \
480 M(BinaryInt32Op, kNoGC) \
481 M(HashDoubleOp, kNoGC) \
482 M(HashIntegerOp, kNoGC) \
483 M(UnarySmiOp, kNoGC) \
484 M(UnaryDoubleOp, kNoGC) \
485 M(CheckStackOverflow, _) \
486 M(SmiToDouble, kNoGC) \
487 M(Int32ToDouble, kNoGC) \
488 M(Int64ToDouble, kNoGC) \
489 M(DoubleToInteger, _) \
490 M(DoubleToSmi, kNoGC) \
491 M(DoubleToFloat, kNoGC) \
492 M(FloatToDouble, kNoGC) \
493 M(FloatCompare, kNoGC) \
494 M(CheckClass, kNoGC) \
495 M(CheckClassId, kNoGC) \
496 M(CheckSmi, kNoGC) \
497 M(CheckNull, kNoGC) \
498 M(CheckCondition, kNoGC) \
499 M(Constant, kNoGC) \
500 M(UnboxedConstant, kNoGC) \
501 M(CheckEitherNonSmi, kNoGC) \
502 M(BinaryDoubleOp, kNoGC) \
503 M(DoubleTestOp, kNoGC) \
504 M(MathMinMax, kNoGC) \
505 M(Box, _) \
506 M(Unbox, kNoGC) \
507 M(BoxInt64, _) \
508 M(UnboxInt64, kNoGC) \
509 M(CaseInsensitiveCompare, kNoGC) \
510 M(BinaryInt64Op, kNoGC) \
511 M(ShiftInt64Op, kNoGC) \
512 M(SpeculativeShiftInt64Op, kNoGC) \
513 M(UnaryInt64Op, kNoGC) \
514 M(CheckArrayBound, kNoGC) \
515 M(GenericCheckBound, kNoGC) \
516 M(CheckWritable, kNoGC) \
517 M(Constraint, kNoGC) \
518 M(StringToCharCode, kNoGC) \
519 M(OneByteStringFromCharCode, kNoGC) \
520 M(Utf8Scan, kNoGC) \
521 M(InvokeMathCFunction, kNoGC) \
522 M(TruncDivMod, kNoGC) \
523 /*We could be more precise about when these 2 instructions can trigger GC.*/ \
524 M(GuardFieldClass, _) \
525 M(GuardFieldLength, _) \
526 M(GuardFieldType, _) \
527 M(IfThenElse, kNoGC) \
528 M(MaterializeObject, _) \
529 M(TestSmi, kNoGC) \
530 M(TestCids, kNoGC) \
531 M(TestRange, kNoGC) \
532 M(ExtractNthOutput, kNoGC) \
533 M(MakePair, kNoGC) \
534 M(UnboxLane, kNoGC) \
535 M(BoxLanes, _) \
536 M(BinaryUint32Op, kNoGC) \
537 M(ShiftUint32Op, kNoGC) \
538 M(SpeculativeShiftUint32Op, kNoGC) \
539 M(UnaryUint32Op, kNoGC) \
540 M(BoxUint32, _) \
541 M(UnboxUint32, kNoGC) \
542 M(BoxInt32, _) \
543 M(UnboxInt32, kNoGC) \
544 M(BoxSmallInt, kNoGC) \
545 M(IntConverter, kNoGC) \
546 M(BitCast, kNoGC) \
547 M(Call1ArgStub, _) \
548 M(LoadThread, kNoGC) \
549 M(Deoptimize, kNoGC) \
550 M(SimdOp, kNoGC) \
551 M(Suspend, _)
552
553#define FOR_EACH_ABSTRACT_INSTRUCTION(M) \
554 M(Allocation, _) \
555 M(ArrayAllocation, _) \
556 M(BinaryIntegerOp, _) \
557 M(BlockEntry, _) \
558 M(BoxInteger, _) \
559 M(CheckBoundBase, _) \
560 M(Comparison, _) \
561 M(InstanceCallBase, _) \
562 M(ReturnBase, _) \
563 M(ShiftIntegerOp, _) \
564 M(UnaryIntegerOp, _) \
565 M(UnboxInteger, _)
566
567#define FORWARD_DECLARATION(type, attrs) class type##Instr;
570#undef FORWARD_DECLARATION
571
572#define DEFINE_INSTRUCTION_TYPE_CHECK(type) \
573 virtual type##Instr* As##type() { \
574 return this; \
575 } \
576 virtual const type##Instr* As##type() const { \
577 return this; \
578 } \
579 virtual const char* DebugName() const { \
580 return #type; \
581 }
582
583// Functions required in all concrete instruction classes.
584#define DECLARE_INSTRUCTION_NO_BACKEND(type) \
585 virtual Tag tag() const { \
586 return k##type; \
587 } \
588 virtual void Accept(InstructionVisitor* visitor); \
589 DEFINE_INSTRUCTION_TYPE_CHECK(type)
590
591#define DECLARE_INSTRUCTION_BACKEND() \
592 virtual LocationSummary* MakeLocationSummary(Zone* zone, bool optimizing) \
593 const; \
594 virtual void EmitNativeCode(FlowGraphCompiler* compiler);
595
596// Functions required in all concrete instruction classes.
597#define DECLARE_INSTRUCTION(type) \
598 DECLARE_INSTRUCTION_NO_BACKEND(type) \
599 DECLARE_INSTRUCTION_BACKEND()
600
601// Functions required in all abstract instruction classes.
602#define DECLARE_ABSTRACT_INSTRUCTION(type) \
603 /* Prevents allocating an instance of abstract instruction */ \
604 /* even if it has a concrete base class. */ \
605 virtual Tag tag() const = 0; \
606 DEFINE_INSTRUCTION_TYPE_CHECK(type)
607
608#define DECLARE_COMPARISON_METHODS \
609 virtual LocationSummary* MakeLocationSummary(Zone* zone, bool optimizing) \
610 const; \
611 virtual Condition EmitComparisonCode(FlowGraphCompiler* compiler, \
612 BranchLabels labels);
613
614#define DECLARE_COMPARISON_INSTRUCTION(type) \
615 DECLARE_INSTRUCTION_NO_BACKEND(type) \
616 DECLARE_COMPARISON_METHODS
617
618template <typename T, bool is_enum>
619struct unwrap_enum {};
620
621template <typename T>
623 using type = std::underlying_type_t<T>;
624};
625
626template <typename T>
628 using type = T;
629};
630
631template <typename T>
633 typename unwrap_enum<std::remove_cv_t<T>, std::is_enum<T>::value>::type;
634
635#define WRITE_INSTRUCTION_FIELD(type, name) \
636 s->Write<serializable_type_t<type>>( \
637 static_cast<serializable_type_t<type>>(name));
638#define READ_INSTRUCTION_FIELD(type, name) \
639 , name(static_cast<std::remove_cv_t<type>>( \
640 d->Read<serializable_type_t<type>>()))
641#define DECLARE_INSTRUCTION_FIELD(type, name) type name;
642
643// Every instruction class should declare its serialization via
644// DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS, DECLARE_EMPTY_SERIALIZATION
645// or DECLARE_CUSTOM_SERIALIZATION.
646// If instruction class has fields which reference other instructions,
647// then it should also use DECLARE_EXTRA_SERIALIZATION and serialize
648// those references in WriteExtra/ReadExtra methods.
649#define DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(Instr, BaseClass, FieldList) \
650 public: \
651 virtual void WriteTo(FlowGraphSerializer* s) { \
652 BaseClass::WriteTo(s); \
653 FieldList(WRITE_INSTRUCTION_FIELD) \
654 } \
655 explicit Instr(FlowGraphDeserializer* d) \
656 : BaseClass(d) FieldList(READ_INSTRUCTION_FIELD) {} \
657 \
658 private: \
659 FieldList(DECLARE_INSTRUCTION_FIELD)
660
661#define DECLARE_CUSTOM_SERIALIZATION(Instr) \
662 public: \
663 virtual void WriteTo(FlowGraphSerializer* s); \
664 explicit Instr(FlowGraphDeserializer* d);
665
666#define DECLARE_EMPTY_SERIALIZATION(Instr, BaseClass) \
667 public: \
668 explicit Instr(FlowGraphDeserializer* d) : BaseClass(d) {}
669
670#define DECLARE_EXTRA_SERIALIZATION \
671 public: \
672 virtual void WriteExtra(FlowGraphSerializer* s); \
673 virtual void ReadExtra(FlowGraphDeserializer* d);
674
675#if defined(INCLUDE_IL_PRINTER)
676#define PRINT_TO_SUPPORT virtual void PrintTo(BaseTextBuffer* f) const;
677#define PRINT_OPERANDS_TO_SUPPORT \
678 virtual void PrintOperandsTo(BaseTextBuffer* f) const;
679// Used for an instruction with a single attribute where the name of the
680// attribute should be derived from the expression. See
681// IlTestPrinter::AttributesSerializer::WriteAttributeName for more info.
682#define DECLARE_ATTRIBUTE(Attribute) \
683 auto GetAttributes() const { \
684 return std::make_tuple(Attribute); \
685 } \
686 static auto GetAttributeNames() { \
687 return std::make_tuple(#Attribute); \
688 }
689// Used for instructions with either multiple attributes or where the name of
690// the attribute should not be derived from the expression.
691#define DECLARE_ATTRIBUTES_NAMED(names, values) \
692 auto GetAttributes() const { \
693 return std::make_tuple values; \
694 } \
695 static auto GetAttributeNames() { \
696 return std::make_tuple names; \
697 }
698#else
699#define PRINT_TO_SUPPORT
700#define PRINT_OPERANDS_TO_SUPPORT
701#define DECLARE_ATTRIBUTE(Attribute)
702#define DECLARE_ATTRIBUTES_NAMED(names, values)
703#endif // defined(INCLUDE_IL_PRINTER)
704
705// Together with CidRange, this represents a mapping from a range of class-ids
706// to a method for a given selector (method name). Also can contain an
707// indication of how frequently a given method has been called at a call site.
708// This information can be harvested from the inline caches (ICs).
709struct TargetInfo : public CidRange {
710 TargetInfo(intptr_t cid_start_arg,
711 intptr_t cid_end_arg,
712 const Function* target_arg,
713 intptr_t count_arg,
715 : CidRange(cid_start_arg, cid_end_arg),
716 target(target_arg),
717 count(count_arg),
719 DEBUG_ASSERT(target->IsNotTemporaryScopedHandle());
720 }
722 intptr_t count;
724
726};
727
728// A set of class-ids, arranged in ranges. Used for the CheckClass
729// and PolymorphicInstanceCall instructions.
730class Cids : public ZoneAllocated {
731 public:
732 explicit Cids(Zone* zone) : cid_ranges_(zone, 6) {}
733 // Creates the off-heap Cids object that reflects the contents
734 // of the on-VM-heap IC data.
735 // Ranges of Cids are merged if there is only one target function and
736 // it is used for all cids in the gaps between ranges.
737 static Cids* CreateForArgument(Zone* zone,
738 const BinaryFeedback& binary_feedback,
739 int argument_number);
740 static Cids* CreateMonomorphic(Zone* zone, intptr_t cid);
741
742 bool Equals(const Cids& other) const;
743
744 bool HasClassId(intptr_t cid) const;
745
747
748 CidRange& operator[](intptr_t index) const { return *cid_ranges_[index]; }
749
750 CidRange* At(int index) const { return cid_ranges_[index]; }
751
752 intptr_t length() const { return cid_ranges_.length(); }
753
754 void SetLength(intptr_t len) { cid_ranges_.SetLength(len); }
755
756 bool is_empty() const { return cid_ranges_.is_empty(); }
757
758 void Sort(int compare(CidRange* const* a, CidRange* const* b)) {
759 cid_ranges_.Sort(compare);
760 }
761
762 bool IsMonomorphic() const;
763 intptr_t MonomorphicReceiverCid() const;
764 intptr_t ComputeLowestCid() const;
765 intptr_t ComputeHighestCid() const;
766
767 protected:
769
770 private:
772};
773
774class CallTargets : public Cids {
775 public:
776 explicit CallTargets(Zone* zone) : Cids(zone) {}
777
778 static const CallTargets* CreateMonomorphic(Zone* zone,
779 intptr_t receiver_cid,
780 const Function& target);
781
782 // Creates the off-heap CallTargets object that reflects the contents
783 // of the on-VM-heap IC data.
784 static const CallTargets* Create(Zone* zone, const ICData& ic_data);
785
786 // This variant also expands the class-ids to neighbouring classes that
787 // inherit the same method.
788 static const CallTargets* CreateAndExpand(Zone* zone, const ICData& ic_data);
789
790 TargetInfo* TargetAt(int i) const { return static_cast<TargetInfo*>(At(i)); }
791
792 intptr_t AggregateCallCount() const;
793
795 bool HasSingleTarget() const;
796 bool HasSingleRecognizedTarget() const;
797 const Function& FirstTarget() const;
798 const Function& MostPopularTarget() const;
799
800 void Print() const;
801
802 bool ReceiverIs(intptr_t cid) const {
804 }
805 bool ReceiverIsSmiOrMint() const {
806 if (cid_ranges_.is_empty()) {
807 return false;
808 }
809 for (intptr_t i = 0, n = cid_ranges_.length(); i < n; i++) {
810 for (intptr_t j = cid_ranges_[i]->cid_start; j <= cid_ranges_[i]->cid_end;
811 j++) {
812 if (j != kSmiCid && j != kMintCid) {
813 return false;
814 }
815 }
816 }
817 return true;
818 }
819
820 void Write(FlowGraphSerializer* s) const;
822
823 private:
824 void CreateHelper(Zone* zone, const ICData& ic_data);
825 void MergeIntoRanges();
826};
827
828// Represents type feedback for the binary operators, and a few recognized
829// static functions (see MethodRecognizer::NumArgsCheckedForStaticCall).
831 public:
832 explicit BinaryFeedback(Zone* zone) : feedback_(zone, 2) {}
833
834 static const BinaryFeedback* Create(Zone* zone, const ICData& ic_data);
835 static const BinaryFeedback* CreateMonomorphic(Zone* zone,
836 intptr_t receiver_cid,
837 intptr_t argument_cid);
838
839 bool ArgumentIs(intptr_t cid) const {
840 if (feedback_.is_empty()) {
841 return false;
842 }
843 for (intptr_t i = 0, n = feedback_.length(); i < n; i++) {
844 if (feedback_[i].second != cid) {
845 return false;
846 }
847 }
848 return true;
849 }
850
851 bool OperandsAreEither(intptr_t cid_a, intptr_t cid_b) const {
852 if (feedback_.is_empty()) {
853 return false;
854 }
855 for (intptr_t i = 0, n = feedback_.length(); i < n; i++) {
856 if ((feedback_[i].first != cid_a) && (feedback_[i].first != cid_b)) {
857 return false;
858 }
859 if ((feedback_[i].second != cid_a) && (feedback_[i].second != cid_b)) {
860 return false;
861 }
862 }
863 return true;
864 }
865 bool OperandsAreSmiOrNull() const {
866 return OperandsAreEither(kSmiCid, kNullCid);
867 }
868 bool OperandsAreSmiOrMint() const {
869 return OperandsAreEither(kSmiCid, kMintCid);
870 }
872 return OperandsAreEither(kSmiCid, kDoubleCid);
873 }
874
875 bool OperandsAre(intptr_t cid) const {
876 if (feedback_.length() != 1) return false;
877 return (feedback_[0].first == cid) && (feedback_[0].second == cid);
878 }
879
880 bool IncludesOperands(intptr_t cid) const {
881 for (intptr_t i = 0, n = feedback_.length(); i < n; i++) {
882 if ((feedback_[i].first == cid) && (feedback_[i].second == cid)) {
883 return true;
884 }
885 }
886 return false;
887 }
888
889 private:
891
892 friend class Cids;
893};
894
897
898template <typename Trait>
900 public:
901 struct Iterator {
903 intptr_t index;
904
905 decltype(Trait::At(instr, index)) operator*() const {
906 return Trait::At(instr, index);
907 }
909 index++;
910 return *this;
911 }
912
913 bool operator==(const Iterator& other) {
914 return instr == other.instr && index == other.index;
915 }
916
917 bool operator!=(const Iterator& other) { return !(*this == other); }
918 };
919
921 : instr_(instr) {}
922
923 Iterator begin() const { return {instr_, 0}; }
924 Iterator end() const { return {instr_, Trait::Length(instr_)}; }
925
926 private:
927 const Instruction* instr_;
928};
929
931 public:
932 struct Iterator {
934
935 Value* operator*() const { return value; }
936
938 value = value->next_use();
939 return *this;
940 }
941
942 bool operator==(const Iterator& other) { return value == other.value; }
943
944 bool operator!=(const Iterator& other) { return !(*this == other); }
945 };
946
947 explicit ValueListIterable(Value* value) : value_(value) {}
948
949 Iterator begin() const { return {value_}; }
950 Iterator end() const { return {nullptr}; }
951
952 private:
953 Value* value_;
954};
955
957 public:
958#define DECLARE_TAG(type, attrs) k##type,
959 enum Tag { FOR_EACH_INSTRUCTION(DECLARE_TAG) kNumInstructions };
960#undef DECLARE_TAG
961
962 static const intptr_t kInstructionAttrs[kNumInstructions];
963
965 // Types of inputs should be checked when unboxing for this instruction.
967 // Each input is guaranteed to have a valid type for the input
968 // representation and its type should not be checked when unboxing.
970 };
971
972 // If the source has the inlining ID of the root function, then don't set
973 // the inlining ID to that; instead, treat it as unset.
975 intptr_t deopt_id = DeoptId::kNone)
976 : deopt_id_(deopt_id), inlining_id_(source.inlining_id) {}
977
980
981 virtual ~Instruction() {}
982
983 virtual Tag tag() const = 0;
984
985 virtual intptr_t statistics_tag() const { return tag(); }
986
987 intptr_t deopt_id() const {
990 CompilerState::Current().is_aot());
991 return GetDeoptId();
992 }
993
994 static const ICData* GetICData(
995 const ZoneGrowableArray<const ICData*>& ic_data_array,
996 intptr_t deopt_id,
997 bool is_static_call);
998
999 virtual TokenPosition token_pos() const { return TokenPosition::kNoSource; }
1000
1001 // Returns the source information for this instruction.
1005
1006 virtual intptr_t InputCount() const = 0;
1007 virtual Value* InputAt(intptr_t i) const = 0;
1008 void SetInputAt(intptr_t i, Value* value) {
1009 ASSERT(value != nullptr);
1010 value->set_instruction(this);
1011 value->set_use_index(i);
1012 RawSetInputAt(i, value);
1013 }
1014
1016 static Definition* At(const Instruction* instr, intptr_t index) {
1017 return instr->InputAt(index)->definition();
1018 }
1019
1020 static intptr_t Length(const Instruction* instr) {
1021 return instr->InputCount();
1022 }
1023 };
1024
1026
1028
1029 // Remove all inputs (including in the environment) from their
1030 // definition's use lists.
1031 void UnuseAllInputs();
1032
1033 // Call instructions override this function and return the number of
1034 // pushed arguments.
1035 virtual intptr_t ArgumentCount() const { return 0; }
1036 inline Value* ArgumentValueAt(intptr_t index) const;
1037 inline Definition* ArgumentAt(intptr_t index) const;
1038
1039 // Sets array of MoveArgument instructions.
1040 virtual void SetMoveArguments(MoveArgumentsArray* move_arguments) {
1041 UNREACHABLE();
1042 }
1043 // Returns array of MoveArgument instructions
1045 UNREACHABLE();
1046 return nullptr;
1047 }
1048 // Replace inputs with separate MoveArgument instructions detached from call.
1050 MoveArgumentsArray* move_arguments) {
1051 UNREACHABLE();
1052 }
1053 bool HasMoveArguments() const { return GetMoveArguments() != nullptr; }
1054
1055 // Replaces direct uses of arguments with uses of corresponding MoveArgument
1056 // instructions.
1058
1059 // Returns true, if this instruction can deoptimize with its current inputs.
1060 // This property can change if we add or remove redefinitions that constrain
1061 // the type or the range of input operands during compilation.
1062 virtual bool ComputeCanDeoptimize() const = 0;
1063
1064 virtual bool ComputeCanDeoptimizeAfterCall() const {
1065 // TODO(dartbug.com/45213): Incrementally migrate IR instructions from using
1066 // [ComputeCanDeoptimize] to [ComputeCanDeoptimizeAfterCall] if they
1067 // can only lazy deoptimize.
1068 return false;
1069 }
1070
1071 // Once we removed the deopt environment, we assume that this
1072 // instruction can't deoptimize.
1073 bool CanDeoptimize() const {
1074 return env() != nullptr &&
1076 }
1077
1078 // Visiting support.
1079 virtual void Accept(InstructionVisitor* visitor) = 0;
1080
1081 Instruction* previous() const { return previous_; }
1083 ASSERT(!IsBlockEntry());
1084 previous_ = instr;
1085 }
1086
1087 Instruction* next() const { return next_; }
1088 void set_next(Instruction* instr) {
1089 ASSERT(!IsGraphEntry());
1090 ASSERT(!IsReturnBase());
1091 ASSERT(!IsBranch() || (instr == nullptr));
1092 ASSERT(!IsPhi());
1093 ASSERT(instr == nullptr || !instr->IsBlockEntry());
1094 // TODO(fschneider): Also add Throw and ReThrow to the list of instructions
1095 // that do not have a successor. Currently, the graph builder will continue
1096 // to append instruction in case of a Throw inside an expression. This
1097 // condition should be handled in the graph builder
1098 next_ = instr;
1099 }
1100
1101 // Link together two instruction.
1103 ASSERT(this != next);
1104 this->set_next(next);
1105 next->set_previous(this);
1106 }
1107
1108 // Removed this instruction from the graph, after use lists have been
1109 // computed. If the instruction is a definition with uses, those uses are
1110 // unaffected (so the instruction can be reinserted, e.g., hoisting).
1111 Instruction* RemoveFromGraph(bool return_previous = true);
1112
1113 // Normal instructions can have 0 (inside a block) or 1 (last instruction in
1114 // a block) successors. Branch instruction with >1 successors override this
1115 // function.
1116 virtual intptr_t SuccessorCount() const;
1117 virtual BlockEntryInstr* SuccessorAt(intptr_t index) const;
1118
1120 static BlockEntryInstr* At(const Instruction* instr, intptr_t index) {
1121 return instr->SuccessorAt(index);
1122 }
1123
1124 static intptr_t Length(const Instruction* instr) {
1125 return instr->SuccessorCount();
1126 }
1127 };
1128
1131
1133 return SuccessorsIterable(this);
1134 }
1135
1136 void Goto(JoinEntryInstr* entry);
1137
1138 virtual const char* DebugName() const = 0;
1139
1140#if defined(DEBUG)
1141 // Checks that the field stored in an instruction has proper form:
1142 // - must be a zone-handle
1143 // - In background compilation, must be cloned.
1144 // Aborts if field is not OK.
1145 void CheckField(const Field& field) const;
1146#else
1147 void CheckField(const Field& field) const {}
1148#endif // DEBUG
1149
1150 // Printing support.
1151 const char* ToCString() const;
1154
1155#define DECLARE_INSTRUCTION_TYPE_CHECK(Name, Type) \
1156 bool Is##Name() const { return (As##Name() != nullptr); } \
1157 Type* As##Name() { \
1158 auto const_this = static_cast<const Instruction*>(this); \
1159 return const_cast<Type*>(const_this->As##Name()); \
1160 } \
1161 virtual const Type* As##Name() const { return nullptr; }
1162#define INSTRUCTION_TYPE_CHECK(Name, Attrs) \
1163 DECLARE_INSTRUCTION_TYPE_CHECK(Name, Name##Instr)
1164
1165 DECLARE_INSTRUCTION_TYPE_CHECK(Definition, Definition)
1170
1171#undef INSTRUCTION_TYPE_CHECK
1172#undef DECLARE_INSTRUCTION_TYPE_CHECK
1173
1174 template <typename T>
1175 T* Cast() {
1176 return static_cast<T*>(this);
1177 }
1178
1179 template <typename T>
1180 const T* Cast() const {
1181 return static_cast<const T*>(this);
1182 }
1183
1184 // Returns structure describing location constraints required
1185 // to emit native code for this instruction.
1187 ASSERT(locs_ != nullptr);
1188 return locs_;
1189 }
1190
1191 bool HasLocs() const { return locs_ != nullptr; }
1192
1194 bool is_optimizing) const = 0;
1195
1196 void InitializeLocationSummary(Zone* zone, bool optimizing) {
1197 ASSERT(locs_ == nullptr);
1198 locs_ = MakeLocationSummary(zone, optimizing);
1199 }
1200
1201 // Makes a new call location summary (or uses `locs`) and initializes the
1202 // output register constraints depending on the representation of [instr].
1204 const Instruction* instr,
1205 LocationSummary* locs = nullptr);
1206
1208
1209 Environment* env() const { return env_; }
1210 void SetEnvironment(Environment* deopt_env);
1211 void RemoveEnvironment();
1212 void ReplaceInEnvironment(Definition* current, Definition* replacement);
1213
1214 virtual intptr_t NumberOfInputsConsumedBeforeCall() const { return 0; }
1215
1216 // Different compiler passes can assign pass specific ids to the instruction.
1217 // Only one id can be stored at a time.
1219 return (PassSpecificId::DecodePass(pass_specific_id_) == pass)
1220 ? PassSpecificId::DecodeId(pass_specific_id_)
1221 : PassSpecificId::kNoId;
1222 }
1223 void SetPassSpecificId(CompilerPass::Id pass, intptr_t id) {
1224 pass_specific_id_ = PassSpecificId::Encode(pass, id);
1225 }
1227 return (PassSpecificId::DecodePass(pass_specific_id_) == pass) &&
1228 (PassSpecificId::DecodeId(pass_specific_id_) !=
1229 PassSpecificId::kNoId);
1230 }
1231
1233
1234 // Returns representation expected for the input operand at the given index.
1235 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
1236 return kTagged;
1237 }
1238
1240 for (intptr_t i = 0; i < InputCount(); i++) {
1242 return kGuardInputs;
1243 }
1244 }
1245 return kNotSpeculative;
1246 }
1247
1248 // By default, instructions should check types of inputs when unboxing
1249 virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const {
1250 return kGuardInputs;
1251 }
1252
1253 // Representation of the value produced by this computation.
1254 virtual Representation representation() const { return kTagged; }
1255
1256 bool WasEliminated() const { return next() == nullptr; }
1257
1258 // Returns deoptimization id that corresponds to the deoptimization target
1259 // that input operands conversions inserted for this instruction can jump
1260 // to.
1261 virtual intptr_t DeoptimizationTarget() const {
1262 UNREACHABLE();
1263 return DeoptId::kNone;
1264 }
1265
1266 // Returns a replacement for the instruction or nullptr if the instruction can
1267 // be eliminated. By default returns the this instruction which means no
1268 // change.
1269 virtual Instruction* Canonicalize(FlowGraph* flow_graph);
1270
1271 // Insert this instruction before 'next' after use lists are computed.
1272 // Instructions cannot be inserted before a block entry or any other
1273 // instruction without a previous instruction.
1275
1276 // Insert this instruction after 'prev' after use lists are computed.
1278
1279 // Append an instruction to the current one and return the tail.
1280 // This function updated def-use chains of the newly appended
1281 // instruction.
1283
1284 // Returns true if CSE and LICM are allowed for this instruction.
1285 virtual bool AllowsCSE() const { return false; }
1286
1287 // Returns true if this instruction has any side-effects besides storing.
1288 // See StoreFieldInstr::HasUnknownSideEffects() for rationale.
1289 virtual bool HasUnknownSideEffects() const = 0;
1290
1291 // Whether this instruction can call Dart code without going through
1292 // the runtime.
1293 //
1294 // Must be true for any instruction which can call Dart code without
1295 // first creating an exit frame to transition into the runtime.
1296 //
1297 // See also WriteBarrierElimination and Thread::RememberLiveTemporaries().
1298 virtual bool CanCallDart() const { return false; }
1299
1300 virtual bool CanTriggerGC() const;
1301
1302 // Get the block entry for this instruction.
1303 virtual BlockEntryInstr* GetBlock();
1304
1305 virtual intptr_t inlining_id() const { return inlining_id_; }
1306 virtual void set_inlining_id(intptr_t value) {
1307 ASSERT(value >= 0);
1308 ASSERT(!has_inlining_id() || inlining_id_ == value);
1309 inlining_id_ = value;
1310 }
1311 virtual bool has_inlining_id() const { return inlining_id_ >= 0; }
1312
1313 // Returns a hash code for use with hash maps.
1314 virtual uword Hash() const;
1315
1316 // Compares two instructions. Returns true, iff:
1317 // 1. They have the same tag.
1318 // 2. All input operands are Equals.
1319 // 3. They satisfy AttributesEqual.
1320 bool Equals(const Instruction& other) const;
1321
1322 // Compare attributes of a instructions (except input operands and tag).
1323 // All instructions that participate in CSE have to override this function.
1324 // This function can assume that the argument has the same type as this.
1325 virtual bool AttributesEqual(const Instruction& other) const {
1326 UNREACHABLE();
1327 return false;
1328 }
1329
1330 void InheritDeoptTarget(Zone* zone, Instruction* other);
1331
1336
1337 virtual bool CanBecomeDeoptimizationTarget() const { return false; }
1338
1339 void InheritDeoptTargetAfter(FlowGraph* flow_graph,
1340 Definition* call,
1342
1343 virtual bool MayThrow() const = 0;
1344
1345 // Returns true if instruction may have a "visible" effect,
1346 virtual bool MayHaveVisibleEffect() const {
1347 return HasUnknownSideEffects() || MayThrow();
1348 }
1349
1350 // Returns true if this instruction can be eliminated if its result is not
1351 // used without changing the behavior of the program. For Definitions,
1352 // overwrite CanReplaceWithConstant() instead.
1353 virtual bool CanEliminate(const BlockEntryInstr* block) const;
1354 bool CanEliminate() { return CanEliminate(GetBlock()); }
1355
1357
1358 void ClearEnv() { env_ = nullptr; }
1359
1361
1362 static bool SlowPathSharingSupported(bool is_optimizing) {
1363#if defined(TARGET_ARCH_IA32)
1364 return false;
1365#else
1366 return FLAG_enable_slow_path_sharing && FLAG_precompiled_mode &&
1367 is_optimizing;
1368#endif
1369 }
1370
1371 virtual bool UseSharedSlowPathStub(bool is_optimizing) const { return false; }
1372
1373 // 'RegisterKindForResult()' returns the register kind necessary to hold the
1374 // result.
1375 //
1376 // This is not virtual because instructions should override representation()
1377 // instead.
1379 const Representation rep = representation();
1380 if ((rep == kUnboxedFloat) || (rep == kUnboxedDouble) ||
1381 (rep == kUnboxedFloat32x4) || (rep == kUnboxedInt32x4) ||
1382 (rep == kUnboxedFloat64x2)) {
1384 }
1385 return Location::kRegister;
1386 }
1387
1390
1391 protected:
1392 // GetDeoptId and/or CopyDeoptIdFrom.
1393 friend class CallSiteInliner;
1394 friend class LICM;
1395 friend class ComparisonInstr;
1396 friend class Scheduler;
1397 friend class BlockEntryInstr;
1398 friend class CatchBlockEntryInstr; // deopt_id_
1399 friend class DebugStepCheckInstr; // deopt_id_
1400 friend class StrictCompareInstr; // deopt_id_
1401
1402 // Fetch deopt id without checking if this computation can deoptimize.
1403 intptr_t GetDeoptId() const { return deopt_id_; }
1404
1405 virtual void CopyDeoptIdFrom(const Instruction& instr) {
1406 deopt_id_ = instr.deopt_id_;
1407 }
1408
1409 // Write/read locs and environment, but not inputs.
1410 // Used when one instruction embeds another and reuses their inputs
1411 // (e.g. Branch/IfThenElse/CheckCondition wrap Comparison).
1414
1415 private:
1416 friend class BranchInstr; // For RawSetInputAt.
1417 friend class IfThenElseInstr; // For RawSetInputAt.
1418 friend class CheckConditionInstr; // For RawSetInputAt.
1419
1420 virtual void RawSetInputAt(intptr_t i, Value* value) = 0;
1421
1422 class PassSpecificId {
1423 public:
1424 static intptr_t Encode(CompilerPass::Id pass, intptr_t id) {
1425 return (id << kPassBits) | pass;
1426 }
1427
1428 static CompilerPass::Id DecodePass(intptr_t value) {
1429 return static_cast<CompilerPass::Id>(value & Utils::NBitMask(kPassBits));
1430 }
1431
1432 static intptr_t DecodeId(intptr_t value) { return (value >> kPassBits); }
1433
1434 static constexpr intptr_t kNoId = -1;
1435
1436 private:
1437 static constexpr intptr_t kPassBits = 8;
1438 static_assert(CompilerPass::kNumPasses <= (1 << kPassBits),
1439 "Pass Id does not fit into the bit field");
1440 };
1441
1442 intptr_t deopt_id_ = DeoptId::kNone;
1443 intptr_t pass_specific_id_ = PassSpecificId::kNoId;
1444 Instruction* previous_ = nullptr;
1445 Instruction* next_ = nullptr;
1446 Environment* env_ = nullptr;
1447 LocationSummary* locs_ = nullptr;
1448 intptr_t inlining_id_;
1449
1451};
1452
1458
1460 public:
1464
1465 virtual bool AllowsCSE() const { return true; }
1466 virtual bool HasUnknownSideEffects() const { return false; }
1467
1469};
1470
1471// Types to be used as ThrowsTrait for TemplateInstruction/TemplateDefinition.
1472struct Throws {
1473 static constexpr bool kCanThrow = true;
1474};
1475
1476struct NoThrow {
1477 static constexpr bool kCanThrow = false;
1478};
1479
1480// Types to be used as CSETrait for TemplateInstruction/TemplateDefinition.
1481// Pure instructions are those that allow CSE and have no effects and
1482// no dependencies.
1483template <typename DefaultBase, typename PureBase>
1484struct Pure {
1485 typedef PureBase Base;
1486};
1487
1488template <typename DefaultBase, typename PureBase>
1489struct NoCSE {
1490 typedef DefaultBase Base;
1491};
1492
1493template <intptr_t N,
1494 typename ThrowsTrait,
1495 template <typename Default, typename Pure> class CSETrait = NoCSE>
1497 : public CSETrait<Instruction, PureInstruction>::Base {
1498 public:
1499 using BaseClass = typename CSETrait<Instruction, PureInstruction>::Base;
1500
1501 explicit TemplateInstruction(intptr_t deopt_id = DeoptId::kNone)
1502 : BaseClass(deopt_id), inputs_() {}
1503
1505 intptr_t deopt_id = DeoptId::kNone)
1506 : BaseClass(source, deopt_id), inputs_() {}
1507
1508 virtual intptr_t InputCount() const { return N; }
1509 virtual Value* InputAt(intptr_t i) const { return inputs_[i]; }
1510
1511 virtual bool MayThrow() const { return ThrowsTrait::kCanThrow; }
1512
1514
1515 protected:
1517
1518 private:
1519 virtual void RawSetInputAt(intptr_t i, Value* value) { inputs_[i] = value; }
1520};
1521
1523 public:
1526 : ZoneAllocated(), dest_(other.dest_), src_(other.src_) {}
1527
1529 dest_ = other.dest_;
1530 src_ = other.src_;
1531 return *this;
1532 }
1533
1534 Location src() const { return src_; }
1535 Location dest() const { return dest_; }
1536
1537 Location* src_slot() { return &src_; }
1538 Location* dest_slot() { return &dest_; }
1539
1540 void set_src(const Location& value) { src_ = value; }
1541 void set_dest(const Location& value) { dest_ = value; }
1542
1543 // The parallel move resolver marks moves as "in-progress" by clearing the
1544 // destination (but not the source).
1546 ASSERT(!IsPending());
1547 Location dest = dest_;
1548 dest_ = Location::NoLocation();
1549 return dest;
1550 }
1551
1553 ASSERT(IsPending());
1554 dest_ = dest;
1555 }
1556
1557 bool IsPending() const {
1558 ASSERT(!src_.IsInvalid() || dest_.IsInvalid());
1559 return dest_.IsInvalid() && !src_.IsInvalid();
1560 }
1561
1562 // True if this move a move from the given location.
1563 bool Blocks(Location loc) const {
1564 return !IsEliminated() && src_.Equals(loc);
1565 }
1566
1567 // A move is redundant if it's been eliminated, if its source and
1568 // destination are the same, or if its destination is unneeded.
1569 bool IsRedundant() const {
1570 return IsEliminated() || dest_.IsInvalid() || src_.Equals(dest_);
1571 }
1572
1573 // We clear both operands to indicate move that's been eliminated.
1574 void Eliminate() { src_ = dest_ = Location::NoLocation(); }
1575 bool IsEliminated() const {
1576 ASSERT(!src_.IsInvalid() || dest_.IsInvalid());
1577 return src_.IsInvalid();
1578 }
1579
1580 void Write(FlowGraphSerializer* s) const;
1582
1583 private:
1584 Location dest_;
1585 Location src_;
1586};
1587
1588class ParallelMoveInstr : public TemplateInstruction<0, NoThrow> {
1589 public:
1590 ParallelMoveInstr() : moves_(4) {}
1591
1592 DECLARE_INSTRUCTION(ParallelMove)
1593
1594 virtual bool ComputeCanDeoptimize() const { return false; }
1595
1596 virtual bool HasUnknownSideEffects() const {
1597 UNREACHABLE(); // This instruction never visited by optimization passes.
1598 return false;
1599 }
1600
1601 const GrowableArray<MoveOperands*>& moves() const { return moves_; }
1602
1604 MoveOperands* move = new MoveOperands(dest, src);
1605 moves_.Add(move);
1606 return move;
1607 }
1608
1609 MoveOperands* MoveOperandsAt(intptr_t index) const { return moves_[index]; }
1610
1611 intptr_t NumMoves() const { return moves_.length(); }
1612
1613 bool IsRedundant() const;
1614
1615 virtual TokenPosition token_pos() const {
1616 return TokenPosition::kParallelMove;
1617 }
1618
1620 ASSERT(move_schedule_ != nullptr);
1621 return *move_schedule_;
1622 }
1623
1624 void set_move_schedule(const MoveSchedule& schedule) {
1625 move_schedule_ = &schedule;
1626 }
1627
1631
1632 private:
1633 GrowableArray<MoveOperands*> moves_; // Elements cannot be null.
1634 const MoveSchedule* move_schedule_ = nullptr;
1635
1637};
1638
1639// Basic block entries are administrative nodes. There is a distinguished
1640// graph entry with no predecessor. Joins are the only nodes with multiple
1641// predecessors. Targets are all other basic block entries. The types
1642// enforce edge-split form---joins are forbidden as the successors of
1643// branches.
1644class BlockEntryInstr : public TemplateInstruction<0, NoThrow> {
1645 public:
1646 virtual intptr_t PredecessorCount() const = 0;
1647 virtual BlockEntryInstr* PredecessorAt(intptr_t index) const = 0;
1648
1649 intptr_t preorder_number() const { return preorder_number_; }
1650 void set_preorder_number(intptr_t number) { preorder_number_ = number; }
1651
1652 intptr_t postorder_number() const { return postorder_number_; }
1653 void set_postorder_number(intptr_t number) { postorder_number_ = number; }
1654
1655 intptr_t block_id() const { return block_id_; }
1656
1657 // NOTE: These are SSA positions and not token positions. These are used by
1658 // the register allocator.
1659 void set_start_pos(intptr_t pos) { start_pos_ = pos; }
1660 intptr_t start_pos() const { return start_pos_; }
1661 void set_end_pos(intptr_t pos) { end_pos_ = pos; }
1662 intptr_t end_pos() const { return end_pos_; }
1663
1664 BlockEntryInstr* dominator() const { return dominator_; }
1666
1668 return dominated_blocks_;
1669 }
1670
1672 ASSERT(!block->IsFunctionEntry() || this->IsGraphEntry());
1673 block->set_dominator(this);
1674 dominated_blocks_.Add(block);
1675 }
1676 void ClearDominatedBlocks() { dominated_blocks_.Clear(); }
1677
1678 bool Dominates(BlockEntryInstr* other) const;
1679
1680 Instruction* last_instruction() const { return last_instruction_; }
1681 void set_last_instruction(Instruction* instr) { last_instruction_ = instr; }
1682
1683 ParallelMoveInstr* parallel_move() const { return parallel_move_; }
1684
1685 bool HasParallelMove() const { return parallel_move_ != nullptr; }
1686
1688 return HasParallelMove() && !parallel_move()->IsRedundant();
1689 }
1690
1692 if (parallel_move_ == nullptr) {
1693 parallel_move_ = new ParallelMoveInstr();
1694 }
1695 return parallel_move_;
1696 }
1697
1698 // Discover basic-block structure of the current block. Must be called
1699 // on all graph blocks in preorder to yield valid results. As a side effect,
1700 // the block entry instructions in the graph are assigned preorder numbers.
1701 // The array 'preorder' maps preorder block numbers to the block entry
1702 // instruction with that number. The depth first spanning tree is recorded
1703 // in the array 'parent', which maps preorder block numbers to the preorder
1704 // number of the block's spanning-tree parent. As a side effect of this
1705 // function, the set of basic block predecessors (e.g., block entry
1706 // instructions of predecessor blocks) and also the last instruction in the
1707 // block is recorded in each entry instruction. Returns true when called the
1708 // first time on this particular block within one graph traversal, and false
1709 // on all successive calls.
1710 bool DiscoverBlock(BlockEntryInstr* predecessor,
1712 GrowableArray<intptr_t>* parent);
1713
1714 virtual bool CanBecomeDeoptimizationTarget() const {
1715 // BlockEntry environment is copied to Goto and Branch instructions
1716 // when we insert new blocks targeting this block.
1717 return true;
1718 }
1719
1720 virtual bool ComputeCanDeoptimize() const { return false; }
1721
1722 virtual bool HasUnknownSideEffects() const { return false; }
1723
1724 intptr_t try_index() const { return try_index_; }
1725 void set_try_index(intptr_t index) { try_index_ = index; }
1726
1727 // True for blocks inside a try { } region.
1728 bool InsideTryBlock() const { return try_index_ != kInvalidTryIndex; }
1729
1730 // Loop related methods.
1731 LoopInfo* loop_info() const { return loop_info_; }
1733 bool IsLoopHeader() const;
1734 intptr_t NestingDepth() const;
1735
1736 virtual BlockEntryInstr* GetBlock() { return this; }
1737
1738 virtual TokenPosition token_pos() const {
1739 return TokenPosition::kControlFlow;
1740 }
1741
1742 // Helper to mutate the graph during inlining. This block should be
1743 // replaced with new_block as a predecessor of all of this block's
1744 // successors.
1746
1747 void set_block_id(intptr_t block_id) { block_id_ = block_id; }
1748
1749 // Stack-based IR bookkeeping.
1750 intptr_t stack_depth() const { return stack_depth_; }
1751 void set_stack_depth(intptr_t s) { stack_depth_ = s; }
1752
1753 // For all instruction in this block: Remove all inputs (including in the
1754 // environment) from their definition's use lists for all instructions.
1755 void ClearAllInstructions();
1756
1758 public:
1759 explicit InstructionsIterable(BlockEntryInstr* block) : block_(block) {}
1760
1761 inline ForwardInstructionIterator begin() const;
1762 inline ForwardInstructionIterator end() const;
1763
1764 private:
1765 BlockEntryInstr* block_;
1766 };
1767
1769
1771
1774
1775 protected:
1777 intptr_t try_index,
1778 intptr_t deopt_id,
1779 intptr_t stack_depth)
1780 : TemplateInstruction(deopt_id),
1781 block_id_(block_id),
1782 try_index_(try_index),
1783 stack_depth_(stack_depth),
1784 dominated_blocks_(1) {}
1785
1786 // Perform a depth first search to find OSR entry and
1787 // link it to the given graph entry.
1788 bool FindOsrEntryAndRelink(GraphEntryInstr* graph_entry,
1789 Instruction* parent,
1790 BitVector* block_marks);
1791
1792 private:
1793 virtual void ClearPredecessors() = 0;
1794 virtual void AddPredecessor(BlockEntryInstr* predecessor) = 0;
1795
1796 void set_dominator(BlockEntryInstr* instr) { dominator_ = instr; }
1797
1798 intptr_t block_id_;
1799 intptr_t try_index_;
1800 intptr_t preorder_number_ = -1;
1801 intptr_t postorder_number_ = -1;
1802 // Expected stack depth on entry (for stack-based IR only).
1803 intptr_t stack_depth_;
1804 // Starting and ending lifetime positions for this block. Used by
1805 // the linear scan register allocator.
1806 intptr_t start_pos_ = -1;
1807 intptr_t end_pos_ = -1;
1808 // Immediate dominator, nullptr for graph entry.
1809 BlockEntryInstr* dominator_ = nullptr;
1810 // TODO(fschneider): Optimize the case of one child to save space.
1811 GrowableArray<BlockEntryInstr*> dominated_blocks_;
1812 Instruction* last_instruction_ = nullptr;
1813
1814 // Parallel move that will be used by linear scan register allocator to
1815 // connect live ranges at the start of the block.
1816 ParallelMoveInstr* parallel_move_ = nullptr;
1817
1818 // Closest enveloping loop in loop hierarchy (nullptr at nesting depth 0).
1819 LoopInfo* loop_info_ = nullptr;
1820
1822};
1823
1825 public:
1828 const ForwardInstructionIterator& other) = default;
1829
1830 ForwardInstructionIterator() : current_(nullptr) {}
1831
1833 : current_(block_entry) {
1834 Advance();
1835 }
1836
1837 void Advance() {
1838 ASSERT(!Done());
1839 current_ = current_->next();
1840 }
1841
1842 bool Done() const { return current_ == nullptr; }
1843
1844 // Removes 'current_' from graph and sets 'current_' to previous instruction.
1846
1847 Instruction* Current() const { return current_; }
1848
1849 Instruction* operator*() const { return Current(); }
1850
1851 bool operator==(const ForwardInstructionIterator& other) const {
1852 return current_ == other.current_;
1853 }
1854
1855 bool operator!=(const ForwardInstructionIterator& other) const {
1856 return !(*this == other);
1857 }
1858
1860 Advance();
1861 return *this;
1862 }
1863
1864 private:
1865 Instruction* current_;
1866};
1867
1872
1876
1878 public:
1880 : block_entry_(block_entry), current_(block_entry->last_instruction()) {
1881 ASSERT(block_entry_->previous() == nullptr);
1882 }
1883
1884 void Advance() {
1885 ASSERT(!Done());
1886 current_ = current_->previous();
1887 }
1888
1889 bool Done() const { return current_ == block_entry_; }
1890
1891 void RemoveCurrentFromGraph();
1892
1893 Instruction* Current() const { return current_; }
1894
1895 private:
1896 BlockEntryInstr* block_entry_;
1897 Instruction* current_;
1898};
1899
1900// Base class shared by all block entries which define initial definitions.
1901//
1902// The initial definitions define parameters, special parameters and constants.
1904 public:
1905 BlockEntryWithInitialDefs(intptr_t block_id,
1906 intptr_t try_index,
1907 intptr_t deopt_id,
1908 intptr_t stack_depth)
1909 : BlockEntryInstr(block_id, try_index, deopt_id, stack_depth) {}
1910
1912 return &initial_definitions_;
1913 }
1915 return &initial_definitions_;
1916 }
1917
1919 return this;
1920 }
1922 return this;
1923 }
1924
1927
1928 protected:
1930
1931 private:
1932 GrowableArray<Definition*> initial_definitions_;
1933
1935};
1936
1938 public:
1939 GraphEntryInstr(const ParsedFunction& parsed_function, intptr_t osr_id);
1940
1941 DECLARE_INSTRUCTION(GraphEntry)
1942
1943 virtual intptr_t PredecessorCount() const { return 0; }
1944 virtual BlockEntryInstr* PredecessorAt(intptr_t index) const {
1945 UNREACHABLE();
1946 return nullptr;
1947 }
1948 virtual intptr_t SuccessorCount() const;
1949 virtual BlockEntryInstr* SuccessorAt(intptr_t index) const;
1950
1951 void AddCatchEntry(CatchBlockEntryInstr* entry) { catch_entries_.Add(entry); }
1952
1953 CatchBlockEntryInstr* GetCatchEntry(intptr_t index);
1954
1956 indirect_entries_.Add(entry);
1957 }
1958
1959 ConstantInstr* constant_null();
1960
1961 void RelinkToOsrEntry(Zone* zone, intptr_t max_block_id);
1962 bool IsCompiledForOsr() const;
1963 intptr_t osr_id() const { return osr_id_; }
1964
1965 intptr_t entry_count() const { return entry_count_; }
1966 void set_entry_count(intptr_t count) { entry_count_ = count; }
1967
1968 intptr_t spill_slot_count() const { return spill_slot_count_; }
1970 ASSERT(count >= 0);
1971 spill_slot_count_ = count;
1972 }
1973
1974 // Returns true if this flow graph needs a stack frame.
1975 bool NeedsFrame() const { return needs_frame_; }
1976 void MarkFrameless() { needs_frame_ = false; }
1977
1978 // Number of stack slots reserved for compiling try-catch. For functions
1979 // without try-catch, this is 0. Otherwise, it is the number of local
1980 // variables.
1981 intptr_t fixed_slot_count() const { return fixed_slot_count_; }
1983 ASSERT(count >= 0);
1984 fixed_slot_count_ = count;
1985 }
1986 FunctionEntryInstr* normal_entry() const { return normal_entry_; }
1987 FunctionEntryInstr* unchecked_entry() const { return unchecked_entry_; }
1988 void set_normal_entry(FunctionEntryInstr* entry) { normal_entry_ = entry; }
1990 unchecked_entry_ = target;
1991 }
1992 OsrEntryInstr* osr_entry() const { return osr_entry_; }
1993 void set_osr_entry(OsrEntryInstr* entry) { osr_entry_ = entry; }
1994
1995 const ParsedFunction& parsed_function() const { return parsed_function_; }
1996
1998 return catch_entries_;
1999 }
2000
2002 return indirect_entries_;
2003 }
2004
2005 bool HasSingleEntryPoint() const {
2006 return catch_entries().is_empty() && unchecked_entry() == nullptr;
2007 }
2008
2012
2013 private:
2014 GraphEntryInstr(const ParsedFunction& parsed_function,
2015 intptr_t osr_id,
2016 intptr_t deopt_id);
2017
2018 virtual void ClearPredecessors() {}
2019 virtual void AddPredecessor(BlockEntryInstr* predecessor) { UNREACHABLE(); }
2020
2021 const ParsedFunction& parsed_function_;
2022 FunctionEntryInstr* normal_entry_ = nullptr;
2023 FunctionEntryInstr* unchecked_entry_ = nullptr;
2024 OsrEntryInstr* osr_entry_ = nullptr;
2026 // Indirect targets are blocks reachable only through indirect gotos.
2027 GrowableArray<IndirectEntryInstr*> indirect_entries_;
2028 const intptr_t osr_id_;
2029 intptr_t entry_count_;
2030 intptr_t spill_slot_count_;
2031 intptr_t fixed_slot_count_; // For try-catch in optimized code.
2032 bool needs_frame_ = true;
2033
2035};
2036
2038 public:
2039 JoinEntryInstr(intptr_t block_id,
2040 intptr_t try_index,
2041 intptr_t deopt_id,
2042 intptr_t stack_depth = 0)
2043 : BlockEntryInstr(block_id, try_index, deopt_id, stack_depth),
2044 phis_(nullptr),
2045 predecessors_(2) // Two is the assumed to be the common case.
2046 {}
2047
2048 DECLARE_INSTRUCTION(JoinEntry)
2049
2050 virtual intptr_t PredecessorCount() const { return predecessors_.length(); }
2051 virtual BlockEntryInstr* PredecessorAt(intptr_t index) const {
2052 return predecessors_[index];
2053 }
2054
2055 // Returns -1 if pred is not in the list.
2056 intptr_t IndexOfPredecessor(BlockEntryInstr* pred) const;
2057
2058 ZoneGrowableArray<PhiInstr*>* phis() const { return phis_; }
2059
2060 PhiInstr* InsertPhi(intptr_t var_index, intptr_t var_count);
2061 void RemoveDeadPhis(Definition* replacement);
2062
2063 void InsertPhi(PhiInstr* phi);
2064 void RemovePhi(PhiInstr* phi);
2065
2066 virtual bool HasUnknownSideEffects() const { return false; }
2067
2069
2070#define FIELD_LIST(F) F(ZoneGrowableArray<PhiInstr*>*, phis_)
2071
2073 BlockEntryInstr,
2074 FIELD_LIST)
2075#undef FIELD_LIST
2077
2078 private:
2079 // Classes that have access to predecessors_ when inlining.
2080 friend class BlockEntryInstr;
2083 friend class IndirectEntryInstr; // Access in il_printer.cc.
2084
2085 // Direct access to phis_ in order to resize it due to phi elimination.
2088
2089 virtual void ClearPredecessors() { predecessors_.Clear(); }
2090 virtual void AddPredecessor(BlockEntryInstr* predecessor);
2091
2093
2095};
2096
2097class PhiIterator : public ValueObject {
2098 public:
2099 explicit PhiIterator(JoinEntryInstr* join) : phis_(join->phis()), index_(0) {}
2100
2101 void Advance() {
2102 ASSERT(!Done());
2103 index_++;
2104 }
2105
2106 bool Done() const {
2107 return (phis_ == nullptr) || (index_ >= phis_->length());
2108 }
2109
2110 PhiInstr* Current() const { return (*phis_)[index_]; }
2111
2112 // Removes current phi from graph and sets current to previous phi.
2113 void RemoveCurrentFromGraph();
2114
2115 private:
2117 intptr_t index_;
2118};
2119
2121 public:
2122 TargetEntryInstr(intptr_t block_id,
2123 intptr_t try_index,
2124 intptr_t deopt_id,
2125 intptr_t stack_depth = 0)
2126 : BlockEntryInstr(block_id, try_index, deopt_id, stack_depth),
2127 edge_weight_(0.0) {}
2128
2129 DECLARE_INSTRUCTION(TargetEntry)
2130
2131 double edge_weight() const { return edge_weight_; }
2132 void set_edge_weight(double weight) { edge_weight_ = weight; }
2133 void adjust_edge_weight(double scale_factor) { edge_weight_ *= scale_factor; }
2134
2135 virtual intptr_t PredecessorCount() const {
2136 return (predecessor_ == nullptr) ? 0 : 1;
2137 }
2138 virtual BlockEntryInstr* PredecessorAt(intptr_t index) const {
2139 ASSERT((index == 0) && (predecessor_ != nullptr));
2140 return predecessor_;
2141 }
2142
2144
2145#define FIELD_LIST(F) F(double, edge_weight_)
2148 FIELD_LIST)
2149#undef FIELD_LIST
2150
2151 private:
2152 friend class BlockEntryInstr; // Access to predecessor_ when inlining.
2153
2154 virtual void ClearPredecessors() { predecessor_ = nullptr; }
2155 virtual void AddPredecessor(BlockEntryInstr* predecessor) {
2156 ASSERT(predecessor_ == nullptr);
2157 predecessor_ = predecessor;
2158 }
2159
2160 // Not serialized, set in DiscoverBlocks.
2161 BlockEntryInstr* predecessor_ = nullptr;
2162
2164};
2165
2166// Represents an entrypoint to a function which callers can invoke (i.e. not
2167// used for OSR entries).
2168//
2169// The flow graph builder might decide to create multiple entrypoints
2170// (e.g. checked/unchecked entrypoints) and will attach those to the
2171// [GraphEntryInstr].
2172//
2173// Every entrypoint has it's own initial definitions. The SSA renaming
2174// will insert phi's for parameter instructions if necessary.
2176 public:
2178 intptr_t block_id,
2179 intptr_t try_index,
2180 intptr_t deopt_id)
2181 : BlockEntryWithInitialDefs(block_id,
2182 try_index,
2183 deopt_id,
2184 /*stack_depth=*/0),
2185 graph_entry_(graph_entry) {}
2186
2187 DECLARE_INSTRUCTION(FunctionEntry)
2188
2189 virtual intptr_t PredecessorCount() const {
2190 return (graph_entry_ == nullptr) ? 0 : 1;
2191 }
2192 virtual BlockEntryInstr* PredecessorAt(intptr_t index) const {
2193 ASSERT(index == 0 && graph_entry_ != nullptr);
2194 return graph_entry_;
2195 }
2196
2197 GraphEntryInstr* graph_entry() const { return graph_entry_; }
2198
2201
2202 private:
2203 virtual void ClearPredecessors() { graph_entry_ = nullptr; }
2204 virtual void AddPredecessor(BlockEntryInstr* predecessor) {
2205 ASSERT(graph_entry_ == nullptr && predecessor->IsGraphEntry());
2206 graph_entry_ = predecessor->AsGraphEntry();
2207 }
2208
2209 GraphEntryInstr* graph_entry_;
2210
2212};
2213
2214// Represents entry into a function from native code.
2215//
2216// Native entries are not allowed to have regular parameters. They should use
2217// NativeParameter instead (which doesn't count as an initial definition).
2219 public:
2221 GraphEntryInstr* graph_entry,
2222 intptr_t block_id,
2223 intptr_t try_index,
2224 intptr_t deopt_id)
2225 : FunctionEntryInstr(graph_entry, block_id, try_index, deopt_id),
2226 marshaller_(marshaller) {}
2227
2229
2231
2232#define FIELD_LIST(F) F(const compiler::ffi::CallbackMarshaller&, marshaller_)
2233
2236 FIELD_LIST)
2237#undef FIELD_LIST
2238
2239 private:
2240 void SaveArguments(FlowGraphCompiler* compiler) const;
2241 void SaveArgument(FlowGraphCompiler* compiler,
2242 const compiler::ffi::NativeLocation& loc) const;
2243};
2244
2245// Represents an OSR entrypoint to a function.
2246//
2247// The OSR entry has it's own initial definitions.
2249 public:
2251 intptr_t block_id,
2252 intptr_t try_index,
2253 intptr_t deopt_id,
2254 intptr_t stack_depth)
2255 : BlockEntryWithInitialDefs(block_id, try_index, deopt_id, stack_depth),
2256 graph_entry_(graph_entry) {}
2257
2258 DECLARE_INSTRUCTION(OsrEntry)
2259
2260 virtual intptr_t PredecessorCount() const {
2261 return (graph_entry_ == nullptr) ? 0 : 1;
2262 }
2263 virtual BlockEntryInstr* PredecessorAt(intptr_t index) const {
2264 ASSERT(index == 0 && graph_entry_ != nullptr);
2265 return graph_entry_;
2266 }
2267
2268 GraphEntryInstr* graph_entry() const { return graph_entry_; }
2269
2272
2273 private:
2274 virtual void ClearPredecessors() { graph_entry_ = nullptr; }
2275 virtual void AddPredecessor(BlockEntryInstr* predecessor) {
2276 ASSERT(graph_entry_ == nullptr && predecessor->IsGraphEntry());
2277 graph_entry_ = predecessor->AsGraphEntry();
2278 }
2279
2280 GraphEntryInstr* graph_entry_;
2281
2283};
2284
2286 public:
2287 IndirectEntryInstr(intptr_t block_id,
2288 intptr_t indirect_id,
2289 intptr_t try_index,
2290 intptr_t deopt_id)
2291 : JoinEntryInstr(block_id, try_index, deopt_id),
2292 indirect_id_(indirect_id) {}
2293
2294 DECLARE_INSTRUCTION(IndirectEntry)
2295
2296 intptr_t indirect_id() const { return indirect_id_; }
2297
2299
2300#define FIELD_LIST(F) F(const intptr_t, indirect_id_)
2301
2304 FIELD_LIST)
2305#undef FIELD_LIST
2306};
2307
2309 public:
2310 CatchBlockEntryInstr(bool is_generated,
2311 intptr_t block_id,
2312 intptr_t try_index,
2313 GraphEntryInstr* graph_entry,
2314 const Array& handler_types,
2315 intptr_t catch_try_index,
2316 bool needs_stacktrace,
2317 intptr_t deopt_id,
2318 const LocalVariable* exception_var,
2319 const LocalVariable* stacktrace_var,
2320 const LocalVariable* raw_exception_var,
2321 const LocalVariable* raw_stacktrace_var)
2322 : BlockEntryWithInitialDefs(block_id,
2323 try_index,
2324 deopt_id,
2325 /*stack_depth=*/0),
2326 graph_entry_(graph_entry),
2327 predecessor_(nullptr),
2328 catch_handler_types_(Array::ZoneHandle(handler_types.ptr())),
2329 catch_try_index_(catch_try_index),
2330 exception_var_(exception_var),
2331 stacktrace_var_(stacktrace_var),
2332 raw_exception_var_(raw_exception_var),
2333 raw_stacktrace_var_(raw_stacktrace_var),
2334 needs_stacktrace_(needs_stacktrace),
2335 is_generated_(is_generated) {}
2336
2337 DECLARE_INSTRUCTION(CatchBlockEntry)
2338
2339 virtual intptr_t PredecessorCount() const {
2340 return (predecessor_ == nullptr) ? 0 : 1;
2341 }
2342 virtual BlockEntryInstr* PredecessorAt(intptr_t index) const {
2343 ASSERT((index == 0) && (predecessor_ != nullptr));
2344 return predecessor_;
2345 }
2346
2347 GraphEntryInstr* graph_entry() const { return graph_entry_; }
2348
2349 const LocalVariable* exception_var() const { return exception_var_; }
2350 const LocalVariable* stacktrace_var() const { return stacktrace_var_; }
2351
2352 const LocalVariable* raw_exception_var() const { return raw_exception_var_; }
2354 return raw_stacktrace_var_;
2355 }
2356
2357 bool needs_stacktrace() const { return needs_stacktrace_; }
2358
2359 bool is_generated() const { return is_generated_; }
2360
2361 // Returns try index for the try block to which this catch handler
2362 // corresponds.
2363 intptr_t catch_try_index() const { return catch_try_index_; }
2364
2365 const Array& catch_handler_types() const { return catch_handler_types_; }
2366
2369
2370 private:
2371 friend class BlockEntryInstr; // Access to predecessor_ when inlining.
2372
2373 virtual void ClearPredecessors() { predecessor_ = nullptr; }
2374 virtual void AddPredecessor(BlockEntryInstr* predecessor) {
2375 ASSERT(predecessor_ == nullptr);
2376 predecessor_ = predecessor;
2377 }
2378
2379 GraphEntryInstr* graph_entry_;
2380 BlockEntryInstr* predecessor_;
2381 const Array& catch_handler_types_;
2382 const intptr_t catch_try_index_;
2383 const LocalVariable* exception_var_;
2384 const LocalVariable* stacktrace_var_;
2385 const LocalVariable* raw_exception_var_;
2386 const LocalVariable* raw_stacktrace_var_;
2387 const bool needs_stacktrace_;
2388 bool is_generated_;
2389
2391};
2392
2393// If the result of the allocation is not stored into any field, passed
2394// as an argument or used in a phi then it can't alias with any other
2395// SSA value.
2397 public:
2398 // It is unknown if value has aliases.
2400
2401 // It is known that value can have aliases.
2402 static AliasIdentity Aliased() { return AliasIdentity(kAliased); }
2403
2404 // It is known that value has no aliases.
2405 static AliasIdentity NotAliased() { return AliasIdentity(kNotAliased); }
2406
2407 // It is known that value has no aliases and it was selected by
2408 // allocation sinking pass as a candidate.
2410 return AliasIdentity(kAllocationSinkingCandidate);
2411 }
2412
2413#define FOR_EACH_ALIAS_IDENTITY_VALUE(V) \
2414 V(Unknown, 0) \
2415 V(NotAliased, 1) \
2416 V(Aliased, 2) \
2417 V(AllocationSinkingCandidate, 3)
2418
2419 const char* ToCString() {
2420 switch (value_) {
2421#define VALUE_CASE(name, val) \
2422 case k##name: \
2423 return #name;
2425#undef VALUE_CASE
2426 default:
2427 UNREACHABLE();
2428 return nullptr;
2429 }
2430 }
2431
2432 bool IsUnknown() const { return value_ == kUnknown; }
2433 bool IsAliased() const { return value_ == kAliased; }
2434 bool IsNotAliased() const { return (value_ & kNotAliased) != 0; }
2436 return value_ == kAllocationSinkingCandidate;
2437 }
2438
2440 : ValueObject(), value_(other.value_) {}
2441
2443 value_ = other.value_;
2444 return *this;
2445 }
2446
2447 void Write(FlowGraphSerializer* s) const;
2449
2450 private:
2451 explicit AliasIdentity(intptr_t value) : value_(value) {}
2452
2453#define VALUE_DEFN(name, val) k##name = val,
2455#undef VALUE_DEFN
2456
2457// Undef the FOR_EACH helper macro, since the enum is private.
2458#undef FOR_EACH_ALIAS_IDENTITY_VALUE
2459
2460 COMPILE_ASSERT((kUnknown & kNotAliased) == 0);
2461 COMPILE_ASSERT((kAliased & kNotAliased) == 0);
2462 COMPILE_ASSERT((kAllocationSinkingCandidate & kNotAliased) != 0);
2463
2464 intptr_t value_;
2465};
2466
2467// Abstract super-class of all instructions that define a value (Bind, Phi).
2468class Definition : public Instruction {
2469 public:
2470 explicit Definition(intptr_t deopt_id = DeoptId::kNone)
2471 : Instruction(deopt_id) {}
2472
2474 intptr_t deopt_id = DeoptId::kNone)
2475 : Instruction(source, deopt_id) {}
2476
2477 // Overridden by definitions that have call counts.
2478 virtual intptr_t CallCount() const { return -1; }
2479
2480 intptr_t temp_index() const { return temp_index_; }
2481 void set_temp_index(intptr_t index) { temp_index_ = index; }
2482 void ClearTempIndex() { temp_index_ = -1; }
2483 bool HasTemp() const { return temp_index_ >= 0; }
2484
2485 intptr_t ssa_temp_index() const { return ssa_temp_index_; }
2486 void set_ssa_temp_index(intptr_t index) {
2487 ASSERT(index >= 0);
2488 ssa_temp_index_ = index;
2489 }
2490 bool HasSSATemp() const { return ssa_temp_index_ >= 0; }
2491 void ClearSSATempIndex() { ssa_temp_index_ = -1; }
2492
2493 intptr_t vreg(intptr_t index) const {
2494 ASSERT((index >= 0) && (index < location_count()));
2495 if (ssa_temp_index_ == -1) return -1;
2496 return ssa_temp_index_ * kMaxLocationCount + index;
2497 }
2498 intptr_t location_count() const { return LocationCount(representation()); }
2499 bool HasPairRepresentation() const { return location_count() == 2; }
2500
2501 // Compile time type of the definition, which may be requested before type
2502 // propagation during graph building.
2504 if (type_ == nullptr) {
2505 auto type = new CompileType(ComputeType());
2506 type->set_owner(this);
2507 set_type(type);
2508 }
2509 return type_;
2510 }
2511
2512 bool HasType() const { return (type_ != nullptr); }
2513
2514 inline bool IsInt64Definition();
2515
2517 return IsBinaryInt32Op() || IsBoxInt32() || IsUnboxInt32() ||
2518 IsIntConverter();
2519 }
2520
2521 // Compute compile type for this definition. It is safe to use this
2522 // approximation even before type propagator was run (e.g. during graph
2523 // building).
2524 virtual CompileType ComputeType() const {
2525 // TODO(vegorov) use range information to improve type if available.
2526 return CompileType::FromRepresentation(representation());
2527 }
2528
2529 // Update CompileType of the definition. Returns true if the type has changed.
2530 virtual bool RecomputeType() { return false; }
2531
2534
2535 bool UpdateType(CompileType new_type) {
2536 if (type_ == nullptr) {
2537 auto type = new CompileType(new_type);
2538 type->set_owner(this);
2539 set_type(type);
2540 return true;
2541 }
2542
2543 if (type_->IsNone() || !type_->IsEqualTo(&new_type)) {
2544 *type_ = new_type;
2545 return true;
2546 }
2547
2548 return false;
2549 }
2550
2551 bool HasUses() const {
2552 return (input_use_list_ != nullptr) || (env_use_list_ != nullptr);
2553 }
2554 bool HasOnlyUse(Value* use) const;
2555 bool HasOnlyInputUse(Value* use) const;
2556
2557 Value* input_use_list() const { return input_use_list_; }
2558 void set_input_use_list(Value* head) { input_use_list_ = head; }
2559
2560 Value* env_use_list() const { return env_use_list_; }
2561 void set_env_use_list(Value* head) { env_use_list_ = head; }
2562
2564 return ValueListIterable(input_use_list_);
2565 }
2566
2567 void AddInputUse(Value* value) { Value::AddToList(value, &input_use_list_); }
2568 void AddEnvUse(Value* value) { Value::AddToList(value, &env_use_list_); }
2569
2570 // Whether an instruction may create an untagged pointer to memory within
2571 // a GC-movable object. If so, then there must be no GC-triggering
2572 // instructions between the result and its uses.
2573 virtual bool MayCreateUnsafeUntaggedPointer() const {
2574 // To ensure the default is safe, conservatively assume any untagged
2575 // result may be a GC-movable address.
2576 return representation() == kUntagged;
2577 }
2578
2579 // Returns true if the definition can be replaced with a constant without
2580 // changing the behavior of the program.
2581 virtual bool CanReplaceWithConstant() const {
2582 return !MayHaveVisibleEffect() && !CanDeoptimize();
2583 }
2584
2585 virtual bool CanEliminate(const BlockEntryInstr* block) const {
2586 // Basic blocks should not end in a definition, so treat this as replacing
2587 // the definition with a constant (that is then unused).
2588 return CanReplaceWithConstant();
2589 }
2590
2591 // Replace uses of this definition with uses of other definition or value.
2592 // Precondition: use lists must be properly calculated.
2593 // Postcondition: use lists and use values are still valid.
2594 void ReplaceUsesWith(Definition* other);
2595
2596 // Replace this definition with another instruction. Use the provided result
2597 // definition to replace uses of the original definition. If replacing during
2598 // iteration, pass the iterator so that the instruction can be replaced
2599 // without affecting iteration order, otherwise pass a nullptr iterator.
2600 void ReplaceWithResult(Instruction* replacement,
2601 Definition* replacement_for_uses,
2602 ForwardInstructionIterator* iterator);
2603
2604 // Replace this definition and all uses with another definition. If
2605 // replacing during iteration, pass the iterator so that the instruction
2606 // can be replaced without affecting iteration order, otherwise pass a
2607 // nullptr iterator.
2608 void ReplaceWith(Definition* other, ForwardInstructionIterator* iterator);
2609
2610 // A value in the constant propagation lattice.
2611 // - non-constant sentinel
2612 // - a constant (any non-sentinel value)
2613 // - unknown sentinel
2614 Object& constant_value();
2615
2616 virtual void InferRange(RangeAnalysis* analysis, Range* range);
2617
2618 Range* range() const { return range_; }
2619 void set_range(const Range&);
2620
2621 // Definitions can be canonicalized only into definitions to ensure
2622 // this check statically we override base Canonicalize with a Canonicalize
2623 // returning Definition (return type is covariant).
2624 virtual Definition* Canonicalize(FlowGraph* flow_graph);
2625
2626 static constexpr intptr_t kReplacementMarker = -2;
2627
2629 if (ssa_temp_index_ == kReplacementMarker) {
2630 return reinterpret_cast<Definition*>(temp_index_);
2631 }
2632 return this;
2633 }
2634
2636 ASSERT(ssa_temp_index_ >= 0);
2637 ASSERT(WasEliminated());
2638 ssa_temp_index_ = kReplacementMarker;
2639 temp_index_ = reinterpret_cast<intptr_t>(other);
2640 }
2641
2642 virtual AliasIdentity Identity() const { return AliasIdentity::Unknown(); }
2643
2644 virtual void SetIdentity(AliasIdentity identity) { UNREACHABLE(); }
2645
2646 // Find the original definition of [this] by following through any
2647 // redefinition and check instructions.
2648 Definition* OriginalDefinition();
2649
2650 // If this definition is a redefinition (in a broad sense, this includes
2651 // CheckArrayBound and CheckNull instructions) return [Value] corresponding
2652 // to the input which is being redefined.
2653 // Otherwise return [nullptr].
2654 virtual Value* RedefinedValue() const;
2655
2656 // Find the original definition of [this].
2657 //
2658 // This is an extension of [OriginalDefinition] which also follows through any
2659 // boxing/unboxing and constraint instructions.
2660 Definition* OriginalDefinitionIgnoreBoxingAndConstraints();
2661
2662 // Helper method to determine if definition denotes an array length.
2663 static bool IsArrayLength(Definition* def);
2664
2665 virtual Definition* AsDefinition() { return this; }
2666 virtual const Definition* AsDefinition() const { return this; }
2667
2669
2670 protected:
2671 friend class RangeAnalysis;
2672 friend class Value;
2673
2674 Range* range_ = nullptr;
2675
2677 ASSERT(type->owner() == this);
2678 type_ = type;
2679 }
2680
2681#if defined(INCLUDE_IL_PRINTER)
2682 const char* TypeAsCString() const {
2683 return HasType() ? type_->ToCString() : "";
2684 }
2685#endif
2686
2687 private:
2688 intptr_t temp_index_ = -1;
2689 intptr_t ssa_temp_index_ = -1;
2690 Value* input_use_list_ = nullptr;
2691 Value* env_use_list_ = nullptr;
2692
2693 Object* constant_value_ = nullptr;
2694 CompileType* type_ = nullptr;
2695
2696 DISALLOW_COPY_AND_ASSIGN(Definition);
2697};
2698
2699// Change a value's definition after use lists have been computed.
2700inline void Value::BindTo(Definition* def) {
2701 RemoveFromUseList();
2702 set_definition(def);
2703 def->AddInputUse(this);
2704}
2705
2707 RemoveFromUseList();
2708 set_definition(def);
2709 def->AddEnvUse(this);
2710}
2711
2713 public:
2714 explicit PureDefinition(intptr_t deopt_id) : Definition(deopt_id) {}
2715 explicit PureDefinition(const InstructionSource& source, intptr_t deopt_id)
2716 : Definition(source, deopt_id) {}
2717
2718 virtual bool AllowsCSE() const { return true; }
2719 virtual bool HasUnknownSideEffects() const { return false; }
2720
2722};
2723
2724template <intptr_t N,
2725 typename ThrowsTrait,
2726 template <typename Impure, typename Pure> class CSETrait = NoCSE>
2727class TemplateDefinition : public CSETrait<Definition, PureDefinition>::Base {
2728 public:
2729 using BaseClass = typename CSETrait<Definition, PureDefinition>::Base;
2730
2731 explicit TemplateDefinition(intptr_t deopt_id = DeoptId::kNone)
2732 : BaseClass(deopt_id), inputs_() {}
2734 intptr_t deopt_id = DeoptId::kNone)
2735 : BaseClass(source, deopt_id), inputs_() {}
2736
2737 virtual intptr_t InputCount() const { return N; }
2738 virtual Value* InputAt(intptr_t i) const { return inputs_[i]; }
2739
2740 virtual bool MayThrow() const { return ThrowsTrait::kCanThrow; }
2741
2743 protected:
2745
2746 private:
2747 friend class BranchInstr;
2748 friend class IfThenElseInstr;
2749
2750 virtual void RawSetInputAt(intptr_t i, Value* value) { inputs_[i] = value; }
2751};
2752
2754 public:
2756 intptr_t deopt_id = DeoptId::kNone)
2757 : Definition(deopt_id), inputs_(std::move(inputs)) {
2758 for (intptr_t i = 0, n = inputs_.length(); i < n; ++i) {
2759 SetInputAt(i, inputs_[i]);
2760 }
2761 }
2764 intptr_t deopt_id = DeoptId::kNone)
2765 : Definition(source, deopt_id), inputs_(std::move(inputs)) {
2766 for (intptr_t i = 0, n = inputs_.length(); i < n; ++i) {
2767 SetInputAt(i, inputs_[i]);
2768 }
2769 }
2770 explicit VariadicDefinition(const intptr_t num_inputs,
2771 intptr_t deopt_id = DeoptId::kNone)
2772 : Definition(deopt_id), inputs_(num_inputs) {
2773 inputs_.EnsureLength(num_inputs, nullptr);
2774 }
2775
2776 intptr_t InputCount() const { return inputs_.length(); }
2777 Value* InputAt(intptr_t i) const { return inputs_[i]; }
2778
2780
2781 protected:
2783
2784 private:
2785 void RawSetInputAt(intptr_t i, Value* value) { inputs_[i] = value; }
2786};
2787
2789 public:
2790 PhiInstr(JoinEntryInstr* block, intptr_t num_inputs)
2791 : VariadicDefinition(num_inputs),
2792 block_(block),
2793 representation_(kTagged),
2794 is_alive_(false),
2795 is_receiver_(kUnknownReceiver) {}
2796
2797 // Get the block entry for that instruction.
2798 virtual BlockEntryInstr* GetBlock() { return block(); }
2799 JoinEntryInstr* block() const { return block_; }
2800
2801 virtual CompileType ComputeType() const;
2802 virtual bool RecomputeType();
2803
2804 virtual bool ComputeCanDeoptimize() const { return false; }
2805
2806 virtual bool HasUnknownSideEffects() const { return false; }
2807
2808 // Phi is alive if it reaches a non-environment use.
2809 bool is_alive() const { return is_alive_; }
2810 void mark_alive() { is_alive_ = true; }
2811 void mark_dead() { is_alive_ = false; }
2812
2814 return representation_;
2815 }
2816
2817 virtual Representation representation() const { return representation_; }
2818
2819 virtual bool MayCreateUnsafeUntaggedPointer() const {
2820 // Unsafe untagged pointers should never escape the basic block in which
2821 // they are defined, so they should never be the input to a Phi node.
2822 // (This is checked in the FlowGraphChecker.)
2823 return false;
2824 }
2825
2826 virtual void set_representation(Representation r) { representation_ = r; }
2827
2828 // Only Int32 phis in JIT mode are unboxed optimistically.
2829 virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const {
2830 return (CompilerState::Current().is_aot() ||
2831 (representation_ != kUnboxedInt32))
2832 ? kNotSpeculative
2833 : kGuardInputs;
2834 }
2835
2836 virtual uword Hash() const {
2837 UNREACHABLE();
2838 return 0;
2839 }
2840
2842
2843 virtual void InferRange(RangeAnalysis* analysis, Range* range);
2844
2845 BitVector* reaching_defs() const { return reaching_defs_; }
2846
2847 void set_reaching_defs(BitVector* reaching_defs) {
2848 reaching_defs_ = reaching_defs;
2849 }
2850
2851 virtual bool MayThrow() const { return false; }
2852
2853 // A phi is redundant if all input operands are the same.
2854 bool IsRedundant() const;
2855
2856 // A phi is redundant if all input operands are redefinitions of the same
2857 // value. Returns the replacement for this phi if it is redundant.
2858 // The replacement is selected among values redefined by inputs.
2859 Definition* GetReplacementForRedundantPhi() const;
2860
2861 virtual Definition* Canonicalize(FlowGraph* flow_graph);
2862
2865
2866 enum ReceiverType { kUnknownReceiver = -1, kNotReceiver = 0, kReceiver = 1 };
2867
2869 return static_cast<ReceiverType>(is_receiver_);
2870 }
2871
2872 void set_is_receiver(ReceiverType is_receiver) { is_receiver_ = is_receiver; }
2873
2874 private:
2875 // Direct access to inputs_ in order to resize it due to unreachable
2876 // predecessors.
2878
2879 JoinEntryInstr* block_;
2880 Representation representation_;
2881 BitVector* reaching_defs_ = nullptr;
2882 bool is_alive_;
2883 int8_t is_receiver_;
2884
2886};
2887
2888// This instruction represents an incoming parameter for a function entry,
2889// or incoming value for OSR entry or incoming value for a catch entry.
2890//
2891// [env_index] is a position of the parameter in the flow graph environment.
2892//
2893// [param_index] is a position of the function parameter, or
2894// kNotFunctionParameter if this instruction doesn't correspond to a real
2895// function parameter.
2896//
2897// [loc] specifies where where the incomming value is located on entry to
2898// the block. Note: for compound values (e.g. unboxed integers on 32-bit
2899// values) this will be a Pair location.
2900class ParameterInstr : public TemplateDefinition<0, NoThrow> {
2901 public:
2902 // [param_index] when ParameterInstr doesn't correspond to
2903 // a function parameter.
2904 static constexpr intptr_t kNotFunctionParameter = -1;
2905
2907 intptr_t env_index,
2908 intptr_t param_index,
2909 const Location& loc,
2910 Representation representation)
2911 : env_index_(env_index),
2912 param_index_(param_index),
2913 representation_(representation),
2914 block_(block),
2915 location_(loc) {}
2916
2917 DECLARE_INSTRUCTION(Parameter)
2918 DECLARE_ATTRIBUTES_NAMED(("index", "location"), (index(), location()))
2919
2920 // Index of the parameter in the flow graph environment.
2921 intptr_t env_index() const { return env_index_; }
2922 intptr_t index() const { return env_index(); }
2923
2924 // Index of the real function parameter
2925 // (between 0 and function.NumParameters()), or -1.
2926 intptr_t param_index() const { return param_index_; }
2927
2928 const Location& location() const { return location_; }
2929
2930 // Get the block entry for that instruction.
2931 virtual BlockEntryInstr* GetBlock() { return block_; }
2932 void set_block(BlockEntryInstr* block) { block_ = block; }
2933
2934 virtual Representation representation() const { return representation_; }
2935
2936 virtual Representation RequiredInputRepresentation(intptr_t index) const {
2937 UNREACHABLE();
2938 return kTagged;
2939 }
2940
2941 virtual bool ComputeCanDeoptimize() const { return false; }
2942
2943 virtual bool HasUnknownSideEffects() const { return false; }
2944
2945 virtual uword Hash() const {
2946 UNREACHABLE();
2947 return 0;
2948 }
2949
2950 virtual CompileType ComputeType() const;
2951
2953
2954#define FIELD_LIST(F) \
2955 F(const intptr_t, env_index_) \
2956 F(const intptr_t, param_index_) \
2957 F(const Representation, representation_)
2958
2961 FIELD_LIST)
2963#undef FIELD_LIST
2964
2965 private:
2966 BlockEntryInstr* block_ = nullptr;
2968
2970};
2971
2972// Native parameters are not treated as initial definitions because they cannot
2973// be inlined and are only usable in optimized code. The location must be a
2974// stack location relative to the position of the stack (SPREG) after
2975// register-based arguments have been saved on entry to a native call. See
2976// NativeEntryInstr::EmitNativeCode for more details.
2977//
2978// TOOD(33549): Unify with ParameterInstr.
2979class NativeParameterInstr : public TemplateDefinition<0, NoThrow> {
2980 public:
2982 intptr_t def_index)
2983 : marshaller_(marshaller), def_index_(def_index) {}
2984
2985 DECLARE_INSTRUCTION(NativeParameter)
2986
2987 virtual Representation representation() const {
2988 return marshaller_.RepInFfiCall(def_index_);
2989 }
2990
2991 virtual bool MayCreateUnsafeUntaggedPointer() const {
2992 // Untagged values flowing into Dart code via callbacks are external
2993 // pointers that are then converted into Dart objects in the IL.
2994 return false;
2995 }
2996
2997 virtual bool ComputeCanDeoptimize() const { return false; }
2998
2999 virtual bool HasUnknownSideEffects() const { return false; }
3000
3002
3003#define FIELD_LIST(F) \
3004 F(const compiler::ffi::CallbackMarshaller&, marshaller_) \
3005 F(const intptr_t, def_index_)
3006
3009 FIELD_LIST)
3010#undef FIELD_LIST
3011
3012 private:
3014};
3015
3016// Stores a tagged pointer to a slot accessible from a fixed register. It has
3017// the form:
3018//
3019// base_reg[index + #constant] = value
3020//
3021// Input 0: A tagged Smi [index]
3022// Input 1: A tagged pointer [value]
3023// offset: A signed constant offset which fits into 8 bits
3024//
3025// Currently this instruction uses pinpoints the register to be FP.
3026//
3027// This low-level instruction is non-inlinable since it makes assumptions about
3028// the frame. This is asserted via `inliner.cc::CalleeGraphValidator`.
3030 public:
3031 StoreIndexedUnsafeInstr(Value* index, Value* value, intptr_t offset)
3032 : offset_(offset) {
3033 SetInputAt(kIndexPos, index);
3034 SetInputAt(kValuePos, value);
3035 }
3036
3037 enum { kIndexPos = 0, kValuePos = 1 };
3038
3039 DECLARE_INSTRUCTION(StoreIndexedUnsafe)
3040
3041 virtual Representation RequiredInputRepresentation(intptr_t index) const {
3042 ASSERT(index == kIndexPos || index == kValuePos);
3043 return kTagged;
3044 }
3045 virtual bool ComputeCanDeoptimize() const { return false; }
3046 virtual bool HasUnknownSideEffects() const { return false; }
3047 virtual bool MayHaveVisibleEffect() const { return true; }
3048
3049 virtual bool AttributesEqual(const Instruction& other) const {
3050 return other.AsStoreIndexedUnsafe()->offset() == offset();
3051 }
3052
3053 Value* index() const { return inputs_[kIndexPos]; }
3054 Value* value() const { return inputs_[kValuePos]; }
3055 Register base_reg() const { return FPREG; }
3056 intptr_t offset() const { return offset_; }
3057
3059
3060#define FIELD_LIST(F) F(const intptr_t, offset_)
3061
3064 FIELD_LIST)
3065#undef FIELD_LIST
3066
3067 private:
3069};
3070
3071// Loads a value from slot accessable from a fixed register. It has
3072// the form:
3073//
3074// base_reg[index + #constant]
3075//
3076// Input 0: A tagged Smi [index]
3077// offset: A signed constant offset which fits into 8 bits
3078//
3079// Currently this instruction uses pinpoints the register to be FP.
3080//
3081// This lowlevel instruction is non-inlinable since it makes assumptions about
3082// the frame. This is asserted via `inliner.cc::CalleeGraphValidator`.
3083class LoadIndexedUnsafeInstr : public TemplateDefinition<1, NoThrow> {
3084 public:
3086 intptr_t offset,
3087 CompileType result_type,
3088 Representation representation = kTagged)
3089 : offset_(offset), representation_(representation) {
3090 UpdateType(result_type);
3091 SetInputAt(0, index);
3092 }
3093
3094 DECLARE_INSTRUCTION(LoadIndexedUnsafe)
3095
3096 virtual Representation RequiredInputRepresentation(intptr_t index) const {
3097 ASSERT(index == 0);
3098 return kTagged;
3099 }
3100 virtual bool ComputeCanDeoptimize() const { return false; }
3101 virtual bool HasUnknownSideEffects() const { return false; }
3102
3103 virtual bool AttributesEqual(const Instruction& other) const {
3104 return other.AsLoadIndexedUnsafe()->offset() == offset();
3105 }
3106
3107 virtual Representation representation() const { return representation_; }
3108
3109 Value* index() const { return InputAt(0); }
3110 Register base_reg() const { return FPREG; }
3111 intptr_t offset() const { return offset_; }
3112
3114
3115#define FIELD_LIST(F) \
3116 F(const intptr_t, offset_) \
3117 F(const Representation, representation_)
3118
3121 FIELD_LIST)
3122#undef FIELD_LIST
3123
3124 private:
3126};
3127
3128class MemoryCopyInstr : public TemplateInstruction<5, NoThrow> {
3129 public:
3131 classid_t src_cid,
3132 Value* dest,
3133 classid_t dest_cid,
3134 Value* src_start,
3135 Value* dest_start,
3136 Value* length,
3137 bool unboxed_inputs,
3138 bool can_overlap = true)
3139 : src_cid_(src_cid),
3140 dest_cid_(dest_cid),
3141 element_size_(Instance::ElementSizeFor(src_cid)),
3142 unboxed_inputs_(unboxed_inputs),
3143 can_overlap_(can_overlap) {
3144 ASSERT(IsArrayTypeSupported(src_cid));
3145 ASSERT(IsArrayTypeSupported(dest_cid));
3146 ASSERT_EQUAL(Instance::ElementSizeFor(src_cid),
3147 Instance::ElementSizeFor(dest_cid));
3148 SetInputAt(kSrcPos, src);
3149 SetInputAt(kDestPos, dest);
3150 SetInputAt(kSrcStartPos, src_start);
3151 SetInputAt(kDestStartPos, dest_start);
3152 SetInputAt(kLengthPos, length);
3153 }
3154
3155 enum {
3156 kSrcPos = 0,
3157 kDestPos = 1,
3158 kSrcStartPos = 2,
3159 kDestStartPos = 3,
3160 kLengthPos = 4
3162
3163 DECLARE_INSTRUCTION(MemoryCopy)
3164
3165 virtual Representation RequiredInputRepresentation(intptr_t index) const {
3166 if (index == kSrcPos || index == kDestPos) {
3167 // Can be either tagged or untagged.
3168 return kNoRepresentation;
3169 }
3170 ASSERT(index <= kLengthPos);
3171 return unboxed_inputs() ? kUnboxedIntPtr : kTagged;
3172 }
3173
3174 virtual bool ComputeCanDeoptimize() const { return false; }
3175 virtual bool HasUnknownSideEffects() const { return true; }
3176
3177 virtual bool AttributesEqual(const Instruction& other) const {
3178 if (auto* const copy = other.AsMemoryCopy()) {
3179 if (element_size_ != copy->element_size_) return false;
3180 if (unboxed_inputs_ != copy->unboxed_inputs_) return false;
3181 if (can_overlap_ != copy->can_overlap_) return false;
3182 if (src_cid_ != copy->src_cid_) return false;
3183 if (dest_cid_ != copy->dest_cid_) return false;
3184 return true;
3185 }
3186 return false;
3187 }
3188
3189 Value* src() const { return inputs_[kSrcPos]; }
3190 Value* dest() const { return inputs_[kDestPos]; }
3191 Value* src_start() const { return inputs_[kSrcStartPos]; }
3192 Value* dest_start() const { return inputs_[kDestStartPos]; }
3193 Value* length() const { return inputs_[kLengthPos]; }
3194
3195 classid_t src_cid() const { return src_cid_; }
3196 classid_t dest_cid() const { return dest_cid_; }
3197 intptr_t element_size() const { return element_size_; }
3198 bool unboxed_inputs() const { return unboxed_inputs_; }
3199 bool can_overlap() const { return can_overlap_; }
3200
3201 // Optimizes MemoryCopyInstr with constant parameters to use larger moves.
3202 virtual Instruction* Canonicalize(FlowGraph* flow_graph);
3203
3205
3207
3208#define FIELD_LIST(F) \
3209 F(const classid_t, src_cid_) \
3210 F(const classid_t, dest_cid_) \
3211 F(intptr_t, element_size_) \
3212 F(bool, unboxed_inputs_) \
3213 F(const bool, can_overlap_)
3214
3217 FIELD_LIST)
3218#undef FIELD_LIST
3219
3220 private:
3221 // Set payload_reg to point to the index indicated by start (contained in
3222 // start_loc) of the typed data or string in array (contained in array_reg).
3223 // If array_rep is tagged, then the payload address is retrieved according
3224 // to array_cid, otherwise the register is assumed to already have the
3225 // payload address.
3226 void EmitComputeStartPointer(FlowGraphCompiler* compiler,
3227 classid_t array_cid,
3228 Register array_reg,
3229 Register payload_reg,
3230 Representation array_rep,
3231 Location start_loc);
3232
3233 // Generates an unrolled loop for copying a known amount of data from
3234 // src to dest.
3235 void EmitUnrolledCopy(FlowGraphCompiler* compiler,
3236 Register dest_reg,
3237 Register src_reg,
3238 intptr_t num_elements,
3239 bool reversed);
3240
3241 // Called prior to EmitLoopCopy() to adjust the length register as needed
3242 // for the code emitted by EmitLoopCopy. May jump to done if the emitted
3243 // loop(s) should be skipped.
3245 Register length_reg,
3247
3248 // Generates a loop for copying the data from src to dest, for cases where
3249 // either the length is not known at compile time or too large to unroll.
3250 //
3251 // copy_forwards is only provided (not nullptr) when a backwards loop is
3252 // requested. May jump to copy_forwards if backwards iteration is slower than
3253 // forwards iteration and the emitted code verifies no actual overlap exists.
3254 //
3255 // May jump to done if no copying is needed.
3256 //
3257 // Assumes that PrepareLengthRegForLoop() has been called beforehand.
3259 Register dest_reg,
3260 Register src_reg,
3261 Register length_reg,
3263 compiler::Label* copy_forwards = nullptr);
3264
3265 static bool IsArrayTypeSupported(classid_t array_cid) {
3266 // We don't handle clamping negative values in this instruction, instead
3267 // those are handled via a native call.
3268 if (IsClampedTypedDataBaseClassId(array_cid)) return false;
3269 // We don't support the following cids for the given reasons:
3270 // * kStringCid: doesn't give element size information or information
3271 // about how the payload address is calculated.
3272 // * kPointerCid: doesn't give element size or signedness information.
3273 if (array_cid == kPointerCid || array_cid == kStringCid) return false;
3274 return IsTypedDataBaseClassId(array_cid) || IsStringClassId(array_cid);
3275 }
3276
3278};
3279
3280// Unwinds the current frame and tail calls a target.
3281//
3282// The return address saved by the original caller of this frame will be in it's
3283// usual location (stack or LR). The arguments descriptor supplied by the
3284// original caller will be put into ARGS_DESC_REG.
3285//
3286// This lowlevel instruction is non-inlinable since it makes assumptions about
3287// the frame. This is asserted via `inliner.cc::CalleeGraphValidator`.
3288class TailCallInstr : public TemplateInstruction<1, Throws, Pure> {
3289 public:
3290 TailCallInstr(const Code& code, Value* arg_desc) : code_(code) {
3291 SetInputAt(0, arg_desc);
3292 }
3293
3294 DECLARE_INSTRUCTION(TailCall)
3295
3296 const Code& code() const { return code_; }
3297
3298 // Two tailcalls can be canonicalized into one instruction if both have the
3299 // same destination.
3300 virtual bool AttributesEqual(const Instruction& other) const {
3301 return &other.AsTailCall()->code() == &code();
3302 }
3303
3304 // Since no code after this instruction will be executed, there will be no
3305 // side-effects for the following code.
3306 virtual bool HasUnknownSideEffects() const { return false; }
3307 virtual bool ComputeCanDeoptimize() const { return false; }
3308
3310
3311#define FIELD_LIST(F) F(const Code&, code_)
3312
3315 FIELD_LIST)
3316#undef FIELD_LIST
3317
3318 private:
3320};
3321
3322// Move the given argument value into the place where callee expects it.
3323//
3324// [location] is expected to either be an SP relative stack slot or a
3325// machine register.
3326//
3327// On 32-bit targets [location] might also be a pair of stack slots or a
3328// pair of machine registers.
3329class MoveArgumentInstr : public TemplateDefinition<1, NoThrow> {
3330 public:
3331 explicit MoveArgumentInstr(Value* value,
3332 Representation representation,
3333 Location location)
3334 : representation_(representation),
3335 is_register_move_(IsRegisterMove(location)),
3336 location_(location) {
3337 ASSERT(IsSupportedLocation(location));
3338 SetInputAt(0, value);
3339 }
3340
3341 DECLARE_INSTRUCTION(MoveArgument)
3342
3343 bool is_register_move() const { return is_register_move_; }
3344
3345 // For stack locations returns the SP relative index corresponding
3346 // to the first slot allocated for the argument.
3347 intptr_t sp_relative_index() const {
3348 ASSERT(!is_register_move());
3349 Location loc = location();
3350 if (loc.IsPairLocation()) {
3351 loc = loc.AsPairLocation()->At(0);
3352 }
3353 return loc.stack_index();
3354 }
3355
3356 Location location() const { return location_; }
3357 Location* location_slot() { return &location_; }
3358
3359 Value* value() const { return InputAt(0); }
3360
3361 virtual bool ComputeCanDeoptimize() const { return false; }
3362
3363 virtual bool HasUnknownSideEffects() const { return false; }
3364
3365 virtual TokenPosition token_pos() const {
3366 return TokenPosition::kMoveArgument;
3367 }
3368
3369 virtual Representation representation() const { return representation_; }
3370
3371 virtual Representation RequiredInputRepresentation(intptr_t index) const {
3372 ASSERT(index == 0);
3373 return representation();
3374 }
3375
3377
3378#define FIELD_LIST(F) \
3379 F(const Representation, representation_) \
3380 F(const bool, is_register_move_)
3381
3384 FIELD_LIST)
3385#undef FIELD_LIST
3386
3388
3389 private:
3390 static bool IsSupportedLocation(Location loc, bool can_be_fpu_value = true) {
3391#if defined(TARGET_ARCH_IS_32_BIT)
3392 if (loc.IsPairLocation()) {
3393 auto pair_loc = loc.AsPairLocation();
3394 return IsSupportedLocation(pair_loc->At(0), /*can_be_fpu_value=*/false) &&
3395 IsSupportedLocation(pair_loc->At(1), /*can_be_fpu_value=*/false);
3396 }
3397#endif
3398 if (loc.IsStackSlot() || (can_be_fpu_value && loc.IsDoubleStackSlot())) {
3399 return loc.base_reg() == SPREG;
3400 } else if (loc.IsRegister() || (can_be_fpu_value && loc.IsFpuRegister())) {
3401 return true;
3402 }
3403 return false;
3404 }
3405
3406 static bool IsRegisterMove(Location loc) {
3407 return loc.IsMachineRegister() ||
3408 (loc.IsPairLocation() &&
3409 loc.AsPairLocation()->At(0).IsMachineRegister());
3410 }
3411
3413
3415};
3416
3417inline Value* Instruction::ArgumentValueAt(intptr_t index) const {
3418 MoveArgumentsArray* move_arguments = GetMoveArguments();
3419 return move_arguments != nullptr ? (*move_arguments)[index]->value()
3420 : InputAt(index);
3421}
3422
3423inline Definition* Instruction::ArgumentAt(intptr_t index) const {
3424 return ArgumentValueAt(index)->definition();
3425}
3426
3428 public:
3430 intptr_t deopt_id = DeoptId::kNone)
3431 : Instruction(source, deopt_id) {}
3432
3434
3435 virtual bool ComputeCanDeoptimize() const { return false; }
3436
3437 virtual bool HasUnknownSideEffects() const { return false; }
3438
3439 virtual bool MayThrow() const { return false; }
3440
3441 virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const {
3442 return kNotSpeculative;
3443 }
3444
3446
3448
3449 private:
3451};
3452
3454 public:
3456 Value* value,
3457 intptr_t deopt_id,
3458 Representation representation = kTagged)
3459 : ReturnBaseInstr(source, deopt_id),
3460 token_pos_(source.token_pos),
3461 representation_(representation) {
3462 SetInputAt(0, value);
3463 }
3464
3465 DECLARE_INSTRUCTION(DartReturn)
3466
3467 virtual TokenPosition token_pos() const { return token_pos_; }
3468 Value* value() const { return inputs_[0]; }
3469
3470 virtual bool CanBecomeDeoptimizationTarget() const {
3471 // Return instruction might turn into a Goto instruction after inlining.
3472 // Every Goto must have an environment.
3473 return true;
3474 }
3475
3476 virtual bool AttributesEqual(const Instruction& other) const {
3477 auto const other_return = other.AsDartReturn();
3478 return token_pos() == other_return->token_pos();
3479 }
3480
3481 virtual intptr_t DeoptimizationTarget() const { return DeoptId::kNone; }
3482
3483 virtual Representation representation() const { return representation_; }
3484
3485 virtual Representation RequiredInputRepresentation(intptr_t index) const {
3486 ASSERT(index == 0);
3487 return representation_;
3488 }
3489
3490 virtual intptr_t InputCount() const { return 1; }
3491
3492 virtual Value* InputAt(intptr_t i) const { return inputs_[i]; }
3493
3494#define FIELD_LIST(F) \
3495 F(const TokenPosition, token_pos_) \
3496 F(const Representation, representation_)
3497
3500 FIELD_LIST)
3501#undef FIELD_LIST
3502
3503 protected:
3505
3506 private:
3507 const Code& GetReturnStub(FlowGraphCompiler* compiler) const;
3508
3509 virtual void RawSetInputAt(intptr_t i, Value* value) { inputs_[i] = value; }
3510
3512};
3513
3514// Represents a return from a Dart function into native code.
3516 public:
3518 const compiler::ffi::CallbackMarshaller& marshaller)
3519 : ReturnBaseInstr(), marshaller_(marshaller) {
3520 SetInputAt(0, value);
3521 inputs_[1] = nullptr;
3522 }
3523
3524 NativeReturnInstr(Value* typed_data_base,
3525 Value* offset,
3526 const compiler::ffi::CallbackMarshaller& marshaller)
3527 : ReturnBaseInstr(), marshaller_(marshaller) {
3528 SetInputAt(0, typed_data_base);
3529 SetInputAt(1, offset);
3530 }
3531
3532 DECLARE_INSTRUCTION(NativeReturn)
3533
3535
3536 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
3537 if (idx == 0) {
3538 return marshaller_.RepInFfiCall(compiler::ffi::kResultIndex);
3539 } else {
3540 ASSERT_EQUAL(idx, 1);
3541 ASSERT_EQUAL(InputCount(), 2);
3542 // Offset in bytes for compounds.
3543 return kUnboxedWord;
3544 }
3545 }
3546
3547 virtual bool CanBecomeDeoptimizationTarget() const {
3548 // Unlike DartReturnInstr, NativeReturnInstr cannot be inlined (because it's
3549 // returning into native code).
3550 return false;
3551 }
3552
3553 virtual intptr_t InputCount() const {
3554 return marshaller_.NumReturnDefinitions();
3555 }
3556
3557 virtual bool AttributesEqual(const Instruction& other) const {
3558 auto const other_return = other.AsNativeReturn();
3559 return token_pos() == other_return->token_pos();
3560 }
3561
3562 virtual Value* InputAt(intptr_t i) const { return inputs_[i]; }
3563
3564#define FIELD_LIST(F) F(const compiler::ffi::CallbackMarshaller&, marshaller_)
3565
3568 FIELD_LIST)
3569#undef FIELD_LIST
3570
3571 protected:
3573
3574 private:
3575 void EmitReturnMoves(FlowGraphCompiler* compiler);
3576
3577 virtual void RawSetInputAt(intptr_t i, Value* value) { inputs_[i] = value; }
3578
3580};
3581
3582class ThrowInstr : public TemplateInstruction<1, Throws> {
3583 public:
3585 intptr_t deopt_id,
3586 Value* exception)
3587 : TemplateInstruction(source, deopt_id), token_pos_(source.token_pos) {
3588 SetInputAt(0, exception);
3589 }
3590
3591 DECLARE_INSTRUCTION(Throw)
3592
3593 virtual TokenPosition token_pos() const { return token_pos_; }
3594 Value* exception() const { return inputs_[0]; }
3595
3596 virtual bool ComputeCanDeoptimize() const { return false; }
3597 virtual bool ComputeCanDeoptimizeAfterCall() const {
3598 return !CompilerState::Current().is_aot();
3599 }
3600
3601 virtual bool HasUnknownSideEffects() const { return false; }
3602
3603#define FIELD_LIST(F) F(const TokenPosition, token_pos_)
3604
3607 FIELD_LIST)
3608#undef FIELD_LIST
3609
3610 private:
3612};
3613
3614class ReThrowInstr : public TemplateInstruction<2, Throws> {
3615 public:
3616 // 'catch_try_index' can be kInvalidTryIndex if the
3617 // rethrow has been artificially generated by the parser.
3619 intptr_t catch_try_index,
3620 intptr_t deopt_id,
3621 Value* exception,
3622 Value* stacktrace)
3623 : TemplateInstruction(source, deopt_id),
3624 token_pos_(source.token_pos),
3625 catch_try_index_(catch_try_index) {
3626 SetInputAt(0, exception);
3627 SetInputAt(1, stacktrace);
3628 }
3629
3630 DECLARE_INSTRUCTION(ReThrow)
3631
3632 virtual TokenPosition token_pos() const { return token_pos_; }
3633 intptr_t catch_try_index() const { return catch_try_index_; }
3634 Value* exception() const { return inputs_[0]; }
3635 Value* stacktrace() const { return inputs_[1]; }
3636
3637 virtual bool ComputeCanDeoptimize() const { return false; }
3638 virtual bool ComputeCanDeoptimizeAfterCall() const {
3639 return !CompilerState::Current().is_aot();
3640 }
3641
3642 virtual bool HasUnknownSideEffects() const { return false; }
3643
3644#define FIELD_LIST(F) \
3645 F(const TokenPosition, token_pos_) \
3646 F(const intptr_t, catch_try_index_)
3647
3650 FIELD_LIST)
3651#undef FIELD_LIST
3652
3653 private:
3655};
3656
3657class StopInstr : public TemplateInstruction<0, NoThrow> {
3658 public:
3659 explicit StopInstr(const char* message) : message_(message) {
3660 ASSERT(message != nullptr);
3661 }
3662
3663 const char* message() const { return message_; }
3664
3666
3667 virtual bool ComputeCanDeoptimize() const { return false; }
3668
3669 virtual bool HasUnknownSideEffects() const { return false; }
3670
3671#define FIELD_LIST(F) F(const char*, message_)
3672
3675 FIELD_LIST)
3676#undef FIELD_LIST
3677
3678 private:
3680};
3681
3682class GotoInstr : public TemplateInstruction<0, NoThrow> {
3683 public:
3684 explicit GotoInstr(JoinEntryInstr* entry, intptr_t deopt_id)
3685 : TemplateInstruction(deopt_id),
3686 edge_weight_(0.0),
3687 parallel_move_(nullptr),
3688 successor_(entry) {}
3689
3691
3692 BlockEntryInstr* block() const { return block_; }
3693 void set_block(BlockEntryInstr* block) { block_ = block; }
3694
3695 JoinEntryInstr* successor() const { return successor_; }
3696 void set_successor(JoinEntryInstr* successor) { successor_ = successor; }
3697 virtual intptr_t SuccessorCount() const;
3698 virtual BlockEntryInstr* SuccessorAt(intptr_t index) const;
3699
3700 double edge_weight() const { return edge_weight_; }
3701 void set_edge_weight(double weight) { edge_weight_ = weight; }
3702 void adjust_edge_weight(double scale_factor) { edge_weight_ *= scale_factor; }
3703
3704 virtual bool CanBecomeDeoptimizationTarget() const {
3705 // Goto instruction can be used as a deoptimization target when LICM
3706 // hoists instructions out of the loop.
3707 return true;
3708 }
3709
3710 // May require a deoptimization target for int32 Phi input conversions.
3711 virtual intptr_t DeoptimizationTarget() const { return GetDeoptId(); }
3712
3713 virtual bool ComputeCanDeoptimize() const { return false; }
3714
3715 virtual bool HasUnknownSideEffects() const { return false; }
3716
3717 ParallelMoveInstr* parallel_move() const { return parallel_move_; }
3718
3719 bool HasParallelMove() const { return parallel_move_ != nullptr; }
3720
3722 return HasParallelMove() && !parallel_move()->IsRedundant();
3723 }
3724
3726 if (parallel_move_ == nullptr) {
3727 parallel_move_ = new ParallelMoveInstr();
3728 }
3729 return parallel_move_;
3730 }
3731
3732 virtual TokenPosition token_pos() const {
3733 return TokenPosition::kControlFlow;
3734 }
3735
3737
3738#define FIELD_LIST(F) \
3739 F(double, edge_weight_) \
3740 /* Parallel move that will be used by linear scan register allocator to */ \
3741 /* connect live ranges at the end of the block and resolve phis. */ \
3742 F(ParallelMoveInstr*, parallel_move_)
3743
3746 FIELD_LIST)
3747#undef FIELD_LIST
3749
3750 private:
3751 BlockEntryInstr* block_ = nullptr;
3752 JoinEntryInstr* successor_ = nullptr;
3753
3755};
3756
3757// IndirectGotoInstr represents a dynamically computed jump. Only
3758// IndirectEntryInstr targets are valid targets of an indirect goto. The
3759// concrete target index to jump to is given as a parameter to the indirect
3760// goto.
3761//
3762// In order to preserve split-edge form, an indirect goto does not itself point
3763// to its targets. Instead, for each possible target, the successors_ field
3764// will contain an ordinary goto instruction that jumps to the target.
3765// TODO(zerny): Implement direct support instead of embedding gotos.
3766//
3767// The input to the [IndirectGotoInstr] is the target index to jump to.
3768// All targets of the [IndirectGotoInstr] are added via [AddSuccessor] and get
3769// increasing indices.
3770//
3771// The FlowGraphCompiler will - as a post-processing step - invoke
3772// [ComputeOffsetTable] of all [IndirectGotoInstr]s. In there we initialize a
3773// TypedDataInt32Array containing offsets of all [IndirectEntryInstr]s (the
3774// offsets are relative to start of the instruction payload).
3775//
3776// => See `FlowGraphCompiler::CompileGraph()`
3777// => See `IndirectGotoInstr::ComputeOffsetTable`
3778class IndirectGotoInstr : public TemplateInstruction<1, NoThrow> {
3779 public:
3780 IndirectGotoInstr(intptr_t target_count, Value* target_index)
3781 : offsets_(TypedData::ZoneHandle(TypedData::New(kTypedDataInt32ArrayCid,
3782 target_count,
3783 Heap::kOld))) {
3784 SetInputAt(0, target_index);
3785 }
3786
3787 DECLARE_INSTRUCTION(IndirectGoto)
3788
3789 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
3790 ASSERT(idx == 0);
3791 return kTagged;
3792 }
3793
3795 ASSERT(successor->next()->IsGoto());
3796 ASSERT(successor->next()->AsGoto()->successor()->IsIndirectEntry());
3797 successors_.Add(successor);
3798 }
3799
3800 virtual intptr_t SuccessorCount() const { return successors_.length(); }
3801 virtual TargetEntryInstr* SuccessorAt(intptr_t index) const {
3802 ASSERT(index < SuccessorCount());
3803 return successors_[index];
3804 }
3805
3806 virtual bool ComputeCanDeoptimize() const { return false; }
3807 virtual bool CanBecomeDeoptimizationTarget() const { return false; }
3808
3809 virtual bool HasUnknownSideEffects() const { return false; }
3810
3811 Value* offset() const { return inputs_[0]; }
3812 void ComputeOffsetTable(FlowGraphCompiler* compiler);
3813
3815
3818
3819 private:
3821 const TypedData& offsets_;
3822
3824};
3825
3827 public:
3828 Value* left() const { return InputAt(0); }
3829 Value* right() const { return InputAt(1); }
3830
3831 virtual TokenPosition token_pos() const { return token_pos_; }
3832 Token::Kind kind() const { return kind_; }
3833 DECLARE_ATTRIBUTE(kind())
3834
3835 virtual ComparisonInstr* CopyWithNewOperands(Value* left, Value* right) = 0;
3836
3837 // Emits instructions to do the comparison and branch to the true or false
3838 // label depending on the result. This implementation will call
3839 // EmitComparisonCode and then generate the branch instructions afterwards.
3840 virtual void EmitBranchCode(FlowGraphCompiler* compiler, BranchInstr* branch);
3841
3842 // Used by EmitBranchCode and EmitNativeCode depending on whether the boolean
3843 // is to be turned into branches or instantiated. May return a valid
3844 // condition in which case the caller is expected to emit a branch to the
3845 // true label based on that condition (or a branch to the false label on the
3846 // opposite condition). May also branch directly to the labels.
3847 virtual Condition EmitComparisonCode(FlowGraphCompiler* compiler,
3848 BranchLabels labels) = 0;
3849
3850 // Emits code that generates 'true' or 'false', depending on the comparison.
3851 // This implementation will call EmitComparisonCode. If EmitComparisonCode
3852 // does not use the labels (merely returning a condition) then EmitNativeCode
3853 // may be able to use the condition to avoid a branch.
3854 virtual void EmitNativeCode(FlowGraphCompiler* compiler);
3855
3856 void SetDeoptId(const Instruction& instr) { CopyDeoptIdFrom(instr); }
3857
3858 // Operation class id is computed from collected ICData.
3859 void set_operation_cid(intptr_t value) { operation_cid_ = value; }
3860 intptr_t operation_cid() const { return operation_cid_; }
3861
3862 virtual void NegateComparison() { kind_ = Token::NegateComparison(kind_); }
3863
3864 virtual bool CanBecomeDeoptimizationTarget() const { return true; }
3865 virtual intptr_t DeoptimizationTarget() const { return GetDeoptId(); }
3866
3867 virtual bool AttributesEqual(const Instruction& other) const {
3868 auto const other_comparison = other.AsComparison();
3869 return kind() == other_comparison->kind() &&
3870 (operation_cid() == other_comparison->operation_cid());
3871 }
3872
3873 // Detects comparison with a constant and returns constant and the other
3874 // operand.
3875 bool IsComparisonWithConstant(Value** other_operand,
3876 ConstantInstr** constant_operand) {
3877 if (right()->BindsToConstant(constant_operand)) {
3878 *other_operand = left();
3879 return true;
3880 } else if (left()->BindsToConstant(constant_operand)) {
3881 *other_operand = right();
3882 return true;
3883 } else {
3884 return false;
3885 }
3886 }
3887
3889
3890#define FIELD_LIST(F) \
3891 F(const TokenPosition, token_pos_) \
3892 F(Token::Kind, kind_) \
3893 /* Set by optimizer. */ \
3894 F(intptr_t, operation_cid_)
3895
3897 Definition,
3898 FIELD_LIST)
3899#undef FIELD_LIST
3900
3901 protected:
3903 Token::Kind kind,
3904 intptr_t deopt_id = DeoptId::kNone)
3905 : Definition(source, deopt_id),
3906 token_pos_(source.token_pos),
3907 kind_(kind),
3908 operation_cid_(kIllegalCid) {}
3909
3910 private:
3912};
3913
3915 public:
3916 virtual bool AllowsCSE() const { return true; }
3917 virtual bool HasUnknownSideEffects() const { return false; }
3918
3920 protected:
3922 Token::Kind kind,
3923 intptr_t deopt_id)
3924 : ComparisonInstr(source, kind, deopt_id) {}
3925};
3926
3927template <intptr_t N,
3928 typename ThrowsTrait,
3929 template <typename Impure, typename Pure> class CSETrait = NoCSE>
3931 : public CSETrait<ComparisonInstr, PureComparison>::Base {
3932 public:
3933 using BaseClass = typename CSETrait<ComparisonInstr, PureComparison>::Base;
3934
3936 Token::Kind kind,
3937 intptr_t deopt_id = DeoptId::kNone)
3938 : BaseClass(source, kind, deopt_id), inputs_() {}
3939
3940 virtual intptr_t InputCount() const { return N; }
3941 virtual Value* InputAt(intptr_t i) const { return inputs_[i]; }
3942
3943 virtual bool MayThrow() const { return ThrowsTrait::kCanThrow; }
3944
3946
3947 protected:
3949
3950 private:
3951 virtual void RawSetInputAt(intptr_t i, Value* value) { inputs_[i] = value; }
3952};
3953
3954class BranchInstr : public Instruction {
3955 public:
3956 explicit BranchInstr(ComparisonInstr* comparison, intptr_t deopt_id)
3957 : Instruction(deopt_id), comparison_(comparison) {
3958 ASSERT(comparison->env() == nullptr);
3959 for (intptr_t i = comparison->InputCount() - 1; i >= 0; --i) {
3960 comparison->InputAt(i)->set_instruction(this);
3961 }
3962 }
3963
3964 DECLARE_INSTRUCTION(Branch)
3965
3966 virtual intptr_t ArgumentCount() const {
3967 return comparison()->ArgumentCount();
3968 }
3969 virtual void SetMoveArguments(MoveArgumentsArray* move_arguments) {
3970 comparison()->SetMoveArguments(move_arguments);
3971 }
3973 return comparison()->GetMoveArguments();
3974 }
3975
3976 intptr_t InputCount() const { return comparison()->InputCount(); }
3977
3978 Value* InputAt(intptr_t i) const { return comparison()->InputAt(i); }
3979
3980 virtual TokenPosition token_pos() const { return comparison_->token_pos(); }
3981 virtual intptr_t inlining_id() const { return comparison_->inlining_id(); }
3982 virtual void set_inlining_id(intptr_t value) {
3983 return comparison_->set_inlining_id(value);
3984 }
3985 virtual bool has_inlining_id() const {
3986 return comparison_->has_inlining_id();
3987 }
3988
3989 virtual bool ComputeCanDeoptimize() const {
3990 return comparison()->ComputeCanDeoptimize();
3991 }
3992
3993 virtual bool CanBecomeDeoptimizationTarget() const {
3994 return comparison()->CanBecomeDeoptimizationTarget();
3995 }
3996
3997 virtual bool HasUnknownSideEffects() const {
3998 return comparison()->HasUnknownSideEffects();
3999 }
4000
4001 virtual bool CanCallDart() const { return comparison()->CanCallDart(); }
4002
4003 ComparisonInstr* comparison() const { return comparison_; }
4004 void SetComparison(ComparisonInstr* comp);
4005
4006 virtual intptr_t DeoptimizationTarget() const {
4007 return comparison()->DeoptimizationTarget();
4008 }
4009
4011 return comparison()->RequiredInputRepresentation(i);
4012 }
4013
4014 virtual Instruction* Canonicalize(FlowGraph* flow_graph);
4015
4017 ASSERT(target == true_successor() || target == false_successor());
4018 constant_target_ = target;
4019 }
4020 TargetEntryInstr* constant_target() const { return constant_target_; }
4021
4022 virtual void CopyDeoptIdFrom(const Instruction& instr) {
4023 Instruction::CopyDeoptIdFrom(instr);
4024 comparison()->CopyDeoptIdFrom(instr);
4025 }
4026
4027 virtual bool MayThrow() const { return comparison()->MayThrow(); }
4028
4029 TargetEntryInstr* true_successor() const { return true_successor_; }
4030 TargetEntryInstr* false_successor() const { return false_successor_; }
4031
4032 TargetEntryInstr** true_successor_address() { return &true_successor_; }
4033 TargetEntryInstr** false_successor_address() { return &false_successor_; }
4034
4035 virtual intptr_t SuccessorCount() const;
4036 virtual BlockEntryInstr* SuccessorAt(intptr_t index) const;
4037
4039
4040#define FIELD_LIST(F) F(ComparisonInstr*, comparison_)
4041
4043#undef FIELD_LIST
4045
4046 private:
4047 virtual void RawSetInputAt(intptr_t i, Value* value) {
4048 comparison()->RawSetInputAt(i, value);
4049 }
4050
4051 TargetEntryInstr* true_successor_ = nullptr;
4052 TargetEntryInstr* false_successor_ = nullptr;
4053 TargetEntryInstr* constant_target_ = nullptr;
4054
4056};
4057
4058class DeoptimizeInstr : public TemplateInstruction<0, NoThrow, Pure> {
4059 public:
4060 DeoptimizeInstr(ICData::DeoptReasonId deopt_reason, intptr_t deopt_id)
4061 : TemplateInstruction(deopt_id), deopt_reason_(deopt_reason) {}
4062
4063 virtual bool ComputeCanDeoptimize() const { return true; }
4064
4065 virtual bool AttributesEqual(const Instruction& other) const { return true; }
4066
4067 DECLARE_INSTRUCTION(Deoptimize)
4068
4069#define FIELD_LIST(F) F(const ICData::DeoptReasonId, deopt_reason_)
4070
4073 FIELD_LIST)
4074#undef FIELD_LIST
4075
4076 private:
4078};
4079
4080class RedefinitionInstr : public TemplateDefinition<1, NoThrow> {
4081 public:
4082 explicit RedefinitionInstr(Value* value,
4083 bool inserted_by_constant_propagation = false)
4084 : constrained_type_(nullptr),
4085 inserted_by_constant_propagation_(inserted_by_constant_propagation) {
4086 SetInputAt(0, value);
4087 }
4088
4089 DECLARE_INSTRUCTION(Redefinition)
4090
4091 Value* value() const { return inputs_[0]; }
4092
4093 virtual CompileType ComputeType() const;
4094 virtual bool RecomputeType();
4095
4096 virtual Definition* Canonicalize(FlowGraph* flow_graph);
4097
4098 void set_constrained_type(CompileType* type) { constrained_type_ = type; }
4099 CompileType* constrained_type() const { return constrained_type_; }
4100
4102 return inserted_by_constant_propagation_;
4103 }
4104
4105 virtual bool ComputeCanDeoptimize() const { return false; }
4106 virtual bool HasUnknownSideEffects() const { return false; }
4107
4108 virtual Value* RedefinedValue() const;
4109
4111
4112#define FIELD_LIST(F) \
4113 F(CompileType*, constrained_type_) \
4114 F(bool, inserted_by_constant_propagation_)
4115
4118 FIELD_LIST)
4119#undef FIELD_LIST
4120
4121 private:
4123};
4124
4125// Keeps the value alive til after this point.
4126//
4127// The fence cannot be moved.
4129 public:
4130 explicit ReachabilityFenceInstr(Value* value) { SetInputAt(0, value); }
4131
4132 DECLARE_INSTRUCTION(ReachabilityFence)
4133
4134 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
4135 return kNoRepresentation;
4136 }
4137
4138 Value* value() const { return inputs_[0]; }
4139
4140 virtual bool ComputeCanDeoptimize() const { return false; }
4141 virtual bool HasUnknownSideEffects() const { return false; }
4142
4143 virtual bool CanEliminate(const BlockEntryInstr* block) const {
4144 return false;
4145 }
4146
4148
4150
4151 private:
4153};
4154
4155class ConstraintInstr : public TemplateDefinition<1, NoThrow> {
4156 public:
4157 ConstraintInstr(Value* value, Range* constraint) : constraint_(constraint) {
4158 SetInputAt(0, value);
4159 }
4160
4161 DECLARE_INSTRUCTION(Constraint)
4162
4163 virtual CompileType ComputeType() const;
4164
4165 virtual bool ComputeCanDeoptimize() const { return false; }
4166
4167 virtual bool HasUnknownSideEffects() const { return false; }
4168
4169 virtual bool AttributesEqual(const Instruction& other) const {
4170 UNREACHABLE();
4171 return false;
4172 }
4173
4174 Value* value() const { return inputs_[0]; }
4175 Range* constraint() const { return constraint_; }
4176
4177 virtual void InferRange(RangeAnalysis* analysis, Range* range);
4178
4179 // Constraints for branches have their target block stored in order
4180 // to find the comparison that generated the constraint:
4181 // target->predecessor->last_instruction->comparison.
4183 TargetEntryInstr* target() const { return target_; }
4184
4186
4187#define FIELD_LIST(F) F(Range*, constraint_)
4188
4191 FIELD_LIST)
4192#undef FIELD_LIST
4194
4195 private:
4196 TargetEntryInstr* target_ = nullptr;
4197
4199};
4200
4201class ConstantInstr : public TemplateDefinition<0, NoThrow, Pure> {
4202 public:
4203 explicit ConstantInstr(const Object& value)
4205 ConstantInstr(const Object& value, const InstructionSource& source);
4206
4207 DECLARE_INSTRUCTION(Constant)
4208 virtual CompileType ComputeType() const;
4209
4210 virtual Definition* Canonicalize(FlowGraph* flow_graph);
4211
4212 const Object& value() const { return value_; }
4213
4214 bool IsSmi() const { return compiler::target::IsSmi(value()); }
4215
4217 switch (representation()) {
4218 case kTagged:
4219 case kUnboxedUint8:
4220 case kUnboxedUint16:
4221 case kUnboxedUint32:
4222 case kUnboxedInt32:
4223 case kUnboxedInt64:
4224 return IsSmi() && compiler::target::SmiValue(value()) == 0;
4225 case kUnboxedDouble:
4226 return compiler::target::IsDouble(value()) &&
4227 bit_cast<uint64_t>(compiler::target::DoubleValue(value())) == 0;
4228 default:
4229 return false;
4230 }
4231 }
4232
4233 virtual bool ComputeCanDeoptimize() const { return false; }
4234
4235 virtual void InferRange(RangeAnalysis* analysis, Range* range);
4236
4237 virtual bool AttributesEqual(const Instruction& other) const;
4238
4239 virtual TokenPosition token_pos() const { return token_pos_; }
4240
4242 const Location& destination,
4243 Register tmp = kNoRegister,
4244 intptr_t pair_index = 0);
4245
4248
4249#define FIELD_LIST(F) \
4250 F(const Object&, value_) \
4251 F(const TokenPosition, token_pos_)
4252
4255 FIELD_LIST)
4256#undef FIELD_LIST
4257
4258 private:
4260};
4261
4262// Merged ConstantInstr -> UnboxedXXX into UnboxedConstantInstr.
4263// TODO(srdjan): Implemented currently for doubles only, should implement
4264// for other unboxing instructions.
4266 public:
4267 explicit UnboxedConstantInstr(const Object& value,
4268 Representation representation);
4269
4270 virtual Representation representation() const { return representation_; }
4271
4272 // Either nullptr or the address of the unboxed constant.
4273 uword constant_address() const { return constant_address_; }
4274
4275 DECLARE_INSTRUCTION(UnboxedConstant)
4277
4278 DECLARE_ATTRIBUTES_NAMED(("value", "representation"),
4279 (&value(), representation()))
4280
4281 private:
4282 const Representation representation_;
4283 uword
4284 constant_address_; // Either nullptr or points to the untagged constant.
4285
4287};
4288
4289// Checks that one type is a subtype of another (e.g. for type parameter bounds
4290// checking). Throws a TypeError otherwise. Both types are instantiated at
4291// runtime as necessary.
4293 public:
4294 enum {
4295 kInstantiatorTAVPos = 0,
4296 kFunctionTAVPos = 1,
4297 kSubTypePos = 2,
4298 kSuperTypePos = 3,
4299 kDstNamePos = 4,
4300 };
4301
4303 Value* instantiator_type_arguments,
4304 Value* function_type_arguments,
4305 Value* sub_type,
4306 Value* super_type,
4307 Value* dst_name,
4308 intptr_t deopt_id)
4309 : TemplateInstruction(source, deopt_id), token_pos_(source.token_pos) {
4310 SetInputAt(kInstantiatorTAVPos, instantiator_type_arguments);
4311 SetInputAt(kFunctionTAVPos, function_type_arguments);
4312 SetInputAt(kSubTypePos, sub_type);
4313 SetInputAt(kSuperTypePos, super_type);
4314 SetInputAt(kDstNamePos, dst_name);
4315 }
4316
4317 DECLARE_INSTRUCTION(AssertSubtype);
4318
4320 return inputs_[kInstantiatorTAVPos];
4321 }
4322 Value* function_type_arguments() const { return inputs_[kFunctionTAVPos]; }
4323 Value* sub_type() const { return inputs_[kSubTypePos]; }
4324 Value* super_type() const { return inputs_[kSuperTypePos]; }
4325 Value* dst_name() const { return inputs_[kDstNamePos]; }
4326
4327 virtual TokenPosition token_pos() const { return token_pos_; }
4328
4329 virtual bool ComputeCanDeoptimize() const { return false; }
4330 virtual bool ComputeCanDeoptimizeAfterCall() const {
4331 return !CompilerState::Current().is_aot();
4332 }
4333 virtual intptr_t NumberOfInputsConsumedBeforeCall() const {
4334 return InputCount();
4335 }
4336
4337 virtual bool CanBecomeDeoptimizationTarget() const { return true; }
4338
4339 virtual Instruction* Canonicalize(FlowGraph* flow_graph);
4340
4341 virtual bool AttributesEqual(const Instruction& other) const { return true; }
4342
4344
4345#define FIELD_LIST(F) F(const TokenPosition, token_pos_)
4346
4349 FIELD_LIST)
4350#undef FIELD_LIST
4351
4352 private:
4354};
4355
4356class AssertAssignableInstr : public TemplateDefinition<4, Throws, Pure> {
4357 public:
4358#define FOR_EACH_ASSERT_ASSIGNABLE_KIND(V) \
4359 V(ParameterCheck) \
4360 V(InsertedByFrontend) \
4361 V(FromSource) \
4362 V(Unknown)
4363
4364#define KIND_DEFN(name) k##name,
4366#undef KIND_DEFN
4367
4368 static const char* KindToCString(Kind kind);
4369 static bool ParseKind(const char* str, Kind* out);
4370
4371 enum {
4372 kInstancePos = 0,
4373 kDstTypePos = 1,
4374 kInstantiatorTAVPos = 2,
4375 kFunctionTAVPos = 3,
4376 kNumInputs = 4,
4377 };
4378
4380 Value* value,
4381 Value* dst_type,
4382 Value* instantiator_type_arguments,
4383 Value* function_type_arguments,
4384 const String& dst_name,
4385 intptr_t deopt_id,
4386 Kind kind = kUnknown)
4387 : TemplateDefinition(source, deopt_id),
4388 token_pos_(source.token_pos),
4389 dst_name_(dst_name),
4390 kind_(kind) {
4391 ASSERT(!dst_name.IsNull());
4392 SetInputAt(kInstancePos, value);
4393 SetInputAt(kDstTypePos, dst_type);
4394 SetInputAt(kInstantiatorTAVPos, instantiator_type_arguments);
4395 SetInputAt(kFunctionTAVPos, function_type_arguments);
4396 }
4397
4398 virtual intptr_t statistics_tag() const;
4399
4400 DECLARE_INSTRUCTION(AssertAssignable)
4401 virtual CompileType ComputeType() const;
4402 virtual bool RecomputeType();
4403
4404 Value* value() const { return inputs_[kInstancePos]; }
4405 Value* dst_type() const { return inputs_[kDstTypePos]; }
4407 return inputs_[kInstantiatorTAVPos];
4408 }
4409 Value* function_type_arguments() const { return inputs_[kFunctionTAVPos]; }
4410
4411 virtual TokenPosition token_pos() const { return token_pos_; }
4412 const String& dst_name() const { return dst_name_; }
4413
4414 virtual bool ComputeCanDeoptimize() const { return false; }
4415 virtual bool ComputeCanDeoptimizeAfterCall() const {
4416 return !CompilerState::Current().is_aot();
4417 }
4418 virtual intptr_t NumberOfInputsConsumedBeforeCall() const {
4419#if !defined(TARGET_ARCH_IA32)
4420 return InputCount();
4421#else
4422 // The ia32 implementation calls the stub by pushing the input registers
4423 // in the same order onto the stack thereby making the deopt-env correct.
4424 // (Due to lack of registers we cannot use all-argument calling convention
4425 // as in other architectures.)
4426 return 0;
4427#endif
4428 }
4429
4430 virtual bool CanBecomeDeoptimizationTarget() const {
4431 // AssertAssignable instructions that are specialized by the optimizer
4432 // (e.g. replaced with CheckClass) need a deoptimization descriptor before.
4433 return true;
4434 }
4435
4436 virtual Definition* Canonicalize(FlowGraph* flow_graph);
4437
4438 virtual bool AttributesEqual(const Instruction& other) const { return true; }
4439
4440 virtual Value* RedefinedValue() const;
4441
4442 virtual void InferRange(RangeAnalysis* analysis, Range* range);
4443
4445
4446#define FIELD_LIST(F) \
4447 F(const TokenPosition, token_pos_) \
4448 F(const String&, dst_name_) \
4449 F(const Kind, kind_)
4450
4453 FIELD_LIST)
4454#undef FIELD_LIST
4455
4456 private:
4458};
4459
4460class AssertBooleanInstr : public TemplateDefinition<1, Throws, Pure> {
4461 public:
4463 Value* value,
4464 intptr_t deopt_id)
4465 : TemplateDefinition(source, deopt_id), token_pos_(source.token_pos) {
4466 SetInputAt(0, value);
4467 }
4468
4469 DECLARE_INSTRUCTION(AssertBoolean)
4470 virtual CompileType ComputeType() const;
4471
4472 virtual TokenPosition token_pos() const { return token_pos_; }
4473 Value* value() const { return inputs_[0]; }
4474
4475 virtual bool ComputeCanDeoptimize() const { return false; }
4476 virtual bool ComputeCanDeoptimizeAfterCall() const {
4477 return !CompilerState::Current().is_aot();
4478 }
4479 virtual intptr_t NumberOfInputsConsumedBeforeCall() const {
4480 return InputCount();
4481 }
4482
4483 virtual Definition* Canonicalize(FlowGraph* flow_graph);
4484
4485 virtual bool AttributesEqual(const Instruction& other) const { return true; }
4486
4487 virtual Value* RedefinedValue() const;
4488
4490
4491#define FIELD_LIST(F) F(const TokenPosition, token_pos_)
4492
4495 FIELD_LIST)
4496#undef FIELD_LIST
4497
4498 private:
4500};
4501
4503 ArgumentsInfo(intptr_t type_args_len,
4504 intptr_t count_with_type_args,
4505 intptr_t size_with_type_args,
4506 const Array& argument_names)
4507 : type_args_len(type_args_len),
4508 count_with_type_args(count_with_type_args),
4509 size_with_type_args(size_with_type_args),
4510 count_without_type_args(count_with_type_args -
4511 (type_args_len > 0 ? 1 : 0)),
4512 size_without_type_args(size_with_type_args -
4513 (type_args_len > 0 ? 1 : 0)),
4514 argument_names(argument_names) {}
4515
4516 ArrayPtr ToArgumentsDescriptor() const {
4517 return ArgumentsDescriptor::New(type_args_len, count_without_type_args,
4518 size_without_type_args, argument_names);
4519 }
4520
4521 const intptr_t type_args_len;
4522 const intptr_t count_with_type_args;
4523 const intptr_t size_with_type_args;
4527};
4528
4529template <intptr_t kExtraInputs>
4531 public:
4532 TemplateDartCall(intptr_t deopt_id,
4533 intptr_t type_args_len,
4534 const Array& argument_names,
4535 InputsArray&& inputs,
4537 : VariadicDefinition(std::move(inputs), source, deopt_id),
4538 type_args_len_(type_args_len),
4539 argument_names_(argument_names),
4540 token_pos_(source.token_pos) {
4541 DEBUG_ASSERT(argument_names.IsNotTemporaryScopedHandle());
4542 ASSERT(InputCount() >= kExtraInputs);
4543 }
4544
4545 inline StringPtr Selector();
4546
4547 virtual bool MayThrow() const { return true; }
4548 virtual bool CanCallDart() const { return true; }
4549
4550 virtual bool ComputeCanDeoptimize() const { return false; }
4551 virtual bool ComputeCanDeoptimizeAfterCall() const {
4552 return !CompilerState::Current().is_aot();
4553 }
4554 virtual intptr_t NumberOfInputsConsumedBeforeCall() const {
4555 return kExtraInputs;
4556 }
4557
4558 intptr_t FirstArgIndex() const { return type_args_len_ > 0 ? 1 : 0; }
4559 Value* Receiver() const { return this->ArgumentValueAt(FirstArgIndex()); }
4561 return ArgumentCount() - FirstArgIndex();
4562 }
4564 return ArgumentsSize() - FirstArgIndex();
4565 }
4566 // ArgumentCount() includes the type argument vector if any.
4567 // Caution: Must override Instruction::ArgumentCount().
4568 intptr_t ArgumentCount() const {
4569 return move_arguments_ != nullptr ? move_arguments_->length()
4570 : InputCount() - kExtraInputs;
4571 }
4572 virtual intptr_t ArgumentsSize() const { return ArgumentCount(); }
4573
4574 virtual void SetMoveArguments(MoveArgumentsArray* move_arguments) {
4575 ASSERT(move_arguments_ == nullptr);
4576 move_arguments_ = move_arguments;
4577 }
4579 return move_arguments_;
4580 }
4582 MoveArgumentsArray* move_arguments) {
4583 ASSERT(move_arguments_ == nullptr);
4584 ASSERT(move_arguments->length() == ArgumentCount());
4585 SetMoveArguments(move_arguments);
4586 ASSERT(InputCount() == ArgumentCount() + kExtraInputs);
4587 const intptr_t extra_inputs_base = InputCount() - kExtraInputs;
4588 for (intptr_t i = 0, n = ArgumentCount(); i < n; ++i) {
4589 InputAt(i)->RemoveFromUseList();
4590 }
4591 for (intptr_t i = 0; i < kExtraInputs; ++i) {
4592 SetInputAt(i, InputAt(extra_inputs_base + i));
4593 }
4594 inputs_.TruncateTo(kExtraInputs);
4595 }
4596 intptr_t type_args_len() const { return type_args_len_; }
4597 const Array& argument_names() const { return argument_names_; }
4598 virtual TokenPosition token_pos() const { return token_pos_; }
4599 ArrayPtr GetArgumentsDescriptor() const {
4600 return ArgumentsDescriptor::New(
4601 type_args_len(), ArgumentCountWithoutTypeArgs(),
4602 ArgumentsSizeWithoutTypeArgs(), argument_names());
4603 }
4604
4607
4608 private:
4609 const intptr_t type_args_len_;
4610 const Array& argument_names_;
4611 const TokenPosition token_pos_;
4612 MoveArgumentsArray* move_arguments_ = nullptr;
4613
4615};
4616
4618 public:
4619 ClosureCallInstr(const Function& target_function,
4620 InputsArray&& inputs,
4621 intptr_t type_args_len,
4622 const Array& argument_names,
4624 intptr_t deopt_id)
4625 : TemplateDartCall(deopt_id,
4626 type_args_len,
4627 argument_names,
4628 std::move(inputs),
4629 source),
4630 target_function_(target_function) {
4631 DEBUG_ASSERT(target_function.IsNotTemporaryScopedHandle());
4632 }
4633
4634 DECLARE_INSTRUCTION(ClosureCall)
4635
4636 const Function& target_function() const { return target_function_; }
4637
4638 // TODO(kmillikin): implement exact call counts for closure calls.
4639 virtual intptr_t CallCount() const { return 1; }
4640
4641 virtual bool HasUnknownSideEffects() const { return true; }
4642
4644
4645#define FIELD_LIST(F) F(const Function&, target_function_)
4648 FIELD_LIST)
4649#undef FIELD_LIST
4650
4651 private:
4653};
4654
4655// Common base class for various kinds of instance call instructions
4656// (InstanceCallInstr, PolymorphicInstanceCallInstr).
4658 public:
4660 const String& function_name,
4661 Token::Kind token_kind,
4662 InputsArray&& arguments,
4663 intptr_t type_args_len,
4664 const Array& argument_names,
4665 const ICData* ic_data,
4666 intptr_t deopt_id,
4667 const Function& interface_target,
4668 const Function& tearoff_interface_target)
4669 : TemplateDartCall(deopt_id,
4670 type_args_len,
4671 argument_names,
4672 std::move(arguments),
4673 source),
4674 ic_data_(ic_data),
4675 function_name_(function_name),
4676 token_kind_(token_kind),
4677 interface_target_(interface_target),
4678 tearoff_interface_target_(tearoff_interface_target),
4679 result_type_(nullptr),
4680 has_unique_selector_(false),
4681 entry_kind_(Code::EntryKind::kNormal),
4682 receiver_is_not_smi_(false),
4683 is_call_on_this_(false) {
4684 DEBUG_ASSERT(function_name.IsNotTemporaryScopedHandle());
4685 DEBUG_ASSERT(interface_target.IsNotTemporaryScopedHandle());
4686 DEBUG_ASSERT(tearoff_interface_target.IsNotTemporaryScopedHandle());
4687 ASSERT(InputCount() > 0);
4688 ASSERT(Token::IsBinaryOperator(token_kind) ||
4689 Token::IsEqualityOperator(token_kind) ||
4690 Token::IsRelationalOperator(token_kind) ||
4691 Token::IsUnaryOperator(token_kind) ||
4692 Token::IsIndexOperator(token_kind) ||
4693 Token::IsTypeTestOperator(token_kind) ||
4694 Token::IsTypeCastOperator(token_kind) || token_kind == Token::kGET ||
4695 token_kind == Token::kSET || token_kind == Token::kILLEGAL);
4696 }
4697
4698 const ICData* ic_data() const { return ic_data_; }
4699 bool HasICData() const {
4700 return (ic_data() != nullptr) && !ic_data()->IsNull();
4701 }
4702
4703 // ICData can be replaced by optimizer.
4704 void set_ic_data(const ICData* value) { ic_data_ = value; }
4705
4706 const String& function_name() const { return function_name_; }
4707 Token::Kind token_kind() const { return token_kind_; }
4708 const Function& interface_target() const { return interface_target_; }
4710 return tearoff_interface_target_;
4711 }
4712
4713 bool has_unique_selector() const { return has_unique_selector_; }
4714 void set_has_unique_selector(bool b) { has_unique_selector_ = b; }
4715
4716 virtual CompileType ComputeType() const;
4717
4718 virtual bool CanBecomeDeoptimizationTarget() const {
4719 // Instance calls that are specialized by the optimizer need a
4720 // deoptimization descriptor before the call.
4721 return true;
4722 }
4723
4724 virtual bool HasUnknownSideEffects() const { return true; }
4725
4726 void SetResultType(Zone* zone, CompileType new_type) {
4727 result_type_ = new (zone) CompileType(new_type);
4728 }
4729
4730 CompileType* result_type() const { return result_type_; }
4731
4732 intptr_t result_cid() const {
4733 if (result_type_ == nullptr) {
4734 return kDynamicCid;
4735 }
4736 return result_type_->ToCid();
4737 }
4738
4739 FunctionPtr ResolveForReceiverClass(const Class& cls, bool allow_add = true);
4740
4741 Code::EntryKind entry_kind() const { return entry_kind_; }
4742 void set_entry_kind(Code::EntryKind value) { entry_kind_ = value; }
4743
4744 void mark_as_call_on_this() { is_call_on_this_ = true; }
4745 bool is_call_on_this() const { return is_call_on_this_; }
4746
4748
4749 bool receiver_is_not_smi() const { return receiver_is_not_smi_; }
4750 void set_receiver_is_not_smi(bool value) { receiver_is_not_smi_ = value; }
4751
4752 // Tries to prove that the receiver will not be a Smi based on the
4753 // interface target, CompileType and hints from TFA.
4754 void UpdateReceiverSminess(Zone* zone);
4755
4756 bool CanReceiverBeSmiBasedOnInterfaceTarget(Zone* zone) const;
4757
4758 virtual SpeculativeMode SpeculativeModeOfInput(intptr_t idx) const {
4759 if (type_args_len() > 0) {
4760 if (idx == 0) {
4761 return kGuardInputs;
4762 }
4763 idx--;
4764 }
4765 if (interface_target_.IsNull()) return kGuardInputs;
4766 return interface_target_.is_unboxed_parameter_at(idx) ? kNotSpeculative
4767 : kGuardInputs;
4768 }
4769
4770 virtual intptr_t ArgumentsSize() const;
4771
4772 virtual Representation RequiredInputRepresentation(intptr_t idx) const;
4773
4774 virtual intptr_t DeoptimizationTarget() const { return DeoptId::kNone; }
4775
4776 virtual Representation representation() const;
4777
4778#define FIELD_LIST(F) \
4779 F(const ICData*, ic_data_) \
4780 F(const String&, function_name_) \
4781 /* Binary op, unary op, kGET or kILLEGAL. */ \
4782 F(const Token::Kind, token_kind_) \
4783 F(const Function&, interface_target_) \
4784 F(const Function&, tearoff_interface_target_) \
4785 /* Inferred result type. */ \
4786 F(CompileType*, result_type_) \
4787 F(bool, has_unique_selector_) \
4788 F(Code::EntryKind, entry_kind_) \
4789 F(bool, receiver_is_not_smi_) \
4790 F(bool, is_call_on_this_)
4791
4794 FIELD_LIST)
4795#undef FIELD_LIST
4796
4797 protected:
4798 friend class CallSpecializer;
4799 void set_ic_data(ICData* value) { ic_data_ = value; }
4800 void set_result_type(CompileType* result_type) { result_type_ = result_type; }
4801
4802 private:
4804};
4805
4807 public:
4810 const String& function_name,
4811 Token::Kind token_kind,
4812 InputsArray&& arguments,
4813 intptr_t type_args_len,
4814 const Array& argument_names,
4815 intptr_t checked_argument_count,
4816 const ZoneGrowableArray<const ICData*>& ic_data_array,
4817 intptr_t deopt_id,
4818 const Function& interface_target = Function::null_function(),
4819 const Function& tearoff_interface_target = Function::null_function())
4821 source,
4823 token_kind,
4824 std::move(arguments),
4825 type_args_len,
4826 argument_names,
4827 GetICData(ic_data_array, deopt_id, /*is_static_call=*/false),
4828 deopt_id,
4829 interface_target,
4830 tearoff_interface_target),
4831 checked_argument_count_(checked_argument_count),
4832 receivers_static_type_(nullptr) {}
4833
4836 const String& function_name,
4837 Token::Kind token_kind,
4838 InputsArray&& arguments,
4839 intptr_t type_args_len,
4840 const Array& argument_names,
4841 intptr_t checked_argument_count,
4842 intptr_t deopt_id,
4843 const Function& interface_target = Function::null_function(),
4844 const Function& tearoff_interface_target = Function::null_function())
4847 token_kind,
4848 std::move(arguments),
4849 type_args_len,
4850 argument_names,
4851 /*ic_data=*/nullptr,
4852 deopt_id,
4853 interface_target,
4854 tearoff_interface_target),
4855 checked_argument_count_(checked_argument_count),
4856 receivers_static_type_(nullptr) {}
4857
4858 DECLARE_INSTRUCTION(InstanceCall)
4859
4860 intptr_t checked_argument_count() const { return checked_argument_count_; }
4861
4862 virtual intptr_t CallCount() const {
4863 return ic_data() == nullptr ? 0 : ic_data()->AggregateCount();
4864 }
4865
4866 void set_receivers_static_type(const AbstractType* receiver_type) {
4867 ASSERT(receiver_type != nullptr);
4868 receivers_static_type_ = receiver_type;
4869 }
4870
4871 virtual Definition* Canonicalize(FlowGraph* flow_graph);
4872
4874
4875 bool MatchesCoreName(const String& name);
4876
4877 const class BinaryFeedback& BinaryFeedback();
4878 void SetBinaryFeedback(const class BinaryFeedback* binary) {
4879 binary_ = binary;
4880 }
4881
4882 const CallTargets& Targets();
4883 void SetTargets(const CallTargets* targets) { targets_ = targets; }
4884
4885 void EnsureICData(FlowGraph* graph);
4886
4887#define FIELD_LIST(F) \
4888 F(const intptr_t, checked_argument_count_) \
4889 F(const AbstractType*, receivers_static_type_)
4890
4893 FIELD_LIST)
4894#undef FIELD_LIST
4895
4896 private:
4897 const CallTargets* targets_ = nullptr;
4898 const class BinaryFeedback* binary_ = nullptr;
4899
4901};
4902
4904 public:
4905 // Generate a replacement polymorphic call instruction.
4908 const CallTargets& targets,
4909 bool complete) {
4910 ASSERT(!call->HasMoveArguments());
4911 InputsArray args(zone, call->ArgumentCount());
4912 for (intptr_t i = 0, n = call->ArgumentCount(); i < n; ++i) {
4913 args.Add(call->ArgumentValueAt(i)->CopyWithType(zone));
4914 }
4915 auto new_call = new (zone) PolymorphicInstanceCallInstr(
4916 call->source(), call->function_name(), call->token_kind(),
4917 std::move(args), call->type_args_len(), call->argument_names(),
4918 call->ic_data(), call->deopt_id(), call->interface_target(),
4919 call->tearoff_interface_target(), targets, complete);
4920 new_call->set_result_type(call->result_type());
4921 new_call->set_entry_kind(call->entry_kind());
4922 new_call->set_has_unique_selector(call->has_unique_selector());
4923 if (call->is_call_on_this()) {
4924 new_call->mark_as_call_on_this();
4925 }
4926 return new_call;
4927 }
4928
4929 bool complete() const { return complete_; }
4930
4931 virtual CompileType ComputeType() const;
4932
4933 bool HasOnlyDispatcherOrImplicitAccessorTargets() const;
4934
4935 const CallTargets& targets() const { return targets_; }
4936 intptr_t NumberOfChecks() const { return targets_.length(); }
4937
4938 bool IsSureToCallSingleRecognizedTarget() const;
4939
4940 virtual intptr_t CallCount() const;
4941
4942 // If this polymorphic call site was created to cover the remaining cids after
4943 // inlining then we need to keep track of the total number of calls including
4944 // the ones that we inlined. This is different from the CallCount above: Eg
4945 // if there were 100 calls originally, distributed across three class-ids in
4946 // the ratio 50, 40, 7, 3. The first two were inlined, so now we have only
4947 // 10 calls in the CallCount above, but the heuristics need to know that the
4948 // last two cids cover 7% and 3% of the calls, not 70% and 30%.
4949 intptr_t total_call_count() { return total_call_count_; }
4950
4951 void set_total_call_count(intptr_t count) { total_call_count_ = count; }
4952
4953 DECLARE_INSTRUCTION(PolymorphicInstanceCall)
4954
4955 virtual Definition* Canonicalize(FlowGraph* graph);
4956
4957 static TypePtr ComputeRuntimeType(const CallTargets& targets);
4958
4960
4961#define FIELD_LIST(F) \
4962 F(const CallTargets&, targets_) \
4963 F(const bool, complete_) \
4964 F(intptr_t, total_call_count_)
4965
4968 FIELD_LIST)
4969#undef FIELD_LIST
4970
4971 private:
4973 const String& function_name,
4974 Token::Kind token_kind,
4975 InputsArray&& arguments,
4976 intptr_t type_args_len,
4977 const Array& argument_names,
4978 const ICData* ic_data,
4979 intptr_t deopt_id,
4980 const Function& interface_target,
4981 const Function& tearoff_interface_target,
4982 const CallTargets& targets,
4983 bool complete)
4986 token_kind,
4987 std::move(arguments),
4988 type_args_len,
4989 argument_names,
4990 ic_data,
4991 deopt_id,
4992 interface_target,
4993 tearoff_interface_target),
4994 targets_(targets),
4995 complete_(complete) {
4996 ASSERT(targets.length() != 0);
4997 total_call_count_ = CallCount();
4998 }
4999
5001
5003};
5004
5005// Instance call using the global dispatch table.
5006//
5007// Takes untagged ClassId of the receiver as extra input.
5009 public:
5011 const Function& interface_target,
5012 const compiler::TableSelector* selector,
5013 InputsArray&& arguments,
5014 intptr_t type_args_len,
5015 const Array& argument_names)
5017 type_args_len,
5018 argument_names,
5019 std::move(arguments),
5020 source),
5021 interface_target_(interface_target),
5022 selector_(selector) {
5023 ASSERT(selector != nullptr);
5024 DEBUG_ASSERT(interface_target_.IsNotTemporaryScopedHandle());
5025 ASSERT(InputCount() > 0);
5026 }
5027
5028 static DispatchTableCallInstr* FromCall(
5029 Zone* zone,
5030 const InstanceCallBaseInstr* call,
5031 Value* cid,
5032 const Function& interface_target,
5033 const compiler::TableSelector* selector);
5034
5035 DECLARE_INSTRUCTION(DispatchTableCall)
5036 DECLARE_ATTRIBUTE(selector_name())
5037
5038 const Function& interface_target() const { return interface_target_; }
5039 const compiler::TableSelector* selector() const { return selector_; }
5040 const char* selector_name() const {
5041 return String::Handle(interface_target().name()).ToCString();
5042 }
5043
5044 Value* class_id() const { return InputAt(InputCount() - 1); }
5045
5046 virtual CompileType ComputeType() const;
5047
5048 virtual Definition* Canonicalize(FlowGraph* flow_graph);
5049
5050 virtual bool CanBecomeDeoptimizationTarget() const { return false; }
5051
5052 virtual intptr_t DeoptimizationTarget() const { return DeoptId::kNone; }
5053
5054 virtual bool HasUnknownSideEffects() const { return true; }
5055
5056 virtual SpeculativeMode SpeculativeModeOfInput(intptr_t idx) const {
5057 if (type_args_len() > 0) {
5058 if (idx == 0) {
5059 return kGuardInputs;
5060 }
5061 idx--;
5062 }
5063 return interface_target_.is_unboxed_parameter_at(idx) ? kNotSpeculative
5064 : kGuardInputs;
5065 }
5066
5067 virtual intptr_t ArgumentsSize() const;
5068
5069 virtual Representation RequiredInputRepresentation(intptr_t idx) const;
5070
5071 virtual Representation representation() const;
5072
5074
5075#define FIELD_LIST(F) \
5076 F(const Function&, interface_target_) \
5077 F(const compiler::TableSelector*, selector_)
5078
5081 FIELD_LIST)
5082#undef FIELD_LIST
5083
5084 private:
5086};
5087
5088class StrictCompareInstr : public TemplateComparison<2, NoThrow, Pure> {
5089 public:
5091 Token::Kind kind,
5092 Value* left,
5093 Value* right,
5094 bool needs_number_check,
5095 intptr_t deopt_id);
5096
5097 DECLARE_COMPARISON_INSTRUCTION(StrictCompare)
5098
5099 virtual ComparisonInstr* CopyWithNewOperands(Value* left, Value* right);
5100
5101 virtual CompileType ComputeType() const;
5102
5103 virtual bool ComputeCanDeoptimize() const { return false; }
5104
5105 virtual Definition* Canonicalize(FlowGraph* flow_graph);
5106
5107 bool needs_number_check() const { return needs_number_check_; }
5108 void set_needs_number_check(bool value) { needs_number_check_ = value; }
5109
5110 bool AttributesEqual(const Instruction& other) const;
5111
5113
5114#define FIELD_LIST(F) \
5115 /* True if the comparison must check for double or Mint and */ \
5116 /* use value comparison instead. */ \
5117 F(bool, needs_number_check_)
5118
5121 FIELD_LIST)
5122#undef FIELD_LIST
5123
5124 private:
5125 Condition EmitComparisonCodeRegConstant(FlowGraphCompiler* compiler,
5126 BranchLabels labels,
5127 Register reg,
5128 const Object& obj);
5129 bool TryEmitBoolTest(FlowGraphCompiler* compiler,
5130 BranchLabels labels,
5131 intptr_t input_index,
5132 const Object& obj,
5133 Condition* condition_out);
5134
5136};
5137
5138// Comparison instruction that is equivalent to the (left & right) == 0
5139// comparison pattern.
5140class TestSmiInstr : public TemplateComparison<2, NoThrow, Pure> {
5141 public:
5143 Token::Kind kind,
5144 Value* left,
5145 Value* right)
5146 : TemplateComparison(source, kind) {
5147 ASSERT(kind == Token::kEQ || kind == Token::kNE);
5148 SetInputAt(0, left);
5149 SetInputAt(1, right);
5150 }
5151
5153
5154 virtual ComparisonInstr* CopyWithNewOperands(Value* left, Value* right);
5155
5156 virtual CompileType ComputeType() const;
5157
5158 virtual bool ComputeCanDeoptimize() const { return false; }
5159
5160 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
5161 return kTagged;
5162 }
5163
5165
5166 private:
5168};
5169
5170// Checks the input value cid against cids stored in a table and returns either
5171// a result or deoptimizes. If the cid is not in the list and there is a deopt
5172// id, then the instruction deoptimizes. If there is no deopt id, all the
5173// results must be the same (all true or all false) and the instruction returns
5174// the opposite for cids not on the list. The first element in the table must
5175// always be the result for the Smi class-id and is allowed to differ from the
5176// other results even in the no-deopt case.
5177class TestCidsInstr : public TemplateComparison<1, NoThrow, Pure> {
5178 public:
5180 Token::Kind kind,
5181 Value* value,
5182 const ZoneGrowableArray<intptr_t>& cid_results,
5183 intptr_t deopt_id);
5184
5186 return cid_results_;
5187 }
5188
5190
5191 virtual ComparisonInstr* CopyWithNewOperands(Value* left, Value* right);
5192
5193 virtual CompileType ComputeType() const;
5194
5195 virtual Definition* Canonicalize(FlowGraph* flow_graph);
5196
5197 virtual bool ComputeCanDeoptimize() const {
5198 return GetDeoptId() != DeoptId::kNone;
5199 }
5200
5201 Value* value() const { return inputs_[0]; }
5202 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
5203 return kTagged;
5204 }
5205
5206 virtual bool AttributesEqual(const Instruction& other) const;
5207
5209
5210#define FIELD_LIST(F) F(const ZoneGrowableArray<intptr_t>&, cid_results_)
5211
5214 FIELD_LIST)
5215#undef FIELD_LIST
5216
5217 private:
5219};
5220
5221class TestRangeInstr : public TemplateComparison<1, NoThrow, Pure> {
5222 public:
5224 Value* value,
5225 uword lower,
5226 uword upper,
5227 Representation value_representation);
5228
5230
5231 uword lower() const { return lower_; }
5232 uword upper() const { return upper_; }
5233
5234 virtual ComparisonInstr* CopyWithNewOperands(Value* left, Value* right);
5235
5236 virtual CompileType ComputeType() const;
5237
5238 virtual Definition* Canonicalize(FlowGraph* flow_graph);
5239
5240 virtual bool ComputeCanDeoptimize() const { return false; }
5241
5242 Value* value() const { return inputs_[0]; }
5243 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
5244 return value_representation_;
5245 }
5246
5247 virtual bool AttributesEqual(const Instruction& other) const;
5248
5250
5251#define FIELD_LIST(F) \
5252 F(const uword, lower_) \
5253 F(const uword, upper_) \
5254 F(const Representation, value_representation_)
5255
5258 FIELD_LIST)
5259#undef FIELD_LIST
5260
5261 private:
5263};
5264
5265class EqualityCompareInstr : public TemplateComparison<2, NoThrow, Pure> {
5266 public:
5268 Token::Kind kind,
5269 Value* left,
5270 Value* right,
5271 intptr_t cid,
5272 intptr_t deopt_id,
5273 bool null_aware = false,
5274 SpeculativeMode speculative_mode = kGuardInputs)
5275 : TemplateComparison(source, kind, deopt_id),
5276 null_aware_(null_aware),
5277 speculative_mode_(speculative_mode) {
5278 ASSERT(Token::IsEqualityOperator(kind));
5279 SetInputAt(0, left);
5280 SetInputAt(1, right);
5281 set_operation_cid(cid);
5282 }
5283
5284 DECLARE_COMPARISON_INSTRUCTION(EqualityCompare)
5285
5286 virtual ComparisonInstr* CopyWithNewOperands(Value* left, Value* right);
5287
5288 virtual CompileType ComputeType() const;
5289
5290 virtual bool ComputeCanDeoptimize() const { return false; }
5291
5292 bool is_null_aware() const { return null_aware_; }
5293 void set_null_aware(bool value) { null_aware_ = value; }
5294
5295 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
5296 ASSERT((idx == 0) || (idx == 1));
5297 if (is_null_aware()) return kTagged;
5298 if (operation_cid() == kDoubleCid) return kUnboxedDouble;
5299 if (operation_cid() == kMintCid) return kUnboxedInt64;
5300 if (operation_cid() == kIntegerCid) return kUnboxedUword;
5301 return kTagged;
5302 }
5303
5304 virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const {
5305 return speculative_mode_;
5306 }
5307
5308 virtual bool AttributesEqual(const Instruction& other) const {
5309 return ComparisonInstr::AttributesEqual(other) &&
5310 (null_aware_ == other.AsEqualityCompare()->null_aware_) &&
5311 (speculative_mode_ == other.AsEqualityCompare()->speculative_mode_);
5312 }
5313
5314 virtual Definition* Canonicalize(FlowGraph* flow_graph);
5315
5317
5318#define FIELD_LIST(F) \
5319 F(bool, null_aware_) \
5320 F(const SpeculativeMode, speculative_mode_)
5321
5324 FIELD_LIST)
5325#undef FIELD_LIST
5326
5327 private:
5329};
5330
5331class RelationalOpInstr : public TemplateComparison<2, NoThrow, Pure> {
5332 public:
5334 Token::Kind kind,
5335 Value* left,
5336 Value* right,
5337 intptr_t cid,
5338 intptr_t deopt_id,
5339 SpeculativeMode speculative_mode = kGuardInputs)
5340 : TemplateComparison(source, kind, deopt_id),
5341 speculative_mode_(speculative_mode) {
5342 ASSERT(Token::IsRelationalOperator(kind));
5343 SetInputAt(0, left);
5344 SetInputAt(1, right);
5345 set_operation_cid(cid);
5346 }
5347
5348 DECLARE_COMPARISON_INSTRUCTION(RelationalOp)
5349
5350 virtual ComparisonInstr* CopyWithNewOperands(Value* left, Value* right);
5351
5352 virtual CompileType ComputeType() const;
5353
5354 virtual bool ComputeCanDeoptimize() const { return false; }
5355
5356 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
5357 ASSERT((idx == 0) || (idx == 1));
5358 if (operation_cid() == kDoubleCid) return kUnboxedDouble;
5359 if (operation_cid() == kMintCid) return kUnboxedInt64;
5360 return kTagged;
5361 }
5362
5363 virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const {
5364 return speculative_mode_;
5365 }
5366
5367 virtual bool AttributesEqual(const Instruction& other) const {
5368 return ComparisonInstr::AttributesEqual(other) &&
5369 (speculative_mode_ == other.AsRelationalOp()->speculative_mode_);
5370 }
5371
5373
5374#define FIELD_LIST(F) F(const SpeculativeMode, speculative_mode_)
5375
5378 FIELD_LIST)
5379#undef FIELD_LIST
5380
5381 private:
5383};
5384
5385// TODO(vegorov): ComparisonInstr should be switched to use IfTheElseInstr for
5386// materialization of true and false constants.
5388 public:
5390 Value* if_true,
5391 Value* if_false,
5392 intptr_t deopt_id)
5393 : Definition(deopt_id),
5394 comparison_(comparison),
5395 if_true_(Smi::Cast(if_true->BoundConstant()).Value()),
5396 if_false_(Smi::Cast(if_false->BoundConstant()).Value()) {
5397 // Adjust uses at the comparison.
5398 ASSERT(comparison->env() == nullptr);
5399 for (intptr_t i = comparison->InputCount() - 1; i >= 0; --i) {
5400 comparison->InputAt(i)->set_instruction(this);
5401 }
5402 }
5403
5404 // Returns true if this combination of comparison and values flowing on
5405 // the true and false paths is supported on the current platform.
5406 static bool Supports(ComparisonInstr* comparison, Value* v1, Value* v2);
5407
5408 DECLARE_INSTRUCTION(IfThenElse)
5409
5410 intptr_t InputCount() const { return comparison()->InputCount(); }
5411
5412 Value* InputAt(intptr_t i) const { return comparison()->InputAt(i); }
5413
5414 virtual bool ComputeCanDeoptimize() const {
5415 return comparison()->ComputeCanDeoptimize();
5416 }
5417
5418 virtual bool CanBecomeDeoptimizationTarget() const {
5419 return comparison()->CanBecomeDeoptimizationTarget();
5420 }
5421
5422 virtual intptr_t DeoptimizationTarget() const {
5423 return comparison()->DeoptimizationTarget();
5424 }
5425
5427 return comparison()->RequiredInputRepresentation(i);
5428 }
5429
5430 virtual CompileType ComputeType() const;
5431
5432 virtual void InferRange(RangeAnalysis* analysis, Range* range);
5433
5434 ComparisonInstr* comparison() const { return comparison_; }
5435 intptr_t if_true() const { return if_true_; }
5436 intptr_t if_false() const { return if_false_; }
5437
5438 virtual bool AllowsCSE() const { return comparison()->AllowsCSE(); }
5439 virtual bool HasUnknownSideEffects() const {
5440 return comparison()->HasUnknownSideEffects();
5441 }
5442 virtual bool CanCallDart() const { return comparison()->CanCallDart(); }
5443
5444 virtual bool AttributesEqual(const Instruction& other) const {
5445 auto const other_if_then_else = other.AsIfThenElse();
5446 return (comparison()->tag() == other_if_then_else->comparison()->tag()) &&
5447 comparison()->AttributesEqual(*other_if_then_else->comparison()) &&
5448 (if_true_ == other_if_then_else->if_true_) &&
5449 (if_false_ == other_if_then_else->if_false_);
5450 }
5451
5452 virtual bool MayThrow() const { return comparison()->MayThrow(); }
5453
5454 virtual void CopyDeoptIdFrom(const Instruction& instr) {
5455 Definition::CopyDeoptIdFrom(instr);
5456 comparison()->CopyDeoptIdFrom(instr);
5457 }
5458
5460
5461#define FIELD_LIST(F) \
5462 F(ComparisonInstr*, comparison_) \
5463 F(const intptr_t, if_true_) \
5464 F(const intptr_t, if_false_)
5465
5467 Definition,
5468 FIELD_LIST)
5469#undef FIELD_LIST
5471
5472 private:
5473 virtual void RawSetInputAt(intptr_t i, Value* value) {
5474 comparison()->RawSetInputAt(i, value);
5475 }
5476
5478};
5479
5481 public:
5483 const Function& function,
5484 intptr_t type_args_len,
5485 const Array& argument_names,
5486 InputsArray&& arguments,
5487 const ZoneGrowableArray<const ICData*>& ic_data_array,
5488 intptr_t deopt_id,
5489 ICData::RebindRule rebind_rule)
5490 : TemplateDartCall(deopt_id,
5491 type_args_len,
5492 argument_names,
5493 std::move(arguments),
5494 source),
5495 ic_data_(GetICData(ic_data_array, deopt_id, /*is_static_call=*/true)),
5496 call_count_(0),
5497 function_(function),
5498 rebind_rule_(rebind_rule),
5499 result_type_(nullptr),
5500 is_known_list_constructor_(false),
5501 entry_kind_(Code::EntryKind::kNormal),
5502 identity_(AliasIdentity::Unknown()) {
5503 DEBUG_ASSERT(function.IsNotTemporaryScopedHandle());
5504 ASSERT(!function.IsNull());
5505 }
5506
5508 const Function& function,
5509 intptr_t type_args_len,
5510 const Array& argument_names,
5511 InputsArray&& arguments,
5512 intptr_t deopt_id,
5513 intptr_t call_count,
5514 ICData::RebindRule rebind_rule)
5515 : TemplateDartCall(deopt_id,
5516 type_args_len,
5517 argument_names,
5518 std::move(arguments),
5519 source),
5520 ic_data_(nullptr),
5521 call_count_(call_count),
5522 function_(function),
5523 rebind_rule_(rebind_rule),
5524 result_type_(nullptr),
5525 is_known_list_constructor_(false),
5526 entry_kind_(Code::EntryKind::kNormal),
5527 identity_(AliasIdentity::Unknown()) {
5528 DEBUG_ASSERT(function.IsNotTemporaryScopedHandle());
5529 ASSERT(!function.IsNull());
5530 }
5531
5532 // Generate a replacement call instruction for an instance call which
5533 // has been found to have only one target.
5534 template <class C>
5536 const C* call,
5537 const Function& target,
5538 intptr_t call_count) {
5539 ASSERT(!call->HasMoveArguments());
5540 InputsArray args(zone, call->ArgumentCount());
5541 for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
5542 args.Add(call->ArgumentValueAt(i)->CopyWithType());
5543 }
5544 StaticCallInstr* new_call = new (zone) StaticCallInstr(
5545 call->source(), target, call->type_args_len(), call->argument_names(),
5546 std::move(args), call->deopt_id(), call_count, ICData::kNoRebind);
5547 if (call->result_type() != nullptr) {
5548 new_call->result_type_ = call->result_type();
5549 }
5550 new_call->set_entry_kind(call->entry_kind());
5551 return new_call;
5552 }
5553
5554 // ICData for static calls carries call count.
5555 const ICData* ic_data() const { return ic_data_; }
5556 bool HasICData() const {
5557 return (ic_data() != nullptr) && !ic_data()->IsNull();
5558 }
5559
5560 void set_ic_data(const ICData* value) { ic_data_ = value; }
5561
5562 DECLARE_INSTRUCTION(StaticCall)
5564
5565 virtual CompileType ComputeType() const;
5566 virtual Definition* Canonicalize(FlowGraph* flow_graph);
5567 bool Evaluate(FlowGraph* flow_graph, const Object& argument, Object* result);
5568 bool Evaluate(FlowGraph* flow_graph,
5569 const Object& argument1,
5570 const Object& argument2,
5571 Object* result);
5572
5573 // Accessors forwarded to the AST node.
5574 const Function& function() const { return function_; }
5575
5576 virtual intptr_t CallCount() const {
5577 return ic_data() == nullptr ? call_count_ : ic_data()->AggregateCount();
5578 }
5579
5580 virtual bool ComputeCanDeoptimize() const { return false; }
5581 virtual bool ComputeCanDeoptimizeAfterCall() const {
5582 return !CompilerState::Current().is_aot();
5583 }
5584
5585 virtual bool CanBecomeDeoptimizationTarget() const {
5586 // Static calls that are specialized by the optimizer (e.g. sqrt) need a
5587 // deoptimization descriptor before the call.
5588 return true;
5589 }
5590
5591 virtual bool HasUnknownSideEffects() const { return true; }
5592 virtual bool CanCallDart() const { return true; }
5593
5594 // Initialize result type of this call instruction if target is a recognized
5595 // method or has pragma annotation.
5596 // Returns true on success, false if result type is still unknown.
5597 bool InitResultType(Zone* zone);
5598
5599 void SetResultType(Zone* zone, CompileType new_type) {
5600 result_type_ = new (zone) CompileType(new_type);
5601 }
5602
5603 CompileType* result_type() const { return result_type_; }
5604
5605 intptr_t result_cid() const {
5606 if (result_type_ == nullptr) {
5607 return kDynamicCid;
5608 }
5609 return result_type_->ToCid();
5610 }
5611
5612 bool is_known_list_constructor() const { return is_known_list_constructor_; }
5614 is_known_list_constructor_ = value;
5615 }
5616
5617 Code::EntryKind entry_kind() const { return entry_kind_; }
5618
5619 void set_entry_kind(Code::EntryKind value) { entry_kind_ = value; }
5620
5621 bool IsRecognizedFactory() const { return is_known_list_constructor(); }
5622
5623 virtual SpeculativeMode SpeculativeModeOfInput(intptr_t idx) const {
5624 if (type_args_len() > 0 || function().IsFactory()) {
5625 if (idx == 0) {
5626 return kGuardInputs;
5627 }
5628 idx--;
5629 }
5630 return function_.is_unboxed_parameter_at(idx) ? kNotSpeculative
5631 : kGuardInputs;
5632 }
5633
5634 virtual intptr_t ArgumentsSize() const;
5635
5636 virtual Representation RequiredInputRepresentation(intptr_t idx) const;
5637
5638 virtual intptr_t DeoptimizationTarget() const { return DeoptId::kNone; }
5639
5640 virtual Representation representation() const;
5641
5642 virtual AliasIdentity Identity() const { return identity_; }
5643 virtual void SetIdentity(AliasIdentity identity) { identity_ = identity; }
5644
5645 const CallTargets& Targets();
5646 const class BinaryFeedback& BinaryFeedback();
5647
5649
5650#define FIELD_LIST(F) \
5651 F(const ICData*, ic_data_) \
5652 F(const intptr_t, call_count_) \
5653 F(const Function&, function_) \
5654 F(const ICData::RebindRule, rebind_rule_) \
5655 /* Known or inferred result type. */ \
5656 F(CompileType*, result_type_) \
5657 /* 'True' for recognized list constructors. */ \
5658 F(bool, is_known_list_constructor_) \
5659 F(Code::EntryKind, entry_kind_) \
5660 F(AliasIdentity, identity_)
5661
5664 FIELD_LIST)
5665#undef FIELD_LIST
5666
5667 private:
5668 const CallTargets* targets_ = nullptr;
5669 const class BinaryFeedback* binary_ = nullptr;
5670
5672};
5673
5674// A call to a function which has no side effects and of which the result can
5675// be cached.
5676//
5677// The arguments flowing into this call must be const.
5678//
5679// The result is cached in the pool. Hence this instruction is not supported
5680// on IA32.
5682 public:
5683 // Instead of inputs to this IL instruction we should pass a
5684 // `GrowableArray<const Object&>` and only push & pop them in the slow path.
5685 // (Right now the inputs are eagerly pushed and therefore have to be also
5686 // poped on the fast path.)
5688 Representation representation,
5689 const Function& function,
5690 intptr_t type_args_len,
5691 const Array& argument_names,
5692 InputsArray&& arguments,
5693 intptr_t deopt_id);
5694
5695 DECLARE_INSTRUCTION(CachableIdempotentCall)
5696
5697 const Function& function() const { return function_; }
5698
5699 virtual Definition* Canonicalize(FlowGraph* flow_graph);
5700
5701 virtual bool MayCreateUnsafeUntaggedPointer() const {
5702 // Either this is a pragma-annotated function, in which case the result
5703 // is not an untagged address, or it's a call to the FFI resolver, in
5704 // which case the returned value is not GC-movable.
5705 return false;
5706 }
5707
5708 virtual bool ComputeCanDeoptimize() const { return false; }
5709
5710 virtual bool ComputeCanDeoptimizeAfterCall() const { return false; }
5711
5712 virtual bool CanBecomeDeoptimizationTarget() const { return false; }
5713
5714 virtual bool HasUnknownSideEffects() const { return true; }
5715
5716 virtual bool CanCallDart() const { return true; }
5717
5718 virtual SpeculativeMode SpeculativeModeOfInput(intptr_t idx) const {
5719 if (type_args_len() > 0) {
5720 if (idx == 0) {
5721 return kGuardInputs;
5722 }
5723 idx--;
5724 }
5725 return function_.is_unboxed_parameter_at(idx) ? kNotSpeculative
5726 : kGuardInputs;
5727 }
5728
5729 virtual intptr_t ArgumentsSize() const;
5730
5731 virtual Representation RequiredInputRepresentation(intptr_t idx) const;
5732
5733 virtual Representation representation() const { return representation_; }
5734
5735 virtual AliasIdentity Identity() const { return identity_; }
5736 virtual void SetIdentity(AliasIdentity identity) { identity_ = identity; }
5737
5739
5740#define FIELD_LIST(F) \
5741 F(const Representation, representation_) \
5742 F(const Function&, function_) \
5743 F(AliasIdentity, identity_)
5744
5747 FIELD_LIST)
5748#undef FIELD_LIST
5749
5750 private:
5752};
5753
5754class LoadLocalInstr : public TemplateDefinition<0, NoThrow> {
5755 public:
5758 local_(local),
5759 is_last_(false),
5760 token_pos_(source.token_pos) {}
5761
5762 DECLARE_INSTRUCTION(LoadLocal)
5763 virtual CompileType ComputeType() const;
5764
5765 const LocalVariable& local() const { return local_; }
5766
5767 virtual bool ComputeCanDeoptimize() const { return false; }
5768
5769 virtual bool HasUnknownSideEffects() const {
5770 UNREACHABLE(); // Eliminated by SSA construction.
5771 return false;
5772 }
5773
5774 void mark_last() { is_last_ = true; }
5775 bool is_last() const { return is_last_; }
5776
5777 virtual TokenPosition token_pos() const { return token_pos_; }
5778
5780
5781#define FIELD_LIST(F) \
5782 F(const LocalVariable&, local_) \
5783 F(bool, is_last_) \
5784 F(const TokenPosition, token_pos_)
5785
5788 FIELD_LIST)
5789#undef FIELD_LIST
5790
5791 private:
5793};
5794
5796 public:
5797 DropTempsInstr(intptr_t num_temps, Value* value)
5798 : num_temps_(num_temps), has_input_(value != nullptr) {
5799 if (has_input_) {
5800 SetInputAt(0, value);
5801 }
5802 }
5803
5804 DECLARE_INSTRUCTION(DropTemps)
5805
5806 virtual intptr_t InputCount() const { return has_input_ ? 1 : 0; }
5807 virtual Value* InputAt(intptr_t i) const {
5808 ASSERT(has_input_ && (i == 0));
5809 return value_;
5810 }
5811
5812 Value* value() const { return value_; }
5813
5814 intptr_t num_temps() const { return num_temps_; }
5815
5816 virtual CompileType ComputeType() const;
5817
5818 virtual bool ComputeCanDeoptimize() const { return false; }
5819
5820 virtual bool HasUnknownSideEffects() const {
5821 UNREACHABLE(); // Eliminated by SSA construction.
5822 return false;
5823 }
5824
5825 virtual bool MayThrow() const { return false; }
5826
5827 virtual TokenPosition token_pos() const { return TokenPosition::kTempMove; }
5828
5830
5831#define FIELD_LIST(F) \
5832 F(const intptr_t, num_temps_) \
5833 F(const bool, has_input_)
5834
5836 Definition,
5837 FIELD_LIST)
5838#undef FIELD_LIST
5839
5840 private:
5841 virtual void RawSetInputAt(intptr_t i, Value* value) {
5842 ASSERT(has_input_);
5843 value_ = value;
5844 }
5845
5846 Value* value_ = nullptr;
5847
5849};
5850
5851// This instruction is used to reserve a space on the expression stack
5852// that later would be filled with StoreLocal. Reserved space would be
5853// filled with a null value initially.
5854//
5855// Note: One must not use Constant(#null) to reserve expression stack space
5856// because it would lead to an incorrectly compiled unoptimized code. Graph
5857// builder would set Constant(#null) as an input definition to the instruction
5858// that consumes this value from the expression stack - not knowing that
5859// this value represents a placeholder - which might lead issues if instruction
5860// has specialization for constant inputs (see https://dartbug.com/33195).
5861class MakeTempInstr : public TemplateDefinition<0, NoThrow, Pure> {
5862 public:
5863 explicit MakeTempInstr(Zone* zone)
5864 : null_(new(zone) ConstantInstr(Object::ZoneHandle())) {
5865 // Note: We put ConstantInstr inside MakeTemp to simplify code generation:
5866 // having ConstantInstr allows us to use Location::Constant(null_) as an
5867 // output location for this instruction.
5868 }
5869
5870 DECLARE_INSTRUCTION(MakeTemp)
5871
5872 virtual bool ComputeCanDeoptimize() const { return false; }
5873
5874 virtual bool HasUnknownSideEffects() const {
5875 UNREACHABLE(); // Eliminated by SSA construction.
5876 return false;
5877 }
5878
5879 virtual bool MayThrow() const { return false; }
5880
5881 virtual TokenPosition token_pos() const { return TokenPosition::kTempMove; }
5882
5884
5885#define FIELD_LIST(F) F(ConstantInstr*, null_)
5886
5889 FIELD_LIST)
5890#undef FIELD_LIST
5892
5893 private:
5895};
5896
5897class StoreLocalInstr : public TemplateDefinition<1, NoThrow> {
5898 public:
5900 Value* value,
5903 local_(local),
5904 is_dead_(false),
5905 is_last_(false),
5906 token_pos_(source.token_pos) {
5907 SetInputAt(0, value);
5908 }
5909
5910 DECLARE_INSTRUCTION(StoreLocal)
5911 virtual CompileType ComputeType() const;
5912
5913 const LocalVariable& local() const { return local_; }
5914 Value* value() const { return inputs_[0]; }
5915
5916 virtual bool ComputeCanDeoptimize() const { return false; }
5917
5918 void mark_dead() { is_dead_ = true; }
5919 bool is_dead() const { return is_dead_; }
5920
5921 void mark_last() { is_last_ = true; }
5922 bool is_last() const { return is_last_; }
5923
5924 virtual bool HasUnknownSideEffects() const {
5925 UNREACHABLE(); // Eliminated by SSA construction.
5926 return false;
5927 }
5928
5929 virtual TokenPosition token_pos() const { return token_pos_; }
5930
5932
5933#define FIELD_LIST(F) \
5934 F(const LocalVariable&, local_) \
5935 F(bool, is_dead_) \
5936 F(bool, is_last_) \
5937 F(const TokenPosition, token_pos_)
5938
5941 FIELD_LIST)
5942#undef FIELD_LIST
5943
5944 private:
5946};
5947
5949 public:
5951 const Function& function,
5952 bool link_lazily,
5954 InputsArray&& args)
5956 0,
5957 Array::null_array(),
5958 std::move(args),
5959 source),
5960 native_name_(name),
5961 function_(function),
5962 token_pos_(source.token_pos),
5963 link_lazily_(link_lazily) {
5964 DEBUG_ASSERT(name.IsNotTemporaryScopedHandle());
5965 DEBUG_ASSERT(function.IsNotTemporaryScopedHandle());
5966 // +1 for return value placeholder.
5967 ASSERT(ArgumentCount() ==
5968 function.NumParameters() + (function.IsGeneric() ? 1 : 0) + 1);
5969 }
5970
5971 DECLARE_INSTRUCTION(NativeCall)
5972
5973 const String& native_name() const { return native_name_; }
5974 const Function& function() const { return function_; }
5975 NativeFunction native_c_function() const { return native_c_function_; }
5976 bool is_bootstrap_native() const { return is_bootstrap_native_; }
5977 bool is_auto_scope() const { return is_auto_scope_; }
5978 bool link_lazily() const { return link_lazily_; }
5979 virtual TokenPosition token_pos() const { return token_pos_; }
5980
5981 virtual bool ComputeCanDeoptimize() const { return false; }
5982
5983 virtual bool HasUnknownSideEffects() const { return true; }
5984
5985 // Always creates an exit frame before more Dart code can be called.
5986 virtual bool CanCallDart() const { return false; }
5987
5988 void SetupNative();
5989
5991
5992#define FIELD_LIST(F) \
5993 F(const String&, native_name_) \
5994 F(const Function&, function_) \
5995 F(const TokenPosition, token_pos_)
5996
5999 FIELD_LIST)
6000#undef FIELD_LIST
6001
6002 private:
6003 void set_native_c_function(NativeFunction value) {
6004 native_c_function_ = value;
6005 }
6006
6007 void set_is_bootstrap_native(bool value) { is_bootstrap_native_ = value; }
6008 void set_is_auto_scope(bool value) { is_auto_scope_ = value; }
6009
6010 // These fields are not serialized.
6011 // IL serialization only supports lazy linking of native functions.
6012 NativeFunction native_c_function_ = nullptr;
6013 bool is_bootstrap_native_ = false;
6014 bool is_auto_scope_ = true;
6015 bool link_lazily_ = true;
6016
6018};
6019
6020// Performs a call to native C code. In contrast to NativeCall, the arguments
6021// are unboxed and passed through the native calling convention. However, not
6022// all dart objects can be passed as arguments. Please see the FFI documentation
6023// for more details.
6024//
6025// Arguments to FfiCallInstr:
6026// - The arguments to the native call, marshalled in IL as far as possible.
6027// - The argument address.
6028// - A TypedData for the return value to populate in machine code (optional).
6030 public:
6031 FfiCallInstr(intptr_t deopt_id,
6032 const compiler::ffi::CallMarshaller& marshaller,
6033 bool is_leaf,
6034 InputsArray&& inputs)
6035 : VariadicDefinition(std::move(inputs), deopt_id),
6036 marshaller_(marshaller),
6037 is_leaf_(is_leaf) {
6038#if defined(DEBUG)
6039 ASSERT_EQUAL(InputCount(), InputCountForMarshaller(marshaller));
6040 // No argument to an FfiCall should be an unsafe untagged pointer,
6041 // including the target address.
6042 for (intptr_t i = 0; i < InputCount(); i++) {
6043 ASSERT(!InputAt(i)->definition()->MayCreateUnsafeUntaggedPointer());
6044 }
6045#endif
6046 }
6047
6048 DECLARE_INSTRUCTION(FfiCall)
6049
6050 // Input index of the function pointer to invoke.
6051 intptr_t TargetAddressIndex() const {
6052 return marshaller_.NumArgumentDefinitions();
6053 }
6054
6055 // Input index of the typed data to populate if return value is struct.
6057 ASSERT(marshaller_.ReturnsCompound());
6058 return marshaller_.NumArgumentDefinitions() + 1;
6059 }
6060
6061 virtual bool MayThrow() const {
6062 // By Dart_PropagateError.
6063 return true;
6064 }
6065
6066 virtual bool MayCreateUnsafeUntaggedPointer() const {
6067 // The only case where we have an untagged result is when the return
6068 // value is a pointer, which is then stored in a newly allocated FFI
6069 // Pointer object by the generated IL, so the C code must return an
6070 // external (not GC-movable) address to Dart.
6071 return false;
6072 }
6073
6074 // FfiCallInstr calls C code, which can call back into Dart.
6075 virtual bool ComputeCanDeoptimize() const { return false; }
6076 virtual bool ComputeCanDeoptimizeAfterCall() const {
6077 return !CompilerState::Current().is_aot();
6078 }
6079
6080 virtual bool HasUnknownSideEffects() const { return true; }
6081
6082 // Always creates an exit frame before more Dart code can be called.
6083 virtual bool CanCallDart() const { return false; }
6084
6085 virtual Representation RequiredInputRepresentation(intptr_t idx) const;
6086 virtual Representation representation() const;
6087
6088 // Returns true if we can assume generated code will be executable during a
6089 // safepoint.
6090 //
6091 // TODO(#37739): This should be true when dual-mapping is enabled as well, but
6092 // there are some bugs where it still switches code protections currently.
6094 return FLAG_precompiled_mode;
6095 }
6096
6098 const compiler::ffi::CallMarshaller& marshaller) {
6099 return marshaller.NumArgumentDefinitions() + 1 +
6100 (marshaller.ReturnsCompound() ? 1 : 0);
6101 }
6102
6104
6105#define FIELD_LIST(F) \
6106 F(const compiler::ffi::CallMarshaller&, marshaller_) \
6107 F(bool, is_leaf_)
6108
6111 FIELD_LIST)
6112#undef FIELD_LIST
6113
6114 private:
6115 LocationSummary* MakeLocationSummaryInternal(Zone* zone,
6116 bool is_optimizing,
6117 const RegList temps) const;
6118
6119 // Clobbers the first two given registers.
6120 // `saved_fp` is used as the frame base to rebase off of.
6121 // `temp1` is only used in case of PointerToMemoryLocation.
6122 void EmitParamMoves(FlowGraphCompiler* compiler,
6123 const Register saved_fp,
6124 const Register temp0,
6125 const Register temp1);
6126 // Clobbers both given temp registers.
6127 void EmitReturnMoves(FlowGraphCompiler* compiler,
6128 const Register temp0,
6129 const Register temp1);
6130
6132};
6133
6134// Has the target address in a register passed as the last input in IL.
6136 public:
6137 static LeafRuntimeCallInstr* Make(
6138 Zone* zone,
6139 Representation return_representation,
6140 const ZoneGrowableArray<Representation>& argument_representations,
6141 InputsArray&& inputs);
6142
6143 DECLARE_INSTRUCTION(LeafRuntimeCall)
6144
6145 LocationSummary* MakeLocationSummaryInternal(Zone* zone,
6146 const RegList temps) const;
6147
6148 // Input index of the function pointer to invoke.
6149 intptr_t TargetAddressIndex() const {
6150 return argument_representations_.length();
6151 }
6152
6153 virtual bool MayThrow() const { return false; }
6154
6155 virtual bool ComputeCanDeoptimize() const { return false; }
6156
6157 virtual bool HasUnknownSideEffects() const { return true; }
6158
6159 virtual bool CanCallDart() const { return false; }
6160
6161 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
6162 if (idx < argument_representations_.length()) {
6163 return argument_representations_.At(idx);
6164 }
6165 ASSERT_EQUAL(idx, TargetAddressIndex());
6166 return kUntagged;
6167 }
6168
6169 virtual bool MayCreateUnsafeUntaggedPointer() const {
6170 if (representation() != kUntagged) return false;
6171 // Returns true iff any of the inputs to the target may be an unsafe
6172 // untagged pointer.
6173 //
6174 // This assumes that the inputs to the target function are only used during
6175 // the dynamic extent of the call and not cached/stored somehow.
6176 for (intptr_t i = 0; i < TargetAddressIndex(); i++) {
6177 if (InputAt(i)->definition()->MayCreateUnsafeUntaggedPointer()) {
6178 return true;
6179 }
6180 }
6181 return false;
6182 }
6183
6185 return return_representation_;
6186 }
6187
6188 virtual CompileType ComputeType() const {
6189 return RepresentationUtils::IsUnboxed(representation())
6190 ? CompileType::FromUnboxedRepresentation(representation())
6191 : CompileType::Object();
6192 }
6193
6194 void EmitParamMoves(FlowGraphCompiler* compiler,
6195 Register saved_fp,
6196 Register temp0);
6197
6199
6201
6202 private:
6204 Representation return_representation,
6205 const ZoneGrowableArray<Representation>& argument_representations,
6206 const compiler::ffi::NativeCallingConvention& native_calling_convention,
6207 InputsArray&& inputs);
6208
6209 // Serialized in the custom serializer.
6210 const Representation return_representation_;
6211 const ZoneGrowableArray<Representation>& argument_representations_;
6212 // Not serialized.
6213 const compiler::ffi::NativeCallingConvention& native_calling_convention_;
6215};
6216
6217class DebugStepCheckInstr : public TemplateInstruction<0, NoThrow> {
6218 public:
6221 intptr_t deopt_id)
6222 : TemplateInstruction(source, deopt_id),
6223 token_pos_(source.token_pos),
6224 stub_kind_(stub_kind) {}
6225
6226 DECLARE_INSTRUCTION(DebugStepCheck)
6227
6228 virtual TokenPosition token_pos() const { return token_pos_; }
6229 virtual bool ComputeCanDeoptimize() const { return false; }
6230 virtual bool HasUnknownSideEffects() const { return true; }
6231 virtual Instruction* Canonicalize(FlowGraph* flow_graph);
6232
6233#define FIELD_LIST(F) \
6234 F(const TokenPosition, token_pos_) \
6235 F(const UntaggedPcDescriptors::Kind, stub_kind_)
6236
6239 FIELD_LIST)
6240#undef FIELD_LIST
6241
6242 private:
6244};
6245
6251
6253
6254// StoreField instruction represents a store of the given [value] into
6255// the specified [slot] on the [instance] object. [emit_store_barrier] allows to
6256// specify whether the store should omit the write barrier. [kind] specifies
6257// whether this store is an initializing store, i.e. the first store into a
6258// field after the allocation.
6259//
6260// In JIT mode a slot might be a subject to the field unboxing optimization:
6261// if field type profiling shows that this slot always contains a double or SIMD
6262// value then this field becomes "unboxed" - in this case when storing into
6263// such field we update the payload of the box referenced by the field, rather
6264// than updating the field itself.
6265//
6266// Note: even if [emit_store_barrier] is set to [kEmitStoreBarrier] the store
6267// can still omit the barrier if it establishes that it is not needed.
6268//
6269// Note: stores generated from the constructor initializer list and from
6270// field initializers *must* be marked as initializing. Initializing stores
6271// into unboxed fields are responsible for allocating the mutable box which
6272// would be mutated by subsequent stores.
6273//
6274// Note: If the value to store is an unboxed derived pointer (e.g. pointer to
6275// start of internal typed data array backing) then this instruction cannot be
6276// moved across instructions which can trigger GC, to ensure that
6277//
6278// LoadUntagged + Arithmetic + StoreField
6279//
6280// are performed as an effectively atomic set of instructions.
6281//
6282// See kernel_to_il.cc:BuildTypedDataViewFactoryConstructor.
6283class StoreFieldInstr : public TemplateInstruction<2, NoThrow> {
6284 public:
6285 enum class Kind {
6286 // Store is known to be the first store into a slot of an object after
6287 // object was allocated and before it escapes (e.g. stores in constructor
6288 // initializer list).
6289 kInitializing,
6290
6291 // All other stores.
6292 kOther,
6293 };
6294
6296 Value* instance,
6297 Value* value,
6298 StoreBarrierType emit_store_barrier,
6299 InnerPointerAccess stores_inner_pointer,
6301 Kind kind = Kind::kOther,
6303 compiler::Assembler::kRelaxedNonAtomic)
6305 slot_(slot),
6306 emit_store_barrier_(emit_store_barrier),
6307 memory_order_(memory_order),
6308 token_pos_(source.token_pos),
6309 is_initialization_(kind == Kind::kInitializing),
6310 stores_inner_pointer_(stores_inner_pointer) {
6311 switch (stores_inner_pointer) {
6312 case InnerPointerAccess::kNotUntagged:
6313 ASSERT(slot.representation() != kUntagged);
6314 break;
6315 case InnerPointerAccess::kMayBeInnerPointer:
6316 ASSERT(slot.representation() == kUntagged);
6318 break;
6319 case InnerPointerAccess::kCannotBeInnerPointer:
6320 ASSERT(slot.representation() == kUntagged);
6321 break;
6322 }
6323 SetInputAt(kInstancePos, instance);
6324 SetInputAt(kValuePos, value);
6325 }
6326
6327 // Convenience constructor for slots not containing an untagged address.
6329 Value* instance,
6330 Value* value,
6331 StoreBarrierType emit_store_barrier,
6333 Kind kind = Kind::kOther,
6335 compiler::Assembler::kRelaxedNonAtomic)
6336 : StoreFieldInstr(slot,
6337 instance,
6338 value,
6339 emit_store_barrier,
6341 source,
6342 kind,
6343 memory_order) {}
6344
6345 // Convenience constructor that looks up an IL Slot for the given [field].
6347 Value* instance,
6348 Value* value,
6349 StoreBarrierType emit_store_barrier,
6351 const ParsedFunction* parsed_function,
6352 Kind kind = Kind::kOther)
6353 : StoreFieldInstr(Slot::Get(field, parsed_function),
6354 instance,
6355 value,
6356 emit_store_barrier,
6357 source,
6358 kind) {}
6359
6360 virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const {
6361 // Slots are unboxed based on statically inferrable type information.
6362 // Either sound non-nullable static types (JIT) or global type flow analysis
6363 // results (AOT).
6364 return slot().representation() != kTagged ? kNotSpeculative : kGuardInputs;
6365 }
6366
6367 DECLARE_INSTRUCTION(StoreField)
6368 DECLARE_ATTRIBUTES_NAMED(("slot", "is_initialization"),
6369 (&slot(), is_initialization()))
6370
6371 enum { kInstancePos = 0, kValuePos = 1 };
6372
6373 Value* instance() const { return inputs_[kInstancePos]; }
6374 const Slot& slot() const { return slot_; }
6375 Value* value() const { return inputs_[kValuePos]; }
6376
6377 virtual TokenPosition token_pos() const { return token_pos_; }
6378 bool is_initialization() const { return is_initialization_; }
6379
6381 if (slot().has_untagged_instance()) {
6382 // The instance is not a Dart object, so not traversed by the GC.
6383 return false;
6384 }
6385 if (slot().representation() != kTagged) {
6386 // The target field is native and unboxed, so not traversed by the GC.
6387 return false;
6388 }
6389 if (instance()->definition() == value()->definition()) {
6390 // `x.slot = x` cannot create an old->new or old&marked->old&unmarked
6391 // reference.
6392 return false;
6393 }
6394
6395 if (value()->definition()->Type()->IsBool()) {
6396 return false;
6397 }
6398 return value()->NeedsWriteBarrier() &&
6399 (emit_store_barrier_ == kEmitStoreBarrier);
6400 }
6401
6403 emit_store_barrier_ = value;
6404 }
6405
6407 return stores_inner_pointer_;
6408 }
6410 // We should never change this for a non-untagged field.
6411 ASSERT(stores_inner_pointer_ != InnerPointerAccess::kNotUntagged);
6412 // We only convert from may to cannot, never the other direction.
6413 ASSERT(value == InnerPointerAccess::kCannotBeInnerPointer);
6414 stores_inner_pointer_ = value;
6415 }
6416
6417 virtual bool CanTriggerGC() const { return false; }
6418
6419 virtual bool ComputeCanDeoptimize() const { return false; }
6420
6421 // May require a deoptimization target for input conversions.
6422 virtual intptr_t DeoptimizationTarget() const { return GetDeoptId(); }
6423
6424 // Currently CSE/LICM don't operate on any instructions that can be affected
6425 // by stores/loads. LoadOptimizer handles loads separately. Hence stores
6426 // are marked as having no side-effects.
6427 virtual bool HasUnknownSideEffects() const { return false; }
6428
6429 virtual bool MayHaveVisibleEffect() const { return true; }
6430
6431 virtual Representation RequiredInputRepresentation(intptr_t index) const;
6432
6433 virtual Instruction* Canonicalize(FlowGraph* flow_graph);
6434
6436
6437#define FIELD_LIST(F) \
6438 F(const Slot&, slot_) \
6439 F(StoreBarrierType, emit_store_barrier_) \
6440 F(compiler::Assembler::MemoryOrder, memory_order_) \
6441 F(const TokenPosition, token_pos_) \
6442 /* Marks initializing stores. E.g. in the constructor. */ \
6443 F(const bool, is_initialization_) \
6444 F(InnerPointerAccess, stores_inner_pointer_)
6445
6448 FIELD_LIST)
6449#undef FIELD_LIST
6450
6451 private:
6452 friend class JitCallSpecializer; // For ASSERT(initialization_).
6453
6454 intptr_t OffsetInBytes() const { return slot().offset_in_bytes(); }
6455
6457 // Write barrier is skipped for nullable and non-nullable smis.
6458 ASSERT(value()->Type()->ToNullableCid() != kSmiCid);
6459 return value()->Type()->CanBeSmi() ? compiler::Assembler::kValueCanBeSmi
6460 : compiler::Assembler::kValueIsNotSmi;
6461 }
6462
6464};
6465
6466class GuardFieldInstr : public TemplateInstruction<1, NoThrow, Pure> {
6467 public:
6468 GuardFieldInstr(Value* value, const Field& field, intptr_t deopt_id)
6469 : TemplateInstruction(deopt_id), field_(field) {
6470 SetInputAt(0, value);
6471 CheckField(field);
6472 }
6473
6474 Value* value() const { return inputs_[0]; }
6475
6476 const Field& field() const { return field_; }
6477
6478 virtual bool ComputeCanDeoptimize() const { return true; }
6479 virtual bool CanBecomeDeoptimizationTarget() const {
6480 // Ensure that we record kDeopt PC descriptor in unoptimized code.
6481 return true;
6482 }
6483
6485
6486#define FIELD_LIST(F) F(const Field&, field_)
6487
6490 FIELD_LIST)
6491#undef FIELD_LIST
6492
6493 private:
6495};
6496
6498 public:
6499 GuardFieldClassInstr(Value* value, const Field& field, intptr_t deopt_id)
6500 : GuardFieldInstr(value, field, deopt_id) {
6501 CheckField(field);
6502 }
6503
6504 DECLARE_INSTRUCTION(GuardFieldClass)
6505
6506 virtual Instruction* Canonicalize(FlowGraph* flow_graph);
6507
6508 virtual bool AttributesEqual(const Instruction& other) const;
6509
6511
6512 private:
6514};
6515
6517 public:
6518 GuardFieldLengthInstr(Value* value, const Field& field, intptr_t deopt_id)
6519 : GuardFieldInstr(value, field, deopt_id) {
6520 CheckField(field);
6521 }
6522
6523 DECLARE_INSTRUCTION(GuardFieldLength)
6524
6525 virtual Instruction* Canonicalize(FlowGraph* flow_graph);
6526
6527 virtual bool AttributesEqual(const Instruction& other) const;
6528
6530
6531 private:
6533};
6534
6535// For a field of static type G<T0, ..., Tn> and a stored value of runtime
6536// type T checks that type arguments of T at G exactly match <T0, ..., Tn>
6537// and updates guarded state (UntaggedField::static_type_exactness_state_)
6538// accordingly.
6539//
6540// See StaticTypeExactnessState for more information.
6542 public:
6543 GuardFieldTypeInstr(Value* value, const Field& field, intptr_t deopt_id)
6544 : GuardFieldInstr(value, field, deopt_id) {
6545 CheckField(field);
6546 }
6547
6548 DECLARE_INSTRUCTION(GuardFieldType)
6549
6550 virtual Instruction* Canonicalize(FlowGraph* flow_graph);
6551
6552 virtual bool AttributesEqual(const Instruction& other) const;
6553
6555
6556 private:
6558};
6559
6560template <intptr_t N>
6561class TemplateLoadField : public TemplateDefinition<N, Throws> {
6563
6564 public:
6566 bool calls_initializer = false,
6567 intptr_t deopt_id = DeoptId::kNone,
6568 const Field* field = nullptr)
6569 : Base(source, deopt_id),
6570 token_pos_(source.token_pos),
6571 throw_exception_on_initialization_(
6572 field != nullptr && !field->has_initializer() && field->is_late()),
6573 calls_initializer_(calls_initializer) {
6574 ASSERT(!calls_initializer || field != nullptr);
6575 ASSERT(!calls_initializer || (deopt_id != DeoptId::kNone));
6576 }
6577
6578 virtual TokenPosition token_pos() const { return token_pos_; }
6579 bool calls_initializer() const { return calls_initializer_; }
6580 void set_calls_initializer(bool value) { calls_initializer_ = value; }
6581
6583 return throw_exception_on_initialization_;
6584 }
6585
6586 // Slow path is used if load throws exception on initialization.
6587 virtual bool UseSharedSlowPathStub(bool is_optimizing) const {
6588 return Base::SlowPathSharingSupported(is_optimizing);
6589 }
6590
6591 virtual intptr_t DeoptimizationTarget() const { return Base::GetDeoptId(); }
6592 virtual bool ComputeCanDeoptimize() const { return false; }
6593 virtual bool ComputeCanDeoptimizeAfterCall() const {
6594 return calls_initializer() && !CompilerState::Current().is_aot();
6595 }
6596 virtual intptr_t NumberOfInputsConsumedBeforeCall() const {
6597 return Base::InputCount();
6598 }
6599
6600 virtual bool HasUnknownSideEffects() const {
6601 return calls_initializer() && !throw_exception_on_initialization();
6602 }
6603
6604 virtual bool CanCallDart() const {
6605 // The slow path (running the field initializer) always calls one of a
6606 // specific set of stubs. For those stubs that do not simply call the
6607 // runtime, the GC recognizes their frames and restores write barriers
6608 // automatically (see Thread::RestoreWriteBarrierInvariant).
6609 return false;
6610 }
6611 virtual bool CanTriggerGC() const { return calls_initializer(); }
6612 virtual bool MayThrow() const { return calls_initializer(); }
6613
6614#define FIELD_LIST(F) \
6615 F(const TokenPosition, token_pos_) \
6616 F(const bool, throw_exception_on_initialization_) \
6617 F(bool, calls_initializer_)
6618
6620#undef FIELD_LIST
6621
6622 private:
6624};
6625
6627 public:
6630 bool calls_initializer = false,
6631 intptr_t deopt_id = DeoptId::kNone)
6632 : TemplateLoadField<0>(source, calls_initializer, deopt_id, &field),
6633 field_(field) {}
6634
6635 DECLARE_INSTRUCTION(LoadStaticField)
6636
6637 virtual CompileType ComputeType() const;
6638
6639 const Field& field() const { return field_; }
6640
6641 virtual bool AllowsCSE() const {
6642 // If two loads of a static-final-late field call the initializer and one
6643 // dominates another, we can remove the dominated load with the result of
6644 // the dominating load.
6645 //
6646 // Though if the field is final-late there can be stores into it via
6647 // load/compare-with-sentinel/store. Those loads have
6648 // `!field().has_initializer()` and we won't allow CSE for them.
6649 return field().is_final() &&
6650 (!field().is_late() || field().has_initializer());
6651 }
6652
6653 virtual bool AttributesEqual(const Instruction& other) const;
6654
6656
6657#define FIELD_LIST(F) F(const Field&, field_)
6658
6661 FIELD_LIST)
6662#undef FIELD_LIST
6663
6664 private:
6666};
6667
6668class StoreStaticFieldInstr : public TemplateDefinition<1, NoThrow> {
6669 public:
6671 Value* value,
6674 field_(field),
6675 token_pos_(source.token_pos) {
6676 DEBUG_ASSERT(field.IsNotTemporaryScopedHandle());
6677 SetInputAt(kValuePos, value);
6678 CheckField(field);
6679 }
6680
6681 enum { kValuePos = 0 };
6682
6683 DECLARE_INSTRUCTION(StoreStaticField)
6684
6685 const Field& field() const { return field_; }
6686 Value* value() const { return inputs_[kValuePos]; }
6687
6688 virtual bool ComputeCanDeoptimize() const { return false; }
6689
6690 // Currently CSE/LICM don't operate on any instructions that can be affected
6691 // by stores/loads. LoadOptimizer handles loads separately. Hence stores
6692 // are marked as having no side-effects.
6693 virtual bool HasUnknownSideEffects() const { return false; }
6694
6695 virtual bool MayHaveVisibleEffect() const { return true; }
6696
6697 virtual TokenPosition token_pos() const { return token_pos_; }
6698
6700
6701#define FIELD_LIST(F) \
6702 F(const Field&, field_) \
6703 F(const TokenPosition, token_pos_)
6704
6707 FIELD_LIST)
6708#undef FIELD_LIST
6709
6710 private:
6711 compiler::Assembler::CanBeSmi CanValueBeSmi() const {
6712 ASSERT(value()->Type()->ToNullableCid() != kSmiCid);
6713 return value()->Type()->CanBeSmi() ? compiler::Assembler::kValueCanBeSmi
6714 : compiler::Assembler::kValueIsNotSmi;
6715 }
6716
6717 DISALLOW_COPY_AND_ASSIGN(StoreStaticFieldInstr);
6718};
6719
6724
6725class LoadIndexedInstr : public TemplateDefinition<2, NoThrow> {
6726 public:
6727 LoadIndexedInstr(Value* array,
6728 Value* index,
6729 bool index_unboxed,
6730 intptr_t index_scale,
6731 intptr_t class_id,
6732 AlignmentType alignment,
6733 intptr_t deopt_id,
6735 CompileType* result_type = nullptr);
6736
6737 enum { kArrayPos = 0, kIndexPos = 1 };
6738
6739 TokenPosition token_pos() const { return token_pos_; }
6740
6741 DECLARE_INSTRUCTION(LoadIndexed)
6742 virtual CompileType ComputeType() const;
6743 virtual bool RecomputeType();
6744
6745 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
6746 // The array may be tagged or untagged (for external arrays).
6747 if (idx == kArrayPos) return kNoRepresentation;
6748 ASSERT_EQUAL(idx, kIndexPos);
6749 return index_unboxed_ ? kUnboxedIntPtr : kTagged;
6750 }
6751
6752 bool IsUntagged() const {
6753 return array()->definition()->representation() == kUntagged;
6754 }
6755
6756 Value* array() const { return inputs_[kArrayPos]; }
6757 Value* index() const { return inputs_[kIndexPos]; }
6758 intptr_t index_scale() const { return index_scale_; }
6759 intptr_t class_id() const { return class_id_; }
6760 bool aligned() const { return alignment_ == kAlignedAccess; }
6761
6762 virtual intptr_t DeoptimizationTarget() const {
6763 // Direct access since this instruction cannot deoptimize, and the deopt-id
6764 // was inherited from another instruction that could deoptimize.
6765 return GetDeoptId();
6766 }
6767
6768 virtual bool ComputeCanDeoptimize() const { return false; }
6769
6770 // The representation returned by LoadIndexed for arrays with the given cid.
6771 // May not match the representation for the element returned by
6772 // RepresentationUtils::RepresentationOfArrayElement.
6773 static Representation ReturnRepresentation(intptr_t array_cid);
6774
6776 return ReturnRepresentation(class_id());
6777 }
6778
6779 virtual void InferRange(RangeAnalysis* analysis, Range* range);
6780
6781 virtual bool HasUnknownSideEffects() const { return false; }
6782
6783 virtual Definition* Canonicalize(FlowGraph* flow_graph);
6784
6786
6787#define FIELD_LIST(F) \
6788 F(const bool, index_unboxed_) \
6789 F(const intptr_t, index_scale_) \
6790 F(const intptr_t, class_id_) \
6791 F(const AlignmentType, alignment_) \
6792 F(const TokenPosition, token_pos_) \
6793 /* derived from call */ \
6794 F(CompileType*, result_type_)
6795
6798 FIELD_LIST)
6799#undef FIELD_LIST
6800
6801 private:
6803};
6804
6805// Loads the specified number of code units from the given string, packing
6806// multiple code units into a single datatype. In essence, this is a specialized
6807// version of LoadIndexedInstr which accepts only string targets and can load
6808// multiple elements at once. The result datatype differs depending on the
6809// string type, element count, and architecture; if possible, the result is
6810// packed into a Smi, falling back to a Mint otherwise.
6811// TODO(zerny): Add support for loading into UnboxedInt32x4.
6812class LoadCodeUnitsInstr : public TemplateDefinition<2, NoThrow> {
6813 public:
6815 Value* index,
6816 intptr_t element_count,
6817 intptr_t class_id,
6820 class_id_(class_id),
6821 token_pos_(source.token_pos),
6822 element_count_(element_count),
6823 representation_(kTagged) {
6824 ASSERT(element_count == 1 || element_count == 2 || element_count == 4);
6825 ASSERT(IsStringClassId(class_id));
6826 SetInputAt(0, str);
6827 SetInputAt(1, index);
6828 }
6829
6830 TokenPosition token_pos() const { return token_pos_; }
6831
6832 DECLARE_INSTRUCTION(LoadCodeUnits)
6833 virtual CompileType ComputeType() const;
6834
6835 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
6836 if (idx == 0) {
6837 // The string may be tagged or untagged (for external strings).
6838 return kNoRepresentation;
6839 }
6840 ASSERT(idx == 1);
6841 return kTagged;
6842 }
6843
6844 bool IsExternal() const {
6845 return array()->definition()->representation() == kUntagged;
6846 }
6847
6848 Value* array() const { return inputs_[0]; }
6849 Value* index() const { return inputs_[1]; }
6850
6851 intptr_t index_scale() const {
6852 return compiler::target::Instance::ElementSizeFor(class_id_);
6853 }
6854
6855 intptr_t class_id() const { return class_id_; }
6856 intptr_t element_count() const { return element_count_; }
6857
6858 bool can_pack_into_smi() const {
6859 return element_count() <=
6860 compiler::target::kSmiBits / (index_scale() * kBitsPerByte);
6861 }
6862
6863 virtual bool ComputeCanDeoptimize() const { return false; }
6864
6865 virtual Representation representation() const { return representation_; }
6866 void set_representation(Representation repr) { representation_ = repr; }
6867 virtual void InferRange(RangeAnalysis* analysis, Range* range);
6868
6869 virtual bool HasUnknownSideEffects() const { return false; }
6870
6871 virtual bool CanTriggerGC() const {
6872 return !can_pack_into_smi() && (representation() == kTagged);
6873 }
6874
6875#define FIELD_LIST(F) \
6876 F(const intptr_t, class_id_) \
6877 F(const TokenPosition, token_pos_) \
6878 F(const intptr_t, element_count_) \
6879 F(Representation, representation_)
6880
6883 FIELD_LIST)
6884#undef FIELD_LIST
6885
6886 private:
6888};
6889
6891 : public TemplateDefinition<1, NoThrow, Pure> {
6892 public:
6894 SetInputAt(0, char_code);
6895 }
6896
6897 DECLARE_INSTRUCTION(OneByteStringFromCharCode)
6898 virtual CompileType ComputeType() const;
6899
6900 Value* char_code() const { return inputs_[0]; }
6901
6902 virtual bool ComputeCanDeoptimize() const { return false; }
6903
6904 virtual bool AttributesEqual(const Instruction& other) const { return true; }
6905
6908
6909 private:
6911};
6912
6913class StringToCharCodeInstr : public TemplateDefinition<1, NoThrow, Pure> {
6914 public:
6915 StringToCharCodeInstr(Value* str, intptr_t cid) : cid_(cid) {
6916 ASSERT(str != nullptr);
6917 SetInputAt(0, str);
6918 }
6919
6920 DECLARE_INSTRUCTION(StringToCharCode)
6921 virtual CompileType ComputeType() const;
6922
6923 Value* str() const { return inputs_[0]; }
6924
6925 virtual bool ComputeCanDeoptimize() const { return false; }
6926
6927 virtual bool AttributesEqual(const Instruction& other) const {
6928 return other.AsStringToCharCode()->cid_ == cid_;
6929 }
6930
6931#define FIELD_LIST(F) F(const intptr_t, cid_)
6932
6935 FIELD_LIST)
6936#undef FIELD_LIST
6937
6938 private:
6940};
6941
6942// Scanning instruction to compute the result size and decoding parameters
6943// for the UTF-8 decoder. Equivalent to:
6944//
6945// int _scan(Uint8List bytes, int start, int end, _OneByteString table,
6946// _Utf8Decoder decoder) {
6947// int size = 0;
6948// int flags = 0;
6949// for (int i = start; i < end; i++) {
6950// int t = table.codeUnitAt(bytes[i]);
6951// size += t & sizeMask;
6952// flags |= t;
6953// }
6954// decoder._scanFlags |= flags & flagsMask;
6955// return size;
6956// }
6957//
6958// under these assumptions:
6959// - The difference between start and end must be less than 2^30, since the
6960// resulting length can be twice the input length (and the result has to be in
6961// Smi range). This is guaranteed by `_Utf8Decoder.chunkSize` which is set to
6962// `65536`.
6963// - The decoder._scanFlags field is unboxed or contains a smi.
6964// - The first 128 entries of the table have the value 1.
6965class Utf8ScanInstr : public TemplateDefinition<5, NoThrow> {
6966 public:
6968 Value* bytes,
6969 Value* start,
6970 Value* end,
6971 Value* table,
6972 const Slot& decoder_scan_flags_field)
6973 : scan_flags_field_(decoder_scan_flags_field) {
6974 SetInputAt(0, decoder);
6975 SetInputAt(1, bytes);
6976 SetInputAt(2, start);
6977 SetInputAt(3, end);
6978 SetInputAt(4, table);
6979 }
6980
6981 DECLARE_INSTRUCTION(Utf8Scan)
6982
6983 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
6984 ASSERT(idx >= 0 || idx <= 4);
6985 // The start and end inputs are unboxed, but in smi range.
6986 if (idx == 2 || idx == 3) return kUnboxedIntPtr;
6987 return kTagged;
6988 }
6989
6990 virtual Representation representation() const { return kUnboxedIntPtr; }
6991
6992 virtual bool HasUnknownSideEffects() const { return true; }
6993 virtual bool ComputeCanDeoptimize() const { return false; }
6994 virtual intptr_t DeoptimizationTarget() const { return DeoptId::kNone; }
6995 virtual void InferRange(RangeAnalysis* analysis, Range* range);
6996
6997 virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const {
6998 return kNotSpeculative;
6999 }
7000
7001 virtual bool AttributesEqual(const Instruction& other) const {
7002 return scan_flags_field_.Equals(other.AsUtf8Scan()->scan_flags_field_);
7003 }
7004
7005 bool IsScanFlagsUnboxed() const;
7006
7008
7009#define FIELD_LIST(F) F(const Slot&, scan_flags_field_)
7010
7013 FIELD_LIST)
7014#undef FIELD_LIST
7015
7016 private:
7018};
7019
7020class StoreIndexedInstr : public TemplateInstruction<3, NoThrow> {
7021 public:
7022 StoreIndexedInstr(Value* array,
7023 Value* index,
7024 Value* value,
7025 StoreBarrierType emit_store_barrier,
7026 bool index_unboxed,
7027 intptr_t index_scale,
7028 intptr_t class_id,
7029 AlignmentType alignment,
7030 intptr_t deopt_id,
7032 SpeculativeMode speculative_mode = kGuardInputs);
7033 DECLARE_INSTRUCTION(StoreIndexed)
7034
7035 enum { kArrayPos = 0, kIndexPos = 1, kValuePos = 2 };
7036
7037 Value* array() const { return inputs_[kArrayPos]; }
7038 Value* index() const { return inputs_[kIndexPos]; }
7039 Value* value() const { return inputs_[kValuePos]; }
7040
7041 intptr_t index_scale() const { return index_scale_; }
7042 intptr_t class_id() const { return class_id_; }
7043 bool aligned() const { return alignment_ == kAlignedAccess; }
7044
7046 if (array()->definition() == value()->definition()) {
7047 // `x[slot] = x` cannot create an old->new or old&marked->old&unmarked
7048 // reference.
7049 return false;
7050 }
7051
7052 if (value()->definition()->Type()->IsBool()) {
7053 return false;
7054 }
7055 return value()->NeedsWriteBarrier() &&
7056 (emit_store_barrier_ == kEmitStoreBarrier);
7057 }
7058
7060 emit_store_barrier_ = value;
7061 }
7062
7063 virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const {
7064 return speculative_mode_;
7065 }
7066
7067 virtual bool ComputeCanDeoptimize() const { return false; }
7068
7069 // The value representation expected by StoreIndexed for arrays with the
7070 // given cid. May not match the representation for the element returned by
7071 // RepresentationUtils::RepresentationOfArrayElement.
7072 static Representation ValueRepresentation(intptr_t array_cid);
7073
7074 virtual Representation RequiredInputRepresentation(intptr_t idx) const;
7075
7076 bool IsUntagged() const {
7077 return array()->definition()->representation() == kUntagged;
7078 }
7079
7080 virtual intptr_t DeoptimizationTarget() const {
7081 // Direct access since this instruction cannot deoptimize, and the deopt-id
7082 // was inherited from another instruction that could deoptimize.
7083 return GetDeoptId();
7084 }
7085
7086 virtual bool HasUnknownSideEffects() const { return false; }
7087
7088 virtual bool MayHaveVisibleEffect() const { return true; }
7089
7090 virtual Instruction* Canonicalize(FlowGraph* flow_graph);
7091
7093
7094#define FIELD_LIST(F) \
7095 F(StoreBarrierType, emit_store_barrier_) \
7096 F(const bool, index_unboxed_) \
7097 F(const intptr_t, index_scale_) \
7098 F(const intptr_t, class_id_) \
7099 F(const AlignmentType, alignment_) \
7100 F(const TokenPosition, token_pos_) \
7101 F(const SpeculativeMode, speculative_mode_)
7102
7105 FIELD_LIST)
7106#undef FIELD_LIST
7107
7108 private:
7109 compiler::Assembler::CanBeSmi CanValueBeSmi() const {
7110 return compiler::Assembler::kValueCanBeSmi;
7111 }
7112
7113 DISALLOW_COPY_AND_ASSIGN(StoreIndexedInstr);
7114};
7115
7116class RecordCoverageInstr : public TemplateInstruction<0, NoThrow> {
7117 public:
7118 RecordCoverageInstr(const Array& coverage_array,
7119 intptr_t coverage_index,
7122 coverage_array_(coverage_array),
7123 coverage_index_(coverage_index),
7124 token_pos_(source.token_pos) {}
7125
7126 DECLARE_INSTRUCTION(RecordCoverage)
7127
7128 virtual TokenPosition token_pos() const { return token_pos_; }
7129 virtual bool ComputeCanDeoptimize() const { return false; }
7130 virtual bool HasUnknownSideEffects() const { return false; }
7131 virtual Instruction* Canonicalize(FlowGraph* flow_graph);
7132
7133#define FIELD_LIST(F) \
7134 F(const Array&, coverage_array_) \
7135 F(const intptr_t, coverage_index_) \
7136 F(const TokenPosition, token_pos_)
7137
7140 FIELD_LIST)
7141#undef FIELD_LIST
7142
7143 private:
7145};
7146
7147// Note overridable, built-in: value ? false : true.
7148class BooleanNegateInstr : public TemplateDefinition<1, NoThrow> {
7149 public:
7150 explicit BooleanNegateInstr(Value* value) { SetInputAt(0, value); }
7151
7152 DECLARE_INSTRUCTION(BooleanNegate)
7153 virtual CompileType ComputeType() const;
7154
7155 Value* value() const { return inputs_[0]; }
7156
7157 virtual bool ComputeCanDeoptimize() const { return false; }
7158
7159 virtual bool HasUnknownSideEffects() const { return false; }
7160
7161 virtual Definition* Canonicalize(FlowGraph* flow_graph);
7162
7164
7165 private:
7167};
7168
7169// bool ? -1 : 0
7170class BoolToIntInstr : public TemplateDefinition<1, NoThrow> {
7171 public:
7172 explicit BoolToIntInstr(Value* value) { SetInputAt(0, value); }
7173
7174 DECLARE_INSTRUCTION(BoolToInt)
7175
7176 Value* value() const { return inputs_[0]; }
7177
7178 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
7179 return kTagged;
7180 }
7181 virtual Representation representation() const { return kUnboxedInt32; }
7182
7183 virtual bool ComputeCanDeoptimize() const { return false; }
7184
7185 virtual bool HasUnknownSideEffects() const { return false; }
7186
7188
7189 private:
7191};
7192
7193// int == 0 ? false : true
7194class IntToBoolInstr : public TemplateDefinition<1, NoThrow> {
7195 public:
7196 explicit IntToBoolInstr(Value* value) {
7197 ASSERT(value->definition()->representation() == kUnboxedInt32);
7198 SetInputAt(0, value);
7199 }
7200
7201 DECLARE_INSTRUCTION(IntToBool)
7202 virtual CompileType ComputeType() const;
7203
7204 Value* value() const { return inputs_[0]; }
7205
7206 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
7207 return kUnboxedInt32;
7208 }
7209 virtual Representation representation() const { return kTagged; }
7210
7211 virtual bool ComputeCanDeoptimize() const { return false; }
7212
7213 virtual bool HasUnknownSideEffects() const { return false; }
7214
7216
7217 private:
7219};
7220
7221class InstanceOfInstr : public TemplateDefinition<3, Throws> {
7222 public:
7224 Value* value,
7225 Value* instantiator_type_arguments,
7226 Value* function_type_arguments,
7227 const AbstractType& type,
7228 intptr_t deopt_id)
7229 : TemplateDefinition(source, deopt_id),
7230 token_pos_(source.token_pos),
7231 type_(type) {
7232 ASSERT(!type.IsNull());
7233 SetInputAt(0, value);
7234 SetInputAt(1, instantiator_type_arguments);
7235 SetInputAt(2, function_type_arguments);
7236 }
7237
7238 DECLARE_INSTRUCTION(InstanceOf)
7239 virtual CompileType ComputeType() const;
7240
7241 Value* value() const { return inputs_[0]; }
7242 Value* instantiator_type_arguments() const { return inputs_[1]; }
7243 Value* function_type_arguments() const { return inputs_[2]; }
7244
7245 const AbstractType& type() const { return type_; }
7246 virtual TokenPosition token_pos() const { return token_pos_; }
7247
7248 virtual bool ComputeCanDeoptimize() const { return false; }
7249 virtual bool ComputeCanDeoptimizeAfterCall() const {
7250 return !CompilerState::Current().is_aot();
7251 }
7252
7253 virtual bool HasUnknownSideEffects() const { return false; }
7254
7256
7257#define FIELD_LIST(F) \
7258 F(const TokenPosition, token_pos_) \
7259 F(const AbstractType&, type_)
7260
7263 FIELD_LIST)
7264#undef FIELD_LIST
7265
7266 private:
7268};
7269
7270// Subclasses of 'AllocationInstr' must maintain the invariant that if
7271// 'WillAllocateNewOrRemembered' is true, then the result of the allocation must
7272// either reside in new space or be in the store buffer.
7274 public:
7276 intptr_t deopt_id = DeoptId::kNone)
7277 : Definition(source, deopt_id),
7278 token_pos_(source.token_pos),
7279 identity_(AliasIdentity::Unknown()) {}
7280
7281 virtual TokenPosition token_pos() const { return token_pos_; }
7282
7283 virtual AliasIdentity Identity() const { return identity_; }
7284 virtual void SetIdentity(AliasIdentity identity) { identity_ = identity; }
7285
7286 // TODO(sjindel): Update these conditions when the incremental write barrier
7287 // is added.
7288 virtual bool WillAllocateNewOrRemembered() const = 0;
7289
7290 virtual bool MayThrow() const {
7291 // Any allocation instruction may throw an OutOfMemory error.
7292 return true;
7293 }
7294 virtual bool ComputeCanDeoptimize() const { return false; }
7295 virtual bool ComputeCanDeoptimizeAfterCall() const {
7296 // We test that allocation instructions have correct deopt environment
7297 // (which is needed in case OOM is thrown) by actually deoptimizing
7298 // optimized code in allocation slow paths.
7299 return !CompilerState::Current().is_aot();
7300 }
7301 virtual intptr_t NumberOfInputsConsumedBeforeCall() const {
7302 return InputCount();
7303 }
7304
7305 // Returns the slot in the allocated object that contains the value at the
7306 // given input position. Returns nullptr if the input position is invalid
7307 // or if the input is not stored in the object.
7308 virtual const Slot* SlotForInput(intptr_t pos) { return nullptr; }
7309
7310 // Returns the input index that has a corresponding slot which is identical to
7311 // the given slot. Returns a negative index if no such input found.
7312 intptr_t InputForSlot(const Slot& slot) {
7313 for (intptr_t i = 0; i < InputCount(); i++) {
7314 auto* const input_slot = SlotForInput(i);
7315 if (input_slot != nullptr && input_slot->IsIdentical(slot)) {
7316 return i;
7317 }
7318 }
7319 return -1;
7320 }
7321
7322 // Returns whether the allocated object has initialized fields and/or payload
7323 // elements. Override for any subclass that returns an uninitialized object.
7324 virtual bool ObjectIsInitialized() { return true; }
7325
7327
7329
7330#define FIELD_LIST(F) \
7331 F(const TokenPosition, token_pos_) \
7332 F(AliasIdentity, identity_)
7333
7335 Definition,
7336 FIELD_LIST)
7337#undef FIELD_LIST
7338
7339 private:
7341};
7342
7343template <intptr_t N>
7345 public:
7347 intptr_t deopt_id)
7348 : AllocationInstr(source, deopt_id), inputs_() {}
7349
7350 virtual intptr_t InputCount() const { return N; }
7351 virtual Value* InputAt(intptr_t i) const { return inputs_[i]; }
7352
7353 // Non-array allocation may throw, but it doesn't have any
7354 // visible effects: it can be eliminated and other
7355 // instructions can be hoisted over.
7356 virtual bool MayHaveVisibleEffect() const { return false; }
7357
7359
7360 protected:
7362
7363 private:
7364 friend class BranchInstr;
7365 friend class IfThenElseInstr;
7367
7368 virtual void RawSetInputAt(intptr_t i, Value* value) { inputs_[i] = value; }
7369};
7370
7372 public:
7373 enum { kTypeArgumentsPos = 0 };
7375 const Class& cls,
7376 intptr_t deopt_id,
7377 Value* type_arguments = nullptr)
7378 : AllocationInstr(source, deopt_id),
7379 cls_(cls),
7380 has_type_arguments_(type_arguments != nullptr),
7381 type_arguments_slot_(nullptr),
7382 type_arguments_(type_arguments) {
7383 DEBUG_ASSERT(cls.IsNotTemporaryScopedHandle());
7384 ASSERT(!cls.IsNull());
7385 ASSERT((cls.NumTypeArguments() > 0) == has_type_arguments_);
7386 if (has_type_arguments_) {
7387 SetInputAt(kTypeArgumentsPos, type_arguments);
7388 type_arguments_slot_ =
7389 &Slot::GetTypeArgumentsSlotFor(Thread::Current(), cls);
7390 }
7391 }
7392
7393 DECLARE_INSTRUCTION(AllocateObject)
7394 virtual CompileType ComputeType() const;
7395
7396 const Class& cls() const { return cls_; }
7397 Value* type_arguments() const { return type_arguments_; }
7398
7399 virtual intptr_t InputCount() const { return has_type_arguments_ ? 1 : 0; }
7400 virtual Value* InputAt(intptr_t i) const {
7401 ASSERT(has_type_arguments_ && i == kTypeArgumentsPos);
7402 return type_arguments_;
7403 }
7404
7405 virtual bool HasUnknownSideEffects() const { return false; }
7406
7407 // Object allocation may throw, but it doesn't have any
7408 // visible effects: it can be eliminated and other
7409 // instructions can be hoisted over.
7410 virtual bool MayHaveVisibleEffect() const { return false; }
7411
7412 virtual bool WillAllocateNewOrRemembered() const {
7413 return WillAllocateNewOrRemembered(cls());
7414 }
7415
7416 static bool WillAllocateNewOrRemembered(const Class& cls) {
7418 }
7419
7420 virtual const Slot* SlotForInput(intptr_t pos) {
7421 return pos == kTypeArgumentsPos ? type_arguments_slot_ : nullptr;
7422 }
7423
7425
7426#define FIELD_LIST(F) \
7427 F(const Class&, cls_) \
7428 F(const bool, has_type_arguments_) \
7429 F(const Slot*, type_arguments_slot_)
7430
7433 FIELD_LIST)
7434#undef FIELD_LIST
7435
7436 private:
7437 virtual void RawSetInputAt(intptr_t i, Value* value) {
7438 ASSERT(has_type_arguments_ && (i == kTypeArgumentsPos));
7439 type_arguments_ = value;
7440 }
7441
7442 Value* type_arguments_ = nullptr;
7443
7445};
7446
7447// Allocates and null initializes a closure object, given the closure function
7448// and the context as values.
7450 public:
7451 enum Inputs {
7452 kFunctionPos = 0,
7453 kContextPos = 1,
7454 kInstantiatorTypeArgsPos = 2,
7455 };
7457 Value* closure_function,
7458 Value* context,
7459 Value* instantiator_type_args, // Optional.
7460 bool is_generic,
7461 bool is_tear_off,
7462 intptr_t deopt_id)
7463 : TemplateAllocation(source, deopt_id),
7464 has_instantiator_type_args_(instantiator_type_args != nullptr),
7465 is_generic_(is_generic),
7466 is_tear_off_(is_tear_off) {
7467 SetInputAt(kFunctionPos, closure_function);
7468 SetInputAt(kContextPos, context);
7469 if (has_instantiator_type_args_) {
7470 SetInputAt(kInstantiatorTypeArgsPos, instantiator_type_args);
7471 }
7472 }
7473
7474 DECLARE_INSTRUCTION(AllocateClosure)
7475 virtual CompileType ComputeType() const;
7476
7477 virtual intptr_t InputCount() const {
7478 return has_instantiator_type_args() ? 3 : 2;
7479 }
7480
7481 Value* closure_function() const { return inputs_[kFunctionPos]; }
7482 Value* context() const { return inputs_[kContextPos]; }
7483
7485 return has_instantiator_type_args_;
7486 }
7487 bool is_generic() const { return is_generic_; }
7488 bool is_tear_off() const { return is_tear_off_; }
7489
7490 const Function& known_function() const {
7491 Value* const value = closure_function();
7492 if (value->BindsToConstant()) {
7493 ASSERT(value->BoundConstant().IsFunction());
7494 return Function::Cast(value->BoundConstant());
7495 }
7496 return Object::null_function();
7497 }
7498
7499 virtual const Slot* SlotForInput(intptr_t pos) {
7500 switch (pos) {
7501 case kFunctionPos:
7502 return &Slot::Closure_function();
7503 case kContextPos:
7504 return &Slot::Closure_context();
7505 case kInstantiatorTypeArgsPos:
7506 return has_instantiator_type_args()
7507 ? &Slot::Closure_instantiator_type_arguments()
7508 : nullptr;
7509 default:
7510 return TemplateAllocation::SlotForInput(pos);
7511 }
7512 }
7513
7514 virtual Definition* Canonicalize(FlowGraph* flow_graph);
7515
7516 virtual bool AllowsCSE() const { return is_tear_off(); }
7517
7518 virtual bool HasUnknownSideEffects() const { return false; }
7519
7520 virtual bool AttributesEqual(const Instruction& other) const {
7521 const auto other_ac = other.AsAllocateClosure();
7522 return (other_ac->has_instantiator_type_args() ==
7523 has_instantiator_type_args()) &&
7524 (other_ac->is_generic() == is_generic()) &&
7525 (other_ac->is_tear_off() == is_tear_off());
7526 }
7527
7528 virtual bool WillAllocateNewOrRemembered() const {
7529 return IsAllocatableInNewSpace(compiler::target::Closure::InstanceSize());
7530 }
7531
7532#define FIELD_LIST(F) \
7533 F(const bool, has_instantiator_type_args_) \
7534 F(const bool, is_generic_) \
7535 F(const bool, is_tear_off_)
7536
7539 FIELD_LIST)
7540#undef FIELD_LIST
7541
7542 private:
7544};
7545
7547 public:
7549 intptr_t num_context_variables,
7550 intptr_t deopt_id);
7551
7552 DECLARE_INSTRUCTION(AllocateUninitializedContext)
7553 virtual CompileType ComputeType() const;
7554
7555 intptr_t num_context_variables() const { return num_context_variables_; }
7556
7557 virtual bool HasUnknownSideEffects() const { return false; }
7558
7559 virtual bool WillAllocateNewOrRemembered() const {
7560 return compiler::target::WillAllocateNewOrRememberedContext(
7561 num_context_variables_);
7562 }
7563
7564 virtual bool ObjectIsInitialized() { return false; }
7565
7567
7568#define FIELD_LIST(F) F(const intptr_t, num_context_variables_)
7569
7572 FIELD_LIST)
7573#undef FIELD_LIST
7574
7575 private:
7577};
7578
7579// Allocates and null initializes a record object.
7581 public:
7583 RecordShape shape,
7584 intptr_t deopt_id)
7585 : TemplateAllocation(source, deopt_id), shape_(shape) {}
7586
7587 DECLARE_INSTRUCTION(AllocateRecord)
7588 virtual CompileType ComputeType() const;
7589
7590 RecordShape shape() const { return shape_; }
7591 intptr_t num_fields() const { return shape_.num_fields(); }
7592
7593 virtual bool HasUnknownSideEffects() const { return false; }
7594
7595 virtual bool WillAllocateNewOrRemembered() const {
7597 compiler::target::Record::InstanceSize(num_fields()));
7598 }
7599
7600#define FIELD_LIST(F) F(const RecordShape, shape_)
7601
7604 FIELD_LIST)
7605#undef FIELD_LIST
7606
7607 private:
7609};
7610
7611// Allocates and initializes fields of a small record object
7612// (with 2 or 3 fields).
7614 public:
7616 RecordShape shape, // 2 or 3 fields.
7617 Value* value0,
7618 Value* value1,
7619 Value* value2, // Optional.
7620 intptr_t deopt_id)
7621 : TemplateAllocation(source, deopt_id), shape_(shape) {
7622 const intptr_t num_fields = shape.num_fields();
7623 ASSERT(num_fields == 2 || num_fields == 3);
7624 ASSERT((num_fields > 2) == (value2 != nullptr));
7625 SetInputAt(0, value0);
7626 SetInputAt(1, value1);
7627 if (num_fields > 2) {
7628 SetInputAt(2, value2);
7629 }
7630 }
7631
7632 DECLARE_INSTRUCTION(AllocateSmallRecord)
7633 virtual CompileType ComputeType() const;
7634
7635 RecordShape shape() const { return shape_; }
7636 intptr_t num_fields() const { return shape().num_fields(); }
7637
7638 virtual intptr_t InputCount() const { return num_fields(); }
7639
7640 virtual const Slot* SlotForInput(intptr_t pos) {
7641 return &Slot::GetRecordFieldSlot(
7642 Thread::Current(), compiler::target::Record::field_offset(pos));
7643 }
7644
7645 virtual bool HasUnknownSideEffects() const { return false; }
7646
7647 virtual bool WillAllocateNewOrRemembered() const {
7649 compiler::target::Record::InstanceSize(num_fields()));
7650 }
7651
7652#define FIELD_LIST(F) F(const RecordShape, shape_)
7653
7656 FIELD_LIST)
7657#undef FIELD_LIST
7658
7659 private:
7661};
7662
7663// This instruction captures the state of the object which had its allocation
7664// removed during the AllocationSinking pass.
7665// It does not produce any real code only deoptimization information.
7667 public:
7669 const Class& cls,
7670 intptr_t length_or_shape,
7671 const ZoneGrowableArray<const Slot*>& slots,
7672 InputsArray&& values)
7673 : VariadicDefinition(std::move(values)),
7674 cls_(cls),
7675 length_or_shape_(length_or_shape),
7676 slots_(slots),
7677 registers_remapped_(false),
7678 allocation_(allocation) {
7679 ASSERT(slots_.length() == InputCount());
7680 }
7681
7682 AllocationInstr* allocation() const { return allocation_; }
7683 const Class& cls() const { return cls_; }
7684
7685 intptr_t length_or_shape() const { return length_or_shape_; }
7686
7687 intptr_t FieldOffsetAt(intptr_t i) const {
7688 return slots_[i]->offset_in_bytes();
7689 }
7690
7691 const Location& LocationAt(intptr_t i) {
7692 ASSERT(0 <= i && i < InputCount());
7693 return locations_[i];
7694 }
7695
7696 DECLARE_INSTRUCTION(MaterializeObject)
7697
7698 // SelectRepresentations pass is run once more while MaterializeObject
7699 // instructions are still in the graph. To avoid any redundant boxing
7700 // operations inserted by that pass we should indicate that this
7701 // instruction can cope with any representation as it is essentially
7702 // an environment use.
7703 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
7704 ASSERT(0 <= idx && idx < InputCount());
7705 return kNoRepresentation;
7706 }
7707
7708 virtual bool ComputeCanDeoptimize() const { return false; }
7709 virtual bool HasUnknownSideEffects() const { return false; }
7710 virtual bool CanReplaceWithConstant() const { return false; }
7711
7712 Location* locations() { return locations_; }
7713 void set_locations(Location* locations) { locations_ = locations; }
7714
7715 virtual bool MayThrow() const { return false; }
7716
7717 void RemapRegisters(intptr_t* cpu_reg_slots, intptr_t* fpu_reg_slots);
7718
7719 bool was_visited_for_liveness() const { return visited_for_liveness_; }
7720 void mark_visited_for_liveness() { visited_for_liveness_ = true; }
7721
7723
7724#define FIELD_LIST(F) \
7725 F(const Class&, cls_) \
7726 F(intptr_t, length_or_shape_) \
7727 F(const ZoneGrowableArray<const Slot*>&, slots_) \
7728 F(bool, registers_remapped_)
7729
7732 FIELD_LIST)
7733#undef FIELD_LIST
7735
7736 private:
7737 Location* locations_ = nullptr;
7738
7739 // Not serialized.
7740 AllocationInstr* allocation_ = nullptr;
7741 bool visited_for_liveness_ = false;
7742
7744};
7745
7747 public:
7749 intptr_t deopt_id)
7750 : AllocationInstr(source, deopt_id) {}
7751
7752 virtual Value* num_elements() const = 0;
7753
7755 return num_elements()->BindsToSmiConstant();
7756 }
7757 intptr_t GetConstantNumElements() const {
7758 return num_elements()->BoundSmiConstant();
7759 }
7760
7762
7764
7765 private:
7767};
7768
7769template <intptr_t N>
7771 public:
7773 intptr_t deopt_id)
7774 : ArrayAllocationInstr(source, deopt_id), inputs_() {}
7775
7776 virtual intptr_t InputCount() const { return N; }
7777 virtual Value* InputAt(intptr_t i) const { return inputs_[i]; }
7778
7780
7781 protected:
7783
7784 private:
7785 virtual void RawSetInputAt(intptr_t i, Value* value) { inputs_[i] = value; }
7786
7788};
7789
7791 public:
7793 Value* type_arguments,
7794 Value* num_elements,
7795 intptr_t deopt_id)
7796 : TemplateArrayAllocation(source, deopt_id) {
7797 SetInputAt(kTypeArgumentsPos, type_arguments);
7798 SetInputAt(kLengthPos, num_elements);
7799 }
7800
7801 enum { kTypeArgumentsPos = 0, kLengthPos = 1 };
7802
7803 DECLARE_INSTRUCTION(CreateArray)
7804 virtual CompileType ComputeType() const;
7805
7806 Value* type_arguments() const { return inputs_[kTypeArgumentsPos]; }
7807 virtual Value* num_elements() const { return inputs_[kLengthPos]; }
7808
7809 virtual bool HasUnknownSideEffects() const { return false; }
7810
7811 virtual bool WillAllocateNewOrRemembered() const {
7812 // Large arrays will use cards instead; cannot skip write barrier.
7813 if (!HasConstantNumElements()) return false;
7814 return compiler::target::WillAllocateNewOrRememberedArray(
7815 GetConstantNumElements());
7816 }
7817
7818 virtual const Slot* SlotForInput(intptr_t pos) {
7819 switch (pos) {
7820 case kTypeArgumentsPos:
7821 return &Slot::Array_type_arguments();
7822 case kLengthPos:
7823 return &Slot::Array_length();
7824 default:
7825 return TemplateArrayAllocation::SlotForInput(pos);
7826 }
7827 }
7828
7830
7831 private:
7833};
7834
7836 public:
7838 classid_t class_id,
7839 Value* num_elements,
7840 intptr_t deopt_id)
7841 : TemplateArrayAllocation(source, deopt_id), class_id_(class_id) {
7842 SetInputAt(kLengthPos, num_elements);
7843 }
7844
7845 enum { kLengthPos = 0 };
7846
7847 DECLARE_INSTRUCTION(AllocateTypedData)
7848 virtual CompileType ComputeType() const;
7849
7850 classid_t class_id() const { return class_id_; }
7851 virtual Value* num_elements() const { return inputs_[kLengthPos]; }
7852
7853 virtual bool HasUnknownSideEffects() const { return false; }
7854
7855 virtual bool WillAllocateNewOrRemembered() const {
7856 // No write barriers are generated for typed data accesses.
7857 return false;
7858 }
7859
7860 virtual const Slot* SlotForInput(intptr_t pos) {
7861 switch (pos) {
7862 case kLengthPos:
7863 return &Slot::TypedDataBase_length();
7864 default:
7865 return TemplateArrayAllocation::SlotForInput(pos);
7866 }
7867 }
7868
7869#define FIELD_LIST(F) F(const classid_t, class_id_)
7870
7873 FIELD_LIST)
7874#undef FIELD_LIST
7875
7876 private:
7878};
7879
7880// This instruction is used to access untagged fields in untagged pointers to
7881// non-Dart objects, such as Thread and IsolateGroup, which do not point to
7882// managed memory.
7883//
7884// To access untagged fields in Dart objects, use LoadField with an
7885// appropriately created Slot.
7886//
7887// To access tagged fields in non-Dart objects, see
7888// FlowGraphBuilder::RawLoadField in kernel_to_il.cc.
7889class LoadUntaggedInstr : public TemplateDefinition<1, NoThrow> {
7890 public:
7891 LoadUntaggedInstr(Value* object, intptr_t offset) : offset_(offset) {
7892 ASSERT(object->definition()->representation() == kUntagged);
7894 SetInputAt(0, object);
7895 }
7896
7897 virtual Representation representation() const { return kUntagged; }
7898 DECLARE_INSTRUCTION(LoadUntagged)
7899
7900 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
7901 ASSERT(idx == 0);
7902 // The object may be tagged or untagged (for external objects).
7903 return kNoRepresentation;
7904 }
7905
7906 Value* object() const { return inputs_[0]; }
7907 intptr_t offset() const { return offset_; }
7908
7909 virtual bool MayCreateUnsafeUntaggedPointer() const {
7910 // See the documentation for LoadUntaggedInstr.
7911 return false;
7912 }
7913
7914 virtual bool ComputeCanDeoptimize() const { return false; }
7915
7916 virtual bool HasUnknownSideEffects() const { return false; }
7917 virtual bool AttributesEqual(const Instruction& other) const {
7918 return other.AsLoadUntagged()->offset_ == offset_;
7919 }
7920
7922
7923#define FIELD_LIST(F) F(const intptr_t, offset_)
7924
7927 FIELD_LIST)
7928#undef FIELD_LIST
7929
7930 private:
7932};
7933
7934// This instruction is used to perform untagged address calculations instead of
7935// converting GC-movable untagged pointers to unboxed integers in IL. Given an
7936// untagged address [base] as well as an [index] and [offset], where [index]
7937// is scaled by [index_scale], returns the untagged address
7938//
7939// base + (index * index_scale) + offset
7940//
7941// This allows the flow graph checker to enforce that there are no live untagged
7942// addresses of GC-movable objects when GC can happen.
7944 public:
7945 enum { kBasePos, kIndexPos, kOffsetPos };
7947 Value* index,
7948 intptr_t index_scale,
7949 Value* offset)
7950 : index_scale_(index_scale) {
7951 ASSERT(base->definition()->representation() == kUntagged);
7952 ASSERT(Utils::IsPowerOfTwo(index_scale));
7953 ASSERT(1 <= index_scale && index_scale <= 16);
7954 SetInputAt(kBasePos, base);
7955 SetInputAt(kIndexPos, index);
7956 SetInputAt(kOffsetPos, offset);
7957 }
7958
7959 DECLARE_INSTRUCTION(CalculateElementAddress)
7960
7961 virtual Representation representation() const { return kUntagged; }
7962
7963 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
7964 if (idx == kBasePos) return kUntagged;
7965 ASSERT(idx == kIndexPos || idx == kOffsetPos);
7966 return kUnboxedIntPtr;
7967 }
7968
7969 Value* base() const { return inputs_[kBasePos]; }
7970 Value* index() const { return inputs_[kIndexPos]; }
7971 Value* offset() const { return inputs_[kOffsetPos]; }
7972 intptr_t index_scale() const { return index_scale_; }
7973
7974 virtual Definition* Canonicalize(FlowGraph* flow_graph);
7975
7976 virtual bool MayCreateUnsafeUntaggedPointer() const {
7977 return base()->definition()->MayCreateUnsafeUntaggedPointer();
7978 }
7979
7980 virtual bool AllowsCSE() const { return !MayCreateUnsafeUntaggedPointer(); }
7981
7982 virtual bool ComputeCanDeoptimize() const { return false; }
7983
7984 virtual bool HasUnknownSideEffects() const { return false; }
7985 virtual bool AttributesEqual(const Instruction& other) const {
7986 return other.AsCalculateElementAddress()->index_scale_ == index_scale_;
7987 }
7988
7990
7991#define FIELD_LIST(F) F(const intptr_t, index_scale_)
7992
7995 FIELD_LIST)
7996#undef FIELD_LIST
7997
7998 private:
8000};
8001
8002class LoadClassIdInstr : public TemplateDefinition<1, NoThrow, Pure> {
8003 public:
8004 explicit LoadClassIdInstr(Value* object,
8005 Representation representation = kTagged,
8006 bool input_can_be_smi = true)
8007 : representation_(representation), input_can_be_smi_(input_can_be_smi) {
8008 ASSERT(representation == kTagged || representation == kUnboxedUword);
8009 SetInputAt(0, object);
8010 }
8011
8012 virtual Representation representation() const { return representation_; }
8013 DECLARE_INSTRUCTION(LoadClassId)
8014 virtual CompileType ComputeType() const;
8015
8016 virtual Definition* Canonicalize(FlowGraph* flow_graph);
8017
8018 Value* object() const { return inputs_[0]; }
8019
8020 virtual bool ComputeCanDeoptimize() const { return false; }
8021
8022 virtual bool AttributesEqual(const Instruction& other) const {
8023 auto const other_load = other.AsLoadClassId();
8024 return other_load->representation_ == representation_ &&
8025 other_load->input_can_be_smi_ == input_can_be_smi_;
8026 }
8027
8028 void InferRange(uword* lower, uword* upper);
8029 virtual void InferRange(RangeAnalysis* analysis, Range* range);
8030
8032
8033#define FIELD_LIST(F) \
8034 F(const Representation, representation_) \
8035 F(const bool, input_can_be_smi_)
8036
8039 FIELD_LIST)
8040#undef FIELD_LIST
8041
8042 private:
8044};
8045
8046// LoadFieldInstr represents a load from the given [slot] in the given
8047// [instance]. If calls_initializer(), then LoadFieldInstr also calls field
8048// initializer if field is not initialized yet (contains sentinel value).
8049//
8050// Note: if slot was a subject of the field unboxing optimization then this load
8051// would both load the box stored in the field and then load the content of
8052// the box.
8054 public:
8056 const Slot& slot,
8057 InnerPointerAccess loads_inner_pointer,
8059 bool calls_initializer = false,
8060 intptr_t deopt_id = DeoptId::kNone)
8062 calls_initializer,
8063 deopt_id,
8064 slot.IsDartField() ? &slot.field() : nullptr),
8065 slot_(slot),
8066 loads_inner_pointer_(loads_inner_pointer) {
8067 switch (loads_inner_pointer) {
8068 case InnerPointerAccess::kNotUntagged:
8069 ASSERT(slot.representation() != kUntagged);
8070 break;
8071 case InnerPointerAccess::kMayBeInnerPointer:
8072 ASSERT(slot.representation() == kUntagged);
8074 break;
8075 case InnerPointerAccess::kCannotBeInnerPointer:
8076 ASSERT(slot.representation() == kUntagged);
8077 break;
8078 }
8079 SetInputAt(0, instance);
8080 }
8081
8082 // Convenience function for slots that cannot hold untagged addresses.
8084 const Slot& slot,
8086 bool calls_initializer = false,
8087 intptr_t deopt_id = DeoptId::kNone)
8089 slot,
8091 source,
8092 calls_initializer,
8093 deopt_id) {}
8094
8095 Value* instance() const { return inputs_[0]; }
8096 const Slot& slot() const { return slot_; }
8097
8099 return loads_inner_pointer_;
8100 }
8102 // We should never change this for a non-untagged field.
8103 ASSERT(loads_inner_pointer_ != InnerPointerAccess::kNotUntagged);
8104 // We only convert from may to cannot, never the other direction.
8105 ASSERT(value == InnerPointerAccess::kCannotBeInnerPointer);
8106 loads_inner_pointer_ = value;
8107 }
8108
8109 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
8110 ASSERT_EQUAL(idx, 0);
8111 return slot_.has_untagged_instance() ? kUntagged : kTagged;
8112 }
8113
8114 virtual Representation representation() const;
8115
8116 DECLARE_INSTRUCTION(LoadField)
8117 DECLARE_ATTRIBUTE(&slot())
8118
8119 virtual CompileType ComputeType() const;
8120
8121 virtual void InferRange(RangeAnalysis* analysis, Range* range);
8122
8123 // Whether the load may return an untagged pointer that points to memory
8124 // within the instance.
8125 bool MayCreateUntaggedAlias() const;
8126
8127 virtual bool MayCreateUnsafeUntaggedPointer() const;
8128
8129 bool IsImmutableLoad() const {
8130 // The data() field in PointerBase is marked mutable, but is not actually
8131 // mutable if it doesn't contain an inner pointer (e.g., for external
8132 // typed data and Pointer objects).
8133 if (slot().IsIdentical(Slot::PointerBase_data())) {
8134 return loads_inner_pointer() != InnerPointerAccess::kMayBeInnerPointer;
8135 }
8136 return slot().is_immutable();
8137 }
8138
8139 bool IsImmutableLengthLoad() const { return slot().IsImmutableLengthSlot(); }
8140
8141 // Try evaluating this load against the given constant value of
8142 // the instance. Returns true if evaluation succeeded and
8143 // puts result into result.
8144 // Note: we only evaluate loads when we can ensure that
8145 // instance has the field.
8146 bool Evaluate(const Object& instance_value, Object* result);
8147
8148 static bool TryEvaluateLoad(const Object& instance,
8149 const Field& field,
8150 Object* result);
8151
8152 static bool TryEvaluateLoad(const Object& instance,
8153 const Slot& field,
8154 Object* result);
8155
8156 virtual Definition* Canonicalize(FlowGraph* flow_graph);
8157
8158 static bool IsFixedLengthArrayCid(intptr_t cid);
8159 static bool IsTypedDataViewFactory(const Function& function);
8160 static bool IsUnmodifiableTypedDataViewFactory(const Function& function);
8161
8162 virtual bool AllowsCSE() const { return slot_.is_immutable(); }
8163
8164 virtual bool CanTriggerGC() const { return calls_initializer(); }
8165
8166 virtual bool AttributesEqual(const Instruction& other) const;
8167
8169
8170#define FIELD_LIST(F) \
8171 F(const Slot&, slot_) \
8172 F(InnerPointerAccess, loads_inner_pointer_)
8173
8176 FIELD_LIST)
8177#undef FIELD_LIST
8178
8179 private:
8180 intptr_t OffsetInBytes() const { return slot().offset_in_bytes(); }
8181
8182 // Generate code which checks if field is initialized and
8183 // calls initializer if it is not. Field value is already loaded.
8184 void EmitNativeCodeForInitializerCall(FlowGraphCompiler* compiler);
8185
8187};
8188
8189class InstantiateTypeInstr : public TemplateDefinition<2, Throws> {
8190 public:
8192 const AbstractType& type,
8193 Value* instantiator_type_arguments,
8194 Value* function_type_arguments,
8195 intptr_t deopt_id)
8196 : TemplateDefinition(source, deopt_id),
8197 token_pos_(source.token_pos),
8198 type_(type) {
8199 DEBUG_ASSERT(type.IsNotTemporaryScopedHandle());
8200 SetInputAt(0, instantiator_type_arguments);
8201 SetInputAt(1, function_type_arguments);
8202 }
8203
8204 DECLARE_INSTRUCTION(InstantiateType)
8205
8206 Value* instantiator_type_arguments() const { return inputs_[0]; }
8207 Value* function_type_arguments() const { return inputs_[1]; }
8208 const AbstractType& type() const { return type_; }
8209 virtual TokenPosition token_pos() const { return token_pos_; }
8210
8211 virtual bool ComputeCanDeoptimize() const { return false; }
8212 virtual bool ComputeCanDeoptimizeAfterCall() const {
8213 return !CompilerState::Current().is_aot();
8214 }
8215 virtual intptr_t NumberOfInputsConsumedBeforeCall() const {
8216 return InputCount();
8217 }
8218
8219 virtual bool HasUnknownSideEffects() const { return false; }
8220
8222
8223#define FIELD_LIST(F) \
8224 F(const TokenPosition, token_pos_) \
8225 F(const AbstractType&, type_)
8226
8229 FIELD_LIST)
8230#undef FIELD_LIST
8231
8232 private:
8234};
8235
8237 public:
8239 Value* instantiator_type_arguments,
8240 Value* function_type_arguments,
8241 Value* type_arguments,
8242 const Class& instantiator_class,
8243 const Function& function,
8244 intptr_t deopt_id)
8245 : TemplateDefinition(source, deopt_id),
8246 token_pos_(source.token_pos),
8247 instantiator_class_(instantiator_class),
8248 function_(function) {
8249 DEBUG_ASSERT(instantiator_class.IsNotTemporaryScopedHandle());
8250 DEBUG_ASSERT(function.IsNotTemporaryScopedHandle());
8251 SetInputAt(0, instantiator_type_arguments);
8252 SetInputAt(1, function_type_arguments);
8253 SetInputAt(2, type_arguments);
8254 }
8255
8256 DECLARE_INSTRUCTION(InstantiateTypeArguments)
8257
8258 Value* instantiator_type_arguments() const { return inputs_[0]; }
8259 Value* function_type_arguments() const { return inputs_[1]; }
8260 Value* type_arguments() const { return inputs_[2]; }
8261 const Class& instantiator_class() const { return instantiator_class_; }
8262 const Function& function() const { return function_; }
8263 virtual TokenPosition token_pos() const { return token_pos_; }
8264
8265 virtual bool ComputeCanDeoptimize() const { return false; }
8266 virtual bool ComputeCanDeoptimizeAfterCall() const {
8267 return !CompilerState::Current().is_aot();
8268 }
8269 virtual intptr_t NumberOfInputsConsumedBeforeCall() const {
8270 return InputCount();
8271 }
8272
8273 virtual bool HasUnknownSideEffects() const { return false; }
8274
8275 virtual Definition* Canonicalize(FlowGraph* flow_graph);
8276
8278 bool* with_runtime_check = nullptr) const {
8279 if (instantiator_class().IsNull() || !type_arguments()->BindsToConstant() ||
8280 !type_arguments()->BoundConstant().IsTypeArguments()) {
8281 return false;
8282 }
8283 const auto& type_args =
8284 TypeArguments::Cast(type_arguments()->BoundConstant());
8285 return type_args.CanShareInstantiatorTypeArguments(instantiator_class(),
8286 with_runtime_check);
8287 }
8288
8289 bool CanShareFunctionTypeArguments(bool* with_runtime_check = nullptr) const {
8290 if (function().IsNull() || !type_arguments()->BindsToConstant() ||
8291 !type_arguments()->BoundConstant().IsTypeArguments()) {
8292 return false;
8293 }
8294 const auto& type_args =
8295 TypeArguments::Cast(type_arguments()->BoundConstant());
8296 return type_args.CanShareFunctionTypeArguments(function(),
8297 with_runtime_check);
8298 }
8299
8300 const Code& GetStub() const {
8301 bool with_runtime_check;
8302 if (CanShareInstantiatorTypeArguments(&with_runtime_check)) {
8303 ASSERT(with_runtime_check);
8304 return StubCode::InstantiateTypeArgumentsMayShareInstantiatorTA();
8305 } else if (CanShareFunctionTypeArguments(&with_runtime_check)) {
8306 ASSERT(with_runtime_check);
8307 return StubCode::InstantiateTypeArgumentsMayShareFunctionTA();
8308 }
8309 return StubCode::InstantiateTypeArguments();
8310 }
8311
8313
8314#define FIELD_LIST(F) \
8315 F(const TokenPosition, token_pos_) \
8316 F(const Class&, instantiator_class_) \
8317 F(const Function&, function_)
8318
8321 FIELD_LIST)
8322#undef FIELD_LIST
8323
8324 private:
8326};
8327
8328// [AllocateContext] instruction allocates a new Context object with the space
8329// for the given [context_variables].
8331 public:
8333 const ZoneGrowableArray<const Slot*>& context_slots,
8334 intptr_t deopt_id)
8335 : TemplateAllocation(source, deopt_id), context_slots_(context_slots) {}
8336
8337 DECLARE_INSTRUCTION(AllocateContext)
8338 virtual CompileType ComputeType() const;
8339
8341 return context_slots_;
8342 }
8343
8344 intptr_t num_context_variables() const { return context_slots().length(); }
8345
8346 virtual Definition* Canonicalize(FlowGraph* flow_graph);
8347
8348 virtual bool ComputeCanDeoptimize() const { return false; }
8349
8350 virtual bool HasUnknownSideEffects() const { return false; }
8351
8352 virtual bool WillAllocateNewOrRemembered() const {
8353 return compiler::target::WillAllocateNewOrRememberedContext(
8354 context_slots().length());
8355 }
8356
8358
8359#define FIELD_LIST(F) F(const ZoneGrowableArray<const Slot*>&, context_slots_)
8360
8363 FIELD_LIST)
8364#undef FIELD_LIST
8365
8366 private:
8368};
8369
8370// [CloneContext] instruction clones the given Context object assuming that
8371// it contains exactly the provided [context_variables].
8372class CloneContextInstr : public TemplateDefinition<1, Throws> {
8373 public:
8375 Value* context_value,
8376 const ZoneGrowableArray<const Slot*>& context_slots,
8377 intptr_t deopt_id)
8378 : TemplateDefinition(source, deopt_id),
8379 token_pos_(source.token_pos),
8380 context_slots_(context_slots) {
8381 SetInputAt(0, context_value);
8382 }
8383
8384 virtual TokenPosition token_pos() const { return token_pos_; }
8385 Value* context_value() const { return inputs_[0]; }
8386
8388 return context_slots_;
8389 }
8390
8391 DECLARE_INSTRUCTION(CloneContext)
8392 virtual CompileType ComputeType() const;
8393
8394 virtual bool ComputeCanDeoptimize() const { return false; }
8395 virtual bool ComputeCanDeoptimizeAfterCall() const {
8396 // We test that allocation instructions have correct deopt environment
8397 // (which is needed in case OOM is thrown) by actually deoptimizing
8398 // optimized code in allocation slow paths.
8399 return !CompilerState::Current().is_aot();
8400 }
8401 virtual intptr_t NumberOfInputsConsumedBeforeCall() const {
8402 return InputCount();
8403 }
8404
8405 virtual bool HasUnknownSideEffects() const { return false; }
8406
8407#define FIELD_LIST(F) \
8408 F(const TokenPosition, token_pos_) \
8409 F(const ZoneGrowableArray<const Slot*>&, context_slots_)
8410
8413 FIELD_LIST)
8414#undef FIELD_LIST
8415
8416 private:
8418};
8419
8420class CheckEitherNonSmiInstr : public TemplateInstruction<2, NoThrow, Pure> {
8421 public:
8423 : TemplateInstruction(deopt_id) {
8424 SetInputAt(0, left);
8425 SetInputAt(1, right);
8426 }
8427
8428 Value* left() const { return inputs_[0]; }
8429 Value* right() const { return inputs_[1]; }
8430
8431 DECLARE_INSTRUCTION(CheckEitherNonSmi)
8432
8433 virtual bool ComputeCanDeoptimize() const { return true; }
8434
8435 virtual Instruction* Canonicalize(FlowGraph* flow_graph);
8436
8437 virtual bool AttributesEqual(const Instruction& other) const { return true; }
8438
8440
8441 private:
8443};
8444
8445struct Boxing : public AllStatic {
8446 // Whether the given representation can be boxed or unboxed.
8447 static bool Supports(Representation rep);
8448
8449 // The native representation that results from unboxing a value with the
8450 // representation [rep].
8451 //
8452 // The native representation can hold all values represented by [rep], but
8453 // may be larger than the value size of [rep]. For example, byte-sized
8454 // values are zero or sign-extended to word-sized values on x86 architectures
8455 // to avoid having to allocate byte registers.
8457 // Only change integer representations.
8458 if (!RepresentationUtils::IsUnboxedInteger(rep)) return rep;
8459 // Use signed word-sized integers for representations smaller than 4 bytes.
8460 return RepresentationUtils::ValueSize(rep) < 4 ? kUnboxedIntPtr : rep;
8461 }
8462
8463 // Whether boxing this value requires allocating a new object.
8464 static bool RequiresAllocation(Representation rep);
8465
8466 // The offset into the Layout object for the boxed value that can store
8467 // the full range of values in the representation.
8468 // Only defined for allocated boxes (i.e., RequiresAllocation must be true).
8469 static intptr_t ValueOffset(Representation rep);
8470
8471 // The class ID for the boxed value that can store the full range
8472 // of values in the representation.
8473 static intptr_t BoxCid(Representation rep);
8474};
8475
8476class BoxInstr : public TemplateDefinition<1, NoThrow, Pure> {
8477 public:
8478 static BoxInstr* Create(Representation from, Value* value);
8479
8480 Value* value() const { return inputs_[0]; }
8481 Representation from_representation() const { return from_representation_; }
8482
8484 virtual CompileType ComputeType() const;
8485
8486 virtual bool ComputeCanDeoptimize() const { return false; }
8487 virtual intptr_t DeoptimizationTarget() const { return DeoptId::kNone; }
8488
8489 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
8490 ASSERT(idx == 0);
8491 return from_representation();
8492 }
8493
8494 virtual bool AttributesEqual(const Instruction& other) const {
8495 return other.AsBox()->from_representation() == from_representation();
8496 }
8497
8498 Definition* Canonicalize(FlowGraph* flow_graph);
8499
8500 virtual TokenPosition token_pos() const { return TokenPosition::kBox; }
8501
8502 virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const {
8503 return kNotSpeculative;
8504 }
8505
8506#define FIELD_LIST(F) F(const Representation, from_representation_)
8507
8510 FIELD_LIST)
8511#undef FIELD_LIST
8512
8513 protected:
8514 BoxInstr(Representation from_representation, Value* value)
8515 : from_representation_(from_representation) {
8516 SetInputAt(0, value);
8517 }
8518
8519 private:
8520 intptr_t ValueOffset() const {
8521 return Boxing::ValueOffset(from_representation());
8522 }
8523
8524 DISALLOW_COPY_AND_ASSIGN(BoxInstr);
8525};
8526
8528 public:
8529 BoxIntegerInstr(Representation representation, Value* value)
8530 : BoxInstr(representation, value) {}
8531
8532 virtual bool ValueFitsSmi() const;
8533
8534 virtual void InferRange(RangeAnalysis* analysis, Range* range);
8535
8536 virtual CompileType ComputeType() const;
8537 virtual bool RecomputeType();
8538
8539 virtual Definition* Canonicalize(FlowGraph* flow_graph);
8540
8541 virtual bool CanTriggerGC() const { return !ValueFitsSmi(); }
8542
8544
8546
8547 private:
8549};
8550
8552 public:
8554 : BoxIntegerInstr(rep, value) {
8555 ASSERT(RepresentationUtils::ValueSize(rep) * kBitsPerByte <=
8556 compiler::target::kSmiBits);
8557 }
8558
8559 virtual bool ValueFitsSmi() const { return true; }
8560
8561 DECLARE_INSTRUCTION(BoxSmallInt)
8562
8564
8565 private:
8567};
8568
8570 public:
8572 : BoxIntegerInstr(representation, value) {}
8573
8575
8577
8578 private:
8580};
8581
8583 public:
8584 explicit BoxInt32Instr(Value* value)
8585 : BoxInteger32Instr(kUnboxedInt32, value) {}
8586
8588
8590
8591 private:
8593};
8594
8596 public:
8597 explicit BoxUint32Instr(Value* value)
8598 : BoxInteger32Instr(kUnboxedUint32, value) {}
8599
8601
8603
8604 private:
8606};
8607
8609 public:
8610 explicit BoxInt64Instr(Value* value)
8611 : BoxIntegerInstr(kUnboxedInt64, value) {}
8612
8613 virtual Definition* Canonicalize(FlowGraph* flow_graph);
8614
8615 DECLARE_INSTRUCTION(BoxInt64)
8616
8618
8619 private:
8621};
8622
8623class UnboxInstr : public TemplateDefinition<1, NoThrow, Pure> {
8624 public:
8625 static UnboxInstr* Create(Representation to,
8626 Value* value,
8627 intptr_t deopt_id,
8628 SpeculativeMode speculative_mode = kGuardInputs);
8629
8630 Value* value() const { return inputs_[0]; }
8631
8632 virtual bool ComputeCanDeoptimize() const {
8633 if (SpeculativeModeOfInputs() == kNotSpeculative) {
8634 return false;
8635 }
8636
8637 const intptr_t value_cid = value()->Type()->ToCid();
8638 const intptr_t box_cid = BoxCid();
8639
8640 if (value_cid == box_cid) {
8641 return false;
8642 }
8643
8644 if (CanConvertSmi() && (value_cid == kSmiCid)) {
8645 return false;
8646 }
8647
8648 return true;
8649 }
8650
8651 virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const {
8652 return speculative_mode_;
8653 }
8654
8655 virtual Representation representation() const { return representation_; }
8656
8657 DECLARE_INSTRUCTION(Unbox)
8658
8659 virtual bool AttributesEqual(const Instruction& other) const {
8660 auto const other_unbox = other.AsUnbox();
8661 return (representation() == other_unbox->representation()) &&
8662 (speculative_mode_ == other_unbox->speculative_mode_);
8663 }
8664
8665 Definition* Canonicalize(FlowGraph* flow_graph);
8666
8667 virtual intptr_t DeoptimizationTarget() const { return GetDeoptId(); }
8668
8669 virtual TokenPosition token_pos() const { return TokenPosition::kBox; }
8670
8671#define FIELD_LIST(F) \
8672 F(const Representation, representation_) \
8673 F(SpeculativeMode, speculative_mode_)
8674
8677 FIELD_LIST)
8678#undef FIELD_LIST
8679
8680 protected:
8681 UnboxInstr(Representation representation,
8682 Value* value,
8683 intptr_t deopt_id,
8684 SpeculativeMode speculative_mode)
8685 : TemplateDefinition(deopt_id),
8686 representation_(representation),
8687 speculative_mode_(speculative_mode) {
8688 // Unboxing doesn't currently handle non-native representations.
8689 ASSERT_EQUAL(Boxing::NativeRepresentation(representation), representation);
8690 SetInputAt(0, value);
8691 }
8692
8693 void set_speculative_mode(SpeculativeMode value) {
8694 speculative_mode_ = value;
8695 }
8696
8697 private:
8698 bool CanConvertSmi() const;
8699 void EmitLoadFromBox(FlowGraphCompiler* compiler);
8700 void EmitSmiConversion(FlowGraphCompiler* compiler);
8701 void EmitLoadInt32FromBoxOrSmi(FlowGraphCompiler* compiler);
8702 void EmitLoadInt64FromBoxOrSmi(FlowGraphCompiler* compiler);
8703 void EmitLoadFromBoxWithDeopt(FlowGraphCompiler* compiler);
8704
8705 intptr_t BoxCid() const { return Boxing::BoxCid(representation_); }
8706
8707 intptr_t ValueOffset() const { return Boxing::ValueOffset(representation_); }
8708
8709 DISALLOW_COPY_AND_ASSIGN(UnboxInstr);
8710};
8711
8713 public:
8714 enum TruncationMode { kTruncate, kNoTruncation };
8715
8717 TruncationMode truncation_mode,
8718 Value* value,
8719 intptr_t deopt_id,
8720 SpeculativeMode speculative_mode)
8721 : UnboxInstr(representation, value, deopt_id, speculative_mode),
8722 is_truncating_(truncation_mode == kTruncate) {}
8723
8724 bool is_truncating() const { return is_truncating_; }
8725
8726 void mark_truncating() { is_truncating_ = true; }
8727
8728 virtual bool ComputeCanDeoptimize() const;
8729
8730 virtual bool AttributesEqual(const Instruction& other) const {
8731 auto const other_unbox = other.AsUnboxInteger();
8732 return UnboxInstr::AttributesEqual(other) &&
8733 (other_unbox->is_truncating_ == is_truncating_);
8734 }
8735
8736 virtual Definition* Canonicalize(FlowGraph* flow_graph);
8737
8738 virtual void InferRange(RangeAnalysis* analysis, Range* range);
8739
8740 DECLARE_ABSTRACT_INSTRUCTION(UnboxInteger)
8741
8743
8744#define FIELD_LIST(F) F(bool, is_truncating_)
8745
8747 UnboxInstr,
8748 FIELD_LIST)
8749#undef FIELD_LIST
8750
8751 private:
8753};
8754
8756 public:
8758 TruncationMode truncation_mode,
8759 Value* value,
8760 intptr_t deopt_id,
8761 SpeculativeMode speculative_mode)
8762 : UnboxIntegerInstr(representation,
8763 truncation_mode,
8764 value,
8765 deopt_id,
8766 speculative_mode) {}
8767
8769
8771
8772 private:
8774};
8775
8777 public:
8779 intptr_t deopt_id,
8780 SpeculativeMode speculative_mode = kGuardInputs)
8781 : UnboxInteger32Instr(kUnboxedUint32,
8782 kTruncate,
8783 value,
8784 deopt_id,
8785 speculative_mode) {
8786 ASSERT(is_truncating());
8787 }
8788
8790
8792
8793 private:
8795};
8796
8798 public:
8800 Value* value,
8801 intptr_t deopt_id,
8802 SpeculativeMode speculative_mode = kGuardInputs)
8803 : UnboxInteger32Instr(kUnboxedInt32,
8804 truncation_mode,
8805 value,
8806 deopt_id,
8807 speculative_mode) {}
8808
8810
8812
8813 private:
8815};
8816
8818 public:
8820 intptr_t deopt_id,
8821 SpeculativeMode speculative_mode)
8822 : UnboxIntegerInstr(kUnboxedInt64,
8823 kNoTruncation,
8824 value,
8825 deopt_id,
8826 speculative_mode) {}
8827
8829
8831
8832 private:
8834};
8835
8836bool Definition::IsInt64Definition() {
8837 return (Type()->ToCid() == kMintCid) || IsBinaryInt64Op() ||
8838 IsUnaryInt64Op() || IsShiftInt64Op() || IsSpeculativeShiftInt64Op() ||
8839 IsBoxInt64() || IsUnboxInt64();
8840}
8841
8842// Calls into the runtime and performs a case-insensitive comparison of the
8843// UTF16 strings (i.e. TwoByteString) located at
8844// str[lhs_index:lhs_index + length] and str[rhs_index:rhs_index + length].
8845// Depending on [handle_surrogates], we will treat the strings as either
8846// UCS2 (no surrogate handling) or UTF16 (surrogates handled appropriately).
8848 : public TemplateDefinition<4, NoThrow, Pure> {
8849 public:
8851 Value* lhs_index,
8852 Value* rhs_index,
8853 Value* length,
8854 bool handle_surrogates,
8855 intptr_t cid)
8856 : handle_surrogates_(handle_surrogates), cid_(cid) {
8857 ASSERT(cid == kTwoByteStringCid);
8858 ASSERT(index_scale() == 2);
8859 SetInputAt(0, str);
8860 SetInputAt(1, lhs_index);
8861 SetInputAt(2, rhs_index);
8862 SetInputAt(3, length);
8863 }
8864
8865 Value* str() const { return inputs_[0]; }
8866 Value* lhs_index() const { return inputs_[1]; }
8867 Value* rhs_index() const { return inputs_[2]; }
8868 Value* length() const { return inputs_[3]; }
8869
8870 const RuntimeEntry& TargetFunction() const;
8871 intptr_t class_id() const { return cid_; }
8872
8873 intptr_t index_scale() const {
8874 return compiler::target::Instance::ElementSizeFor(cid_);
8875 }
8876
8877 virtual bool ComputeCanDeoptimize() const { return false; }
8878
8879 virtual Representation representation() const { return kTagged; }
8880
8881 DECLARE_INSTRUCTION(CaseInsensitiveCompare)
8882 virtual CompileType ComputeType() const;
8883
8884 virtual bool AttributesEqual(const Instruction& other) const {
8885 const auto* other_compare = other.AsCaseInsensitiveCompare();
8886 return (other_compare->handle_surrogates_ == handle_surrogates_) &&
8887 (other_compare->cid_ == cid_);
8888 }
8889
8890#define FIELD_LIST(F) \
8891 F(const bool, handle_surrogates_) \
8892 F(const intptr_t, cid_)
8893
8896 FIELD_LIST)
8897#undef FIELD_LIST
8898
8899 private:
8901};
8902
8903// Represents Math's static min and max functions.
8904class MathMinMaxInstr : public TemplateDefinition<2, NoThrow, Pure> {
8905 public:
8907 Value* left_value,
8908 Value* right_value,
8909 intptr_t deopt_id,
8910 intptr_t result_cid)
8911 : TemplateDefinition(deopt_id),
8912 op_kind_(op_kind),
8913 result_cid_(result_cid) {
8914 ASSERT((result_cid == kSmiCid) || (result_cid == kDoubleCid));
8915 SetInputAt(0, left_value);
8916 SetInputAt(1, right_value);
8917 }
8918
8919 MethodRecognizer::Kind op_kind() const { return op_kind_; }
8920
8921 Value* left() const { return inputs_[0]; }
8922 Value* right() const { return inputs_[1]; }
8923
8924 intptr_t result_cid() const { return result_cid_; }
8925
8926 virtual bool ComputeCanDeoptimize() const { return false; }
8927
8929 if (result_cid() == kSmiCid) {
8930 return kTagged;
8931 }
8932 ASSERT(result_cid() == kDoubleCid);
8933 return kUnboxedDouble;
8934 }
8935
8936 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
8937 if (result_cid() == kSmiCid) {
8938 return kTagged;
8939 }
8940 ASSERT(result_cid() == kDoubleCid);
8941 return kUnboxedDouble;
8942 }
8943
8944 virtual intptr_t DeoptimizationTarget() const {
8945 // Direct access since this instruction cannot deoptimize, and the deopt-id
8946 // was inherited from another instruction that could deoptimize.
8947 return GetDeoptId();
8948 }
8949
8950 DECLARE_INSTRUCTION(MathMinMax)
8951 virtual CompileType ComputeType() const;
8952 virtual bool AttributesEqual(const Instruction& other) const;
8953
8954#define FIELD_LIST(F) \
8955 F(const MethodRecognizer::Kind, op_kind_) \
8956 F(const intptr_t, result_cid_)
8957
8960 FIELD_LIST)
8961#undef FIELD_LIST
8962
8963 private:
8965};
8966
8967class BinaryDoubleOpInstr : public TemplateDefinition<2, NoThrow, Pure> {
8968 public:
8970 Value* left,
8971 Value* right,
8972 intptr_t deopt_id,
8974 SpeculativeMode speculative_mode = kGuardInputs,
8975 Representation representation = kUnboxedDouble)
8976 : TemplateDefinition(source, deopt_id),
8977 op_kind_(op_kind),
8978 token_pos_(source.token_pos),
8979 speculative_mode_(speculative_mode),
8980 representation_(representation) {
8981 ASSERT((representation == kUnboxedFloat) ||
8982 (representation == kUnboxedDouble));
8983 SetInputAt(0, left);
8984 SetInputAt(1, right);
8985 }
8986
8987 Value* left() const { return inputs_[0]; }
8988 Value* right() const { return inputs_[1]; }
8989
8990 Token::Kind op_kind() const { return op_kind_; }
8991
8992 virtual TokenPosition token_pos() const { return token_pos_; }
8993
8994 virtual bool ComputeCanDeoptimize() const { return false; }
8995
8996 virtual Representation representation() const { return representation_; }
8997
8998 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
8999 ASSERT((idx == 0) || (idx == 1));
9000 return representation_;
9001 }
9002
9003 virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const {
9004 return speculative_mode_;
9005 }
9006
9007 virtual intptr_t DeoptimizationTarget() const {
9008 // Direct access since this instruction cannot deoptimize, and the deopt-id
9009 // was inherited from another instruction that could deoptimize.
9010 return GetDeoptId();
9011 }
9012
9013 DECLARE_ATTRIBUTE(op_kind())
9014
9016
9017 DECLARE_INSTRUCTION(BinaryDoubleOp)
9018
9019 virtual Definition* Canonicalize(FlowGraph* flow_graph);
9020
9021 virtual bool AttributesEqual(const Instruction& other) const {
9022 auto const other_bin_op = other.AsBinaryDoubleOp();
9023 return (op_kind() == other_bin_op->op_kind()) &&
9024 (speculative_mode_ == other_bin_op->speculative_mode_) &&
9025 (representation_ == other_bin_op->representation_);
9026 }
9027
9028#define FIELD_LIST(F) \
9029 F(const Token::Kind, op_kind_) \
9030 F(const TokenPosition, token_pos_) \
9031 F(const SpeculativeMode, speculative_mode_) \
9032 F(const Representation, representation_)
9033
9036 FIELD_LIST)
9037#undef FIELD_LIST
9038
9039 private:
9041};
9042
9043class DoubleTestOpInstr : public TemplateComparison<1, NoThrow, Pure> {
9044 public:
9046 Value* value,
9047 intptr_t deopt_id,
9049 : TemplateComparison(source, Token::kEQ, deopt_id), op_kind_(op_kind) {
9050 SetInputAt(0, value);
9051 }
9052
9053 Value* value() const { return InputAt(0); }
9054
9055 MethodRecognizer::Kind op_kind() const { return op_kind_; }
9056
9057 virtual bool ComputeCanDeoptimize() const { return false; }
9058
9059 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
9060 ASSERT(idx == 0);
9061 return kUnboxedDouble;
9062 }
9063
9065
9066 DECLARE_COMPARISON_INSTRUCTION(DoubleTestOp)
9067
9068 virtual CompileType ComputeType() const;
9069
9070 virtual Definition* Canonicalize(FlowGraph* flow_graph);
9071
9072 virtual bool AttributesEqual(const Instruction& other) const {
9073 return op_kind_ == other.AsDoubleTestOp()->op_kind() &&
9074 ComparisonInstr::AttributesEqual(other);
9075 }
9076
9077 virtual ComparisonInstr* CopyWithNewOperands(Value* left, Value* right);
9078
9079#define FIELD_LIST(F) F(const MethodRecognizer::Kind, op_kind_)
9080
9083 FIELD_LIST)
9084#undef FIELD_LIST
9085
9086 private:
9088};
9089
9090class HashDoubleOpInstr : public TemplateDefinition<1, NoThrow, Pure> {
9091 public:
9092 HashDoubleOpInstr(Value* value, intptr_t deopt_id)
9093 : TemplateDefinition(deopt_id) {
9094 SetInputAt(0, value);
9095 }
9096
9097 static HashDoubleOpInstr* Create(Value* value, intptr_t deopt_id) {
9098 return new HashDoubleOpInstr(value, deopt_id);
9099 }
9100
9101 Value* value() const { return inputs_[0]; }
9102
9103 virtual intptr_t DeoptimizationTarget() const {
9104 // Direct access since this instruction cannot deoptimize, and the deopt-id
9105 // was inherited from another instruction that could deoptimize.
9106 return GetDeoptId();
9107 }
9108
9109 virtual Representation representation() const { return kUnboxedInt64; }
9110
9111 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
9112 ASSERT(idx == 0);
9113 return kUnboxedDouble;
9114 }
9115
9116 DECLARE_INSTRUCTION(HashDoubleOp)
9117
9118 virtual bool ComputeCanDeoptimize() const { return false; }
9119
9120 virtual CompileType ComputeType() const { return CompileType::Smi(); }
9121
9122 virtual bool AttributesEqual(const Instruction& other) const { return true; }
9123
9125
9126 private:
9128};
9129
9130class HashIntegerOpInstr : public TemplateDefinition<1, NoThrow, Pure> {
9131 public:
9132 HashIntegerOpInstr(Value* value, bool smi, intptr_t deopt_id)
9133 : TemplateDefinition(deopt_id), smi_(smi) {
9134 SetInputAt(0, value);
9135 }
9136
9137 static HashIntegerOpInstr* Create(Value* value, bool smi, intptr_t deopt_id) {
9138 return new HashIntegerOpInstr(value, smi, deopt_id);
9139 }
9140
9141 Value* value() const { return inputs_[0]; }
9142
9143 virtual intptr_t DeoptimizationTarget() const {
9144 // Direct access since this instruction cannot deoptimize, and the deopt-id
9145 // was inherited from another instruction that could deoptimize.
9146 return GetDeoptId();
9147 }
9148
9149 virtual Representation representation() const { return kTagged; }
9150
9151 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
9152 ASSERT(idx == 0);
9153 return kTagged;
9154 }
9155
9156 DECLARE_INSTRUCTION(HashIntegerOp)
9157
9158 virtual bool ComputeCanDeoptimize() const { return false; }
9159
9160 virtual CompileType ComputeType() const { return CompileType::Smi(); }
9161
9162 virtual bool AttributesEqual(const Instruction& other) const { return true; }
9163
9164#define FIELD_LIST(F) F(const bool, smi_)
9165
9168 FIELD_LIST)
9169#undef FIELD_LIST
9170
9172
9173 private:
9175};
9176
9177class UnaryIntegerOpInstr : public TemplateDefinition<1, NoThrow, Pure> {
9178 public:
9179 UnaryIntegerOpInstr(Token::Kind op_kind, Value* value, intptr_t deopt_id)
9180 : TemplateDefinition(deopt_id), op_kind_(op_kind) {
9181 ASSERT((op_kind == Token::kNEGATE) || (op_kind == Token::kBIT_NOT));
9182 SetInputAt(0, value);
9183 }
9184
9185 static UnaryIntegerOpInstr* Make(Representation representation,
9186 Token::Kind op_kind,
9187 Value* value,
9188 intptr_t deopt_id,
9189 SpeculativeMode speculative_mode,
9190 Range* range);
9191
9192 Value* value() const { return inputs_[0]; }
9193 Token::Kind op_kind() const { return op_kind_; }
9194
9195 virtual Definition* Canonicalize(FlowGraph* flow_graph);
9196
9197 virtual bool AttributesEqual(const Instruction& other) const {
9198 return other.AsUnaryIntegerOp()->op_kind() == op_kind();
9199 }
9200
9201 virtual intptr_t DeoptimizationTarget() const {
9202 // Direct access since this instruction cannot deoptimize, and the deopt-id
9203 // was inherited from another instruction that could deoptimize.
9204 return GetDeoptId();
9205 }
9206
9208
9209 DECLARE_ABSTRACT_INSTRUCTION(UnaryIntegerOp)
9210
9211 DECLARE_ATTRIBUTE(op_kind())
9212
9213#define FIELD_LIST(F) F(const Token::Kind, op_kind_)
9214
9217 FIELD_LIST)
9218#undef FIELD_LIST
9219
9220 private:
9222};
9223
9224// Handles both Smi operations: BIT_OR and NEGATE.
9226 public:
9227 UnarySmiOpInstr(Token::Kind op_kind, Value* value, intptr_t deopt_id)
9228 : UnaryIntegerOpInstr(op_kind, value, deopt_id) {}
9229
9230 virtual bool ComputeCanDeoptimize() const {
9231 return op_kind() == Token::kNEGATE;
9232 }
9233
9234 virtual CompileType ComputeType() const;
9235
9236 DECLARE_INSTRUCTION(UnarySmiOp)
9237
9239
9240 private:
9242};
9243
9245 public:
9246 UnaryUint32OpInstr(Token::Kind op_kind, Value* value, intptr_t deopt_id)
9247 : UnaryIntegerOpInstr(op_kind, value, deopt_id) {
9248 ASSERT(IsSupported(op_kind));
9249 }
9250
9251 virtual bool ComputeCanDeoptimize() const { return false; }
9252
9253 virtual Representation representation() const { return kUnboxedUint32; }
9254
9255 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
9256 ASSERT(idx == 0);
9257 return kUnboxedUint32;
9258 }
9259
9260 static bool IsSupported(Token::Kind op_kind) {
9261 return op_kind == Token::kBIT_NOT;
9262 }
9263
9264 DECLARE_INSTRUCTION(UnaryUint32Op)
9265
9267
9268 private:
9270};
9271
9273 public:
9275 Value* value,
9276 intptr_t deopt_id,
9277 SpeculativeMode speculative_mode = kGuardInputs)
9278 : UnaryIntegerOpInstr(op_kind, value, deopt_id),
9279 speculative_mode_(speculative_mode) {
9280 ASSERT(op_kind == Token::kBIT_NOT || op_kind == Token::kNEGATE);
9281 }
9282
9283 virtual bool ComputeCanDeoptimize() const { return false; }
9284
9285 virtual Representation representation() const { return kUnboxedInt64; }
9286
9287 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
9288 ASSERT(idx == 0);
9289 return kUnboxedInt64;
9290 }
9291
9292 virtual bool AttributesEqual(const Instruction& other) const {
9293 auto const unary_op_other = other.AsUnaryInt64Op();
9294 return UnaryIntegerOpInstr::AttributesEqual(other) &&
9295 (speculative_mode_ == unary_op_other->speculative_mode_);
9296 }
9297
9298 virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const {
9299 return speculative_mode_;
9300 }
9301
9302 DECLARE_INSTRUCTION(UnaryInt64Op)
9303
9304#define FIELD_LIST(F) F(const SpeculativeMode, speculative_mode_)
9305
9308 FIELD_LIST)
9309#undef FIELD_LIST
9310
9311 private:
9313};
9314
9315class BinaryIntegerOpInstr : public TemplateDefinition<2, NoThrow, Pure> {
9316 public:
9318 Value* left,
9319 Value* right,
9320 intptr_t deopt_id)
9321 : TemplateDefinition(deopt_id),
9322 op_kind_(op_kind),
9323 can_overflow_(true),
9324 is_truncating_(false) {
9325 SetInputAt(0, left);
9326 SetInputAt(1, right);
9327 }
9328
9329 static BinaryIntegerOpInstr* Make(
9330 Representation representation,
9331 Token::Kind op_kind,
9332 Value* left,
9333 Value* right,
9334 intptr_t deopt_id,
9335 SpeculativeMode speculative_mode = kGuardInputs);
9336
9337 static BinaryIntegerOpInstr* Make(
9338 Representation representation,
9339 Token::Kind op_kind,
9340 Value* left,
9341 Value* right,
9342 intptr_t deopt_id,
9343 bool can_overflow,
9344 bool is_truncating,
9345 Range* range,
9346 SpeculativeMode speculative_mode = kGuardInputs);
9347
9348 Token::Kind op_kind() const { return op_kind_; }
9349 Value* left() const { return inputs_[0]; }
9350 Value* right() const { return inputs_[1]; }
9351
9352 bool can_overflow() const { return can_overflow_; }
9353 void set_can_overflow(bool overflow) {
9354 ASSERT(!is_truncating_ || !overflow);
9355 can_overflow_ = overflow;
9356 }
9357
9358 bool is_truncating() const { return is_truncating_; }
9360 is_truncating_ = true;
9361 set_can_overflow(false);
9362 }
9363
9364 // Returns true if right is either a non-zero Integer constant or has a range
9365 // that does not include the possibility of being zero.
9366 bool RightIsNonZero() const;
9367
9368 // Returns true if right is a non-zero Smi constant which absolute value is
9369 // a power of two.
9370 bool RightIsPowerOfTwoConstant() const;
9371
9372 virtual Definition* Canonicalize(FlowGraph* flow_graph);
9373
9374 virtual bool AttributesEqual(const Instruction& other) const;
9375
9376 virtual intptr_t DeoptimizationTarget() const { return GetDeoptId(); }
9377
9378 virtual void InferRange(RangeAnalysis* analysis, Range* range);
9379
9381
9382 DECLARE_ABSTRACT_INSTRUCTION(BinaryIntegerOp)
9383
9384 DECLARE_ATTRIBUTE(op_kind())
9385
9386#define FIELD_LIST(F) \
9387 F(const Token::Kind, op_kind_) \
9388 F(bool, can_overflow_) \
9389 F(bool, is_truncating_)
9390
9393 FIELD_LIST)
9394#undef FIELD_LIST
9395
9396 protected:
9397 void InferRangeHelper(const Range* left_range,
9398 const Range* right_range,
9399 Range* range);
9400
9401 private:
9402 Definition* CreateConstantResult(FlowGraph* graph, const Integer& result);
9403
9405};
9406
9408 public:
9410 Value* left,
9411 Value* right,
9412 intptr_t deopt_id,
9413 // Provided by BinaryIntegerOpInstr::Make for constant RHS.
9414 Range* right_range = nullptr)
9415 : BinaryIntegerOpInstr(op_kind, left, right, deopt_id),
9416 right_range_(right_range) {}
9417
9418 virtual bool ComputeCanDeoptimize() const;
9419
9420 virtual void InferRange(RangeAnalysis* analysis, Range* range);
9421 virtual CompileType ComputeType() const;
9422
9423 DECLARE_INSTRUCTION(BinarySmiOp)
9424
9425 Range* right_range() const { return right_range_; }
9426
9427#define FIELD_LIST(F) F(Range*, right_range_)
9428
9431 FIELD_LIST)
9432#undef FIELD_LIST
9433
9434 private:
9436};
9437
9439 public:
9441 Value* left,
9442 Value* right,
9443 intptr_t deopt_id)
9444 : BinaryIntegerOpInstr(op_kind, left, right, deopt_id) {
9445 SetInputAt(0, left);
9446 SetInputAt(1, right);
9447 }
9448
9449 static bool IsSupported(Token::Kind op_kind, Value* left, Value* right) {
9450#if defined(TARGET_ARCH_IS_32_BIT)
9451 switch (op_kind) {
9452 case Token::kADD:
9453 case Token::kSUB:
9454 case Token::kMUL:
9455 case Token::kBIT_AND:
9456 case Token::kBIT_OR:
9457 case Token::kBIT_XOR:
9458 return true;
9459
9460 case Token::kSHL:
9461 case Token::kSHR:
9462 case Token::kUSHR:
9463 if (right->BindsToConstant() && right->BoundConstant().IsSmi()) {
9464 const intptr_t value = Smi::Cast(right->BoundConstant()).Value();
9465 return 0 <= value && value < kBitsPerWord;
9466 }
9467 return false;
9468
9469 default:
9470 return false;
9471 }
9472#else
9473 return false;
9474#endif
9475 }
9476
9477 virtual bool ComputeCanDeoptimize() const;
9478
9479 virtual Representation representation() const { return kUnboxedInt32; }
9480
9481 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
9482 ASSERT((idx == 0) || (idx == 1));
9483 return kUnboxedInt32;
9484 }
9485
9486 DECLARE_INSTRUCTION(BinaryInt32Op)
9487
9489
9490 private:
9492};
9493
9495 public:
9497 Value* left,
9498 Value* right,
9499 intptr_t deopt_id)
9500 : BinaryIntegerOpInstr(op_kind, left, right, deopt_id) {
9501 mark_truncating();
9502 ASSERT(IsSupported(op_kind));
9503 }
9504
9505 virtual bool ComputeCanDeoptimize() const { return false; }
9506
9507 virtual Representation representation() const { return kUnboxedUint32; }
9508
9509 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
9510 ASSERT((idx == 0) || (idx == 1));
9511 return kUnboxedUint32;
9512 }
9513
9514 virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const {
9515 return kNotSpeculative;
9516 }
9517
9518 static bool IsSupported(Token::Kind op_kind) {
9519 switch (op_kind) {
9520 case Token::kADD:
9521 case Token::kSUB:
9522 case Token::kMUL:
9523 case Token::kBIT_AND:
9524 case Token::kBIT_OR:
9525 case Token::kBIT_XOR:
9526 return true;
9527 default:
9528 return false;
9529 }
9530 }
9531
9532 DECLARE_INSTRUCTION(BinaryUint32Op)
9533
9535
9536 private:
9538};
9539
9541 public:
9543 Value* left,
9544 Value* right,
9545 intptr_t deopt_id,
9546 SpeculativeMode speculative_mode = kGuardInputs)
9547 : BinaryIntegerOpInstr(op_kind, left, right, deopt_id),
9548 speculative_mode_(speculative_mode) {
9549 mark_truncating();
9550 }
9551
9552 virtual bool ComputeCanDeoptimize() const {
9553 ASSERT(!can_overflow());
9554 return false;
9555 }
9556
9557 virtual bool MayThrow() const {
9558 return (op_kind() == Token::kMOD || op_kind() == Token::kTRUNCDIV) &&
9559 !RightIsNonZero();
9560 }
9561
9562 virtual Representation representation() const { return kUnboxedInt64; }
9563
9564 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
9565 ASSERT((idx == 0) || (idx == 1));
9566 return kUnboxedInt64;
9567 }
9568
9569 virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const {
9570 return speculative_mode_;
9571 }
9572
9573 virtual bool AttributesEqual(const Instruction& other) const {
9574 return BinaryIntegerOpInstr::AttributesEqual(other) &&
9575 (speculative_mode_ == other.AsBinaryInt64Op()->speculative_mode_);
9576 }
9577
9578 DECLARE_INSTRUCTION(BinaryInt64Op)
9579
9580#define FIELD_LIST(F) F(const SpeculativeMode, speculative_mode_)
9581
9584 FIELD_LIST)
9585#undef FIELD_LIST
9586
9587 private:
9589};
9590
9591// Base class for integer shift operations.
9593 public:
9595 Value* left,
9596 Value* right,
9597 intptr_t deopt_id,
9598 // Provided by BinaryIntegerOpInstr::Make for constant RHS
9599 Range* right_range = nullptr)
9600 : BinaryIntegerOpInstr(op_kind, left, right, deopt_id),
9601 shift_range_(right_range) {
9602 ASSERT((op_kind == Token::kSHL) || (op_kind == Token::kSHR) ||
9603 (op_kind == Token::kUSHR));
9604 mark_truncating();
9605 }
9606
9607 Range* shift_range() const { return shift_range_; }
9608
9609 // Set the range directly (takes ownership).
9610 void set_shift_range(Range* shift_range) { shift_range_ = shift_range; }
9611
9612 virtual void InferRange(RangeAnalysis* analysis, Range* range);
9613
9614 DECLARE_ABSTRACT_INSTRUCTION(ShiftIntegerOp)
9615
9616#define FIELD_LIST(F) F(Range*, shift_range_)
9617
9620 FIELD_LIST)
9621#undef FIELD_LIST
9622
9623 protected:
9624 static constexpr intptr_t kShiftCountLimit = 63;
9625
9626 // Returns true if the shift amount is guaranteed to be in
9627 // [0..max] range.
9628 bool IsShiftCountInRange(int64_t max = kShiftCountLimit) const;
9629
9630 private:
9632};
9633
9634// Non-speculative int64 shift. Takes 2 unboxed int64.
9635// Throws if right operand is negative.
9637 public:
9639 Value* left,
9640 Value* right,
9641 intptr_t deopt_id,
9642 Range* right_range = nullptr)
9643 : ShiftIntegerOpInstr(op_kind, left, right, deopt_id, right_range) {}
9644
9645 virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const {
9646 return kNotSpeculative;
9647 }
9648 virtual bool ComputeCanDeoptimize() const { return false; }
9649 virtual bool MayThrow() const { return !IsShiftCountInRange(); }
9650
9651 virtual Representation representation() const { return kUnboxedInt64; }
9652
9653 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
9654 ASSERT((idx == 0) || (idx == 1));
9655 return kUnboxedInt64;
9656 }
9657
9658 DECLARE_INSTRUCTION(ShiftInt64Op)
9659
9661
9662 private:
9664};
9665
9666// Speculative int64 shift. Takes unboxed int64 and smi.
9667// Deoptimizes if right operand is negative or greater than kShiftCountLimit.
9669 public:
9671 Value* left,
9672 Value* right,
9673 intptr_t deopt_id,
9674 Range* right_range = nullptr)
9675 : ShiftIntegerOpInstr(op_kind, left, right, deopt_id, right_range) {}
9676
9677 virtual bool ComputeCanDeoptimize() const {
9678 ASSERT(!can_overflow());
9679 return !IsShiftCountInRange();
9680 }
9681
9682 virtual Representation representation() const { return kUnboxedInt64; }
9683
9684 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
9685 ASSERT((idx == 0) || (idx == 1));
9686 return (idx == 0) ? kUnboxedInt64 : kTagged;
9687 }
9688
9689 DECLARE_INSTRUCTION(SpeculativeShiftInt64Op)
9690
9692
9693 private:
9695};
9696
9697// Non-speculative uint32 shift. Takes unboxed uint32 and unboxed int64.
9698// Throws if right operand is negative.
9700 public:
9702 Value* left,
9703 Value* right,
9704 intptr_t deopt_id,
9705 Range* right_range = nullptr)
9706 : ShiftIntegerOpInstr(op_kind, left, right, deopt_id, right_range) {}
9707
9708 virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const {
9709 return kNotSpeculative;
9710 }
9711 virtual bool ComputeCanDeoptimize() const { return false; }
9712 virtual bool MayThrow() const {
9713 return !IsShiftCountInRange(kUint32ShiftCountLimit);
9714 }
9715
9716 virtual Representation representation() const { return kUnboxedUint32; }
9717
9718 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
9719 ASSERT((idx == 0) || (idx == 1));
9720 return (idx == 0) ? kUnboxedUint32 : kUnboxedInt64;
9721 }
9722
9723 DECLARE_INSTRUCTION(ShiftUint32Op)
9724
9726
9727 private:
9728 static constexpr intptr_t kUint32ShiftCountLimit = 31;
9729
9731};
9732
9733// Speculative uint32 shift. Takes unboxed uint32 and smi.
9734// Deoptimizes if right operand is negative.
9736 public:
9738 Value* left,
9739 Value* right,
9740 intptr_t deopt_id,
9741 Range* right_range = nullptr)
9742 : ShiftIntegerOpInstr(op_kind, left, right, deopt_id, right_range) {}
9743
9744 virtual bool ComputeCanDeoptimize() const { return !IsShiftCountInRange(); }
9745
9746 virtual Representation representation() const { return kUnboxedUint32; }
9747
9748 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
9749 ASSERT((idx == 0) || (idx == 1));
9750 return (idx == 0) ? kUnboxedUint32 : kTagged;
9751 }
9752
9753 DECLARE_INSTRUCTION(SpeculativeShiftUint32Op)
9754
9757
9758 private:
9759 static constexpr intptr_t kUint32ShiftCountLimit = 31;
9760
9762};
9763
9764class UnaryDoubleOpInstr : public TemplateDefinition<1, NoThrow, Pure> {
9765 public:
9767 Value* value,
9768 intptr_t deopt_id,
9769 SpeculativeMode speculative_mode = kGuardInputs,
9770 Representation representation = kUnboxedDouble)
9771 : TemplateDefinition(deopt_id),
9772 op_kind_(op_kind),
9773 speculative_mode_(speculative_mode),
9774 representation_(representation) {
9775 ASSERT((representation == kUnboxedFloat) ||
9776 (representation == kUnboxedDouble));
9777 SetInputAt(0, value);
9778 }
9779
9780 Value* value() const { return inputs_[0]; }
9781 Token::Kind op_kind() const { return op_kind_; }
9782
9783 DECLARE_INSTRUCTION(UnaryDoubleOp)
9784
9785 virtual bool ComputeCanDeoptimize() const { return false; }
9786
9787 virtual intptr_t DeoptimizationTarget() const {
9788 // Direct access since this instruction cannot deoptimize, and the deopt-id
9789 // was inherited from another instruction that could deoptimize.
9790 return GetDeoptId();
9791 }
9792
9793 virtual Representation representation() const { return representation_; }
9794
9795 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
9796 ASSERT(idx == 0);
9797 return representation_;
9798 }
9799
9800 virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const {
9801 return speculative_mode_;
9802 }
9803
9804 virtual bool AttributesEqual(const Instruction& other) const {
9805 auto other_op = other.Cast<UnaryDoubleOpInstr>();
9806 return (op_kind_ == other_op->op_kind_) &&
9807 (speculative_mode_ == other_op->speculative_mode_) &&
9808 (representation_ == other_op->representation_);
9809 }
9810
9811 DECLARE_ATTRIBUTE(op_kind())
9812
9814
9815#define FIELD_LIST(F) \
9816 F(const Token::Kind, op_kind_) \
9817 F(const SpeculativeMode, speculative_mode_) \
9818 F(const Representation, representation_)
9819
9822 FIELD_LIST)
9823#undef FIELD_LIST
9824
9825 private:
9827};
9828
9830 public:
9831 enum Kind {
9832 // kOsrAndPreemption stack overflow checks are emitted in both unoptimized
9833 // and optimized versions of the code and they serve as both preemption and
9834 // OSR entry points.
9836
9837 // kOsrOnly stack overflow checks are only needed in the unoptimized code
9838 // because we can't OSR optimized code.
9840 };
9841
9843 intptr_t stack_depth,
9844 intptr_t loop_depth,
9845 intptr_t deopt_id,
9846 Kind kind)
9847 : TemplateInstruction(source, deopt_id),
9848 token_pos_(source.token_pos),
9849 stack_depth_(stack_depth),
9850 loop_depth_(loop_depth),
9851 kind_(kind) {
9852 ASSERT(kind != kOsrOnly || loop_depth > 0);
9853 }
9854
9855 virtual TokenPosition token_pos() const { return token_pos_; }
9856 bool in_loop() const { return loop_depth_ > 0; }
9857 intptr_t stack_depth() const { return stack_depth_; }
9858 intptr_t loop_depth() const { return loop_depth_; }
9859
9860 DECLARE_INSTRUCTION(CheckStackOverflow)
9861
9862 virtual bool ComputeCanDeoptimize() const { return false; }
9863 virtual bool ComputeCanDeoptimizeAfterCall() const {
9864 return !CompilerState::Current().is_aot();
9865 }
9866
9867 virtual Instruction* Canonicalize(FlowGraph* flow_graph);
9868
9869 virtual bool HasUnknownSideEffects() const { return false; }
9870
9871 virtual bool CanEliminate(const BlockEntryInstr* block) const {
9872 return false;
9873 }
9874
9875 virtual bool UseSharedSlowPathStub(bool is_optimizing) const {
9876 return SlowPathSharingSupported(is_optimizing);
9877 }
9878
9880
9881#define FIELD_LIST(F) \
9882 F(const TokenPosition, token_pos_) \
9883 F(const intptr_t, stack_depth_) \
9884 F(const intptr_t, loop_depth_) \
9885 F(const Kind, kind_)
9886
9889 FIELD_LIST)
9890#undef FIELD_LIST
9891
9892 private:
9894};
9895
9896// TODO(vegorov): remove this instruction in favor of Int32ToDouble.
9897class SmiToDoubleInstr : public TemplateDefinition<1, NoThrow, Pure> {
9898 public:
9900 : TemplateDefinition(source), token_pos_(source.token_pos) {
9901 SetInputAt(0, value);
9902 }
9903
9904 Value* value() const { return inputs_[0]; }
9905 virtual TokenPosition token_pos() const { return token_pos_; }
9906
9907 DECLARE_INSTRUCTION(SmiToDouble)
9908
9909 virtual Representation representation() const { return kUnboxedDouble; }
9910
9911 virtual bool ComputeCanDeoptimize() const { return false; }
9912
9913 virtual bool AttributesEqual(const Instruction& other) const { return true; }
9914
9915#define FIELD_LIST(F) F(const TokenPosition, token_pos_)
9916
9919 FIELD_LIST)
9920#undef FIELD_LIST
9921
9922 private:
9924};
9925
9926class Int32ToDoubleInstr : public TemplateDefinition<1, NoThrow, Pure> {
9927 public:
9928 explicit Int32ToDoubleInstr(Value* value) { SetInputAt(0, value); }
9929
9930 Value* value() const { return inputs_[0]; }
9931
9932 DECLARE_INSTRUCTION(Int32ToDouble)
9933
9934 virtual Representation RequiredInputRepresentation(intptr_t index) const {
9935 ASSERT(index == 0);
9936 return kUnboxedInt32;
9937 }
9938
9939 virtual Representation representation() const { return kUnboxedDouble; }
9940
9941 virtual bool ComputeCanDeoptimize() const { return false; }
9942
9943 virtual bool AttributesEqual(const Instruction& other) const { return true; }
9944
9946
9947 private:
9949};
9950
9951class Int64ToDoubleInstr : public TemplateDefinition<1, NoThrow, Pure> {
9952 public:
9954 intptr_t deopt_id,
9955 SpeculativeMode speculative_mode = kGuardInputs)
9956 : TemplateDefinition(deopt_id), speculative_mode_(speculative_mode) {
9957 SetInputAt(0, value);
9958 }
9959
9960 Value* value() const { return inputs_[0]; }
9961
9962 DECLARE_INSTRUCTION(Int64ToDouble)
9963
9964 virtual Representation RequiredInputRepresentation(intptr_t index) const {
9965 ASSERT(index == 0);
9966 return kUnboxedInt64;
9967 }
9968
9969 virtual Representation representation() const { return kUnboxedDouble; }
9970
9971 virtual intptr_t DeoptimizationTarget() const {
9972 // Direct access since this instruction cannot deoptimize, and the deopt-id
9973 // was inherited from another instruction that could deoptimize.
9974 return GetDeoptId();
9975 }
9976
9977 virtual bool ComputeCanDeoptimize() const { return false; }
9978
9979 virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const {
9980 return speculative_mode_;
9981 }
9982
9983 virtual bool AttributesEqual(const Instruction& other) const {
9984 return speculative_mode_ == other.AsInt64ToDouble()->speculative_mode_;
9985 }
9986
9987#define FIELD_LIST(F) F(const SpeculativeMode, speculative_mode_)
9988
9991 FIELD_LIST)
9992#undef FIELD_LIST
9993
9994 private:
9996};
9997
9998class DoubleToIntegerInstr : public TemplateDefinition<1, Throws, Pure> {
9999 public:
10001 MethodRecognizer::Kind recognized_kind,
10002 intptr_t deopt_id)
10003 : TemplateDefinition(deopt_id), recognized_kind_(recognized_kind) {
10004 ASSERT((recognized_kind == MethodRecognizer::kDoubleToInteger) ||
10005 (recognized_kind == MethodRecognizer::kDoubleFloorToInt) ||
10006 (recognized_kind == MethodRecognizer::kDoubleCeilToInt));
10007 SetInputAt(0, value);
10008 }
10009
10010 Value* value() const { return inputs_[0]; }
10011
10012 MethodRecognizer::Kind recognized_kind() const { return recognized_kind_; }
10013
10014 DECLARE_INSTRUCTION(DoubleToInteger)
10015 virtual CompileType ComputeType() const;
10016
10017 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
10018 ASSERT(idx == 0);
10019 return kUnboxedDouble;
10020 }
10021
10022 virtual SpeculativeMode SpeculativeModeOfInput(intptr_t idx) const {
10023 ASSERT(idx == 0);
10024 return kNotSpeculative;
10025 }
10026
10027 virtual bool ComputeCanDeoptimize() const {
10028 return !CompilerState::Current().is_aot();
10029 }
10030
10031 virtual intptr_t DeoptimizationTarget() const { return GetDeoptId(); }
10032
10033 virtual bool HasUnknownSideEffects() const { return false; }
10034
10035 virtual bool AttributesEqual(const Instruction& other) const {
10036 return other.AsDoubleToInteger()->recognized_kind() == recognized_kind();
10037 }
10038
10039#define FIELD_LIST(F) F(const MethodRecognizer::Kind, recognized_kind_)
10040
10043 FIELD_LIST)
10044#undef FIELD_LIST
10045
10046 private:
10048};
10049
10050// Similar to 'DoubleToIntegerInstr' but expects unboxed double as input
10051// and creates a Smi.
10052class DoubleToSmiInstr : public TemplateDefinition<1, NoThrow, Pure> {
10053 public:
10054 DoubleToSmiInstr(Value* value, intptr_t deopt_id)
10055 : TemplateDefinition(deopt_id) {
10056 SetInputAt(0, value);
10057 }
10058
10059 Value* value() const { return inputs_[0]; }
10060
10061 DECLARE_INSTRUCTION(DoubleToSmi)
10062 virtual CompileType ComputeType() const;
10063
10064 virtual bool ComputeCanDeoptimize() const { return true; }
10065
10066 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
10067 ASSERT(idx == 0);
10068 return kUnboxedDouble;
10069 }
10070
10071 virtual intptr_t DeoptimizationTarget() const { return GetDeoptId(); }
10072
10073 virtual bool AttributesEqual(const Instruction& other) const { return true; }
10074
10076
10077 private:
10079};
10080
10081class DoubleToFloatInstr : public TemplateDefinition<1, NoThrow, Pure> {
10082 public:
10084 intptr_t deopt_id,
10085 SpeculativeMode speculative_mode = kGuardInputs)
10086 : TemplateDefinition(deopt_id), speculative_mode_(speculative_mode) {
10087 SetInputAt(0, value);
10088 }
10089
10090 Value* value() const { return inputs_[0]; }
10091
10092 DECLARE_INSTRUCTION(DoubleToFloat)
10093
10094 virtual bool ComputeCanDeoptimize() const { return false; }
10095
10096 virtual Representation representation() const { return kUnboxedFloat; }
10097
10098 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
10099 ASSERT(idx == 0);
10100 return kUnboxedDouble;
10101 }
10102
10103 virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const {
10104 return speculative_mode_;
10105 }
10106
10107 virtual intptr_t DeoptimizationTarget() const { return GetDeoptId(); }
10108
10109 virtual bool AttributesEqual(const Instruction& other) const { return true; }
10110
10111 virtual Definition* Canonicalize(FlowGraph* flow_graph);
10112
10113#define FIELD_LIST(F) F(const SpeculativeMode, speculative_mode_)
10114
10117 FIELD_LIST)
10118#undef FIELD_LIST
10119
10120 private:
10122};
10123
10124class FloatToDoubleInstr : public TemplateDefinition<1, NoThrow, Pure> {
10125 public:
10126 FloatToDoubleInstr(Value* value, intptr_t deopt_id)
10127 : TemplateDefinition(deopt_id) {
10128 SetInputAt(0, value);
10129 }
10130
10131 Value* value() const { return inputs_[0]; }
10132
10133 DECLARE_INSTRUCTION(FloatToDouble)
10134
10135 virtual Representation representation() const { return kUnboxedDouble; }
10136
10137 virtual bool ComputeCanDeoptimize() const { return false; }
10138
10139 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
10140 ASSERT(idx == 0);
10141 return kUnboxedFloat;
10142 }
10143
10144 virtual intptr_t DeoptimizationTarget() const { return GetDeoptId(); }
10145
10146 virtual bool AttributesEqual(const Instruction& other) const { return true; }
10147
10148 virtual Definition* Canonicalize(FlowGraph* flow_graph);
10149
10151
10152 private:
10154};
10155
10156// left op right ? -1 : 0
10157class FloatCompareInstr : public TemplateDefinition<2, NoThrow, Pure> {
10158 public:
10160 : op_kind_(op_kind) {
10161 SetInputAt(0, left);
10162 SetInputAt(1, right);
10163 }
10164
10165 Value* left() const { return inputs_[0]; }
10166 Value* right() const { return inputs_[1]; }
10167
10168 Token::Kind op_kind() const { return op_kind_; }
10169
10170 DECLARE_INSTRUCTION(FloatCompare)
10171
10172 DECLARE_ATTRIBUTE(op_kind())
10173
10174 virtual bool ComputeCanDeoptimize() const { return false; }
10175
10176 virtual Representation representation() const { return kUnboxedInt32; }
10177
10178 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
10179 return kUnboxedFloat;
10180 }
10181
10182 virtual bool AttributesEqual(const Instruction& other) const {
10183 return other.AsFloatCompare()->op_kind() == op_kind();
10184 }
10185
10186#define FIELD_LIST(F) F(const Token::Kind, op_kind_)
10187
10190 FIELD_LIST)
10191#undef FIELD_LIST
10192
10193 private:
10195};
10196
10197// TODO(sjindel): Replace with FFICallInstr.
10199 public:
10201 intptr_t deopt_id,
10202 MethodRecognizer::Kind recognized_kind,
10203 const InstructionSource& source);
10204
10205 static intptr_t ArgumentCountFor(MethodRecognizer::Kind recognized_kind_);
10206
10207 const RuntimeEntry& TargetFunction() const;
10208
10209 MethodRecognizer::Kind recognized_kind() const { return recognized_kind_; }
10210
10211 virtual TokenPosition token_pos() const { return token_pos_; }
10212
10213 DECLARE_INSTRUCTION(InvokeMathCFunction)
10214
10215 virtual bool ComputeCanDeoptimize() const { return false; }
10216
10217 virtual Representation representation() const { return kUnboxedDouble; }
10218
10219 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
10220 ASSERT((0 <= idx) && (idx < InputCount()));
10221 return kUnboxedDouble;
10222 }
10223
10224 virtual SpeculativeMode SpeculativeModeOfInput(intptr_t idx) const {
10225 ASSERT((0 <= idx) && (idx < InputCount()));
10226 return kNotSpeculative;
10227 }
10228
10229 virtual intptr_t DeoptimizationTarget() const { return GetDeoptId(); }
10230
10231 virtual bool AllowsCSE() const { return true; }
10232 virtual bool HasUnknownSideEffects() const { return false; }
10233
10234 virtual bool AttributesEqual(const Instruction& other) const {
10235 auto const other_invoke = other.AsInvokeMathCFunction();
10236 return other_invoke->recognized_kind() == recognized_kind();
10237 }
10238
10239 virtual bool MayThrow() const { return false; }
10240
10241 static constexpr intptr_t kSavedSpTempIndex = 0;
10242 static constexpr intptr_t kObjectTempIndex = 1;
10243 static constexpr intptr_t kDoubleTempIndex = 2;
10244
10246
10247#define FIELD_LIST(F) \
10248 F(const MethodRecognizer::Kind, recognized_kind_) \
10249 F(const TokenPosition, token_pos_)
10250
10253 FIELD_LIST)
10254#undef FIELD_LIST
10255
10256 private:
10258};
10259
10260class ExtractNthOutputInstr : public TemplateDefinition<1, NoThrow, Pure> {
10261 public:
10262 // Extract the Nth output register from value.
10264 intptr_t n,
10265 Representation definition_rep,
10266 intptr_t definition_cid)
10267 : index_(n),
10268 definition_rep_(definition_rep),
10269 definition_cid_(definition_cid) {
10270 SetInputAt(0, value);
10271 }
10272
10273 Value* value() const { return inputs_[0]; }
10274
10275 DECLARE_INSTRUCTION(ExtractNthOutput)
10276 DECLARE_ATTRIBUTE(index())
10277
10278 virtual CompileType ComputeType() const;
10279 virtual bool ComputeCanDeoptimize() const { return false; }
10280
10281 intptr_t index() const { return index_; }
10282
10283 virtual Representation representation() const { return definition_rep_; }
10284
10285 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
10286 ASSERT(idx == 0);
10287 if (representation() == kTagged) {
10288 return kPairOfTagged;
10289 }
10290 UNREACHABLE();
10291 return definition_rep_;
10292 }
10293
10294 virtual bool AttributesEqual(const Instruction& other) const {
10295 auto const other_extract = other.AsExtractNthOutput();
10296 return (other_extract->representation() == representation()) &&
10297 (other_extract->index() == index());
10298 }
10299
10301
10302#define FIELD_LIST(F) \
10303 F(const intptr_t, index_) \
10304 F(const Representation, definition_rep_) \
10305 F(const intptr_t, definition_cid_)
10306
10309 FIELD_LIST)
10310#undef FIELD_LIST
10311
10312 private:
10314};
10315
10316// Combines 2 values into a pair with kPairOfTagged representation.
10317class MakePairInstr : public TemplateDefinition<2, NoThrow, Pure> {
10318 public:
10320 SetInputAt(0, x);
10321 SetInputAt(1, y);
10322 }
10323
10324 DECLARE_INSTRUCTION(MakePair)
10325
10326 virtual bool ComputeCanDeoptimize() const { return false; }
10327
10328 virtual Representation representation() const { return kPairOfTagged; }
10329
10330 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
10331 ASSERT((0 <= idx) && (idx < InputCount()));
10332 return kTagged;
10333 }
10334
10335 virtual bool AttributesEqual(const Instruction& other) const { return true; }
10336
10338
10339 private:
10341};
10342
10343class UnboxLaneInstr : public TemplateDefinition<1, NoThrow, Pure> {
10344 public:
10346 intptr_t n,
10347 Representation definition_rep,
10348 intptr_t definition_cid)
10349 : lane_(n),
10350 definition_rep_(definition_rep),
10351 definition_cid_(definition_cid) {
10352 SetInputAt(0, value);
10353 }
10354
10355 Value* value() const { return inputs_[0]; }
10356
10357 DECLARE_INSTRUCTION(UnboxLane)
10358
10359 virtual CompileType ComputeType() const;
10360 virtual bool ComputeCanDeoptimize() const { return false; }
10361
10362 intptr_t lane() const { return lane_; }
10363
10364 virtual Representation representation() const { return definition_rep_; }
10365
10366 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
10367 ASSERT(idx == 0);
10368 return kTagged;
10369 }
10370
10371 virtual bool AttributesEqual(const Instruction& other) const {
10372 auto const other_split = other.AsUnboxLane();
10373 return (other_split->representation() == representation()) &&
10374 (other_split->lane() == lane());
10375 }
10376
10377 Definition* Canonicalize(FlowGraph* flow_graph);
10378
10380
10381#define FIELD_LIST(F) \
10382 F(const intptr_t, lane_) \
10383 F(const Representation, definition_rep_) \
10384 F(const intptr_t, definition_cid_)
10385
10388 FIELD_LIST)
10389#undef FIELD_LIST
10390
10391 private:
10393};
10394
10395class BoxLanesInstr : public TemplateDefinition<4, NoThrow, Pure> {
10396 public:
10397 BoxLanesInstr(Representation from_representation, Value* x, Value* y)
10398 : from_representation_(from_representation) {
10399 ASSERT(from_representation == kUnboxedDouble);
10400 ASSERT(x->definition()->representation() == from_representation);
10401 ASSERT(y->definition()->representation() == from_representation);
10402 SetInputAt(0, x);
10403 SetInputAt(1, y);
10404 }
10405 BoxLanesInstr(Representation from_representation,
10406 Value* x,
10407 Value* y,
10408 Value* z,
10409 Value* w)
10410 : from_representation_(from_representation) {
10411 ASSERT((from_representation == kUnboxedInt32) ||
10412 (from_representation == kUnboxedFloat));
10413 ASSERT(x->definition()->representation() == from_representation);
10414 ASSERT(y->definition()->representation() == from_representation);
10415 ASSERT(z->definition()->representation() == from_representation);
10416 ASSERT(w->definition()->representation() == from_representation);
10417 SetInputAt(0, x);
10418 SetInputAt(1, y);
10419 SetInputAt(2, z);
10420 SetInputAt(3, w);
10421 }
10422
10423 intptr_t InputCount() const {
10424 switch (from_representation_) {
10425 case kUnboxedDouble:
10426 return 2;
10427 case kUnboxedFloat:
10428 return 4;
10429 case kUnboxedInt32:
10430 return 4;
10431 default:
10432 UNREACHABLE();
10433 return 0;
10434 }
10435 }
10436 Value* x() const { return inputs_[0]; }
10437 Value* y() const { return inputs_[1]; }
10438 Value* z() const {
10439 ASSERT((from_representation() == kUnboxedInt32) ||
10440 (from_representation() == kUnboxedFloat));
10441 return inputs_[2];
10442 }
10443 Value* w() const {
10444 ASSERT((from_representation() == kUnboxedInt32) ||
10445 (from_representation() == kUnboxedFloat));
10446 return inputs_[3];
10447 }
10448 Representation from_representation() const { return from_representation_; }
10449
10450 DECLARE_INSTRUCTION(BoxLanes)
10451 virtual CompileType ComputeType() const;
10452
10453 virtual bool ComputeCanDeoptimize() const { return false; }
10454 virtual intptr_t DeoptimizationTarget() const { return DeoptId::kNone; }
10455
10456 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
10457 ASSERT(idx == 0 || idx == 1 || idx == 2 || idx == 3);
10458 return from_representation();
10459 }
10460
10461 virtual bool AttributesEqual(const Instruction& other) const {
10462 return other.AsBoxLanes()->from_representation() == from_representation();
10463 }
10464
10465 Definition* Canonicalize(FlowGraph* flow_graph);
10466
10467 virtual TokenPosition token_pos() const { return TokenPosition::kBox; }
10468
10469 virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const {
10470 return kNotSpeculative;
10471 }
10472
10474
10475#define FIELD_LIST(F) F(const Representation, from_representation_)
10476
10479 FIELD_LIST)
10480#undef FIELD_LIST
10481
10482 private:
10484};
10485
10486class TruncDivModInstr : public TemplateDefinition<2, NoThrow, Pure> {
10487 public:
10488 TruncDivModInstr(Value* lhs, Value* rhs, intptr_t deopt_id);
10489
10490 static intptr_t OutputIndexOf(Token::Kind token);
10491
10492 virtual bool ComputeCanDeoptimize() const { return true; }
10493
10494 virtual Representation representation() const { return kPairOfTagged; }
10495
10496 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
10497 ASSERT((0 <= idx) && (idx < InputCount()));
10498 return kTagged;
10499 }
10500
10501 virtual intptr_t DeoptimizationTarget() const { return GetDeoptId(); }
10502
10503 DECLARE_INSTRUCTION(TruncDivMod)
10504
10505 virtual bool AttributesEqual(const Instruction& other) const { return true; }
10506
10508
10510
10511 private:
10512 Range* divisor_range() const {
10513 // Note: this range is only used to remove check for zero divisor from
10514 // the emitted pattern. It is not used for deciding whether instruction
10515 // will deoptimize or not - that is why it is ok to access range of
10516 // the definition directly. Otherwise range analysis or another pass
10517 // needs to cache range of the divisor in the operation to prevent
10518 // bugs when range information gets out of sync with the final decision
10519 // whether some instruction can deoptimize or not made in
10520 // EliminateEnvironments().
10521 return InputAt(1)->definition()->range();
10522 }
10523
10524 DISALLOW_COPY_AND_ASSIGN(TruncDivModInstr);
10525};
10526
10527class CheckClassInstr : public TemplateInstruction<1, NoThrow> {
10528 public:
10530 intptr_t deopt_id,
10531 const Cids& cids,
10532 const InstructionSource& source);
10533
10534 DECLARE_INSTRUCTION(CheckClass)
10535
10536 virtual bool ComputeCanDeoptimize() const { return true; }
10537
10538 virtual TokenPosition token_pos() const { return token_pos_; }
10539
10540 Value* value() const { return inputs_[0]; }
10541
10542 const Cids& cids() const { return cids_; }
10543
10544 virtual Instruction* Canonicalize(FlowGraph* flow_graph);
10545
10546 bool IsNullCheck() const { return IsDeoptIfNull() || IsDeoptIfNotNull(); }
10547
10548 bool IsDeoptIfNull() const;
10549 bool IsDeoptIfNotNull() const;
10550
10551 bool IsBitTest() const;
10552 static bool IsCompactCidRange(const Cids& cids);
10553 intptr_t ComputeCidMask() const;
10554
10555 virtual bool AllowsCSE() const { return true; }
10556 virtual bool HasUnknownSideEffects() const { return false; }
10557
10558 virtual bool AttributesEqual(const Instruction& other) const;
10559
10561
10562#define FIELD_LIST(F) \
10563 F(const Cids&, cids_) \
10564 F(bool, is_bit_test_) \
10565 F(const TokenPosition, token_pos_)
10566
10569 FIELD_LIST)
10570#undef FIELD_LIST
10571
10572 private:
10573 int EmitCheckCid(FlowGraphCompiler* compiler,
10574 int bias,
10575 intptr_t cid_start,
10576 intptr_t cid_end,
10577 bool is_last,
10578 compiler::Label* is_ok,
10579 compiler::Label* deopt,
10580 bool use_near_jump);
10582 intptr_t min,
10583 intptr_t max,
10584 intptr_t mask,
10585 compiler::Label* deopt);
10587
10589};
10590
10591class CheckSmiInstr : public TemplateInstruction<1, NoThrow, Pure> {
10592 public:
10594 intptr_t deopt_id,
10596 : TemplateInstruction(source, deopt_id), token_pos_(source.token_pos) {
10597 SetInputAt(0, value);
10598 }
10599
10600 Value* value() const { return inputs_[0]; }
10601 virtual TokenPosition token_pos() const { return token_pos_; }
10602
10603 DECLARE_INSTRUCTION(CheckSmi)
10604
10605 virtual bool ComputeCanDeoptimize() const { return true; }
10606
10607 virtual Instruction* Canonicalize(FlowGraph* flow_graph);
10608
10609 virtual bool AttributesEqual(const Instruction& other) const { return true; }
10610
10611#define FIELD_LIST(F) F(const TokenPosition, token_pos_)
10612
10615 FIELD_LIST)
10616#undef FIELD_LIST
10617
10618 private:
10620};
10621
10622// CheckNull instruction takes one input (`value`) and tests it for `null`.
10623// If `value` is `null`, then an exception is thrown according to
10624// `exception_type`. Otherwise, execution proceeds to the next instruction.
10625class CheckNullInstr : public TemplateDefinition<1, Throws, Pure> {
10626 public:
10632
10634 const String& function_name,
10635 intptr_t deopt_id,
10637 ExceptionType exception_type = kNoSuchMethod)
10638 : TemplateDefinition(source, deopt_id),
10639 token_pos_(source.token_pos),
10640 function_name_(function_name),
10641 exception_type_(exception_type) {
10642 DEBUG_ASSERT(function_name.IsNotTemporaryScopedHandle());
10643 ASSERT(function_name.IsSymbol());
10644 SetInputAt(0, value);
10645 }
10646
10647 Value* value() const { return inputs_[0]; }
10648 virtual TokenPosition token_pos() const { return token_pos_; }
10649 const String& function_name() const { return function_name_; }
10650 ExceptionType exception_type() const { return exception_type_; }
10651
10652 virtual bool UseSharedSlowPathStub(bool is_optimizing) const {
10653 return SlowPathSharingSupported(is_optimizing);
10654 }
10655
10656 DECLARE_INSTRUCTION(CheckNull)
10657
10658 virtual CompileType ComputeType() const;
10659 virtual bool RecomputeType();
10660
10661 // CheckNull can implicitly call Dart code (NoSuchMethodError constructor),
10662 // so it needs a deopt ID in optimized and unoptimized code.
10663 virtual bool ComputeCanDeoptimize() const { return false; }
10664 virtual bool ComputeCanDeoptimizeAfterCall() const {
10665 return !CompilerState::Current().is_aot();
10666 }
10667 virtual bool CanBecomeDeoptimizationTarget() const { return true; }
10668
10669 virtual Definition* Canonicalize(FlowGraph* flow_graph);
10670
10671 virtual bool AttributesEqual(const Instruction& other) const;
10672
10673 static void AddMetadataForRuntimeCall(CheckNullInstr* check_null,
10675
10676 virtual Value* RedefinedValue() const;
10677
10679
10680#define FIELD_LIST(F) \
10681 F(const TokenPosition, token_pos_) \
10682 F(const String&, function_name_) \
10683 F(const ExceptionType, exception_type_)
10684
10687 FIELD_LIST)
10688#undef FIELD_LIST
10689
10690 private:
10692};
10693
10694class CheckClassIdInstr : public TemplateInstruction<1, NoThrow> {
10695 public:
10696 CheckClassIdInstr(Value* value, CidRangeValue cids, intptr_t deopt_id)
10697 : TemplateInstruction(deopt_id), cids_(cids) {
10698 SetInputAt(0, value);
10699 }
10700
10701 Value* value() const { return inputs_[0]; }
10702 const CidRangeValue& cids() const { return cids_; }
10703
10704 DECLARE_INSTRUCTION(CheckClassId)
10705
10706 virtual bool ComputeCanDeoptimize() const { return true; }
10707
10708 virtual Instruction* Canonicalize(FlowGraph* flow_graph);
10709
10710 virtual bool AllowsCSE() const { return true; }
10711 virtual bool HasUnknownSideEffects() const { return false; }
10712
10713 virtual bool AttributesEqual(const Instruction& other) const {
10714 return other.Cast<CheckClassIdInstr>()->cids().Equals(cids_);
10715 }
10716
10718
10719#define FIELD_LIST(F) F(CidRangeValue, cids_)
10720
10723 FIELD_LIST)
10724#undef FIELD_LIST
10725
10726 private:
10727 bool Contains(intptr_t cid) const;
10728
10730};
10731
10732// Base class for speculative [CheckArrayBoundInstr] and
10733// non-speculative [GenericCheckBoundInstr] bounds checking.
10734class CheckBoundBaseInstr : public TemplateDefinition<2, NoThrow, Pure> {
10735 public:
10736 CheckBoundBaseInstr(Value* length, Value* index, intptr_t deopt_id)
10737 : TemplateDefinition(deopt_id) {
10738 SetInputAt(kLengthPos, length);
10739 SetInputAt(kIndexPos, index);
10740 }
10741
10742 Value* length() const { return inputs_[kLengthPos]; }
10743 Value* index() const { return inputs_[kIndexPos]; }
10744
10745 virtual Definition* Canonicalize(FlowGraph* flow_graph);
10746
10748
10749 virtual Value* RedefinedValue() const;
10750
10751 // Returns true if the bounds check can be eliminated without
10752 // changing the semantics (viz. 0 <= index < length).
10753 bool IsRedundant(bool use_loops = false);
10754
10755 // Give a name to the location/input indices.
10756 enum { kLengthPos = 0, kIndexPos = 1 };
10757
10759
10760 private:
10762};
10763
10764// Performs an array bounds check, where
10765// safe_index := CheckArrayBound(length, index)
10766// returns the "safe" index when
10767// 0 <= index < length
10768// or otherwise deoptimizes (viz. speculative).
10770 public:
10771 CheckArrayBoundInstr(Value* length, Value* index, intptr_t deopt_id)
10772 : CheckBoundBaseInstr(length, index, deopt_id), generalized_(false) {}
10773
10774 DECLARE_INSTRUCTION(CheckArrayBound)
10775
10776 virtual CompileType ComputeType() const;
10777 virtual bool RecomputeType();
10778
10779 virtual bool ComputeCanDeoptimize() const { return true; }
10780
10781 void mark_generalized() { generalized_ = true; }
10782
10783 // Returns the length offset for array and string types.
10784 static intptr_t LengthOffsetFor(intptr_t class_id);
10785
10786 static bool IsFixedLengthArrayType(intptr_t class_id);
10787
10788 virtual bool AttributesEqual(const Instruction& other) const { return true; }
10789
10790#define FIELD_LIST(F) F(bool, generalized_)
10791
10794 FIELD_LIST)
10795#undef FIELD_LIST
10796
10797 private:
10799};
10800
10801// Performs an array bounds check, where
10802// safe_index := GenericCheckBound(length, index)
10803// returns the "safe" index when
10804// 0 <= index < length
10805// or otherwise throws an out-of-bounds exception (viz. non-speculative).
10807 public:
10808 // We prefer to have unboxed inputs on 64-bit where values can fit into a
10809 // register.
10811 return compiler::target::kWordSize == 8;
10812 }
10813
10814 GenericCheckBoundInstr(Value* length, Value* index, intptr_t deopt_id)
10815 : CheckBoundBaseInstr(length, index, deopt_id) {}
10816
10817 virtual bool AttributesEqual(const Instruction& other) const { return true; }
10818
10819 DECLARE_INSTRUCTION(GenericCheckBound)
10820
10821 virtual CompileType ComputeType() const;
10822 virtual bool RecomputeType();
10823
10824 virtual intptr_t DeoptimizationTarget() const { return DeoptId::kNone; }
10825
10826 virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const {
10827 return kNotSpeculative;
10828 }
10829
10831 return UseUnboxedRepresentation() ? kUnboxedInt64 : kTagged;
10832 }
10833
10834 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
10835 ASSERT(idx == kIndexPos || idx == kLengthPos);
10836 return UseUnboxedRepresentation() ? kUnboxedInt64 : kTagged;
10837 }
10838
10839 // GenericCheckBound can implicitly call Dart code (RangeError or
10840 // ArgumentError constructor), so it can lazily deopt.
10841 virtual bool ComputeCanDeoptimize() const { return false; }
10842 virtual bool ComputeCanDeoptimizeAfterCall() const {
10843 return !CompilerState::Current().is_aot();
10844 }
10845
10846 virtual bool MayThrow() const { return true; }
10847
10848 virtual bool UseSharedSlowPathStub(bool is_optimizing) const {
10849 return SlowPathSharingSupported(is_optimizing);
10850 }
10851
10853
10854 private:
10856};
10857
10858class CheckWritableInstr : public TemplateDefinition<1, Throws, Pure> {
10859 public:
10860 enum Kind {
10861 kWriteUnmodifiableTypedData = 0,
10862 kDeeplyImmutableAttachNativeFinalizer = 1,
10863 };
10864
10866 intptr_t deopt_id,
10868 Kind kind = Kind::kWriteUnmodifiableTypedData)
10869 : TemplateDefinition(source, deopt_id), kind_(kind) {
10870 SetInputAt(kReceiver, receiver);
10871 }
10872
10873 virtual bool AttributesEqual(const Instruction& other) const { return true; }
10874
10875 DECLARE_INSTRUCTION(CheckWritable)
10876
10877 Value* value() const { return inputs_[kReceiver]; }
10878
10879 virtual Definition* Canonicalize(FlowGraph* flow_graph);
10880
10881 virtual Value* RedefinedValue() const;
10882
10883 virtual bool ComputeCanDeoptimize() const { return false; }
10884 virtual bool ComputeCanDeoptimizeAfterCall() const {
10885 return !CompilerState::Current().is_aot();
10886 }
10887
10888 Kind kind() const { return kind_; }
10889
10890 // Give a name to the location/input indices.
10891 enum {
10892 kReceiver = 0,
10893 };
10894
10895#define FIELD_LIST(F) F(const Kind, kind_)
10896
10899 FIELD_LIST)
10900
10901#undef FIELD_LIST
10902
10903 private:
10905};
10906
10907// Instruction evaluates the given comparison and deoptimizes if it evaluates
10908// to false.
10910 public:
10911 CheckConditionInstr(ComparisonInstr* comparison, intptr_t deopt_id)
10912 : Instruction(deopt_id), comparison_(comparison) {
10913 ASSERT(comparison->ArgumentCount() == 0);
10914 ASSERT(comparison->env() == nullptr);
10915 for (intptr_t i = comparison->InputCount() - 1; i >= 0; --i) {
10916 comparison->InputAt(i)->set_instruction(this);
10917 }
10918 }
10919
10920 ComparisonInstr* comparison() const { return comparison_; }
10921
10922 DECLARE_INSTRUCTION(CheckCondition)
10923
10924 virtual bool ComputeCanDeoptimize() const { return true; }
10925
10926 virtual Instruction* Canonicalize(FlowGraph* flow_graph);
10927
10928 virtual bool AllowsCSE() const { return true; }
10929 virtual bool HasUnknownSideEffects() const { return false; }
10930
10931 virtual bool AttributesEqual(const Instruction& other) const {
10932 return other.AsCheckCondition()->comparison()->AttributesEqual(
10933 *comparison());
10934 }
10935
10936 virtual intptr_t InputCount() const { return comparison()->InputCount(); }
10937 virtual Value* InputAt(intptr_t i) const { return comparison()->InputAt(i); }
10938
10939 virtual bool MayThrow() const { return false; }
10940
10941 virtual void CopyDeoptIdFrom(const Instruction& instr) {
10942 Instruction::CopyDeoptIdFrom(instr);
10943 comparison()->CopyDeoptIdFrom(instr);
10944 }
10945
10947
10948#define FIELD_LIST(F) F(ComparisonInstr*, comparison_)
10949
10952 FIELD_LIST)
10953#undef FIELD_LIST
10955
10956 private:
10957 virtual void RawSetInputAt(intptr_t i, Value* value) {
10958 comparison()->RawSetInputAt(i, value);
10959 }
10960
10962};
10963
10964class IntConverterInstr : public TemplateDefinition<1, NoThrow, Pure> {
10965 public:
10967 Representation to,
10968 Value* value,
10969 intptr_t deopt_id)
10970 : TemplateDefinition(deopt_id),
10971 from_representation_(from),
10972 to_representation_(to),
10973 is_truncating_(to == kUnboxedUint32) {
10974 ASSERT(from != to);
10975 // Integer conversion doesn't currently handle non-native representations.
10976 ASSERT_EQUAL(Boxing::NativeRepresentation(from), from);
10977 ASSERT_EQUAL(Boxing::NativeRepresentation(to), to);
10978 ASSERT(from == kUnboxedInt64 || from == kUnboxedUint32 ||
10979 from == kUnboxedInt32 || from == kUntagged);
10980 ASSERT(to == kUnboxedInt64 || to == kUnboxedUint32 || to == kUnboxedInt32 ||
10981 to == kUntagged);
10982 ASSERT(from != kUntagged || to == kUnboxedIntPtr || to == kUnboxedAddress);
10983 ASSERT(to != kUntagged || from == kUnboxedIntPtr ||
10984 from == kUnboxedAddress);
10985 // Don't allow conversions from unsafe untagged addresses.
10986 ASSERT(!value->definition()->MayCreateUnsafeUntaggedPointer());
10987 SetInputAt(0, value);
10988 }
10989
10990 Value* value() const { return inputs_[0]; }
10991
10992 Representation from() const { return from_representation_; }
10993 Representation to() const { return to_representation_; }
10994 bool is_truncating() const { return is_truncating_; }
10995
10996 void mark_truncating() { is_truncating_ = true; }
10997
10998 Definition* Canonicalize(FlowGraph* flow_graph);
10999
11000 virtual bool ComputeCanDeoptimize() const;
11001
11002 virtual Representation representation() const { return to(); }
11003
11004 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
11005 ASSERT(idx == 0);
11006 return from();
11007 }
11008
11009 virtual bool AttributesEqual(const Instruction& other) const {
11010 ASSERT(other.IsIntConverter());
11011 auto const converter = other.AsIntConverter();
11012 return (converter->from() == from()) && (converter->to() == to()) &&
11013 (converter->is_truncating() == is_truncating());
11014 }
11015
11016 virtual intptr_t DeoptimizationTarget() const { return GetDeoptId(); }
11017
11018 virtual void InferRange(RangeAnalysis* analysis, Range* range);
11019
11020 virtual bool MayCreateUnsafeUntaggedPointer() const {
11021 // The compiler no longer converts between unsafe untagged pointers and
11022 // unboxed integers.
11023 return false;
11024 }
11025
11026 DECLARE_INSTRUCTION(IntConverter);
11027
11028 DECLARE_ATTRIBUTES_NAMED(("from", "to", "is_truncating"),
11029 (from(), to(), is_truncating()))
11030
11032
11033#define FIELD_LIST(F) \
11034 F(const Representation, from_representation_) \
11035 F(const Representation, to_representation_) \
11036 F(bool, is_truncating_)
11037
11040 FIELD_LIST)
11041#undef FIELD_LIST
11042
11043 private:
11045};
11046
11047// Moves a floating-point value between CPU and FPU registers. Used to implement
11048// "softfp" calling conventions, where FPU arguments/return values are passed in
11049// normal CPU registers.
11050class BitCastInstr : public TemplateDefinition<1, NoThrow, Pure> {
11051 public:
11054 from_representation_(from),
11055 to_representation_(to) {
11056 ASSERT(from != to);
11057 ASSERT((to == kUnboxedInt32 && from == kUnboxedFloat) ||
11058 (to == kUnboxedFloat && from == kUnboxedInt32) ||
11059 (to == kUnboxedInt64 && from == kUnboxedDouble) ||
11060 (to == kUnboxedDouble && from == kUnboxedInt64));
11061 SetInputAt(0, value);
11062 }
11063
11064 Value* value() const { return inputs_[0]; }
11065
11066 Representation from() const { return from_representation_; }
11067 Representation to() const { return to_representation_; }
11068
11069 virtual bool ComputeCanDeoptimize() const { return false; }
11070
11071 virtual Representation representation() const { return to(); }
11072
11073 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
11074 ASSERT(idx == 0);
11075 return from();
11076 }
11077
11078 virtual bool AttributesEqual(const Instruction& other) const {
11079 ASSERT(other.IsBitCast());
11080 auto const converter = other.AsBitCast();
11081 return converter->from() == from() && converter->to() == to();
11082 }
11083
11085
11087
11088#define FIELD_LIST(F) \
11089 F(const Representation, from_representation_) \
11090 F(const Representation, to_representation_)
11091
11094 FIELD_LIST)
11095#undef FIELD_LIST
11096
11097 private:
11099};
11100
11101class LoadThreadInstr : public TemplateDefinition<0, NoThrow, Pure> {
11102 public:
11104
11105 virtual bool ComputeCanDeoptimize() const { return false; }
11106
11107 virtual Representation representation() const { return kUntagged; }
11108
11109 virtual Representation RequiredInputRepresentation(intptr_t idx) const {
11110 UNREACHABLE();
11111 }
11112
11113 virtual bool MayCreateUnsafeUntaggedPointer() const {
11114 // Threads are not GC-movable objects.
11115 return false;
11116 }
11117
11118 // CSE is allowed. The thread should always be the same value.
11119 virtual bool AttributesEqual(const Instruction& other) const {
11120 ASSERT(other.IsLoadThread());
11121 return true;
11122 }
11123
11125
11127
11128 private:
11130};
11131
11132// SimdOpInstr
11133//
11134// All SIMD intrinsics and recognized methods are represented via instances
11135// of SimdOpInstr, a particular type of SimdOp is selected by SimdOpInstr::Kind.
11136//
11137// Defines below are used to construct SIMD_OP_LIST - a list of all SIMD
11138// operations. SIMD_OP_LIST contains information such as arity, input types and
11139// output type for each SIMD op and is used to derive things like input
11140// and output representations, type of return value, etc.
11141//
11142// Lists of SIMD ops are defined using macro M, OP and BINARY_OP which are
11143// expected to have the following signature:
11144//
11145// (Arity, HasMask, Name, (In_0, ..., In_Arity), Out)
11146//
11147// where:
11148//
11149// HasMask is either _ or MASK and determines if operation has an
11150// constant mask attribute
11151// In_0, ..., In_Arity are input types
11152// Out is output type
11153//
11154
11155// A binary SIMD op with the given name that has signature T x T -> T.
11156#define SIMD_BINARY_OP(M, T, Name) M(2, _, T##Name, (T, T), T)
11157
11158// List of SIMD_BINARY_OPs common for Float32x4 or Float64x2.
11159// Note: M for recognized methods and OP for operators.
11160#define SIMD_BINARY_FLOAT_OP_LIST(M, OP, T) \
11161 SIMD_BINARY_OP(OP, T, Add) \
11162 SIMD_BINARY_OP(OP, T, Sub) \
11163 SIMD_BINARY_OP(OP, T, Mul) \
11164 SIMD_BINARY_OP(OP, T, Div) \
11165 SIMD_BINARY_OP(M, T, Min) \
11166 SIMD_BINARY_OP(M, T, Max)
11167
11168// List of SIMD_BINARY_OP for Int32x4.
11169// Note: M for recognized methods and OP for operators.
11170#define SIMD_BINARY_INTEGER_OP_LIST(M, OP, T) \
11171 SIMD_BINARY_OP(OP, T, Add) \
11172 SIMD_BINARY_OP(OP, T, Sub) \
11173 SIMD_BINARY_OP(OP, T, BitAnd) \
11174 SIMD_BINARY_OP(OP, T, BitOr) \
11175 SIMD_BINARY_OP(OP, T, BitXor)
11176
11177// Given a signature of a given SIMD op construct its per component variations.
11178#define SIMD_PER_COMPONENT_XYZW(M, Arity, Name, Inputs, Output) \
11179 M(Arity, _, Name##X, Inputs, Output) \
11180 M(Arity, _, Name##Y, Inputs, Output) \
11181 M(Arity, _, Name##Z, Inputs, Output) \
11182 M(Arity, _, Name##W, Inputs, Output)
11183
11184// Define conversion between two SIMD types.
11185#define SIMD_CONVERSION(M, FromType, ToType) \
11186 M(1, _, FromType##To##ToType, (FromType), ToType)
11187
11188// List of all recognized SIMD operations.
11189// Note: except for operations that map to operators (Add, Mul, Sub, Div,
11190// BitXor, BitOr) all other operations must match names used by
11191// MethodRecognizer. This allows to autogenerate conversion from
11192// MethodRecognizer::Kind into SimdOpInstr::Kind (see KindForMethod helper).
11193// Note: M is for those SimdOp that are recognized methods and BINARY_OP
11194// is for operators.
11195#define SIMD_OP_LIST(M, BINARY_OP) \
11196 SIMD_BINARY_FLOAT_OP_LIST(M, BINARY_OP, Float32x4) \
11197 SIMD_BINARY_FLOAT_OP_LIST(M, BINARY_OP, Float64x2) \
11198 SIMD_BINARY_INTEGER_OP_LIST(M, BINARY_OP, Int32x4) \
11199 SIMD_PER_COMPONENT_XYZW(M, 1, Float32x4Get, (Float32x4), Double) \
11200 SIMD_PER_COMPONENT_XYZW(M, 2, Float32x4With, (Double, Float32x4), Float32x4) \
11201 SIMD_PER_COMPONENT_XYZW(M, 1, Int32x4GetFlag, (Int32x4), Bool) \
11202 SIMD_PER_COMPONENT_XYZW(M, 2, Int32x4WithFlag, (Int32x4, Bool), Int32x4) \
11203 M(1, MASK, Float32x4Shuffle, (Float32x4), Float32x4) \
11204 M(1, MASK, Int32x4Shuffle, (Int32x4), Int32x4) \
11205 M(2, MASK, Float32x4ShuffleMix, (Float32x4, Float32x4), Float32x4) \
11206 M(2, MASK, Int32x4ShuffleMix, (Int32x4, Int32x4), Int32x4) \
11207 M(2, _, Float32x4Equal, (Float32x4, Float32x4), Int32x4) \
11208 M(2, _, Float32x4GreaterThan, (Float32x4, Float32x4), Int32x4) \
11209 M(2, _, Float32x4GreaterThanOrEqual, (Float32x4, Float32x4), Int32x4) \
11210 M(2, _, Float32x4LessThan, (Float32x4, Float32x4), Int32x4) \
11211 M(2, _, Float32x4LessThanOrEqual, (Float32x4, Float32x4), Int32x4) \
11212 M(2, _, Float32x4NotEqual, (Float32x4, Float32x4), Int32x4) \
11213 M(4, _, Int32x4FromInts, (Int32, Int32, Int32, Int32), Int32x4) \
11214 M(4, _, Int32x4FromBools, (Bool, Bool, Bool, Bool), Int32x4) \
11215 M(4, _, Float32x4FromDoubles, (Double, Double, Double, Double), Float32x4) \
11216 M(2, _, Float64x2FromDoubles, (Double, Double), Float64x2) \
11217 M(0, _, Float32x4Zero, (), Float32x4) \
11218 M(0, _, Float64x2Zero, (), Float64x2) \
11219 M(1, _, Float32x4Splat, (Double), Float32x4) \
11220 M(1, _, Float64x2Splat, (Double), Float64x2) \
11221 M(1, _, Int32x4GetSignMask, (Int32x4), Int8) \
11222 M(1, _, Float32x4GetSignMask, (Float32x4), Int8) \
11223 M(1, _, Float64x2GetSignMask, (Float64x2), Int8) \
11224 M(2, _, Float32x4Scale, (Double, Float32x4), Float32x4) \
11225 M(2, _, Float64x2Scale, (Float64x2, Double), Float64x2) \
11226 M(1, _, Float32x4Sqrt, (Float32x4), Float32x4) \
11227 M(1, _, Float64x2Sqrt, (Float64x2), Float64x2) \
11228 M(1, _, Float32x4Reciprocal, (Float32x4), Float32x4) \
11229 M(1, _, Float32x4ReciprocalSqrt, (Float32x4), Float32x4) \
11230 M(1, _, Float32x4Negate, (Float32x4), Float32x4) \
11231 M(1, _, Float64x2Negate, (Float64x2), Float64x2) \
11232 M(1, _, Float32x4Abs, (Float32x4), Float32x4) \
11233 M(1, _, Float64x2Abs, (Float64x2), Float64x2) \
11234 M(3, _, Float32x4Clamp, (Float32x4, Float32x4, Float32x4), Float32x4) \
11235 M(3, _, Float64x2Clamp, (Float64x2, Float64x2, Float64x2), Float64x2) \
11236 M(1, _, Float64x2GetX, (Float64x2), Double) \
11237 M(1, _, Float64x2GetY, (Float64x2), Double) \
11238 M(2, _, Float64x2WithX, (Float64x2, Double), Float64x2) \
11239 M(2, _, Float64x2WithY, (Float64x2, Double), Float64x2) \
11240 M(3, _, Int32x4Select, (Int32x4, Float32x4, Float32x4), Float32x4) \
11241 SIMD_CONVERSION(M, Float32x4, Int32x4) \
11242 SIMD_CONVERSION(M, Int32x4, Float32x4) \
11243 SIMD_CONVERSION(M, Float32x4, Float64x2) \
11244 SIMD_CONVERSION(M, Float64x2, Float32x4)
11245
11246class SimdOpInstr : public Definition {
11247 public:
11248 enum Kind {
11249#define DECLARE_ENUM(Arity, Mask, Name, ...) k##Name,
11251#undef DECLARE_ENUM
11253 };
11254
11255 // Create SimdOp from the arguments of the given call and the given receiver.
11256 static SimdOpInstr* CreateFromCall(Zone* zone,
11258 Definition* receiver,
11259 Instruction* call,
11260 intptr_t mask = 0);
11261
11262 // Create SimdOp from the arguments of the given factory call.
11263 static SimdOpInstr* CreateFromFactoryCall(Zone* zone,
11265 Instruction* call);
11266
11267 // Create a binary SimdOp instr.
11269 Value* left,
11270 Value* right,
11271 intptr_t deopt_id) {
11272 return new SimdOpInstr(kind, left, right, deopt_id);
11273 }
11274
11275 // Create a binary SimdOp instr.
11277 Value* left,
11278 Value* right,
11279 intptr_t deopt_id) {
11280 return new SimdOpInstr(KindForMethod(kind), left, right, deopt_id);
11281 }
11282
11283 // Create a unary SimdOp.
11285 Value* left,
11286 intptr_t deopt_id) {
11287 return new SimdOpInstr(KindForMethod(kind), left, deopt_id);
11288 }
11289
11290 static Kind KindForOperator(MethodRecognizer::Kind kind);
11291
11292 static Kind KindForMethod(MethodRecognizer::Kind method_kind);
11293
11294 // Convert a combination of SIMD cid and an arithmetic token into Kind, e.g.
11295 // Float32x4 and Token::kADD becomes Float32x4Add.
11296 static Kind KindForOperator(intptr_t cid, Token::Kind op);
11297
11298 virtual intptr_t InputCount() const;
11299 virtual Value* InputAt(intptr_t i) const {
11300 ASSERT(0 <= i && i < InputCount());
11301 return inputs_[i];
11302 }
11303
11304 Kind kind() const { return kind_; }
11305 intptr_t mask() const {
11306 ASSERT(HasMask());
11307 return mask_;
11308 }
11309
11310 virtual Representation representation() const;
11311 virtual Representation RequiredInputRepresentation(intptr_t idx) const;
11312
11313 virtual CompileType ComputeType() const;
11314
11315 virtual bool MayThrow() const { return false; }
11316 virtual bool ComputeCanDeoptimize() const { return false; }
11317
11318 virtual intptr_t DeoptimizationTarget() const {
11319 // Direct access since this instruction cannot deoptimize, and the deopt-id
11320 // was inherited from another instruction that could deoptimize.
11321 return GetDeoptId();
11322 }
11323
11324 virtual bool HasUnknownSideEffects() const { return false; }
11325 virtual bool AllowsCSE() const { return true; }
11326
11327 virtual bool AttributesEqual(const Instruction& other) const {
11328 auto const other_op = other.AsSimdOp();
11329 return kind() == other_op->kind() &&
11330 (!HasMask() || mask() == other_op->mask());
11331 }
11332
11333 virtual Definition* Canonicalize(FlowGraph* flow_graph);
11334
11335 DECLARE_INSTRUCTION(SimdOp)
11337
11338#define FIELD_LIST(F) \
11339 F(const Kind, kind_) \
11340 F(intptr_t, mask_)
11341
11343#undef FIELD_LIST
11344
11345 private:
11346 SimdOpInstr(Kind kind, intptr_t deopt_id)
11347 : Definition(deopt_id), kind_(kind) {}
11348
11349 SimdOpInstr(Kind kind, Value* left, intptr_t deopt_id)
11350 : Definition(deopt_id), kind_(kind) {
11351 SetInputAt(0, left);
11352 }
11353
11354 SimdOpInstr(Kind kind, Value* left, Value* right, intptr_t deopt_id)
11355 : Definition(deopt_id), kind_(kind) {
11356 SetInputAt(0, left);
11357 SetInputAt(1, right);
11358 }
11359
11360 bool HasMask() const;
11361 void set_mask(intptr_t mask) { mask_ = mask; }
11362
11363 virtual void RawSetInputAt(intptr_t i, Value* value) { inputs_[i] = value; }
11364
11365 // We consider SimdOpInstr to be very uncommon so we don't optimize them for
11366 // size. Any instance of SimdOpInstr has enough space to fit any variation.
11367 // TODO(dartbug.com/30949) optimize this for size.
11368 Value* inputs_[4];
11369
11371};
11372
11373// Generic instruction to call 1-argument stubs specified using [StubId].
11374class Call1ArgStubInstr : public TemplateDefinition<1, Throws> {
11375 public:
11376 enum class StubId {
11377 kCloneSuspendState,
11378 kInitAsync,
11379 kInitAsyncStar,
11380 kInitSyncStar,
11381 kFfiAsyncCallbackSend,
11382 };
11383
11385 StubId stub_id,
11386 Value* operand,
11387 intptr_t deopt_id)
11388 : TemplateDefinition(source, deopt_id),
11389 stub_id_(stub_id),
11390 token_pos_(source.token_pos) {
11391 SetInputAt(0, operand);
11392 }
11393
11394 Value* operand() const { return inputs_[0]; }
11395 StubId stub_id() const { return stub_id_; }
11396 virtual TokenPosition token_pos() const { return token_pos_; }
11397
11398 virtual bool CanCallDart() const { return true; }
11399 virtual bool ComputeCanDeoptimize() const { return false; }
11400 virtual bool ComputeCanDeoptimizeAfterCall() const { return true; }
11401 virtual bool HasUnknownSideEffects() const { return true; }
11402 virtual intptr_t NumberOfInputsConsumedBeforeCall() const {
11403 return InputCount();
11404 }
11405
11406 DECLARE_INSTRUCTION(Call1ArgStub);
11408
11409#define FIELD_LIST(F) \
11410 F(const StubId, stub_id_) \
11411 F(const TokenPosition, token_pos_)
11412
11415 FIELD_LIST)
11416#undef FIELD_LIST
11417
11418 private:
11420};
11421
11422// Suspends execution using the suspend stub specified using [StubId].
11423class SuspendInstr : public TemplateDefinition<2, Throws> {
11424 public:
11425 enum class StubId {
11426 kAwait,
11427 kAwaitWithTypeCheck,
11428 kYieldAsyncStar,
11429 kSuspendSyncStarAtStart,
11430 kSuspendSyncStarAtYield,
11431 };
11432
11434 StubId stub_id,
11435 Value* operand,
11436 Value* type_args,
11437 intptr_t deopt_id,
11438 intptr_t resume_deopt_id)
11439 : TemplateDefinition(source, deopt_id),
11440 stub_id_(stub_id),
11441 resume_deopt_id_(resume_deopt_id),
11442 token_pos_(source.token_pos) {
11443 SetInputAt(0, operand);
11444 if (has_type_args()) {
11445 SetInputAt(1, type_args);
11446 } else {
11447 ASSERT(type_args == nullptr);
11448 }
11449 }
11450
11451 bool has_type_args() const { return stub_id_ == StubId::kAwaitWithTypeCheck; }
11452 virtual intptr_t InputCount() const { return has_type_args() ? 2 : 1; }
11453
11454 Value* operand() const { return inputs_[0]; }
11455 Value* type_args() const {
11456 ASSERT(has_type_args());
11457 return inputs_[1];
11458 }
11459
11460 StubId stub_id() const { return stub_id_; }
11461 intptr_t resume_deopt_id() const { return resume_deopt_id_; }
11462 virtual TokenPosition token_pos() const { return token_pos_; }
11463
11464 virtual bool CanCallDart() const { return true; }
11465 virtual bool ComputeCanDeoptimize() const { return false; }
11466 virtual bool ComputeCanDeoptimizeAfterCall() const { return true; }
11467 virtual bool HasUnknownSideEffects() const { return true; }
11468 virtual intptr_t NumberOfInputsConsumedBeforeCall() const {
11469 return InputCount();
11470 }
11471
11474
11475 virtual Definition* Canonicalize(FlowGraph* flow_graph);
11476
11477#define FIELD_LIST(F) \
11478 F(StubId, stub_id_) \
11479 F(const intptr_t, resume_deopt_id_) \
11480 F(const TokenPosition, token_pos_)
11481
11484 FIELD_LIST)
11485#undef FIELD_LIST
11486
11487 private:
11489};
11490
11491#undef DECLARE_INSTRUCTION
11492
11494 public:
11495 // Iterate the non-null values in the innermost level of an environment.
11497 public:
11498 explicit ShallowIterator(Environment* environment)
11499 : environment_(environment), index_(0) {}
11500
11502 : ValueObject(),
11503 environment_(other.environment_),
11504 index_(other.index_) {}
11505
11507 environment_ = other.environment_;
11508 index_ = other.index_;
11509 return *this;
11510 }
11511
11512 Environment* environment() const { return environment_; }
11513
11514 void Advance() {
11515 ASSERT(!Done());
11516 ++index_;
11517 }
11518
11519 bool Done() const {
11520 return (environment_ == nullptr) || (index_ >= environment_->Length());
11521 }
11522
11524 ASSERT(!Done());
11525 ASSERT(environment_->values_[index_] != nullptr);
11526 return environment_->values_[index_];
11527 }
11528
11529 void SetCurrentValue(Value* value) {
11530 ASSERT(!Done());
11531 ASSERT(value != nullptr);
11532 environment_->values_[index_] = value;
11533 }
11534
11536 ASSERT(!Done());
11537 return environment_->locations_[index_];
11538 }
11539
11541 ASSERT(!Done());
11542 environment_->locations_[index_] = loc;
11543 }
11544
11545 private:
11546 Environment* environment_;
11547 intptr_t index_;
11548 };
11549
11550 // Iterate all non-null values in an environment, including outer
11551 // environments. Note that the iterator skips empty environments.
11552 class DeepIterator : public ValueObject {
11553 public:
11554 explicit DeepIterator(Environment* environment) : iterator_(environment) {
11555 SkipDone();
11556 }
11557
11558 void Advance() {
11559 ASSERT(!Done());
11560 iterator_.Advance();
11561 SkipDone();
11562 }
11563
11564 bool Done() const { return iterator_.environment() == nullptr; }
11565
11567 ASSERT(!Done());
11568 return iterator_.CurrentValue();
11569 }
11570
11571 void SetCurrentValue(Value* value) {
11572 ASSERT(!Done());
11573 iterator_.SetCurrentValue(value);
11574 }
11575
11577 ASSERT(!Done());
11578 return iterator_.CurrentLocation();
11579 }
11580
11582 ASSERT(!Done());
11583 iterator_.SetCurrentLocation(loc);
11584 }
11585
11586 private:
11587 void SkipDone() {
11588 while (!Done() && iterator_.Done()) {
11589 iterator_ = ShallowIterator(iterator_.environment()->outer());
11590 }
11591 }
11592
11593 ShallowIterator iterator_;
11594 };
11595
11596 // Construct an environment by constructing uses from an array of definitions.
11597 static Environment* From(Zone* zone,
11598 const GrowableArray<Definition*>& definitions,
11599 intptr_t fixed_parameter_count,
11600 intptr_t lazy_deopt_pruning_count,
11601 const ParsedFunction& parsed_function);
11602
11603 void set_locations(Location* locations) {
11604 ASSERT(locations_ == nullptr);
11605 locations_ = locations;
11606 }
11607
11608 // Get deopt_id associated with this environment.
11609 // Note that only outer environments have deopt id associated with
11610 // them (set by DeepCopyToOuter).
11611 intptr_t GetDeoptId() const {
11612 ASSERT(DeoptIdBits::decode(bitfield_) != DeoptId::kNone);
11613 return DeoptIdBits::decode(bitfield_);
11614 }
11615
11616 intptr_t LazyDeoptPruneCount() const {
11617 return LazyDeoptPruningBits::decode(bitfield_);
11618 }
11619
11621 return LazyDeoptToBeforeDeoptId::decode(bitfield_);
11622 }
11623
11625 bitfield_ = LazyDeoptToBeforeDeoptId::update(true, bitfield_);
11626 // As eager and lazy deopts will target the before environment, we do not
11627 // want to prune inputs on lazy deopts.
11628 bitfield_ = LazyDeoptPruningBits::update(0, bitfield_);
11629 }
11630
11631 // This environment belongs to an optimistically hoisted instruction.
11632 bool IsHoisted() const { return Hoisted::decode(bitfield_); }
11633
11634 void MarkAsHoisted() { bitfield_ = Hoisted::update(true, bitfield_); }
11635
11637 if (LazyDeoptToBeforeDeoptId()) {
11638 ASSERT(LazyDeoptPruneCount() == 0);
11639 }
11640 const intptr_t num_args_to_prune = LazyDeoptPruneCount();
11641 if (num_args_to_prune == 0) return this;
11642 return DeepCopy(zone, Length() - num_args_to_prune);
11643 }
11644
11645 Environment* outer() const { return outer_; }
11646
11648 Environment* result = this;
11649 while (result->outer() != nullptr)
11650 result = result->outer();
11651 return result;
11652 }
11653
11654 Value* ValueAt(intptr_t ix) const { return values_[ix]; }
11655
11656 void PushValue(Value* value);
11657
11658 intptr_t Length() const { return values_.length(); }
11659
11660 Location LocationAt(intptr_t index) const {
11661 ASSERT((index >= 0) && (index < values_.length()));
11662 return locations_[index];
11663 }
11664
11665 // The use index is the index in the flattened environment.
11666 Value* ValueAtUseIndex(intptr_t index) const {
11667 const Environment* env = this;
11668 while (index >= env->Length()) {
11669 ASSERT(env->outer_ != nullptr);
11670 index -= env->Length();
11671 env = env->outer_;
11672 }
11673 return env->ValueAt(index);
11674 }
11675
11676 intptr_t fixed_parameter_count() const { return fixed_parameter_count_; }
11677
11678 intptr_t CountArgsPushed() {
11679 intptr_t count = 0;
11680 for (Environment::DeepIterator it(this); !it.Done(); it.Advance()) {
11681 if (it.CurrentValue()->definition()->IsMoveArgument()) {
11682 count++;
11683 }
11684 }
11685 return count;
11686 }
11687
11688 const Function& function() const { return function_; }
11689
11690 Environment* DeepCopy(Zone* zone) const { return DeepCopy(zone, Length()); }
11691
11692 void DeepCopyTo(Zone* zone, Instruction* instr) const;
11693 void DeepCopyToOuter(Zone* zone,
11694 Instruction* instr,
11695 intptr_t outer_deopt_id) const;
11696
11697 void DeepCopyAfterTo(Zone* zone,
11698 Instruction* instr,
11699 intptr_t argc,
11700 Definition* dead,
11701 Definition* result) const;
11702
11703 void PrintTo(BaseTextBuffer* f) const;
11704 const char* ToCString() const;
11705
11706 // Deep copy an environment. The 'length' parameter may be less than the
11707 // environment's length in order to drop values (e.g., passed arguments)
11708 // from the copy.
11709 Environment* DeepCopy(Zone* zone, intptr_t length) const;
11710
11711 void Write(FlowGraphSerializer* s) const;
11713
11714 private:
11715 friend class ShallowIterator;
11716 friend class compiler::BlockBuilder; // For Environment constructor.
11717
11718 class LazyDeoptPruningBits : public BitField<uintptr_t, uintptr_t, 0, 8> {};
11719 class LazyDeoptToBeforeDeoptId
11720 : public BitField<uintptr_t, bool, LazyDeoptPruningBits::kNextBit, 1> {};
11721 class Hoisted : public BitField<uintptr_t,
11722 bool,
11723 LazyDeoptToBeforeDeoptId::kNextBit,
11724 1> {};
11725 class DeoptIdBits : public BitField<uintptr_t,
11726 intptr_t,
11727 Hoisted::kNextBit,
11728 kBitsPerWord - Hoisted::kNextBit,
11729 /*sign_extend=*/true> {};
11730
11731 Environment(intptr_t length,
11732 intptr_t fixed_parameter_count,
11733 intptr_t lazy_deopt_pruning_count,
11734 const Function& function,
11735 Environment* outer)
11736 : values_(length),
11737 fixed_parameter_count_(fixed_parameter_count),
11738 bitfield_(DeoptIdBits::encode(DeoptId::kNone) |
11739 LazyDeoptToBeforeDeoptId::encode(false) |
11740 LazyDeoptPruningBits::encode(lazy_deopt_pruning_count)),
11741 function_(function),
11742 outer_(outer) {}
11743
11744 void SetDeoptId(intptr_t deopt_id) {
11745 bitfield_ = DeoptIdBits::update(deopt_id, bitfield_);
11746 }
11747 void SetLazyDeoptPruneCount(intptr_t value) {
11748 bitfield_ = LazyDeoptPruningBits::update(value, bitfield_);
11749 }
11750 void SetLazyDeoptToBeforeDeoptId(bool value) {
11751 bitfield_ = LazyDeoptToBeforeDeoptId::update(value, bitfield_);
11752 }
11753
11754 GrowableArray<Value*> values_;
11755 Location* locations_ = nullptr;
11756 const intptr_t fixed_parameter_count_;
11757 // Deoptimization id associated with this environment. Only set for
11758 // outer environments.
11759 uintptr_t bitfield_;
11760 const Function& function_;
11761 Environment* outer_;
11762
11763 DISALLOW_COPY_AND_ASSIGN(Environment);
11764};
11765
11767 public:
11770
11771// Visit functions for instruction classes, with an empty default
11772// implementation.
11773#define DECLARE_VISIT_INSTRUCTION(ShortName, Attrs) \
11774 virtual void Visit##ShortName(ShortName##Instr* instr) {}
11775
11777
11778#undef DECLARE_VISIT_INSTRUCTION
11779
11780 private:
11781 DISALLOW_COPY_AND_ASSIGN(InstructionVisitor);
11782};
11783
11784// Visitor base class to visit each instruction and computation in a flow
11785// graph as defined by a reversed list of basic blocks.
11787 public:
11789 : current_iterator_(nullptr), block_order_(&block_order) {}
11791
11793 return current_iterator_;
11794 }
11795
11796 // Visit each block in the block order, and for each block its
11797 // instructions in order from the block entry to exit.
11798 virtual void VisitBlocks();
11799
11800 protected:
11802 block_order_ = &block_order;
11803 }
11804
11806
11807 private:
11808 const GrowableArray<BlockEntryInstr*>* block_order_;
11810};
11811
11812// Helper macros for platform ports.
11813#define DEFINE_UNIMPLEMENTED_INSTRUCTION(Name) \
11814 LocationSummary* Name::MakeLocationSummary(Zone* zone, bool opt) const { \
11815 UNIMPLEMENTED(); \
11816 return nullptr; \
11817 } \
11818 void Name::EmitNativeCode(FlowGraphCompiler* compiler) { \
11819 UNIMPLEMENTED(); \
11820 }
11821
11822template <intptr_t kExtraInputs>
11824 if (auto static_call = this->AsStaticCall()) {
11825 return static_call->function().name();
11826 } else if (auto instance_call = this->AsInstanceCall()) {
11827 return instance_call->function_name().ptr();
11828 } else {
11829 UNREACHABLE();
11830 }
11831}
11832
11833inline bool Value::CanBe(const Object& value) {
11834 ConstantInstr* constant = definition()->AsConstant();
11835 return (constant == nullptr) || constant->value().ptr() == value.ptr();
11836}
11837#undef DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS
11838#undef DECLARE_CUSTOM_SERIALIZATION
11839#undef DECLARE_EMPTY_SERIALIZATION
11840
11841} // namespace dart
11842
11843#endif // RUNTIME_VM_COMPILER_BACKEND_IL_H_
static bool compare(const SkBitmap &ref, const SkIRect &iref, const SkBitmap &test, const SkIRect &itest)
Definition BlurTest.cpp:100
static void done(const char *config, const char *src, const char *srcOptions, const char *name)
Definition DM.cpp:263
int count
SkPoint pos
static float next(float f)
static float prev(float f)
static sk_sp< Effect > Create()
static std::unique_ptr< SkEncoder > Make(SkWStream *dst, const SkPixmap *src, const SkYUVAPixmaps *srcYUVA, const SkColorSpace *srcYUVAColorSpace, const SkJpegEncoder::Options &options)
static void encode(uint8_t output[16], const uint32_t input[4])
Definition SkMD5.cpp:240
static bool left(const SkPoint &p0, const SkPoint &p1)
static bool right(const SkPoint &p0, const SkPoint &p1)
SI F table(const skcms_Curve *curve, F v)
static size_t element_size(Layout layout, SkSLType type)
Vec2Value v2
#define UNREACHABLE()
Definition assert.h:248
#define DEBUG_ASSERT(cond)
Definition assert.h:321
#define ASSERT_EQUAL(expected, actual)
Definition assert.h:309
#define COMPILE_ASSERT(expr)
Definition assert.h:339
#define N
Definition beziers.cpp:19
static AliasIdentity NotAliased()
Definition il.h:2405
static AliasIdentity Aliased()
Definition il.h:2402
bool IsAliased() const
Definition il.h:2433
bool IsNotAliased() const
Definition il.h:2434
AliasIdentity & operator=(const AliasIdentity &other)
Definition il.h:2442
bool IsUnknown() const
Definition il.h:2432
bool IsAllocationSinkingCandidate() const
Definition il.h:2435
static AliasIdentity Unknown()
Definition il.h:2399
AliasIdentity(const AliasIdentity &other)
Definition il.h:2439
const char * ToCString()
Definition il.h:2419
static AliasIdentity AllocationSinkingCandidate()
Definition il.h:2409
virtual const Slot * SlotForInput(intptr_t pos)
Definition il.h:7499
virtual bool WillAllocateNewOrRemembered() const
Definition il.h:7528
virtual bool AllowsCSE() const
Definition il.h:7516
virtual intptr_t InputCount() const
Definition il.h:7477
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:7520
bool is_generic() const
Definition il.h:7487
Value * context() const
Definition il.h:7482
bool has_instantiator_type_args() const
Definition il.h:7484
Value * closure_function() const
Definition il.h:7481
bool is_tear_off() const
Definition il.h:7488
virtual bool HasUnknownSideEffects() const
Definition il.h:7518
const Function & known_function() const
Definition il.h:7490
AllocateClosureInstr(const InstructionSource &source, Value *closure_function, Value *context, Value *instantiator_type_args, bool is_generic, bool is_tear_off, intptr_t deopt_id)
Definition il.h:7456
virtual bool HasUnknownSideEffects() const
Definition il.h:8350
const ZoneGrowableArray< const Slot * > & context_slots() const
Definition il.h:8340
virtual bool ComputeCanDeoptimize() const
Definition il.h:8348
AllocateContextInstr(const InstructionSource &source, const ZoneGrowableArray< const Slot * > &context_slots, intptr_t deopt_id)
Definition il.h:8332
intptr_t num_context_variables() const
Definition il.h:8344
virtual bool WillAllocateNewOrRemembered() const
Definition il.h:8352
DISALLOW_COPY_AND_ASSIGN(AllocateObjectInstr)
Value * type_arguments() const
Definition il.h:7397
virtual bool MayHaveVisibleEffect() const
Definition il.h:7410
const Class & cls() const
Definition il.h:7396
virtual bool HasUnknownSideEffects() const
Definition il.h:7405
virtual Value * InputAt(intptr_t i) const
Definition il.h:7400
AllocateObjectInstr(const InstructionSource &source, const Class &cls, intptr_t deopt_id, Value *type_arguments=nullptr)
Definition il.h:7374
virtual const Slot * SlotForInput(intptr_t pos)
Definition il.h:7420
virtual bool WillAllocateNewOrRemembered() const
Definition il.h:7412
DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(AllocateObjectInstr, AllocationInstr, FIELD_LIST) private
Definition il.h:7431
static bool WillAllocateNewOrRemembered(const Class &cls)
Definition il.h:7416
virtual intptr_t InputCount() const
Definition il.h:7399
virtual bool HasUnknownSideEffects() const
Definition il.h:7593
virtual bool WillAllocateNewOrRemembered() const
Definition il.h:7595
AllocateRecordInstr(const InstructionSource &source, RecordShape shape, intptr_t deopt_id)
Definition il.h:7582
RecordShape shape() const
Definition il.h:7590
intptr_t num_fields() const
Definition il.h:7591
virtual bool WillAllocateNewOrRemembered() const
Definition il.h:7647
intptr_t num_fields() const
Definition il.h:7636
AllocateSmallRecordInstr(const InstructionSource &source, RecordShape shape, Value *value0, Value *value1, Value *value2, intptr_t deopt_id)
Definition il.h:7615
virtual const Slot * SlotForInput(intptr_t pos)
Definition il.h:7640
virtual bool HasUnknownSideEffects() const
Definition il.h:7645
RecordShape shape() const
Definition il.h:7635
virtual intptr_t InputCount() const
Definition il.h:7638
virtual bool WillAllocateNewOrRemembered() const
Definition il.h:7855
AllocateTypedDataInstr(const InstructionSource &source, classid_t class_id, Value *num_elements, intptr_t deopt_id)
Definition il.h:7837
classid_t class_id() const
Definition il.h:7850
virtual Value * num_elements() const
Definition il.h:7851
virtual bool HasUnknownSideEffects() const
Definition il.h:7853
virtual const Slot * SlotForInput(intptr_t pos)
Definition il.h:7860
virtual bool WillAllocateNewOrRemembered() const
Definition il.h:7559
virtual bool HasUnknownSideEffects() const
Definition il.h:7557
intptr_t num_context_variables() const
Definition il.h:7555
virtual bool MayThrow() const
Definition il.h:7290
intptr_t InputForSlot(const Slot &slot)
Definition il.h:7312
virtual bool WillAllocateNewOrRemembered() const =0
virtual AliasIdentity Identity() const
Definition il.h:7283
virtual bool ObjectIsInitialized()
Definition il.h:7324
virtual void SetIdentity(AliasIdentity identity)
Definition il.h:7284
virtual const Slot * SlotForInput(intptr_t pos)
Definition il.h:7308
AllocationInstr(const InstructionSource &source, intptr_t deopt_id=DeoptId::kNone)
Definition il.h:7275
virtual TokenPosition token_pos() const
Definition il.h:7281
virtual bool ComputeCanDeoptimize() const
Definition il.h:7294
virtual bool ComputeCanDeoptimizeAfterCall() const
Definition il.h:7295
virtual intptr_t NumberOfInputsConsumedBeforeCall() const
Definition il.h:7301
PRINT_OPERANDS_TO_SUPPORT DECLARE_ABSTRACT_INSTRUCTION(Allocation)
intptr_t GetConstantNumElements() const
Definition il.h:7757
ArrayAllocationInstr(const InstructionSource &source, intptr_t deopt_id)
Definition il.h:7748
bool HasConstantNumElements() const
Definition il.h:7754
virtual Value * num_elements() const =0
DECLARE_ABSTRACT_INSTRUCTION(ArrayAllocation)
Value * dst_type() const
Definition il.h:4405
virtual bool ComputeCanDeoptimize() const
Definition il.h:4414
const String & dst_name() const
Definition il.h:4412
Value * value() const
Definition il.h:4404
virtual intptr_t NumberOfInputsConsumedBeforeCall() const
Definition il.h:4418
Value * function_type_arguments() const
Definition il.h:4409
Value * instantiator_type_arguments() const
Definition il.h:4406
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:4438
virtual bool CanBecomeDeoptimizationTarget() const
Definition il.h:4430
virtual bool ComputeCanDeoptimizeAfterCall() const
Definition il.h:4415
AssertAssignableInstr(const InstructionSource &source, Value *value, Value *dst_type, Value *instantiator_type_arguments, Value *function_type_arguments, const String &dst_name, intptr_t deopt_id, Kind kind=kUnknown)
Definition il.h:4379
virtual TokenPosition token_pos() const
Definition il.h:4411
virtual TokenPosition token_pos() const
Definition il.h:4472
virtual bool ComputeCanDeoptimizeAfterCall() const
Definition il.h:4476
virtual intptr_t NumberOfInputsConsumedBeforeCall() const
Definition il.h:4479
Value * value() const
Definition il.h:4473
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:4485
AssertBooleanInstr(const InstructionSource &source, Value *value, intptr_t deopt_id)
Definition il.h:4462
virtual bool ComputeCanDeoptimize() const
Definition il.h:4475
virtual bool CanBecomeDeoptimizationTarget() const
Definition il.h:4337
AssertSubtypeInstr(const InstructionSource &source, Value *instantiator_type_arguments, Value *function_type_arguments, Value *sub_type, Value *super_type, Value *dst_name, intptr_t deopt_id)
Definition il.h:4302
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:4341
Value * function_type_arguments() const
Definition il.h:4322
DECLARE_INSTRUCTION(AssertSubtype)
virtual TokenPosition token_pos() const
Definition il.h:4327
Value * dst_name() const
Definition il.h:4325
Value * super_type() const
Definition il.h:4324
Value * sub_type() const
Definition il.h:4323
virtual bool ComputeCanDeoptimizeAfterCall() const
Definition il.h:4330
virtual bool ComputeCanDeoptimize() const
Definition il.h:4329
Value * instantiator_type_arguments() const
Definition il.h:4319
virtual intptr_t NumberOfInputsConsumedBeforeCall() const
Definition il.h:4333
Instruction * Current() const
Definition il.h:1893
BackwardInstructionIterator(BlockEntryInstr *block_entry)
Definition il.h:1879
intptr_t length() const
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const
Definition il.h:9003
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:8998
BinaryDoubleOpInstr(Token::Kind op_kind, Value *left, Value *right, intptr_t deopt_id, const InstructionSource &source, SpeculativeMode speculative_mode=kGuardInputs, Representation representation=kUnboxedDouble)
Definition il.h:8969
Token::Kind op_kind() const
Definition il.h:8990
Value * right() const
Definition il.h:8988
virtual TokenPosition token_pos() const
Definition il.h:8992
virtual Representation representation() const
Definition il.h:8996
virtual bool ComputeCanDeoptimize() const
Definition il.h:8994
Value * left() const
Definition il.h:8987
virtual intptr_t DeoptimizationTarget() const
Definition il.h:9007
bool OperandsAre(intptr_t cid) const
Definition il.h:875
bool OperandsAreSmiOrMint() const
Definition il.h:868
bool IncludesOperands(intptr_t cid) const
Definition il.h:880
bool OperandsAreSmiOrNull() const
Definition il.h:865
bool ArgumentIs(intptr_t cid) const
Definition il.h:839
static const BinaryFeedback * CreateMonomorphic(Zone *zone, intptr_t receiver_cid, intptr_t argument_cid)
Definition il.cc:4113
bool OperandsAreSmiOrDouble() const
Definition il.h:871
bool OperandsAreEither(intptr_t cid_a, intptr_t cid_b) const
Definition il.h:851
BinaryFeedback(Zone *zone)
Definition il.h:832
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:9481
BinaryInt32OpInstr(Token::Kind op_kind, Value *left, Value *right, intptr_t deopt_id)
Definition il.h:9440
virtual Representation representation() const
Definition il.h:9479
static bool IsSupported(Token::Kind op_kind, Value *left, Value *right)
Definition il.h:9449
virtual bool ComputeCanDeoptimize() const
Definition il.h:9552
BinaryInt64OpInstr(Token::Kind op_kind, Value *left, Value *right, intptr_t deopt_id, SpeculativeMode speculative_mode=kGuardInputs)
Definition il.h:9542
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:9564
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:9573
virtual Representation representation() const
Definition il.h:9562
virtual bool MayThrow() const
Definition il.h:9557
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const
Definition il.h:9569
void set_can_overflow(bool overflow)
Definition il.h:9353
bool can_overflow() const
Definition il.h:9352
Value * right() const
Definition il.h:9350
Token::Kind op_kind() const
Definition il.h:9348
Value * left() const
Definition il.h:9349
bool is_truncating() const
Definition il.h:9358
BinaryIntegerOpInstr(Token::Kind op_kind, Value *left, Value *right, intptr_t deopt_id)
Definition il.h:9317
virtual intptr_t DeoptimizationTarget() const
Definition il.h:9376
BinarySmiOpInstr(Token::Kind op_kind, Value *left, Value *right, intptr_t deopt_id, Range *right_range=nullptr)
Definition il.h:9409
virtual bool ComputeCanDeoptimize() const
Definition il.h:9505
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const
Definition il.h:9514
virtual Representation representation() const
Definition il.h:9507
BinaryUint32OpInstr(Token::Kind op_kind, Value *left, Value *right, intptr_t deopt_id)
Definition il.h:9496
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:9509
static bool IsSupported(Token::Kind op_kind)
Definition il.h:9518
BitCastInstr(Representation from, Representation to, Value *value)
Definition il.h:11052
Value * value() const
Definition il.h:11064
Representation to() const
Definition il.h:11067
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:11078
virtual bool ComputeCanDeoptimize() const
Definition il.h:11069
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:11073
Representation from() const
Definition il.h:11066
DECLARE_INSTRUCTION(BitCast)
virtual Representation representation() const
Definition il.h:11071
ForwardInstructionIterator end() const
Definition il.h:1873
ForwardInstructionIterator begin() const
Definition il.h:1868
InstructionsIterable(BlockEntryInstr *block)
Definition il.h:1759
BlockEntryInstr * dominator() const
Definition il.h:1664
intptr_t end_pos() const
Definition il.h:1662
InstructionsIterable instructions()
Definition il.h:1768
void ClearDominatedBlocks()
Definition il.h:1676
intptr_t NestingDepth() const
Definition il.cc:1829
void set_preorder_number(intptr_t number)
Definition il.h:1650
intptr_t try_index() const
Definition il.h:1724
intptr_t postorder_number() const
Definition il.h:1652
ParallelMoveInstr * GetParallelMove()
Definition il.h:1691
bool FindOsrEntryAndRelink(GraphEntryInstr *graph_entry, Instruction *parent, BitVector *block_marks)
Definition il.cc:1747
void AddDominatedBlock(BlockEntryInstr *block)
Definition il.h:1671
virtual void ClearPredecessors()=0
ParallelMoveInstr * parallel_move() const
Definition il.h:1683
void set_block_id(intptr_t block_id)
Definition il.h:1747
virtual bool ComputeCanDeoptimize() const
Definition il.h:1720
bool HasNonRedundantParallelMove() const
Definition il.h:1687
intptr_t preorder_number() const
Definition il.h:1649
bool HasParallelMove() const
Definition il.h:1685
bool InsideTryBlock() const
Definition il.h:1728
intptr_t block_id() const
Definition il.h:1655
virtual bool HasUnknownSideEffects() const
Definition il.h:1722
virtual intptr_t PredecessorCount() const =0
void set_try_index(intptr_t index)
Definition il.h:1725
BlockEntryInstr * ImmediateDominator() const
Definition il.cc:1817
LoopInfo * loop_info() const
Definition il.h:1731
virtual BlockEntryInstr * GetBlock()
Definition il.h:1736
void set_loop_info(LoopInfo *loop_info)
Definition il.h:1732
virtual void AddPredecessor(BlockEntryInstr *predecessor)=0
void set_end_pos(intptr_t pos)
Definition il.h:1661
void set_stack_depth(intptr_t s)
Definition il.h:1751
const GrowableArray< BlockEntryInstr * > & dominated_blocks()
Definition il.h:1667
void set_start_pos(intptr_t pos)
Definition il.h:1659
bool Dominates(BlockEntryInstr *other) const
Definition il.cc:1806
virtual bool CanBecomeDeoptimizationTarget() const
Definition il.h:1714
BlockEntryInstr(intptr_t block_id, intptr_t try_index, intptr_t deopt_id, intptr_t stack_depth)
Definition il.h:1776
void ReplaceAsPredecessorWith(BlockEntryInstr *new_block)
Definition il.cc:1838
void set_postorder_number(intptr_t number)
Definition il.h:1653
virtual BlockEntryInstr * PredecessorAt(intptr_t index) const =0
bool IsLoopHeader() const
Definition il.cc:1825
void ClearAllInstructions()
Definition il.cc:1896
virtual TokenPosition token_pos() const
Definition il.h:1738
void set_last_instruction(Instruction *instr)
Definition il.h:1681
intptr_t stack_depth() const
Definition il.h:1750
bool DiscoverBlock(BlockEntryInstr *predecessor, GrowableArray< BlockEntryInstr * > *preorder, GrowableArray< intptr_t > *parent)
Definition il.cc:1690
intptr_t start_pos() const
Definition il.h:1660
Instruction * last_instruction() const
Definition il.h:1680
const GrowableArray< Definition * > * initial_definitions() const
Definition il.h:1914
void PrintInitialDefinitionsTo(BaseTextBuffer *f) const
virtual BlockEntryWithInitialDefs * AsBlockEntryWithInitialDefs()
Definition il.h:1918
BlockEntryWithInitialDefs(intptr_t block_id, intptr_t try_index, intptr_t deopt_id, intptr_t stack_depth)
Definition il.h:1905
GrowableArray< Definition * > * initial_definitions()
Definition il.h:1911
virtual const BlockEntryWithInitialDefs * AsBlockEntryWithInitialDefs() const
Definition il.h:1921
virtual bool ComputeCanDeoptimize() const
Definition il.h:7183
virtual bool HasUnknownSideEffects() const
Definition il.h:7185
virtual Representation representation() const
Definition il.h:7181
BoolToIntInstr(Value *value)
Definition il.h:7172
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:7178
virtual bool ComputeCanDeoptimize() const
Definition il.h:7157
virtual bool HasUnknownSideEffects() const
Definition il.h:7159
BooleanNegateInstr(Value *value)
Definition il.h:7150
Value * value() const
Definition il.h:7155
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:8489
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const
Definition il.h:8502
virtual bool ComputeCanDeoptimize() const
Definition il.h:8486
virtual TokenPosition token_pos() const
Definition il.h:8500
virtual intptr_t DeoptimizationTarget() const
Definition il.h:8487
DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(BoxInstr, TemplateDefinition, FIELD_LIST) protected
Definition il.h:8508
Value * value() const
Definition il.h:8480
Representation from_representation() const
Definition il.h:8481
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:8494
BoxInt32Instr(Value *value)
Definition il.h:8584
BoxInt64Instr(Value *value)
Definition il.h:8610
BoxInteger32Instr(Representation representation, Value *value)
Definition il.h:8571
BoxIntegerInstr(Representation representation, Value *value)
Definition il.h:8529
virtual bool CanTriggerGC() const
Definition il.h:8541
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const
Definition il.h:10469
intptr_t InputCount() const
Definition il.h:10423
Value * z() const
Definition il.h:10438
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:10456
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:10461
virtual intptr_t DeoptimizationTarget() const
Definition il.h:10454
BoxLanesInstr(Representation from_representation, Value *x, Value *y)
Definition il.h:10397
Value * y() const
Definition il.h:10437
virtual TokenPosition token_pos() const
Definition il.h:10467
Value * w() const
Definition il.h:10443
Value * x() const
Definition il.h:10436
virtual bool ComputeCanDeoptimize() const
Definition il.h:10453
BoxLanesInstr(Representation from_representation, Value *x, Value *y, Value *z, Value *w)
Definition il.h:10405
Representation from_representation() const
Definition il.h:10448
BoxSmallIntInstr(Representation rep, Value *value)
Definition il.h:8553
virtual bool ValueFitsSmi() const
Definition il.h:8559
BoxUint32Instr(Value *value)
Definition il.h:8597
virtual void CopyDeoptIdFrom(const Instruction &instr)
Definition il.h:4022
TargetEntryInstr ** false_successor_address()
Definition il.h:4033
TargetEntryInstr * false_successor() const
Definition il.h:4030
intptr_t InputCount() const
Definition il.h:3976
void set_constant_target(TargetEntryInstr *target)
Definition il.h:4016
virtual void SetMoveArguments(MoveArgumentsArray *move_arguments)
Definition il.h:3969
virtual bool MayThrow() const
Definition il.h:4027
virtual MoveArgumentsArray * GetMoveArguments() const
Definition il.h:3972
TargetEntryInstr ** true_successor_address()
Definition il.h:4032
virtual bool has_inlining_id() const
Definition il.h:3985
virtual void RawSetInputAt(intptr_t i, Value *value)
Definition il.h:4047
virtual bool ComputeCanDeoptimize() const
Definition il.h:3989
virtual intptr_t inlining_id() const
Definition il.h:3981
TargetEntryInstr * constant_target() const
Definition il.h:4020
virtual intptr_t DeoptimizationTarget() const
Definition il.h:4006
virtual void set_inlining_id(intptr_t value)
Definition il.h:3982
virtual bool HasUnknownSideEffects() const
Definition il.h:3997
TargetEntryInstr * true_successor() const
Definition il.h:4029
ComparisonInstr * comparison() const
Definition il.h:4003
virtual Representation RequiredInputRepresentation(intptr_t i) const
Definition il.h:4010
Value * InputAt(intptr_t i) const
Definition il.h:3978
BranchInstr(ComparisonInstr *comparison, intptr_t deopt_id)
Definition il.h:3956
virtual bool CanCallDart() const
Definition il.h:4001
virtual TokenPosition token_pos() const
Definition il.h:3980
virtual bool CanBecomeDeoptimizationTarget() const
Definition il.h:3993
virtual bool ComputeCanDeoptimize() const
Definition il.h:5708
virtual void SetIdentity(AliasIdentity identity)
Definition il.h:5736
virtual bool ComputeCanDeoptimizeAfterCall() const
Definition il.h:5710
virtual bool HasUnknownSideEffects() const
Definition il.h:5714
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t idx) const
Definition il.h:5718
virtual AliasIdentity Identity() const
Definition il.h:5735
virtual bool CanBecomeDeoptimizationTarget() const
Definition il.h:5712
virtual Representation representation() const
Definition il.h:5733
virtual bool MayCreateUnsafeUntaggedPointer() const
Definition il.h:5701
virtual bool CanCallDart() const
Definition il.h:5716
CalculateElementAddressInstr(Value *base, Value *index, intptr_t index_scale, Value *offset)
Definition il.h:7946
virtual bool MayCreateUnsafeUntaggedPointer() const
Definition il.h:7976
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:7963
intptr_t index_scale() const
Definition il.h:7972
virtual bool HasUnknownSideEffects() const
Definition il.h:7984
virtual bool AllowsCSE() const
Definition il.h:7980
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:7985
virtual bool ComputeCanDeoptimize() const
Definition il.h:7982
Call1ArgStubInstr(const InstructionSource &source, StubId stub_id, Value *operand, intptr_t deopt_id)
Definition il.h:11384
virtual intptr_t NumberOfInputsConsumedBeforeCall() const
Definition il.h:11402
Value * operand() const
Definition il.h:11394
virtual TokenPosition token_pos() const
Definition il.h:11396
virtual bool ComputeCanDeoptimize() const
Definition il.h:11399
DECLARE_INSTRUCTION(Call1ArgStub)
virtual bool HasUnknownSideEffects() const
Definition il.h:11401
virtual bool CanCallDart() const
Definition il.h:11398
StubId stub_id() const
Definition il.h:11395
virtual bool ComputeCanDeoptimizeAfterCall() const
Definition il.h:11400
void Print() const
Definition il.cc:4261
void Write(FlowGraphSerializer *s) const
bool ReceiverIs(intptr_t cid) const
Definition il.h:802
CallTargets(Zone *zone)
Definition il.h:776
bool ReceiverIsSmiOrMint() const
Definition il.h:805
static const CallTargets * CreateMonomorphic(Zone *zone, intptr_t receiver_cid, const Function &target)
Definition il.cc:4121
const Function & MostPopularTarget() const
Definition il.cc:5521
TargetInfo * TargetAt(int i) const
Definition il.h:790
bool HasSingleTarget() const
Definition il.cc:5507
static const CallTargets * CreateAndExpand(Zone *zone, const ICData &ic_data)
Definition il.cc:4140
intptr_t AggregateCallCount() const
Definition il.cc:5530
const Function & FirstTarget() const
Definition il.cc:5515
StaticTypeExactnessState MonomorphicExactness() const
Definition il.cc:809
bool HasSingleRecognizedTarget() const
Definition il.cc:5502
virtual bool ComputeCanDeoptimize() const
Definition il.h:8877
Value * rhs_index() const
Definition il.h:8867
CaseInsensitiveCompareInstr(Value *str, Value *lhs_index, Value *rhs_index, Value *length, bool handle_surrogates, intptr_t cid)
Definition il.h:8850
intptr_t class_id() const
Definition il.h:8871
Value * lhs_index() const
Definition il.h:8866
virtual Representation representation() const
Definition il.h:8879
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:8884
intptr_t index_scale() const
Definition il.h:8873
const LocalVariable * exception_var() const
Definition il.h:2349
CatchBlockEntryInstr(bool is_generated, intptr_t block_id, intptr_t try_index, GraphEntryInstr *graph_entry, const Array &handler_types, intptr_t catch_try_index, bool needs_stacktrace, intptr_t deopt_id, const LocalVariable *exception_var, const LocalVariable *stacktrace_var, const LocalVariable *raw_exception_var, const LocalVariable *raw_stacktrace_var)
Definition il.h:2310
const LocalVariable * raw_stacktrace_var() const
Definition il.h:2353
virtual void ClearPredecessors()
Definition il.h:2373
virtual BlockEntryInstr * PredecessorAt(intptr_t index) const
Definition il.h:2342
virtual void AddPredecessor(BlockEntryInstr *predecessor)
Definition il.h:2374
intptr_t catch_try_index() const
Definition il.h:2363
const Array & catch_handler_types() const
Definition il.h:2365
const LocalVariable * stacktrace_var() const
Definition il.h:2350
bool needs_stacktrace() const
Definition il.h:2357
bool is_generated() const
Definition il.h:2359
const LocalVariable * raw_exception_var() const
Definition il.h:2352
GraphEntryInstr * graph_entry() const
Definition il.h:2347
virtual bool ComputeCanDeoptimize() const
Definition il.h:10779
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:10788
CheckArrayBoundInstr(Value *length, Value *index, intptr_t deopt_id)
Definition il.h:10771
CheckBoundBaseInstr(Value *length, Value *index, intptr_t deopt_id)
Definition il.h:10736
Value * index() const
Definition il.h:10743
Value * length() const
Definition il.h:10742
DECLARE_ABSTRACT_INSTRUCTION(CheckBoundBase)
const CidRangeValue & cids() const
Definition il.h:10702
DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(CheckClassIdInstr, TemplateInstruction, FIELD_LIST) private DISALLOW_COPY_AND_ASSIGN(CheckClassIdInstr)
virtual bool AllowsCSE() const
Definition il.h:10710
virtual bool HasUnknownSideEffects() const
Definition il.h:10711
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:10713
Value * value() const
Definition il.h:10701
CheckClassIdInstr(Value *value, CidRangeValue cids, intptr_t deopt_id)
Definition il.h:10696
DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(CheckClassInstr, TemplateInstruction, FIELD_LIST) private void EmitBitTest(FlowGraphCompiler *compiler, intptr_t min, intptr_t max, intptr_t mask, compiler::Label *deopt)
Value * value() const
Definition il.h:10540
void EmitNullCheck(FlowGraphCompiler *compiler, compiler::Label *deopt)
virtual TokenPosition token_pos() const
Definition il.h:10538
const Cids & cids() const
Definition il.h:10542
DISALLOW_COPY_AND_ASSIGN(CheckClassInstr)
bool IsNullCheck() const
Definition il.h:10546
virtual bool HasUnknownSideEffects() const
Definition il.h:10556
virtual bool AllowsCSE() const
Definition il.h:10555
virtual Value * InputAt(intptr_t i) const
Definition il.h:10937
CheckConditionInstr(ComparisonInstr *comparison, intptr_t deopt_id)
Definition il.h:10911
virtual void CopyDeoptIdFrom(const Instruction &instr)
Definition il.h:10941
virtual bool MayThrow() const
Definition il.h:10939
virtual bool AllowsCSE() const
Definition il.h:10928
virtual intptr_t InputCount() const
Definition il.h:10936
ComparisonInstr * comparison() const
Definition il.h:10920
DISALLOW_COPY_AND_ASSIGN(CheckConditionInstr)
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:10931
DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(CheckConditionInstr, Instruction, FIELD_LIST) DECLARE_EXTRA_SERIALIZATION private
Definition il.h:10950
virtual bool HasUnknownSideEffects() const
Definition il.h:10929
Value * right() const
Definition il.h:8429
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:8437
Value * left() const
Definition il.h:8428
CheckEitherNonSmiInstr(Value *left, Value *right, intptr_t deopt_id)
Definition il.h:8422
virtual bool UseSharedSlowPathStub(bool is_optimizing) const
Definition il.h:10652
virtual bool ComputeCanDeoptimizeAfterCall() const
Definition il.h:10664
CheckNullInstr(Value *value, const String &function_name, intptr_t deopt_id, const InstructionSource &source, ExceptionType exception_type=kNoSuchMethod)
Definition il.h:10633
virtual bool CanBecomeDeoptimizationTarget() const
Definition il.h:10667
const String & function_name() const
Definition il.h:10649
Value * value() const
Definition il.h:10647
virtual TokenPosition token_pos() const
Definition il.h:10648
ExceptionType exception_type() const
Definition il.h:10650
virtual bool ComputeCanDeoptimize() const
Definition il.h:10663
virtual TokenPosition token_pos() const
Definition il.h:10601
Value * value() const
Definition il.h:10600
CheckSmiInstr(Value *value, intptr_t deopt_id, const InstructionSource &source)
Definition il.h:10593
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:10609
virtual TokenPosition token_pos() const
Definition il.h:9855
virtual bool ComputeCanDeoptimizeAfterCall() const
Definition il.h:9863
CheckStackOverflowInstr(const InstructionSource &source, intptr_t stack_depth, intptr_t loop_depth, intptr_t deopt_id, Kind kind)
Definition il.h:9842
virtual bool UseSharedSlowPathStub(bool is_optimizing) const
Definition il.h:9875
virtual bool HasUnknownSideEffects() const
Definition il.h:9869
intptr_t stack_depth() const
Definition il.h:9857
virtual bool CanEliminate(const BlockEntryInstr *block) const
Definition il.h:9871
intptr_t loop_depth() const
Definition il.h:9858
Kind kind() const
Definition il.h:10888
virtual bool ComputeCanDeoptimizeAfterCall() const
Definition il.h:10884
CheckWritableInstr(Value *receiver, intptr_t deopt_id, const InstructionSource &source, Kind kind=Kind::kWriteUnmodifiableTypedData)
Definition il.h:10865
virtual bool ComputeCanDeoptimize() const
Definition il.h:10883
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:10873
static bool ContainsCid(const CidRangeVector &ranges, intptr_t cid)
Definition il.h:257
Cids(Zone *zone)
Definition il.h:732
void Sort(int compare(CidRange *const *a, CidRange *const *b))
Definition il.h:758
bool HasClassId(intptr_t cid) const
Definition il.cc:680
static Cids * CreateMonomorphic(Zone *zone, intptr_t cid)
Definition il.cc:689
intptr_t MonomorphicReceiverCid() const
Definition il.cc:804
static Cids * CreateForArgument(Zone *zone, const BinaryFeedback &binary_feedback, int argument_number)
Definition il.cc:695
void SetLength(intptr_t len)
Definition il.h:754
intptr_t ComputeLowestCid() const
Definition il.cc:664
CidRange * At(int index) const
Definition il.h:750
intptr_t length() const
Definition il.h:752
intptr_t ComputeHighestCid() const
Definition il.cc:672
GrowableArray< CidRange * > cid_ranges_
Definition il.h:768
void Add(CidRange *target)
Definition il.h:746
bool is_empty() const
Definition il.h:756
bool Equals(const Cids &other) const
Definition il.cc:653
bool IsMonomorphic() const
Definition il.cc:799
CidRange & operator[](intptr_t index) const
Definition il.h:748
intptr_t target_instance_size() const
Definition object.h:1149
intptr_t NumTypeArguments() const
Definition object.cc:3690
virtual TokenPosition token_pos() const
Definition il.h:8384
const ZoneGrowableArray< const Slot * > & context_slots() const
Definition il.h:8387
virtual intptr_t NumberOfInputsConsumedBeforeCall() const
Definition il.h:8401
virtual bool ComputeCanDeoptimizeAfterCall() const
Definition il.h:8395
Value * context_value() const
Definition il.h:8385
virtual bool ComputeCanDeoptimize() const
Definition il.h:8394
virtual bool HasUnknownSideEffects() const
Definition il.h:8405
CloneContextInstr(const InstructionSource &source, Value *context_value, const ZoneGrowableArray< const Slot * > &context_slots, intptr_t deopt_id)
Definition il.h:8374
virtual intptr_t CallCount() const
Definition il.h:4639
virtual bool HasUnknownSideEffects() const
Definition il.h:4641
ClosureCallInstr(const Function &target_function, InputsArray &&inputs, intptr_t type_args_len, const Array &argument_names, const InstructionSource &source, intptr_t deopt_id)
Definition il.h:4619
virtual void NegateComparison()
Definition il.h:3862
virtual bool CanBecomeDeoptimizationTarget() const
Definition il.h:3864
void set_operation_cid(intptr_t value)
Definition il.h:3859
bool IsComparisonWithConstant(Value **other_operand, ConstantInstr **constant_operand)
Definition il.h:3875
intptr_t operation_cid() const
Definition il.h:3860
Value * right() const
Definition il.h:3829
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:3867
DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(ComparisonInstr, Definition, FIELD_LIST) protected
Definition il.h:3896
Value * left() const
Definition il.h:3828
virtual intptr_t DeoptimizationTarget() const
Definition il.h:3865
virtual TokenPosition token_pos() const
Definition il.h:3831
Token::Kind kind() const
Definition il.h:3832
static constexpr intptr_t kNumPasses
static CompilerState & Current()
const Object & value() const
Definition il.h:4212
void EmitMoveToLocation(FlowGraphCompiler *compiler, const Location &destination, Register tmp=kNoRegister, intptr_t pair_index=0)
ConstantInstr(const Object &value)
Definition il.h:4203
PRINT_OPERANDS_TO_SUPPORT DECLARE_ATTRIBUTE & value()
bool HasZeroRepresentation() const
Definition il.h:4216
virtual TokenPosition token_pos() const
Definition il.h:4239
bool IsSmi() const
Definition il.h:4214
virtual bool ComputeCanDeoptimize() const
Definition il.h:4233
virtual bool ComputeCanDeoptimize() const
Definition il.h:4165
Value * value() const
Definition il.h:4174
void set_target(TargetEntryInstr *target)
Definition il.h:4182
TargetEntryInstr * target() const
Definition il.h:4183
DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(ConstraintInstr, TemplateDefinition, FIELD_LIST) DECLARE_EXTRA_SERIALIZATION private DISALLOW_COPY_AND_ASSIGN(ConstraintInstr)
ConstraintInstr(Value *value, Range *constraint)
Definition il.h:4157
virtual bool HasUnknownSideEffects() const
Definition il.h:4167
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:4169
Range * constraint() const
Definition il.h:4175
virtual const Slot * SlotForInput(intptr_t pos)
Definition il.h:7818
virtual bool WillAllocateNewOrRemembered() const
Definition il.h:7811
virtual bool HasUnknownSideEffects() const
Definition il.h:7809
CreateArrayInstr(const InstructionSource &source, Value *type_arguments, Value *num_elements, intptr_t deopt_id)
Definition il.h:7792
Value * type_arguments() const
Definition il.h:7806
virtual Value * num_elements() const
Definition il.h:7807
virtual intptr_t InputCount() const
Definition il.h:3490
virtual Value * InputAt(intptr_t i) const
Definition il.h:3492
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:3476
DartReturnInstr(const InstructionSource &source, Value *value, intptr_t deopt_id, Representation representation=kTagged)
Definition il.h:3455
Value * value() const
Definition il.h:3468
virtual intptr_t DeoptimizationTarget() const
Definition il.h:3481
virtual Representation representation() const
Definition il.h:3483
virtual Representation RequiredInputRepresentation(intptr_t index) const
Definition il.h:3485
virtual bool CanBecomeDeoptimizationTarget() const
Definition il.h:3470
virtual void RawSetInputAt(intptr_t i, Value *value)
Definition il.h:3509
virtual bool HasUnknownSideEffects() const
Definition il.h:6230
virtual bool ComputeCanDeoptimize() const
Definition il.h:6229
DebugStepCheckInstr(const InstructionSource &source, UntaggedPcDescriptors::Kind stub_kind, intptr_t deopt_id)
Definition il.h:6219
bool HasUses() const
Definition il.h:2551
Value * env_use_list() const
Definition il.h:2560
PRINT_OPERANDS_TO_SUPPORT PRINT_TO_SUPPORT bool UpdateType(CompileType new_type)
Definition il.h:2535
virtual AliasIdentity Identity() const
Definition il.h:2642
void SetReplacement(Definition *other)
Definition il.h:2635
Value * input_use_list() const
Definition il.h:2557
virtual CompileType ComputeType() const
Definition il.h:2524
Definition * Replacement()
Definition il.h:2628
bool HasTemp() const
Definition il.h:2483
Range * range() const
Definition il.h:2618
virtual bool CanEliminate(const BlockEntryInstr *block) const
Definition il.h:2585
CompileType * Type()
Definition il.h:2503
intptr_t location_count() const
Definition il.h:2498
void AddEnvUse(Value *value)
Definition il.h:2568
bool IsInt32Definition()
Definition il.h:2516
void set_temp_index(intptr_t index)
Definition il.h:2481
void set_type(CompileType *type)
Definition il.h:2676
virtual intptr_t CallCount() const
Definition il.h:2478
bool HasSSATemp() const
Definition il.h:2490
virtual bool MayCreateUnsafeUntaggedPointer() const
Definition il.h:2573
bool HasPairRepresentation() const
Definition il.h:2499
virtual Definition * AsDefinition()
Definition il.h:2665
Definition(intptr_t deopt_id=DeoptId::kNone)
Definition il.h:2470
intptr_t vreg(intptr_t index) const
Definition il.h:2493
Definition(const InstructionSource &source, intptr_t deopt_id=DeoptId::kNone)
Definition il.h:2473
void AddInputUse(Value *value)
Definition il.h:2567
intptr_t temp_index() const
Definition il.h:2480
virtual bool RecomputeType()
Definition il.h:2530
void set_ssa_temp_index(intptr_t index)
Definition il.h:2486
void set_input_use_list(Value *head)
Definition il.h:2558
void ClearTempIndex()
Definition il.h:2482
virtual const Definition * AsDefinition() const
Definition il.h:2666
virtual void SetIdentity(AliasIdentity identity)
Definition il.h:2644
virtual bool CanReplaceWithConstant() const
Definition il.h:2581
ValueListIterable input_uses() const
Definition il.h:2563
intptr_t ssa_temp_index() const
Definition il.h:2485
bool HasType() const
Definition il.h:2512
void set_env_use_list(Value *head)
Definition il.h:2561
void ClearSSATempIndex()
Definition il.h:2491
static constexpr intptr_t kNone
Definition deopt_id.h:27
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:4065
virtual bool ComputeCanDeoptimize() const
Definition il.h:4063
DeoptimizeInstr(ICData::DeoptReasonId deopt_reason, intptr_t deopt_id)
Definition il.h:4060
virtual bool HasUnknownSideEffects() const
Definition il.h:5054
Value * class_id() const
Definition il.h:5044
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t idx) const
Definition il.h:5056
virtual bool CanBecomeDeoptimizationTarget() const
Definition il.h:5050
virtual intptr_t DeoptimizationTarget() const
Definition il.h:5052
const compiler::TableSelector * selector() const
Definition il.h:5039
const char * selector_name() const
Definition il.h:5040
DispatchTableCallInstr(const InstructionSource &source, const Function &interface_target, const compiler::TableSelector *selector, InputsArray &&arguments, intptr_t type_args_len, const Array &argument_names)
Definition il.h:5010
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:9072
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:9059
virtual bool ComputeCanDeoptimize() const
Definition il.h:9057
Value * value() const
Definition il.h:9053
MethodRecognizer::Kind op_kind() const
Definition il.h:9055
DoubleTestOpInstr(MethodRecognizer::Kind op_kind, Value *value, intptr_t deopt_id, const InstructionSource &source)
Definition il.h:9045
Value * value() const
Definition il.h:10090
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:10098
virtual Representation representation() const
Definition il.h:10096
virtual intptr_t DeoptimizationTarget() const
Definition il.h:10107
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:10109
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const
Definition il.h:10103
DoubleToFloatInstr(Value *value, intptr_t deopt_id, SpeculativeMode speculative_mode=kGuardInputs)
Definition il.h:10083
virtual intptr_t DeoptimizationTarget() const
Definition il.h:10031
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:10035
MethodRecognizer::Kind recognized_kind() const
Definition il.h:10012
Value * value() const
Definition il.h:10010
virtual bool HasUnknownSideEffects() const
Definition il.h:10033
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:10017
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t idx) const
Definition il.h:10022
virtual bool ComputeCanDeoptimize() const
Definition il.h:10027
DoubleToIntegerInstr(Value *value, MethodRecognizer::Kind recognized_kind, intptr_t deopt_id)
Definition il.h:10000
virtual intptr_t DeoptimizationTarget() const
Definition il.h:10071
DoubleToSmiInstr(Value *value, intptr_t deopt_id)
Definition il.h:10054
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:10073
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:10066
Value * value() const
Definition il.h:10059
virtual bool ComputeCanDeoptimize() const
Definition il.h:10064
DISALLOW_COPY_AND_ASSIGN(DropTempsInstr)
virtual bool HasUnknownSideEffects() const
Definition il.h:5820
Value * value() const
Definition il.h:5812
intptr_t num_temps() const
Definition il.h:5814
DropTempsInstr(intptr_t num_temps, Value *value)
Definition il.h:5797
virtual TokenPosition token_pos() const
Definition il.h:5827
virtual Value * InputAt(intptr_t i) const
Definition il.h:5807
virtual bool ComputeCanDeoptimize() const
Definition il.h:5818
virtual bool MayThrow() const
Definition il.h:5825
DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(DropTempsInstr, Definition, FIELD_LIST) private
Definition il.h:5835
intptr_t length() const
Definition il.h:376
T & operator[](intptr_t i)
Definition il.h:382
const T & operator[](intptr_t i) const
Definition il.h:377
void SetAt(intptr_t i, const T &val)
Definition il.h:367
T & operator[](intptr_t i)
Definition il.h:360
const T & At(intptr_t i) const
Definition il.h:365
const T & operator[](intptr_t i) const
Definition il.h:355
intptr_t length() const
Definition il.h:353
void SetCurrentValue(Value *value)
Definition il.h:11571
Value * CurrentValue() const
Definition il.h:11566
Location CurrentLocation() const
Definition il.h:11576
DeepIterator(Environment *environment)
Definition il.h:11554
void SetCurrentLocation(Location loc)
Definition il.h:11581
ShallowIterator(Environment *environment)
Definition il.h:11498
Environment * environment() const
Definition il.h:11512
void SetCurrentLocation(Location loc)
Definition il.h:11540
ShallowIterator(const ShallowIterator &other)
Definition il.h:11501
ShallowIterator & operator=(const ShallowIterator &other)
Definition il.h:11506
Value * CurrentValue() const
Definition il.h:11523
Location CurrentLocation() const
Definition il.h:11535
void SetCurrentValue(Value *value)
Definition il.h:11529
intptr_t CountArgsPushed()
Definition il.h:11678
intptr_t Length() const
Definition il.h:11658
Location LocationAt(intptr_t index) const
Definition il.h:11660
intptr_t fixed_parameter_count() const
Definition il.h:11676
intptr_t LazyDeoptPruneCount() const
Definition il.h:11616
void PrintTo(BaseTextBuffer *f) const
void set_locations(Location *locations)
Definition il.h:11603
void MarkAsLazyDeoptToBeforeDeoptId()
Definition il.h:11624
const Function & function() const
Definition il.h:11688
const char * ToCString() const
void MarkAsHoisted()
Definition il.h:11634
intptr_t GetDeoptId() const
Definition il.h:11611
bool LazyDeoptToBeforeDeoptId() const
Definition il.h:11620
Environment * Outermost()
Definition il.h:11647
Value * ValueAt(intptr_t ix) const
Definition il.h:11654
Environment * DeepCopy(Zone *zone) const
Definition il.h:11690
Environment * outer() const
Definition il.h:11645
bool IsHoisted() const
Definition il.h:11632
Environment * GetLazyDeoptEnv(Zone *zone)
Definition il.h:11636
Value * ValueAtUseIndex(intptr_t index) const
Definition il.h:11666
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:5308
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const
Definition il.h:5304
virtual bool ComputeCanDeoptimize() const
Definition il.h:5290
EqualityCompareInstr(const InstructionSource &source, Token::Kind kind, Value *left, Value *right, intptr_t cid, intptr_t deopt_id, bool null_aware=false, SpeculativeMode speculative_mode=kGuardInputs)
Definition il.h:5267
bool is_null_aware() const
Definition il.h:5292
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:5295
void set_null_aware(bool value)
Definition il.h:5293
virtual Representation representation() const
Definition il.h:10283
intptr_t index() const
Definition il.h:10281
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:10294
Value * value() const
Definition il.h:10273
ExtractNthOutputInstr(Value *value, intptr_t n, Representation definition_rep, intptr_t definition_cid)
Definition il.h:10263
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:10285
intptr_t CompoundReturnTypedDataIndex() const
Definition il.h:6056
DISALLOW_COPY_AND_ASSIGN(FfiCallInstr)
FfiCallInstr(intptr_t deopt_id, const compiler::ffi::CallMarshaller &marshaller, bool is_leaf, InputsArray &&inputs)
Definition il.h:6031
virtual bool MayThrow() const
Definition il.h:6061
virtual bool HasUnknownSideEffects() const
Definition il.h:6080
static intptr_t InputCountForMarshaller(const compiler::ffi::CallMarshaller &marshaller)
Definition il.h:6097
static bool CanExecuteGeneratedCodeInSafepoint()
Definition il.h:6093
virtual bool MayCreateUnsafeUntaggedPointer() const
Definition il.h:6066
virtual bool CanCallDart() const
Definition il.h:6083
virtual bool ComputeCanDeoptimize() const
Definition il.h:6075
virtual bool ComputeCanDeoptimizeAfterCall() const
Definition il.h:6076
Value * right() const
Definition il.h:10166
Token::Kind op_kind() const
Definition il.h:10168
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:10178
virtual Representation representation() const
Definition il.h:10176
Value * left() const
Definition il.h:10165
FloatCompareInstr(Token::Kind op_kind, Value *left, Value *right)
Definition il.h:10159
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:10182
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:10146
Value * value() const
Definition il.h:10131
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:10139
virtual intptr_t DeoptimizationTarget() const
Definition il.h:10144
FloatToDoubleInstr(Value *value, intptr_t deopt_id)
Definition il.h:10126
virtual bool ComputeCanDeoptimize() const
Definition il.h:10137
void set_block_order(const GrowableArray< BlockEntryInstr * > &block_order)
Definition il.h:11801
FlowGraphVisitor(const GrowableArray< BlockEntryInstr * > &block_order)
Definition il.h:11788
ForwardInstructionIterator * current_iterator() const
Definition il.h:11792
virtual ~FlowGraphVisitor()
Definition il.h:11790
ForwardInstructionIterator * current_iterator_
Definition il.h:11805
ForwardInstructionIterator(const ForwardInstructionIterator &other)=default
ForwardInstructionIterator & operator++()
Definition il.h:1859
Instruction * operator*() const
Definition il.h:1849
ForwardInstructionIterator(BlockEntryInstr *block_entry)
Definition il.h:1832
bool operator!=(const ForwardInstructionIterator &other) const
Definition il.h:1855
Instruction * Current() const
Definition il.h:1847
bool operator==(const ForwardInstructionIterator &other) const
Definition il.h:1851
ForwardInstructionIterator & operator=(const ForwardInstructionIterator &other)=default
GraphEntryInstr * graph_entry() const
Definition il.h:2197
virtual BlockEntryInstr * PredecessorAt(intptr_t index) const
Definition il.h:2192
virtual void ClearPredecessors()
Definition il.h:2203
virtual void AddPredecessor(BlockEntryInstr *predecessor)
Definition il.h:2204
FunctionEntryInstr(GraphEntryInstr *graph_entry, intptr_t block_id, intptr_t try_index, intptr_t deopt_id)
Definition il.h:2177
GenericCheckBoundInstr(Value *length, Value *index, intptr_t deopt_id)
Definition il.h:10814
virtual intptr_t DeoptimizationTarget() const
Definition il.h:10824
virtual bool MayThrow() const
Definition il.h:10846
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:10817
static bool UseUnboxedRepresentation()
Definition il.h:10810
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const
Definition il.h:10826
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:10834
virtual bool UseSharedSlowPathStub(bool is_optimizing) const
Definition il.h:10848
virtual bool ComputeCanDeoptimizeAfterCall() const
Definition il.h:10842
virtual bool ComputeCanDeoptimize() const
Definition il.h:10841
virtual Representation representation() const
Definition il.h:10830
ParallelMoveInstr * parallel_move() const
Definition il.h:3717
bool HasNonRedundantParallelMove() const
Definition il.h:3721
bool HasParallelMove() const
Definition il.h:3719
JoinEntryInstr * successor() const
Definition il.h:3695
void adjust_edge_weight(double scale_factor)
Definition il.h:3702
double edge_weight() const
Definition il.h:3700
void set_edge_weight(double weight)
Definition il.h:3701
virtual bool HasUnknownSideEffects() const
Definition il.h:3715
virtual bool ComputeCanDeoptimize() const
Definition il.h:3713
virtual intptr_t DeoptimizationTarget() const
Definition il.h:3711
DISALLOW_COPY_AND_ASSIGN(GotoInstr)
void set_successor(JoinEntryInstr *successor)
Definition il.h:3696
void set_block(BlockEntryInstr *block)
Definition il.h:3693
virtual bool CanBecomeDeoptimizationTarget() const
Definition il.h:3704
GotoInstr(JoinEntryInstr *entry, intptr_t deopt_id)
Definition il.h:3684
virtual TokenPosition token_pos() const
Definition il.h:3732
ParallelMoveInstr * GetParallelMove()
Definition il.h:3725
intptr_t fixed_slot_count() const
Definition il.h:1981
intptr_t entry_count() const
Definition il.h:1965
void MarkFrameless()
Definition il.h:1976
void AddCatchEntry(CatchBlockEntryInstr *entry)
Definition il.h:1951
FunctionEntryInstr * normal_entry() const
Definition il.h:1986
intptr_t spill_slot_count() const
Definition il.h:1968
FunctionEntryInstr * unchecked_entry() const
Definition il.h:1987
void AddIndirectEntry(IndirectEntryInstr *entry)
Definition il.h:1955
void set_unchecked_entry(FunctionEntryInstr *target)
Definition il.h:1989
const ParsedFunction & parsed_function() const
Definition il.h:1995
bool HasSingleEntryPoint() const
Definition il.h:2005
void set_normal_entry(FunctionEntryInstr *entry)
Definition il.h:1988
const GrowableArray< IndirectEntryInstr * > & indirect_entries() const
Definition il.h:2001
virtual BlockEntryInstr * PredecessorAt(intptr_t index) const
Definition il.h:1944
intptr_t osr_id() const
Definition il.h:1963
void set_fixed_slot_count(intptr_t count)
Definition il.h:1982
virtual void ClearPredecessors()
Definition il.h:2018
virtual void AddPredecessor(BlockEntryInstr *predecessor)
Definition il.h:2019
void set_osr_entry(OsrEntryInstr *entry)
Definition il.h:1993
OsrEntryInstr * osr_entry() const
Definition il.h:1992
void set_spill_slot_count(intptr_t count)
Definition il.h:1969
bool NeedsFrame() const
Definition il.h:1975
void set_entry_count(intptr_t count)
Definition il.h:1966
const GrowableArray< CatchBlockEntryInstr * > & catch_entries() const
Definition il.h:1997
GuardFieldClassInstr(Value *value, const Field &field, intptr_t deopt_id)
Definition il.h:6499
virtual bool ComputeCanDeoptimize() const
Definition il.h:6478
virtual bool CanBecomeDeoptimizationTarget() const
Definition il.h:6479
const Field & field() const
Definition il.h:6476
Value * value() const
Definition il.h:6474
GuardFieldInstr(Value *value, const Field &field, intptr_t deopt_id)
Definition il.h:6468
GuardFieldLengthInstr(Value *value, const Field &field, intptr_t deopt_id)
Definition il.h:6518
GuardFieldTypeInstr(Value *value, const Field &field, intptr_t deopt_id)
Definition il.h:6543
virtual Representation representation() const
Definition il.h:9109
Value * value() const
Definition il.h:9101
virtual CompileType ComputeType() const
Definition il.h:9120
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:9122
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:9111
HashDoubleOpInstr(Value *value, intptr_t deopt_id)
Definition il.h:9092
virtual intptr_t DeoptimizationTarget() const
Definition il.h:9103
static HashDoubleOpInstr * Create(Value *value, intptr_t deopt_id)
Definition il.h:9097
HashIntegerOpInstr(Value *value, bool smi, intptr_t deopt_id)
Definition il.h:9132
Value * value() const
Definition il.h:9141
virtual Representation representation() const
Definition il.h:9149
virtual CompileType ComputeType() const
Definition il.h:9160
static HashIntegerOpInstr * Create(Value *value, bool smi, intptr_t deopt_id)
Definition il.h:9137
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:9151
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:9162
virtual intptr_t DeoptimizationTarget() const
Definition il.h:9143
bool InstanceOfHasClassRange(const AbstractType &type, intptr_t *lower_limit, intptr_t *upper_limit)
Definition il.cc:410
bool CanUseGenericSubtypeRangeCheckFor(const AbstractType &type)
Definition il.cc:344
const CidRangeVector & SubtypeRangesForClass(const Class &klass, bool include_abstract, bool exclude_null)
Definition il.cc:110
static constexpr intptr_t kNoCompatibleTAVOffset
Definition il.h:282
HierarchyInfo(Thread *thread)
Definition il.h:269
bool CanUseRecordSubtypeRangeCheckFor(const AbstractType &type)
Definition il.cc:393
bool CanUseSubtypeRangeCheckFor(const AbstractType &type)
Definition il.cc:305
virtual bool AllowsCSE() const
Definition il.h:5438
virtual bool HasUnknownSideEffects() const
Definition il.h:5439
Value * InputAt(intptr_t i) const
Definition il.h:5412
virtual void CopyDeoptIdFrom(const Instruction &instr)
Definition il.h:5454
virtual bool CanCallDart() const
Definition il.h:5442
intptr_t if_true() const
Definition il.h:5435
ComparisonInstr * comparison() const
Definition il.h:5434
DISALLOW_COPY_AND_ASSIGN(IfThenElseInstr)
intptr_t if_false() const
Definition il.h:5436
virtual bool MayThrow() const
Definition il.h:5452
virtual bool ComputeCanDeoptimize() const
Definition il.h:5414
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:5444
virtual bool CanBecomeDeoptimizationTarget() const
Definition il.h:5418
IfThenElseInstr(ComparisonInstr *comparison, Value *if_true, Value *if_false, intptr_t deopt_id)
Definition il.h:5389
DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(IfThenElseInstr, Definition, FIELD_LIST) DECLARE_EXTRA_SERIALIZATION private
Definition il.h:5466
virtual intptr_t DeoptimizationTarget() const
Definition il.h:5422
virtual Representation RequiredInputRepresentation(intptr_t i) const
Definition il.h:5426
IndirectEntryInstr(intptr_t block_id, intptr_t indirect_id, intptr_t try_index, intptr_t deopt_id)
Definition il.h:2287
virtual bool ComputeCanDeoptimize() const
Definition il.h:3806
virtual intptr_t SuccessorCount() const
Definition il.h:3800
void AddSuccessor(TargetEntryInstr *successor)
Definition il.h:3794
virtual bool CanBecomeDeoptimizationTarget() const
Definition il.h:3807
virtual TargetEntryInstr * SuccessorAt(intptr_t index) const
Definition il.h:3801
virtual bool HasUnknownSideEffects() const
Definition il.h:3809
IndirectGotoInstr(intptr_t target_count, Value *target_index)
Definition il.h:3780
Value * offset() const
Definition il.h:3811
void set_ic_data(const ICData *value)
Definition il.h:4704
CompileType * result_type() const
Definition il.h:4730
virtual intptr_t DeoptimizationTarget() const
Definition il.h:4774
DECLARE_ABSTRACT_INSTRUCTION(InstanceCallBase)
void set_result_type(CompileType *result_type)
Definition il.h:4800
virtual bool CanBecomeDeoptimizationTarget() const
Definition il.h:4718
Code::EntryKind entry_kind() const
Definition il.h:4741
void set_has_unique_selector(bool b)
Definition il.h:4714
const ICData * ic_data() const
Definition il.h:4698
DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(InstanceCallBaseInstr, TemplateDartCall, FIELD_LIST) protected void set_ic_data(ICData *value)
Definition il.h:4799
void set_receiver_is_not_smi(bool value)
Definition il.h:4750
const Function & tearoff_interface_target() const
Definition il.h:4709
InstanceCallBaseInstr(const InstructionSource &source, const String &function_name, Token::Kind token_kind, InputsArray &&arguments, intptr_t type_args_len, const Array &argument_names, const ICData *ic_data, intptr_t deopt_id, const Function &interface_target, const Function &tearoff_interface_target)
Definition il.h:4659
const Function & interface_target() const
Definition il.h:4708
bool is_call_on_this() const
Definition il.h:4745
void SetResultType(Zone *zone, CompileType new_type)
Definition il.h:4726
bool HasICData() const
Definition il.h:4699
Token::Kind token_kind() const
Definition il.h:4707
bool receiver_is_not_smi() const
Definition il.h:4749
virtual bool HasUnknownSideEffects() const
Definition il.h:4724
intptr_t result_cid() const
Definition il.h:4732
void set_entry_kind(Code::EntryKind value)
Definition il.h:4742
const String & function_name() const
Definition il.h:4706
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t idx) const
Definition il.h:4758
bool has_unique_selector() const
Definition il.h:4713
InstanceCallInstr(const InstructionSource &source, const String &function_name, Token::Kind token_kind, InputsArray &&arguments, intptr_t type_args_len, const Array &argument_names, intptr_t checked_argument_count, const ZoneGrowableArray< const ICData * > &ic_data_array, intptr_t deopt_id, const Function &interface_target=Function::null_function(), const Function &tearoff_interface_target=Function::null_function())
Definition il.h:4808
virtual intptr_t CallCount() const
Definition il.h:4862
DISALLOW_COPY_AND_ASSIGN(InstanceCallInstr)
void SetTargets(const CallTargets *targets)
Definition il.h:4883
void set_receivers_static_type(const AbstractType *receiver_type)
Definition il.h:4866
InstanceCallInstr(const InstructionSource &source, const String &function_name, Token::Kind token_kind, InputsArray &&arguments, intptr_t type_args_len, const Array &argument_names, intptr_t checked_argument_count, intptr_t deopt_id, const Function &interface_target=Function::null_function(), const Function &tearoff_interface_target=Function::null_function())
Definition il.h:4834
void SetBinaryFeedback(const class BinaryFeedback *binary)
Definition il.h:4878
InstanceOfInstr(const InstructionSource &source, Value *value, Value *instantiator_type_arguments, Value *function_type_arguments, const AbstractType &type, intptr_t deopt_id)
Definition il.h:7223
virtual bool ComputeCanDeoptimize() const
Definition il.h:7248
virtual bool ComputeCanDeoptimizeAfterCall() const
Definition il.h:7249
const AbstractType & type() const
Definition il.h:7245
virtual bool HasUnknownSideEffects() const
Definition il.h:7253
virtual TokenPosition token_pos() const
Definition il.h:7246
Value * function_type_arguments() const
Definition il.h:7243
Value * instantiator_type_arguments() const
Definition il.h:7242
Value * value() const
Definition il.h:7241
Value * type_arguments() const
Definition il.h:8260
Value * function_type_arguments() const
Definition il.h:8259
InstantiateTypeArgumentsInstr(const InstructionSource &source, Value *instantiator_type_arguments, Value *function_type_arguments, Value *type_arguments, const Class &instantiator_class, const Function &function, intptr_t deopt_id)
Definition il.h:8238
virtual bool ComputeCanDeoptimizeAfterCall() const
Definition il.h:8266
bool CanShareFunctionTypeArguments(bool *with_runtime_check=nullptr) const
Definition il.h:8289
virtual TokenPosition token_pos() const
Definition il.h:8263
virtual intptr_t NumberOfInputsConsumedBeforeCall() const
Definition il.h:8269
virtual bool HasUnknownSideEffects() const
Definition il.h:8273
const Class & instantiator_class() const
Definition il.h:8261
const Function & function() const
Definition il.h:8262
const Code & GetStub() const
Definition il.h:8300
virtual bool ComputeCanDeoptimize() const
Definition il.h:8265
bool CanShareInstantiatorTypeArguments(bool *with_runtime_check=nullptr) const
Definition il.h:8277
virtual bool HasUnknownSideEffects() const
Definition il.h:8219
Value * function_type_arguments() const
Definition il.h:8207
const AbstractType & type() const
Definition il.h:8208
virtual bool ComputeCanDeoptimizeAfterCall() const
Definition il.h:8212
virtual bool ComputeCanDeoptimize() const
Definition il.h:8211
virtual TokenPosition token_pos() const
Definition il.h:8209
InstantiateTypeInstr(const InstructionSource &source, const AbstractType &type, Value *instantiator_type_arguments, Value *function_type_arguments, intptr_t deopt_id)
Definition il.h:8191
virtual intptr_t NumberOfInputsConsumedBeforeCall() const
Definition il.h:8215
InstructionIndexedPropertyIterable(const Instruction *instr)
Definition il.h:920
virtual ~InstructionVisitor()
Definition il.h:11769
bool WasEliminated() const
Definition il.h:1256
void InsertBefore(Instruction *next)
Definition il.h:1274
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:1325
virtual void Accept(InstructionVisitor *visitor)=0
Instruction * next() const
Definition il.h:1087
virtual intptr_t InputCount() const =0
intptr_t GetDeoptId() const
Definition il.h:1403
virtual bool UseSharedSlowPathStub(bool is_optimizing) const
Definition il.h:1371
virtual void RawSetInputAt(intptr_t i, Value *value)=0
void set_previous(Instruction *instr)
Definition il.h:1082
void SetEnvironment(Environment *deopt_env)
Definition il.cc:1270
void InheritDeoptTargetAfter(FlowGraph *flow_graph, Definition *call, Definition *result)
Definition il.cc:1549
void LinkTo(Instruction *next)
Definition il.h:1102
Instruction(const InstructionSource &source, intptr_t deopt_id=DeoptId::kNone)
Definition il.h:974
virtual bool MayThrow() const =0
void InheritDeoptTarget(Zone *zone, Instruction *other)
Definition il.cc:1560
virtual bool HasUnknownSideEffects() const =0
virtual Value * InputAt(intptr_t i) const =0
void Goto(JoinEntryInstr *entry)
Definition il.cc:2021
virtual bool ComputeCanDeoptimizeAfterCall() const
Definition il.h:1064
virtual BlockEntryInstr * SuccessorAt(intptr_t index) const
Definition il.cc:1972
virtual BlockEntryInstr * GetBlock()
Definition il.cc:1350
void ReadExtraWithoutInputs(FlowGraphDeserializer *d)
virtual void CopyDeoptIdFrom(const Instruction &instr)
Definition il.h:1405
virtual bool ComputeCanDeoptimize() const =0
virtual bool CanBecomeDeoptimizationTarget() const
Definition il.h:1337
Environment * env() const
Definition il.h:1209
virtual LocationSummary * MakeLocationSummary(Zone *zone, bool is_optimizing) const =0
@ kNotSpeculative
Definition il.h:969
void RemoveEnvironment()
Definition il.cc:1280
virtual void EmitNativeCode(FlowGraphCompiler *compiler)
Definition il.h:1207
bool HasUnmatchedInputRepresentations() const
Definition il.cc:1600
const char * ToCString() const
virtual uword Hash() const
Definition il.cc:608
@ FOR_EACH_INSTRUCTION
Definition il.h:959
virtual void SetMoveArguments(MoveArgumentsArray *move_arguments)
Definition il.h:1040
InputsIterable inputs()
Definition il.h:1027
Instruction * AppendInstruction(Instruction *tail)
Definition il.cc:1339
void InitializeLocationSummary(Zone *zone, bool optimizing)
Definition il.h:1196
void CheckField(const Field &field) const
Definition il.h:1147
virtual TokenPosition token_pos() const
Definition il.h:999
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:1235
virtual void ReplaceInputsWithMoveArguments(MoveArgumentsArray *move_arguments)
Definition il.h:1049
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const
Definition il.h:1249
bool HasPassSpecificId(CompilerPass::Id pass) const
Definition il.h:1226
void UnuseAllInputs()
Definition il.cc:1525
virtual bool MayHaveVisibleEffect() const
Definition il.h:1346
virtual intptr_t ArgumentCount() const
Definition il.h:1035
void set_next(Instruction *instr)
Definition il.h:1088
virtual ~Instruction()
Definition il.h:981
InstructionIndexedPropertyIterable< SuccessorsTrait > SuccessorsIterable
Definition il.h:1130
virtual intptr_t statistics_tag() const
Definition il.h:985
bool HasLocs() const
Definition il.h:1191
void WriteExtraWithoutInputs(FlowGraphSerializer *s)
static const intptr_t kInstructionAttrs[kNumInstructions]
Definition il.h:962
bool IsDominatedBy(Instruction *dom)
Definition il.cc:1572
bool Equals(const Instruction &other) const
Definition il.cc:617
virtual intptr_t DeoptimizationTarget() const
Definition il.h:1261
static const ICData * GetICData(const ZoneGrowableArray< const ICData * > &ic_data_array, intptr_t deopt_id, bool is_static_call)
Definition il.cc:593
Definition * ArgumentAt(intptr_t index) const
Definition il.h:3423
void Unsupported(FlowGraphCompiler *compiler)
Definition il.cc:626
Instruction(intptr_t deopt_id=DeoptId::kNone)
Definition il.h:978
bool NeedsEnvironment() const
Definition il.h:1332
virtual Representation representation() const
Definition il.h:1254
SuccessorsIterable successors() const
Definition il.h:1132
bool CanDeoptimize() const
Definition il.h:1073
virtual intptr_t NumberOfInputsConsumedBeforeCall() const
Definition il.h:1214
intptr_t GetPassSpecificId(CompilerPass::Id pass) const
Definition il.h:1218
virtual bool AllowsCSE() const
Definition il.h:1285
void RepairArgumentUsesInEnvironment() const
Definition il.cc:1534
void ClearEnv()
Definition il.h:1358
LocationSummary * locs()
Definition il.h:1186
void ReplaceInEnvironment(Definition *current, Definition *replacement)
Definition il.cc:1287
InstructionIndexedPropertyIterable< InputsTrait > InputsIterable
Definition il.h:1025
Location::Kind RegisterKindForResult() const
Definition il.h:1378
virtual Tag tag() const =0
void SetInputAt(intptr_t i, Value *value)
Definition il.h:1008
InstructionSource source() const
Definition il.h:1002
Value * ArgumentValueAt(intptr_t index) const
Definition il.h:3417
virtual bool has_inlining_id() const
Definition il.h:1311
intptr_t deopt_id() const
Definition il.h:987
void InsertAfter(Instruction *prev)
Definition il.cc:1323
virtual bool CanCallDart() const
Definition il.h:1298
virtual intptr_t SuccessorCount() const
Definition il.cc:1968
bool CanEliminate()
Definition il.h:1354
Instruction * RemoveFromGraph(bool return_previous=true)
Definition il.cc:1299
bool HasMoveArguments() const
Definition il.h:1053
void SetPassSpecificId(CompilerPass::Id pass, intptr_t id)
Definition il.h:1223
const T * Cast() const
Definition il.h:1180
SpeculativeMode SpeculativeModeOfInputs() const
Definition il.h:1239
virtual MoveArgumentsArray * GetMoveArguments() const
Definition il.h:1044
virtual void set_inlining_id(intptr_t value)
Definition il.h:1306
static bool SlowPathSharingSupported(bool is_optimizing)
Definition il.h:1362
virtual bool CanTriggerGC() const
Definition il.cc:1619
virtual const char * DebugName() const =0
Instruction * previous() const
Definition il.h:1081
static LocationSummary * MakeCallSummary(Zone *zone, const Instruction *instr, LocationSummary *locs=nullptr)
virtual intptr_t inlining_id() const
Definition il.h:1305
Value * value() const
Definition il.h:9930
Int32ToDoubleInstr(Value *value)
Definition il.h:9928
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:9943
virtual Representation representation() const
Definition il.h:9939
virtual bool ComputeCanDeoptimize() const
Definition il.h:9941
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:9983
virtual intptr_t DeoptimizationTarget() const
Definition il.h:9971
virtual bool ComputeCanDeoptimize() const
Definition il.h:9977
Value * value() const
Definition il.h:9960
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const
Definition il.h:9979
Int64ToDoubleInstr(Value *value, intptr_t deopt_id, SpeculativeMode speculative_mode=kGuardInputs)
Definition il.h:9953
virtual Representation representation() const
Definition il.h:9969
Value * value() const
Definition il.h:10990
IntConverterInstr(Representation from, Representation to, Value *value, intptr_t deopt_id)
Definition il.h:10966
virtual Representation representation() const
Definition il.h:11002
DECLARE_INSTRUCTION(IntConverter)
virtual bool MayCreateUnsafeUntaggedPointer() const
Definition il.h:11020
bool is_truncating() const
Definition il.h:10994
DECLARE_ATTRIBUTES_NAMED(("from", "to", "is_truncating"),(from(), to(), is_truncating())) PRINT_OPERANDS_TO_SUPPORT DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(IntConverterInstr
virtual intptr_t DeoptimizationTarget() const
Definition il.h:11016
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:11009
Representation to() const
Definition il.h:10993
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:11004
Representation from() const
Definition il.h:10992
IntToBoolInstr(Value *value)
Definition il.h:7196
virtual bool ComputeCanDeoptimize() const
Definition il.h:7211
virtual bool HasUnknownSideEffects() const
Definition il.h:7213
virtual Representation representation() const
Definition il.h:7209
Value * value() const
Definition il.h:7204
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:7206
virtual bool AllowsCSE() const
Definition il.h:10231
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:10234
virtual intptr_t DeoptimizationTarget() const
Definition il.h:10229
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:10219
virtual Representation representation() const
Definition il.h:10217
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t idx) const
Definition il.h:10224
MethodRecognizer::Kind recognized_kind() const
Definition il.h:10209
virtual bool MayThrow() const
Definition il.h:10239
virtual TokenPosition token_pos() const
Definition il.h:10211
virtual bool HasUnknownSideEffects() const
Definition il.h:10232
ZoneGrowableArray< PhiInstr * > * phis() const
Definition il.h:2058
JoinEntryInstr(intptr_t block_id, intptr_t try_index, intptr_t deopt_id, intptr_t stack_depth=0)
Definition il.h:2039
virtual BlockEntryInstr * PredecessorAt(intptr_t index) const
Definition il.h:2051
virtual bool HasUnknownSideEffects() const
Definition il.h:2066
GrowableArray< BlockEntryInstr * > predecessors_
Definition il.h:2092
virtual void ClearPredecessors()
Definition il.h:2089
DISALLOW_COPY_AND_ASSIGN(JoinEntryInstr)
virtual CompileType ComputeType() const
Definition il.h:6188
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:6161
virtual Representation representation() const
Definition il.h:6184
virtual bool MayThrow() const
Definition il.h:6153
intptr_t TargetAddressIndex() const
Definition il.h:6149
virtual bool MayCreateUnsafeUntaggedPointer() const
Definition il.h:6169
virtual bool HasUnknownSideEffects() const
Definition il.h:6157
virtual bool CanCallDart() const
Definition il.h:6159
virtual bool ComputeCanDeoptimize() const
Definition il.h:6155
Value * object() const
Definition il.h:8018
virtual bool ComputeCanDeoptimize() const
Definition il.h:8020
LoadClassIdInstr(Value *object, Representation representation=kTagged, bool input_can_be_smi=true)
Definition il.h:8004
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:8022
virtual Representation representation() const
Definition il.h:8012
virtual Representation representation() const
Definition il.h:6865
virtual bool ComputeCanDeoptimize() const
Definition il.h:6863
intptr_t index_scale() const
Definition il.h:6851
Value * index() const
Definition il.h:6849
Value * array() const
Definition il.h:6848
bool can_pack_into_smi() const
Definition il.h:6858
virtual bool CanTriggerGC() const
Definition il.h:6871
intptr_t element_count() const
Definition il.h:6856
virtual bool HasUnknownSideEffects() const
Definition il.h:6869
bool IsExternal() const
Definition il.h:6844
LoadCodeUnitsInstr(Value *str, Value *index, intptr_t element_count, intptr_t class_id, const InstructionSource &source)
Definition il.h:6814
intptr_t class_id() const
Definition il.h:6855
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:6835
TokenPosition token_pos() const
Definition il.h:6830
void set_representation(Representation repr)
Definition il.h:6866
bool IsImmutableLengthLoad() const
Definition il.h:8139
virtual bool AllowsCSE() const
Definition il.h:8162
void set_loads_inner_pointer(InnerPointerAccess value)
Definition il.h:8101
const Slot & slot() const
Definition il.h:8096
InnerPointerAccess loads_inner_pointer() const
Definition il.h:8098
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:8109
LoadFieldInstr(Value *instance, const Slot &slot, const InstructionSource &source, bool calls_initializer=false, intptr_t deopt_id=DeoptId::kNone)
Definition il.h:8083
DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(LoadFieldInstr, TemplateLoadField, FIELD_LIST) private DISALLOW_COPY_AND_ASSIGN(LoadFieldInstr)
Value * instance() const
Definition il.h:8095
virtual bool CanTriggerGC() const
Definition il.h:8164
LoadFieldInstr(Value *instance, const Slot &slot, InnerPointerAccess loads_inner_pointer, const InstructionSource &source, bool calls_initializer=false, intptr_t deopt_id=DeoptId::kNone)
Definition il.h:8055
intptr_t class_id() const
Definition il.h:6759
TokenPosition token_pos() const
Definition il.h:6739
bool IsUntagged() const
Definition il.h:6752
bool aligned() const
Definition il.h:6760
virtual intptr_t DeoptimizationTarget() const
Definition il.h:6762
virtual bool ComputeCanDeoptimize() const
Definition il.h:6768
virtual bool HasUnknownSideEffects() const
Definition il.h:6781
Value * array() const
Definition il.h:6756
intptr_t index_scale() const
Definition il.h:6758
Representation representation() const
Definition il.h:6775
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:6745
Value * index() const
Definition il.h:6757
Value * index() const
Definition il.h:3109
virtual bool HasUnknownSideEffects() const
Definition il.h:3101
LoadIndexedUnsafeInstr(Value *index, intptr_t offset, CompileType result_type, Representation representation=kTagged)
Definition il.h:3085
intptr_t offset() const
Definition il.h:3111
Register base_reg() const
Definition il.h:3110
virtual Representation representation() const
Definition il.h:3107
virtual bool ComputeCanDeoptimize() const
Definition il.h:3100
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:3103
LoadLocalInstr(const LocalVariable &local, const InstructionSource &source)
Definition il.h:5756
void mark_last()
Definition il.h:5774
virtual TokenPosition token_pos() const
Definition il.h:5777
const LocalVariable & local() const
Definition il.h:5765
virtual bool HasUnknownSideEffects() const
Definition il.h:5769
bool is_last() const
Definition il.h:5775
virtual bool ComputeCanDeoptimize() const
Definition il.h:5767
LoadStaticFieldInstr(const Field &field, const InstructionSource &source, bool calls_initializer=false, intptr_t deopt_id=DeoptId::kNone)
Definition il.h:6628
virtual bool AllowsCSE() const
Definition il.h:6641
const Field & field() const
Definition il.h:6639
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:11109
virtual bool MayCreateUnsafeUntaggedPointer() const
Definition il.h:11113
DECLARE_INSTRUCTION(LoadThread)
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:11119
virtual Representation representation() const
Definition il.h:11107
virtual bool ComputeCanDeoptimize() const
Definition il.h:11105
virtual bool ComputeCanDeoptimize() const
Definition il.h:7914
LoadUntaggedInstr(Value *object, intptr_t offset)
Definition il.h:7891
Value * object() const
Definition il.h:7906
virtual bool HasUnknownSideEffects() const
Definition il.h:7916
virtual bool MayCreateUnsafeUntaggedPointer() const
Definition il.h:7909
intptr_t offset() const
Definition il.h:7907
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:7917
virtual Representation representation() const
Definition il.h:7897
bool IsInvalid() const
Definition locations.h:289
static Location NoLocation()
Definition locations.h:387
bool IsFpuRegister() const
Definition locations.h:414
bool IsRegister() const
Definition locations.h:402
bool IsDoubleStackSlot() const
Definition locations.h:467
intptr_t stack_index() const
Definition locations.h:485
Register base_reg() const
Definition locations.h:480
PairLocation * AsPairLocation() const
Definition locations.cc:280
bool Equals(Location other) const
Definition locations.h:519
bool IsPairLocation() const
Definition locations.h:316
bool IsMachineRegister() const
Definition locations.h:434
bool IsStackSlot() const
Definition locations.h:456
MakePairInstr(Value *x, Value *y)
Definition il.h:10319
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:10330
virtual Representation representation() const
Definition il.h:10328
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:10335
MakeTempInstr(Zone *zone)
Definition il.h:5863
virtual TokenPosition token_pos() const
Definition il.h:5881
virtual bool MayThrow() const
Definition il.h:5879
virtual bool HasUnknownSideEffects() const
Definition il.h:5874
intptr_t FieldOffsetAt(intptr_t i) const
Definition il.h:7687
void set_locations(Location *locations)
Definition il.h:7713
Location * locations()
Definition il.h:7712
virtual bool MayThrow() const
Definition il.h:7715
AllocationInstr * allocation() const
Definition il.h:7682
void mark_visited_for_liveness()
Definition il.h:7720
bool was_visited_for_liveness() const
Definition il.h:7719
virtual bool ComputeCanDeoptimize() const
Definition il.h:7708
const Class & cls() const
Definition il.h:7683
intptr_t length_or_shape() const
Definition il.h:7685
DISALLOW_COPY_AND_ASSIGN(MaterializeObjectInstr)
MaterializeObjectInstr(AllocationInstr *allocation, const Class &cls, intptr_t length_or_shape, const ZoneGrowableArray< const Slot * > &slots, InputsArray &&values)
Definition il.h:7668
virtual bool HasUnknownSideEffects() const
Definition il.h:7709
const Location & LocationAt(intptr_t i)
Definition il.h:7691
virtual bool CanReplaceWithConstant() const
Definition il.h:7710
virtual intptr_t DeoptimizationTarget() const
Definition il.h:8944
Value * right() const
Definition il.h:8922
MathMinMaxInstr(MethodRecognizer::Kind op_kind, Value *left_value, Value *right_value, intptr_t deopt_id, intptr_t result_cid)
Definition il.h:8906
intptr_t result_cid() const
Definition il.h:8924
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:8936
Value * left() const
Definition il.h:8921
virtual Representation representation() const
Definition il.h:8928
virtual bool ComputeCanDeoptimize() const
Definition il.h:8926
MethodRecognizer::Kind op_kind() const
Definition il.h:8919
Value * length() const
Definition il.h:3193
bool unboxed_inputs() const
Definition il.h:3198
Value * dest() const
Definition il.h:3190
classid_t src_cid() const
Definition il.h:3195
PRINT_OPERANDS_TO_SUPPORT DECLARE_ATTRIBUTE(element_size())
classid_t dest_cid() const
Definition il.h:3196
virtual bool HasUnknownSideEffects() const
Definition il.h:3175
intptr_t element_size() const
Definition il.h:3197
Value * src_start() const
Definition il.h:3191
bool can_overlap() const
Definition il.h:3199
Value * src() const
Definition il.h:3189
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:3177
static bool IsArrayTypeSupported(classid_t array_cid)
Definition il.h:3265
DISALLOW_COPY_AND_ASSIGN(MemoryCopyInstr)
void EmitLoopCopy(FlowGraphCompiler *compiler, Register dest_reg, Register src_reg, Register length_reg, compiler::Label *done, compiler::Label *copy_forwards=nullptr)
void PrepareLengthRegForLoop(FlowGraphCompiler *compiler, Register length_reg, compiler::Label *done)
virtual bool ComputeCanDeoptimize() const
Definition il.h:3174
Value * dest_start() const
Definition il.h:3192
MemoryCopyInstr(Value *src, classid_t src_cid, Value *dest, classid_t dest_cid, Value *src_start, Value *dest_start, Value *length, bool unboxed_inputs, bool can_overlap=true)
Definition il.h:3130
virtual Representation RequiredInputRepresentation(intptr_t index) const
Definition il.h:3371
static bool IsRegisterMove(Location loc)
Definition il.h:3406
DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(MoveArgumentInstr, TemplateDefinition, FIELD_LIST) DECLARE_EXTRA_SERIALIZATION private
Definition il.h:3382
virtual bool HasUnknownSideEffects() const
Definition il.h:3363
Location * location_slot()
Definition il.h:3357
virtual Representation representation() const
Definition il.h:3369
Value * value() const
Definition il.h:3359
Location location() const
Definition il.h:3356
virtual TokenPosition token_pos() const
Definition il.h:3365
virtual bool ComputeCanDeoptimize() const
Definition il.h:3361
intptr_t sp_relative_index() const
Definition il.h:3347
MoveArgumentInstr(Value *value, Representation representation, Location location)
Definition il.h:3331
DISALLOW_COPY_AND_ASSIGN(MoveArgumentInstr)
Location location_
Definition il.h:3412
void ClearPending(Location dest)
Definition il.h:1552
Location * dest_slot()
Definition il.h:1538
bool Blocks(Location loc) const
Definition il.h:1563
bool IsEliminated() const
Definition il.h:1575
MoveOperands & operator=(const MoveOperands &other)
Definition il.h:1528
Location src() const
Definition il.h:1534
void Write(FlowGraphSerializer *s) const
Location MarkPending()
Definition il.h:1545
void Eliminate()
Definition il.h:1574
Location dest() const
Definition il.h:1535
void set_dest(const Location &value)
Definition il.h:1541
MoveOperands(const MoveOperands &other)
Definition il.h:1525
MoveOperands(Location dest, Location src)
Definition il.h:1524
void set_src(const Location &value)
Definition il.h:1540
bool IsPending() const
Definition il.h:1557
bool IsRedundant() const
Definition il.h:1569
Location * src_slot()
Definition il.h:1537
void set_is_bootstrap_native(bool value)
Definition il.h:6007
virtual bool ComputeCanDeoptimize() const
Definition il.h:5981
DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(NativeCallInstr, TemplateDartCall, FIELD_LIST) private
Definition il.h:5997
bool is_auto_scope() const
Definition il.h:5977
virtual TokenPosition token_pos() const
Definition il.h:5979
DISALLOW_COPY_AND_ASSIGN(NativeCallInstr)
NativeCallInstr(const String &name, const Function &function, bool link_lazily, const InstructionSource &source, InputsArray &&args)
Definition il.h:5950
void set_is_auto_scope(bool value)
Definition il.h:6008
virtual bool HasUnknownSideEffects() const
Definition il.h:5983
bool is_bootstrap_native() const
Definition il.h:5976
virtual bool CanCallDart() const
Definition il.h:5986
const Function & function() const
Definition il.h:5974
NativeFunction native_c_function() const
Definition il.h:5975
bool link_lazily() const
Definition il.h:5978
NativeEntryInstr(const compiler::ffi::CallbackMarshaller &marshaller, GraphEntryInstr *graph_entry, intptr_t block_id, intptr_t try_index, intptr_t deopt_id)
Definition il.h:2220
virtual bool MayCreateUnsafeUntaggedPointer() const
Definition il.h:2991
NativeParameterInstr(const compiler::ffi::CallbackMarshaller &marshaller, intptr_t def_index)
Definition il.h:2981
virtual bool HasUnknownSideEffects() const
Definition il.h:2999
virtual bool ComputeCanDeoptimize() const
Definition il.h:2997
NativeReturnInstr(Value *typed_data_base, Value *offset, const compiler::ffi::CallbackMarshaller &marshaller)
Definition il.h:3524
virtual PRINT_OPERANDS_TO_SUPPORT Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:3536
virtual Value * InputAt(intptr_t i) const
Definition il.h:3562
virtual bool CanBecomeDeoptimizationTarget() const
Definition il.h:3547
virtual void RawSetInputAt(intptr_t i, Value *value)
Definition il.h:3577
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:3557
NativeReturnInstr(Value *value, const compiler::ffi::CallbackMarshaller &marshaller)
Definition il.h:3517
virtual intptr_t InputCount() const
Definition il.h:3553
ObjectPtr ptr() const
Definition object.h:332
bool IsNull() const
Definition object.h:363
virtual bool ComputeCanDeoptimize() const
Definition il.h:6902
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:6904
OneByteStringFromCharCodeInstr(Value *char_code)
Definition il.h:6893
OsrEntryInstr(GraphEntryInstr *graph_entry, intptr_t block_id, intptr_t try_index, intptr_t deopt_id, intptr_t stack_depth)
Definition il.h:2250
virtual BlockEntryInstr * PredecessorAt(intptr_t index) const
Definition il.h:2263
virtual void ClearPredecessors()
Definition il.h:2274
GraphEntryInstr * graph_entry() const
Definition il.h:2268
virtual void AddPredecessor(BlockEntryInstr *predecessor)
Definition il.h:2275
Location At(intptr_t i) const
Definition locations.h:618
virtual bool HasUnknownSideEffects() const
Definition il.h:1596
intptr_t NumMoves() const
Definition il.h:1611
virtual bool ComputeCanDeoptimize() const
Definition il.h:1594
const MoveSchedule & move_schedule() const
Definition il.h:1619
const GrowableArray< MoveOperands * > & moves() const
Definition il.h:1601
bool IsRedundant() const
Definition il.cc:4925
virtual TokenPosition token_pos() const
Definition il.h:1615
MoveOperands * AddMove(Location dest, Location src)
Definition il.h:1603
MoveOperands * MoveOperandsAt(intptr_t index) const
Definition il.h:1609
void set_move_schedule(const MoveSchedule &schedule)
Definition il.h:1624
void set_block(BlockEntryInstr *block)
Definition il.h:2932
intptr_t index() const
Definition il.h:2922
virtual bool HasUnknownSideEffects() const
Definition il.h:2943
virtual Representation RequiredInputRepresentation(intptr_t index) const
Definition il.h:2936
intptr_t param_index() const
Definition il.h:2926
DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(ParameterInstr, TemplateDefinition, FIELD_LIST) DECLARE_EXTRA_SERIALIZATION private Location location_
Definition il.h:2959
virtual bool ComputeCanDeoptimize() const
Definition il.h:2941
const Location & location() const
Definition il.h:2928
virtual uword Hash() const
Definition il.h:2945
ParameterInstr(BlockEntryInstr *block, intptr_t env_index, intptr_t param_index, const Location &loc, Representation representation)
Definition il.h:2906
virtual BlockEntryInstr * GetBlock()
Definition il.h:2931
virtual Representation representation() const
Definition il.h:2934
DISALLOW_COPY_AND_ASSIGN(ParameterInstr)
JoinEntryInstr * block() const
Definition il.h:2799
virtual void set_representation(Representation r)
Definition il.h:2826
virtual uword Hash() const
Definition il.h:2836
bool is_alive() const
Definition il.h:2809
void mark_dead()
Definition il.h:2811
virtual bool HasUnknownSideEffects() const
Definition il.h:2806
void set_is_receiver(ReceiverType is_receiver)
Definition il.h:2872
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const
Definition il.h:2829
PhiInstr(JoinEntryInstr *block, intptr_t num_inputs)
Definition il.h:2790
virtual Representation RequiredInputRepresentation(intptr_t i) const
Definition il.h:2813
BitVector * reaching_defs() const
Definition il.h:2845
void set_reaching_defs(BitVector *reaching_defs)
Definition il.h:2847
void mark_alive()
Definition il.h:2810
virtual bool MayCreateUnsafeUntaggedPointer() const
Definition il.h:2819
virtual bool ComputeCanDeoptimize() const
Definition il.h:2804
virtual Representation representation() const
Definition il.h:2817
virtual bool MayThrow() const
Definition il.h:2851
ReceiverType is_receiver() const
Definition il.h:2868
virtual BlockEntryInstr * GetBlock()
Definition il.h:2798
bool Done() const
Definition il.h:2106
PhiInstr * Current() const
Definition il.h:2110
void Advance()
Definition il.h:2101
PhiIterator(JoinEntryInstr *join)
Definition il.h:2099
void set_total_call_count(intptr_t count)
Definition il.h:4951
DISALLOW_COPY_AND_ASSIGN(PolymorphicInstanceCallInstr)
intptr_t NumberOfChecks() const
Definition il.h:4936
const CallTargets & targets() const
Definition il.h:4935
DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(PolymorphicInstanceCallInstr, InstanceCallBaseInstr, FIELD_LIST) private
Definition il.h:4966
static PolymorphicInstanceCallInstr * FromCall(Zone *zone, InstanceCallBaseInstr *call, const CallTargets &targets, bool complete)
Definition il.h:4906
virtual bool HasUnknownSideEffects() const
Definition il.h:3917
virtual bool AllowsCSE() const
Definition il.h:3916
PureComparison(const InstructionSource &source, Token::Kind kind, intptr_t deopt_id)
Definition il.h:3921
virtual bool HasUnknownSideEffects() const
Definition il.h:2719
virtual bool AllowsCSE() const
Definition il.h:2718
PureDefinition(const InstructionSource &source, intptr_t deopt_id)
Definition il.h:2715
PureDefinition(intptr_t deopt_id)
Definition il.h:2714
PureInstruction(intptr_t deopt_id)
Definition il.h:1461
virtual bool AllowsCSE() const
Definition il.h:1465
PureInstruction(const InstructionSource &source, intptr_t deopt_id)
Definition il.h:1462
virtual bool HasUnknownSideEffects() const
Definition il.h:1466
intptr_t catch_try_index() const
Definition il.h:3633
virtual bool ComputeCanDeoptimizeAfterCall() const
Definition il.h:3638
virtual bool ComputeCanDeoptimize() const
Definition il.h:3637
Value * stacktrace() const
Definition il.h:3635
Value * exception() const
Definition il.h:3634
virtual bool HasUnknownSideEffects() const
Definition il.h:3642
ReThrowInstr(const InstructionSource &source, intptr_t catch_try_index, intptr_t deopt_id, Value *exception, Value *stacktrace)
Definition il.h:3618
Value * value() const
Definition il.h:4138
virtual bool HasUnknownSideEffects() const
Definition il.h:4141
virtual bool ComputeCanDeoptimize() const
Definition il.h:4140
ReachabilityFenceInstr(Value *value)
Definition il.h:4130
virtual bool CanEliminate(const BlockEntryInstr *block) const
Definition il.h:4143
RecordCoverageInstr(const Array &coverage_array, intptr_t coverage_index, const InstructionSource &source)
Definition il.h:7118
virtual bool HasUnknownSideEffects() const
Definition il.h:7130
virtual bool ComputeCanDeoptimize() const
Definition il.h:7129
intptr_t num_fields() const
Definition object.h:11288
bool inserted_by_constant_propagation() const
Definition il.h:4101
RedefinitionInstr(Value *value, bool inserted_by_constant_propagation=false)
Definition il.h:4082
virtual bool ComputeCanDeoptimize() const
Definition il.h:4105
void set_constrained_type(CompileType *type)
Definition il.h:4098
virtual bool HasUnknownSideEffects() const
Definition il.h:4106
CompileType * constrained_type() const
Definition il.h:4099
virtual bool ComputeCanDeoptimize() const
Definition il.h:5354
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const
Definition il.h:5363
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:5367
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:5356
RelationalOpInstr(const InstructionSource &source, Token::Kind kind, Value *left, Value *right, intptr_t cid, intptr_t deopt_id, SpeculativeMode speculative_mode=kGuardInputs)
Definition il.h:5333
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const
Definition il.h:3441
virtual bool ComputeCanDeoptimize() const
Definition il.h:3435
virtual bool HasUnknownSideEffects() const
Definition il.h:3437
virtual bool MayThrow() const
Definition il.h:3439
ReturnBaseInstr(const InstructionSource &source, intptr_t deopt_id=DeoptId::kNone)
Definition il.h:3429
virtual bool ComputeCanDeoptimize() const
Definition il.h:9648
ShiftInt64OpInstr(Token::Kind op_kind, Value *left, Value *right, intptr_t deopt_id, Range *right_range=nullptr)
Definition il.h:9638
virtual Representation representation() const
Definition il.h:9651
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:9653
virtual bool MayThrow() const
Definition il.h:9649
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const
Definition il.h:9645
void set_shift_range(Range *shift_range)
Definition il.h:9610
ShiftIntegerOpInstr(Token::Kind op_kind, Value *left, Value *right, intptr_t deopt_id, Range *right_range=nullptr)
Definition il.h:9594
Range * shift_range() const
Definition il.h:9607
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const
Definition il.h:9708
virtual bool ComputeCanDeoptimize() const
Definition il.h:9711
virtual Representation representation() const
Definition il.h:9716
virtual bool MayThrow() const
Definition il.h:9712
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:9718
ShiftUint32OpInstr(Token::Kind op_kind, Value *left, Value *right, intptr_t deopt_id, Range *right_range=nullptr)
Definition il.h:9701
intptr_t mask() const
Definition il.h:11305
static SimdOpInstr * Create(Kind kind, Value *left, Value *right, intptr_t deopt_id)
Definition il.h:11268
virtual Value * InputAt(intptr_t i) const
Definition il.h:11299
virtual intptr_t DeoptimizationTarget() const
Definition il.h:11318
virtual bool AllowsCSE() const
Definition il.h:11325
virtual bool MayThrow() const
Definition il.h:11315
virtual void RawSetInputAt(intptr_t i, Value *value)
Definition il.h:11363
virtual bool ComputeCanDeoptimize() const
Definition il.h:11316
static SimdOpInstr * Create(MethodRecognizer::Kind kind, Value *left, Value *right, intptr_t deopt_id)
Definition il.h:11276
static SimdOpInstr * Create(MethodRecognizer::Kind kind, Value *left, intptr_t deopt_id)
Definition il.h:11284
Kind kind() const
Definition il.h:11304
virtual bool HasUnknownSideEffects() const
Definition il.h:11324
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:11327
Representation representation() const
Definition slot.h:519
bool may_contain_inner_pointer() const
Definition slot.h:533
virtual TokenPosition token_pos() const
Definition il.h:9905
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:9913
Value * value() const
Definition il.h:9904
virtual bool ComputeCanDeoptimize() const
Definition il.h:9911
SmiToDoubleInstr(Value *value, const InstructionSource &source)
Definition il.h:9899
SpeculativeShiftInt64OpInstr(Token::Kind op_kind, Value *left, Value *right, intptr_t deopt_id, Range *right_range=nullptr)
Definition il.h:9670
virtual Representation representation() const
Definition il.h:9682
virtual bool ComputeCanDeoptimize() const
Definition il.h:9677
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:9684
SpeculativeShiftUint32OpInstr(Token::Kind op_kind, Value *left, Value *right, intptr_t deopt_id, Range *right_range=nullptr)
Definition il.h:9737
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:9748
virtual Representation representation() const
Definition il.h:9746
DECLARE_EMPTY_SERIALIZATION(SpeculativeShiftUint32OpInstr, ShiftIntegerOpInstr) private DISALLOW_COPY_AND_ASSIGN(SpeculativeShiftUint32OpInstr)
virtual bool ComputeCanDeoptimize() const
Definition il.h:9744
const ICData * ic_data() const
Definition il.h:5555
StaticCallInstr(const InstructionSource &source, const Function &function, intptr_t type_args_len, const Array &argument_names, InputsArray &&arguments, const ZoneGrowableArray< const ICData * > &ic_data_array, intptr_t deopt_id, ICData::RebindRule rebind_rule)
Definition il.h:5482
CompileType * result_type() const
Definition il.h:5603
static StaticCallInstr * FromCall(Zone *zone, const C *call, const Function &target, intptr_t call_count)
Definition il.h:5535
virtual bool ComputeCanDeoptimizeAfterCall() const
Definition il.h:5581
DISALLOW_COPY_AND_ASSIGN(StaticCallInstr)
void SetResultType(Zone *zone, CompileType new_type)
Definition il.h:5599
void set_ic_data(const ICData *value)
Definition il.h:5560
virtual bool HasUnknownSideEffects() const
Definition il.h:5591
intptr_t result_cid() const
Definition il.h:5605
void set_is_known_list_constructor(bool value)
Definition il.h:5613
virtual bool CanCallDart() const
Definition il.h:5592
Code::EntryKind entry_kind() const
Definition il.h:5617
virtual intptr_t CallCount() const
Definition il.h:5576
virtual bool CanBecomeDeoptimizationTarget() const
Definition il.h:5585
void set_entry_kind(Code::EntryKind value)
Definition il.h:5619
bool is_known_list_constructor() const
Definition il.h:5612
virtual bool ComputeCanDeoptimize() const
Definition il.h:5580
virtual void SetIdentity(AliasIdentity identity)
Definition il.h:5643
virtual intptr_t DeoptimizationTarget() const
Definition il.h:5638
virtual AliasIdentity Identity() const
Definition il.h:5642
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t idx) const
Definition il.h:5623
bool IsRecognizedFactory() const
Definition il.h:5621
StaticCallInstr(const InstructionSource &source, const Function &function, intptr_t type_args_len, const Array &argument_names, InputsArray &&arguments, intptr_t deopt_id, intptr_t call_count, ICData::RebindRule rebind_rule)
Definition il.h:5507
bool HasICData() const
Definition il.h:5556
StopInstr(const char *message)
Definition il.h:3659
virtual bool ComputeCanDeoptimize() const
Definition il.h:3667
DECLARE_INSTRUCTION(Stop)
virtual bool HasUnknownSideEffects() const
Definition il.h:3669
const char * message() const
Definition il.h:3663
InnerPointerAccess stores_inner_pointer() const
Definition il.h:6406
void set_emit_store_barrier(StoreBarrierType value)
Definition il.h:6402
void set_stores_inner_pointer(InnerPointerAccess value)
Definition il.h:6409
StoreFieldInstr(const Slot &slot, Value *instance, Value *value, StoreBarrierType emit_store_barrier, const InstructionSource &source, Kind kind=Kind::kOther, compiler::Assembler::MemoryOrder memory_order=compiler::Assembler::kRelaxedNonAtomic)
Definition il.h:6328
bool ShouldEmitStoreBarrier() const
Definition il.h:6380
DISALLOW_COPY_AND_ASSIGN(StoreFieldInstr)
virtual TokenPosition token_pos() const
Definition il.h:6377
virtual intptr_t DeoptimizationTarget() const
Definition il.h:6422
bool is_initialization() const
Definition il.h:6378
virtual bool MayHaveVisibleEffect() const
Definition il.h:6429
DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(StoreFieldInstr, TemplateInstruction, FIELD_LIST) private intptr_t OffsetInBytes() const
Definition il.h:6454
virtual bool HasUnknownSideEffects() const
Definition il.h:6427
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const
Definition il.h:6360
StoreFieldInstr(const Field &field, Value *instance, Value *value, StoreBarrierType emit_store_barrier, const InstructionSource &source, const ParsedFunction *parsed_function, Kind kind=Kind::kOther)
Definition il.h:6346
virtual bool CanTriggerGC() const
Definition il.h:6417
StoreFieldInstr(const Slot &slot, Value *instance, Value *value, StoreBarrierType emit_store_barrier, InnerPointerAccess stores_inner_pointer, const InstructionSource &source, Kind kind=Kind::kOther, compiler::Assembler::MemoryOrder memory_order=compiler::Assembler::kRelaxedNonAtomic)
Definition il.h:6295
compiler::Assembler::CanBeSmi CanValueBeSmi() const
Definition il.h:6456
Value * value() const
Definition il.h:6375
Value * instance() const
Definition il.h:6373
virtual bool ComputeCanDeoptimize() const
Definition il.h:6419
const Slot & slot() const
Definition il.h:6374
bool ShouldEmitStoreBarrier() const
Definition il.h:7045
virtual bool HasUnknownSideEffects() const
Definition il.h:7086
Value * value() const
Definition il.h:7039
Value * array() const
Definition il.h:7037
intptr_t class_id() const
Definition il.h:7042
virtual intptr_t DeoptimizationTarget() const
Definition il.h:7080
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const
Definition il.h:7063
bool IsUntagged() const
Definition il.h:7076
bool aligned() const
Definition il.h:7043
intptr_t index_scale() const
Definition il.h:7041
virtual bool ComputeCanDeoptimize() const
Definition il.h:7067
void set_emit_store_barrier(StoreBarrierType value)
Definition il.h:7059
virtual bool MayHaveVisibleEffect() const
Definition il.h:7088
Value * index() const
Definition il.h:7038
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:3049
virtual bool HasUnknownSideEffects() const
Definition il.h:3046
virtual bool MayHaveVisibleEffect() const
Definition il.h:3047
intptr_t offset() const
Definition il.h:3056
Value * value() const
Definition il.h:3054
StoreIndexedUnsafeInstr(Value *index, Value *value, intptr_t offset)
Definition il.h:3031
Register base_reg() const
Definition il.h:3055
Value * index() const
Definition il.h:3053
virtual bool ComputeCanDeoptimize() const
Definition il.h:3045
bool is_dead() const
Definition il.h:5919
virtual TokenPosition token_pos() const
Definition il.h:5929
StoreLocalInstr(const LocalVariable &local, Value *value, const InstructionSource &source)
Definition il.h:5899
virtual bool HasUnknownSideEffects() const
Definition il.h:5924
bool is_last() const
Definition il.h:5922
Value * value() const
Definition il.h:5914
const LocalVariable & local() const
Definition il.h:5913
virtual bool ComputeCanDeoptimize() const
Definition il.h:5916
Value * value() const
Definition il.h:6686
StoreStaticFieldInstr(const Field &field, Value *value, const InstructionSource &source)
Definition il.h:6670
virtual bool HasUnknownSideEffects() const
Definition il.h:6693
virtual TokenPosition token_pos() const
Definition il.h:6697
virtual bool MayHaveVisibleEffect() const
Definition il.h:6695
virtual bool ComputeCanDeoptimize() const
Definition il.h:6688
virtual bool ComputeCanDeoptimize() const
Definition il.h:5103
bool needs_number_check() const
Definition il.h:5107
DISALLOW_COPY_AND_ASSIGN(StrictCompareInstr)
void set_needs_number_check(bool value)
Definition il.h:5108
StringToCharCodeInstr(Value *str, intptr_t cid)
Definition il.h:6915
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:6927
virtual bool ComputeCanDeoptimize() const
Definition il.h:6925
Value * str() const
Definition il.h:6923
virtual intptr_t InputCount() const
Definition il.h:11452
virtual TokenPosition token_pos() const
Definition il.h:11462
SuspendInstr(const InstructionSource &source, StubId stub_id, Value *operand, Value *type_args, intptr_t deopt_id, intptr_t resume_deopt_id)
Definition il.h:11433
virtual bool HasUnknownSideEffects() const
Definition il.h:11467
bool has_type_args() const
Definition il.h:11451
intptr_t resume_deopt_id() const
Definition il.h:11461
StubId stub_id() const
Definition il.h:11460
virtual intptr_t NumberOfInputsConsumedBeforeCall() const
Definition il.h:11468
Value * type_args() const
Definition il.h:11455
virtual bool ComputeCanDeoptimizeAfterCall() const
Definition il.h:11466
virtual bool CanCallDart() const
Definition il.h:11464
DECLARE_INSTRUCTION(Suspend)
Value * operand() const
Definition il.h:11454
virtual bool ComputeCanDeoptimize() const
Definition il.h:11465
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:3300
TailCallInstr(const Code &code, Value *arg_desc)
Definition il.h:3290
virtual bool ComputeCanDeoptimize() const
Definition il.h:3307
virtual bool HasUnknownSideEffects() const
Definition il.h:3306
void adjust_edge_weight(double scale_factor)
Definition il.h:2133
DISALLOW_COPY_AND_ASSIGN(TargetEntryInstr)
virtual DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(TargetEntryInstr, BlockEntryInstr, FIELD_LIST) private void ClearPredecessors()
Definition il.h:2154
virtual BlockEntryInstr * PredecessorAt(intptr_t index) const
Definition il.h:2138
virtual intptr_t PredecessorCount() const
Definition il.h:2135
TargetEntryInstr(intptr_t block_id, intptr_t try_index, intptr_t deopt_id, intptr_t stack_depth=0)
Definition il.h:2122
void set_edge_weight(double weight)
Definition il.h:2132
virtual void AddPredecessor(BlockEntryInstr *predecessor)
Definition il.h:2155
virtual intptr_t InputCount() const
Definition il.h:7350
virtual Value * InputAt(intptr_t i) const
Definition il.h:7351
virtual bool MayHaveVisibleEffect() const
Definition il.h:7356
virtual void RawSetInputAt(intptr_t i, Value *value)
Definition il.h:7368
EmbeddedArray< Value *, N > inputs_
Definition il.h:7361
TemplateAllocation(const InstructionSource &source, intptr_t deopt_id)
Definition il.h:7346
virtual void RawSetInputAt(intptr_t i, Value *value)
Definition il.h:7785
virtual intptr_t InputCount() const
Definition il.h:7776
virtual Value * InputAt(intptr_t i) const
Definition il.h:7777
TemplateArrayAllocation(const InstructionSource &source, intptr_t deopt_id)
Definition il.h:7772
EmbeddedArray< Value *, N > inputs_
Definition il.h:7782
virtual intptr_t InputCount() const
Definition il.h:3940
virtual Value * InputAt(intptr_t i) const
Definition il.h:3941
virtual void RawSetInputAt(intptr_t i, Value *value)
Definition il.h:3951
EmbeddedArray< Value *, N > inputs_
Definition il.h:3948
TemplateComparison(const InstructionSource &source, Token::Kind kind, intptr_t deopt_id=DeoptId::kNone)
Definition il.h:3935
virtual bool MayThrow() const
Definition il.h:3943
typename CSETrait< ComparisonInstr, PureComparison >::Base BaseClass
Definition il.h:3933
virtual MoveArgumentsArray * GetMoveArguments() const
Definition il.h:4578
virtual bool MayThrow() const
Definition il.h:4547
intptr_t type_args_len() const
Definition il.h:4596
const Array & argument_names() const
Definition il.h:4597
intptr_t ArgumentCount() const
Definition il.h:4568
intptr_t FirstArgIndex() const
Definition il.h:4558
virtual bool CanCallDart() const
Definition il.h:4548
virtual bool ComputeCanDeoptimizeAfterCall() const
Definition il.h:4551
TemplateDartCall(intptr_t deopt_id, intptr_t type_args_len, const Array &argument_names, InputsArray &&inputs, const InstructionSource &source)
Definition il.h:4532
virtual void SetMoveArguments(MoveArgumentsArray *move_arguments)
Definition il.h:4574
intptr_t ArgumentCountWithoutTypeArgs() const
Definition il.h:4560
virtual intptr_t ArgumentsSize() const
Definition il.h:4572
Value * Receiver() const
Definition il.h:4559
virtual intptr_t NumberOfInputsConsumedBeforeCall() const
Definition il.h:4554
intptr_t ArgumentsSizeWithoutTypeArgs() const
Definition il.h:4563
ArrayPtr GetArgumentsDescriptor() const
Definition il.h:4599
virtual bool ComputeCanDeoptimize() const
Definition il.h:4550
virtual void ReplaceInputsWithMoveArguments(MoveArgumentsArray *move_arguments)
Definition il.h:4581
virtual TokenPosition token_pos() const
Definition il.h:4598
StringPtr Selector()
Definition il.h:11823
TemplateDefinition(intptr_t deopt_id=DeoptId::kNone)
Definition il.h:2731
EmbeddedArray< Value *, N > inputs_
Definition il.h:2744
typename CSETrait< Definition, PureDefinition >::Base BaseClass
Definition il.h:2729
virtual intptr_t InputCount() const
Definition il.h:2737
virtual bool MayThrow() const
Definition il.h:2740
virtual Value * InputAt(intptr_t i) const
Definition il.h:2738
TemplateDefinition(const InstructionSource &source, intptr_t deopt_id=DeoptId::kNone)
Definition il.h:2733
virtual void RawSetInputAt(intptr_t i, Value *value)
Definition il.h:2750
TemplateInstruction(intptr_t deopt_id=DeoptId::kNone)
Definition il.h:1501
TemplateInstruction(const InstructionSource &source, intptr_t deopt_id=DeoptId::kNone)
Definition il.h:1504
virtual void RawSetInputAt(intptr_t i, Value *value)
Definition il.h:1519
EmbeddedArray< Value *, N > inputs_
Definition il.h:1516
typename CSETrait< Instruction, PureInstruction >::Base BaseClass
Definition il.h:1499
virtual intptr_t InputCount() const
Definition il.h:1508
virtual Value * InputAt(intptr_t i) const
Definition il.h:1509
virtual bool MayThrow() const
Definition il.h:1511
virtual bool ComputeCanDeoptimize() const
Definition il.h:6592
virtual bool CanTriggerGC() const
Definition il.h:6611
virtual bool CanCallDart() const
Definition il.h:6604
virtual intptr_t NumberOfInputsConsumedBeforeCall() const
Definition il.h:6596
void set_calls_initializer(bool value)
Definition il.h:6580
bool calls_initializer() const
Definition il.h:6579
bool throw_exception_on_initialization() const
Definition il.h:6582
virtual bool HasUnknownSideEffects() const
Definition il.h:6600
virtual bool ComputeCanDeoptimizeAfterCall() const
Definition il.h:6593
virtual bool UseSharedSlowPathStub(bool is_optimizing) const
Definition il.h:6587
TemplateLoadField(const InstructionSource &source, bool calls_initializer=false, intptr_t deopt_id=DeoptId::kNone, const Field *field=nullptr)
Definition il.h:6565
virtual TokenPosition token_pos() const
Definition il.h:6578
virtual intptr_t DeoptimizationTarget() const
Definition il.h:6591
virtual bool MayThrow() const
Definition il.h:6612
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:5202
virtual bool ComputeCanDeoptimize() const
Definition il.h:5197
Value * value() const
Definition il.h:5201
DECLARE_COMPARISON_INSTRUCTION(TestCids)
const ZoneGrowableArray< intptr_t > & cid_results() const
Definition il.h:5185
virtual bool ComputeCanDeoptimize() const
Definition il.h:5240
uword upper() const
Definition il.h:5232
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:5243
uword lower() const
Definition il.h:5231
DECLARE_COMPARISON_INSTRUCTION(TestRange)
Value * value() const
Definition il.h:5242
TestSmiInstr(const InstructionSource &source, Token::Kind kind, Value *left, Value *right)
Definition il.h:5142
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:5160
DECLARE_COMPARISON_INSTRUCTION(TestSmi)
virtual bool ComputeCanDeoptimize() const
Definition il.h:5158
void set_hierarchy_info(HierarchyInfo *value)
Definition thread.h:593
static Thread * Current()
Definition thread.h:361
ThrowInstr(const InstructionSource &source, intptr_t deopt_id, Value *exception)
Definition il.h:3584
virtual bool ComputeCanDeoptimize() const
Definition il.h:3596
virtual bool ComputeCanDeoptimizeAfterCall() const
Definition il.h:3597
virtual bool HasUnknownSideEffects() const
Definition il.h:3601
Value * exception() const
Definition il.h:3594
virtual bool ComputeCanDeoptimize() const
Definition il.h:10492
virtual Representation representation() const
Definition il.h:10494
virtual intptr_t DeoptimizationTarget() const
Definition il.h:10501
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:10496
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const
Definition il.h:9800
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:9804
virtual Representation representation() const
Definition il.h:9793
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:9795
virtual intptr_t DeoptimizationTarget() const
Definition il.h:9787
UnaryDoubleOpInstr(Token::Kind op_kind, Value *value, intptr_t deopt_id, SpeculativeMode speculative_mode=kGuardInputs, Representation representation=kUnboxedDouble)
Definition il.h:9766
Value * value() const
Definition il.h:9780
Token::Kind op_kind() const
Definition il.h:9781
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const
Definition il.h:9298
virtual bool ComputeCanDeoptimize() const
Definition il.h:9283
virtual Representation representation() const
Definition il.h:9285
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:9292
UnaryInt64OpInstr(Token::Kind op_kind, Value *value, intptr_t deopt_id, SpeculativeMode speculative_mode=kGuardInputs)
Definition il.h:9274
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:9287
virtual intptr_t DeoptimizationTarget() const
Definition il.h:9201
UnaryIntegerOpInstr(Token::Kind op_kind, Value *value, intptr_t deopt_id)
Definition il.h:9179
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:9197
Value * value() const
Definition il.h:9192
Token::Kind op_kind() const
Definition il.h:9193
virtual bool ComputeCanDeoptimize() const
Definition il.h:9230
UnarySmiOpInstr(Token::Kind op_kind, Value *value, intptr_t deopt_id)
Definition il.h:9227
virtual bool ComputeCanDeoptimize() const
Definition il.h:9251
UnaryUint32OpInstr(Token::Kind op_kind, Value *value, intptr_t deopt_id)
Definition il.h:9246
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:9255
virtual Representation representation() const
Definition il.h:9253
static bool IsSupported(Token::Kind op_kind)
Definition il.h:9260
virtual TokenPosition token_pos() const
Definition il.h:8669
virtual Representation representation() const
Definition il.h:8655
Value * value() const
Definition il.h:8630
void set_speculative_mode(SpeculativeMode value)
Definition il.h:8693
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const
Definition il.h:8651
DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(UnboxInstr, TemplateDefinition, FIELD_LIST) protected
Definition il.h:8675
virtual intptr_t DeoptimizationTarget() const
Definition il.h:8667
virtual bool ComputeCanDeoptimize() const
Definition il.h:8632
UnboxInt32Instr(TruncationMode truncation_mode, Value *value, intptr_t deopt_id, SpeculativeMode speculative_mode=kGuardInputs)
Definition il.h:8799
UnboxInt64Instr(Value *value, intptr_t deopt_id, SpeculativeMode speculative_mode)
Definition il.h:8819
UnboxInteger32Instr(Representation representation, TruncationMode truncation_mode, Value *value, intptr_t deopt_id, SpeculativeMode speculative_mode)
Definition il.h:8757
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:8730
UnboxIntegerInstr(Representation representation, TruncationMode truncation_mode, Value *value, intptr_t deopt_id, SpeculativeMode speculative_mode)
Definition il.h:8716
bool is_truncating() const
Definition il.h:8724
void mark_truncating()
Definition il.h:8726
intptr_t lane() const
Definition il.h:10362
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:10371
UnboxLaneInstr(Value *value, intptr_t n, Representation definition_rep, intptr_t definition_cid)
Definition il.h:10345
virtual bool ComputeCanDeoptimize() const
Definition il.h:10360
virtual Representation representation() const
Definition il.h:10364
virtual Representation RequiredInputRepresentation(intptr_t idx) const
Definition il.h:10366
Value * value() const
Definition il.h:10355
UnboxUint32Instr(Value *value, intptr_t deopt_id, SpeculativeMode speculative_mode=kGuardInputs)
Definition il.h:8778
uword constant_address() const
Definition il.h:4273
virtual Representation representation() const
Definition il.h:4270
virtual bool AttributesEqual(const Instruction &other) const
Definition il.h:7001
virtual bool HasUnknownSideEffects() const
Definition il.h:6992
virtual bool ComputeCanDeoptimize() const
Definition il.h:6993
virtual intptr_t DeoptimizationTarget() const
Definition il.h:6994
Utf8ScanInstr(Value *decoder, Value *bytes, Value *start, Value *end, Value *table, const Slot &decoder_scan_flags_field)
Definition il.h:6967
virtual Representation representation() const
Definition il.h:6990
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const
Definition il.h:6997
static constexpr T NBitMask(size_t n)
Definition utils.h:533
ValueListIterable(Value *value)
Definition il.h:947
Iterator end() const
Definition il.h:950
Iterator begin() const
Definition il.h:949
bool Done() const
Definition il.h:83
void Advance()
Definition il.h:84
Iterator(Value *head)
Definition il.h:81
Value * Current() const
Definition il.h:82
void BindToEnvironment(Definition *definition)
Definition il.h:2706
void set_use_index(intptr_t index)
Definition il.h:125
Value * Copy(Zone *zone)
Definition il.h:134
bool IsSingleUse() const
Definition il.h:117
bool NeedsWriteBarrier()
Definition il.cc:1388
bool BindsToConstantNull() const
Definition il.cc:1194
Value * CopyWithType()
Definition il.h:143
bool BindsToConstant() const
Definition il.cc:1181
void set_previous_use(Value *previous)
Definition il.h:112
intptr_t use_index() const
Definition il.h:124
bool CanBe(const Object &value)
Definition il.h:11833
static void AddToList(Value *value, Value **list)
Definition il.cc:1437
void SetReachingType(CompileType *type)
bool Equals(const Value &other) const
Definition il.cc:631
bool IsSmiValue()
Definition il.h:157
intptr_t BoundSmiConstant() const
Definition il.cc:1210
bool BindsToSmiConstant() const
Definition il.cc:1206
Instruction * instruction() const
Definition il.h:121
void set_next_use(Value *next)
Definition il.h:115
Value * previous_use() const
Definition il.h:111
const Object & BoundConstant() const
Definition il.cc:1199
Value * next_use() const
Definition il.h:114
void set_definition(Definition *definition)
Definition il.h:104
Value * CopyWithType(Zone *zone)
Definition il.h:138
void RemoveFromUseList()
Definition il.cc:1448
CompileType * reaching_type() const
Definition il.h:147
Definition * definition() const
Definition il.h:103
void BindTo(Definition *definition)
Definition il.h:2700
CompileType * Type()
Value(Definition *definition)
Definition il.h:95
const char * ToCString() const
void RefineReachingType(CompileType *type)
void set_instruction(Instruction *instruction)
Definition il.h:122
VariadicDefinition(InputsArray &&inputs, intptr_t deopt_id=DeoptId::kNone)
Definition il.h:2755
VariadicDefinition(const intptr_t num_inputs, intptr_t deopt_id=DeoptId::kNone)
Definition il.h:2770
InputsArray inputs_
Definition il.h:2782
intptr_t InputCount() const
Definition il.h:2776
Value * InputAt(intptr_t i) const
Definition il.h:2777
VariadicDefinition(InputsArray &&inputs, const InstructionSource &source, intptr_t deopt_id=DeoptId::kNone)
Definition il.h:2762
#define UNIMPLEMENTED
@ kNormal
Default priority level.
Definition embedder.h:260
#define ASSERT(E)
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition main.cc:19
VkInstance instance
Definition main.cc:48
SkBitmap source
Definition examples.cpp:28
static bool b
struct MyStruct s
struct MyStruct a[10]
glong glong end
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
uint8_t value
void PrintTo(FlValue *v, std::ostream *os)
Definition fl_test.cc:78
GAsyncResult * result
uint32_t * target
Dart_NativeFunction function
Definition fuchsia.cc:51
const char * name
Definition fuchsia.cc:50
static float max(float r, float g, float b)
Definition hsl.cpp:49
static float min(float r, float g, float b)
Definition hsl.cpp:48
#define VALUE_DEFN(name, val)
Definition il.h:2453
#define DECLARE_INSTRUCTION_BACKEND()
Definition il.h:591
#define DECLARE_COMPARISON_INSTRUCTION(type)
Definition il.h:614
#define DECLARE_VISIT_INSTRUCTION(ShortName, Attrs)
Definition il.h:11773
#define DECLARE_EMPTY_SERIALIZATION(Instr, BaseClass)
Definition il.h:666
#define DECLARE_INSTRUCTION_TYPE_CHECK(Name, Type)
Definition il.h:1155
#define DECLARE_TAG(type, attrs)
Definition il.h:958
#define FOR_EACH_INSTRUCTION(M)
Definition il.h:405
#define DECLARE_ATTRIBUTE(Attribute)
Definition il.h:701
#define DECLARE_ABSTRACT_INSTRUCTION(type)
Definition il.h:602
#define DECLARE_ATTRIBUTES_NAMED(names, values)
Definition il.h:702
#define FIELD_LIST(F)
Definition il.h:2070
#define DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(Instr, BaseClass, FieldList)
Definition il.h:649
#define VALUE_CASE(name, val)
#define PRINT_OPERANDS_TO_SUPPORT
Definition il.h:700
#define INSTRUCTION_TYPE_CHECK(Name, Attrs)
Definition il.h:1162
#define DECLARE_INSTRUCTION_NO_BACKEND(type)
Definition il.h:584
#define FOR_EACH_ALIAS_IDENTITY_VALUE(V)
Definition il.h:2413
#define KIND_DEFN(name)
Definition il.h:4364
#define PRINT_TO_SUPPORT
Definition il.h:699
#define DECLARE_INSTRUCTION(type)
Definition il.h:597
#define DECLARE_ENUM(Arity, Mask, Name,...)
Definition il.h:11249
#define FORWARD_DECLARATION(type, attrs)
Definition il.h:567
#define DECLARE_CUSTOM_SERIALIZATION(Instr)
Definition il.h:661
#define SIMD_OP_LIST(M, BINARY_OP)
Definition il.h:11195
#define DECLARE_EXTRA_SERIALIZATION
Definition il.h:670
#define FOR_EACH_ABSTRACT_INSTRUCTION(M)
Definition il.h:553
size_t length
Win32Message message
double y
double x
Definition copy.py:1
bool IsTypedDataBaseClassId(intptr_t index)
Definition class_id.h:429
constexpr intptr_t kBitsPerWord
Definition globals.h:514
InnerPointerAccess
Definition il.h:6246
DART_EXPORT bool IsNull(Dart_Handle object)
uint16_t RegList
int32_t classid_t
Definition globals.h:524
StoreBarrierType
Definition il.h:6252
@ kNoStoreBarrier
Definition il.h:6252
@ kEmitStoreBarrier
Definition il.h:6252
@ kIllegalCid
Definition class_id.h:214
@ kNullCid
Definition class_id.h:252
@ kDynamicCid
Definition class_id.h:253
Representation
Definition locations.h:66
constexpr intptr_t kBitsPerByte
Definition globals.h:463
GrowableArray< Value * > InputsArray
Definition il.h:895
unibrow::Mapping< unibrow::Ecma262Canonicalize > Canonicalize
intptr_t LocationCount(Representation rep)
Definition locations.h:75
MallocGrowableArray< CidRangeValue > CidRangeVector
Definition il.h:253
uintptr_t uword
Definition globals.h:501
bool IsClampedTypedDataBaseClassId(intptr_t index)
Definition class_id.h:461
bool IsAllocatableInNewSpace(intptr_t size)
Definition spaces.h:57
const Register FPREG
const intptr_t cid
ZoneGrowableArray< MoveArgumentInstr * > MoveArgumentsArray
Definition il.h:896
typename unwrap_enum< std::remove_cv_t< T >, std::is_enum< T >::value >::type serializable_type_t
Definition il.h:633
const char *const function_name
void(* NativeFunction)(NativeArguments *arguments)
static constexpr intptr_t kInvalidTryIndex
const Register SPREG
AlignmentType
Definition il.h:6720
@ kUnalignedAccess
Definition il.h:6721
@ kAlignedAccess
Definition il.h:6722
bool IsStringClassId(intptr_t index)
Definition class_id.h:350
Definition dom.py:1
Definition __init__.py:1
Definition ref_ptr.h:256
SkScalar w
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName)
Definition globals.h:593
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition globals.h:581
#define T
Point offset
const intptr_t count_with_type_args
Definition il.h:4522
const intptr_t count_without_type_args
Definition il.h:4524
const intptr_t type_args_len
Definition il.h:4521
ArgumentsInfo(intptr_t type_args_len, intptr_t count_with_type_args, intptr_t size_with_type_args, const Array &argument_names)
Definition il.h:4503
const intptr_t size_with_type_args
Definition il.h:4523
const intptr_t size_without_type_args
Definition il.h:4525
const Array & argument_names
Definition il.h:4526
ArrayPtr ToArgumentsDescriptor() const
Definition il.h:4516
static constexpr Representation NativeRepresentation(Representation rep)
Definition il.h:8456
compiler::Label * fall_through
Definition il.h:1456
compiler::Label * false_label
Definition il.h:1455
compiler::Label * true_label
Definition il.h:1454
CidRangeValue(intptr_t cid_start_arg, intptr_t cid_end_arg)
Definition il.h:227
bool Contains(intptr_t cid) const
Definition il.h:233
bool IsSingleCid() const
Definition il.h:232
intptr_t cid_end
Definition il.h:250
bool Equals(const CidRangeValue &other) const
Definition il.h:245
CidRangeValue(const CidRange &other)
Definition il.h:229
bool IsIllegalRange() const
Definition il.h:241
intptr_t size() const
Definition il.h:239
intptr_t cid_start
Definition il.h:249
int32_t Extent() const
Definition il.h:236
int32_t Extent() const
Definition il.h:211
intptr_t cid_start
Definition il.h:220
bool IsSingleCid() const
Definition il.h:207
CidRange(intptr_t cid_start_arg, intptr_t cid_end_arg)
Definition il.h:203
bool IsIllegalRange() const
Definition il.h:216
DISALLOW_COPY_AND_ASSIGN(CidRange)
intptr_t size() const
Definition il.h:214
bool Contains(intptr_t cid) const
Definition il.h:208
intptr_t cid_end
Definition il.h:221
bool operator==(const Iterator &other)
Definition il.h:913
bool operator!=(const Iterator &other)
Definition il.h:917
static intptr_t Length(const Instruction *instr)
Definition il.h:1020
static Definition * At(const Instruction *instr, intptr_t index)
Definition il.h:1016
static BlockEntryInstr * At(const Instruction *instr, intptr_t index)
Definition il.h:1120
static intptr_t Length(const Instruction *instr)
Definition il.h:1124
DefaultBase Base
Definition il.h:1490
static constexpr bool kCanThrow
Definition il.h:1477
PureBase Base
Definition il.h:1485
const Function * target
Definition il.h:721
StaticTypeExactnessState exactness
Definition il.h:723
DISALLOW_COPY_AND_ASSIGN(TargetInfo)
TargetInfo(intptr_t cid_start_arg, intptr_t cid_end_arg, const Function *target_arg, intptr_t count_arg, StaticTypeExactnessState exactness)
Definition il.h:710
intptr_t count
Definition il.h:722
static constexpr bool kCanThrow
Definition il.h:1473
bool operator==(const Iterator &other)
Definition il.h:942
Value * operator*() const
Definition il.h:935
bool operator!=(const Iterator &other)
Definition il.h:944
std::underlying_type_t< T > type
Definition il.h:623