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