2012-05-21 19:51:17 +00:00
|
|
|
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
|
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
#include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32.
|
|
|
|
#if defined(TARGET_ARCH_IA32)
|
|
|
|
|
2012-05-31 18:09:11 +00:00
|
|
|
#include "vm/intermediate_language.h"
|
|
|
|
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
#include "lib/error.h"
|
2012-05-21 19:51:17 +00:00
|
|
|
#include "vm/flow_graph_compiler.h"
|
|
|
|
#include "vm/locations.h"
|
2012-06-01 18:38:35 +00:00
|
|
|
#include "vm/object_store.h"
|
2012-06-22 01:24:36 +00:00
|
|
|
#include "vm/parser.h"
|
2012-05-31 17:24:23 +00:00
|
|
|
#include "vm/stub_code.h"
|
2012-07-24 00:01:50 +00:00
|
|
|
#include "vm/symbols.h"
|
2012-05-21 19:51:17 +00:00
|
|
|
|
|
|
|
#define __ compiler->assembler()->
|
|
|
|
|
|
|
|
namespace dart {
|
|
|
|
|
2012-05-31 18:09:11 +00:00
|
|
|
DECLARE_FLAG(int, optimization_counter_threshold);
|
2012-05-31 17:24:23 +00:00
|
|
|
DECLARE_FLAG(bool, trace_functions);
|
|
|
|
|
|
|
|
// Generic summary for call instructions that have all arguments pushed
|
|
|
|
// on the stack and return the result in a fixed register EAX.
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
LocationSummary* Computation::MakeCallSummary() {
|
2012-06-18 18:04:22 +00:00
|
|
|
LocationSummary* result = new LocationSummary(0, 0, LocationSummary::kCall);
|
2012-05-31 17:24:23 +00:00
|
|
|
result->set_out(Location::RegisterLocation(EAX));
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2012-05-31 15:52:39 +00:00
|
|
|
|
2012-05-30 16:57:19 +00:00
|
|
|
void BindInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-05-31 17:24:23 +00:00
|
|
|
computation()->EmitNativeCode(compiler);
|
2012-08-21 13:58:57 +00:00
|
|
|
if (is_used() && !compiler->is_optimizing()) {
|
|
|
|
__ pushl(locs()->out().reg());
|
2012-06-13 16:23:14 +00:00
|
|
|
}
|
2012-05-31 17:24:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* ReturnInstr::MakeLocationSummary() const {
|
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 1;
|
2012-07-31 11:51:47 +00:00
|
|
|
LocationSummary* locs =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2012-05-31 17:24:23 +00:00
|
|
|
locs->set_in(0, Location::RegisterLocation(EAX));
|
|
|
|
locs->set_temp(0, Location::RequiresRegister());
|
|
|
|
return locs;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ReturnInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
Register result = locs()->in(0).reg();
|
|
|
|
Register temp = locs()->temp(0).reg();
|
|
|
|
ASSERT(result == EAX);
|
|
|
|
if (!compiler->is_optimizing()) {
|
|
|
|
// Count only in unoptimized code.
|
|
|
|
// TODO(srdjan): Replace the counting code with a type feedback
|
|
|
|
// collection and counting stub.
|
|
|
|
const Function& function =
|
|
|
|
Function::ZoneHandle(compiler->parsed_function().function().raw());
|
|
|
|
__ LoadObject(temp, function);
|
|
|
|
__ incl(FieldAddress(temp, Function::usage_counter_offset()));
|
2012-06-26 17:43:44 +00:00
|
|
|
if (FlowGraphCompiler::CanOptimize()) {
|
2012-05-31 17:24:23 +00:00
|
|
|
// Do not optimize if usage count must be reported.
|
|
|
|
__ cmpl(FieldAddress(temp, Function::usage_counter_offset()),
|
|
|
|
Immediate(FLAG_optimization_counter_threshold));
|
2012-07-16 20:55:09 +00:00
|
|
|
Label not_yet_hot, already_optimized;
|
|
|
|
__ j(LESS, ¬_yet_hot, Assembler::kNearJump);
|
|
|
|
__ j(GREATER, &already_optimized, Assembler::kNearJump);
|
2012-05-31 17:24:23 +00:00
|
|
|
__ pushl(result); // Preserve result.
|
|
|
|
__ pushl(temp); // Argument for runtime: function to optimize.
|
|
|
|
__ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry);
|
|
|
|
__ popl(temp); // Remove argument.
|
|
|
|
__ popl(result); // Restore result.
|
|
|
|
__ Bind(¬_yet_hot);
|
2012-07-16 20:55:09 +00:00
|
|
|
__ Bind(&already_optimized);
|
2012-05-31 18:09:11 +00:00
|
|
|
}
|
2012-05-31 17:24:23 +00:00
|
|
|
}
|
|
|
|
if (FLAG_trace_functions) {
|
|
|
|
const Function& function =
|
|
|
|
Function::ZoneHandle(compiler->parsed_function().function().raw());
|
|
|
|
__ LoadObject(temp, function);
|
|
|
|
__ pushl(result); // Preserve result.
|
|
|
|
__ pushl(temp);
|
2012-08-06 20:24:03 +00:00
|
|
|
compiler->GenerateCallRuntime(Isolate::kNoDeoptId,
|
2012-05-31 17:24:23 +00:00
|
|
|
0,
|
|
|
|
CatchClauseNode::kInvalidTryIndex,
|
2012-08-14 06:59:24 +00:00
|
|
|
kTraceFunctionExitRuntimeEntry,
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
2012-05-31 17:24:23 +00:00
|
|
|
__ popl(temp); // Remove argument.
|
|
|
|
__ popl(result); // Restore result.
|
|
|
|
}
|
2012-08-07 20:15:17 +00:00
|
|
|
#if defined(DEBUG)
|
|
|
|
// TODO(srdjan): Fix for functions with finally clause.
|
|
|
|
// A finally clause may leave a previously pushed return value if it
|
|
|
|
// has its own return instruction. Method that have finally are currently
|
|
|
|
// not optimized.
|
|
|
|
if (!compiler->HasFinally()) {
|
|
|
|
Label done;
|
|
|
|
__ movl(EDI, EBP);
|
|
|
|
__ subl(EDI, ESP);
|
|
|
|
// + 1 for Pc marker.
|
|
|
|
__ cmpl(EDI, Immediate((compiler->StackSize() + 1) * kWordSize));
|
|
|
|
__ j(EQUAL, &done, Assembler::kNearJump);
|
|
|
|
__ int3();
|
|
|
|
__ Bind(&done);
|
|
|
|
}
|
|
|
|
#endif
|
2012-05-31 17:24:23 +00:00
|
|
|
__ LeaveFrame();
|
|
|
|
__ ret();
|
2012-06-22 01:24:36 +00:00
|
|
|
|
|
|
|
// Generate 1 byte NOP so that the debugger can patch the
|
|
|
|
// return pattern with a call to the debug stub.
|
2012-05-31 17:24:23 +00:00
|
|
|
__ nop(1);
|
|
|
|
compiler->AddCurrentDescriptor(PcDescriptors::kReturn,
|
2012-08-06 20:24:03 +00:00
|
|
|
deopt_id(),
|
2012-06-22 20:37:01 +00:00
|
|
|
token_pos(),
|
2012-05-31 17:24:23 +00:00
|
|
|
CatchClauseNode::kInvalidTryIndex);
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
2012-05-21 19:51:17 +00:00
|
|
|
|
2012-05-22 18:36:19 +00:00
|
|
|
|
2012-05-30 16:57:19 +00:00
|
|
|
LocationSummary* ClosureCallComp::MakeLocationSummary() const {
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
const intptr_t kNumInputs = 0;
|
|
|
|
const intptr_t kNumTemps = 1;
|
2012-07-31 11:51:47 +00:00
|
|
|
LocationSummary* result =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
result->set_out(Location::RegisterLocation(EAX));
|
|
|
|
result->set_temp(0, Location::RegisterLocation(EDX)); // Arg. descriptor.
|
|
|
|
return result;
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* LoadLocalComp::MakeLocationSummary() const {
|
2012-07-31 11:51:47 +00:00
|
|
|
return LocationSummary::Make(0,
|
|
|
|
Location::RequiresRegister(),
|
|
|
|
LocationSummary::kNoCall);
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-31 17:24:23 +00:00
|
|
|
void LoadLocalComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
Register result = locs()->out().reg();
|
|
|
|
__ movl(result, Address(EBP, local().index() * kWordSize));
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* StoreLocalComp::MakeLocationSummary() const {
|
2012-07-31 11:51:47 +00:00
|
|
|
return LocationSummary::Make(1,
|
|
|
|
Location::SameAsFirstInput(),
|
|
|
|
LocationSummary::kNoCall);
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-31 17:24:23 +00:00
|
|
|
void StoreLocalComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
Register value = locs()->in(0).reg();
|
|
|
|
Register result = locs()->out().reg();
|
|
|
|
ASSERT(result == value); // Assert that register assignment is correct.
|
|
|
|
__ movl(Address(EBP, local().index() * kWordSize), value);
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-21 13:36:36 +00:00
|
|
|
LocationSummary* MaterializeComp::MakeLocationSummary() const {
|
2012-07-31 11:51:47 +00:00
|
|
|
return LocationSummary::Make(0,
|
|
|
|
Location::RequiresRegister(),
|
|
|
|
LocationSummary::kNoCall);
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-21 13:36:36 +00:00
|
|
|
void MaterializeComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-05-31 17:24:23 +00:00
|
|
|
Register result = locs()->out().reg();
|
2012-08-21 13:36:36 +00:00
|
|
|
__ LoadObject(result, constant_val()->value());
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* AssertAssignableComp::MakeLocationSummary() const {
|
2012-06-25 23:50:37 +00:00
|
|
|
const intptr_t kNumInputs = 3;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2012-07-31 11:51:47 +00:00
|
|
|
LocationSummary* summary =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
summary->set_in(0, Location::RegisterLocation(EAX)); // Value.
|
|
|
|
summary->set_in(1, Location::RegisterLocation(ECX)); // Instantiator.
|
|
|
|
summary->set_in(2, Location::RegisterLocation(EDX)); // Type arguments.
|
2012-06-04 17:06:43 +00:00
|
|
|
summary->set_out(Location::RegisterLocation(EAX));
|
|
|
|
return summary;
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-24 17:19:20 +00:00
|
|
|
LocationSummary* AssertBooleanComp::MakeLocationSummary() const {
|
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2012-07-31 11:51:47 +00:00
|
|
|
LocationSummary* locs =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
|
2012-07-24 17:19:20 +00:00
|
|
|
locs->set_in(0, Location::RegisterLocation(EAX));
|
|
|
|
locs->set_out(Location::RegisterLocation(EAX));
|
|
|
|
return locs;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
void AssertBooleanComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
Register obj = locs()->in(0).reg();
|
|
|
|
Register result = locs()->out().reg();
|
2012-05-30 16:57:19 +00:00
|
|
|
|
2012-08-13 22:31:07 +00:00
|
|
|
if (!is_eliminated()) {
|
|
|
|
// 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.
|
|
|
|
Label done;
|
|
|
|
__ CompareObject(obj, compiler->bool_true());
|
|
|
|
__ j(EQUAL, &done, Assembler::kNearJump);
|
|
|
|
__ CompareObject(obj, compiler->bool_false());
|
|
|
|
__ j(EQUAL, &done, Assembler::kNearJump);
|
|
|
|
|
|
|
|
__ pushl(obj); // Push the source object.
|
|
|
|
compiler->GenerateCallRuntime(deopt_id(),
|
|
|
|
token_pos(),
|
|
|
|
try_index(),
|
2012-08-14 06:59:24 +00:00
|
|
|
kConditionTypeErrorRuntimeEntry,
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
2012-08-13 22:31:07 +00:00
|
|
|
// We should never return here.
|
|
|
|
__ int3();
|
|
|
|
__ Bind(&done);
|
|
|
|
}
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
ASSERT(obj == result);
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-20 15:20:11 +00:00
|
|
|
static Condition TokenKindToSmiCondition(Token::Kind kind) {
|
|
|
|
switch (kind) {
|
|
|
|
case Token::kEQ: return EQUAL;
|
|
|
|
case Token::kNE: return NOT_EQUAL;
|
|
|
|
case Token::kLT: return LESS;
|
|
|
|
case Token::kGT: return GREATER;
|
|
|
|
case Token::kLTE: return LESS_EQUAL;
|
|
|
|
case Token::kGTE: return GREATER_EQUAL;
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
return OVERFLOW;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-30 16:57:19 +00:00
|
|
|
LocationSummary* EqualityCompareComp::MakeLocationSummary() const {
|
2012-06-13 18:48:46 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
2012-08-13 23:44:07 +00:00
|
|
|
const bool is_checked_strict_equal =
|
2012-08-22 22:21:44 +00:00
|
|
|
HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid);
|
2012-08-13 23:44:07 +00:00
|
|
|
if ((receiver_class_id() == kSmiCid) ||
|
|
|
|
(receiver_class_id() == kDoubleCid) ||
|
|
|
|
is_checked_strict_equal) {
|
2012-06-13 18:48:46 +00:00
|
|
|
const intptr_t kNumTemps = 1;
|
2012-07-31 11:51:47 +00:00
|
|
|
LocationSummary* locs =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2012-06-13 18:48:46 +00:00
|
|
|
locs->set_in(0, Location::RequiresRegister());
|
|
|
|
locs->set_in(1, Location::RequiresRegister());
|
|
|
|
locs->set_temp(0, Location::RequiresRegister());
|
2012-07-19 15:52:44 +00:00
|
|
|
locs->set_out(Location::RequiresRegister());
|
2012-06-13 18:48:46 +00:00
|
|
|
return locs;
|
2012-06-13 16:23:14 +00:00
|
|
|
}
|
2012-06-19 21:49:11 +00:00
|
|
|
if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
|
2012-06-15 00:40:58 +00:00
|
|
|
const intptr_t kNumTemps = 1;
|
2012-07-31 11:51:47 +00:00
|
|
|
LocationSummary* locs =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
|
2012-07-24 17:19:20 +00:00
|
|
|
locs->set_in(0, Location::RegisterLocation(ECX));
|
|
|
|
locs->set_in(1, Location::RegisterLocation(EDX));
|
|
|
|
locs->set_temp(0, Location::RegisterLocation(EBX));
|
2012-07-19 15:52:44 +00:00
|
|
|
locs->set_out(Location::RegisterLocation(EAX));
|
2012-06-13 18:48:46 +00:00
|
|
|
return locs;
|
|
|
|
}
|
2012-06-15 00:40:58 +00:00
|
|
|
const intptr_t kNumTemps = 0;
|
2012-07-31 11:51:47 +00:00
|
|
|
LocationSummary* locs =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
|
2012-07-24 17:19:20 +00:00
|
|
|
locs->set_in(0, Location::RegisterLocation(ECX));
|
|
|
|
locs->set_in(1, Location::RegisterLocation(EDX));
|
2012-07-19 15:52:44 +00:00
|
|
|
locs->set_out(Location::RegisterLocation(EAX));
|
2012-06-15 00:40:58 +00:00
|
|
|
return locs;
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-15 00:40:58 +00:00
|
|
|
static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler,
|
2012-08-17 21:18:26 +00:00
|
|
|
intptr_t deopt_id,
|
|
|
|
intptr_t token_pos,
|
|
|
|
intptr_t try_index,
|
|
|
|
Token::Kind kind,
|
2012-08-23 10:08:37 +00:00
|
|
|
LocationSummary* locs) {
|
2012-06-15 00:40:58 +00:00
|
|
|
compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
|
2012-08-17 21:18:26 +00:00
|
|
|
deopt_id,
|
|
|
|
token_pos,
|
|
|
|
try_index);
|
2012-07-24 00:01:50 +00:00
|
|
|
const String& operator_name = String::ZoneHandle(Symbols::New("=="));
|
2012-06-15 00:40:58 +00:00
|
|
|
const int kNumberOfArguments = 2;
|
|
|
|
const Array& kNoArgumentNames = Array::Handle();
|
|
|
|
const int kNumArgumentsChecked = 2;
|
|
|
|
|
2012-08-17 17:30:06 +00:00
|
|
|
Label done, false_label, true_label;
|
2012-08-23 10:08:37 +00:00
|
|
|
Register left = locs->in(0).reg();
|
|
|
|
Register right = locs->in(1).reg();
|
2012-08-17 17:30:06 +00:00
|
|
|
__ popl(right);
|
|
|
|
__ popl(left);
|
|
|
|
const Immediate raw_null =
|
|
|
|
Immediate(reinterpret_cast<intptr_t>(Object::null()));
|
|
|
|
Label check_identity, instance_call;
|
|
|
|
__ cmpl(right, raw_null);
|
|
|
|
__ j(EQUAL, &check_identity, Assembler::kNearJump);
|
|
|
|
__ cmpl(left, raw_null);
|
|
|
|
__ j(NOT_EQUAL, &instance_call, Assembler::kNearJump);
|
|
|
|
|
|
|
|
__ Bind(&check_identity);
|
|
|
|
__ cmpl(left, right);
|
|
|
|
__ j(EQUAL, &true_label);
|
2012-08-17 21:18:26 +00:00
|
|
|
if (kind == Token::kEQ) {
|
2012-08-17 17:30:06 +00:00
|
|
|
__ LoadObject(EAX, compiler->bool_false());
|
|
|
|
__ jmp(&done);
|
|
|
|
__ Bind(&true_label);
|
|
|
|
__ LoadObject(EAX, compiler->bool_true());
|
|
|
|
__ jmp(&done);
|
|
|
|
} else {
|
2012-08-17 21:18:26 +00:00
|
|
|
ASSERT(kind == Token::kNE);
|
2012-08-17 17:30:06 +00:00
|
|
|
__ jmp(&false_label);
|
|
|
|
}
|
|
|
|
|
|
|
|
__ Bind(&instance_call);
|
|
|
|
__ pushl(left);
|
|
|
|
__ pushl(right);
|
2012-08-17 21:18:26 +00:00
|
|
|
compiler->GenerateInstanceCall(deopt_id,
|
|
|
|
token_pos,
|
|
|
|
try_index,
|
2012-06-15 00:40:58 +00:00
|
|
|
operator_name,
|
|
|
|
kNumberOfArguments,
|
|
|
|
kNoArgumentNames,
|
2012-08-14 06:59:24 +00:00
|
|
|
kNumArgumentsChecked,
|
2012-08-23 10:08:37 +00:00
|
|
|
locs);
|
2012-08-17 21:18:26 +00:00
|
|
|
if (kind == Token::kNE) {
|
2012-08-17 17:30:06 +00:00
|
|
|
// Negate the condition: true label returns false and vice versa.
|
2012-07-20 15:20:11 +00:00
|
|
|
__ CompareObject(EAX, compiler->bool_true());
|
2012-08-17 17:30:06 +00:00
|
|
|
__ j(EQUAL, &true_label, Assembler::kNearJump);
|
|
|
|
__ Bind(&false_label);
|
2012-07-20 15:20:11 +00:00
|
|
|
__ LoadObject(EAX, compiler->bool_true());
|
|
|
|
__ jmp(&done, Assembler::kNearJump);
|
2012-08-17 17:30:06 +00:00
|
|
|
__ Bind(&true_label);
|
2012-07-20 15:20:11 +00:00
|
|
|
__ LoadObject(EAX, compiler->bool_false());
|
|
|
|
}
|
2012-08-17 17:30:06 +00:00
|
|
|
__ Bind(&done);
|
2012-06-15 00:40:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler,
|
2012-07-19 15:52:44 +00:00
|
|
|
const ICData& orig_ic_data,
|
2012-08-23 10:08:37 +00:00
|
|
|
LocationSummary* locs,
|
2012-07-19 15:52:44 +00:00
|
|
|
BranchInstr* branch,
|
|
|
|
Token::Kind kind,
|
2012-08-06 20:24:03 +00:00
|
|
|
intptr_t deopt_id,
|
2012-07-19 15:52:44 +00:00
|
|
|
intptr_t token_pos,
|
2012-08-23 10:08:37 +00:00
|
|
|
intptr_t try_index) {
|
2012-07-20 15:20:11 +00:00
|
|
|
ASSERT((kind == Token::kEQ) || (kind == Token::kNE));
|
2012-07-19 15:52:44 +00:00
|
|
|
const ICData& ic_data = ICData::Handle(orig_ic_data.AsUnaryClassChecks());
|
2012-06-19 21:49:11 +00:00
|
|
|
ASSERT(ic_data.NumberOfChecks() > 0);
|
2012-06-20 23:19:02 +00:00
|
|
|
ASSERT(ic_data.num_args_tested() == 1);
|
2012-08-08 22:15:38 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(deopt_id, try_index, kDeoptEquality);
|
2012-08-23 10:08:37 +00:00
|
|
|
Register left = locs->in(0).reg();
|
|
|
|
Register right = locs->in(1).reg();
|
2012-06-15 00:40:58 +00:00
|
|
|
__ testl(left, Immediate(kSmiTagMask));
|
2012-08-23 10:08:37 +00:00
|
|
|
Register temp = locs->temp(0).reg();
|
2012-08-08 19:46:23 +00:00
|
|
|
if (ic_data.GetReceiverClassIdAt(0) == kSmiCid) {
|
2012-06-15 00:40:58 +00:00
|
|
|
Label done, load_class_id;
|
|
|
|
__ j(NOT_ZERO, &load_class_id, Assembler::kNearJump);
|
2012-08-08 19:46:23 +00:00
|
|
|
__ movl(temp, Immediate(kSmiCid));
|
2012-06-15 00:40:58 +00:00
|
|
|
__ jmp(&done, Assembler::kNearJump);
|
|
|
|
__ Bind(&load_class_id);
|
|
|
|
__ LoadClassId(temp, left);
|
|
|
|
__ Bind(&done);
|
|
|
|
} else {
|
|
|
|
__ j(ZERO, deopt); // Smi deopts.
|
|
|
|
__ LoadClassId(temp, left);
|
|
|
|
}
|
2012-08-13 23:44:07 +00:00
|
|
|
// 'temp' contains class-id of the left argument.
|
|
|
|
ObjectStore* object_store = Isolate::Current()->object_store();
|
2012-07-20 15:20:11 +00:00
|
|
|
Condition cond = TokenKindToSmiCondition(kind);
|
2012-06-15 00:40:58 +00:00
|
|
|
Label done;
|
2012-06-19 21:49:11 +00:00
|
|
|
for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) {
|
2012-08-13 23:44:07 +00:00
|
|
|
// Assert that the Smi is at position 0, if at all.
|
2012-08-08 19:46:23 +00:00
|
|
|
ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmiCid) || (i == 0));
|
2012-06-15 00:40:58 +00:00
|
|
|
Label next_test;
|
2012-06-19 21:49:11 +00:00
|
|
|
__ cmpl(temp, Immediate(ic_data.GetReceiverClassIdAt(i)));
|
2012-07-20 15:43:52 +00:00
|
|
|
__ j(NOT_EQUAL, &next_test);
|
2012-06-19 21:49:11 +00:00
|
|
|
const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i));
|
2012-08-14 00:38:01 +00:00
|
|
|
if (target.Owner() == object_store->object_class()) {
|
2012-06-15 00:40:58 +00:00
|
|
|
// Object.== is same as ===.
|
|
|
|
__ Drop(2);
|
|
|
|
__ cmpl(left, right);
|
2012-07-19 15:52:44 +00:00
|
|
|
if (branch != NULL) {
|
|
|
|
branch->EmitBranchOnCondition(compiler, cond);
|
2012-06-15 00:40:58 +00:00
|
|
|
} else {
|
2012-08-23 10:08:37 +00:00
|
|
|
Register result = locs->out().reg();
|
2012-06-15 00:40:58 +00:00
|
|
|
Label load_true;
|
2012-07-19 15:52:44 +00:00
|
|
|
__ j(cond, &load_true, Assembler::kNearJump);
|
2012-06-15 00:40:58 +00:00
|
|
|
__ LoadObject(result, compiler->bool_false());
|
|
|
|
__ jmp(&done);
|
|
|
|
__ Bind(&load_true);
|
|
|
|
__ LoadObject(result, compiler->bool_true());
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
const int kNumberOfArguments = 2;
|
|
|
|
const Array& kNoArgumentNames = Array::Handle();
|
2012-08-06 20:24:03 +00:00
|
|
|
compiler->GenerateStaticCall(deopt_id,
|
2012-07-19 15:52:44 +00:00
|
|
|
token_pos,
|
|
|
|
try_index,
|
2012-06-15 00:40:58 +00:00
|
|
|
target,
|
|
|
|
kNumberOfArguments,
|
2012-08-14 06:59:24 +00:00
|
|
|
kNoArgumentNames,
|
2012-08-23 10:08:37 +00:00
|
|
|
locs);
|
2012-07-20 15:20:11 +00:00
|
|
|
if (branch == NULL) {
|
|
|
|
if (kind == Token::kNE) {
|
|
|
|
Label false_label;
|
|
|
|
__ CompareObject(EAX, compiler->bool_true());
|
|
|
|
__ j(EQUAL, &false_label, Assembler::kNearJump);
|
|
|
|
__ LoadObject(EAX, compiler->bool_true());
|
2012-07-20 15:43:52 +00:00
|
|
|
__ jmp(&done);
|
2012-07-20 15:20:11 +00:00
|
|
|
__ Bind(&false_label);
|
|
|
|
__ LoadObject(EAX, compiler->bool_false());
|
|
|
|
__ jmp(&done);
|
|
|
|
}
|
|
|
|
} else {
|
2012-06-15 00:40:58 +00:00
|
|
|
__ CompareObject(EAX, compiler->bool_true());
|
2012-07-19 15:52:44 +00:00
|
|
|
branch->EmitBranchOnCondition(compiler, cond);
|
2012-06-15 00:40:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
__ jmp(&done);
|
|
|
|
__ Bind(&next_test);
|
|
|
|
}
|
|
|
|
// Fall through leads to deoptimization
|
|
|
|
__ jmp(deopt);
|
|
|
|
__ Bind(&done);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-13 23:44:07 +00:00
|
|
|
// 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,
|
|
|
|
intptr_t token_pos,
|
|
|
|
intptr_t try_index) {
|
|
|
|
ASSERT((kind == Token::kEQ) || (kind == Token::kNE));
|
|
|
|
Register left = locs.in(0).reg();
|
|
|
|
Register right = locs.in(1).reg();
|
|
|
|
Register temp = locs.temp(0).reg();
|
|
|
|
Label* deopt = compiler->AddDeoptStub(deopt_id,
|
|
|
|
try_index,
|
2012-08-21 13:58:57 +00:00
|
|
|
kDeoptEquality);
|
2012-08-13 23:44:07 +00:00
|
|
|
__ testl(left, Immediate(kSmiTagMask));
|
|
|
|
__ j(ZERO, deopt);
|
2012-08-17 17:30:06 +00:00
|
|
|
// 'left' is not Smi.
|
|
|
|
const Immediate raw_null =
|
|
|
|
Immediate(reinterpret_cast<intptr_t>(Object::null()));
|
|
|
|
Label identity_compare;
|
|
|
|
__ cmpl(right, raw_null);
|
|
|
|
__ j(EQUAL, &identity_compare);
|
|
|
|
__ cmpl(left, raw_null);
|
|
|
|
__ j(EQUAL, &identity_compare);
|
|
|
|
|
2012-08-13 23:44:07 +00:00
|
|
|
__ LoadClassId(temp, left);
|
|
|
|
for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) {
|
|
|
|
__ cmpl(temp, Immediate(ic_data.GetReceiverClassIdAt(i)));
|
|
|
|
if (i == (ic_data.NumberOfChecks() - 1)) {
|
|
|
|
__ j(NOT_EQUAL, deopt);
|
|
|
|
} else {
|
2012-08-17 17:30:06 +00:00
|
|
|
__ j(EQUAL, &identity_compare);
|
2012-08-13 23:44:07 +00:00
|
|
|
}
|
|
|
|
}
|
2012-08-17 17:30:06 +00:00
|
|
|
__ Bind(&identity_compare);
|
2012-08-13 23:44:07 +00:00
|
|
|
__ cmpl(left, right);
|
|
|
|
if (branch == NULL) {
|
|
|
|
Label done, is_equal;
|
|
|
|
Register result = locs.out().reg();
|
|
|
|
__ j(EQUAL, &is_equal, Assembler::kNearJump);
|
|
|
|
// Not equal.
|
|
|
|
__ LoadObject(result, (kind == Token::kEQ) ? compiler->bool_false()
|
|
|
|
: compiler->bool_true());
|
|
|
|
__ jmp(&done, Assembler::kNearJump);
|
|
|
|
__ Bind(&is_equal);
|
|
|
|
__ LoadObject(result, (kind == Token::kEQ) ? compiler->bool_true()
|
|
|
|
: compiler->bool_false());
|
|
|
|
__ Bind(&done);
|
|
|
|
} else {
|
|
|
|
Condition cond = TokenKindToSmiCondition(kind);
|
|
|
|
branch->EmitBranchOnCondition(compiler, cond);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-15 00:40:58 +00:00
|
|
|
// 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.
|
2012-06-13 18:48:46 +00:00
|
|
|
static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler,
|
2012-08-23 10:08:37 +00:00
|
|
|
LocationSummary* locs,
|
2012-07-19 15:52:44 +00:00
|
|
|
Token::Kind kind,
|
|
|
|
BranchInstr* branch,
|
|
|
|
const ICData& ic_data,
|
2012-08-06 20:24:03 +00:00
|
|
|
intptr_t deopt_id,
|
2012-07-19 15:52:44 +00:00
|
|
|
intptr_t token_pos,
|
|
|
|
intptr_t try_index) {
|
2012-07-20 15:20:11 +00:00
|
|
|
ASSERT((kind == Token::kEQ) || (kind == Token::kNE));
|
2012-07-19 15:52:44 +00:00
|
|
|
ASSERT(!ic_data.IsNull() && (ic_data.NumberOfChecks() > 0));
|
2012-08-23 10:08:37 +00:00
|
|
|
Register left = locs->in(0).reg();
|
|
|
|
Register right = locs->in(1).reg();
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
const Immediate raw_null =
|
|
|
|
Immediate(reinterpret_cast<intptr_t>(Object::null()));
|
2012-08-17 17:30:06 +00:00
|
|
|
Label done, identity_compare, non_null_compare;
|
|
|
|
__ cmpl(right, raw_null);
|
|
|
|
__ j(EQUAL, &identity_compare, Assembler::kNearJump);
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
__ cmpl(left, raw_null);
|
|
|
|
__ j(NOT_EQUAL, &non_null_compare, Assembler::kNearJump);
|
|
|
|
// Comparison with NULL is "===".
|
2012-08-17 17:30:06 +00:00
|
|
|
__ Bind(&identity_compare);
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
__ cmpl(left, right);
|
2012-07-20 15:20:11 +00:00
|
|
|
Condition cond = TokenKindToSmiCondition(kind);
|
2012-07-19 15:52:44 +00:00
|
|
|
if (branch != NULL) {
|
|
|
|
branch->EmitBranchOnCondition(compiler, cond);
|
2012-06-13 18:48:46 +00:00
|
|
|
} else {
|
2012-08-23 10:08:37 +00:00
|
|
|
Register result = locs->out().reg();
|
2012-06-13 16:23:14 +00:00
|
|
|
Label load_true;
|
2012-07-19 15:52:44 +00:00
|
|
|
__ j(cond, &load_true, Assembler::kNearJump);
|
2012-06-13 16:23:14 +00:00
|
|
|
__ LoadObject(result, compiler->bool_false());
|
2012-06-15 00:40:58 +00:00
|
|
|
__ jmp(&done);
|
2012-06-13 16:23:14 +00:00
|
|
|
__ Bind(&load_true);
|
|
|
|
__ LoadObject(result, compiler->bool_true());
|
|
|
|
}
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
__ jmp(&done);
|
2012-06-15 00:40:58 +00:00
|
|
|
__ Bind(&non_null_compare); // Receiver is not null.
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
__ pushl(left);
|
|
|
|
__ pushl(right);
|
2012-07-19 15:52:44 +00:00
|
|
|
EmitEqualityAsPolymorphicCall(compiler, ic_data, locs, branch, kind,
|
2012-08-23 10:08:37 +00:00
|
|
|
deopt_id, token_pos, try_index);
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
__ Bind(&done);
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-19 15:52:44 +00:00
|
|
|
static void EmitSmiComparisonOp(FlowGraphCompiler* compiler,
|
|
|
|
const LocationSummary& locs,
|
|
|
|
Token::Kind kind,
|
|
|
|
BranchInstr* branch,
|
2012-08-06 20:24:03 +00:00
|
|
|
intptr_t deopt_id,
|
2012-07-19 15:52:44 +00:00
|
|
|
intptr_t token_pos,
|
|
|
|
intptr_t try_index) {
|
|
|
|
Register left = locs.in(0).reg();
|
|
|
|
Register right = locs.in(1).reg();
|
2012-08-11 00:09:12 +00:00
|
|
|
const bool left_is_smi = (branch == NULL) ?
|
2012-08-16 22:22:57 +00:00
|
|
|
false : (branch->left()->ResultCid() == kSmiCid);
|
2012-08-11 00:09:12 +00:00
|
|
|
const bool right_is_smi = (branch == NULL) ?
|
2012-08-16 22:22:57 +00:00
|
|
|
false : (branch->right()->ResultCid() == kSmiCid);
|
2012-08-11 00:09:12 +00:00
|
|
|
if (!left_is_smi || !right_is_smi) {
|
|
|
|
Register temp = locs.temp(0).reg();
|
|
|
|
Label* deopt = compiler->AddDeoptStub(deopt_id,
|
|
|
|
try_index,
|
2012-08-21 13:58:57 +00:00
|
|
|
kDeoptSmiCompareSmi);
|
2012-08-11 00:09:12 +00:00
|
|
|
__ movl(temp, left);
|
|
|
|
__ orl(temp, right);
|
|
|
|
__ testl(temp, Immediate(kSmiTagMask));
|
|
|
|
__ j(NOT_ZERO, deopt);
|
|
|
|
}
|
2012-06-11 17:02:39 +00:00
|
|
|
|
2012-07-19 15:52:44 +00:00
|
|
|
Condition true_condition = TokenKindToSmiCondition(kind);
|
2012-06-11 17:02:39 +00:00
|
|
|
__ cmpl(left, right);
|
2012-06-13 16:23:14 +00:00
|
|
|
|
2012-07-19 15:52:44 +00:00
|
|
|
if (branch != NULL) {
|
|
|
|
branch->EmitBranchOnCondition(compiler, true_condition);
|
2012-06-13 16:23:14 +00:00
|
|
|
} else {
|
2012-07-19 15:52:44 +00:00
|
|
|
Register result = locs.out().reg();
|
2012-06-13 16:23:14 +00:00
|
|
|
Label done, is_true;
|
|
|
|
__ j(true_condition, &is_true);
|
|
|
|
__ LoadObject(result, compiler->bool_false());
|
|
|
|
__ jmp(&done);
|
|
|
|
__ Bind(&is_true);
|
|
|
|
__ LoadObject(result, compiler->bool_true());
|
|
|
|
__ Bind(&done);
|
|
|
|
}
|
2012-06-11 17:02:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static Condition TokenKindToDoubleCondition(Token::Kind kind) {
|
|
|
|
switch (kind) {
|
|
|
|
case Token::kEQ: return EQUAL;
|
2012-07-19 15:52:44 +00:00
|
|
|
case Token::kNE: return NOT_EQUAL;
|
2012-06-11 17:02:39 +00:00
|
|
|
case Token::kLT: return BELOW;
|
|
|
|
case Token::kGT: return ABOVE;
|
|
|
|
case Token::kLTE: return BELOW_EQUAL;
|
2012-06-12 16:09:02 +00:00
|
|
|
case Token::kGTE: return ABOVE_EQUAL;
|
2012-06-11 17:02:39 +00:00
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
return OVERFLOW;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-19 15:52:44 +00:00
|
|
|
static void EmitDoubleComparisonOp(FlowGraphCompiler* compiler,
|
|
|
|
const LocationSummary& locs,
|
|
|
|
Token::Kind kind,
|
|
|
|
BranchInstr* branch,
|
2012-08-06 20:24:03 +00:00
|
|
|
intptr_t deopt_id,
|
2012-07-19 15:52:44 +00:00
|
|
|
intptr_t token_pos,
|
|
|
|
intptr_t try_index) {
|
|
|
|
Register left = locs.in(0).reg();
|
|
|
|
Register right = locs.in(1).reg();
|
2012-06-11 17:02:39 +00:00
|
|
|
// TODO(srdjan): temp is only needed if a conversion Smi->Double occurs.
|
2012-07-19 15:52:44 +00:00
|
|
|
Register temp = locs.temp(0).reg();
|
2012-08-06 20:24:03 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(deopt_id,
|
2012-07-19 15:52:44 +00:00
|
|
|
try_index,
|
2012-08-21 13:58:57 +00:00
|
|
|
kDeoptDoubleComparison);
|
2012-06-11 17:02:39 +00:00
|
|
|
compiler->LoadDoubleOrSmiToXmm(XMM0, left, temp, deopt);
|
|
|
|
compiler->LoadDoubleOrSmiToXmm(XMM1, right, temp, deopt);
|
2012-06-13 16:23:14 +00:00
|
|
|
|
2012-07-19 15:52:44 +00:00
|
|
|
Condition true_condition = TokenKindToDoubleCondition(kind);
|
|
|
|
if (branch != NULL) {
|
2012-07-13 20:17:42 +00:00
|
|
|
compiler->EmitDoubleCompareBranch(
|
2012-07-19 15:52:44 +00:00
|
|
|
true_condition, XMM0, XMM1, branch);
|
2012-06-13 16:23:14 +00:00
|
|
|
} else {
|
2012-07-13 20:17:42 +00:00
|
|
|
compiler->EmitDoubleCompareBool(
|
2012-07-19 15:52:44 +00:00
|
|
|
true_condition, XMM0, XMM1, locs.out().reg());
|
2012-06-13 16:23:14 +00:00
|
|
|
}
|
2012-06-11 17:02:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-08 14:05:53 +00:00
|
|
|
void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-08-08 19:46:23 +00:00
|
|
|
if (receiver_class_id() == kSmiCid) {
|
2012-08-17 17:30:06 +00:00
|
|
|
// Deoptimizes if both arguments not Smi.
|
2012-08-08 14:05:53 +00:00
|
|
|
EmitSmiComparisonOp(compiler, *locs(), kind(), NULL, // No branch.
|
|
|
|
deopt_id(), token_pos(), try_index());
|
|
|
|
return;
|
|
|
|
}
|
2012-08-08 19:46:23 +00:00
|
|
|
if (receiver_class_id() == kDoubleCid) {
|
2012-08-17 17:30:06 +00:00
|
|
|
// Deoptimizes if both arguments are Smi, or if none is Double or Smi.
|
2012-08-08 14:05:53 +00:00
|
|
|
EmitDoubleComparisonOp(compiler, *locs(), kind(), NULL, // No branch.
|
|
|
|
deopt_id(), token_pos(), try_index());
|
|
|
|
return;
|
|
|
|
}
|
2012-08-13 23:44:07 +00:00
|
|
|
const bool is_checked_strict_equal =
|
2012-08-22 22:21:44 +00:00
|
|
|
HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid);
|
2012-08-13 23:44:07 +00:00
|
|
|
if (is_checked_strict_equal) {
|
|
|
|
EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), NULL,
|
|
|
|
deopt_id(), token_pos(), try_index());
|
|
|
|
return;
|
|
|
|
}
|
2012-08-08 14:05:53 +00:00
|
|
|
if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
|
2012-08-23 10:08:37 +00:00
|
|
|
EmitGenericEqualityCompare(compiler, locs(), kind(), NULL, *ic_data(),
|
2012-08-08 14:05:53 +00:00
|
|
|
deopt_id(), token_pos(), try_index());
|
|
|
|
} else {
|
|
|
|
Register left = locs()->in(0).reg();
|
|
|
|
Register right = locs()->in(1).reg();
|
|
|
|
__ pushl(left);
|
|
|
|
__ pushl(right);
|
2012-08-17 21:18:26 +00:00
|
|
|
EmitEqualityAsInstanceCall(compiler,
|
|
|
|
deopt_id(),
|
|
|
|
token_pos(),
|
|
|
|
try_index(),
|
|
|
|
kind(),
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
2012-08-17 21:18:26 +00:00
|
|
|
ASSERT(locs()->out().reg() == EAX);
|
2012-08-08 14:05:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* RelationalOpComp::MakeLocationSummary() const {
|
2012-08-16 08:46:45 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
2012-08-08 19:46:23 +00:00
|
|
|
if ((operands_class_id() == kSmiCid) || (operands_class_id() == kDoubleCid)) {
|
2012-08-08 14:05:53 +00:00
|
|
|
const intptr_t kNumTemps = 1;
|
|
|
|
LocationSummary* summary =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
|
|
|
summary->set_in(1, Location::RequiresRegister());
|
|
|
|
summary->set_out(Location::RequiresRegister());
|
|
|
|
summary->set_temp(0, Location::RequiresRegister());
|
|
|
|
return summary;
|
|
|
|
}
|
2012-08-16 08:46:45 +00:00
|
|
|
const intptr_t kNumTemps = 0;
|
|
|
|
LocationSummary* locs =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
|
|
|
|
// Pick arbitrary fixed input registers because this is a call.
|
|
|
|
locs->set_in(0, Location::RegisterLocation(EAX));
|
|
|
|
locs->set_in(1, Location::RegisterLocation(ECX));
|
|
|
|
locs->set_out(Location::RegisterLocation(EAX));
|
|
|
|
return locs;
|
2012-08-08 14:05:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-11 17:02:39 +00:00
|
|
|
void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-08-08 19:46:23 +00:00
|
|
|
if (operands_class_id() == kSmiCid) {
|
2012-07-19 15:52:44 +00:00
|
|
|
EmitSmiComparisonOp(compiler, *locs(), kind(), NULL,
|
2012-08-06 20:24:03 +00:00
|
|
|
deopt_id(), token_pos(), try_index());
|
2012-06-11 17:02:39 +00:00
|
|
|
return;
|
|
|
|
}
|
2012-08-08 19:46:23 +00:00
|
|
|
if (operands_class_id() == kDoubleCid) {
|
2012-07-19 15:52:44 +00:00
|
|
|
EmitDoubleComparisonOp(compiler, *locs(), kind(), NULL,
|
2012-08-06 20:24:03 +00:00
|
|
|
deopt_id(), token_pos(), try_index());
|
2012-06-11 17:02:39 +00:00
|
|
|
return;
|
|
|
|
}
|
2012-08-16 08:46:45 +00:00
|
|
|
|
|
|
|
// Push arguments for the call.
|
|
|
|
// TODO(fschneider): Split this instruction into different types to avoid
|
|
|
|
// explicitly pushing arguments to the call here.
|
|
|
|
Register left = locs()->in(0).reg();
|
|
|
|
Register right = locs()->in(1).reg();
|
|
|
|
__ pushl(left);
|
|
|
|
__ pushl(right);
|
2012-07-16 20:55:09 +00:00
|
|
|
if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
|
2012-08-06 20:24:03 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(deopt_id(),
|
2012-07-16 20:55:09 +00:00
|
|
|
try_index(),
|
|
|
|
kDeoptRelationalOp);
|
2012-08-16 08:46:45 +00:00
|
|
|
// Load class into EDI. Since this is a call, any register except
|
|
|
|
// the fixed input registers would be ok.
|
|
|
|
ASSERT((left != EDI) && (right != EDI));
|
2012-07-16 20:55:09 +00:00
|
|
|
Label done;
|
|
|
|
const intptr_t kNumArguments = 2;
|
2012-08-08 19:46:23 +00:00
|
|
|
__ movl(EDI, Immediate(kSmiCid));
|
2012-08-16 08:46:45 +00:00
|
|
|
__ testl(left, Immediate(kSmiTagMask));
|
2012-07-16 20:55:09 +00:00
|
|
|
__ j(ZERO, &done);
|
2012-08-16 08:46:45 +00:00
|
|
|
__ LoadClassId(EDI, left);
|
2012-07-16 20:55:09 +00:00
|
|
|
__ Bind(&done);
|
|
|
|
compiler->EmitTestAndCall(ICData::Handle(ic_data()->AsUnaryClassChecks()),
|
|
|
|
EDI, // Class id register.
|
|
|
|
kNumArguments,
|
|
|
|
Array::Handle(), // No named arguments.
|
|
|
|
deopt, // Deoptimize target.
|
|
|
|
NULL, // Fallthrough when done.
|
2012-08-06 20:24:03 +00:00
|
|
|
deopt_id(),
|
2012-07-16 20:55:09 +00:00
|
|
|
token_pos(),
|
2012-08-14 06:59:24 +00:00
|
|
|
try_index(),
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
2012-08-16 08:46:45 +00:00
|
|
|
ASSERT(locs()->out().reg() == EAX);
|
2012-07-16 20:55:09 +00:00
|
|
|
return;
|
|
|
|
}
|
2012-06-11 17:02:39 +00:00
|
|
|
const String& function_name =
|
2012-07-24 00:01:50 +00:00
|
|
|
String::ZoneHandle(Symbols::New(Token::Str(kind())));
|
2012-06-11 17:02:39 +00:00
|
|
|
compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
|
2012-08-06 20:24:03 +00:00
|
|
|
deopt_id(),
|
2012-06-22 20:37:01 +00:00
|
|
|
token_pos(),
|
2012-06-11 17:02:39 +00:00
|
|
|
try_index());
|
|
|
|
const intptr_t kNumArguments = 2;
|
|
|
|
const intptr_t kNumArgsChecked = 2; // Type-feedback.
|
2012-08-06 20:24:03 +00:00
|
|
|
compiler->GenerateInstanceCall(deopt_id(),
|
2012-06-22 20:37:01 +00:00
|
|
|
token_pos(),
|
2012-06-11 17:02:39 +00:00
|
|
|
try_index(),
|
|
|
|
function_name,
|
|
|
|
kNumArguments,
|
|
|
|
Array::ZoneHandle(), // No optional arguments.
|
2012-08-14 06:59:24 +00:00
|
|
|
kNumArgsChecked,
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
2012-06-11 17:02:39 +00:00
|
|
|
ASSERT(locs()->out().reg() == EAX);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-30 16:57:19 +00:00
|
|
|
LocationSummary* NativeCallComp::MakeLocationSummary() const {
|
2012-06-22 01:24:36 +00:00
|
|
|
const intptr_t kNumInputs = 0;
|
|
|
|
const intptr_t kNumTemps = 3;
|
2012-07-31 11:51:47 +00:00
|
|
|
LocationSummary* locs =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
|
2012-05-31 17:24:23 +00:00
|
|
|
locs->set_temp(0, Location::RegisterLocation(EAX));
|
|
|
|
locs->set_temp(1, Location::RegisterLocation(ECX));
|
|
|
|
locs->set_temp(2, Location::RegisterLocation(EDX));
|
2012-07-24 16:01:54 +00:00
|
|
|
locs->set_out(Location::RegisterLocation(EAX));
|
2012-05-31 17:24:23 +00:00
|
|
|
return locs;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void NativeCallComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
ASSERT(locs()->temp(0).reg() == EAX);
|
|
|
|
ASSERT(locs()->temp(1).reg() == ECX);
|
|
|
|
ASSERT(locs()->temp(2).reg() == EDX);
|
|
|
|
Register result = locs()->out().reg();
|
2012-06-22 01:24:36 +00:00
|
|
|
|
2012-05-31 17:24:23 +00:00
|
|
|
// Push the result place holder initialized to NULL.
|
|
|
|
__ PushObject(Object::ZoneHandle());
|
|
|
|
// Pass a pointer to the first argument in EAX.
|
2012-06-18 19:56:06 +00:00
|
|
|
intptr_t arg_count = argument_count();
|
|
|
|
if (is_native_instance_closure()) {
|
|
|
|
arg_count += 1;
|
|
|
|
}
|
|
|
|
if (!has_optional_parameters() && !is_native_instance_closure()) {
|
|
|
|
__ leal(EAX, Address(EBP, (1 + arg_count) * kWordSize));
|
2012-05-31 17:24:23 +00:00
|
|
|
} else {
|
|
|
|
__ leal(EAX,
|
|
|
|
Address(EBP, ParsedFunction::kFirstLocalSlotIndex * kWordSize));
|
|
|
|
}
|
|
|
|
__ movl(ECX, Immediate(reinterpret_cast<uword>(native_c_function())));
|
2012-06-18 19:56:06 +00:00
|
|
|
__ movl(EDX, Immediate(arg_count));
|
2012-06-22 20:37:01 +00:00
|
|
|
compiler->GenerateCall(token_pos(),
|
2012-05-31 17:24:23 +00:00
|
|
|
try_index(),
|
|
|
|
&StubCode::CallNativeCFunctionLabel(),
|
2012-08-14 06:59:24 +00:00
|
|
|
PcDescriptors::kOther,
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
2012-05-31 17:24:23 +00:00
|
|
|
__ popl(result);
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-08 19:36:26 +00:00
|
|
|
LocationSummary* LoadIndexedComp::MakeLocationSummary() const {
|
2012-08-15 13:54:38 +00:00
|
|
|
ASSERT((receiver_type() == kGrowableObjectArrayCid) ||
|
|
|
|
(receiver_type() == kArrayCid) ||
|
|
|
|
(receiver_type() == kImmutableArrayCid));
|
2012-06-12 16:27:18 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
2012-08-15 13:54:38 +00:00
|
|
|
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;
|
2012-06-20 23:19:02 +00:00
|
|
|
}
|
|
|
|
|
2012-06-12 16:27:18 +00:00
|
|
|
|
2012-06-08 19:36:26 +00:00
|
|
|
void LoadIndexedComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-06-12 16:27:18 +00:00
|
|
|
Register receiver = locs()->in(0).reg();
|
|
|
|
Register index = locs()->in(1).reg();
|
|
|
|
Register result = locs()->out().reg();
|
|
|
|
Register temp = locs()->temp(0).reg();
|
2012-06-08 19:36:26 +00:00
|
|
|
|
2012-08-08 19:46:23 +00:00
|
|
|
const DeoptReasonId deopt_reason =
|
|
|
|
(receiver_type() == kGrowableObjectArrayCid) ?
|
2012-06-12 16:27:18 +00:00
|
|
|
kDeoptLoadIndexedGrowableArray : kDeoptLoadIndexedFixedArray;
|
|
|
|
|
2012-08-15 13:54:38 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(original()->deopt_id(),
|
|
|
|
original()->try_index(),
|
2012-08-21 13:58:57 +00:00
|
|
|
deopt_reason);
|
2012-06-12 16:27:18 +00:00
|
|
|
|
|
|
|
__ testl(receiver, Immediate(kSmiTagMask)); // Deoptimize if Smi.
|
|
|
|
__ j(ZERO, deopt);
|
2012-06-22 01:24:36 +00:00
|
|
|
__ CompareClassId(receiver, receiver_type(), temp);
|
2012-06-12 16:27:18 +00:00
|
|
|
__ j(NOT_EQUAL, deopt);
|
|
|
|
|
|
|
|
__ testl(index, Immediate(kSmiTagMask));
|
|
|
|
__ j(NOT_ZERO, deopt);
|
|
|
|
|
|
|
|
switch (receiver_type()) {
|
2012-08-08 19:46:23 +00:00
|
|
|
case kArrayCid:
|
|
|
|
case kImmutableArrayCid:
|
2012-06-12 16:27:18 +00:00
|
|
|
__ cmpl(index, FieldAddress(receiver, Array::length_offset()));
|
|
|
|
__ j(ABOVE_EQUAL, deopt);
|
|
|
|
// Note that index is Smi, i.e, times 2.
|
|
|
|
ASSERT(kSmiTagShift == 1);
|
|
|
|
__ movl(result, FieldAddress(receiver, index, TIMES_2, sizeof(RawArray)));
|
|
|
|
break;
|
|
|
|
|
2012-08-08 19:46:23 +00:00
|
|
|
case kGrowableObjectArrayCid: {
|
2012-06-12 16:27:18 +00:00
|
|
|
Register temp = locs()->temp(0).reg();
|
|
|
|
|
|
|
|
__ cmpl(index,
|
|
|
|
FieldAddress(receiver, GrowableObjectArray::length_offset()));
|
|
|
|
__ j(ABOVE_EQUAL, deopt);
|
|
|
|
__ movl(temp, FieldAddress(receiver, GrowableObjectArray::data_offset()));
|
|
|
|
// Note that index is Smi, i.e, times 2.
|
|
|
|
ASSERT(kSmiTagShift == 1);
|
|
|
|
__ movl(result, FieldAddress(temp, index, TIMES_2, sizeof(RawArray)));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
break;
|
|
|
|
}
|
2012-06-08 19:36:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-30 16:57:19 +00:00
|
|
|
LocationSummary* StoreIndexedComp::MakeLocationSummary() const {
|
2012-08-15 13:54:38 +00:00
|
|
|
ASSERT((receiver_type() == kGrowableObjectArrayCid) ||
|
|
|
|
(receiver_type() == kArrayCid));
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
const intptr_t kNumInputs = 3;
|
2012-08-15 13:54:38 +00:00
|
|
|
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_in(2, Location::RequiresRegister());
|
|
|
|
locs->set_temp(0, Location::RequiresRegister());
|
|
|
|
locs->set_out(Location::NoLocation());
|
|
|
|
return locs;
|
2012-06-20 23:19:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-13 08:53:54 +00:00
|
|
|
void StoreIndexedComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
Register receiver = locs()->in(0).reg();
|
|
|
|
Register index = locs()->in(1).reg();
|
|
|
|
Register value = locs()->in(2).reg();
|
|
|
|
Register temp = locs()->temp(0).reg();
|
|
|
|
|
2012-08-15 13:54:38 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(original()->deopt_id(),
|
|
|
|
original()->try_index(),
|
2012-08-21 13:58:57 +00:00
|
|
|
kDeoptStoreIndexed);
|
2012-06-13 08:53:54 +00:00
|
|
|
|
|
|
|
__ testl(receiver, Immediate(kSmiTagMask)); // Deoptimize if Smi.
|
|
|
|
__ j(ZERO, deopt);
|
|
|
|
__ CompareClassId(receiver, receiver_type(), temp);
|
|
|
|
__ j(NOT_EQUAL, deopt);
|
|
|
|
|
|
|
|
__ testl(index, Immediate(kSmiTagMask));
|
|
|
|
__ j(NOT_ZERO, deopt);
|
|
|
|
|
|
|
|
switch (receiver_type()) {
|
2012-08-08 19:46:23 +00:00
|
|
|
case kArrayCid:
|
|
|
|
case kImmutableArrayCid:
|
2012-06-13 08:53:54 +00:00
|
|
|
__ cmpl(index, FieldAddress(receiver, Array::length_offset()));
|
|
|
|
__ j(ABOVE_EQUAL, deopt);
|
|
|
|
// Note that index is Smi, i.e, times 2.
|
|
|
|
ASSERT(kSmiTagShift == 1);
|
2012-08-24 23:06:12 +00:00
|
|
|
if (this->value()->BindsToConstant()) {
|
|
|
|
// Compile time constants are Smi or allocated in the old space.
|
|
|
|
__ movl(FieldAddress(receiver, index, TIMES_2, sizeof(RawArray)),
|
|
|
|
value);
|
|
|
|
} else {
|
|
|
|
__ StoreIntoObject(receiver,
|
|
|
|
FieldAddress(receiver, index, TIMES_2, sizeof(RawArray)),
|
|
|
|
value);
|
|
|
|
}
|
2012-06-13 08:53:54 +00:00
|
|
|
break;
|
|
|
|
|
2012-08-08 19:46:23 +00:00
|
|
|
case kGrowableObjectArrayCid: {
|
2012-06-13 08:53:54 +00:00
|
|
|
__ cmpl(index,
|
|
|
|
FieldAddress(receiver, GrowableObjectArray::length_offset()));
|
|
|
|
__ j(ABOVE_EQUAL, deopt);
|
|
|
|
__ movl(temp, FieldAddress(receiver, GrowableObjectArray::data_offset()));
|
|
|
|
// Note that index is Smi, i.e, times 2.
|
|
|
|
ASSERT(kSmiTagShift == 1);
|
2012-08-24 23:06:12 +00:00
|
|
|
if (this->value()->BindsToConstant()) {
|
|
|
|
// Compile time constants are Smi or allocated in the old space.
|
|
|
|
__ movl(FieldAddress(temp, index, TIMES_2, sizeof(RawArray)),
|
|
|
|
value);
|
|
|
|
} else {
|
|
|
|
__ StoreIntoObject(temp,
|
|
|
|
FieldAddress(temp, index, TIMES_2, sizeof(RawArray)),
|
|
|
|
value);
|
|
|
|
}
|
2012-06-13 08:53:54 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-30 16:57:19 +00:00
|
|
|
LocationSummary* LoadInstanceFieldComp::MakeLocationSummary() const {
|
2012-06-07 18:06:15 +00:00
|
|
|
// TODO(fschneider): For this instruction the input register may be
|
|
|
|
// reused for the result (but is not required to) because the input
|
|
|
|
// is not used after the result is defined. We should consider adding
|
|
|
|
// this information to the input policy.
|
2012-07-31 11:51:47 +00:00
|
|
|
return LocationSummary::Make(1,
|
|
|
|
Location::RequiresRegister(),
|
|
|
|
LocationSummary::kNoCall);
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-31 17:24:23 +00:00
|
|
|
void LoadInstanceFieldComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-06-19 21:49:11 +00:00
|
|
|
Register instance_reg = locs()->in(0).reg();
|
|
|
|
Register result_reg = locs()->out().reg();
|
2012-06-07 18:06:15 +00:00
|
|
|
|
2012-06-19 21:49:11 +00:00
|
|
|
if (HasICData()) {
|
2012-06-07 19:49:50 +00:00
|
|
|
ASSERT(original() != NULL);
|
2012-08-06 20:24:03 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(original()->deopt_id(),
|
2012-06-07 19:49:50 +00:00
|
|
|
original()->try_index(),
|
2012-08-21 13:58:57 +00:00
|
|
|
kDeoptInstanceGetterSameTarget);
|
2012-06-07 19:49:50 +00:00
|
|
|
// Smis do not have instance fields (Smi class is always first).
|
|
|
|
// Use 'result' as temporary register.
|
2012-06-19 21:49:11 +00:00
|
|
|
ASSERT(result_reg != instance_reg);
|
|
|
|
ASSERT(ic_data() != NULL);
|
|
|
|
compiler->EmitClassChecksNoSmi(*ic_data(), instance_reg, result_reg, deopt);
|
2012-06-07 19:49:50 +00:00
|
|
|
}
|
2012-06-19 21:49:11 +00:00
|
|
|
__ movl(result_reg, FieldAddress(instance_reg, field().Offset()));
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-24 23:06:12 +00:00
|
|
|
LocationSummary* StoreInstanceFieldComp::MakeLocationSummary() const {
|
|
|
|
const intptr_t kNumInputs = 2;
|
|
|
|
const intptr_t num_temps = HasICData() ? 1 : 0;
|
|
|
|
LocationSummary* summary =
|
|
|
|
new LocationSummary(kNumInputs, num_temps, LocationSummary::kNoCall);
|
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
|
|
|
summary->set_in(1, Location::RequiresRegister());
|
|
|
|
if (HasICData()) {
|
|
|
|
summary->set_temp(0, Location::RequiresRegister());
|
|
|
|
}
|
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StoreInstanceFieldComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
Register instance_reg = locs()->in(0).reg();
|
|
|
|
Register value_reg = locs()->in(1).reg();
|
|
|
|
|
|
|
|
if (HasICData()) {
|
|
|
|
ASSERT(original() != NULL);
|
|
|
|
Label* deopt = compiler->AddDeoptStub(original()->deopt_id(),
|
|
|
|
original()->try_index(),
|
|
|
|
kDeoptInstanceGetterSameTarget);
|
|
|
|
// Smis do not have instance fields (Smi class is always first).
|
|
|
|
Register temp_reg = locs()->temp(0).reg();
|
|
|
|
ASSERT(temp_reg != instance_reg);
|
|
|
|
ASSERT(temp_reg != value_reg);
|
|
|
|
ASSERT(ic_data() != NULL);
|
|
|
|
compiler->EmitClassChecksNoSmi(*ic_data(), instance_reg, temp_reg, deopt);
|
|
|
|
}
|
|
|
|
if (this->value()->BindsToConstant()) {
|
|
|
|
// Compile time constants are Smi or allocated in the old space.
|
|
|
|
__ movl(FieldAddress(instance_reg, field().Offset()), value_reg);
|
|
|
|
} else {
|
|
|
|
__ StoreIntoObject(instance_reg,
|
|
|
|
FieldAddress(instance_reg, field().Offset()), value_reg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-30 16:57:19 +00:00
|
|
|
LocationSummary* LoadStaticFieldComp::MakeLocationSummary() const {
|
2012-07-31 11:51:47 +00:00
|
|
|
return LocationSummary::Make(0,
|
|
|
|
Location::RequiresRegister(),
|
|
|
|
LocationSummary::kNoCall);
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-31 17:24:23 +00:00
|
|
|
void LoadStaticFieldComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
Register result = locs()->out().reg();
|
|
|
|
__ LoadObject(result, field());
|
|
|
|
__ movl(result, FieldAddress(result, Field::value_offset()));
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-24 23:06:12 +00:00
|
|
|
LocationSummary* StoreStaticFieldComp::MakeLocationSummary() const {
|
|
|
|
LocationSummary* locs = new LocationSummary(1, 1, LocationSummary::kNoCall);
|
|
|
|
locs->set_in(0, Location::RequiresRegister());
|
|
|
|
locs->set_temp(0, Location::RequiresRegister());
|
|
|
|
locs->set_out(Location::SameAsFirstInput());
|
|
|
|
return locs;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StoreStaticFieldComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
Register value = locs()->in(0).reg();
|
|
|
|
Register temp = locs()->temp(0).reg();
|
|
|
|
ASSERT(locs()->out().reg() == value);
|
|
|
|
|
|
|
|
__ LoadObject(temp, field());
|
|
|
|
if (this->value()->BindsToConstant()) {
|
|
|
|
// Compile time constants are Smi or allocated in the old space.
|
|
|
|
__ movl(FieldAddress(temp, Field::value_offset()), value);
|
|
|
|
} else {
|
|
|
|
__ StoreIntoObject(temp, FieldAddress(temp, Field::value_offset()), value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-30 16:57:19 +00:00
|
|
|
LocationSummary* InstanceOfComp::MakeLocationSummary() const {
|
2012-06-25 23:50:37 +00:00
|
|
|
const intptr_t kNumInputs = 3;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2012-07-31 11:51:47 +00:00
|
|
|
LocationSummary* summary =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
|
2012-06-04 17:06:43 +00:00
|
|
|
summary->set_in(0, Location::RegisterLocation(EAX));
|
|
|
|
summary->set_in(1, Location::RegisterLocation(ECX));
|
|
|
|
summary->set_in(2, Location::RegisterLocation(EDX));
|
|
|
|
summary->set_out(Location::RegisterLocation(EAX));
|
|
|
|
return summary;
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-31 17:24:23 +00:00
|
|
|
void InstanceOfComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-06-04 17:06:43 +00:00
|
|
|
ASSERT(locs()->in(0).reg() == EAX); // Value.
|
|
|
|
ASSERT(locs()->in(1).reg() == ECX); // Instantiator.
|
|
|
|
ASSERT(locs()->in(2).reg() == EDX); // Instantiator type arguments.
|
|
|
|
|
2012-08-06 20:24:03 +00:00
|
|
|
compiler->GenerateInstanceOf(deopt_id(),
|
2012-06-22 20:37:01 +00:00
|
|
|
token_pos(),
|
2012-06-04 17:06:43 +00:00
|
|
|
try_index(),
|
|
|
|
type(),
|
2012-08-14 06:59:24 +00:00
|
|
|
negate_result(),
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
2012-06-04 17:06:43 +00:00
|
|
|
ASSERT(locs()->out().reg() == EAX);
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* CreateArrayComp::MakeLocationSummary() const {
|
2012-08-07 10:34:39 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
|
|
|
LocationSummary* locs =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
|
|
|
|
locs->set_in(0, Location::RegisterLocation(ECX));
|
|
|
|
locs->set_out(Location::RegisterLocation(EAX));
|
|
|
|
return locs;
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-31 17:24:23 +00:00
|
|
|
void CreateArrayComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-06-22 01:24:36 +00:00
|
|
|
// Allocate the array. EDX = length, ECX = element type.
|
2012-08-07 10:34:39 +00:00
|
|
|
ASSERT(locs()->in(0).reg() == ECX);
|
2012-08-17 11:46:28 +00:00
|
|
|
__ movl(EDX, Immediate(Smi::RawValue(ArgumentCount())));
|
2012-06-22 20:37:01 +00:00
|
|
|
compiler->GenerateCall(token_pos(),
|
2012-06-04 15:31:13 +00:00
|
|
|
try_index(),
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
&StubCode::AllocateArrayLabel(),
|
2012-08-14 06:59:24 +00:00
|
|
|
PcDescriptors::kOther,
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
2012-08-06 11:38:45 +00:00
|
|
|
ASSERT(locs()->out().reg() == EAX);
|
2012-06-22 01:24:36 +00:00
|
|
|
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
// Pop the element values from the stack into the array.
|
2012-08-06 11:38:45 +00:00
|
|
|
__ leal(EDX, FieldAddress(EAX, Array::data_offset()));
|
2012-08-17 11:46:28 +00:00
|
|
|
for (int i = ArgumentCount() - 1; i >= 0; --i) {
|
|
|
|
ASSERT(ArgumentAt(i)->value()->IsUse());
|
2012-08-06 11:38:45 +00:00
|
|
|
__ popl(Address(EDX, i * kWordSize));
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
}
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary*
|
2012-06-22 01:24:36 +00:00
|
|
|
AllocateObjectWithBoundsCheckComp::MakeLocationSummary() const {
|
2012-07-24 17:19:20 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2012-07-31 11:51:47 +00:00
|
|
|
LocationSummary* locs =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
|
2012-07-24 17:19:20 +00:00
|
|
|
locs->set_in(0, Location::RegisterLocation(EAX));
|
|
|
|
locs->set_in(1, Location::RegisterLocation(ECX));
|
|
|
|
locs->set_out(Location::RegisterLocation(EAX));
|
|
|
|
return locs;
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AllocateObjectWithBoundsCheckComp::EmitNativeCode(
|
2012-05-31 17:24:23 +00:00
|
|
|
FlowGraphCompiler* compiler) {
|
2012-08-14 00:38:01 +00:00
|
|
|
const Class& cls = Class::ZoneHandle(constructor().Owner());
|
2012-06-04 15:31:13 +00:00
|
|
|
Register type_arguments = locs()->in(0).reg();
|
|
|
|
Register instantiator_type_arguments = locs()->in(1).reg();
|
|
|
|
Register result = locs()->out().reg();
|
|
|
|
|
2012-06-22 01:24:36 +00:00
|
|
|
// Push the result place holder initialized to NULL.
|
2012-06-04 15:31:13 +00:00
|
|
|
__ PushObject(Object::ZoneHandle());
|
|
|
|
__ PushObject(cls);
|
|
|
|
__ pushl(type_arguments);
|
|
|
|
__ pushl(instantiator_type_arguments);
|
2012-08-06 20:24:03 +00:00
|
|
|
compiler->GenerateCallRuntime(deopt_id(),
|
2012-06-22 20:37:01 +00:00
|
|
|
token_pos(),
|
2012-06-04 15:31:13 +00:00
|
|
|
try_index(),
|
2012-08-14 06:59:24 +00:00
|
|
|
kAllocateObjectWithBoundsCheckRuntimeEntry,
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
2012-07-10 23:59:09 +00:00
|
|
|
// Pop instantiator type arguments, type arguments, and class.
|
2012-06-04 15:31:13 +00:00
|
|
|
// source location.
|
2012-07-10 23:59:09 +00:00
|
|
|
__ Drop(3);
|
2012-06-04 15:31:13 +00:00
|
|
|
__ popl(result); // Pop new instance.
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* LoadVMFieldComp::MakeLocationSummary() const {
|
2012-07-31 11:51:47 +00:00
|
|
|
return LocationSummary::Make(1,
|
|
|
|
Location::RequiresRegister(),
|
|
|
|
LocationSummary::kNoCall);
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-31 17:24:23 +00:00
|
|
|
void LoadVMFieldComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-06-19 21:49:11 +00:00
|
|
|
Register instance_reg = locs()->in(0).reg();
|
|
|
|
Register result_reg = locs()->out().reg();
|
|
|
|
if (HasICData()) {
|
2012-06-12 16:09:02 +00:00
|
|
|
ASSERT(original() != NULL);
|
2012-08-06 20:24:03 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(original()->deopt_id(),
|
2012-06-12 16:09:02 +00:00
|
|
|
original()->try_index(),
|
2012-08-21 13:58:57 +00:00
|
|
|
kDeoptInstanceGetterSameTarget);
|
2012-06-12 16:09:02 +00:00
|
|
|
// Smis do not have instance fields (Smi class is always first).
|
|
|
|
// Use 'result' as temporary register.
|
2012-06-19 21:49:11 +00:00
|
|
|
ASSERT(result_reg != instance_reg);
|
|
|
|
ASSERT(ic_data() != NULL);
|
|
|
|
compiler->EmitClassChecksNoSmi(*ic_data(), instance_reg, result_reg, deopt);
|
2012-06-12 16:09:02 +00:00
|
|
|
}
|
2012-06-04 15:31:13 +00:00
|
|
|
|
2012-06-19 21:49:11 +00:00
|
|
|
__ movl(result_reg, FieldAddress(instance_reg, offset_in_bytes()));
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* InstantiateTypeArgumentsComp::MakeLocationSummary() const {
|
2012-06-04 15:31:13 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 1;
|
2012-07-31 11:51:47 +00:00
|
|
|
LocationSummary* locs =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
|
2012-07-24 17:19:20 +00:00
|
|
|
locs->set_in(0, Location::RegisterLocation(EAX));
|
|
|
|
locs->set_temp(0, Location::RegisterLocation(ECX));
|
|
|
|
locs->set_out(Location::RegisterLocation(EAX));
|
2012-06-04 15:31:13 +00:00
|
|
|
return locs;
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void InstantiateTypeArgumentsComp::EmitNativeCode(
|
2012-05-31 17:24:23 +00:00
|
|
|
FlowGraphCompiler* compiler) {
|
2012-06-04 15:31:13 +00:00
|
|
|
Register instantiator_reg = locs()->in(0).reg();
|
|
|
|
Register temp = locs()->temp(0).reg();
|
|
|
|
Register result_reg = locs()->out().reg();
|
|
|
|
|
|
|
|
// 'instantiator_reg' is the instantiator AbstractTypeArguments object
|
|
|
|
// (or null).
|
|
|
|
// If the instantiator is null and if the type argument vector
|
|
|
|
// instantiated from null becomes a vector of Dynamic, then use null as
|
|
|
|
// the type arguments.
|
|
|
|
Label type_arguments_instantiated;
|
|
|
|
const intptr_t len = type_arguments().Length();
|
|
|
|
if (type_arguments().IsRawInstantiatedRaw(len)) {
|
|
|
|
const Immediate raw_null =
|
|
|
|
Immediate(reinterpret_cast<intptr_t>(Object::null()));
|
|
|
|
__ cmpl(instantiator_reg, raw_null);
|
|
|
|
__ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
|
|
|
|
}
|
|
|
|
// Instantiate non-null type arguments.
|
|
|
|
if (type_arguments().IsUninstantiatedIdentity()) {
|
|
|
|
// Check if the instantiator type argument vector is a TypeArguments of a
|
|
|
|
// matching length and, if so, use it as the instantiated type_arguments.
|
2012-06-22 01:24:36 +00:00
|
|
|
// No need to check the instantiator ('instantiator_reg') for null here,
|
|
|
|
// because a null instantiator will have the wrong class (Null instead of
|
|
|
|
// TypeArguments).
|
2012-06-04 15:31:13 +00:00
|
|
|
Label type_arguments_uninstantiated;
|
2012-08-08 19:46:23 +00:00
|
|
|
__ CompareClassId(instantiator_reg, kTypeArgumentsCid, temp);
|
2012-06-04 15:31:13 +00:00
|
|
|
__ j(NOT_EQUAL, &type_arguments_uninstantiated, Assembler::kNearJump);
|
|
|
|
__ cmpl(FieldAddress(instantiator_reg, TypeArguments::length_offset()),
|
|
|
|
Immediate(Smi::RawValue(len)));
|
|
|
|
__ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
|
|
|
|
__ Bind(&type_arguments_uninstantiated);
|
|
|
|
}
|
|
|
|
// A runtime call to instantiate the type arguments is required.
|
|
|
|
__ PushObject(Object::ZoneHandle()); // Make room for the result.
|
|
|
|
__ PushObject(type_arguments());
|
|
|
|
__ pushl(instantiator_reg); // Push instantiator type arguments.
|
2012-08-06 20:24:03 +00:00
|
|
|
compiler->GenerateCallRuntime(deopt_id(),
|
2012-06-22 20:37:01 +00:00
|
|
|
token_pos(),
|
2012-06-04 15:31:13 +00:00
|
|
|
try_index(),
|
2012-08-14 06:59:24 +00:00
|
|
|
kInstantiateTypeArgumentsRuntimeEntry,
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
2012-06-04 15:31:13 +00:00
|
|
|
__ Drop(2); // Drop instantiator and uninstantiated type arguments.
|
|
|
|
__ popl(result_reg); // Pop instantiated type arguments.
|
|
|
|
__ Bind(&type_arguments_instantiated);
|
|
|
|
ASSERT(instantiator_reg == result_reg);
|
2012-06-22 01:24:36 +00:00
|
|
|
// 'result_reg': Instantiated type arguments.
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary*
|
2012-06-22 01:24:36 +00:00
|
|
|
ExtractConstructorTypeArgumentsComp::MakeLocationSummary() const {
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 1;
|
2012-07-31 11:51:47 +00:00
|
|
|
LocationSummary* locs =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
locs->set_in(0, Location::RequiresRegister());
|
|
|
|
locs->set_out(Location::SameAsFirstInput());
|
|
|
|
locs->set_temp(0, Location::RequiresRegister());
|
|
|
|
return locs;
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ExtractConstructorTypeArgumentsComp::EmitNativeCode(
|
2012-05-31 17:24:23 +00:00
|
|
|
FlowGraphCompiler* compiler) {
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
Register instantiator_reg = locs()->in(0).reg();
|
|
|
|
Register result_reg = locs()->out().reg();
|
|
|
|
ASSERT(instantiator_reg == result_reg);
|
|
|
|
Register temp_reg = locs()->temp(0).reg();
|
|
|
|
|
|
|
|
// instantiator_reg is the instantiator type argument vector, i.e. an
|
|
|
|
// AbstractTypeArguments object (or null).
|
|
|
|
// If the instantiator is null and if the type argument vector
|
|
|
|
// instantiated from null becomes a vector of Dynamic, then use null as
|
|
|
|
// the type arguments.
|
|
|
|
Label type_arguments_instantiated;
|
|
|
|
const intptr_t len = type_arguments().Length();
|
|
|
|
if (type_arguments().IsRawInstantiatedRaw(len)) {
|
|
|
|
const Immediate raw_null =
|
|
|
|
Immediate(reinterpret_cast<intptr_t>(Object::null()));
|
|
|
|
__ cmpl(instantiator_reg, raw_null);
|
|
|
|
__ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
|
|
|
|
}
|
|
|
|
// Instantiate non-null type arguments.
|
|
|
|
if (type_arguments().IsUninstantiatedIdentity()) {
|
|
|
|
// Check if the instantiator type argument vector is a TypeArguments of a
|
|
|
|
// matching length and, if so, use it as the instantiated type_arguments.
|
|
|
|
// No need to check instantiator_reg for null here, because a null
|
|
|
|
// instantiator will have the wrong class (Null instead of TypeArguments).
|
|
|
|
Label type_arguments_uninstantiated;
|
2012-08-08 19:46:23 +00:00
|
|
|
__ CompareClassId(instantiator_reg, kTypeArgumentsCid, temp_reg);
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
__ j(NOT_EQUAL, &type_arguments_uninstantiated, Assembler::kNearJump);
|
|
|
|
Immediate arguments_length =
|
|
|
|
Immediate(Smi::RawValue(type_arguments().Length()));
|
|
|
|
__ cmpl(FieldAddress(instantiator_reg, TypeArguments::length_offset()),
|
|
|
|
arguments_length);
|
|
|
|
__ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
|
|
|
|
__ Bind(&type_arguments_uninstantiated);
|
|
|
|
}
|
|
|
|
// In the non-factory case, we rely on the allocation stub to
|
|
|
|
// instantiate the type arguments.
|
|
|
|
__ LoadObject(result_reg, type_arguments());
|
|
|
|
// result_reg: uninstantiated type arguments.
|
|
|
|
__ Bind(&type_arguments_instantiated);
|
|
|
|
// result_reg: uninstantiated or instantiated type arguments.
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary*
|
2012-06-22 01:24:36 +00:00
|
|
|
ExtractConstructorInstantiatorComp::MakeLocationSummary() const {
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 1;
|
2012-07-31 11:51:47 +00:00
|
|
|
LocationSummary* locs =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
locs->set_in(0, Location::RequiresRegister());
|
|
|
|
locs->set_out(Location::SameAsFirstInput());
|
|
|
|
locs->set_temp(0, Location::RequiresRegister());
|
|
|
|
return locs;
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ExtractConstructorInstantiatorComp::EmitNativeCode(
|
2012-05-31 17:24:23 +00:00
|
|
|
FlowGraphCompiler* compiler) {
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
ASSERT(instantiator()->IsUse());
|
|
|
|
Register instantiator_reg = locs()->in(0).reg();
|
|
|
|
ASSERT(locs()->out().reg() == instantiator_reg);
|
|
|
|
Register temp_reg = locs()->temp(0).reg();
|
|
|
|
|
|
|
|
// instantiator_reg is the instantiator AbstractTypeArguments object
|
|
|
|
// (or null). If the instantiator is null and if the type argument vector
|
|
|
|
// instantiated from null becomes a vector of Dynamic, then use null as
|
|
|
|
// the type arguments and do not pass the instantiator.
|
|
|
|
Label done;
|
|
|
|
const intptr_t len = type_arguments().Length();
|
|
|
|
if (type_arguments().IsRawInstantiatedRaw(len)) {
|
|
|
|
const Immediate raw_null =
|
|
|
|
Immediate(reinterpret_cast<intptr_t>(Object::null()));
|
|
|
|
Label instantiator_not_null;
|
|
|
|
__ cmpl(instantiator_reg, raw_null);
|
|
|
|
__ j(NOT_EQUAL, &instantiator_not_null, Assembler::kNearJump);
|
|
|
|
// Null was used in VisitExtractConstructorTypeArguments as the
|
|
|
|
// instantiated type arguments, no proper instantiator needed.
|
|
|
|
__ movl(instantiator_reg,
|
|
|
|
Immediate(Smi::RawValue(StubCode::kNoInstantiator)));
|
|
|
|
__ jmp(&done);
|
|
|
|
__ Bind(&instantiator_not_null);
|
|
|
|
}
|
|
|
|
// Instantiate non-null type arguments.
|
|
|
|
if (type_arguments().IsUninstantiatedIdentity()) {
|
|
|
|
// TODO(regis): The following emitted code is duplicated in
|
|
|
|
// VisitExtractConstructorTypeArguments above. The reason is that the code
|
|
|
|
// is split between two computations, so that each one produces a
|
|
|
|
// single value, rather than producing a pair of values.
|
|
|
|
// If this becomes an issue, we should expose these tests at the IL level.
|
|
|
|
|
|
|
|
// Check if the instantiator type argument vector is a TypeArguments of a
|
|
|
|
// matching length and, if so, use it as the instantiated type_arguments.
|
|
|
|
// No need to check the instantiator (RAX) for null here, because a null
|
|
|
|
// instantiator will have the wrong class (Null instead of TypeArguments).
|
2012-08-08 19:46:23 +00:00
|
|
|
__ CompareClassId(instantiator_reg, kTypeArgumentsCid, temp_reg);
|
More code for ia32, more shared code.
CreateArrayComp, EqualityCompareComp, StoreStaticField, LoadStaticField, StoreIndexedComp, StoreInstanceFieldComp, Throw, Rethrow, AssertBooleanComp.
Made more code shared, which has the disadvantage od splitting MakeLocationSummary from EmitNativeCode. Discuss.
Review URL: https://chromiumcodereview.appspot.com//10543013
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8343 260f80e4-7a28-3924-810f-c04153c831b5
2012-06-06 15:42:07 +00:00
|
|
|
__ j(NOT_EQUAL, &done, Assembler::kNearJump);
|
|
|
|
Immediate arguments_length =
|
|
|
|
Immediate(Smi::RawValue(type_arguments().Length()));
|
|
|
|
__ cmpl(FieldAddress(instantiator_reg, TypeArguments::length_offset()),
|
|
|
|
arguments_length);
|
|
|
|
__ j(NOT_EQUAL, &done, Assembler::kNearJump);
|
|
|
|
// The instantiator was used in VisitExtractConstructorTypeArguments as the
|
|
|
|
// instantiated type arguments, no proper instantiator needed.
|
|
|
|
__ movl(instantiator_reg,
|
|
|
|
Immediate(Smi::RawValue(StubCode::kNoInstantiator)));
|
|
|
|
}
|
|
|
|
__ Bind(&done);
|
|
|
|
// instantiator_reg: instantiator or kNoInstantiator.
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* AllocateContextComp::MakeLocationSummary() const {
|
2012-06-04 15:54:56 +00:00
|
|
|
const intptr_t kNumInputs = 0;
|
|
|
|
const intptr_t kNumTemps = 1;
|
2012-07-31 11:51:47 +00:00
|
|
|
LocationSummary* locs =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
|
2012-06-04 15:54:56 +00:00
|
|
|
locs->set_temp(0, Location::RegisterLocation(EDX));
|
|
|
|
locs->set_out(Location::RegisterLocation(EAX));
|
|
|
|
return locs;
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-31 17:24:23 +00:00
|
|
|
void AllocateContextComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-06-04 15:54:56 +00:00
|
|
|
ASSERT(locs()->temp(0).reg() == EDX);
|
|
|
|
ASSERT(locs()->out().reg() == EAX);
|
|
|
|
|
|
|
|
__ movl(EDX, Immediate(num_context_variables()));
|
|
|
|
const ExternalLabel label("alloc_context",
|
|
|
|
StubCode::AllocateContextEntryPoint());
|
2012-06-22 20:37:01 +00:00
|
|
|
compiler->GenerateCall(token_pos(),
|
2012-06-04 15:54:56 +00:00
|
|
|
try_index(),
|
|
|
|
&label,
|
2012-08-14 06:59:24 +00:00
|
|
|
PcDescriptors::kOther,
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* CloneContextComp::MakeLocationSummary() const {
|
2012-07-24 16:01:54 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2012-07-31 11:51:47 +00:00
|
|
|
LocationSummary* locs =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
|
2012-07-24 16:01:54 +00:00
|
|
|
locs->set_in(0, Location::RegisterLocation(EAX));
|
|
|
|
locs->set_out(Location::RegisterLocation(EAX));
|
|
|
|
return locs;
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-31 17:24:23 +00:00
|
|
|
void CloneContextComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-06-04 15:54:56 +00:00
|
|
|
Register context_value = locs()->in(0).reg();
|
|
|
|
Register result = locs()->out().reg();
|
|
|
|
|
|
|
|
__ PushObject(Object::ZoneHandle()); // Make room for the result.
|
|
|
|
__ pushl(context_value);
|
2012-08-06 20:24:03 +00:00
|
|
|
compiler->GenerateCallRuntime(deopt_id(),
|
2012-06-22 20:37:01 +00:00
|
|
|
token_pos(),
|
2012-06-04 15:54:56 +00:00
|
|
|
try_index(),
|
2012-08-14 06:59:24 +00:00
|
|
|
kCloneContextRuntimeEntry,
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
2012-06-04 15:54:56 +00:00
|
|
|
__ popl(result); // Remove argument.
|
|
|
|
__ popl(result); // Get result (cloned context).
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* CatchEntryComp::MakeLocationSummary() const {
|
2012-07-31 11:51:47 +00:00
|
|
|
return LocationSummary::Make(0,
|
|
|
|
Location::NoLocation(),
|
|
|
|
LocationSummary::kNoCall);
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-07 18:06:15 +00:00
|
|
|
// Restore stack and initialize the two exception variables:
|
|
|
|
// exception and stack trace variables.
|
2012-05-31 17:24:23 +00:00
|
|
|
void CatchEntryComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-06-07 18:06:15 +00:00
|
|
|
// Restore RSP from RBP as we are coming from a throw and the code for
|
|
|
|
// popping arguments has not been run.
|
|
|
|
const intptr_t locals_space_size = compiler->StackSize() * kWordSize;
|
|
|
|
ASSERT(locals_space_size >= 0);
|
|
|
|
const intptr_t offset_size =
|
|
|
|
-locals_space_size + FlowGraphCompiler::kLocalsOffsetFromFP;
|
|
|
|
__ leal(ESP, Address(EBP, offset_size));
|
|
|
|
|
|
|
|
ASSERT(!exception_var().is_captured());
|
|
|
|
ASSERT(!stacktrace_var().is_captured());
|
|
|
|
__ movl(Address(EBP, exception_var().index() * kWordSize),
|
|
|
|
kExceptionObjectReg);
|
|
|
|
__ movl(Address(EBP, stacktrace_var().index() * kWordSize),
|
|
|
|
kStackTraceObjectReg);
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-11 17:02:39 +00:00
|
|
|
LocationSummary* CheckStackOverflowComp::MakeLocationSummary() const {
|
2012-07-25 00:25:00 +00:00
|
|
|
const intptr_t kNumInputs = 0;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2012-07-31 11:51:47 +00:00
|
|
|
LocationSummary* summary =
|
2012-08-14 12:47:42 +00:00
|
|
|
new LocationSummary(kNumInputs,
|
|
|
|
kNumTemps,
|
|
|
|
LocationSummary::kCallOnSlowPath);
|
2012-07-25 00:25:00 +00:00
|
|
|
return summary;
|
2012-06-11 17:02:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-14 12:47:42 +00:00
|
|
|
class CheckStackOverflowSlowPath : public SlowPathCode {
|
|
|
|
public:
|
|
|
|
explicit CheckStackOverflowSlowPath(CheckStackOverflowComp* computation)
|
|
|
|
: computation_(computation) { }
|
|
|
|
|
|
|
|
virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
__ Bind(entry_label());
|
|
|
|
compiler->SaveLiveRegisters(computation_->locs());
|
|
|
|
compiler->GenerateCallRuntime(computation_->deopt_id(),
|
|
|
|
computation_->token_pos(),
|
|
|
|
computation_->try_index(),
|
|
|
|
kStackOverflowRuntimeEntry,
|
2012-08-23 10:08:37 +00:00
|
|
|
computation_->locs());
|
2012-08-14 12:47:42 +00:00
|
|
|
compiler->RestoreLiveRegisters(computation_->locs());
|
|
|
|
__ jmp(exit_label());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
CheckStackOverflowComp* computation_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2012-06-11 17:02:39 +00:00
|
|
|
void CheckStackOverflowComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-08-14 12:47:42 +00:00
|
|
|
CheckStackOverflowSlowPath* slow_path = new CheckStackOverflowSlowPath(this);
|
|
|
|
compiler->AddSlowPathCode(slow_path);
|
|
|
|
|
2012-06-11 17:02:39 +00:00
|
|
|
__ cmpl(ESP,
|
|
|
|
Address::Absolute(Isolate::Current()->stack_limit_address()));
|
2012-08-14 12:47:42 +00:00
|
|
|
__ j(BELOW_EQUAL, slow_path->entry_label());
|
|
|
|
__ Bind(slow_path->exit_label());
|
2012-06-11 17:02:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-22 11:17:57 +00:00
|
|
|
LocationSummary* BinarySmiOpComp::MakeLocationSummary() const {
|
2012-05-31 17:24:23 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
2012-06-08 16:59:49 +00:00
|
|
|
if (op_kind() == Token::kTRUNCDIV) {
|
|
|
|
const intptr_t kNumTemps = 3;
|
2012-07-31 11:51:47 +00:00
|
|
|
LocationSummary* summary =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2012-06-08 16:59:49 +00:00
|
|
|
summary->set_in(0, Location::RegisterLocation(EAX));
|
|
|
|
summary->set_in(1, Location::RegisterLocation(ECX));
|
|
|
|
summary->set_out(Location::SameAsFirstInput());
|
|
|
|
summary->set_temp(0, Location::RegisterLocation(EBX));
|
|
|
|
// Will be used for for sign extension.
|
|
|
|
summary->set_temp(1, Location::RegisterLocation(EDX));
|
|
|
|
summary->set_temp(2, Location::RequiresRegister());
|
|
|
|
return summary;
|
|
|
|
} else if (op_kind() == Token::kSHR) {
|
2012-08-23 08:24:29 +00:00
|
|
|
const intptr_t kNumTemps = 0;
|
2012-07-31 11:51:47 +00:00
|
|
|
LocationSummary* summary =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2012-06-08 16:59:49 +00:00
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
|
|
|
summary->set_in(1, Location::RegisterLocation(ECX));
|
|
|
|
summary->set_out(Location::SameAsFirstInput());
|
|
|
|
return summary;
|
|
|
|
} else if (op_kind() == Token::kSHL) {
|
2012-06-21 23:02:30 +00:00
|
|
|
// Two Smi operands can easily overflow into Mint.
|
2012-06-08 16:59:49 +00:00
|
|
|
const intptr_t kNumTemps = 2;
|
2012-06-21 23:02:30 +00:00
|
|
|
LocationSummary* summary =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
|
|
|
|
summary->set_in(0, Location::RegisterLocation(EAX));
|
2012-07-24 17:19:20 +00:00
|
|
|
summary->set_in(1, Location::RegisterLocation(EDX));
|
|
|
|
summary->set_temp(0, Location::RegisterLocation(EBX));
|
2012-06-08 16:59:49 +00:00
|
|
|
summary->set_temp(1, Location::RegisterLocation(ECX));
|
2012-07-24 17:19:20 +00:00
|
|
|
summary->set_out(Location::RegisterLocation(EAX));
|
2012-06-08 16:59:49 +00:00
|
|
|
return summary;
|
|
|
|
} else {
|
2012-08-23 08:24:29 +00:00
|
|
|
const intptr_t kNumTemps = 0;
|
2012-07-31 11:51:47 +00:00
|
|
|
LocationSummary* summary =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2012-06-08 16:59:49 +00:00
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
|
|
|
summary->set_in(1, Location::RequiresRegister());
|
|
|
|
summary->set_out(Location::SameAsFirstInput());
|
|
|
|
return summary;
|
|
|
|
}
|
2012-05-31 17:24:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-22 11:17:57 +00:00
|
|
|
void BinarySmiOpComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
Register left = locs()->in(0).reg();
|
|
|
|
Register right = locs()->in(1).reg();
|
|
|
|
Register result = locs()->out().reg();
|
2012-06-08 16:59:49 +00:00
|
|
|
ASSERT(left == result);
|
2012-08-23 08:24:29 +00:00
|
|
|
Label* deopt = NULL;
|
2012-08-22 11:17:57 +00:00
|
|
|
switch (op_kind()) {
|
2012-08-11 00:09:12 +00:00
|
|
|
case Token::kBIT_AND:
|
|
|
|
case Token::kBIT_OR:
|
|
|
|
case Token::kBIT_XOR:
|
2012-08-23 08:24:29 +00:00
|
|
|
// Can't deoptimize. Arguments are already checked for smi.
|
2012-08-11 00:09:12 +00:00
|
|
|
break;
|
|
|
|
default:
|
2012-08-23 08:24:29 +00:00
|
|
|
deopt = compiler->AddDeoptStub(instance_call()->deopt_id(),
|
|
|
|
instance_call()->try_index(),
|
|
|
|
kDeoptBinarySmiOp);
|
2012-08-11 00:09:12 +00:00
|
|
|
}
|
2012-08-23 08:24:29 +00:00
|
|
|
|
2012-08-22 11:17:57 +00:00
|
|
|
switch (op_kind()) {
|
2012-06-08 16:59:49 +00:00
|
|
|
case Token::kADD: {
|
|
|
|
__ addl(left, right);
|
|
|
|
__ j(OVERFLOW, deopt);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token::kSUB: {
|
|
|
|
__ subl(left, right);
|
|
|
|
__ j(OVERFLOW, deopt);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token::kMUL: {
|
|
|
|
__ SmiUntag(left);
|
|
|
|
__ imull(left, right);
|
|
|
|
__ j(OVERFLOW, deopt);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token::kBIT_AND: {
|
|
|
|
// No overflow check.
|
|
|
|
__ andl(left, right);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token::kBIT_OR: {
|
|
|
|
// No overflow check.
|
|
|
|
__ orl(left, right);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token::kBIT_XOR: {
|
|
|
|
// No overflow check.
|
|
|
|
__ xorl(left, right);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token::kTRUNCDIV: {
|
2012-08-23 08:24:29 +00:00
|
|
|
Register temp = locs()->temp(0).reg();
|
2012-06-08 16:59:49 +00:00
|
|
|
// Handle divide by zero in runtime.
|
|
|
|
// Deoptimization requires that temp and right are preserved.
|
|
|
|
__ testl(right, right);
|
|
|
|
__ j(ZERO, deopt);
|
|
|
|
ASSERT(left == EAX);
|
|
|
|
ASSERT((right != EDX) && (right != EAX));
|
|
|
|
ASSERT((temp != EDX) && (temp != EAX));
|
2012-08-22 11:17:57 +00:00
|
|
|
ASSERT(locs()->temp(1).reg() == EDX);
|
2012-06-08 16:59:49 +00:00
|
|
|
ASSERT(result == EAX);
|
2012-08-22 11:17:57 +00:00
|
|
|
Register right_temp = locs()->temp(2).reg();
|
2012-06-08 16:59:49 +00:00
|
|
|
__ movl(right_temp, right);
|
|
|
|
__ SmiUntag(left);
|
|
|
|
__ SmiUntag(right_temp);
|
|
|
|
__ cdq(); // Sign extend EAX -> EDX:EAX.
|
|
|
|
__ idivl(right_temp); // EAX: quotient, EDX: remainder.
|
|
|
|
// Check the corner case of dividing the 'MIN_SMI' with -1, in which
|
|
|
|
// case we cannot tag the result.
|
|
|
|
__ cmpl(result, Immediate(0x40000000));
|
|
|
|
__ j(EQUAL, deopt);
|
|
|
|
__ SmiTag(result);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token::kSHR: {
|
|
|
|
// sarl operation masks the count to 5 bits.
|
|
|
|
const Immediate kCountLimit = Immediate(0x1F);
|
|
|
|
__ cmpl(right, Immediate(0));
|
|
|
|
__ j(LESS, deopt);
|
|
|
|
__ SmiUntag(right);
|
|
|
|
__ cmpl(right, kCountLimit);
|
|
|
|
Label count_ok;
|
|
|
|
__ j(LESS, &count_ok, Assembler::kNearJump);
|
|
|
|
__ movl(right, kCountLimit);
|
|
|
|
__ Bind(&count_ok);
|
|
|
|
ASSERT(right == ECX); // Count must be in ECX
|
|
|
|
__ SmiUntag(left);
|
|
|
|
__ sarl(left, right);
|
|
|
|
__ SmiTag(left);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token::kSHL: {
|
2012-08-23 08:24:29 +00:00
|
|
|
Register temp = locs()->temp(0).reg();
|
2012-06-21 23:02:30 +00:00
|
|
|
Label call_method, done;
|
2012-06-08 16:59:49 +00:00
|
|
|
// Check if count too large for handling it inlined.
|
2012-08-21 16:22:21 +00:00
|
|
|
__ movl(temp, left);
|
2012-06-08 16:59:49 +00:00
|
|
|
__ cmpl(right,
|
|
|
|
Immediate(reinterpret_cast<int64_t>(Smi::New(Smi::kBits))));
|
2012-06-21 23:02:30 +00:00
|
|
|
__ j(ABOVE_EQUAL, &call_method, Assembler::kNearJump);
|
2012-08-22 11:17:57 +00:00
|
|
|
Register right_temp = locs()->temp(1).reg();
|
2012-06-08 16:59:49 +00:00
|
|
|
ASSERT(right_temp == ECX); // Count must be in ECX
|
|
|
|
__ movl(right_temp, right);
|
|
|
|
__ SmiUntag(right_temp);
|
|
|
|
// Overflow test (preserve temp and right);
|
|
|
|
__ shll(left, right_temp);
|
|
|
|
__ sarl(left, right_temp);
|
|
|
|
__ cmpl(left, temp);
|
2012-06-21 23:02:30 +00:00
|
|
|
__ j(NOT_EQUAL, &call_method, Assembler::kNearJump); // Overflow.
|
2012-06-08 16:59:49 +00:00
|
|
|
// Shift for result now we know there is no overflow.
|
|
|
|
__ shll(left, right_temp);
|
2012-06-21 23:02:30 +00:00
|
|
|
__ jmp(&done);
|
|
|
|
{
|
|
|
|
__ Bind(&call_method);
|
|
|
|
Function& target = Function::ZoneHandle(
|
2012-08-22 11:17:57 +00:00
|
|
|
ic_data()->GetTargetForReceiverClassId(kSmiCid));
|
2012-06-21 23:02:30 +00:00
|
|
|
ASSERT(!target.IsNull());
|
|
|
|
const intptr_t kArgumentCount = 2;
|
|
|
|
__ pushl(temp);
|
|
|
|
__ pushl(right);
|
2012-08-14 06:59:24 +00:00
|
|
|
compiler->GenerateStaticCall(
|
2012-08-22 11:17:57 +00:00
|
|
|
instance_call()->deopt_id(),
|
|
|
|
instance_call()->token_pos(),
|
|
|
|
instance_call()->try_index(),
|
2012-08-14 06:59:24 +00:00
|
|
|
target,
|
|
|
|
kArgumentCount,
|
|
|
|
Array::Handle(), // No argument names.
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
2012-06-21 23:02:30 +00:00
|
|
|
ASSERT(result == EAX);
|
|
|
|
}
|
|
|
|
__ Bind(&done);
|
2012-06-08 16:59:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token::kDIV: {
|
|
|
|
// Dispatches to 'Double./'.
|
|
|
|
// TODO(srdjan): Implement as conversion to double and double division.
|
|
|
|
UNREACHABLE();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token::kMOD: {
|
|
|
|
// TODO(srdjan): Implement.
|
|
|
|
UNREACHABLE();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token::kOR:
|
|
|
|
case Token::kAND: {
|
|
|
|
// Flow graph builder has dissected this operation to guarantee correct
|
|
|
|
// behavior (short-circuit evaluation).
|
|
|
|
UNREACHABLE();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-22 11:17:57 +00:00
|
|
|
LocationSummary* BinaryMintOpComp::MakeLocationSummary() const {
|
|
|
|
const intptr_t kNumInputs = 2;
|
|
|
|
ASSERT(op_kind() == Token::kBIT_AND);
|
|
|
|
const intptr_t kNumTemps = 1;
|
|
|
|
LocationSummary* summary =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
|
|
|
|
summary->set_in(0, Location::RegisterLocation(EAX));
|
|
|
|
summary->set_in(1, Location::RegisterLocation(ECX));
|
|
|
|
summary->set_temp(0, Location::RegisterLocation(EDX));
|
|
|
|
summary->set_out(Location::RegisterLocation(EAX));
|
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BinaryMintOpComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-06-18 21:55:52 +00:00
|
|
|
// TODO(regis): For now, we only support Token::kBIT_AND for a Mint or Smi
|
2012-06-21 19:37:15 +00:00
|
|
|
// receiver and a Mint or Smi argument. We fall back to the run time call if
|
|
|
|
// both receiver and argument are Mint or if one of them is Mint and the other
|
|
|
|
// is a negative Smi.
|
2012-08-22 11:17:57 +00:00
|
|
|
Register left = locs()->in(0).reg();
|
|
|
|
Register right = locs()->in(1).reg();
|
|
|
|
Register result = locs()->out().reg();
|
|
|
|
Register temp = locs()->temp(0).reg();
|
2012-06-18 21:55:52 +00:00
|
|
|
ASSERT(left == result);
|
2012-08-22 11:17:57 +00:00
|
|
|
ASSERT(op_kind() == Token::kBIT_AND);
|
|
|
|
Label* deopt = compiler->AddDeoptStub(instance_call()->deopt_id(),
|
|
|
|
instance_call()->try_index(),
|
|
|
|
kDeoptBinaryMintOp);
|
2012-06-21 19:37:15 +00:00
|
|
|
Label mint_static_call, smi_static_call, non_smi, smi_smi, done;
|
|
|
|
__ testl(left, Immediate(kSmiTagMask)); // Is receiver Smi?
|
|
|
|
__ j(NOT_ZERO, &non_smi);
|
|
|
|
__ testl(right, Immediate(kSmiTagMask)); // Is argument Smi?
|
|
|
|
__ j(ZERO, &smi_smi);
|
2012-08-08 19:46:23 +00:00
|
|
|
__ CompareClassId(right, kMintCid, temp); // Is argument Mint?
|
2012-06-21 19:37:15 +00:00
|
|
|
__ j(NOT_EQUAL, deopt); // Argument neither Smi nor Mint.
|
|
|
|
__ cmpl(left, Immediate(0));
|
|
|
|
__ j(LESS, &smi_static_call); // Negative Smi receiver, Mint argument.
|
|
|
|
|
|
|
|
// Positive Smi receiver, Mint argument.
|
|
|
|
// Load lower argument Mint word, convert to Smi. It is OK to loose bits.
|
|
|
|
__ movl(right, FieldAddress(right, Mint::value_offset()));
|
|
|
|
__ SmiTag(right);
|
|
|
|
__ andl(result, right);
|
|
|
|
__ jmp(&done);
|
2012-06-18 21:55:52 +00:00
|
|
|
|
2012-06-21 19:37:15 +00:00
|
|
|
__ Bind(&non_smi); // Receiver is non-Smi.
|
2012-08-08 19:46:23 +00:00
|
|
|
__ CompareClassId(left, kMintCid, temp); // Is receiver Mint?
|
2012-06-21 19:37:15 +00:00
|
|
|
__ j(NOT_EQUAL, deopt); // Receiver neither Smi nor Mint.
|
|
|
|
__ testl(right, Immediate(kSmiTagMask)); // Is argument Smi?
|
|
|
|
__ j(NOT_ZERO, &mint_static_call); // Mint receiver, non-Smi argument.
|
|
|
|
__ cmpl(right, Immediate(0));
|
|
|
|
__ j(LESS, &mint_static_call); // Mint receiver, negative Smi argument.
|
2012-06-18 21:55:52 +00:00
|
|
|
|
2012-06-21 19:37:15 +00:00
|
|
|
// Mint receiver, positive Smi argument.
|
|
|
|
// Load lower receiver Mint word, convert to Smi. It is OK to loose bits.
|
2012-06-18 21:55:52 +00:00
|
|
|
__ movl(result, FieldAddress(left, Mint::value_offset()));
|
|
|
|
__ SmiTag(result);
|
2012-06-21 19:37:15 +00:00
|
|
|
__ Bind(&smi_smi);
|
2012-06-18 21:55:52 +00:00
|
|
|
__ andl(result, right);
|
2012-06-21 19:37:15 +00:00
|
|
|
__ jmp(&done);
|
|
|
|
|
|
|
|
__ Bind(&smi_static_call);
|
|
|
|
{
|
|
|
|
Function& target = Function::ZoneHandle(
|
2012-08-22 11:17:57 +00:00
|
|
|
ic_data()->GetTargetForReceiverClassId(kSmiCid));
|
2012-06-21 19:37:15 +00:00
|
|
|
if (target.IsNull()) {
|
|
|
|
__ jmp(deopt);
|
|
|
|
} else {
|
|
|
|
__ pushl(left);
|
|
|
|
__ pushl(right);
|
2012-08-14 06:59:24 +00:00
|
|
|
compiler->GenerateStaticCall(
|
2012-08-22 11:17:57 +00:00
|
|
|
instance_call()->deopt_id(),
|
|
|
|
instance_call()->token_pos(),
|
|
|
|
instance_call()->try_index(),
|
2012-08-14 06:59:24 +00:00
|
|
|
target,
|
2012-08-22 11:17:57 +00:00
|
|
|
instance_call()->ArgumentCount(),
|
|
|
|
instance_call()->argument_names(),
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
2012-06-21 19:37:15 +00:00
|
|
|
ASSERT(result == EAX);
|
|
|
|
__ jmp(&done);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
__ Bind(&mint_static_call);
|
|
|
|
{
|
|
|
|
Function& target = Function::ZoneHandle(
|
2012-08-22 11:17:57 +00:00
|
|
|
ic_data()->GetTargetForReceiverClassId(kMintCid));
|
2012-06-21 19:37:15 +00:00
|
|
|
if (target.IsNull()) {
|
|
|
|
__ jmp(deopt);
|
|
|
|
} else {
|
|
|
|
__ pushl(left);
|
|
|
|
__ pushl(right);
|
2012-08-14 06:59:24 +00:00
|
|
|
compiler->GenerateStaticCall(
|
2012-08-22 11:17:57 +00:00
|
|
|
instance_call()->deopt_id(),
|
|
|
|
instance_call()->token_pos(),
|
|
|
|
instance_call()->try_index(),
|
2012-08-14 06:59:24 +00:00
|
|
|
target,
|
2012-08-22 11:17:57 +00:00
|
|
|
instance_call()->ArgumentCount(),
|
|
|
|
instance_call()->argument_names(),
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
2012-06-21 19:37:15 +00:00
|
|
|
ASSERT(result == EAX);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
__ Bind(&done);
|
2012-06-18 21:55:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-22 11:17:57 +00:00
|
|
|
LocationSummary* BinaryDoubleOpComp::MakeLocationSummary() const {
|
2012-08-02 16:26:46 +00:00
|
|
|
return MakeCallSummary(); // Calls into a stub for allocation.
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-22 11:17:57 +00:00
|
|
|
void BinaryDoubleOpComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-06-18 18:04:22 +00:00
|
|
|
Register left = EBX;
|
|
|
|
Register right = ECX;
|
|
|
|
Register temp = EDX;
|
2012-08-02 16:26:46 +00:00
|
|
|
Register result = locs()->out().reg();
|
2012-06-12 16:09:02 +00:00
|
|
|
|
2012-06-15 00:56:25 +00:00
|
|
|
const Class& double_class = compiler->double_class();
|
2012-06-12 16:09:02 +00:00
|
|
|
const Code& stub =
|
|
|
|
Code::Handle(StubCode::GetAllocationStubForClass(double_class));
|
|
|
|
const ExternalLabel label(double_class.ToCString(), stub.EntryPoint());
|
2012-08-02 16:26:46 +00:00
|
|
|
compiler->GenerateCall(instance_call()->token_pos(),
|
|
|
|
instance_call()->try_index(),
|
2012-06-12 16:09:02 +00:00
|
|
|
&label,
|
2012-08-14 06:59:24 +00:00
|
|
|
PcDescriptors::kOther,
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
2012-06-12 16:09:02 +00:00
|
|
|
// Newly allocated object is now in the result register (RAX).
|
|
|
|
ASSERT(result == EAX);
|
2012-08-10 14:28:02 +00:00
|
|
|
__ movl(right, Address(ESP, 0));
|
|
|
|
__ movl(left, Address(ESP, kWordSize));
|
2012-06-12 16:09:02 +00:00
|
|
|
|
2012-08-06 20:24:03 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(instance_call()->deopt_id(),
|
2012-08-02 16:26:46 +00:00
|
|
|
instance_call()->try_index(),
|
2012-08-22 11:17:57 +00:00
|
|
|
kDeoptBinaryDoubleOp);
|
2012-06-12 16:09:02 +00:00
|
|
|
|
2012-08-07 00:32:22 +00:00
|
|
|
// Binary operation of two Smi's produces a Smi not a double.
|
|
|
|
__ movl(temp, left);
|
|
|
|
__ orl(temp, right);
|
|
|
|
__ testl(temp, Immediate(kSmiTagMask));
|
|
|
|
__ j(ZERO, deopt);
|
|
|
|
|
2012-06-12 16:09:02 +00:00
|
|
|
compiler->LoadDoubleOrSmiToXmm(XMM0, left, temp, deopt);
|
|
|
|
compiler->LoadDoubleOrSmiToXmm(XMM1, right, temp, deopt);
|
|
|
|
|
2012-08-02 16:26:46 +00:00
|
|
|
switch (op_kind()) {
|
2012-06-12 16:09:02 +00:00
|
|
|
case Token::kADD: __ addsd(XMM0, XMM1); break;
|
|
|
|
case Token::kSUB: __ subsd(XMM0, XMM1); break;
|
|
|
|
case Token::kMUL: __ mulsd(XMM0, XMM1); break;
|
|
|
|
case Token::kDIV: __ divsd(XMM0, XMM1); break;
|
|
|
|
default: UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
__ movsd(FieldAddress(result, Double::value_offset()), XMM0);
|
2012-08-10 14:28:02 +00:00
|
|
|
|
|
|
|
__ Drop(2);
|
2012-06-08 16:59:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-24 14:45:42 +00:00
|
|
|
LocationSummary* CheckEitherNonSmiComp::MakeLocationSummary() const {
|
|
|
|
ASSERT((left()->ResultCid() != kDoubleCid) &&
|
|
|
|
(right()->ResultCid() != kDoubleCid));
|
|
|
|
const intptr_t kNumInputs = 2;
|
|
|
|
const intptr_t kNumTemps = 1;
|
|
|
|
LocationSummary* summary =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
|
|
|
summary->set_in(1, Location::RequiresRegister());
|
|
|
|
summary->set_temp(0, Location::RequiresRegister());
|
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CheckEitherNonSmiComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
Label* deopt = compiler->AddDeoptStub(instance_call_->deopt_id(),
|
|
|
|
instance_call_->try_index(),
|
|
|
|
kDeoptBinaryDoubleOp);
|
|
|
|
|
|
|
|
Register temp = locs()->temp(0).reg();
|
|
|
|
__ movl(temp, locs()->in(0).reg());
|
|
|
|
__ orl(temp, locs()->in(1).reg());
|
|
|
|
__ testl(temp, Immediate(kSmiTagMask));
|
|
|
|
__ j(ZERO, deopt);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* BoxDoubleComp::MakeLocationSummary() const {
|
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
|
|
|
LocationSummary* summary =
|
|
|
|
new LocationSummary(kNumInputs,
|
|
|
|
kNumTemps,
|
|
|
|
LocationSummary::kCallOnSlowPath);
|
|
|
|
summary->set_in(0, Location::RequiresXmmRegister());
|
|
|
|
summary->set_out(Location::RequiresRegister());
|
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class BoxDoubleSlowPath : public SlowPathCode {
|
|
|
|
public:
|
|
|
|
explicit BoxDoubleSlowPath(BoxDoubleComp* computation)
|
|
|
|
: computation_(computation) { }
|
|
|
|
|
|
|
|
virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
__ Bind(entry_label());
|
|
|
|
const Class& double_class = compiler->double_class();
|
|
|
|
const Code& stub =
|
|
|
|
Code::Handle(StubCode::GetAllocationStubForClass(double_class));
|
|
|
|
const ExternalLabel label(double_class.ToCString(), stub.EntryPoint());
|
|
|
|
|
|
|
|
// TODO(vegorov): here stack map needs to be set up correctly to skip
|
|
|
|
// double registers.
|
|
|
|
LocationSummary* locs = computation_->locs();
|
|
|
|
locs->live_registers()->Remove(locs->out());
|
|
|
|
|
|
|
|
compiler->SaveLiveRegisters(locs);
|
|
|
|
compiler->GenerateCall(computation_->instance_call()->token_pos(),
|
|
|
|
computation_->instance_call()->try_index(),
|
|
|
|
&label,
|
|
|
|
PcDescriptors::kOther,
|
|
|
|
locs);
|
|
|
|
if (EAX != locs->out().reg()) __ movl(locs->out().reg(), EAX);
|
|
|
|
compiler->RestoreLiveRegisters(locs);
|
|
|
|
|
|
|
|
__ jmp(exit_label());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
BoxDoubleComp* computation_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
void BoxDoubleComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this);
|
|
|
|
compiler->AddSlowPathCode(slow_path);
|
|
|
|
|
|
|
|
Register out_reg = locs()->out().reg();
|
|
|
|
XmmRegister value = locs()->in(0).xmm_reg();
|
|
|
|
|
|
|
|
AssemblerMacros::TryAllocate(compiler->assembler(),
|
|
|
|
compiler->double_class(),
|
|
|
|
slow_path->entry_label(),
|
|
|
|
Assembler::kFarJump,
|
|
|
|
out_reg);
|
|
|
|
__ Bind(slow_path->exit_label());
|
|
|
|
__ movsd(FieldAddress(out_reg, Double::value_offset()), value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* UnboxDoubleComp::MakeLocationSummary() const {
|
|
|
|
const intptr_t v_cid = value()->ResultCid();
|
|
|
|
|
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = (v_cid != kDoubleCid) ? 1 : 0;
|
|
|
|
LocationSummary* summary =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
|
|
|
if (v_cid != kDoubleCid) summary->set_temp(0, Location::RequiresRegister());
|
|
|
|
summary->set_out(Location::RequiresXmmRegister());
|
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UnboxDoubleComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
const intptr_t v_cid = value()->ResultCid();
|
|
|
|
|
|
|
|
const Register value = locs()->in(0).reg();
|
|
|
|
const XmmRegister result = locs()->out().xmm_reg();
|
|
|
|
if (v_cid != kDoubleCid) {
|
|
|
|
Label* deopt = compiler->AddDeoptStub(instance_call()->deopt_id(),
|
|
|
|
instance_call()->try_index(),
|
|
|
|
kDeoptBinaryDoubleOp);
|
|
|
|
compiler->LoadDoubleOrSmiToXmm(result,
|
|
|
|
value,
|
|
|
|
locs()->temp(0).reg(),
|
|
|
|
deopt);
|
|
|
|
} else {
|
|
|
|
__ movsd(result, FieldAddress(value, Double::value_offset()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* UnboxedDoubleBinaryOpComp::MakeLocationSummary() const {
|
|
|
|
const intptr_t kNumInputs = 2;
|
|
|
|
const intptr_t kNumTemps = 0;
|
|
|
|
LocationSummary* summary =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
|
|
|
summary->set_in(0, Location::RequiresXmmRegister());
|
|
|
|
summary->set_in(1, Location::RequiresXmmRegister());
|
|
|
|
summary->set_out(Location::SameAsFirstInput());
|
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UnboxedDoubleBinaryOpComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
XmmRegister left = locs()->in(0).xmm_reg();
|
|
|
|
XmmRegister right = locs()->in(1).xmm_reg();
|
|
|
|
|
|
|
|
ASSERT(locs()->out().xmm_reg() == left);
|
|
|
|
|
|
|
|
switch (op_kind()) {
|
|
|
|
case Token::kADD: __ addsd(left, right); break;
|
|
|
|
case Token::kSUB: __ subsd(left, right); break;
|
|
|
|
case Token::kMUL: __ mulsd(left, right); break;
|
|
|
|
case Token::kDIV: __ divsd(left, right); break;
|
|
|
|
default: UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-31 20:38:55 +00:00
|
|
|
LocationSummary* UnarySmiOpComp::MakeLocationSummary() const {
|
2012-06-01 18:38:35 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2012-07-31 11:51:47 +00:00
|
|
|
LocationSummary* summary =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2012-06-01 18:38:35 +00:00
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
|
|
|
summary->set_out(Location::SameAsFirstInput());
|
|
|
|
return summary;
|
2012-05-31 20:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-01 18:38:35 +00:00
|
|
|
void UnarySmiOpComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
const ICData& ic_data = *instance_call()->ic_data();
|
|
|
|
ASSERT(!ic_data.IsNull());
|
|
|
|
ASSERT(ic_data.num_args_tested() == 1);
|
|
|
|
// TODO(srdjan): Implement for more checks.
|
|
|
|
ASSERT(ic_data.NumberOfChecks() == 1);
|
2012-06-19 21:19:00 +00:00
|
|
|
intptr_t test_class_id;
|
2012-06-01 18:38:35 +00:00
|
|
|
Function& target = Function::Handle();
|
2012-06-19 21:19:00 +00:00
|
|
|
ic_data.GetOneClassCheckAt(0, &test_class_id, &target);
|
2012-06-01 18:38:35 +00:00
|
|
|
|
|
|
|
Register value = locs()->in(0).reg();
|
|
|
|
Register result = locs()->out().reg();
|
|
|
|
ASSERT(value == result);
|
2012-08-06 20:24:03 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(instance_call()->deopt_id(),
|
2012-06-01 18:38:35 +00:00
|
|
|
instance_call()->try_index(),
|
2012-08-21 13:58:57 +00:00
|
|
|
kDeoptUnaryOp);
|
2012-08-08 19:46:23 +00:00
|
|
|
if (test_class_id == kSmiCid) {
|
2012-06-01 18:38:35 +00:00
|
|
|
__ testl(value, Immediate(kSmiTagMask));
|
|
|
|
__ j(NOT_ZERO, deopt);
|
|
|
|
switch (op_kind()) {
|
|
|
|
case Token::kNEGATE:
|
|
|
|
__ negl(value);
|
|
|
|
__ j(OVERFLOW, deopt);
|
|
|
|
break;
|
|
|
|
case Token::kBIT_NOT:
|
|
|
|
__ notl(value);
|
|
|
|
__ andl(value, Immediate(~kSmiTagMask)); // Remove inverted smi-tag.
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
2012-05-31 20:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* NumberNegateComp::MakeLocationSummary() const {
|
2012-06-01 18:38:35 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 1; // Needed for doubles.
|
2012-07-31 11:51:47 +00:00
|
|
|
LocationSummary* summary =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
|
2012-07-24 17:19:20 +00:00
|
|
|
summary->set_in(0, Location::RegisterLocation(EAX));
|
|
|
|
summary->set_temp(0, Location::RegisterLocation(ECX));
|
|
|
|
summary->set_out(Location::RegisterLocation(EAX));
|
2012-06-01 18:38:35 +00:00
|
|
|
return summary;
|
2012-05-31 20:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-01 18:38:35 +00:00
|
|
|
void NumberNegateComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
const ICData& ic_data = *instance_call()->ic_data();
|
|
|
|
ASSERT(!ic_data.IsNull());
|
|
|
|
ASSERT(ic_data.num_args_tested() == 1);
|
|
|
|
|
|
|
|
// TODO(srdjan): Implement for more checks.
|
|
|
|
ASSERT(ic_data.NumberOfChecks() == 1);
|
2012-06-19 21:19:00 +00:00
|
|
|
intptr_t test_class_id;
|
2012-06-01 18:38:35 +00:00
|
|
|
Function& target = Function::Handle();
|
2012-06-19 21:19:00 +00:00
|
|
|
ic_data.GetOneClassCheckAt(0, &test_class_id, &target);
|
2012-06-01 18:38:35 +00:00
|
|
|
|
|
|
|
Register value = locs()->in(0).reg();
|
|
|
|
Register result = locs()->out().reg();
|
|
|
|
ASSERT(value == result);
|
2012-08-06 20:24:03 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(instance_call()->deopt_id(),
|
2012-06-01 18:38:35 +00:00
|
|
|
instance_call()->try_index(),
|
2012-08-21 13:58:57 +00:00
|
|
|
kDeoptUnaryOp);
|
2012-08-08 19:46:23 +00:00
|
|
|
if (test_class_id == kDoubleCid) {
|
2012-06-01 18:38:35 +00:00
|
|
|
Register temp = locs()->temp(0).reg();
|
|
|
|
__ testl(value, Immediate(kSmiTagMask));
|
|
|
|
__ j(ZERO, deopt); // Smi.
|
2012-08-08 19:46:23 +00:00
|
|
|
__ CompareClassId(value, kDoubleCid, temp);
|
2012-06-01 18:38:35 +00:00
|
|
|
__ j(NOT_EQUAL, deopt);
|
|
|
|
// Allocate result object.
|
2012-06-15 00:56:25 +00:00
|
|
|
const Class& double_class = compiler->double_class();
|
2012-06-01 18:38:35 +00:00
|
|
|
const Code& stub =
|
|
|
|
Code::Handle(StubCode::GetAllocationStubForClass(double_class));
|
|
|
|
const ExternalLabel label(double_class.ToCString(), stub.EntryPoint());
|
|
|
|
__ pushl(value);
|
2012-06-22 20:37:01 +00:00
|
|
|
compiler->GenerateCall(instance_call()->token_pos(),
|
2012-06-01 18:38:35 +00:00
|
|
|
instance_call()->try_index(),
|
|
|
|
&label,
|
2012-08-14 06:59:24 +00:00
|
|
|
PcDescriptors::kOther,
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
2012-06-01 18:38:35 +00:00
|
|
|
// Result is in EAX.
|
2012-06-22 01:24:36 +00:00
|
|
|
ASSERT(result != temp);
|
2012-06-01 18:38:35 +00:00
|
|
|
__ movl(result, EAX);
|
|
|
|
__ popl(temp);
|
|
|
|
__ movsd(XMM0, FieldAddress(temp, Double::value_offset()));
|
|
|
|
__ DoubleNegate(XMM0);
|
|
|
|
__ movsd(FieldAddress(result, Double::value_offset()), XMM0);
|
|
|
|
} else {
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
2012-08-16 22:22:57 +00:00
|
|
|
ASSERT(ResultCid() == kDoubleCid);
|
2012-05-31 20:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-15 11:31:51 +00:00
|
|
|
LocationSummary* DoubleToDoubleComp::MakeLocationSummary() const {
|
2012-06-13 08:29:40 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
2012-08-15 11:31:51 +00:00
|
|
|
const intptr_t kNumTemps = 1;
|
|
|
|
LocationSummary* locs =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
|
|
|
locs->set_in(0, Location::RequiresRegister());
|
|
|
|
locs->set_temp(0, Location::RequiresRegister());
|
|
|
|
locs->set_out(Location::SameAsFirstInput());
|
|
|
|
return locs;
|
2012-06-13 08:29:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-15 11:31:51 +00:00
|
|
|
void DoubleToDoubleComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
Register value = locs()->in(0).reg();
|
2012-06-22 01:24:36 +00:00
|
|
|
Register result = locs()->out().reg();
|
2012-06-13 08:29:40 +00:00
|
|
|
|
2012-08-06 20:24:03 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(instance_call()->deopt_id(),
|
2012-06-13 08:29:40 +00:00
|
|
|
instance_call()->try_index(),
|
2012-08-21 13:58:57 +00:00
|
|
|
kDeoptDoubleToDouble);
|
2012-08-15 11:31:51 +00:00
|
|
|
Register temp = locs()->temp(0).reg();
|
|
|
|
__ testl(value, Immediate(kSmiTagMask));
|
|
|
|
__ j(ZERO, deopt); // Deoptimize if Smi.
|
|
|
|
__ CompareClassId(value, kDoubleCid, temp);
|
|
|
|
__ j(NOT_EQUAL, deopt); // Deoptimize if not Double.
|
|
|
|
ASSERT(value == result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* SmiToDoubleComp::MakeLocationSummary() const {
|
|
|
|
return MakeCallSummary(); // Calls a stub to allocate result.
|
|
|
|
}
|
2012-06-13 08:29:40 +00:00
|
|
|
|
|
|
|
|
2012-08-15 11:31:51 +00:00
|
|
|
void SmiToDoubleComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
Register result = locs()->out().reg();
|
|
|
|
|
|
|
|
Label* deopt = compiler->AddDeoptStub(instance_call()->deopt_id(),
|
|
|
|
instance_call()->try_index(),
|
|
|
|
kDeoptIntegerToDouble);
|
2012-06-13 08:29:40 +00:00
|
|
|
|
2012-06-15 00:56:25 +00:00
|
|
|
const Class& double_class = compiler->double_class();
|
2012-06-13 08:29:40 +00:00
|
|
|
const Code& stub =
|
|
|
|
Code::Handle(StubCode::GetAllocationStubForClass(double_class));
|
|
|
|
const ExternalLabel label(double_class.ToCString(), stub.EntryPoint());
|
|
|
|
|
2012-06-18 18:04:22 +00:00
|
|
|
// TODO(vegorov): allocate box in the driver loop to avoid spilling.
|
2012-06-22 20:37:01 +00:00
|
|
|
compiler->GenerateCall(instance_call()->token_pos(),
|
2012-06-13 08:29:40 +00:00
|
|
|
instance_call()->try_index(),
|
|
|
|
&label,
|
2012-08-14 06:59:24 +00:00
|
|
|
PcDescriptors::kOther,
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
2012-06-13 08:29:40 +00:00
|
|
|
ASSERT(result == EAX);
|
2012-08-15 11:31:51 +00:00
|
|
|
Register value = EBX;
|
|
|
|
// Preserve argument on the stack until after the deoptimization point.
|
|
|
|
__ movl(value, Address(ESP, 0));
|
2012-06-13 08:29:40 +00:00
|
|
|
|
|
|
|
__ testl(value, Immediate(kSmiTagMask));
|
|
|
|
__ j(NOT_ZERO, deopt); // Deoptimize if not Smi.
|
|
|
|
__ SmiUntag(value);
|
|
|
|
__ cvtsi2sd(XMM0, value);
|
|
|
|
__ movsd(FieldAddress(result, Double::value_offset()), XMM0);
|
2012-08-15 11:31:51 +00:00
|
|
|
__ Drop(1);
|
2012-06-13 08:29:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-14 18:07:43 +00:00
|
|
|
LocationSummary* PolymorphicInstanceCallComp::MakeLocationSummary() const {
|
|
|
|
return MakeCallSummary();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void PolymorphicInstanceCallComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-08-06 20:24:03 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(instance_call()->deopt_id(),
|
2012-06-14 18:07:43 +00:00
|
|
|
instance_call()->try_index(),
|
|
|
|
kDeoptPolymorphicInstanceCallTestFail);
|
2012-06-20 23:19:02 +00:00
|
|
|
if (!HasICData() || (ic_data()->NumberOfChecks() == 0)) {
|
|
|
|
__ jmp(deopt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ASSERT(HasICData());
|
|
|
|
ASSERT(ic_data()->num_args_tested() == 1);
|
2012-08-23 21:25:27 +00:00
|
|
|
if (!with_checks()) {
|
|
|
|
const Function& target = Function::ZoneHandle(ic_data()->GetTargetAt(0));
|
|
|
|
compiler->GenerateStaticCall(instance_call()->deopt_id(),
|
|
|
|
instance_call()->token_pos(),
|
|
|
|
instance_call()->try_index(),
|
|
|
|
target,
|
|
|
|
instance_call()->ArgumentCount(),
|
|
|
|
instance_call()->argument_names(),
|
|
|
|
locs());
|
|
|
|
return;
|
|
|
|
}
|
2012-06-14 18:07:43 +00:00
|
|
|
Label handle_smi;
|
2012-06-19 21:49:11 +00:00
|
|
|
Label* is_smi_label =
|
2012-08-08 19:46:23 +00:00
|
|
|
ic_data()->GetReceiverClassIdAt(0) == kSmiCid ? &handle_smi : deopt;
|
2012-06-19 21:49:11 +00:00
|
|
|
|
2012-06-14 18:07:43 +00:00
|
|
|
// Load receiver into EAX.
|
|
|
|
__ movl(EAX,
|
|
|
|
Address(ESP, (instance_call()->ArgumentCount() - 1) * kWordSize));
|
|
|
|
__ testl(EAX, Immediate(kSmiTagMask));
|
|
|
|
__ j(ZERO, is_smi_label);
|
|
|
|
Label done;
|
|
|
|
__ LoadClassId(EDI, EAX);
|
2012-06-20 23:19:02 +00:00
|
|
|
compiler->EmitTestAndCall(*ic_data(),
|
|
|
|
EDI, // Class id register.
|
|
|
|
instance_call()->ArgumentCount(),
|
|
|
|
instance_call()->argument_names(),
|
2012-07-10 18:22:45 +00:00
|
|
|
deopt,
|
|
|
|
(is_smi_label == &handle_smi) ? &done : NULL,
|
2012-08-06 20:24:03 +00:00
|
|
|
instance_call()->deopt_id(),
|
2012-06-22 20:37:01 +00:00
|
|
|
instance_call()->token_pos(),
|
2012-08-14 06:59:24 +00:00
|
|
|
instance_call()->try_index(),
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
2012-06-14 18:07:43 +00:00
|
|
|
if (is_smi_label == &handle_smi) {
|
|
|
|
__ Bind(&handle_smi);
|
2012-08-08 19:46:23 +00:00
|
|
|
ASSERT(ic_data()->GetReceiverClassIdAt(0) == kSmiCid);
|
2012-06-19 21:49:11 +00:00
|
|
|
const Function& target = Function::ZoneHandle(ic_data()->GetTargetAt(0));
|
2012-08-06 20:24:03 +00:00
|
|
|
compiler->GenerateStaticCall(instance_call()->deopt_id(),
|
2012-06-22 20:37:01 +00:00
|
|
|
instance_call()->token_pos(),
|
2012-06-14 18:07:43 +00:00
|
|
|
instance_call()->try_index(),
|
2012-06-19 21:49:11 +00:00
|
|
|
target,
|
2012-06-14 18:07:43 +00:00
|
|
|
instance_call()->ArgumentCount(),
|
2012-08-14 06:59:24 +00:00
|
|
|
instance_call()->argument_names(),
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
2012-06-14 18:07:43 +00:00
|
|
|
}
|
|
|
|
__ Bind(&done);
|
|
|
|
}
|
|
|
|
|
2012-07-19 15:52:44 +00:00
|
|
|
|
|
|
|
// TODO(srdjan): Move to shared.
|
|
|
|
static bool ICDataWithBothClassIds(const ICData& ic_data, intptr_t class_id) {
|
|
|
|
if (ic_data.num_args_tested() != 2) return false;
|
|
|
|
if (ic_data.NumberOfChecks() != 1) return false;
|
|
|
|
Function& target = Function::Handle();
|
|
|
|
GrowableArray<intptr_t> class_ids;
|
|
|
|
ic_data.GetCheckAt(0, &class_ids, &target);
|
|
|
|
return (class_ids[0] == class_id) && (class_ids[1] == class_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-13 23:44:07 +00:00
|
|
|
static bool IsCheckedStrictEquals(const ICData& ic_data, Token::Kind kind) {
|
|
|
|
if ((kind == Token::kEQ) || (kind == Token::kNE)) {
|
2012-08-22 22:21:44 +00:00
|
|
|
return ic_data.AllTargetsHaveSameOwner(kInstanceCid);
|
2012-08-13 23:44:07 +00:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-19 15:52:44 +00:00
|
|
|
LocationSummary* BranchInstr::MakeLocationSummary() const {
|
|
|
|
if ((kind() == Token::kEQ_STRICT) || (kind() == Token::kNE_STRICT)) {
|
|
|
|
const int kNumInputs = 2;
|
|
|
|
const int kNumTemps = 0;
|
2012-07-31 11:51:47 +00:00
|
|
|
LocationSummary* locs =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2012-07-19 15:52:44 +00:00
|
|
|
locs->set_in(0, Location::RequiresRegister());
|
|
|
|
locs->set_in(1, Location::RequiresRegister());
|
|
|
|
return locs;
|
|
|
|
}
|
|
|
|
if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
|
2012-08-08 19:46:23 +00:00
|
|
|
if (ICDataWithBothClassIds(*ic_data(), kSmiCid) ||
|
2012-08-13 23:44:07 +00:00
|
|
|
ICDataWithBothClassIds(*ic_data(), kDoubleCid) ||
|
|
|
|
IsCheckedStrictEquals(*ic_data(), kind())) {
|
2012-07-19 15:52:44 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
|
|
|
const intptr_t kNumTemps = 1;
|
2012-07-31 11:51:47 +00:00
|
|
|
LocationSummary* summary =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2012-07-19 15:52:44 +00:00
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
|
|
|
summary->set_in(1, Location::RequiresRegister());
|
|
|
|
summary->set_temp(0, Location::RequiresRegister());
|
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
if ((kind() == Token::kEQ) || (kind() == Token::kNE)) {
|
|
|
|
const intptr_t kNumInputs = 2;
|
|
|
|
const intptr_t kNumTemps = 1;
|
2012-07-31 11:51:47 +00:00
|
|
|
LocationSummary* locs =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
|
2012-07-24 17:19:20 +00:00
|
|
|
locs->set_in(0, Location::RegisterLocation(EAX));
|
|
|
|
locs->set_in(1, Location::RegisterLocation(ECX));
|
|
|
|
locs->set_temp(0, Location::RegisterLocation(EDX));
|
2012-07-19 15:52:44 +00:00
|
|
|
return locs;
|
|
|
|
}
|
|
|
|
// Otherwise polymorphic dispatch.
|
|
|
|
}
|
|
|
|
// Call.
|
2012-08-10 10:34:38 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
|
|
|
const intptr_t kNumTemps = 0;
|
|
|
|
LocationSummary* locs =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
|
|
|
|
locs->set_in(0, Location::RegisterLocation(EAX));
|
|
|
|
locs->set_in(1, Location::RegisterLocation(ECX));
|
|
|
|
return locs;
|
2012-07-19 15:52:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
if ((kind() == Token::kEQ_STRICT) || (kind() == Token::kNE_STRICT)) {
|
|
|
|
Register left = locs()->in(0).reg();
|
|
|
|
Register right = locs()->in(1).reg();
|
|
|
|
__ cmpl(left, right);
|
|
|
|
Condition cond = (kind() == Token::kEQ_STRICT) ? EQUAL : NOT_EQUAL;
|
|
|
|
EmitBranchOnCondition(compiler, cond);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Relational or equality.
|
|
|
|
if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
|
2012-08-08 19:46:23 +00:00
|
|
|
if (ICDataWithBothClassIds(*ic_data(), kSmiCid)) {
|
2012-07-19 15:52:44 +00:00
|
|
|
EmitSmiComparisonOp(compiler, *locs(), kind(), this,
|
2012-08-06 20:24:03 +00:00
|
|
|
deopt_id(), token_pos(), try_index());
|
2012-07-19 15:52:44 +00:00
|
|
|
return;
|
|
|
|
}
|
2012-08-08 19:46:23 +00:00
|
|
|
if (ICDataWithBothClassIds(*ic_data(), kDoubleCid)) {
|
2012-07-19 15:52:44 +00:00
|
|
|
EmitDoubleComparisonOp(compiler, *locs(), kind(), this,
|
2012-08-06 20:24:03 +00:00
|
|
|
deopt_id(), token_pos(), try_index());
|
2012-07-19 15:52:44 +00:00
|
|
|
return;
|
|
|
|
}
|
2012-08-13 23:44:07 +00:00
|
|
|
if (IsCheckedStrictEquals(*ic_data(), kind())) {
|
|
|
|
EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), this,
|
|
|
|
deopt_id(), token_pos(), try_index());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-07-19 15:52:44 +00:00
|
|
|
// TODO(srdjan): Add Smi/Double, Double/Smi comparisons.
|
|
|
|
if ((kind() == Token::kEQ) || (kind() == Token::kNE)) {
|
2012-08-23 10:08:37 +00:00
|
|
|
EmitGenericEqualityCompare(compiler, locs(), kind(), this, *ic_data(),
|
2012-08-06 20:24:03 +00:00
|
|
|
deopt_id(), token_pos(), try_index());
|
2012-07-19 15:52:44 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Otherwise polymorphic dispatch?
|
|
|
|
}
|
2012-08-10 10:34:38 +00:00
|
|
|
Register left = locs()->in(0).reg();
|
|
|
|
Register right = locs()->in(1).reg();
|
|
|
|
__ pushl(left);
|
|
|
|
__ pushl(right);
|
2012-08-17 21:18:26 +00:00
|
|
|
if ((kind() == Token::kNE) || (kind() == Token::kEQ)) {
|
|
|
|
EmitEqualityAsInstanceCall(compiler,
|
|
|
|
deopt_id(),
|
|
|
|
token_pos(),
|
|
|
|
try_index(),
|
|
|
|
Token::kEQ, // kNE reverse occurs at branch.
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
2012-08-17 21:18:26 +00:00
|
|
|
} else {
|
|
|
|
const String& function_name =
|
|
|
|
String::ZoneHandle(Symbols::New(Token::Str(kind())));
|
|
|
|
compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
|
|
|
|
deopt_id(),
|
|
|
|
token_pos(),
|
|
|
|
try_index());
|
|
|
|
const intptr_t kNumArguments = 2;
|
|
|
|
const intptr_t kNumArgsChecked = 2; // Type-feedback.
|
|
|
|
compiler->GenerateInstanceCall(deopt_id(),
|
|
|
|
token_pos(),
|
|
|
|
try_index(),
|
|
|
|
function_name,
|
|
|
|
kNumArguments,
|
|
|
|
Array::ZoneHandle(), // No optional args.
|
|
|
|
kNumArgsChecked,
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
2012-08-17 21:18:26 +00:00
|
|
|
}
|
2012-07-19 15:52:44 +00:00
|
|
|
Condition branch_condition = (kind() == Token::kNE) ? NOT_EQUAL : EQUAL;
|
2012-08-10 10:34:38 +00:00
|
|
|
__ CompareObject(EAX, compiler->bool_true());
|
2012-07-19 15:52:44 +00:00
|
|
|
EmitBranchOnCondition(compiler, branch_condition);
|
|
|
|
}
|
|
|
|
|
2012-08-20 12:40:14 +00:00
|
|
|
|
|
|
|
LocationSummary* CheckClassComp::MakeLocationSummary() const {
|
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 1;
|
|
|
|
LocationSummary* summary =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
|
|
|
summary->set_temp(0, Location::RequiresRegister());
|
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CheckClassComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-08-21 22:31:49 +00:00
|
|
|
const intptr_t v_cid = value()->ResultCid();
|
|
|
|
const intptr_t num_checks = ic_data()->NumberOfChecks();
|
|
|
|
if ((num_checks == 1) &&
|
|
|
|
(v_cid == ic_data()->GetReceiverClassIdAt(0))) {
|
|
|
|
// No checks needed.
|
|
|
|
// TODO(srdjan): Should the computation have been removed instead?
|
|
|
|
return;
|
|
|
|
}
|
2012-08-20 12:40:14 +00:00
|
|
|
Register value = locs()->in(0).reg();
|
|
|
|
Register temp = locs()->temp(0).reg();
|
|
|
|
Label* deopt = compiler->AddDeoptStub(deopt_id(),
|
|
|
|
try_index(),
|
2012-08-21 13:58:57 +00:00
|
|
|
kDeoptCheckClass);
|
2012-08-20 12:40:14 +00:00
|
|
|
ASSERT(ic_data()->GetReceiverClassIdAt(0) != kSmiCid);
|
|
|
|
__ testl(value, Immediate(kSmiTagMask));
|
|
|
|
__ j(ZERO, deopt);
|
|
|
|
__ LoadClassId(temp, value);
|
|
|
|
Label is_ok;
|
|
|
|
const bool use_near_jump = num_checks < 5;
|
|
|
|
for (intptr_t i = 0; i < num_checks; i++) {
|
|
|
|
__ cmpl(temp, Immediate(ic_data()->GetReceiverClassIdAt(i)));
|
|
|
|
if (i == (num_checks - 1)) {
|
|
|
|
__ j(NOT_EQUAL, deopt);
|
|
|
|
} else {
|
|
|
|
if (use_near_jump) {
|
|
|
|
__ j(EQUAL, &is_ok, Assembler::kNearJump);
|
|
|
|
} else {
|
|
|
|
__ j(EQUAL, &is_ok);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
__ Bind(&is_ok);
|
|
|
|
}
|
|
|
|
|
2012-08-23 08:24:29 +00:00
|
|
|
|
|
|
|
LocationSummary* CheckSmiComp::MakeLocationSummary() const {
|
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
|
|
|
LocationSummary* summary =
|
|
|
|
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CheckSmiComp::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
Register value = locs()->in(0).reg();
|
|
|
|
Label* deopt = compiler->AddDeoptStub(deopt_id(),
|
|
|
|
try_index(),
|
|
|
|
kDeoptCheckSmi);
|
|
|
|
__ testl(value, Immediate(kSmiTagMask));
|
|
|
|
__ j(NOT_ZERO, deopt);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-21 19:51:17 +00:00
|
|
|
} // namespace dart
|
|
|
|
|
|
|
|
#undef __
|
|
|
|
|
|
|
|
#endif // defined TARGET_ARCH_X64
|