Index: runtime/vm/intermediate_language.h |
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h |
index e7933fcb63c2cf75952bee0dfd8a3d0db7d4bc2c..6d047e8e3052044ce7e36ee6ae87d05f34eca4b9 100644 |
--- a/runtime/vm/intermediate_language.h |
+++ b/runtime/vm/intermediate_language.h |
@@ -423,6 +423,7 @@ class EmbeddedArray<T, 0> { |
M(GraphEntry) \ |
M(JoinEntry) \ |
M(TargetEntry) \ |
+ M(IndirectEntry) \ |
M(CatchBlockEntry) \ |
M(Phi) \ |
M(Redefinition) \ |
@@ -433,6 +434,7 @@ class EmbeddedArray<T, 0> { |
M(Throw) \ |
M(ReThrow) \ |
M(Goto) \ |
+ M(IndirectGoto) \ |
M(Branch) \ |
M(AssertAssignable) \ |
M(AssertBoolean) \ |
@@ -452,6 +454,7 @@ class EmbeddedArray<T, 0> { |
M(NativeCall) \ |
M(DebugStepCheck) \ |
M(LoadIndexed) \ |
+ M(LoadCodeUnits) \ |
M(StoreIndexed) \ |
M(StoreInstanceField) \ |
M(InitStaticField) \ |
@@ -491,6 +494,7 @@ class EmbeddedArray<T, 0> { |
M(BinaryDoubleOp) \ |
M(MathUnary) \ |
M(MathMinMax) \ |
+ M(CaseInsensitiveCompareUC16) \ |
M(UnboxDouble) \ |
M(BoxDouble) \ |
M(BoxFloat32x4) \ |
@@ -886,6 +890,7 @@ FOR_EACH_ABSTRACT_INSTRUCTION(INSTRUCTION_TYPE_CHECK) |
friend class UnaryDoubleOpInstr; |
friend class MathUnaryInstr; |
friend class MathMinMaxInstr; |
+ friend class CaseInsensitiveCompareUC16Instr; |
Florian Schneider
2014/10/01 17:04:13
Not needed?
jgruber1
2014/10/03 18:59:51
Done, unneeded now that deopt_id_ is not accessed
|
friend class CheckClassInstr; |
friend class CheckClassIdInstr; |
friend class GuardFieldInstr; |
@@ -901,10 +906,12 @@ FOR_EACH_ABSTRACT_INSTRUCTION(INSTRUCTION_TYPE_CHECK) |
friend class MergedMathInstr; |
friend class FlowGraphOptimizer; |
friend class LoadIndexedInstr; |
+ friend class LoadCodeUnitsInstr; |
friend class StoreIndexedInstr; |
friend class StoreInstanceFieldInstr; |
friend class ComparisonInstr; |
friend class TargetEntryInstr; |
+ friend class IndirectEntryInstr; |
Florian Schneider
2014/10/01 17:04:13
Not needed?
jgruber1
2014/10/03 18:59:51
Done.
|
friend class JoinEntryInstr; |
friend class InstanceOfInstr; |
friend class PolymorphicInstanceCallInstr; |
@@ -1187,6 +1194,9 @@ class BlockEntryInstr : public Instruction { |
void set_block_id(intptr_t block_id) { block_id_ = block_id; } |
+ intptr_t offset() const { return offset_; } |
+ void set_offset(intptr_t offset) { offset_ = offset; } |
+ |
// For all instruction in this block: Remove all inputs (including in the |
// environment) from their definition's use lists for all instructions. |
void ClearAllInstructions(); |
@@ -1202,6 +1212,7 @@ class BlockEntryInstr : public Instruction { |
dominator_(NULL), |
dominated_blocks_(1), |
last_instruction_(NULL), |
+ offset_(-1), |
parallel_move_(NULL), |
loop_info_(NULL) { } |
@@ -1226,6 +1237,9 @@ class BlockEntryInstr : public Instruction { |
GrowableArray<BlockEntryInstr*> dominated_blocks_; |
Instruction* last_instruction_; |
+ // Offset of this block from the start of the emitted code. |
+ intptr_t offset_; |
+ |
// Parallel move that will be used by linear scan register allocator to |
// connect live ranges at the start of the block. |
ParallelMoveInstr* parallel_move_; |
@@ -1306,6 +1320,10 @@ class GraphEntryInstr : public BlockEntryInstr { |
CatchBlockEntryInstr* GetCatchEntry(intptr_t index); |
+ void AddIndirectEntry(IndirectEntryInstr* entry) { |
+ indirect_entries_.Add(entry); |
+ } |
+ |
GrowableArray<Definition*>* initial_definitions() { |
return &initial_definitions_; |
} |
@@ -1340,6 +1358,10 @@ class GraphEntryInstr : public BlockEntryInstr { |
return catch_entries_; |
} |
+ const GrowableArray<IndirectEntryInstr*>& indirect_entries() const { |
+ return indirect_entries_; |
+ } |
+ |
virtual void PrintTo(BufferFormatter* f) const; |
private: |
@@ -1349,6 +1371,8 @@ class GraphEntryInstr : public BlockEntryInstr { |
const ParsedFunction* parsed_function_; |
TargetEntryInstr* normal_entry_; |
GrowableArray<CatchBlockEntryInstr*> catch_entries_; |
+ // Indirect targets are blocks reachable only through indirect gotos. |
+ GrowableArray<IndirectEntryInstr*> indirect_entries_; |
GrowableArray<Definition*> initial_definitions_; |
const intptr_t osr_id_; |
intptr_t entry_count_; |
@@ -1394,6 +1418,7 @@ class JoinEntryInstr : public BlockEntryInstr { |
friend class BlockEntryInstr; |
friend class InlineExitCollector; |
friend class PolymorphicInliner; |
+ friend class IndirectEntryInstr; // Access in il_printer.cc. |
// Direct access to phis_ in order to resize it due to phi elimination. |
friend class ConstantPropagator; |
@@ -1473,6 +1498,25 @@ class TargetEntryInstr : public BlockEntryInstr { |
}; |
+class IndirectEntryInstr : public JoinEntryInstr { |
+ public: |
+ IndirectEntryInstr(intptr_t block_id, |
+ intptr_t indirect_id, |
+ intptr_t try_index) |
+ : JoinEntryInstr(block_id, try_index), |
+ indirect_id_(indirect_id) { } |
+ |
+ DECLARE_INSTRUCTION(IndirectEntry) |
+ |
+ virtual void PrintTo(BufferFormatter* f) const; |
+ |
+ intptr_t indirect_id() const { return indirect_id_; } |
+ |
+ private: |
+ const intptr_t indirect_id_; |
+}; |
+ |
+ |
class CatchBlockEntryInstr : public BlockEntryInstr { |
public: |
CatchBlockEntryInstr(intptr_t block_id, |
@@ -2141,6 +2185,73 @@ class GotoInstr : public TemplateInstruction<0> { |
}; |
+// As a high level description, an indirect goto takes the indirect_id of an |
+// indirect entry as a parameter, and jumps to that location. |
+// |
+// In more detail: in order to preserve split-edge form, an intermediate target |
+// entry consisting of a goto to the final indirect entry is inserted on |
+// each possible indirect goto -> indirect entry edge. These target entries are |
+// accessible through successors_. |
+// |
+// Byte offsets of all possible indirect targets are stored in the offsets_ |
+// array and are looked up at runtime. |
+class IndirectGotoInstr : public TemplateInstruction<1> { |
+ public: |
+ IndirectGotoInstr(GrowableObjectArray* offsets, |
Florian Schneider
2014/10/01 17:04:13
Can this be NULL? If not, just pass a const Growab
jgruber1
2014/10/03 18:59:51
No, but it is modified in SetOffsetCount() and Set
|
+ Value* offset_from_start) |
+ : offset_from_start_(offset_from_start), |
+ offsets_(*offsets) { |
+ inputs_[0] = offset_from_start_; |
Vyacheslav Egorov (Google)
2014/10/01 20:13:21
please add a comment explaining why you can't SetI
jgruber1
2014/10/03 18:59:51
Done, changed to SetInputAt().
|
+ offset_from_start_->set_instruction(this); |
+ offset_from_start_->set_use_index(0); |
+ } |
+ |
+ DECLARE_INSTRUCTION(IndirectGoto) |
+ |
+ virtual intptr_t ArgumentCount() const { return 0; } |
+ |
+ void AddSuccessor(TargetEntryInstr* successor) { |
+ ASSERT(successor->next()->IsGoto()); |
+ ASSERT(successor->next()->AsGoto()->successor()->IsIndirectEntry()); |
+ successors_.Add(successor); |
+ } |
+ |
+ virtual intptr_t SuccessorCount() const { return successors_.length(); } |
+ virtual TargetEntryInstr* SuccessorAt(intptr_t index) const { |
+ ASSERT(index < SuccessorCount()); |
+ return successors_[index]; |
+ } |
+ |
+ virtual bool CanDeoptimize() const { return false; } |
+ virtual bool CanBecomeDeoptimizationTarget() const { return false; } |
+ |
+ virtual EffectSet Effects() const { return EffectSet::None(); } |
+ |
+ virtual void PrintTo(BufferFormatter* f) const; |
+ |
+ virtual bool MayThrow() const { return false; } |
+ |
+ const GrowableObjectArray& offsets() const { return offsets_; } |
+ void SetOffsetCount(Isolate* isolate, intptr_t count) { |
+ if (offsets_.Capacity() < count) { |
+ offsets_.Grow(count, Heap::kOld); |
+ } |
+ if (offsets_.Length() < count) { |
+ offsets_.SetLength(count); |
+ } |
+ } |
+ void SetOffsetAt(Isolate* isolate, intptr_t index, intptr_t offset) { |
+ offsets_.SetAt(index, Smi::ZoneHandle(isolate, Smi::New(offset))); |
+ } |
+ |
+ private: |
+ Value* offset_from_start_; |
Florian Schneider
2014/10/02 11:58:12
Remove this member. SetInputAt(0,...) already stor
jgruber1
2014/10/03 18:59:51
Done.
|
+ |
+ GrowableArray<TargetEntryInstr*> successors_; |
+ GrowableObjectArray& offsets_; |
+}; |
+ |
+ |
class ComparisonInstr : public TemplateDefinition<2> { |
public: |
Value* left() const { return inputs_[0]; } |
@@ -3767,6 +3878,71 @@ class LoadIndexedInstr : public TemplateDefinition<2> { |
}; |
+// Loads the specified number of code units from the given string, packing |
+// multiple code units into a single datatype. In essence, this is a specialized |
+// version of LoadIndexedInstr which accepts only string targets may load |
+// multiple elements at once. The result datatype differs depending on the |
+// string type, element count, and architecture; if possible, the result is |
+// packed into a Smi, falling back to a Mint otherwise. |
+// TODO(jgruber): Add support for loading into UnboxedInt32x4. |
+class LoadCodeUnitsInstr : public TemplateDefinition<2> { |
+ public: |
+ LoadCodeUnitsInstr(Value* array, |
+ Value* index, |
+ intptr_t index_scale, |
+ intptr_t element_count, |
+ intptr_t class_id, |
+ intptr_t deopt_id, |
+ intptr_t token_pos) |
+ : index_scale_(index_scale), |
+ class_id_(class_id), |
+ token_pos_(token_pos), |
+ element_count_(element_count) { |
+ ASSERT(class_id == kOneByteStringCid || class_id == kTwoByteStringCid); |
+ SetInputAt(0, array); |
+ SetInputAt(1, index); |
+ deopt_id_ = deopt_id; |
Vyacheslav Egorov (Google)
2014/10/01 20:13:21
I don't think it can deoptimize.
jgruber1
2014/10/03 18:59:51
Done.
|
+ } |
+ |
+ intptr_t token_pos() const { return token_pos_; } |
+ |
+ DECLARE_INSTRUCTION(LoadCodeUnits) |
+ virtual CompileType ComputeType() const; |
+ |
+ bool IsExternal() const { |
+ return array()->definition()->representation() == kUntagged; |
+ } |
+ |
+ Value* array() const { return inputs_[0]; } |
+ Value* index() const { return inputs_[1]; } |
+ intptr_t index_scale() const { return index_scale_; } |
+ intptr_t class_id() const { return class_id_; } |
+ intptr_t element_count() const { return element_count_; } |
+ |
+ virtual bool CanDeoptimize() const { |
+ return deopt_id_ != Isolate::kNoDeoptId; |
+ } |
+ |
+ virtual Representation representation() const; |
+ virtual void InferRange(RangeAnalysis* analysis, Range* range); |
+ |
+ virtual bool AllowsCSE() const { return false; } |
+ virtual EffectSet Effects() const { return EffectSet::None(); } |
+ virtual EffectSet Dependencies() const { return EffectSet::All(); } |
+ virtual bool AttributesEqual(Instruction* other) const; |
+ |
+ virtual bool MayThrow() const { return false; } |
+ |
+ private: |
+ const intptr_t index_scale_; |
+ const intptr_t class_id_; |
+ const intptr_t token_pos_; |
+ const intptr_t element_count_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(LoadCodeUnitsInstr); |
+}; |
+ |
+ |
class StringFromCharCodeInstr : public TemplateDefinition<1> { |
public: |
StringFromCharCodeInstr(Value* char_code, intptr_t cid) : cid_(cid) { |
@@ -4995,6 +5171,67 @@ class MathUnaryInstr : public TemplateDefinition<1> { |
}; |
+// Calls into the runtime and performs a case-insensitive comparison of the |
+// UTF16 strings (i.e. TwoByteString or ExternalTwoByteString) located at |
+// str[lhs_index:lhs_index + length] and str[rhs_index:rhs_index + length]. |
+// |
+// TODO(jgruber): Remove this once (if) functions inherited from unibrow |
+// are moved to dart code. |
+class CaseInsensitiveCompareUC16Instr : public TemplateDefinition<4> { |
+ public: |
+ CaseInsensitiveCompareUC16Instr( |
+ Value* str, |
+ Value* lhs_index, |
+ Value* rhs_index, |
+ Value* length, |
+ intptr_t cid, |
+ intptr_t deopt_id) |
+ : cid_(cid) { |
+ ASSERT(cid == kTwoByteStringCid || cid == kExternalTwoByteStringCid); |
+ ASSERT(index_scale() == 2); |
+ SetInputAt(0, str); |
+ SetInputAt(1, lhs_index); |
+ SetInputAt(2, rhs_index); |
+ SetInputAt(3, length); |
+ deopt_id_ = deopt_id; |
Florian Schneider
2014/10/01 17:04:13
Not needed, since it can't deoptimize and also can
jgruber1
2014/10/03 18:59:51
Done.
|
+ } |
+ |
+ Value* str() const { return inputs_[0]; } |
+ Value* lhs_index() const { return inputs_[1]; } |
+ Value* rhs_index() const { return inputs_[2]; } |
+ Value* length() const { return inputs_[3]; } |
+ |
+ const RuntimeEntry& TargetFunction() const; |
+ bool IsExternal() const { return cid_ == kExternalTwoByteStringCid; } |
+ intptr_t class_id() const { return cid_; } |
+ intptr_t index_scale() const { return Instance::ElementSizeFor(cid_); } |
+ |
+ virtual void PrintOperandsTo(BufferFormatter* f) const; |
+ |
+ virtual bool CanDeoptimize() const { return false; } |
+ |
+ virtual Representation representation() const { |
+ return kTagged; |
+ } |
+ |
+ DECLARE_INSTRUCTION(CaseInsensitiveCompareUC16) |
+ virtual CompileType ComputeType() const; |
+ |
+ virtual bool AllowsCSE() const { return true; } |
+ virtual EffectSet Effects() const { return EffectSet::None(); } |
+ virtual EffectSet Dependencies() const { return EffectSet::None(); } |
+ |
+ virtual bool MayThrow() const { return false; } |
+ |
+ Definition* Canonicalize(FlowGraph* flow_graph); |
+ |
+ private: |
+ const intptr_t cid_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(CaseInsensitiveCompareUC16Instr); |
+}; |
+ |
+ |
// Represents Math's static min and max functions. |
class MathMinMaxInstr : public TemplateDefinition<2> { |
public: |