Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(599)

Unified Diff: runtime/vm/intermediate_language_arm.cc

Issue 13502002: Support FrameLookup vm test on ARM, requiring among other things: (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: runtime/vm/intermediate_language_arm.cc
===================================================================
--- runtime/vm/intermediate_language_arm.cc (revision 20838)
+++ runtime/vm/intermediate_language_arm.cc (working copy)
@@ -167,13 +167,47 @@
LocationSummary* AssertBooleanInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
+ locs->set_in(0, Location::RegisterLocation(R0));
+ locs->set_out(Location::RegisterLocation(R0));
+ return locs;
}
+static void EmitAssertBoolean(Register reg,
+ intptr_t token_pos,
+ intptr_t deopt_id,
+ LocationSummary* locs,
+ FlowGraphCompiler* compiler) {
+ // Check that the type of the value is allowed in conditional context.
+ // Call the runtime if the object is not bool::true or bool::false.
+ ASSERT(locs->always_calls());
+ Label done;
+ __ CompareObject(reg, Bool::True());
+ __ b(&done, EQ);
+ __ CompareObject(reg, Bool::False());
+ __ b(&done, EQ);
+
+ __ Push(reg); // Push the source object.
+ compiler->GenerateCallRuntime(token_pos,
+ deopt_id,
+ kConditionTypeErrorRuntimeEntry,
+ locs);
+ // We should never return here.
+ __ bkpt(0);
+ __ Bind(&done);
+}
+
+
void AssertBooleanInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Register obj = locs()->in(0).reg();
+ Register result = locs()->out().reg();
+
+ EmitAssertBoolean(obj, token_pos(), deopt_id(), locs(), compiler);
+ ASSERT(obj == result);
}
@@ -189,19 +223,298 @@
LocationSummary* EqualityCompareInstr::MakeLocationSummary() const {
+ const intptr_t kNumInputs = 2;
+ const bool is_checked_strict_equal =
+ HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid);
+ if (receiver_class_id() == kMintCid) {
+ const intptr_t kNumTemps = 1;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ locs->set_in(0, Location::RequiresFpuRegister());
+ locs->set_in(1, Location::RequiresFpuRegister());
+ locs->set_temp(0, Location::RequiresRegister());
+ locs->set_out(Location::RequiresRegister());
+ return locs;
+ }
+ if (receiver_class_id() == kDoubleCid) {
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ locs->set_in(0, Location::RequiresFpuRegister());
+ locs->set_in(1, Location::RequiresFpuRegister());
+ locs->set_out(Location::RequiresRegister());
+ return locs;
+ }
+ if (receiver_class_id() == kSmiCid) {
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ locs->set_in(0, Location::RegisterOrConstant(left()));
+ // Only one input can be a constant operand. The case of two constant
+ // operands should be handled by constant propagation.
+ locs->set_in(1, locs->in(0).IsConstant()
+ ? Location::RequiresRegister()
+ : Location::RegisterOrConstant(right()));
+ locs->set_out(Location::RequiresRegister());
+ return locs;
+ }
+ if (is_checked_strict_equal) {
+ const intptr_t kNumTemps = 1;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ locs->set_in(0, Location::RequiresRegister());
+ locs->set_in(1, Location::RequiresRegister());
+ locs->set_temp(0, Location::RequiresRegister());
+ locs->set_out(Location::RequiresRegister());
+ return locs;
+ }
+ if (IsPolymorphic()) {
+ const intptr_t kNumTemps = 1;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
+ UNIMPLEMENTED(); // TODO(regis): Verify register allocation.
+ return locs;
+ }
+ const intptr_t kNumTemps = 1;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
+ locs->set_in(0, Location::RegisterLocation(R1));
+ locs->set_in(1, Location::RegisterLocation(R0));
+ locs->set_temp(0, Location::RegisterLocation(R6));
+ locs->set_out(Location::RegisterLocation(R0));
+ return locs;
+}
+
+
+// R1: left.
+// R0: right.
+// Uses R6 to load ic_call_data.
+static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler,
+ intptr_t deopt_id,
+ intptr_t token_pos,
+ Token::Kind kind,
+ LocationSummary* locs,
+ const ICData& original_ic_data) {
+ if (!compiler->is_optimizing()) {
+ compiler->AddCurrentDescriptor(PcDescriptors::kDeoptBefore,
+ deopt_id,
+ token_pos);
+ }
+ const int kNumberOfArguments = 2;
+ const Array& kNoArgumentNames = Array::Handle();
+ const int kNumArgumentsChecked = 2;
+
+ Label check_identity;
+ __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null()));
+ __ cmp(R1, ShifterOperand(IP));
+ __ b(&check_identity, EQ);
+ __ cmp(R0, ShifterOperand(IP));
+ __ b(&check_identity, EQ);
+
+ ICData& equality_ic_data = ICData::ZoneHandle();
+ if (compiler->is_optimizing() && FLAG_propagate_ic_data) {
+ ASSERT(!original_ic_data.IsNull());
+ if (original_ic_data.NumberOfChecks() == 0) {
+ // IC call for reoptimization populates original ICData.
+ equality_ic_data = original_ic_data.raw();
+ } else {
+ // Megamorphic call.
+ equality_ic_data = original_ic_data.AsUnaryClassChecks();
+ }
+ } else {
+ equality_ic_data = ICData::New(compiler->parsed_function().function(),
+ Symbols::EqualOperator(),
+ deopt_id,
+ kNumArgumentsChecked);
+ }
+ __ PushList((1 << R0) | (1 << R1));
+ compiler->GenerateInstanceCall(deopt_id,
+ token_pos,
+ kNumberOfArguments,
+ kNoArgumentNames,
+ locs,
+ equality_ic_data);
+ Label check_ne;
+ __ b(&check_ne);
+
+ __ Bind(&check_identity);
+ Label equality_done;
+ if (compiler->is_optimizing()) {
+ // No need to update IC data.
+ Label is_true;
+ __ cmp(R0, ShifterOperand(R1));
+ __ b(&is_true, EQ);
+ __ LoadObject(R0, (kind == Token::kEQ) ? Bool::False() : Bool::True());
+ __ b(&equality_done);
+ __ Bind(&is_true);
+ __ LoadObject(R0, (kind == Token::kEQ) ? Bool::True() : Bool::False());
+ if (kind == Token::kNE) {
+ // Skip not-equal result conversion.
+ __ b(&equality_done);
+ }
+ } else {
+ // Call stub, load IC data in register. The stub will update ICData if
+ // necessary.
+ Register ic_data_reg = locs->temp(0).reg();
+ ASSERT(ic_data_reg == R6); // Stub depends on it.
+ __ LoadObject(ic_data_reg, equality_ic_data);
+ // Pass left in R1 and right in R0.
+ compiler->GenerateCall(token_pos,
+ &StubCode::EqualityWithNullArgLabel(),
+ PcDescriptors::kOther,
+ locs);
+ }
+ __ Bind(&check_ne);
+ if (kind == Token::kNE) {
+ Label false_label, true_label, done;
+ // Negate the condition: true label returns false and vice versa.
+ __ CompareObject(R0, Bool::True());
+ __ b(&true_label, EQ);
+ __ Bind(&false_label);
zra 2013/04/03 17:39:47 Nothing branches to this label.
regis 2013/04/03 20:06:07 Removed here and on other platforms.
+ __ LoadObject(R0, Bool::True());
+ __ b(&done);
+ __ Bind(&true_label);
+ __ LoadObject(R0, Bool::False());
+ __ Bind(&done);
+ }
+ __ Bind(&equality_done);
+}
+
+
+// Emit code when ICData's targets are all Object == (which is ===).
+static void EmitCheckedStrictEqual(FlowGraphCompiler* compiler,
+ const ICData& ic_data,
+ const LocationSummary& locs,
+ Token::Kind kind,
+ BranchInstr* branch,
+ intptr_t deopt_id) {
UNIMPLEMENTED();
- return NULL;
}
-void EqualityCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+// First test if receiver is NULL, in which case === is applied.
+// If type feedback was provided (lists of <class-id, target>), do a
+// type by type check (either === or static call to the operator.
+static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler,
+ LocationSummary* locs,
+ Token::Kind kind,
+ BranchInstr* branch,
+ const ICData& ic_data,
+ intptr_t deopt_id,
+ intptr_t token_pos) {
UNIMPLEMENTED();
}
+static void EmitSmiComparisonOp(FlowGraphCompiler* compiler,
+ const LocationSummary& locs,
+ Token::Kind kind,
+ BranchInstr* branch) {
+ UNIMPLEMENTED();
+}
+
+
+static void EmitUnboxedMintEqualityOp(FlowGraphCompiler* compiler,
+ const LocationSummary& locs,
+ Token::Kind kind,
+ BranchInstr* branch) {
+ UNIMPLEMENTED();
+}
+
+
+static void EmitDoubleComparisonOp(FlowGraphCompiler* compiler,
+ const LocationSummary& locs,
+ Token::Kind kind,
+ BranchInstr* branch) {
+ UNIMPLEMENTED();
+}
+
+
+void EqualityCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ));
+ BranchInstr* kNoBranch = NULL;
+ if (receiver_class_id() == kSmiCid) {
+ EmitSmiComparisonOp(compiler, *locs(), kind(), kNoBranch);
+ return;
+ }
+ if (receiver_class_id() == kMintCid) {
+ EmitUnboxedMintEqualityOp(compiler, *locs(), kind(), kNoBranch);
+ return;
+ }
+ if (receiver_class_id() == kDoubleCid) {
+ EmitDoubleComparisonOp(compiler, *locs(), kind(), kNoBranch);
+ return;
+ }
+ const bool is_checked_strict_equal =
+ HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid);
+ if (is_checked_strict_equal) {
+ EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), kNoBranch,
+ deopt_id());
+ return;
+ }
+ if (IsPolymorphic()) {
+ EmitGenericEqualityCompare(compiler, locs(), kind(), kNoBranch, *ic_data(),
+ deopt_id(), token_pos());
+ return;
+ }
+ Register left = locs()->in(0).reg();
+ Register right = locs()->in(1).reg();
+ ASSERT(left == R1);
+ ASSERT(right == R0);
+ EmitEqualityAsInstanceCall(compiler,
+ deopt_id(),
+ token_pos(),
+ kind(),
+ locs(),
+ *ic_data());
+ ASSERT(locs()->out().reg() == R0);
+}
+
+
void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch) {
- UNIMPLEMENTED();
+ ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ));
+ if (receiver_class_id() == kSmiCid) {
+ // Deoptimizes if both arguments not Smi.
+ EmitSmiComparisonOp(compiler, *locs(), kind(), branch);
+ return;
+ }
+ if (receiver_class_id() == kMintCid) {
+ EmitUnboxedMintEqualityOp(compiler, *locs(), kind(), branch);
+ return;
+ }
+ if (receiver_class_id() == kDoubleCid) {
+ EmitDoubleComparisonOp(compiler, *locs(), kind(), branch);
+ return;
+ }
+ const bool is_checked_strict_equal =
+ HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid);
+ if (is_checked_strict_equal) {
+ EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), branch,
+ deopt_id());
+ return;
+ }
+ if (IsPolymorphic()) {
+ EmitGenericEqualityCompare(compiler, locs(), kind(), branch, *ic_data(),
+ deopt_id(), token_pos());
+ return;
+ }
+ Register left = locs()->in(0).reg();
+ Register right = locs()->in(1).reg();
+ ASSERT(left == R1);
+ ASSERT(right == R0);
+ EmitEqualityAsInstanceCall(compiler,
+ deopt_id(),
+ token_pos(),
+ Token::kEQ, // kNE reverse occurs at branch.
+ locs(),
+ *ic_data());
+ if (branch->is_checked()) {
+ EmitAssertBoolean(R0, token_pos(), deopt_id(), locs(), compiler);
+ }
+ Condition branch_condition = (kind() == Token::kNE) ? NE : EQ;
+ __ CompareObject(R0, Bool::True());
+ branch->EmitBranchOnCondition(compiler, branch_condition);
}
@@ -691,7 +1004,7 @@
void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ comparison()->EmitBranchCode(compiler, this);
}
@@ -807,25 +1120,77 @@
LocationSummary* GotoInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ return new LocationSummary(0, 0, LocationSummary::kNoCall);
}
void GotoInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ // Add deoptimization descriptor for deoptimizing instructions
+ // that may be inserted before this instruction.
+ if (!compiler->is_optimizing()) {
+ compiler->AddCurrentDescriptor(PcDescriptors::kDeoptBefore,
+ GetDeoptId(),
+ 0); // No token position.
+ }
+
+ if (HasParallelMove()) {
+ compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
+ }
+
+ // We can fall through if the successor is the next block in the list.
+ // Otherwise, we need a jump.
+ if (!compiler->CanFallThroughTo(successor())) {
+ __ b(compiler->GetJumpLabel(successor()));
+ }
}
+static Condition NegateCondition(Condition condition) {
+ switch (condition) {
+ case EQ: return NE;
+ case NE: return EQ;
+ case LT: return GE;
+ case LE: return GT;
+ case GT: return LE;
+ case GE: return LT;
+ case CC: return CS;
+ case LS: return HI;
+ case HI: return LS;
+ case CS: return CC;
+ default:
+ OS::Print("Error %d\n", condition);
+ UNIMPLEMENTED();
+ return EQ;
+ }
+}
+
+
void ControlInstruction::EmitBranchOnValue(FlowGraphCompiler* compiler,
bool value) {
- UNIMPLEMENTED();
+ if (value && !compiler->CanFallThroughTo(true_successor())) {
+ __ b(compiler->GetJumpLabel(true_successor()));
+ } else if (!value && !compiler->CanFallThroughTo(false_successor())) {
+ __ b(compiler->GetJumpLabel(false_successor()));
+ }
}
void ControlInstruction::EmitBranchOnCondition(FlowGraphCompiler* compiler,
Condition true_condition) {
- UNIMPLEMENTED();
+ if (compiler->CanFallThroughTo(false_successor())) {
+ // If the next block is the false successor we will fall through to it.
+ __ b(compiler->GetJumpLabel(true_successor()), true_condition);
+ } else {
+ // If the next block is the true successor we negate comparison and fall
+ // through to it.
+ Condition false_condition = NegateCondition(true_condition);
+ __ b(compiler->GetJumpLabel(false_successor()), false_condition);
+
+ // Fall through or jump to the true successor.
+ if (!compiler->CanFallThroughTo(true_successor())) {
+ __ b(compiler->GetJumpLabel(true_successor()));
+ }
+ }
}
@@ -841,19 +1206,85 @@
LocationSummary* StrictCompareInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 2;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ locs->set_in(0, Location::RegisterOrConstant(left()));
+ locs->set_in(1, Location::RegisterOrConstant(right()));
+ locs->set_out(Location::RequiresRegister());
+ return locs;
}
+// Special code for numbers (compare values instead of references.)
void StrictCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ ASSERT(kind() == Token::kEQ_STRICT || kind() == Token::kNE_STRICT);
+ Location left = locs()->in(0);
+ Location right = locs()->in(1);
+ if (left.IsConstant() && right.IsConstant()) {
+ // TODO(vegorov): should be eliminated earlier by constant propagation.
zra 2013/04/03 17:39:47 Unless constant propagation/folding is really bad,
regis 2013/04/03 20:06:07 I cannot answer for Slava :-) Since there is alrea
+ const bool result = (kind() == Token::kEQ_STRICT) ?
+ left.constant().raw() == right.constant().raw() :
+ left.constant().raw() != right.constant().raw();
+ __ LoadObject(locs()->out().reg(), result ? Bool::True() : Bool::False());
+ return;
+ }
+ if (left.IsConstant()) {
+ compiler->EmitEqualityRegConstCompare(right.reg(),
+ left.constant(),
+ needs_number_check());
+ } else if (right.IsConstant()) {
+ compiler->EmitEqualityRegConstCompare(left.reg(),
+ right.constant(),
+ needs_number_check());
+ } else {
+ compiler->EmitEqualityRegRegCompare(left.reg(),
+ right.reg(),
+ needs_number_check());
+ }
+
+ Register result = locs()->out().reg();
+ Label load_true, done;
+ Condition true_condition = (kind() == Token::kEQ_STRICT) ? EQ : NE;
+ __ b(&load_true, true_condition);
+ __ LoadObject(result, Bool::False());
+ __ b(&done);
+ __ Bind(&load_true);
+ __ LoadObject(result, Bool::True());
+ __ Bind(&done);
}
void StrictCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch) {
- UNIMPLEMENTED();
+ ASSERT(kind() == Token::kEQ_STRICT || kind() == Token::kNE_STRICT);
+ Location left = locs()->in(0);
+ Location right = locs()->in(1);
+ if (left.IsConstant() && right.IsConstant()) {
+ // TODO(vegorov): should be eliminated earlier by constant propagation.
zra 2013/04/03 17:39:47 Here too?
regis 2013/04/03 20:06:07 ditto
+ const bool result = (kind() == Token::kEQ_STRICT) ?
+ left.constant().raw() == right.constant().raw() :
+ left.constant().raw() != right.constant().raw();
+ branch->EmitBranchOnValue(compiler, result);
+ return;
+ }
+ if (left.IsConstant()) {
+ compiler->EmitEqualityRegConstCompare(right.reg(),
+ left.constant(),
+ needs_number_check());
+ } else if (right.IsConstant()) {
+ compiler->EmitEqualityRegConstCompare(left.reg(),
+ right.constant(),
+ needs_number_check());
+ } else {
+ compiler->EmitEqualityRegRegCompare(left.reg(),
+ right.reg(),
+ needs_number_check());
+ }
+
+ Condition true_condition = (kind() == Token::kEQ_STRICT) ? EQ : NE;
+ branch->EmitBranchOnCondition(compiler, true_condition);
}
@@ -896,13 +1327,19 @@
LocationSummary* AllocateObjectInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ return MakeCallSummary();
}
void AllocateObjectInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ const Class& cls = Class::ZoneHandle(constructor().Owner());
+ const Code& stub = Code::Handle(StubCode::GetAllocationStubForClass(cls));
+ const ExternalLabel label(cls.ToCString(), stub.EntryPoint());
+ compiler->GenerateCall(token_pos(),
+ &label,
+ PcDescriptors::kOther,
+ locs());
+ __ Drop(ArgumentCount()); // Discard arguments.
}

Powered by Google App Engine
This is Rietveld 408576698