2013-01-18 00:34:20 +00:00
|
|
|
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
2012-05-21 19:51:17 +00:00
|
|
|
// 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"
|
|
|
|
|
2013-01-18 00:34:20 +00:00
|
|
|
#include "vm/dart_entry.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"
|
2013-03-19 20:15:10 +00:00
|
|
|
#include "vm/stack_frame.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 {
|
|
|
|
|
2014-05-22 23:47:20 +00:00
|
|
|
DECLARE_FLAG(bool, emit_edge_counters);
|
2012-05-31 18:09:11 +00:00
|
|
|
DECLARE_FLAG(int, optimization_counter_threshold);
|
2012-10-31 20:07:31 +00:00
|
|
|
DECLARE_FLAG(bool, propagate_ic_data);
|
2013-06-17 11:05:15 +00:00
|
|
|
DECLARE_FLAG(bool, use_osr);
|
2013-08-02 18:37:20 +00:00
|
|
|
DECLARE_FLAG(bool, throw_on_javascript_int_overflow);
|
2014-03-03 10:24:59 +00:00
|
|
|
DECLARE_FLAG(bool, use_slow_path);
|
2012-05-31 17:24:23 +00:00
|
|
|
|
|
|
|
// Generic summary for call instructions that have all arguments pushed
|
|
|
|
// on the stack and return the result in a fixed register EAX.
|
2012-09-05 17:04:49 +00:00
|
|
|
LocationSummary* Instruction::MakeCallSummary() {
|
2014-05-23 12:07:33 +00:00
|
|
|
Isolate* isolate = Isolate::Current();
|
|
|
|
LocationSummary* result = new(isolate) LocationSummary(
|
|
|
|
isolate, 0, 0, LocationSummary::kCall);
|
2014-03-21 14:40:30 +00:00
|
|
|
result->set_out(0, Location::RegisterLocation(EAX));
|
2012-05-31 17:24:23 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2012-05-31 15:52:39 +00:00
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* PushArgumentInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-01-08 16:51:57 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps= 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* locs = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-01-08 16:51:57 +00:00
|
|
|
locs->set_in(0, Location::AnyOrConstant(value()));
|
|
|
|
return locs;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void PushArgumentInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
// In SSA mode, we need an explicit push. Nothing to do in non-SSA mode
|
|
|
|
// where PushArgument is handled by BindInstr::EmitNativeCode.
|
|
|
|
if (compiler->is_optimizing()) {
|
|
|
|
Location value = locs()->in(0);
|
|
|
|
if (value.IsRegister()) {
|
|
|
|
__ pushl(value.reg());
|
|
|
|
} else if (value.IsConstant()) {
|
|
|
|
__ PushObject(value.constant());
|
|
|
|
} else {
|
|
|
|
ASSERT(value.IsStackSlot());
|
|
|
|
__ pushl(value.ToStackSlotAddress());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* ReturnInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2012-05-31 17:24:23 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
2013-01-10 00:28:57 +00:00
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* locs = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2012-05-31 17:24:23 +00:00
|
|
|
locs->set_in(0, Location::RegisterLocation(EAX));
|
|
|
|
return locs;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-13 18:34:05 +00:00
|
|
|
// Attempt optimized compilation at return instruction instead of at the entry.
|
|
|
|
// The entry needs to be patchable, no inlined objects are allowed in the area
|
|
|
|
// that will be overwritten by the patch instruction: a jump).
|
2012-05-31 17:24:23 +00:00
|
|
|
void ReturnInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
Register result = locs()->in(0).reg();
|
|
|
|
ASSERT(result == EAX);
|
2012-08-07 20:15:17 +00:00
|
|
|
#if defined(DEBUG)
|
2014-01-30 12:12:31 +00:00
|
|
|
__ Comment("Stack Check");
|
|
|
|
Label done;
|
|
|
|
const intptr_t fp_sp_dist =
|
|
|
|
(kFirstLocalSlotFromFp + 1 - compiler->StackSize()) * kWordSize;
|
|
|
|
ASSERT(fp_sp_dist <= 0);
|
|
|
|
__ movl(EDI, ESP);
|
|
|
|
__ subl(EDI, EBP);
|
|
|
|
__ cmpl(EDI, Immediate(fp_sp_dist));
|
|
|
|
__ j(EQUAL, &done, Assembler::kNearJump);
|
|
|
|
__ int3();
|
|
|
|
__ Bind(&done);
|
2012-08-07 20:15:17 +00:00
|
|
|
#endif
|
2012-05-31 17:24:23 +00:00
|
|
|
__ LeaveFrame();
|
|
|
|
__ ret();
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
2012-05-21 19:51:17 +00:00
|
|
|
|
2012-05-22 18:36:19 +00:00
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* LoadLocalInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-05-22 14:32:18 +00:00
|
|
|
const intptr_t kNumInputs = 0;
|
2014-01-08 10:27:01 +00:00
|
|
|
const intptr_t stack_index = (local().index() < 0)
|
|
|
|
? kFirstLocalSlotFromFp - local().index()
|
|
|
|
: kParamEndSlotFromFp - local().index();
|
2014-05-27 10:15:50 +00:00
|
|
|
return LocationSummary::Make(isolate,
|
|
|
|
kNumInputs,
|
2014-01-08 10:27:01 +00:00
|
|
|
Location::StackSlot(stack_index),
|
2012-07-31 11:51:47 +00:00
|
|
|
LocationSummary::kNoCall);
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void LoadLocalInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2014-01-08 10:27:01 +00:00
|
|
|
ASSERT(!compiler->is_optimizing());
|
|
|
|
// Nothing to do.
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* StoreLocalInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-05-22 14:32:18 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
2014-05-27 10:15:50 +00:00
|
|
|
return LocationSummary::Make(isolate,
|
|
|
|
kNumInputs,
|
2012-07-31 11:51:47 +00:00
|
|
|
Location::SameAsFirstInput(),
|
|
|
|
LocationSummary::kNoCall);
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void StoreLocalInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-05-31 17:24:23 +00:00
|
|
|
Register value = locs()->in(0).reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
Register result = locs()->out(0).reg();
|
2012-05-31 17:24:23 +00:00
|
|
|
ASSERT(result == value); // Assert that register assignment is correct.
|
|
|
|
__ movl(Address(EBP, local().index() * kWordSize), value);
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* ConstantInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-05-22 14:32:18 +00:00
|
|
|
const intptr_t kNumInputs = 0;
|
2014-05-27 10:15:50 +00:00
|
|
|
return LocationSummary::Make(isolate,
|
|
|
|
kNumInputs,
|
2012-07-31 11:51:47 +00:00
|
|
|
Location::RequiresRegister(),
|
|
|
|
LocationSummary::kNoCall);
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void ConstantInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
// The register allocator drops constant definitions that have no uses.
|
2014-03-21 14:40:30 +00:00
|
|
|
if (!locs()->out(0).IsInvalid()) {
|
|
|
|
Register result = locs()->out(0).reg();
|
2013-10-30 11:38:39 +00:00
|
|
|
__ LoadObjectSafely(result, value());
|
2012-09-04 09:58:57 +00:00
|
|
|
}
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* UnboxedConstantInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2014-05-01 22:03:21 +00:00
|
|
|
const intptr_t kNumInputs = 0;
|
|
|
|
const intptr_t kNumTemps = (constant_address() == 0) ? 1 : 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* locs = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2014-05-01 22:03:21 +00:00
|
|
|
locs->set_out(0, Location::RequiresFpuRegister());
|
|
|
|
if (kNumTemps == 1) {
|
|
|
|
locs->set_temp(0, Location::RequiresRegister());
|
|
|
|
}
|
|
|
|
return locs;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UnboxedConstantInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
// The register allocator drops constant definitions that have no uses.
|
|
|
|
if (!locs()->out(0).IsInvalid()) {
|
2014-05-02 23:50:22 +00:00
|
|
|
XmmRegister result = locs()->out(0).fpu_reg();
|
2014-05-01 22:03:21 +00:00
|
|
|
if (constant_address() == 0) {
|
|
|
|
Register boxed = locs()->temp(0).reg();
|
|
|
|
__ LoadObjectSafely(boxed, value());
|
|
|
|
__ movsd(result, FieldAddress(boxed, Double::value_offset()));
|
2014-05-02 23:50:22 +00:00
|
|
|
} else if (Utils::DoublesBitEqual(Double::Cast(value()).value(), 0.0)) {
|
|
|
|
__ xorps(result, result);
|
2014-05-01 22:03:21 +00:00
|
|
|
} else {
|
|
|
|
__ movsd(result, Address::Absolute(constant_address()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* AssertAssignableInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2012-06-25 23:50:37 +00:00
|
|
|
const intptr_t kNumInputs = 3;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, 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.
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::RegisterLocation(EAX));
|
2012-06-04 17:06:43 +00:00
|
|
|
return summary;
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* AssertBooleanInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2012-07-24 17:19:20 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* locs = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kCall);
|
2012-07-24 17:19:20 +00:00
|
|
|
locs->set_in(0, Location::RegisterLocation(EAX));
|
2014-03-21 14:40:30 +00:00
|
|
|
locs->set_out(0, Location::RegisterLocation(EAX));
|
2012-07-24 17:19:20 +00:00
|
|
|
return locs;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-24 10:44:00 +00:00
|
|
|
static void EmitAssertBoolean(Register reg,
|
|
|
|
intptr_t token_pos,
|
2013-01-29 12:38:27 +00:00
|
|
|
intptr_t deopt_id,
|
2012-10-24 10:44:00 +00:00
|
|
|
LocationSummary* locs,
|
|
|
|
FlowGraphCompiler* compiler) {
|
|
|
|
// Check that the type of the value is allowed in conditional context.
|
|
|
|
// Call the runtime if the object is not bool::true or bool::false.
|
|
|
|
ASSERT(locs->always_calls());
|
|
|
|
Label done;
|
2013-01-04 01:52:05 +00:00
|
|
|
__ CompareObject(reg, Bool::True());
|
2012-10-24 10:44:00 +00:00
|
|
|
__ j(EQUAL, &done, Assembler::kNearJump);
|
2013-01-04 01:52:05 +00:00
|
|
|
__ CompareObject(reg, Bool::False());
|
2012-10-24 10:44:00 +00:00
|
|
|
__ j(EQUAL, &done, Assembler::kNearJump);
|
|
|
|
|
|
|
|
__ pushl(reg); // Push the source object.
|
2013-10-25 10:17:10 +00:00
|
|
|
compiler->GenerateRuntimeCall(token_pos,
|
2013-01-29 12:38:27 +00:00
|
|
|
deopt_id,
|
2013-10-30 23:30:32 +00:00
|
|
|
kNonBoolTypeErrorRuntimeEntry,
|
2013-08-28 23:07:14 +00:00
|
|
|
1,
|
2012-10-24 10:44:00 +00:00
|
|
|
locs);
|
|
|
|
// We should never return here.
|
|
|
|
__ int3();
|
|
|
|
__ Bind(&done);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void AssertBooleanInstr::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 obj = locs()->in(0).reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
Register result = locs()->out(0).reg();
|
2012-05-30 16:57:19 +00:00
|
|
|
|
2013-02-13 17:16:35 +00:00
|
|
|
EmitAssertBoolean(obj, token_pos(), deopt_id(), locs(), 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(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;
|
2013-04-05 16:46:53 +00:00
|
|
|
case Token::kGTE: return GREATER_EQUAL;
|
2012-07-20 15:20:11 +00:00
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
return OVERFLOW;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* EqualityCompareInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2012-06-13 18:48:46 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
2013-07-26 16:48:46 +00:00
|
|
|
if (operation_cid() == kMintCid) {
|
2014-05-22 06:30:51 +00:00
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* locs = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2014-05-22 06:30:51 +00:00
|
|
|
locs->set_in(0, Location::Pair(Location::RequiresRegister(),
|
|
|
|
Location::RequiresRegister()));
|
|
|
|
locs->set_in(1, Location::Pair(Location::RequiresRegister(),
|
|
|
|
Location::RequiresRegister()));
|
2014-03-21 14:40:30 +00:00
|
|
|
locs->set_out(0, Location::RequiresRegister());
|
2012-10-02 11:25:53 +00:00
|
|
|
return locs;
|
|
|
|
}
|
2013-07-26 16:48:46 +00:00
|
|
|
if (operation_cid() == kDoubleCid) {
|
2012-08-30 20:39:48 +00:00
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* locs = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-01-18 00:34:20 +00:00
|
|
|
locs->set_in(0, Location::RequiresFpuRegister());
|
|
|
|
locs->set_in(1, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
locs->set_out(0, Location::RequiresRegister());
|
2012-08-30 20:39:48 +00:00
|
|
|
return locs;
|
|
|
|
}
|
2013-07-26 16:48:46 +00:00
|
|
|
if (operation_cid() == kSmiCid) {
|
2012-09-06 13:27:30 +00:00
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* locs = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2012-09-06 13:27:30 +00:00
|
|
|
locs->set_in(0, Location::RegisterOrConstant(left()));
|
2012-11-12 22:44:34 +00:00
|
|
|
// Only one input can be a constant operand. The case of two constant
|
|
|
|
// operands should be handled by constant propagation.
|
2013-05-22 14:32:18 +00:00
|
|
|
// Only right can be a stack slot.
|
2012-11-12 22:44:34 +00:00
|
|
|
locs->set_in(1, locs->in(0).IsConstant()
|
|
|
|
? Location::RequiresRegister()
|
2013-06-07 07:13:54 +00:00
|
|
|
: Location::RegisterOrConstant(right()));
|
2014-03-21 14:40:30 +00:00
|
|
|
locs->set_out(0, Location::RequiresRegister());
|
2012-09-06 13:27:30 +00:00
|
|
|
return locs;
|
|
|
|
}
|
2013-11-04 11:32:52 +00:00
|
|
|
UNREACHABLE();
|
|
|
|
return NULL;
|
2012-06-15 00:40:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-19 20:15:10 +00:00
|
|
|
static void LoadValueCid(FlowGraphCompiler* compiler,
|
|
|
|
Register value_cid_reg,
|
|
|
|
Register value_reg,
|
|
|
|
Label* value_is_smi = NULL) {
|
|
|
|
Label done;
|
|
|
|
if (value_is_smi == NULL) {
|
|
|
|
__ movl(value_cid_reg, Immediate(kSmiCid));
|
|
|
|
}
|
|
|
|
__ testl(value_reg, Immediate(kSmiTagMask));
|
|
|
|
if (value_is_smi == NULL) {
|
|
|
|
__ j(ZERO, &done, Assembler::kNearJump);
|
|
|
|
} else {
|
|
|
|
__ j(ZERO, value_is_smi);
|
|
|
|
}
|
|
|
|
__ LoadClassId(value_cid_reg, value_reg);
|
|
|
|
__ Bind(&done);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-05-24 18:52:34 +00:00
|
|
|
static Condition FlipCondition(Condition condition) {
|
|
|
|
switch (condition) {
|
|
|
|
case EQUAL: return EQUAL;
|
|
|
|
case NOT_EQUAL: return NOT_EQUAL;
|
|
|
|
case LESS: return GREATER;
|
|
|
|
case LESS_EQUAL: return GREATER_EQUAL;
|
|
|
|
case GREATER: return LESS;
|
|
|
|
case GREATER_EQUAL: return LESS_EQUAL;
|
|
|
|
case BELOW: return ABOVE;
|
|
|
|
case BELOW_EQUAL: return ABOVE_EQUAL;
|
|
|
|
case ABOVE: return BELOW;
|
|
|
|
case ABOVE_EQUAL: return BELOW_EQUAL;
|
|
|
|
default:
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
return EQUAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-07 11:47:04 +00:00
|
|
|
static Condition NegateCondition(Condition condition) {
|
|
|
|
switch (condition) {
|
|
|
|
case EQUAL: return NOT_EQUAL;
|
|
|
|
case NOT_EQUAL: return EQUAL;
|
|
|
|
case LESS: return GREATER_EQUAL;
|
|
|
|
case LESS_EQUAL: return GREATER;
|
|
|
|
case GREATER: return LESS_EQUAL;
|
|
|
|
case GREATER_EQUAL: return LESS;
|
|
|
|
case BELOW: return ABOVE_EQUAL;
|
|
|
|
case BELOW_EQUAL: return ABOVE;
|
|
|
|
case ABOVE: return BELOW_EQUAL;
|
|
|
|
case ABOVE_EQUAL: return BELOW;
|
|
|
|
default:
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
return EQUAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void EmitBranchOnCondition(FlowGraphCompiler* compiler,
|
2013-11-13 18:21:27 +00:00
|
|
|
Condition true_condition,
|
|
|
|
BranchLabels labels) {
|
|
|
|
if (labels.fall_through == labels.false_label) {
|
2013-11-07 11:47:04 +00:00
|
|
|
// If the next block is the false successor, fall through to it.
|
2013-11-13 18:21:27 +00:00
|
|
|
__ j(true_condition, labels.true_label);
|
2013-11-07 11:47:04 +00:00
|
|
|
} else {
|
|
|
|
// If the next block is not the false successor, branch to it.
|
|
|
|
Condition false_condition = NegateCondition(true_condition);
|
2013-11-13 18:21:27 +00:00
|
|
|
__ j(false_condition, labels.false_label);
|
2013-11-07 11:47:04 +00:00
|
|
|
|
|
|
|
// Fall through or jump to the true successor.
|
2013-11-13 18:21:27 +00:00
|
|
|
if (labels.fall_through != labels.true_label) {
|
|
|
|
__ jmp(labels.true_label);
|
2013-11-07 11:47:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-25 12:57:21 +00:00
|
|
|
static Condition EmitSmiComparisonOp(FlowGraphCompiler* compiler,
|
|
|
|
const LocationSummary& locs,
|
|
|
|
Token::Kind kind,
|
|
|
|
BranchLabels labels) {
|
2012-09-06 13:27:30 +00:00
|
|
|
Location left = locs.in(0);
|
|
|
|
Location right = locs.in(1);
|
2012-11-12 22:44:34 +00:00
|
|
|
ASSERT(!left.IsConstant() || !right.IsConstant());
|
2012-06-11 17:02:39 +00:00
|
|
|
|
2012-07-19 15:52:44 +00:00
|
|
|
Condition true_condition = TokenKindToSmiCondition(kind);
|
2012-09-06 13:27:30 +00:00
|
|
|
|
|
|
|
if (left.IsConstant()) {
|
2012-10-02 22:52:39 +00:00
|
|
|
__ CompareObject(right.reg(), left.constant());
|
2013-05-24 18:52:34 +00:00
|
|
|
true_condition = FlipCondition(true_condition);
|
2012-09-06 13:27:30 +00:00
|
|
|
} else if (right.IsConstant()) {
|
2012-10-02 22:52:39 +00:00
|
|
|
__ CompareObject(left.reg(), right.constant());
|
2013-05-22 14:32:18 +00:00
|
|
|
} else if (right.IsStackSlot()) {
|
|
|
|
__ cmpl(left.reg(), right.ToStackSlotAddress());
|
2012-09-06 13:27:30 +00:00
|
|
|
} else {
|
|
|
|
__ cmpl(left.reg(), right.reg());
|
|
|
|
}
|
2013-11-25 12:57:21 +00:00
|
|
|
return true_condition;
|
2012-06-11 17:02:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-02 18:37:20 +00:00
|
|
|
static void EmitJavascriptIntOverflowCheck(FlowGraphCompiler* compiler,
|
|
|
|
Label* overflow,
|
2014-05-22 06:30:51 +00:00
|
|
|
Register result_lo,
|
|
|
|
Register result_hi) {
|
2013-08-02 18:37:20 +00:00
|
|
|
// Compare upper half.
|
2014-03-21 16:26:21 +00:00
|
|
|
Label check_lower;
|
2014-05-22 06:30:51 +00:00
|
|
|
__ cmpl(result_hi, Immediate(0x00200000));
|
2013-08-02 18:37:20 +00:00
|
|
|
__ j(GREATER, overflow);
|
|
|
|
__ j(NOT_EQUAL, &check_lower);
|
|
|
|
|
2014-05-22 06:30:51 +00:00
|
|
|
__ cmpl(result_lo, Immediate(0));
|
2013-08-02 18:37:20 +00:00
|
|
|
__ j(ABOVE, overflow);
|
|
|
|
|
|
|
|
__ Bind(&check_lower);
|
2014-05-22 06:30:51 +00:00
|
|
|
__ cmpl(result_hi, Immediate(-0x00200000));
|
2013-08-02 18:37:20 +00:00
|
|
|
__ j(LESS, overflow);
|
|
|
|
// Anything in the lower part would make the number bigger than the lower
|
|
|
|
// bound, so we are done.
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-02 11:25:53 +00:00
|
|
|
static Condition TokenKindToMintCondition(Token::Kind kind) {
|
|
|
|
switch (kind) {
|
|
|
|
case Token::kEQ: return EQUAL;
|
|
|
|
case Token::kNE: return NOT_EQUAL;
|
2012-10-31 14:53:15 +00:00
|
|
|
case Token::kLT: return LESS;
|
|
|
|
case Token::kGT: return GREATER;
|
|
|
|
case Token::kLTE: return LESS_EQUAL;
|
|
|
|
case Token::kGTE: return GREATER_EQUAL;
|
2012-10-02 11:25:53 +00:00
|
|
|
default:
|
2012-10-31 14:53:15 +00:00
|
|
|
UNREACHABLE();
|
2012-10-02 11:25:53 +00:00
|
|
|
return OVERFLOW;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-25 12:57:21 +00:00
|
|
|
static Condition EmitUnboxedMintEqualityOp(FlowGraphCompiler* compiler,
|
|
|
|
const LocationSummary& locs,
|
|
|
|
Token::Kind kind,
|
|
|
|
BranchLabels labels) {
|
2012-10-02 11:25:53 +00:00
|
|
|
ASSERT(Token::IsEqualityOperator(kind));
|
2014-05-22 06:30:51 +00:00
|
|
|
PairLocation* left_pair = locs.in(0).AsPairLocation();
|
|
|
|
Register left1 = left_pair->At(0).reg();
|
|
|
|
Register left2 = left_pair->At(1).reg();
|
|
|
|
PairLocation* right_pair = locs.in(1).AsPairLocation();
|
|
|
|
Register right1 = right_pair->At(0).reg();
|
|
|
|
Register right2 = right_pair->At(1).reg();
|
|
|
|
Label done;
|
|
|
|
// Compare lower.
|
|
|
|
__ cmpl(left1, right1);
|
|
|
|
__ j(NOT_EQUAL, &done);
|
|
|
|
// Lower is equal, compare upper.
|
|
|
|
__ cmpl(left2, right2);
|
|
|
|
__ Bind(&done);
|
2012-10-02 11:25:53 +00:00
|
|
|
Condition true_condition = TokenKindToMintCondition(kind);
|
2013-11-25 12:57:21 +00:00
|
|
|
return true_condition;
|
2012-10-02 11:25:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-25 12:57:21 +00:00
|
|
|
static Condition EmitUnboxedMintComparisonOp(FlowGraphCompiler* compiler,
|
|
|
|
const LocationSummary& locs,
|
|
|
|
Token::Kind kind,
|
|
|
|
BranchLabels labels) {
|
2014-05-22 06:30:51 +00:00
|
|
|
PairLocation* left_pair = locs.in(0).AsPairLocation();
|
|
|
|
Register left1 = left_pair->At(0).reg();
|
|
|
|
Register left2 = left_pair->At(1).reg();
|
|
|
|
PairLocation* right_pair = locs.in(1).AsPairLocation();
|
|
|
|
Register right1 = right_pair->At(0).reg();
|
|
|
|
Register right2 = right_pair->At(1).reg();
|
2012-10-31 14:53:15 +00:00
|
|
|
|
|
|
|
Condition hi_cond = OVERFLOW, lo_cond = OVERFLOW;
|
|
|
|
switch (kind) {
|
|
|
|
case Token::kLT:
|
|
|
|
hi_cond = LESS;
|
|
|
|
lo_cond = BELOW;
|
|
|
|
break;
|
|
|
|
case Token::kGT:
|
|
|
|
hi_cond = GREATER;
|
|
|
|
lo_cond = ABOVE;
|
|
|
|
break;
|
|
|
|
case Token::kLTE:
|
|
|
|
hi_cond = LESS;
|
|
|
|
lo_cond = BELOW_EQUAL;
|
|
|
|
break;
|
|
|
|
case Token::kGTE:
|
|
|
|
hi_cond = GREATER;
|
|
|
|
lo_cond = ABOVE_EQUAL;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ASSERT(hi_cond != OVERFLOW && lo_cond != OVERFLOW);
|
|
|
|
Label is_true, is_false;
|
|
|
|
// Compare upper halves first.
|
2014-05-22 06:30:51 +00:00
|
|
|
__ cmpl(left2, right2);
|
2013-11-13 18:21:27 +00:00
|
|
|
__ j(hi_cond, labels.true_label);
|
|
|
|
__ j(FlipCondition(hi_cond), labels.false_label);
|
2012-10-31 14:53:15 +00:00
|
|
|
|
|
|
|
// If upper is equal, compare lower half.
|
2014-05-22 06:30:51 +00:00
|
|
|
__ cmpl(left1, right1);
|
2013-11-25 12:57:21 +00:00
|
|
|
return lo_cond;
|
2012-10-31 14:53:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-25 12:57:21 +00:00
|
|
|
static Condition EmitDoubleComparisonOp(FlowGraphCompiler* compiler,
|
|
|
|
const LocationSummary& locs,
|
|
|
|
Token::Kind kind,
|
|
|
|
BranchLabels labels) {
|
2013-01-18 00:34:20 +00:00
|
|
|
XmmRegister left = locs.in(0).fpu_reg();
|
|
|
|
XmmRegister right = locs.in(1).fpu_reg();
|
2012-06-13 16:23:14 +00:00
|
|
|
|
2013-11-13 18:21:27 +00:00
|
|
|
__ comisd(left, right);
|
|
|
|
|
2012-07-19 15:52:44 +00:00
|
|
|
Condition true_condition = TokenKindToDoubleCondition(kind);
|
2013-11-13 18:21:27 +00:00
|
|
|
Label* nan_result = (true_condition == NOT_EQUAL)
|
|
|
|
? labels.true_label : labels.false_label;
|
|
|
|
__ j(PARITY_EVEN, nan_result);
|
2013-11-25 12:57:21 +00:00
|
|
|
return true_condition;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Condition EqualityCompareInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
|
|
|
|
BranchLabels labels) {
|
|
|
|
if (operation_cid() == kSmiCid) {
|
|
|
|
return EmitSmiComparisonOp(compiler, *locs(), kind(), labels);
|
|
|
|
} else if (operation_cid() == kMintCid) {
|
|
|
|
return EmitUnboxedMintEqualityOp(compiler, *locs(), kind(), labels);
|
|
|
|
} else {
|
|
|
|
ASSERT(operation_cid() == kDoubleCid);
|
|
|
|
return EmitDoubleComparisonOp(compiler, *locs(), kind(), labels);
|
|
|
|
}
|
2012-06-11 17:02:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void EqualityCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-08-29 09:07:11 +00:00
|
|
|
ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ));
|
2013-11-13 18:21:27 +00:00
|
|
|
|
|
|
|
Label is_true, is_false;
|
|
|
|
BranchLabels labels = { &is_true, &is_false, &is_false };
|
2013-11-25 12:57:21 +00:00
|
|
|
Condition true_condition = EmitComparisonCode(compiler, labels);
|
|
|
|
EmitBranchOnCondition(compiler, true_condition, labels);
|
2013-11-13 18:21:27 +00:00
|
|
|
|
2014-03-21 14:40:30 +00:00
|
|
|
Register result = locs()->out(0).reg();
|
2013-11-13 18:21:27 +00:00
|
|
|
Label done;
|
|
|
|
__ Bind(&is_false);
|
|
|
|
__ LoadObject(result, Bool::False());
|
|
|
|
__ jmp(&done, Assembler::kNearJump);
|
|
|
|
__ Bind(&is_true);
|
|
|
|
__ LoadObject(result, Bool::True());
|
|
|
|
__ Bind(&done);
|
2012-08-29 09:07:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler,
|
|
|
|
BranchInstr* branch) {
|
2012-08-29 09:07:11 +00:00
|
|
|
ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ));
|
2013-11-13 18:21:27 +00:00
|
|
|
|
|
|
|
BranchLabels labels = compiler->CreateBranchLabels(branch);
|
2013-11-25 12:57:21 +00:00
|
|
|
Condition true_condition = EmitComparisonCode(compiler, labels);
|
|
|
|
EmitBranchOnCondition(compiler, true_condition, labels);
|
2012-08-08 14:05:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* TestSmiInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-11-06 12:13:29 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* locs = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-11-06 12:13:29 +00:00
|
|
|
locs->set_in(0, Location::RequiresRegister());
|
|
|
|
// Only one input can be a constant operand. The case of two constant
|
|
|
|
// operands should be handled by constant propagation.
|
|
|
|
locs->set_in(1, Location::RegisterOrConstant(right()));
|
|
|
|
return locs;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-25 12:57:21 +00:00
|
|
|
Condition TestSmiInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
|
|
|
|
BranchLabels labels) {
|
2013-11-06 12:13:29 +00:00
|
|
|
Register left = locs()->in(0).reg();
|
|
|
|
Location right = locs()->in(1);
|
|
|
|
if (right.IsConstant()) {
|
|
|
|
ASSERT(right.constant().IsSmi());
|
|
|
|
const int32_t imm =
|
|
|
|
reinterpret_cast<int32_t>(right.constant().raw());
|
|
|
|
__ testl(left, Immediate(imm));
|
|
|
|
} else {
|
|
|
|
__ testl(left, right.reg());
|
|
|
|
}
|
2013-11-25 12:57:21 +00:00
|
|
|
Condition true_condition = (kind() == Token::kNE) ? NOT_ZERO : ZERO;
|
|
|
|
return true_condition;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TestSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
// Never emitted outside of the BranchInstr.
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TestSmiInstr::EmitBranchCode(FlowGraphCompiler* compiler,
|
|
|
|
BranchInstr* branch) {
|
|
|
|
BranchLabels labels = compiler->CreateBranchLabels(branch);
|
|
|
|
Condition true_condition = EmitComparisonCode(compiler, labels);
|
2013-11-13 18:21:27 +00:00
|
|
|
EmitBranchOnCondition(compiler, true_condition, labels);
|
2013-11-06 12:13:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-04-25 23:21:12 +00:00
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* TestCidsInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2014-04-25 23:21:12 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 1;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* locs = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2014-04-25 23:21:12 +00:00
|
|
|
locs->set_in(0, Location::RequiresRegister());
|
|
|
|
locs->set_temp(0, Location::RequiresRegister());
|
|
|
|
locs->set_out(0, Location::RequiresRegister());
|
|
|
|
return locs;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Condition TestCidsInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
|
|
|
|
BranchLabels labels) {
|
|
|
|
ASSERT((kind() == Token::kIS) || (kind() == Token::kISNOT));
|
|
|
|
Register val_reg = locs()->in(0).reg();
|
|
|
|
Register cid_reg = locs()->temp(0).reg();
|
|
|
|
|
|
|
|
Label* deopt = CanDeoptimize() ?
|
2014-04-25 23:45:14 +00:00
|
|
|
compiler->AddDeoptStub(deopt_id(), ICData::kDeoptTestCids) : NULL;
|
2014-04-25 23:21:12 +00:00
|
|
|
|
|
|
|
const intptr_t true_result = (kind() == Token::kIS) ? 1 : 0;
|
|
|
|
const ZoneGrowableArray<intptr_t>& data = cid_results();
|
|
|
|
ASSERT(data[0] == kSmiCid);
|
|
|
|
bool result = data[1] == true_result;
|
|
|
|
__ testl(val_reg, Immediate(kSmiTagMask));
|
|
|
|
__ j(ZERO, result ? labels.true_label : labels.false_label);
|
|
|
|
__ LoadClassId(cid_reg, val_reg);
|
|
|
|
for (intptr_t i = 2; i < data.length(); i += 2) {
|
|
|
|
const intptr_t test_cid = data[i];
|
|
|
|
ASSERT(test_cid != kSmiCid);
|
|
|
|
result = data[i + 1] == true_result;
|
|
|
|
__ cmpl(cid_reg, Immediate(test_cid));
|
|
|
|
__ j(EQUAL, result ? labels.true_label : labels.false_label);
|
|
|
|
}
|
|
|
|
// No match found, deoptimize or false.
|
|
|
|
if (deopt == NULL) {
|
|
|
|
Label* target = result ? labels.false_label : labels.true_label;
|
|
|
|
if (target != labels.fall_through) {
|
|
|
|
__ jmp(target);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
__ jmp(deopt);
|
|
|
|
}
|
|
|
|
// Dummy result as the last instruction is a jump, any conditional
|
|
|
|
// branch using the result will therefore be skipped.
|
|
|
|
return ZERO;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TestCidsInstr::EmitBranchCode(FlowGraphCompiler* compiler,
|
|
|
|
BranchInstr* branch) {
|
|
|
|
BranchLabels labels = compiler->CreateBranchLabels(branch);
|
|
|
|
EmitComparisonCode(compiler, labels);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TestCidsInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
Register result_reg = locs()->out(0).reg();
|
|
|
|
Label is_true, is_false, done;
|
|
|
|
BranchLabels labels = { &is_true, &is_false, &is_false };
|
|
|
|
EmitComparisonCode(compiler, labels);
|
|
|
|
__ Bind(&is_false);
|
|
|
|
__ LoadObject(result_reg, Bool::False());
|
|
|
|
__ jmp(&done, Assembler::kNearJump);
|
|
|
|
__ Bind(&is_true);
|
|
|
|
__ LoadObject(result_reg, Bool::True());
|
|
|
|
__ Bind(&done);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* RelationalOpInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2012-08-16 08:46:45 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
2012-09-06 13:27:30 +00:00
|
|
|
const intptr_t kNumTemps = 0;
|
2013-07-26 16:48:46 +00:00
|
|
|
if (operation_cid() == kMintCid) {
|
2014-05-22 06:30:51 +00:00
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* locs = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2014-05-22 06:30:51 +00:00
|
|
|
locs->set_in(0, Location::Pair(Location::RequiresRegister(),
|
|
|
|
Location::RequiresRegister()));
|
|
|
|
locs->set_in(1, Location::Pair(Location::RequiresRegister(),
|
|
|
|
Location::RequiresRegister()));
|
2014-03-21 14:40:30 +00:00
|
|
|
locs->set_out(0, Location::RequiresRegister());
|
2012-10-31 14:53:15 +00:00
|
|
|
return locs;
|
|
|
|
}
|
2013-07-26 16:48:46 +00:00
|
|
|
if (operation_cid() == kDoubleCid) {
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-01-18 00:34:20 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
|
|
|
summary->set_in(1, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::RequiresRegister());
|
2012-08-30 20:39:48 +00:00
|
|
|
return summary;
|
2012-08-08 14:05:53 +00:00
|
|
|
}
|
2013-09-03 14:02:53 +00:00
|
|
|
ASSERT(operation_cid() == kSmiCid);
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-09-03 14:02:53 +00:00
|
|
|
summary->set_in(0, Location::RegisterOrConstant(left()));
|
|
|
|
// Only one input can be a constant operand. The case of two constant
|
|
|
|
// operands should be handled by constant propagation.
|
|
|
|
summary->set_in(1, summary->in(0).IsConstant()
|
|
|
|
? Location::RequiresRegister()
|
|
|
|
: Location::RegisterOrConstant(right()));
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::RequiresRegister());
|
2013-09-03 14:02:53 +00:00
|
|
|
return summary;
|
2012-08-08 14:05:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-25 12:57:21 +00:00
|
|
|
Condition RelationalOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
|
|
|
|
BranchLabels labels) {
|
2013-07-26 16:48:46 +00:00
|
|
|
if (operation_cid() == kSmiCid) {
|
2013-11-25 12:57:21 +00:00
|
|
|
return EmitSmiComparisonOp(compiler, *locs(), kind(), labels);
|
2013-11-13 18:21:27 +00:00
|
|
|
} else if (operation_cid() == kMintCid) {
|
2013-11-25 12:57:21 +00:00
|
|
|
return EmitUnboxedMintComparisonOp(compiler, *locs(), kind(), labels);
|
2013-11-13 18:21:27 +00:00
|
|
|
} else {
|
|
|
|
ASSERT(operation_cid() == kDoubleCid);
|
2013-11-25 12:57:21 +00:00
|
|
|
return EmitDoubleComparisonOp(compiler, *locs(), kind(), labels);
|
2012-10-31 14:53:15 +00:00
|
|
|
}
|
2013-11-25 12:57:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RelationalOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
Label is_true, is_false;
|
|
|
|
BranchLabels labels = { &is_true, &is_false, &is_false };
|
|
|
|
Condition true_condition = EmitComparisonCode(compiler, labels);
|
|
|
|
EmitBranchOnCondition(compiler, true_condition, labels);
|
|
|
|
|
2014-03-21 14:40:30 +00:00
|
|
|
Register result = locs()->out(0).reg();
|
2013-11-13 18:21:27 +00:00
|
|
|
Label done;
|
|
|
|
__ Bind(&is_false);
|
|
|
|
__ LoadObject(result, Bool::False());
|
|
|
|
__ jmp(&done, Assembler::kNearJump);
|
|
|
|
__ Bind(&is_true);
|
|
|
|
__ LoadObject(result, Bool::True());
|
|
|
|
__ Bind(&done);
|
2012-08-29 09:07:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void RelationalOpInstr::EmitBranchCode(FlowGraphCompiler* compiler,
|
|
|
|
BranchInstr* branch) {
|
2013-11-13 18:21:27 +00:00
|
|
|
BranchLabels labels = compiler->CreateBranchLabels(branch);
|
2013-11-25 12:57:21 +00:00
|
|
|
Condition true_condition = EmitComparisonCode(compiler, labels);
|
|
|
|
EmitBranchOnCondition(compiler, true_condition, labels);
|
2012-06-11 17:02:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* NativeCallInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2012-06-22 01:24:36 +00:00
|
|
|
const intptr_t kNumInputs = 0;
|
|
|
|
const intptr_t kNumTemps = 3;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* locs = new(isolate) LocationSummary(
|
|
|
|
isolate, 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));
|
2014-03-21 14:40:30 +00:00
|
|
|
locs->set_out(0, Location::RegisterLocation(EAX));
|
2012-05-31 17:24:23 +00:00
|
|
|
return locs;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-05-31 17:24:23 +00:00
|
|
|
ASSERT(locs()->temp(0).reg() == EAX);
|
|
|
|
ASSERT(locs()->temp(1).reg() == ECX);
|
|
|
|
ASSERT(locs()->temp(2).reg() == EDX);
|
2014-03-21 14:40:30 +00:00
|
|
|
Register result = locs()->out(0).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-11-08 18:28:07 +00:00
|
|
|
if (!function().HasOptionalParameters()) {
|
2013-05-07 18:06:21 +00:00
|
|
|
__ leal(EAX, Address(EBP, (kParamEndSlotFromFp +
|
|
|
|
function().NumParameters()) * kWordSize));
|
2012-05-31 17:24:23 +00:00
|
|
|
} else {
|
2013-05-07 18:06:21 +00:00
|
|
|
__ leal(EAX, Address(EBP, kFirstLocalSlotFromFp * kWordSize));
|
2012-05-31 17:24:23 +00:00
|
|
|
}
|
|
|
|
__ movl(ECX, Immediate(reinterpret_cast<uword>(native_c_function())));
|
2012-11-08 18:28:07 +00:00
|
|
|
__ movl(EDX, Immediate(NativeArguments::ComputeArgcTag(function())));
|
2013-08-06 19:27:48 +00:00
|
|
|
const ExternalLabel* stub_entry =
|
|
|
|
(is_bootstrap_native()) ? &StubCode::CallBootstrapCFunctionLabel() :
|
|
|
|
&StubCode::CallNativeCFunctionLabel();
|
2012-06-22 20:37:01 +00:00
|
|
|
compiler->GenerateCall(token_pos(),
|
2013-08-06 19:27:48 +00:00
|
|
|
stub_entry,
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-10-30 11:38:39 +00:00
|
|
|
static bool CanBeImmediateIndex(Value* value, intptr_t cid) {
|
|
|
|
ConstantInstr* constant = value->definition()->AsConstant();
|
|
|
|
if ((constant == NULL) || !Assembler::IsSafeSmi(constant->value())) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
const int64_t index = Smi::Cast(constant->value()).AsInt64Value();
|
2014-05-23 18:31:10 +00:00
|
|
|
const intptr_t scale = Instance::ElementSizeFor(cid);
|
|
|
|
const intptr_t offset = Instance::DataOffsetFor(cid);
|
2013-10-30 11:38:39 +00:00
|
|
|
const int64_t displacement = index * scale + offset;
|
|
|
|
return Utils::IsInt(32, displacement);
|
2012-09-12 13:49:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* StringFromCharCodeInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2012-11-22 12:06:52 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
// TODO(fschneider): Allow immediate operands for the char code.
|
2014-05-27 10:15:50 +00:00
|
|
|
return LocationSummary::Make(isolate,
|
|
|
|
kNumInputs,
|
2013-05-06 17:22:18 +00:00
|
|
|
Location::RequiresRegister(),
|
|
|
|
LocationSummary::kNoCall);
|
2012-11-22 12:06:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StringFromCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
Register char_code = locs()->in(0).reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
Register result = locs()->out(0).reg();
|
2012-11-22 12:06:52 +00:00
|
|
|
__ movl(result,
|
|
|
|
Immediate(reinterpret_cast<uword>(Symbols::PredefinedAddress())));
|
|
|
|
__ movl(result, Address(result,
|
|
|
|
char_code,
|
|
|
|
TIMES_HALF_WORD_SIZE, // Char code is a smi.
|
2013-01-02 19:31:59 +00:00
|
|
|
Symbols::kNullCharCodeSymbolOffset * kWordSize));
|
2012-11-22 12:06:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* StringToCharCodeInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-12-20 20:11:38 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
2014-05-27 10:15:50 +00:00
|
|
|
return LocationSummary::Make(isolate,
|
|
|
|
kNumInputs,
|
2013-12-20 20:11:38 +00:00
|
|
|
Location::RequiresRegister(),
|
|
|
|
LocationSummary::kNoCall);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StringToCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
ASSERT(cid_ == kOneByteStringCid);
|
|
|
|
Register str = locs()->in(0).reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
Register result = locs()->out(0).reg();
|
2013-12-20 20:11:38 +00:00
|
|
|
Label is_one, done;
|
|
|
|
__ movl(result, FieldAddress(str, String::length_offset()));
|
|
|
|
__ cmpl(result, Immediate(Smi::RawValue(1)));
|
|
|
|
__ j(EQUAL, &is_one, Assembler::kNearJump);
|
|
|
|
__ movl(result, Immediate(Smi::RawValue(-1)));
|
|
|
|
__ jmp(&done);
|
|
|
|
__ Bind(&is_one);
|
|
|
|
__ movzxb(result, FieldAddress(str, OneByteString::data_offset()));
|
|
|
|
__ SmiTag(result);
|
|
|
|
__ Bind(&done);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* StringInterpolateInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-10-16 18:12:08 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kCall);
|
2013-10-16 18:12:08 +00:00
|
|
|
summary->set_in(0, Location::RegisterLocation(EAX));
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::RegisterLocation(EAX));
|
2013-10-16 18:12:08 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StringInterpolateInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
Register array = locs()->in(0).reg();
|
|
|
|
__ pushl(array);
|
|
|
|
const int kNumberOfArguments = 1;
|
|
|
|
const Array& kNoArgumentNames = Object::null_array();
|
|
|
|
compiler->GenerateStaticCall(deopt_id(),
|
|
|
|
token_pos(),
|
|
|
|
CallFunction(),
|
|
|
|
kNumberOfArguments,
|
|
|
|
kNoArgumentNames,
|
|
|
|
locs());
|
2014-03-21 14:40:30 +00:00
|
|
|
ASSERT(locs()->out(0).reg() == EAX);
|
2013-10-16 18:12:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* LoadUntaggedInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-03-19 12:06:23 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
2014-05-27 10:15:50 +00:00
|
|
|
return LocationSummary::Make(isolate,
|
|
|
|
kNumInputs,
|
2013-05-06 17:22:18 +00:00
|
|
|
Location::RequiresRegister(),
|
|
|
|
LocationSummary::kNoCall);
|
2013-03-19 12:06:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void LoadUntaggedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
Register object = locs()->in(0).reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
Register result = locs()->out(0).reg();
|
2013-03-19 12:06:23 +00:00
|
|
|
__ movl(result, FieldAddress(object, offset()));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* LoadClassIdInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-05-06 17:22:18 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
2014-05-27 10:15:50 +00:00
|
|
|
return LocationSummary::Make(isolate,
|
|
|
|
kNumInputs,
|
2013-05-06 17:22:18 +00:00
|
|
|
Location::RequiresRegister(),
|
|
|
|
LocationSummary::kNoCall);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void LoadClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
Register object = locs()->in(0).reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
Register result = locs()->out(0).reg();
|
2013-05-06 17:22:18 +00:00
|
|
|
Label load, done;
|
|
|
|
__ testl(object, Immediate(kSmiTagMask));
|
|
|
|
__ j(NOT_ZERO, &load, Assembler::kNearJump);
|
|
|
|
__ movl(result, Immediate(Smi::RawValue(kSmiCid)));
|
|
|
|
__ jmp(&done);
|
|
|
|
__ Bind(&load);
|
|
|
|
__ LoadClassId(result, object);
|
|
|
|
__ SmiTag(result);
|
|
|
|
__ Bind(&done);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-02-22 16:33:37 +00:00
|
|
|
CompileType LoadIndexedInstr::ComputeType() const {
|
2013-01-21 16:19:42 +00:00
|
|
|
switch (class_id_) {
|
|
|
|
case kArrayCid:
|
|
|
|
case kImmutableArrayCid:
|
2013-02-13 17:16:35 +00:00
|
|
|
return CompileType::Dynamic();
|
|
|
|
|
2013-03-14 10:39:20 +00:00
|
|
|
case kTypedDataFloat32ArrayCid:
|
|
|
|
case kTypedDataFloat64ArrayCid:
|
2013-02-13 17:16:35 +00:00
|
|
|
return CompileType::FromCid(kDoubleCid);
|
2013-04-11 12:50:46 +00:00
|
|
|
case kTypedDataFloat32x4ArrayCid:
|
|
|
|
return CompileType::FromCid(kFloat32x4Cid);
|
2013-11-04 21:56:59 +00:00
|
|
|
case kTypedDataInt32x4ArrayCid:
|
|
|
|
return CompileType::FromCid(kInt32x4Cid);
|
2014-02-20 20:41:54 +00:00
|
|
|
case kTypedDataFloat64x2ArrayCid:
|
|
|
|
return CompileType::FromCid(kFloat64x2Cid);
|
2013-02-13 17:16:35 +00:00
|
|
|
|
2013-03-14 10:39:20 +00:00
|
|
|
case kTypedDataInt8ArrayCid:
|
|
|
|
case kTypedDataUint8ArrayCid:
|
|
|
|
case kTypedDataUint8ClampedArrayCid:
|
|
|
|
case kExternalTypedDataUint8ArrayCid:
|
|
|
|
case kExternalTypedDataUint8ClampedArrayCid:
|
|
|
|
case kTypedDataInt16ArrayCid:
|
|
|
|
case kTypedDataUint16ArrayCid:
|
2013-01-21 16:19:42 +00:00
|
|
|
case kOneByteStringCid:
|
|
|
|
case kTwoByteStringCid:
|
2013-02-13 17:16:35 +00:00
|
|
|
return CompileType::FromCid(kSmiCid);
|
|
|
|
|
2013-03-14 10:39:20 +00:00
|
|
|
case kTypedDataInt32ArrayCid:
|
|
|
|
case kTypedDataUint32ArrayCid:
|
2013-01-29 21:16:44 +00:00
|
|
|
// Result can be Smi or Mint when boxed.
|
|
|
|
// Instruction can deoptimize if we optimistically assumed that the result
|
|
|
|
// fits into Smi.
|
2013-02-13 17:16:35 +00:00
|
|
|
return CanDeoptimize() ? CompileType::FromCid(kSmiCid)
|
|
|
|
: CompileType::Int();
|
|
|
|
|
2013-01-21 16:19:42 +00:00
|
|
|
default:
|
|
|
|
UNIMPLEMENTED();
|
2013-02-13 17:16:35 +00:00
|
|
|
return CompileType::Dynamic();
|
2013-01-21 16:19:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Representation LoadIndexedInstr::representation() const {
|
|
|
|
switch (class_id_) {
|
|
|
|
case kArrayCid:
|
|
|
|
case kImmutableArrayCid:
|
2013-03-14 10:39:20 +00:00
|
|
|
case kTypedDataInt8ArrayCid:
|
|
|
|
case kTypedDataUint8ArrayCid:
|
|
|
|
case kTypedDataUint8ClampedArrayCid:
|
|
|
|
case kExternalTypedDataUint8ArrayCid:
|
|
|
|
case kExternalTypedDataUint8ClampedArrayCid:
|
|
|
|
case kTypedDataInt16ArrayCid:
|
|
|
|
case kTypedDataUint16ArrayCid:
|
2013-01-21 16:19:42 +00:00
|
|
|
case kOneByteStringCid:
|
|
|
|
case kTwoByteStringCid:
|
|
|
|
return kTagged;
|
2013-03-14 10:39:20 +00:00
|
|
|
case kTypedDataInt32ArrayCid:
|
|
|
|
case kTypedDataUint32ArrayCid:
|
2013-01-29 21:16:44 +00:00
|
|
|
// Instruction can deoptimize if we optimistically assumed that the result
|
|
|
|
// fits into Smi.
|
|
|
|
return CanDeoptimize() ? kTagged : kUnboxedMint;
|
2013-03-14 10:39:20 +00:00
|
|
|
case kTypedDataFloat32ArrayCid:
|
|
|
|
case kTypedDataFloat64ArrayCid:
|
2013-01-21 16:19:42 +00:00
|
|
|
return kUnboxedDouble;
|
2013-04-11 12:50:46 +00:00
|
|
|
case kTypedDataFloat32x4ArrayCid:
|
|
|
|
return kUnboxedFloat32x4;
|
2013-11-04 21:56:59 +00:00
|
|
|
case kTypedDataInt32x4ArrayCid:
|
|
|
|
return kUnboxedInt32x4;
|
2014-02-20 20:41:54 +00:00
|
|
|
case kTypedDataFloat64x2ArrayCid:
|
|
|
|
return kUnboxedFloat64x2;
|
2013-01-21 16:19:42 +00:00
|
|
|
default:
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
return kTagged;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* LoadIndexedInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2012-06-12 16:27:18 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
2012-09-12 13:49:12 +00:00
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* locs = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2012-09-12 13:49:12 +00:00
|
|
|
locs->set_in(0, Location::RequiresRegister());
|
2013-10-30 11:38:39 +00:00
|
|
|
if (CanBeImmediateIndex(index(), class_id())) {
|
|
|
|
// CanBeImmediateIndex must return false for unsafe smis.
|
|
|
|
locs->set_in(1, Location::Constant(index()->BoundConstant()));
|
2013-02-14 11:41:08 +00:00
|
|
|
} else {
|
2013-10-30 11:38:39 +00:00
|
|
|
// The index is either untagged (element size == 1) or a smi (for all
|
|
|
|
// element sizes > 1).
|
|
|
|
locs->set_in(1, (index_scale() == 1)
|
|
|
|
? Location::WritableRegister()
|
|
|
|
: Location::RequiresRegister());
|
2013-02-14 11:41:08 +00:00
|
|
|
}
|
2013-10-31 04:57:38 +00:00
|
|
|
if ((representation() == kUnboxedDouble) ||
|
|
|
|
(representation() == kUnboxedFloat32x4) ||
|
2014-02-20 20:41:54 +00:00
|
|
|
(representation() == kUnboxedInt32x4) ||
|
|
|
|
(representation() == kUnboxedFloat64x2)) {
|
2014-03-21 14:40:30 +00:00
|
|
|
locs->set_out(0, Location::RequiresFpuRegister());
|
2014-05-22 06:30:51 +00:00
|
|
|
} else if (representation() == kUnboxedMint) {
|
|
|
|
if (class_id() == kTypedDataInt32ArrayCid) {
|
|
|
|
locs->set_out(0, Location::Pair(Location::RegisterLocation(EAX),
|
|
|
|
Location::RegisterLocation(EDX)));
|
|
|
|
} else {
|
|
|
|
ASSERT(class_id() == kTypedDataUint32ArrayCid);
|
|
|
|
locs->set_out(0, Location::Pair(Location::RequiresRegister(),
|
|
|
|
Location::RequiresRegister()));
|
|
|
|
}
|
2012-10-16 15:40:54 +00:00
|
|
|
} else {
|
2014-05-22 06:30:51 +00:00
|
|
|
ASSERT(representation() == kTagged);
|
2014-03-21 14:40:30 +00:00
|
|
|
locs->set_out(0, Location::RequiresRegister());
|
2012-10-16 15:40:54 +00:00
|
|
|
}
|
2012-09-12 13:49:12 +00:00
|
|
|
return locs;
|
2012-06-20 23:19:02 +00:00
|
|
|
}
|
|
|
|
|
2012-06-12 16:27:18 +00:00
|
|
|
|
2014-05-23 18:31:10 +00:00
|
|
|
static Address ElementAddressForIntIndex(bool is_external,
|
|
|
|
intptr_t cid,
|
|
|
|
intptr_t index_scale,
|
|
|
|
Register array,
|
|
|
|
intptr_t index) {
|
|
|
|
if (is_external) {
|
|
|
|
return Address(array, index * index_scale);
|
|
|
|
} else {
|
|
|
|
const int64_t disp = static_cast<int64_t>(index) * index_scale +
|
|
|
|
Instance::DataOffsetFor(cid);
|
|
|
|
ASSERT(Utils::IsInt(32, disp));
|
|
|
|
return FieldAddress(array, static_cast<int32_t>(disp));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static ScaleFactor ToScaleFactor(intptr_t index_scale) {
|
|
|
|
// Note that index is expected smi-tagged, (i.e, times 2) for all arrays with
|
|
|
|
// index scale factor > 1. E.g., for Uint8Array and OneByteString the index is
|
|
|
|
// expected to be untagged before accessing.
|
|
|
|
ASSERT(kSmiTagShift == 1);
|
|
|
|
switch (index_scale) {
|
|
|
|
case 1: return TIMES_1;
|
|
|
|
case 2: return TIMES_1;
|
|
|
|
case 4: return TIMES_2;
|
|
|
|
case 8: return TIMES_4;
|
|
|
|
case 16: return TIMES_8;
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
return TIMES_1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static Address ElementAddressForRegIndex(bool is_external,
|
|
|
|
intptr_t cid,
|
|
|
|
intptr_t index_scale,
|
|
|
|
Register array,
|
|
|
|
Register index) {
|
|
|
|
if (is_external) {
|
|
|
|
return Address(array, index, ToScaleFactor(index_scale), 0);
|
|
|
|
} else {
|
|
|
|
return FieldAddress(array,
|
|
|
|
index,
|
|
|
|
ToScaleFactor(index_scale),
|
|
|
|
Instance::DataOffsetFor(cid));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2014-05-27 18:27:54 +00:00
|
|
|
// The array register points to the backing store for external arrays.
|
|
|
|
const Register array = locs()->in(0).reg();
|
|
|
|
const Location index = locs()->in(1);
|
2012-11-26 11:50:07 +00:00
|
|
|
|
2014-05-27 18:27:54 +00:00
|
|
|
Address element_address = index.IsRegister()
|
2014-05-23 18:31:10 +00:00
|
|
|
? ElementAddressForRegIndex(IsExternal(), class_id(), index_scale(),
|
|
|
|
array, index.reg())
|
|
|
|
: ElementAddressForIntIndex(IsExternal(), class_id(), index_scale(),
|
|
|
|
array, Smi::Cast(index.constant()).Value());
|
2012-11-26 11:50:07 +00:00
|
|
|
|
2013-01-21 16:19:42 +00:00
|
|
|
if ((representation() == kUnboxedDouble) ||
|
2013-10-31 04:57:38 +00:00
|
|
|
(representation() == kUnboxedFloat32x4) ||
|
2014-02-20 20:41:54 +00:00
|
|
|
(representation() == kUnboxedInt32x4) ||
|
|
|
|
(representation() == kUnboxedFloat64x2)) {
|
2014-03-21 14:40:30 +00:00
|
|
|
XmmRegister result = locs()->out(0).fpu_reg();
|
2013-02-06 19:00:50 +00:00
|
|
|
if ((index_scale() == 1) && index.IsRegister()) {
|
2013-02-06 15:18:57 +00:00
|
|
|
__ SmiUntag(index.reg());
|
|
|
|
}
|
2013-01-21 16:19:42 +00:00
|
|
|
switch (class_id()) {
|
2013-03-14 10:39:20 +00:00
|
|
|
case kTypedDataFloat32ArrayCid:
|
2013-01-21 16:19:42 +00:00
|
|
|
__ movss(result, element_address);
|
|
|
|
break;
|
2013-03-14 10:39:20 +00:00
|
|
|
case kTypedDataFloat64ArrayCid:
|
2013-01-21 16:19:42 +00:00
|
|
|
__ movsd(result, element_address);
|
|
|
|
break;
|
2013-11-04 21:56:59 +00:00
|
|
|
case kTypedDataInt32x4ArrayCid:
|
2013-04-11 12:50:46 +00:00
|
|
|
case kTypedDataFloat32x4ArrayCid:
|
2014-02-20 20:41:54 +00:00
|
|
|
case kTypedDataFloat64x2ArrayCid:
|
2013-04-11 12:50:46 +00:00
|
|
|
__ movups(result, element_address);
|
|
|
|
break;
|
2014-05-22 06:30:51 +00:00
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (representation() == kUnboxedMint) {
|
|
|
|
ASSERT(locs()->out(0).IsPairLocation());
|
|
|
|
PairLocation* result_pair = locs()->out(0).AsPairLocation();
|
|
|
|
Register result1 = result_pair->At(0).reg();
|
|
|
|
Register result2 = result_pair->At(1).reg();
|
|
|
|
if ((index_scale() == 1) && index.IsRegister()) {
|
|
|
|
__ SmiUntag(index.reg());
|
|
|
|
}
|
|
|
|
switch (class_id()) {
|
|
|
|
case kTypedDataInt32ArrayCid:
|
|
|
|
ASSERT(result1 == EAX);
|
|
|
|
ASSERT(result2 == EDX);
|
|
|
|
__ movl(result1, element_address);
|
|
|
|
__ cdq();
|
|
|
|
break;
|
|
|
|
case kTypedDataUint32ArrayCid:
|
|
|
|
__ movl(result1, element_address);
|
|
|
|
__ xorl(result2, result2);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
2012-10-22 17:04:50 +00:00
|
|
|
}
|
2012-11-26 11:50:07 +00:00
|
|
|
return;
|
2012-09-12 13:49:12 +00:00
|
|
|
}
|
2012-11-26 11:50:07 +00:00
|
|
|
|
2014-05-22 06:30:51 +00:00
|
|
|
ASSERT(representation() == kTagged);
|
|
|
|
|
2014-03-21 14:40:30 +00:00
|
|
|
Register result = locs()->out(0).reg();
|
2013-02-06 19:00:50 +00:00
|
|
|
if ((index_scale() == 1) && index.IsRegister()) {
|
2013-02-06 15:18:57 +00:00
|
|
|
__ SmiUntag(index.reg());
|
|
|
|
}
|
2013-01-17 10:43:46 +00:00
|
|
|
switch (class_id()) {
|
2013-03-14 10:39:20 +00:00
|
|
|
case kTypedDataInt8ArrayCid:
|
|
|
|
ASSERT(index_scale() == 1);
|
|
|
|
__ movsxb(result, element_address);
|
|
|
|
__ SmiTag(result);
|
|
|
|
break;
|
|
|
|
case kTypedDataUint8ArrayCid:
|
|
|
|
case kTypedDataUint8ClampedArrayCid:
|
2013-03-19 12:06:23 +00:00
|
|
|
case kExternalTypedDataUint8ArrayCid:
|
|
|
|
case kExternalTypedDataUint8ClampedArrayCid:
|
2013-01-18 14:03:40 +00:00
|
|
|
case kOneByteStringCid:
|
2013-02-06 15:18:57 +00:00
|
|
|
ASSERT(index_scale() == 1);
|
2013-03-14 10:39:20 +00:00
|
|
|
__ movzxb(result, element_address);
|
2013-01-17 10:43:46 +00:00
|
|
|
__ SmiTag(result);
|
|
|
|
break;
|
2013-03-14 10:39:20 +00:00
|
|
|
case kTypedDataInt16ArrayCid:
|
2013-01-17 10:43:46 +00:00
|
|
|
__ movsxw(result, element_address);
|
|
|
|
__ SmiTag(result);
|
|
|
|
break;
|
2013-03-14 10:39:20 +00:00
|
|
|
case kTypedDataUint16ArrayCid:
|
2013-01-18 14:03:40 +00:00
|
|
|
case kTwoByteStringCid:
|
2013-01-17 10:43:46 +00:00
|
|
|
__ movzxw(result, element_address);
|
|
|
|
__ SmiTag(result);
|
|
|
|
break;
|
2013-03-14 10:39:20 +00:00
|
|
|
case kTypedDataInt32ArrayCid: {
|
2014-04-25 23:45:14 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(deopt_id(),
|
|
|
|
ICData::kDeoptInt32Load);
|
2013-01-29 21:16:44 +00:00
|
|
|
__ movl(result, element_address);
|
|
|
|
// Verify that the signed value in 'result' can fit inside a Smi.
|
|
|
|
__ cmpl(result, Immediate(0xC0000000));
|
|
|
|
__ j(NEGATIVE, deopt);
|
|
|
|
__ SmiTag(result);
|
|
|
|
}
|
|
|
|
break;
|
2013-03-14 10:39:20 +00:00
|
|
|
case kTypedDataUint32ArrayCid: {
|
2014-04-25 23:45:14 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(deopt_id(),
|
|
|
|
ICData::kDeoptUint32Load);
|
2013-01-29 21:16:44 +00:00
|
|
|
__ movl(result, element_address);
|
|
|
|
// Verify that the unsigned value in 'result' can fit inside a Smi.
|
|
|
|
__ testl(result, Immediate(0xC0000000));
|
|
|
|
__ j(NOT_ZERO, deopt);
|
|
|
|
__ SmiTag(result);
|
|
|
|
}
|
|
|
|
break;
|
2013-01-17 10:43:46 +00:00
|
|
|
default:
|
|
|
|
ASSERT((class_id() == kArrayCid) || (class_id() == kImmutableArrayCid));
|
|
|
|
__ movl(result, element_address);
|
|
|
|
break;
|
2012-11-26 11:50:07 +00:00
|
|
|
}
|
2012-06-08 19:36:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-01-21 16:19:42 +00:00
|
|
|
Representation StoreIndexedInstr::RequiredInputRepresentation(
|
|
|
|
intptr_t idx) const {
|
2013-03-19 12:06:23 +00:00
|
|
|
// Array can be a Dart object or a pointer to external data.
|
|
|
|
if (idx == 0) return kNoRepresentation; // Flexible input representation.
|
|
|
|
if (idx == 1) return kTagged; // Index is a smi.
|
2013-01-21 16:19:42 +00:00
|
|
|
ASSERT(idx == 2);
|
|
|
|
switch (class_id_) {
|
|
|
|
case kArrayCid:
|
2013-05-08 20:03:33 +00:00
|
|
|
case kOneByteStringCid:
|
2013-03-14 10:39:20 +00:00
|
|
|
case kTypedDataInt8ArrayCid:
|
|
|
|
case kTypedDataUint8ArrayCid:
|
|
|
|
case kExternalTypedDataUint8ArrayCid:
|
|
|
|
case kTypedDataUint8ClampedArrayCid:
|
|
|
|
case kExternalTypedDataUint8ClampedArrayCid:
|
|
|
|
case kTypedDataInt16ArrayCid:
|
|
|
|
case kTypedDataUint16ArrayCid:
|
2013-01-21 16:19:42 +00:00
|
|
|
return kTagged;
|
2013-03-14 10:39:20 +00:00
|
|
|
case kTypedDataInt32ArrayCid:
|
|
|
|
case kTypedDataUint32ArrayCid:
|
2013-02-18 16:52:36 +00:00
|
|
|
return value()->IsSmiValue() ? kTagged : kUnboxedMint;
|
2013-03-19 12:06:23 +00:00
|
|
|
case kTypedDataFloat32ArrayCid:
|
|
|
|
case kTypedDataFloat64ArrayCid:
|
2013-01-21 16:19:42 +00:00
|
|
|
return kUnboxedDouble;
|
2013-04-11 12:50:46 +00:00
|
|
|
case kTypedDataFloat32x4ArrayCid:
|
|
|
|
return kUnboxedFloat32x4;
|
2013-11-04 21:56:59 +00:00
|
|
|
case kTypedDataInt32x4ArrayCid:
|
|
|
|
return kUnboxedInt32x4;
|
2014-02-20 20:41:54 +00:00
|
|
|
case kTypedDataFloat64x2ArrayCid:
|
|
|
|
return kUnboxedFloat64x2;
|
2013-01-21 16:19:42 +00:00
|
|
|
default:
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
return kTagged;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* StoreIndexedInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) 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 = 3;
|
2013-01-14 10:27:28 +00:00
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* locs = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2012-08-15 13:54:38 +00:00
|
|
|
locs->set_in(0, Location::RequiresRegister());
|
2013-10-30 11:38:39 +00:00
|
|
|
if (CanBeImmediateIndex(index(), class_id())) {
|
|
|
|
// CanBeImmediateIndex must return false for unsafe smis.
|
|
|
|
locs->set_in(1, Location::Constant(index()->BoundConstant()));
|
2013-02-14 11:41:08 +00:00
|
|
|
} else {
|
2013-10-30 11:38:39 +00:00
|
|
|
// The index is either untagged (element size == 1) or a smi (for all
|
|
|
|
// element sizes > 1).
|
|
|
|
locs->set_in(1, (index_scale() == 1)
|
|
|
|
? Location::WritableRegister()
|
|
|
|
: Location::RequiresRegister());
|
2013-02-14 11:41:08 +00:00
|
|
|
}
|
2013-01-14 10:27:28 +00:00
|
|
|
switch (class_id()) {
|
|
|
|
case kArrayCid:
|
|
|
|
locs->set_in(2, ShouldEmitStoreBarrier()
|
|
|
|
? Location::WritableRegister()
|
|
|
|
: Location::RegisterOrConstant(value()));
|
|
|
|
break;
|
2013-03-14 10:39:20 +00:00
|
|
|
case kExternalTypedDataUint8ArrayCid:
|
|
|
|
case kExternalTypedDataUint8ClampedArrayCid:
|
|
|
|
case kTypedDataInt8ArrayCid:
|
|
|
|
case kTypedDataUint8ArrayCid:
|
|
|
|
case kTypedDataUint8ClampedArrayCid:
|
2013-05-08 20:03:33 +00:00
|
|
|
case kOneByteStringCid:
|
2013-01-14 10:27:28 +00:00
|
|
|
// TODO(fschneider): Add location constraint for byte registers (EAX,
|
|
|
|
// EBX, ECX, EDX) instead of using a fixed register.
|
|
|
|
locs->set_in(2, Location::FixedRegisterOrSmiConstant(value(), EAX));
|
|
|
|
break;
|
2013-03-14 10:39:20 +00:00
|
|
|
case kTypedDataInt16ArrayCid:
|
|
|
|
case kTypedDataUint16ArrayCid:
|
2013-01-17 10:43:46 +00:00
|
|
|
// Writable register because the value must be untagged before storing.
|
|
|
|
locs->set_in(2, Location::WritableRegister());
|
|
|
|
break;
|
2013-03-14 10:39:20 +00:00
|
|
|
case kTypedDataInt32ArrayCid:
|
|
|
|
case kTypedDataUint32ArrayCid:
|
2014-05-22 06:30:51 +00:00
|
|
|
// For smis, use a writable register because the value must be untagged
|
|
|
|
// before storing. Mints are stored in registers pairs.
|
|
|
|
if (value()->IsSmiValue()) {
|
|
|
|
locs->set_in(2, Location::WritableRegister());
|
|
|
|
} else {
|
|
|
|
// We only move the lower 32-bits so we don't care where the high bits
|
|
|
|
// are located.
|
|
|
|
locs->set_in(2, Location::Pair(Location::RequiresRegister(),
|
|
|
|
Location::Any()));
|
|
|
|
}
|
2013-02-18 16:52:36 +00:00
|
|
|
break;
|
2013-03-14 10:39:20 +00:00
|
|
|
case kTypedDataFloat32ArrayCid:
|
|
|
|
case kTypedDataFloat64ArrayCid:
|
2013-01-14 10:27:28 +00:00
|
|
|
// TODO(srdjan): Support Float64 constants.
|
2013-01-18 00:34:20 +00:00
|
|
|
locs->set_in(2, Location::RequiresFpuRegister());
|
2013-01-14 10:27:28 +00:00
|
|
|
break;
|
2013-11-04 21:56:59 +00:00
|
|
|
case kTypedDataInt32x4ArrayCid:
|
2013-04-11 12:50:46 +00:00
|
|
|
case kTypedDataFloat32x4ArrayCid:
|
2014-02-20 20:41:54 +00:00
|
|
|
case kTypedDataFloat64x2ArrayCid:
|
2013-04-11 12:50:46 +00:00
|
|
|
locs->set_in(2, Location::RequiresFpuRegister());
|
|
|
|
break;
|
2013-01-14 10:27:28 +00:00
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
return NULL;
|
2012-10-16 15:40:54 +00:00
|
|
|
}
|
2012-08-15 13:54:38 +00:00
|
|
|
return locs;
|
2012-06-20 23:19:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void StoreIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2014-05-27 18:27:54 +00:00
|
|
|
// The array register points to the backing store for external arrays.
|
|
|
|
const Register array = locs()->in(0).reg();
|
|
|
|
const Location index = locs()->in(1);
|
2012-10-16 15:40:54 +00:00
|
|
|
|
2014-05-27 18:27:54 +00:00
|
|
|
Address element_address = index.IsRegister()
|
2014-05-23 18:31:10 +00:00
|
|
|
? ElementAddressForRegIndex(IsExternal(), class_id(), index_scale(),
|
|
|
|
array, index.reg())
|
|
|
|
: ElementAddressForIntIndex(IsExternal(), class_id(), index_scale(),
|
|
|
|
array, Smi::Cast(index.constant()).Value());
|
2012-10-16 15:40:54 +00:00
|
|
|
|
2013-03-11 12:16:54 +00:00
|
|
|
if ((index_scale() == 1) && index.IsRegister()) {
|
|
|
|
__ SmiUntag(index.reg());
|
|
|
|
}
|
2013-01-14 10:27:28 +00:00
|
|
|
switch (class_id()) {
|
|
|
|
case kArrayCid:
|
|
|
|
if (ShouldEmitStoreBarrier()) {
|
|
|
|
Register value = locs()->in(2).reg();
|
|
|
|
__ StoreIntoObject(array, element_address, value);
|
|
|
|
} else if (locs()->in(2).IsConstant()) {
|
|
|
|
const Object& constant = locs()->in(2).constant();
|
|
|
|
__ StoreIntoObjectNoBarrier(array, element_address, constant);
|
|
|
|
} else {
|
|
|
|
Register value = locs()->in(2).reg();
|
|
|
|
__ StoreIntoObjectNoBarrier(array, element_address, value);
|
|
|
|
}
|
|
|
|
break;
|
2013-03-14 10:39:20 +00:00
|
|
|
case kTypedDataInt8ArrayCid:
|
|
|
|
case kTypedDataUint8ArrayCid:
|
|
|
|
case kExternalTypedDataUint8ArrayCid:
|
2013-05-08 20:03:33 +00:00
|
|
|
case kOneByteStringCid:
|
2013-01-14 10:27:28 +00:00
|
|
|
if (locs()->in(2).IsConstant()) {
|
|
|
|
const Smi& constant = Smi::Cast(locs()->in(2).constant());
|
|
|
|
__ movb(element_address,
|
|
|
|
Immediate(static_cast<int8_t>(constant.Value())));
|
|
|
|
} else {
|
|
|
|
ASSERT(locs()->in(2).reg() == EAX);
|
|
|
|
__ SmiUntag(EAX);
|
|
|
|
__ movb(element_address, AL);
|
|
|
|
}
|
|
|
|
break;
|
2013-03-14 10:39:20 +00:00
|
|
|
case kTypedDataUint8ClampedArrayCid:
|
|
|
|
case kExternalTypedDataUint8ClampedArrayCid: {
|
2013-01-17 10:43:46 +00:00
|
|
|
if (locs()->in(2).IsConstant()) {
|
|
|
|
const Smi& constant = Smi::Cast(locs()->in(2).constant());
|
|
|
|
intptr_t value = constant.Value();
|
|
|
|
// Clamp to 0x0 or 0xFF respectively.
|
|
|
|
if (value > 0xFF) {
|
|
|
|
value = 0xFF;
|
|
|
|
} else if (value < 0) {
|
|
|
|
value = 0;
|
|
|
|
}
|
|
|
|
__ movb(element_address,
|
|
|
|
Immediate(static_cast<int8_t>(value)));
|
|
|
|
} else {
|
|
|
|
ASSERT(locs()->in(2).reg() == EAX);
|
|
|
|
Label store_value, store_0xff;
|
|
|
|
__ SmiUntag(EAX);
|
|
|
|
__ cmpl(EAX, Immediate(0xFF));
|
|
|
|
__ j(BELOW_EQUAL, &store_value, Assembler::kNearJump);
|
|
|
|
// Clamp to 0x0 or 0xFF respectively.
|
|
|
|
__ j(GREATER, &store_0xff);
|
|
|
|
__ xorl(EAX, EAX);
|
|
|
|
__ jmp(&store_value, Assembler::kNearJump);
|
|
|
|
__ Bind(&store_0xff);
|
|
|
|
__ movl(EAX, Immediate(0xFF));
|
|
|
|
__ Bind(&store_value);
|
|
|
|
__ movb(element_address, AL);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2013-03-14 10:39:20 +00:00
|
|
|
case kTypedDataInt16ArrayCid:
|
|
|
|
case kTypedDataUint16ArrayCid: {
|
2013-01-21 16:19:42 +00:00
|
|
|
Register value = locs()->in(2).reg();
|
|
|
|
__ SmiUntag(value);
|
|
|
|
__ movw(element_address, value);
|
|
|
|
break;
|
|
|
|
}
|
2013-03-14 10:39:20 +00:00
|
|
|
case kTypedDataInt32ArrayCid:
|
|
|
|
case kTypedDataUint32ArrayCid:
|
2013-02-18 16:52:36 +00:00
|
|
|
if (value()->IsSmiValue()) {
|
|
|
|
ASSERT(RequiredInputRepresentation(2) == kTagged);
|
|
|
|
Register value = locs()->in(2).reg();
|
|
|
|
__ SmiUntag(value);
|
|
|
|
__ movl(element_address, value);
|
|
|
|
} else {
|
|
|
|
ASSERT(RequiredInputRepresentation(2) == kUnboxedMint);
|
2014-05-22 06:30:51 +00:00
|
|
|
PairLocation* value_pair = locs()->in(2).AsPairLocation();
|
|
|
|
Register value1 = value_pair->At(0).reg();
|
|
|
|
__ movl(element_address, value1);
|
2013-02-18 16:52:36 +00:00
|
|
|
}
|
2013-01-21 16:19:42 +00:00
|
|
|
break;
|
2013-03-14 10:39:20 +00:00
|
|
|
case kTypedDataFloat32ArrayCid:
|
2014-02-21 12:12:29 +00:00
|
|
|
__ movss(element_address, locs()->in(2).fpu_reg());
|
2013-01-14 10:27:28 +00:00
|
|
|
break;
|
2013-03-14 10:39:20 +00:00
|
|
|
case kTypedDataFloat64ArrayCid:
|
2013-01-18 00:34:20 +00:00
|
|
|
__ movsd(element_address, locs()->in(2).fpu_reg());
|
2013-01-14 10:27:28 +00:00
|
|
|
break;
|
2013-11-04 21:56:59 +00:00
|
|
|
case kTypedDataInt32x4ArrayCid:
|
2013-04-11 12:50:46 +00:00
|
|
|
case kTypedDataFloat32x4ArrayCid:
|
2014-02-20 20:41:54 +00:00
|
|
|
case kTypedDataFloat64x2ArrayCid:
|
2013-04-11 12:50:46 +00:00
|
|
|
__ movups(element_address, locs()->in(2).fpu_reg());
|
|
|
|
break;
|
2013-01-14 10:27:28 +00:00
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
2012-06-13 08:53:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-02 13:53:53 +00:00
|
|
|
LocationSummary* GuardFieldClassInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-03-19 20:15:10 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
2014-06-02 13:53:53 +00:00
|
|
|
|
|
|
|
const intptr_t value_cid = value()->Type()->ToCid();
|
|
|
|
const intptr_t field_cid = field().guarded_cid();
|
|
|
|
|
|
|
|
const bool emit_full_guard = !opt || (field_cid == kIllegalCid);
|
|
|
|
const bool needs_value_cid_temp_reg =
|
|
|
|
(value_cid == kDynamicCid) && (emit_full_guard || (field_cid != kSmiCid));
|
|
|
|
const bool needs_field_temp_reg = emit_full_guard;
|
|
|
|
|
2014-06-03 16:40:30 +00:00
|
|
|
intptr_t num_temps = 0;
|
2014-06-02 13:53:53 +00:00
|
|
|
if (needs_value_cid_temp_reg) {
|
2014-06-03 16:40:30 +00:00
|
|
|
num_temps++;
|
2013-03-19 20:15:10 +00:00
|
|
|
}
|
2014-06-02 13:53:53 +00:00
|
|
|
if (needs_field_temp_reg) {
|
2014-06-03 16:40:30 +00:00
|
|
|
num_temps++;
|
|
|
|
}
|
|
|
|
|
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, num_temps, LocationSummary::kNoCall);
|
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
|
|
|
|
|
|
|
for (intptr_t i = 0; i < num_temps; i++) {
|
|
|
|
summary->set_temp(i, Location::RequiresRegister());
|
2013-03-19 20:15:10 +00:00
|
|
|
}
|
2014-06-02 13:53:53 +00:00
|
|
|
|
2013-03-19 20:15:10 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-02 13:53:53 +00:00
|
|
|
void GuardFieldClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
const intptr_t value_cid = value()->Type()->ToCid();
|
2013-03-19 20:15:10 +00:00
|
|
|
const intptr_t field_cid = field().guarded_cid();
|
|
|
|
const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid;
|
|
|
|
|
|
|
|
if (field_cid == kDynamicCid) {
|
|
|
|
ASSERT(!compiler->is_optimizing());
|
|
|
|
return; // Nothing to emit.
|
|
|
|
}
|
|
|
|
|
2014-06-02 13:53:53 +00:00
|
|
|
const bool emit_full_guard =
|
|
|
|
!compiler->is_optimizing() || (field_cid == kIllegalCid);
|
|
|
|
|
|
|
|
const bool needs_value_cid_temp_reg =
|
|
|
|
(value_cid == kDynamicCid) && (emit_full_guard || (field_cid != kSmiCid));
|
2013-03-19 20:15:10 +00:00
|
|
|
|
2014-06-02 13:53:53 +00:00
|
|
|
const bool needs_field_temp_reg = emit_full_guard;
|
|
|
|
|
|
|
|
const Register value_reg = locs()->in(0).reg();
|
|
|
|
|
|
|
|
const Register value_cid_reg = needs_value_cid_temp_reg ?
|
2013-08-21 15:32:45 +00:00
|
|
|
locs()->temp(0).reg() : kNoRegister;
|
2013-03-19 20:15:10 +00:00
|
|
|
|
2014-06-02 13:53:53 +00:00
|
|
|
const Register field_reg = needs_field_temp_reg ?
|
2013-03-19 20:15:10 +00:00
|
|
|
locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister;
|
|
|
|
|
|
|
|
Label ok, fail_label;
|
|
|
|
|
|
|
|
Label* deopt = compiler->is_optimizing() ?
|
2014-04-25 23:45:14 +00:00
|
|
|
compiler->AddDeoptStub(deopt_id(), ICData::kDeoptGuardField) : NULL;
|
2013-03-19 20:15:10 +00:00
|
|
|
|
|
|
|
Label* fail = (deopt != NULL) ? deopt : &fail_label;
|
|
|
|
|
2014-06-02 13:53:53 +00:00
|
|
|
if (emit_full_guard) {
|
2013-03-19 20:15:10 +00:00
|
|
|
__ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
|
|
|
|
|
|
|
|
FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset());
|
|
|
|
FieldAddress field_nullability_operand(
|
|
|
|
field_reg, Field::is_nullable_offset());
|
|
|
|
|
|
|
|
if (value_cid == kDynamicCid) {
|
|
|
|
LoadValueCid(compiler, value_cid_reg, value_reg);
|
|
|
|
__ cmpl(value_cid_reg, field_cid_operand);
|
2014-06-02 13:53:53 +00:00
|
|
|
__ j(EQUAL, &ok);
|
2013-03-19 20:15:10 +00:00
|
|
|
__ cmpl(value_cid_reg, field_nullability_operand);
|
|
|
|
} else if (value_cid == kNullCid) {
|
2013-08-21 15:32:45 +00:00
|
|
|
// Value in graph known to be null.
|
|
|
|
// Compare with null.
|
2013-03-19 20:15:10 +00:00
|
|
|
__ cmpl(field_nullability_operand, Immediate(value_cid));
|
|
|
|
} else {
|
2013-08-21 15:32:45 +00:00
|
|
|
// Value in graph known to be non-null.
|
|
|
|
// Compare class id with guard field class id.
|
2013-03-19 20:15:10 +00:00
|
|
|
__ cmpl(field_cid_operand, Immediate(value_cid));
|
|
|
|
}
|
|
|
|
__ j(EQUAL, &ok);
|
|
|
|
|
2014-06-02 13:53:53 +00:00
|
|
|
// Check if the tracked state of the guarded field can be initialized
|
|
|
|
// inline. If the field needs length check we fall through to runtime
|
|
|
|
// which is responsible for computing offset of the length field
|
|
|
|
// based on the class id.
|
|
|
|
// Length guard will be emitted separately when needed via GuardFieldLength
|
|
|
|
// instruction after GuardFieldClass.
|
|
|
|
if (!field().needs_length_check()) {
|
|
|
|
// Uninitialized field can be handled inline. Check if the
|
|
|
|
// field is still unitialized.
|
|
|
|
__ cmpl(field_cid_operand, Immediate(kIllegalCid));
|
|
|
|
// Jump to failure path when guard field has been initialized and
|
|
|
|
// the field and value class ids do not not match.
|
|
|
|
__ j(NOT_EQUAL, fail);
|
2013-03-19 20:15:10 +00:00
|
|
|
|
2014-06-02 13:53:53 +00:00
|
|
|
if (value_cid == kDynamicCid) {
|
|
|
|
// Do not know value's class id.
|
|
|
|
__ movl(field_cid_operand, value_cid_reg);
|
|
|
|
__ movl(field_nullability_operand, value_cid_reg);
|
|
|
|
} else {
|
|
|
|
ASSERT(field_reg != kNoRegister);
|
|
|
|
__ movl(field_cid_operand, Immediate(value_cid));
|
|
|
|
__ movl(field_nullability_operand, Immediate(value_cid));
|
2013-08-21 15:32:45 +00:00
|
|
|
}
|
2014-06-02 13:53:53 +00:00
|
|
|
|
|
|
|
if (deopt == NULL) {
|
|
|
|
ASSERT(!compiler->is_optimizing());
|
|
|
|
__ jmp(&ok);
|
2013-08-21 15:32:45 +00:00
|
|
|
}
|
2013-03-19 20:15:10 +00:00
|
|
|
}
|
|
|
|
|
2013-12-05 11:17:06 +00:00
|
|
|
if (deopt == NULL) {
|
|
|
|
ASSERT(!compiler->is_optimizing());
|
|
|
|
__ Bind(fail);
|
|
|
|
|
|
|
|
__ cmpl(FieldAddress(field_reg, Field::guarded_cid_offset()),
|
|
|
|
Immediate(kDynamicCid));
|
|
|
|
__ j(EQUAL, &ok);
|
|
|
|
|
|
|
|
__ pushl(field_reg);
|
|
|
|
__ pushl(value_reg);
|
|
|
|
__ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
|
|
|
|
__ Drop(2); // Drop the field and the value.
|
|
|
|
}
|
2013-03-19 20:15:10 +00:00
|
|
|
} else {
|
2013-12-05 11:17:06 +00:00
|
|
|
ASSERT(compiler->is_optimizing());
|
|
|
|
ASSERT(deopt != NULL);
|
2014-06-02 13:53:53 +00:00
|
|
|
ASSERT(fail == deopt);
|
2013-08-21 15:32:45 +00:00
|
|
|
|
2014-06-02 13:53:53 +00:00
|
|
|
// Field guard class has been initialized and is known.
|
2013-03-19 20:15:10 +00:00
|
|
|
if (value_cid == kDynamicCid) {
|
2013-08-21 15:32:45 +00:00
|
|
|
// Value's class id is not known.
|
2013-03-19 20:15:10 +00:00
|
|
|
__ testl(value_reg, Immediate(kSmiTagMask));
|
|
|
|
|
|
|
|
if (field_cid != kSmiCid) {
|
|
|
|
__ j(ZERO, fail);
|
|
|
|
__ LoadClassId(value_cid_reg, value_reg);
|
|
|
|
__ cmpl(value_cid_reg, Immediate(field_cid));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (field().is_nullable() && (field_cid != kNullCid)) {
|
|
|
|
__ j(EQUAL, &ok);
|
2014-06-02 13:53:53 +00:00
|
|
|
if (field_cid != kSmiCid) {
|
|
|
|
__ cmpl(value_cid_reg, Immediate(kNullCid));
|
|
|
|
} else {
|
|
|
|
const Immediate& raw_null =
|
|
|
|
Immediate(reinterpret_cast<intptr_t>(Object::null()));
|
|
|
|
__ cmpl(value_reg, raw_null);
|
|
|
|
}
|
2013-03-19 20:15:10 +00:00
|
|
|
}
|
2013-12-05 11:17:06 +00:00
|
|
|
__ j(NOT_EQUAL, fail);
|
2013-03-19 20:15:10 +00:00
|
|
|
} else {
|
|
|
|
// Both value's and field's class id is known.
|
2014-06-02 13:53:53 +00:00
|
|
|
ASSERT((value_cid != field_cid) && (value_cid != nullability));
|
|
|
|
__ jmp(fail);
|
2013-03-19 20:15:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
__ Bind(&ok);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-02 13:53:53 +00:00
|
|
|
LocationSummary* GuardFieldLengthInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
if (!opt || (field().guarded_list_length() == Field::kUnknownFixedLength)) {
|
2014-06-03 16:40:30 +00:00
|
|
|
const intptr_t kNumTemps = 3;
|
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
2014-06-02 13:53:53 +00:00
|
|
|
// We need temporaries for field object, length offset and expected length.
|
2014-06-03 16:40:30 +00:00
|
|
|
summary->set_temp(0, Location::RequiresRegister());
|
|
|
|
summary->set_temp(1, Location::RequiresRegister());
|
|
|
|
summary->set_temp(2, Location::RequiresRegister());
|
|
|
|
return summary;
|
|
|
|
} else {
|
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, 0, LocationSummary::kNoCall);
|
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
|
|
|
return summary;
|
2014-06-02 13:53:53 +00:00
|
|
|
}
|
2014-06-03 16:40:30 +00:00
|
|
|
UNREACHABLE();
|
2014-06-02 13:53:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GuardFieldLengthInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
if (field().guarded_list_length() == Field::kNoFixedLength) {
|
|
|
|
ASSERT(!compiler->is_optimizing());
|
|
|
|
return; // Nothing to emit.
|
|
|
|
}
|
|
|
|
|
|
|
|
Label* deopt = compiler->is_optimizing() ?
|
|
|
|
compiler->AddDeoptStub(deopt_id(), ICData::kDeoptGuardField) : NULL;
|
|
|
|
|
|
|
|
const Register value_reg = locs()->in(0).reg();
|
|
|
|
|
|
|
|
if (!compiler->is_optimizing() ||
|
|
|
|
(field().guarded_list_length() == Field::kUnknownFixedLength)) {
|
|
|
|
const Register field_reg = locs()->temp(0).reg();
|
|
|
|
const Register offset_reg = locs()->temp(1).reg();
|
|
|
|
const Register length_reg = locs()->temp(2).reg();
|
|
|
|
|
|
|
|
Label ok;
|
|
|
|
|
|
|
|
__ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
|
|
|
|
|
|
|
|
__ movsxb(offset_reg, FieldAddress(field_reg,
|
|
|
|
Field::guarded_list_length_in_object_offset_offset()));
|
|
|
|
__ movl(length_reg, FieldAddress(field_reg,
|
|
|
|
Field::guarded_list_length_offset()));
|
|
|
|
|
|
|
|
__ cmpl(offset_reg, Immediate(0));
|
|
|
|
__ j(NEGATIVE, &ok);
|
|
|
|
|
|
|
|
// Load the length from the value. GuardFieldClass already verified that
|
|
|
|
// value's class matches guarded class id of the field.
|
|
|
|
// offset_reg contains offset already corrected by -kHeapObjectTag that is
|
|
|
|
// why we use Address instead of FieldAddress.
|
|
|
|
__ cmpl(length_reg, Address(value_reg, offset_reg, TIMES_1, 0));
|
|
|
|
|
|
|
|
if (deopt == NULL) {
|
|
|
|
__ j(EQUAL, &ok);
|
|
|
|
|
|
|
|
__ pushl(field_reg);
|
|
|
|
__ pushl(value_reg);
|
|
|
|
__ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
|
|
|
|
__ Drop(2); // Drop the field and the value.
|
|
|
|
} else {
|
|
|
|
__ j(NOT_EQUAL, deopt);
|
|
|
|
}
|
|
|
|
|
|
|
|
__ Bind(&ok);
|
|
|
|
} else {
|
|
|
|
ASSERT(compiler->is_optimizing());
|
|
|
|
ASSERT(field().guarded_list_length() >= 0);
|
|
|
|
ASSERT(field().guarded_list_length_in_object_offset() !=
|
|
|
|
Field::kUnknownLengthOffset);
|
|
|
|
|
|
|
|
__ cmpl(FieldAddress(value_reg,
|
|
|
|
field().guarded_list_length_in_object_offset()),
|
|
|
|
Immediate(Smi::RawValue(field().guarded_list_length())));
|
|
|
|
__ j(NOT_EQUAL, deopt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-12-16 15:11:31 +00:00
|
|
|
class StoreInstanceFieldSlowPath : public SlowPathCode {
|
|
|
|
public:
|
2014-01-31 16:45:23 +00:00
|
|
|
StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction,
|
|
|
|
const Class& cls)
|
|
|
|
: instruction_(instruction), cls_(cls) { }
|
2013-12-16 15:11:31 +00:00
|
|
|
|
|
|
|
virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
__ Comment("StoreInstanceFieldSlowPath");
|
|
|
|
__ Bind(entry_label());
|
|
|
|
const Code& stub =
|
2014-01-31 16:45:23 +00:00
|
|
|
Code::Handle(StubCode::GetAllocationStubForClass(cls_));
|
2014-05-27 10:15:50 +00:00
|
|
|
const ExternalLabel label(stub.EntryPoint());
|
2013-12-16 15:11:31 +00:00
|
|
|
|
|
|
|
LocationSummary* locs = instruction_->locs();
|
2014-03-21 14:40:30 +00:00
|
|
|
locs->live_registers()->Remove(locs->out(0));
|
2013-12-16 15:11:31 +00:00
|
|
|
compiler->SaveLiveRegisters(locs);
|
2014-01-21 23:46:26 +00:00
|
|
|
compiler->GenerateCall(Scanner::kNoSourcePos, // No token position.
|
2013-12-16 15:11:31 +00:00
|
|
|
&label,
|
|
|
|
PcDescriptors::kOther,
|
|
|
|
locs);
|
|
|
|
__ MoveRegister(locs->temp(0).reg(), EAX);
|
|
|
|
compiler->RestoreLiveRegisters(locs);
|
|
|
|
__ jmp(exit_label());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
StoreInstanceFieldInstr* instruction_;
|
2014-01-31 16:45:23 +00:00
|
|
|
const Class& cls_;
|
2013-12-16 15:11:31 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2012-08-24 23:06:12 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
2014-06-03 16:40:30 +00:00
|
|
|
const intptr_t kNumTemps =
|
|
|
|
(IsUnboxedStore() && opt) ? 2 :
|
|
|
|
((IsPotentialUnboxedStore()) ? 3 : 0);
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps,
|
2014-02-26 12:12:40 +00:00
|
|
|
!field().IsNull() &&
|
|
|
|
((field().guarded_cid() == kIllegalCid) || is_initialization_)
|
2013-12-16 15:11:31 +00:00
|
|
|
? LocationSummary::kCallOnSlowPath
|
|
|
|
: LocationSummary::kNoCall);
|
|
|
|
|
2012-08-24 23:06:12 +00:00
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
2013-12-16 15:11:31 +00:00
|
|
|
if (IsUnboxedStore() && opt) {
|
|
|
|
summary->set_in(1, Location::RequiresFpuRegister());
|
2014-06-03 16:40:30 +00:00
|
|
|
summary->set_temp(0, Location::RequiresRegister());
|
|
|
|
summary->set_temp(1, Location::RequiresRegister());
|
2013-12-16 15:11:31 +00:00
|
|
|
} else if (IsPotentialUnboxedStore()) {
|
|
|
|
summary->set_in(1, ShouldEmitStoreBarrier()
|
|
|
|
? Location::WritableRegister()
|
|
|
|
: Location::RequiresRegister());
|
2014-06-03 16:40:30 +00:00
|
|
|
summary->set_temp(0, Location::RequiresRegister());
|
|
|
|
summary->set_temp(1, Location::RequiresRegister());
|
|
|
|
summary->set_temp(2, opt ? Location::RequiresFpuRegister()
|
|
|
|
: Location::FpuRegisterLocation(XMM1));
|
2013-12-16 15:11:31 +00:00
|
|
|
} else {
|
|
|
|
summary->set_in(1, ShouldEmitStoreBarrier()
|
2012-09-13 10:49:01 +00:00
|
|
|
? Location::WritableRegister()
|
|
|
|
: Location::RegisterOrConstant(value()));
|
2013-12-16 15:11:31 +00:00
|
|
|
}
|
2012-08-24 23:06:12 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void StoreInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2013-12-16 15:11:31 +00:00
|
|
|
Label skip_store;
|
|
|
|
|
2012-08-24 23:06:12 +00:00
|
|
|
Register instance_reg = locs()->in(0).reg();
|
2013-12-16 15:11:31 +00:00
|
|
|
|
|
|
|
if (IsUnboxedStore() && compiler->is_optimizing()) {
|
|
|
|
XmmRegister value = locs()->in(1).fpu_reg();
|
|
|
|
Register temp = locs()->temp(0).reg();
|
|
|
|
Register temp2 = locs()->temp(1).reg();
|
2014-01-31 16:45:23 +00:00
|
|
|
const intptr_t cid = field().UnboxedFieldCid();
|
2013-12-16 15:11:31 +00:00
|
|
|
|
|
|
|
if (is_initialization_) {
|
2014-01-31 16:45:23 +00:00
|
|
|
const Class* cls = NULL;
|
|
|
|
switch (cid) {
|
|
|
|
case kDoubleCid:
|
|
|
|
cls = &compiler->double_class();
|
|
|
|
break;
|
2014-02-07 15:30:25 +00:00
|
|
|
case kFloat32x4Cid:
|
|
|
|
cls = &compiler->float32x4_class();
|
|
|
|
break;
|
2014-03-11 17:59:45 +00:00
|
|
|
case kFloat64x2Cid:
|
|
|
|
cls = &compiler->float64x2_class();
|
|
|
|
break;
|
2014-01-31 16:45:23 +00:00
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
2014-02-07 15:30:25 +00:00
|
|
|
|
2013-12-16 15:11:31 +00:00
|
|
|
StoreInstanceFieldSlowPath* slow_path =
|
2014-01-31 16:45:23 +00:00
|
|
|
new StoreInstanceFieldSlowPath(this, *cls);
|
2013-12-16 15:11:31 +00:00
|
|
|
compiler->AddSlowPathCode(slow_path);
|
|
|
|
|
2014-01-31 16:45:23 +00:00
|
|
|
__ TryAllocate(*cls,
|
2013-12-16 15:11:31 +00:00
|
|
|
slow_path->entry_label(),
|
|
|
|
Assembler::kFarJump,
|
2014-01-22 19:21:22 +00:00
|
|
|
temp,
|
|
|
|
temp2);
|
2013-12-16 15:11:31 +00:00
|
|
|
__ Bind(slow_path->exit_label());
|
|
|
|
__ movl(temp2, temp);
|
|
|
|
__ StoreIntoObject(instance_reg,
|
2014-02-26 12:12:40 +00:00
|
|
|
FieldAddress(instance_reg, offset_in_bytes_),
|
2013-12-16 15:11:31 +00:00
|
|
|
temp2);
|
|
|
|
} else {
|
2014-02-26 12:12:40 +00:00
|
|
|
__ movl(temp, FieldAddress(instance_reg, offset_in_bytes_));
|
2013-12-16 15:11:31 +00:00
|
|
|
}
|
2014-01-31 16:45:23 +00:00
|
|
|
switch (cid) {
|
|
|
|
case kDoubleCid:
|
2014-02-07 15:30:25 +00:00
|
|
|
__ Comment("UnboxedDoubleStoreInstanceFieldInstr");
|
|
|
|
__ movsd(FieldAddress(temp, Double::value_offset()), value);
|
|
|
|
break;
|
|
|
|
case kFloat32x4Cid:
|
|
|
|
__ Comment("UnboxedFloat32x4StoreInstanceFieldInstr");
|
|
|
|
__ movups(FieldAddress(temp, Float32x4::value_offset()), value);
|
2014-01-31 16:45:23 +00:00
|
|
|
break;
|
2014-03-11 17:59:45 +00:00
|
|
|
case kFloat64x2Cid:
|
|
|
|
__ Comment("UnboxedFloat64x2StoreInstanceFieldInstr");
|
|
|
|
__ movups(FieldAddress(temp, Float64x2::value_offset()), value);
|
|
|
|
break;
|
2014-01-31 16:45:23 +00:00
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
2013-12-16 15:11:31 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IsPotentialUnboxedStore()) {
|
|
|
|
Register value_reg = locs()->in(1).reg();
|
|
|
|
Register temp = locs()->temp(0).reg();
|
|
|
|
Register temp2 = locs()->temp(1).reg();
|
|
|
|
FpuRegister fpu_temp = locs()->temp(2).fpu_reg();
|
|
|
|
|
2014-01-31 16:45:23 +00:00
|
|
|
Label store_pointer;
|
|
|
|
Label store_double;
|
2014-02-07 15:30:25 +00:00
|
|
|
Label store_float32x4;
|
2014-03-11 17:59:45 +00:00
|
|
|
Label store_float64x2;
|
2014-01-31 16:45:23 +00:00
|
|
|
|
2013-12-16 15:11:31 +00:00
|
|
|
__ LoadObject(temp, Field::ZoneHandle(field().raw()));
|
2014-01-31 16:45:23 +00:00
|
|
|
|
2013-12-16 15:11:31 +00:00
|
|
|
__ cmpl(FieldAddress(temp, Field::is_nullable_offset()),
|
|
|
|
Immediate(kNullCid));
|
|
|
|
__ j(EQUAL, &store_pointer);
|
2014-01-31 16:45:23 +00:00
|
|
|
|
2013-12-18 15:46:39 +00:00
|
|
|
__ movzxb(temp2, FieldAddress(temp, Field::kind_bits_offset()));
|
|
|
|
__ testl(temp2, Immediate(1 << Field::kUnboxingCandidateBit));
|
|
|
|
__ j(ZERO, &store_pointer);
|
2013-12-16 15:11:31 +00:00
|
|
|
|
2014-01-31 16:45:23 +00:00
|
|
|
__ cmpl(FieldAddress(temp, Field::guarded_cid_offset()),
|
|
|
|
Immediate(kDoubleCid));
|
|
|
|
__ j(EQUAL, &store_double);
|
|
|
|
|
2014-02-07 15:30:25 +00:00
|
|
|
__ cmpl(FieldAddress(temp, Field::guarded_cid_offset()),
|
|
|
|
Immediate(kFloat32x4Cid));
|
|
|
|
__ j(EQUAL, &store_float32x4);
|
|
|
|
|
2014-03-11 17:59:45 +00:00
|
|
|
__ cmpl(FieldAddress(temp, Field::guarded_cid_offset()),
|
|
|
|
Immediate(kFloat64x2Cid));
|
|
|
|
__ j(EQUAL, &store_float64x2);
|
|
|
|
|
2014-01-31 16:45:23 +00:00
|
|
|
// Fall through.
|
|
|
|
__ jmp(&store_pointer);
|
|
|
|
|
2013-12-16 15:11:31 +00:00
|
|
|
|
|
|
|
if (!compiler->is_optimizing()) {
|
|
|
|
locs()->live_registers()->Add(locs()->in(0));
|
|
|
|
locs()->live_registers()->Add(locs()->in(1));
|
|
|
|
}
|
|
|
|
|
2014-02-07 15:30:25 +00:00
|
|
|
{
|
|
|
|
__ Bind(&store_double);
|
|
|
|
Label copy_double;
|
|
|
|
|
|
|
|
StoreInstanceFieldSlowPath* slow_path =
|
|
|
|
new StoreInstanceFieldSlowPath(this, compiler->double_class());
|
|
|
|
compiler->AddSlowPathCode(slow_path);
|
|
|
|
|
|
|
|
const Immediate& raw_null =
|
|
|
|
Immediate(reinterpret_cast<intptr_t>(Object::null()));
|
2014-02-26 12:12:40 +00:00
|
|
|
__ movl(temp, FieldAddress(instance_reg, offset_in_bytes_));
|
2014-02-07 15:30:25 +00:00
|
|
|
__ cmpl(temp, raw_null);
|
|
|
|
__ j(NOT_EQUAL, ©_double);
|
|
|
|
|
|
|
|
__ TryAllocate(compiler->double_class(),
|
|
|
|
slow_path->entry_label(),
|
|
|
|
Assembler::kFarJump,
|
|
|
|
temp,
|
|
|
|
temp2);
|
|
|
|
__ Bind(slow_path->exit_label());
|
|
|
|
__ movl(temp2, temp);
|
|
|
|
__ StoreIntoObject(instance_reg,
|
2014-02-26 12:12:40 +00:00
|
|
|
FieldAddress(instance_reg, offset_in_bytes_),
|
2014-02-07 15:30:25 +00:00
|
|
|
temp2);
|
|
|
|
|
|
|
|
__ Bind(©_double);
|
|
|
|
__ movsd(fpu_temp, FieldAddress(value_reg, Double::value_offset()));
|
|
|
|
__ movsd(FieldAddress(temp, Double::value_offset()), fpu_temp);
|
|
|
|
__ jmp(&skip_store);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
__ Bind(&store_float32x4);
|
|
|
|
Label copy_float32x4;
|
|
|
|
|
|
|
|
StoreInstanceFieldSlowPath* slow_path =
|
|
|
|
new StoreInstanceFieldSlowPath(this, compiler->float32x4_class());
|
|
|
|
compiler->AddSlowPathCode(slow_path);
|
|
|
|
|
|
|
|
const Immediate& raw_null =
|
|
|
|
Immediate(reinterpret_cast<intptr_t>(Object::null()));
|
2014-02-26 12:12:40 +00:00
|
|
|
__ movl(temp, FieldAddress(instance_reg, offset_in_bytes_));
|
2014-02-07 15:30:25 +00:00
|
|
|
__ cmpl(temp, raw_null);
|
|
|
|
__ j(NOT_EQUAL, ©_float32x4);
|
2013-12-16 15:11:31 +00:00
|
|
|
|
2014-02-07 15:30:25 +00:00
|
|
|
__ TryAllocate(compiler->float32x4_class(),
|
|
|
|
slow_path->entry_label(),
|
|
|
|
Assembler::kFarJump,
|
|
|
|
temp,
|
|
|
|
temp2);
|
|
|
|
__ Bind(slow_path->exit_label());
|
|
|
|
__ movl(temp2, temp);
|
|
|
|
__ StoreIntoObject(instance_reg,
|
2014-02-26 12:12:40 +00:00
|
|
|
FieldAddress(instance_reg, offset_in_bytes_),
|
2014-02-07 15:30:25 +00:00
|
|
|
temp2);
|
|
|
|
|
|
|
|
__ Bind(©_float32x4);
|
|
|
|
__ movups(fpu_temp, FieldAddress(value_reg, Float32x4::value_offset()));
|
|
|
|
__ movups(FieldAddress(temp, Float32x4::value_offset()), fpu_temp);
|
|
|
|
__ jmp(&skip_store);
|
|
|
|
}
|
2014-03-11 17:59:45 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
__ Bind(&store_float64x2);
|
|
|
|
Label copy_float64x2;
|
|
|
|
|
|
|
|
StoreInstanceFieldSlowPath* slow_path =
|
|
|
|
new StoreInstanceFieldSlowPath(this, compiler->float64x2_class());
|
|
|
|
compiler->AddSlowPathCode(slow_path);
|
|
|
|
|
|
|
|
const Immediate& raw_null =
|
|
|
|
Immediate(reinterpret_cast<intptr_t>(Object::null()));
|
|
|
|
__ movl(temp, FieldAddress(instance_reg, offset_in_bytes_));
|
|
|
|
__ cmpl(temp, raw_null);
|
|
|
|
__ j(NOT_EQUAL, ©_float64x2);
|
|
|
|
|
|
|
|
__ TryAllocate(compiler->float64x2_class(),
|
|
|
|
slow_path->entry_label(),
|
|
|
|
Assembler::kFarJump,
|
|
|
|
temp,
|
|
|
|
temp2);
|
|
|
|
__ Bind(slow_path->exit_label());
|
|
|
|
__ movl(temp2, temp);
|
|
|
|
__ StoreIntoObject(instance_reg,
|
|
|
|
FieldAddress(instance_reg, offset_in_bytes_),
|
|
|
|
temp2);
|
|
|
|
|
|
|
|
__ Bind(©_float64x2);
|
|
|
|
__ movups(fpu_temp, FieldAddress(value_reg, Float64x2::value_offset()));
|
|
|
|
__ movups(FieldAddress(temp, Float64x2::value_offset()), fpu_temp);
|
|
|
|
__ jmp(&skip_store);
|
|
|
|
}
|
|
|
|
|
2013-12-16 15:11:31 +00:00
|
|
|
__ Bind(&store_pointer);
|
|
|
|
}
|
|
|
|
|
2012-09-13 10:49:01 +00:00
|
|
|
if (ShouldEmitStoreBarrier()) {
|
|
|
|
Register value_reg = locs()->in(1).reg();
|
2012-08-24 23:06:12 +00:00
|
|
|
__ StoreIntoObject(instance_reg,
|
2014-02-26 12:12:40 +00:00
|
|
|
FieldAddress(instance_reg, offset_in_bytes_),
|
2013-03-22 11:28:13 +00:00
|
|
|
value_reg,
|
|
|
|
CanValueBeSmi());
|
2012-08-25 00:27:07 +00:00
|
|
|
} else {
|
2012-09-13 10:49:01 +00:00
|
|
|
if (locs()->in(1).IsConstant()) {
|
|
|
|
__ StoreIntoObjectNoBarrier(
|
|
|
|
instance_reg,
|
2014-02-26 12:12:40 +00:00
|
|
|
FieldAddress(instance_reg, offset_in_bytes_),
|
2012-09-13 10:49:01 +00:00
|
|
|
locs()->in(1).constant());
|
|
|
|
} else {
|
|
|
|
Register value_reg = locs()->in(1).reg();
|
|
|
|
__ StoreIntoObjectNoBarrier(instance_reg,
|
2014-02-26 12:12:40 +00:00
|
|
|
FieldAddress(instance_reg, offset_in_bytes_), value_reg);
|
2012-09-13 10:49:01 +00:00
|
|
|
}
|
2012-08-24 23:06:12 +00:00
|
|
|
}
|
2013-12-16 15:11:31 +00:00
|
|
|
__ Bind(&skip_store);
|
2012-08-24 23:06:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* LoadStaticFieldInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-06-14 18:15:49 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-06-14 18:15:49 +00:00
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
|
|
|
// By specifying same register as input, our simple register allocator can
|
|
|
|
// generate better code.
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2013-06-14 18:15:49 +00:00
|
|
|
return summary;
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-06-18 06:55:32 +00:00
|
|
|
// When the parser is building an implicit static getter for optimization,
|
|
|
|
// it can generate a function body where deoptimization ids do not line up
|
|
|
|
// with the unoptimized code.
|
|
|
|
//
|
|
|
|
// This is safe only so long as LoadStaticFieldInstr cannot deoptimize.
|
2012-09-05 17:04:49 +00:00
|
|
|
void LoadStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2013-06-14 18:15:49 +00:00
|
|
|
Register field = locs()->in(0).reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
Register result = locs()->out(0).reg();
|
2013-06-14 18:15:49 +00:00
|
|
|
__ movl(result, FieldAddress(field, Field::value_offset()));
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* StoreStaticFieldInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
|
|
|
LocationSummary* locs = new(isolate) LocationSummary(
|
|
|
|
isolate, 1, 1, LocationSummary::kNoCall);
|
2012-09-11 12:50:52 +00:00
|
|
|
locs->set_in(0, value()->NeedsStoreBuffer() ? Location::WritableRegister()
|
|
|
|
: Location::RequiresRegister());
|
2012-08-24 23:06:12 +00:00
|
|
|
locs->set_temp(0, Location::RequiresRegister());
|
|
|
|
return locs;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void StoreStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-08-24 23:06:12 +00:00
|
|
|
Register value = locs()->in(0).reg();
|
|
|
|
Register temp = locs()->temp(0).reg();
|
|
|
|
|
|
|
|
__ LoadObject(temp, field());
|
2012-08-25 00:27:07 +00:00
|
|
|
if (this->value()->NeedsStoreBuffer()) {
|
2013-04-11 21:27:19 +00:00
|
|
|
__ StoreIntoObject(temp,
|
|
|
|
FieldAddress(temp, Field::value_offset()), value, CanValueBeSmi());
|
2012-08-25 00:27:07 +00:00
|
|
|
} else {
|
|
|
|
__ StoreIntoObjectNoBarrier(
|
|
|
|
temp, FieldAddress(temp, Field::value_offset()), value);
|
2012-08-24 23:06:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* InstanceOfInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2012-06-25 23:50:37 +00:00
|
|
|
const intptr_t kNumInputs = 3;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, 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));
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::RegisterLocation(EAX));
|
2012-06-04 17:06:43 +00:00
|
|
|
return summary;
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void InstanceOfInstr::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-31 15:46:10 +00:00
|
|
|
compiler->GenerateInstanceOf(token_pos(),
|
2013-01-29 12:38:27 +00:00
|
|
|
deopt_id(),
|
2012-06-04 17:06:43 +00:00
|
|
|
type(),
|
2012-08-14 06:59:24 +00:00
|
|
|
negate_result(),
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
2014-03-21 14:40:30 +00:00
|
|
|
ASSERT(locs()->out(0).reg() == EAX);
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-15 21:40:10 +00:00
|
|
|
// TODO(srdjan): In case of constant inputs make CreateArray kNoCall and
|
|
|
|
// use slow path stub.
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* CreateArrayInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2014-01-31 13:26:48 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
2012-08-07 10:34:39 +00:00
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* locs = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kCall);
|
2012-08-07 10:34:39 +00:00
|
|
|
locs->set_in(0, Location::RegisterLocation(ECX));
|
2014-01-31 13:26:48 +00:00
|
|
|
locs->set_in(1, Location::RegisterLocation(EDX));
|
2014-03-21 14:40:30 +00:00
|
|
|
locs->set_out(0, Location::RegisterLocation(EAX));
|
2012-08-07 10:34:39 +00:00
|
|
|
return locs;
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-15 21:40:10 +00:00
|
|
|
// Inlines array allocation for known constant values.
|
|
|
|
static void InlineArrayAllocation(FlowGraphCompiler* compiler,
|
|
|
|
intptr_t num_elements,
|
|
|
|
Label* slow_path,
|
|
|
|
Label* done) {
|
|
|
|
const Register kLengthReg = EDX;
|
|
|
|
const Register kElemTypeReg = ECX;
|
|
|
|
const intptr_t kArraySize = Array::InstanceSize(num_elements);
|
|
|
|
Isolate* isolate = Isolate::Current();
|
|
|
|
Heap* heap = isolate->heap();
|
|
|
|
|
|
|
|
__ movl(EAX, Address::Absolute(heap->TopAddress()));
|
|
|
|
__ movl(EBX, EAX);
|
|
|
|
|
|
|
|
__ addl(EBX, Immediate(kArraySize));
|
|
|
|
__ j(CARRY, slow_path);
|
|
|
|
|
|
|
|
// Check if the allocation fits into the remaining space.
|
|
|
|
// EAX: potential new object start.
|
|
|
|
// EBX: potential next object start.
|
|
|
|
__ cmpl(EBX, Address::Absolute(heap->EndAddress()));
|
|
|
|
__ j(ABOVE_EQUAL, slow_path);
|
|
|
|
|
|
|
|
// Successfully allocated the object(s), now update top to point to
|
|
|
|
// next object start and initialize the object.
|
|
|
|
__ movl(Address::Absolute(heap->TopAddress()), EBX);
|
|
|
|
__ addl(EAX, Immediate(kHeapObjectTag));
|
|
|
|
__ UpdateAllocationStatsWithSize(kArrayCid, kArraySize, kNoRegister);
|
|
|
|
|
|
|
|
// Initialize the tags.
|
|
|
|
// EAX: new object start as a tagged pointer.
|
|
|
|
{
|
|
|
|
uword tags = 0;
|
|
|
|
tags = RawObject::ClassIdTag::update(kArrayCid, tags);
|
|
|
|
tags = RawObject::SizeTag::update(kArraySize, tags);
|
|
|
|
__ movl(FieldAddress(EAX, Array::tags_offset()), Immediate(tags));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Store the type argument field.
|
|
|
|
__ StoreIntoObjectNoBarrier(EAX,
|
|
|
|
FieldAddress(EAX, Array::type_arguments_offset()),
|
|
|
|
kElemTypeReg);
|
|
|
|
|
|
|
|
// Set the length field.
|
|
|
|
__ StoreIntoObjectNoBarrier(EAX,
|
|
|
|
FieldAddress(EAX, Array::length_offset()),
|
|
|
|
kLengthReg);
|
|
|
|
|
|
|
|
// Initialize all array elements to raw_null.
|
|
|
|
// EAX: new object start as a tagged pointer.
|
|
|
|
// EBX: new object end address.
|
|
|
|
// EDI: iterator which initially points to the start of the variable
|
|
|
|
// data area to be initialized.
|
|
|
|
const Immediate& raw_null =
|
|
|
|
Immediate(reinterpret_cast<intptr_t>(Object::null()));
|
|
|
|
__ leal(EDI, FieldAddress(EAX, sizeof(RawArray)));
|
|
|
|
Label init_loop;
|
|
|
|
__ Bind(&init_loop);
|
|
|
|
__ cmpl(EDI, EBX);
|
|
|
|
__ j(ABOVE_EQUAL, done, Assembler::kNearJump);
|
|
|
|
__ movl(Address(EDI, 0), raw_null);
|
|
|
|
__ addl(EDI, Immediate(kWordSize));
|
|
|
|
__ jmp(&init_loop, Assembler::kNearJump);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-06-22 01:24:36 +00:00
|
|
|
// Allocate the array. EDX = length, ECX = element type.
|
2014-05-15 21:40:10 +00:00
|
|
|
const Register kLengthReg = EDX;
|
|
|
|
const Register kElemTypeReg = ECX;
|
|
|
|
const Register kResultReg = EAX;
|
|
|
|
ASSERT(locs()->in(0).reg() == kElemTypeReg);
|
|
|
|
ASSERT(locs()->in(1).reg() == kLengthReg);
|
|
|
|
|
|
|
|
Label slow_path, done;
|
|
|
|
if (num_elements()->BindsToConstant() &&
|
|
|
|
num_elements()->BoundConstant().IsSmi()) {
|
|
|
|
const intptr_t length = Smi::Cast(num_elements()->BoundConstant()).Value();
|
|
|
|
if ((length >= 0) && (length <= Array::kMaxElements)) {
|
|
|
|
Label slow_path, done;
|
|
|
|
InlineArrayAllocation(compiler, length, &slow_path, &done);
|
|
|
|
__ Bind(&slow_path);
|
|
|
|
__ PushObject(Object::ZoneHandle()); // Make room for the result.
|
|
|
|
__ pushl(kLengthReg);
|
|
|
|
__ pushl(kElemTypeReg);
|
|
|
|
compiler->GenerateRuntimeCall(token_pos(),
|
|
|
|
deopt_id(),
|
|
|
|
kAllocateArrayRuntimeEntry,
|
|
|
|
2,
|
|
|
|
locs());
|
|
|
|
__ Drop(2);
|
|
|
|
__ popl(kResultReg);
|
|
|
|
__ Bind(&done);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
__ Bind(&slow_path);
|
2012-06-22 20:37:01 +00:00
|
|
|
compiler->GenerateCall(token_pos(),
|
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());
|
2014-05-15 21:40:10 +00:00
|
|
|
__ Bind(&done);
|
|
|
|
ASSERT(locs()->out(0).reg() == kResultReg);
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-12-16 15:11:31 +00:00
|
|
|
class BoxDoubleSlowPath : public SlowPathCode {
|
|
|
|
public:
|
|
|
|
explicit BoxDoubleSlowPath(Instruction* instruction)
|
|
|
|
: instruction_(instruction) { }
|
|
|
|
|
|
|
|
virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
__ Comment("BoxDoubleSlowPath");
|
|
|
|
__ Bind(entry_label());
|
|
|
|
const Class& double_class = compiler->double_class();
|
|
|
|
const Code& stub =
|
|
|
|
Code::Handle(StubCode::GetAllocationStubForClass(double_class));
|
2014-05-27 10:15:50 +00:00
|
|
|
const ExternalLabel label(stub.EntryPoint());
|
2013-12-16 15:11:31 +00:00
|
|
|
|
|
|
|
LocationSummary* locs = instruction_->locs();
|
2014-03-21 14:40:30 +00:00
|
|
|
locs->live_registers()->Remove(locs->out(0));
|
2013-12-16 15:11:31 +00:00
|
|
|
|
|
|
|
compiler->SaveLiveRegisters(locs);
|
2014-01-21 23:46:26 +00:00
|
|
|
compiler->GenerateCall(Scanner::kNoSourcePos, // No token position.
|
2013-12-16 15:11:31 +00:00
|
|
|
&label,
|
|
|
|
PcDescriptors::kOther,
|
|
|
|
locs);
|
2014-03-21 14:40:30 +00:00
|
|
|
__ MoveRegister(locs->out(0).reg(), EAX);
|
2013-12-16 15:11:31 +00:00
|
|
|
compiler->RestoreLiveRegisters(locs);
|
|
|
|
|
|
|
|
__ jmp(exit_label());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Instruction* instruction_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2014-02-07 15:30:25 +00:00
|
|
|
class BoxFloat32x4SlowPath : public SlowPathCode {
|
|
|
|
public:
|
|
|
|
explicit BoxFloat32x4SlowPath(Instruction* instruction)
|
|
|
|
: instruction_(instruction) { }
|
|
|
|
|
|
|
|
virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
__ Comment("BoxFloat32x4SlowPath");
|
|
|
|
__ Bind(entry_label());
|
|
|
|
const Class& float32x4_class = compiler->float32x4_class();
|
|
|
|
const Code& stub =
|
|
|
|
Code::Handle(StubCode::GetAllocationStubForClass(float32x4_class));
|
2014-05-27 10:15:50 +00:00
|
|
|
const ExternalLabel label(stub.EntryPoint());
|
2014-02-07 15:30:25 +00:00
|
|
|
|
|
|
|
LocationSummary* locs = instruction_->locs();
|
2014-03-21 14:40:30 +00:00
|
|
|
locs->live_registers()->Remove(locs->out(0));
|
2014-02-07 15:30:25 +00:00
|
|
|
|
|
|
|
compiler->SaveLiveRegisters(locs);
|
|
|
|
compiler->GenerateCall(Scanner::kNoSourcePos, // No token position.
|
|
|
|
&label,
|
|
|
|
PcDescriptors::kOther,
|
|
|
|
locs);
|
2014-03-21 14:40:30 +00:00
|
|
|
__ MoveRegister(locs->out(0).reg(), EAX);
|
2014-02-07 15:30:25 +00:00
|
|
|
compiler->RestoreLiveRegisters(locs);
|
|
|
|
|
|
|
|
__ jmp(exit_label());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Instruction* instruction_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2014-02-20 20:41:54 +00:00
|
|
|
class BoxFloat64x2SlowPath : public SlowPathCode {
|
|
|
|
public:
|
|
|
|
explicit BoxFloat64x2SlowPath(Instruction* instruction)
|
|
|
|
: instruction_(instruction) { }
|
|
|
|
|
|
|
|
virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
__ Comment("BoxFloat64x2SlowPath");
|
|
|
|
__ Bind(entry_label());
|
|
|
|
const Class& float64x2_class = compiler->float64x2_class();
|
|
|
|
const Code& stub =
|
|
|
|
Code::Handle(StubCode::GetAllocationStubForClass(float64x2_class));
|
2014-05-27 10:15:50 +00:00
|
|
|
const ExternalLabel label(stub.EntryPoint());
|
2014-02-20 20:41:54 +00:00
|
|
|
|
|
|
|
LocationSummary* locs = instruction_->locs();
|
2014-03-21 14:40:30 +00:00
|
|
|
locs->live_registers()->Remove(locs->out(0));
|
2014-02-20 20:41:54 +00:00
|
|
|
|
|
|
|
compiler->SaveLiveRegisters(locs);
|
|
|
|
compiler->GenerateCall(Scanner::kNoSourcePos, // No token position.
|
|
|
|
&label,
|
|
|
|
PcDescriptors::kOther,
|
|
|
|
locs);
|
2014-03-21 14:40:30 +00:00
|
|
|
__ MoveRegister(locs->out(0).reg(), EAX);
|
2014-02-20 20:41:54 +00:00
|
|
|
compiler->RestoreLiveRegisters(locs);
|
|
|
|
|
|
|
|
__ jmp(exit_label());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Instruction* instruction_;
|
|
|
|
};
|
|
|
|
|
2014-02-07 15:30:25 +00:00
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* LoadFieldInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-12-16 15:11:31 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
2014-06-03 16:40:30 +00:00
|
|
|
const intptr_t kNumTemps =
|
|
|
|
(IsUnboxedLoad() && opt) ? 1 :
|
|
|
|
((IsPotentialUnboxedLoad()) ? 2 : 0);
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* locs = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps,
|
2013-12-16 15:11:31 +00:00
|
|
|
(opt && !IsPotentialUnboxedLoad())
|
|
|
|
? LocationSummary::kNoCall
|
|
|
|
: LocationSummary::kCallOnSlowPath);
|
|
|
|
|
|
|
|
locs->set_in(0, Location::RequiresRegister());
|
|
|
|
|
|
|
|
if (IsUnboxedLoad() && opt) {
|
2014-06-03 16:40:30 +00:00
|
|
|
locs->set_temp(0, Location::RequiresRegister());
|
2013-12-16 15:11:31 +00:00
|
|
|
} else if (IsPotentialUnboxedLoad()) {
|
2014-06-03 16:40:30 +00:00
|
|
|
locs->set_temp(0, opt ? Location::RequiresFpuRegister()
|
|
|
|
: Location::FpuRegisterLocation(XMM1));
|
|
|
|
locs->set_temp(1, Location::RequiresRegister());
|
2013-12-16 15:11:31 +00:00
|
|
|
}
|
2014-03-21 14:40:30 +00:00
|
|
|
locs->set_out(0, Location::RequiresRegister());
|
2013-12-16 15:11:31 +00:00
|
|
|
return locs;
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-12 17:43:37 +00:00
|
|
|
void LoadFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-06-19 21:49:11 +00:00
|
|
|
Register instance_reg = locs()->in(0).reg();
|
2013-12-16 15:11:31 +00:00
|
|
|
if (IsUnboxedLoad() && compiler->is_optimizing()) {
|
2014-03-21 14:40:30 +00:00
|
|
|
XmmRegister result = locs()->out(0).fpu_reg();
|
2013-12-16 15:11:31 +00:00
|
|
|
Register temp = locs()->temp(0).reg();
|
|
|
|
__ movl(temp, FieldAddress(instance_reg, offset_in_bytes()));
|
2014-01-31 16:45:23 +00:00
|
|
|
const intptr_t cid = field()->UnboxedFieldCid();
|
|
|
|
switch (cid) {
|
|
|
|
case kDoubleCid:
|
2014-02-07 15:30:25 +00:00
|
|
|
__ Comment("UnboxedDoubleLoadFieldInstr");
|
2014-01-31 16:45:23 +00:00
|
|
|
__ movsd(result, FieldAddress(temp, Double::value_offset()));
|
|
|
|
break;
|
2014-02-07 15:30:25 +00:00
|
|
|
case kFloat32x4Cid:
|
|
|
|
__ Comment("UnboxedFloat32x4LoadFieldInstr");
|
|
|
|
__ movups(result, FieldAddress(temp, Float32x4::value_offset()));
|
|
|
|
break;
|
2014-03-11 17:59:45 +00:00
|
|
|
case kFloat64x2Cid:
|
|
|
|
__ Comment("UnboxedFloat64x2LoadFieldInstr");
|
|
|
|
__ movups(result, FieldAddress(temp, Float64x2::value_offset()));
|
|
|
|
break;
|
2014-01-31 16:45:23 +00:00
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
2013-12-16 15:11:31 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Label done;
|
2014-03-21 14:40:30 +00:00
|
|
|
Register result = locs()->out(0).reg();
|
2013-12-16 15:11:31 +00:00
|
|
|
if (IsPotentialUnboxedLoad()) {
|
|
|
|
Register temp = locs()->temp(1).reg();
|
|
|
|
XmmRegister value = locs()->temp(0).fpu_reg();
|
|
|
|
|
2014-02-07 15:30:25 +00:00
|
|
|
|
2013-12-16 15:11:31 +00:00
|
|
|
Label load_pointer;
|
2014-01-31 16:45:23 +00:00
|
|
|
Label load_double;
|
2014-02-07 15:30:25 +00:00
|
|
|
Label load_float32x4;
|
2014-03-11 17:59:45 +00:00
|
|
|
Label load_float64x2;
|
2014-02-07 15:30:25 +00:00
|
|
|
|
2013-12-16 15:11:31 +00:00
|
|
|
__ LoadObject(result, Field::ZoneHandle(field()->raw()));
|
|
|
|
|
|
|
|
FieldAddress field_cid_operand(result, Field::guarded_cid_offset());
|
|
|
|
FieldAddress field_nullability_operand(result, Field::is_nullable_offset());
|
|
|
|
|
|
|
|
__ cmpl(field_nullability_operand, Immediate(kNullCid));
|
|
|
|
__ j(EQUAL, &load_pointer);
|
|
|
|
|
2014-01-31 16:45:23 +00:00
|
|
|
__ cmpl(field_cid_operand, Immediate(kDoubleCid));
|
|
|
|
__ j(EQUAL, &load_double);
|
|
|
|
|
2014-02-07 15:30:25 +00:00
|
|
|
__ cmpl(field_cid_operand, Immediate(kFloat32x4Cid));
|
|
|
|
__ j(EQUAL, &load_float32x4);
|
|
|
|
|
2014-03-11 17:59:45 +00:00
|
|
|
__ cmpl(field_cid_operand, Immediate(kFloat64x2Cid));
|
|
|
|
__ j(EQUAL, &load_float64x2);
|
|
|
|
|
2014-01-31 16:45:23 +00:00
|
|
|
// Fall through.
|
|
|
|
__ jmp(&load_pointer);
|
|
|
|
|
2013-12-16 15:11:31 +00:00
|
|
|
if (!compiler->is_optimizing()) {
|
|
|
|
locs()->live_registers()->Add(locs()->in(0));
|
|
|
|
}
|
|
|
|
|
2014-02-07 15:30:25 +00:00
|
|
|
{
|
|
|
|
__ Bind(&load_double);
|
|
|
|
BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this);
|
|
|
|
compiler->AddSlowPathCode(slow_path);
|
|
|
|
|
|
|
|
__ TryAllocate(compiler->double_class(),
|
|
|
|
slow_path->entry_label(),
|
|
|
|
Assembler::kFarJump,
|
|
|
|
result,
|
|
|
|
temp);
|
|
|
|
__ Bind(slow_path->exit_label());
|
|
|
|
__ movl(temp, FieldAddress(instance_reg, offset_in_bytes()));
|
|
|
|
__ movsd(value, FieldAddress(temp, Double::value_offset()));
|
|
|
|
__ movsd(FieldAddress(result, Double::value_offset()), value);
|
|
|
|
__ jmp(&done);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
__ Bind(&load_float32x4);
|
|
|
|
|
|
|
|
BoxFloat32x4SlowPath* slow_path = new BoxFloat32x4SlowPath(this);
|
|
|
|
compiler->AddSlowPathCode(slow_path);
|
2014-01-31 16:45:23 +00:00
|
|
|
|
2014-02-07 15:30:25 +00:00
|
|
|
__ TryAllocate(compiler->float32x4_class(),
|
|
|
|
slow_path->entry_label(),
|
|
|
|
Assembler::kFarJump,
|
|
|
|
result,
|
|
|
|
temp);
|
|
|
|
__ Bind(slow_path->exit_label());
|
|
|
|
__ movl(temp, FieldAddress(instance_reg, offset_in_bytes()));
|
|
|
|
__ movups(value, FieldAddress(temp, Float32x4::value_offset()));
|
|
|
|
__ movups(FieldAddress(result, Float32x4::value_offset()), value);
|
|
|
|
__ jmp(&done);
|
|
|
|
}
|
2014-01-31 16:45:23 +00:00
|
|
|
|
2014-03-11 17:59:45 +00:00
|
|
|
{
|
|
|
|
__ Bind(&load_float64x2);
|
|
|
|
|
|
|
|
BoxFloat64x2SlowPath* slow_path = new BoxFloat64x2SlowPath(this);
|
|
|
|
compiler->AddSlowPathCode(slow_path);
|
|
|
|
|
|
|
|
__ TryAllocate(compiler->float64x2_class(),
|
|
|
|
slow_path->entry_label(),
|
|
|
|
Assembler::kFarJump,
|
|
|
|
result,
|
|
|
|
temp);
|
|
|
|
__ Bind(slow_path->exit_label());
|
|
|
|
__ movl(temp, FieldAddress(instance_reg, offset_in_bytes()));
|
|
|
|
__ movups(value, FieldAddress(temp, Float64x2::value_offset()));
|
|
|
|
__ movups(FieldAddress(result, Float64x2::value_offset()), value);
|
|
|
|
__ jmp(&done);
|
|
|
|
}
|
|
|
|
|
2013-12-16 15:11:31 +00:00
|
|
|
__ Bind(&load_pointer);
|
|
|
|
}
|
|
|
|
__ movl(result, FieldAddress(instance_reg, offset_in_bytes()));
|
|
|
|
__ Bind(&done);
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* InstantiateTypeInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-07-09 19:35:56 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* locs = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kCall);
|
2013-07-09 19:35:56 +00:00
|
|
|
locs->set_in(0, Location::RegisterLocation(EAX));
|
2014-03-21 14:40:30 +00:00
|
|
|
locs->set_out(0, Location::RegisterLocation(EAX));
|
2013-07-09 19:35:56 +00:00
|
|
|
return locs;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void InstantiateTypeInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
Register instantiator_reg = locs()->in(0).reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
Register result_reg = locs()->out(0).reg();
|
2013-07-09 19:35:56 +00:00
|
|
|
|
2014-02-07 19:54:33 +00:00
|
|
|
// 'instantiator_reg' is the instantiator TypeArguments object (or null).
|
2013-07-09 19:35:56 +00:00
|
|
|
// A runtime call to instantiate the type is required.
|
|
|
|
__ PushObject(Object::ZoneHandle()); // Make room for the result.
|
|
|
|
__ PushObject(type());
|
|
|
|
__ pushl(instantiator_reg); // Push instantiator type arguments.
|
2013-10-25 10:17:10 +00:00
|
|
|
compiler->GenerateRuntimeCall(token_pos(),
|
2013-07-09 19:35:56 +00:00
|
|
|
deopt_id(),
|
|
|
|
kInstantiateTypeRuntimeEntry,
|
2013-08-28 23:07:14 +00:00
|
|
|
2,
|
2013-07-09 19:35:56 +00:00
|
|
|
locs());
|
|
|
|
__ Drop(2); // Drop instantiator and uninstantiated type.
|
|
|
|
__ popl(result_reg); // Pop instantiated type.
|
|
|
|
ASSERT(instantiator_reg == result_reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-12-16 15:11:31 +00:00
|
|
|
LocationSummary* InstantiateTypeArgumentsInstr::MakeLocationSummary(
|
2014-05-23 12:07:33 +00:00
|
|
|
Isolate* isolate, bool opt) const {
|
2012-06-04 15:31:13 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
2013-04-26 00:04:13 +00:00
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* locs = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kCall);
|
2012-07-24 17:19:20 +00:00
|
|
|
locs->set_in(0, Location::RegisterLocation(EAX));
|
2014-03-21 14:40:30 +00:00
|
|
|
locs->set_out(0, Location::RegisterLocation(EAX));
|
2012-06-04 15:31:13 +00:00
|
|
|
return locs;
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void InstantiateTypeArgumentsInstr::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();
|
2014-03-21 14:40:30 +00:00
|
|
|
Register result_reg = locs()->out(0).reg();
|
2014-02-14 13:03:35 +00:00
|
|
|
ASSERT(instantiator_reg == EAX);
|
|
|
|
ASSERT(instantiator_reg == result_reg);
|
2012-06-04 15:31:13 +00:00
|
|
|
|
2014-02-07 19:54:33 +00:00
|
|
|
// 'instantiator_reg' is the instantiator TypeArguments object (or null).
|
2013-05-27 10:19:49 +00:00
|
|
|
ASSERT(!type_arguments().IsUninstantiatedIdentity() &&
|
|
|
|
!type_arguments().CanShareInstantiatorTypeArguments(
|
|
|
|
instantiator_class()));
|
|
|
|
// 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);
|
|
|
|
}
|
2014-02-14 13:03:35 +00:00
|
|
|
// Lookup cache before calling runtime.
|
|
|
|
// TODO(fschneider): Consider moving this into a shared stub to reduce
|
|
|
|
// generated code size.
|
|
|
|
__ LoadObject(EDI, type_arguments());
|
|
|
|
__ movl(EDI, FieldAddress(EDI, TypeArguments::instantiations_offset()));
|
|
|
|
__ leal(EDI, FieldAddress(EDI, Array::data_offset()));
|
2014-02-18 19:30:03 +00:00
|
|
|
// The instantiations cache is initialized with Object::zero_array() and is
|
|
|
|
// therefore guaranteed to contain kNoInstantiator. No length check needed.
|
2014-02-14 13:03:35 +00:00
|
|
|
Label loop, found, slow_case;
|
|
|
|
__ Bind(&loop);
|
|
|
|
__ movl(EDX, Address(EDI, 0 * kWordSize)); // Cached instantiator.
|
|
|
|
__ cmpl(EDX, EAX);
|
|
|
|
__ j(EQUAL, &found, Assembler::kNearJump);
|
|
|
|
__ addl(EDI, Immediate(2 * kWordSize));
|
2014-02-18 19:30:03 +00:00
|
|
|
__ cmpl(EDX, Immediate(Smi::RawValue(StubCode::kNoInstantiator)));
|
|
|
|
__ j(NOT_EQUAL, &loop, Assembler::kNearJump);
|
|
|
|
__ jmp(&slow_case, Assembler::kNearJump);
|
2014-02-14 13:03:35 +00:00
|
|
|
__ Bind(&found);
|
|
|
|
__ movl(EAX, Address(EDI, 1 * kWordSize)); // Cached instantiated args.
|
2014-02-18 19:30:03 +00:00
|
|
|
__ jmp(&type_arguments_instantiated, Assembler::kNearJump);
|
2014-02-14 13:03:35 +00:00
|
|
|
|
|
|
|
__ Bind(&slow_case);
|
2013-05-27 10:19:49 +00:00
|
|
|
// Instantiate non-null type arguments.
|
|
|
|
// 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.
|
2013-10-25 10:17:10 +00:00
|
|
|
compiler->GenerateRuntimeCall(token_pos(),
|
2013-05-27 10:19:49 +00:00
|
|
|
deopt_id(),
|
|
|
|
kInstantiateTypeArgumentsRuntimeEntry,
|
2013-08-28 23:07:14 +00:00
|
|
|
2,
|
2013-05-27 10:19:49 +00:00
|
|
|
locs());
|
|
|
|
__ Drop(2); // Drop instantiator and uninstantiated type arguments.
|
|
|
|
__ popl(result_reg); // Pop instantiated type arguments.
|
|
|
|
__ Bind(&type_arguments_instantiated);
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* AllocateContextInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2014-03-03 10:24:59 +00:00
|
|
|
if (opt) {
|
|
|
|
const intptr_t kNumInputs = 0;
|
|
|
|
const intptr_t kNumTemps = 2;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* locs = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kCallOnSlowPath);
|
2014-03-03 10:24:59 +00:00
|
|
|
locs->set_temp(0, Location::RegisterLocation(ECX));
|
|
|
|
locs->set_temp(1, Location::RegisterLocation(EBX));
|
2014-03-21 14:40:30 +00:00
|
|
|
locs->set_out(0, Location::RegisterLocation(EAX));
|
2014-03-03 10:24:59 +00:00
|
|
|
return locs;
|
|
|
|
}
|
2012-06-04 15:54:56 +00:00
|
|
|
const intptr_t kNumInputs = 0;
|
|
|
|
const intptr_t kNumTemps = 1;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* locs = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kCall);
|
2012-06-04 15:54:56 +00:00
|
|
|
locs->set_temp(0, Location::RegisterLocation(EDX));
|
2014-03-21 14:40:30 +00:00
|
|
|
locs->set_out(0, Location::RegisterLocation(EAX));
|
2012-06-04 15:54:56 +00:00
|
|
|
return locs;
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-03 10:24:59 +00:00
|
|
|
class AllocateContextSlowPath : public SlowPathCode {
|
|
|
|
public:
|
|
|
|
explicit AllocateContextSlowPath(AllocateContextInstr* instruction)
|
|
|
|
: instruction_(instruction) { }
|
|
|
|
|
|
|
|
virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
__ Comment("AllocateContextSlowPath");
|
|
|
|
__ Bind(entry_label());
|
|
|
|
|
|
|
|
LocationSummary* locs = instruction_->locs();
|
2014-03-21 14:40:30 +00:00
|
|
|
locs->live_registers()->Remove(locs->out(0));
|
2014-03-03 10:24:59 +00:00
|
|
|
|
|
|
|
compiler->SaveLiveRegisters(locs);
|
|
|
|
|
|
|
|
__ movl(EDX, Immediate(instruction_->num_context_variables()));
|
2014-05-27 10:15:50 +00:00
|
|
|
const ExternalLabel label(StubCode::AllocateContextEntryPoint());
|
2014-03-03 10:24:59 +00:00
|
|
|
compiler->GenerateCall(instruction_->token_pos(),
|
|
|
|
&label,
|
|
|
|
PcDescriptors::kOther,
|
|
|
|
locs);
|
2014-03-21 14:40:30 +00:00
|
|
|
ASSERT(instruction_->locs()->out(0).reg() == EAX);
|
2014-03-03 10:24:59 +00:00
|
|
|
compiler->RestoreLiveRegisters(instruction_->locs());
|
|
|
|
__ jmp(exit_label());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
AllocateContextInstr* instruction_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void AllocateContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2014-03-03 10:24:59 +00:00
|
|
|
if (compiler->is_optimizing()) {
|
|
|
|
Register temp0 = locs()->temp(0).reg();
|
|
|
|
Register temp1 = locs()->temp(1).reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
Register result = locs()->out(0).reg();
|
2014-03-03 10:24:59 +00:00
|
|
|
// Try allocate the object.
|
|
|
|
AllocateContextSlowPath* slow_path = new AllocateContextSlowPath(this);
|
|
|
|
compiler->AddSlowPathCode(slow_path);
|
|
|
|
intptr_t instance_size = Context::InstanceSize(num_context_variables());
|
|
|
|
__ movl(temp1, Immediate(instance_size));
|
|
|
|
Isolate* isolate = Isolate::Current();
|
|
|
|
Heap* heap = isolate->heap();
|
|
|
|
__ movl(result, Address::Absolute(heap->TopAddress()));
|
|
|
|
__ addl(temp1, result);
|
|
|
|
// Check if the allocation fits into the remaining space.
|
|
|
|
// EAX: potential new object.
|
|
|
|
// EBX: potential next object start.
|
|
|
|
__ cmpl(temp1, Address::Absolute(heap->EndAddress()));
|
|
|
|
if (FLAG_use_slow_path) {
|
|
|
|
__ jmp(slow_path->entry_label());
|
|
|
|
} else {
|
|
|
|
__ j(ABOVE_EQUAL, slow_path->entry_label());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Successfully allocated the object, now update top to point to
|
|
|
|
// next object start and initialize the object.
|
|
|
|
// EAX: new object.
|
|
|
|
// EBX: next object start.
|
|
|
|
// EDX: number of context variables.
|
|
|
|
__ movl(Address::Absolute(heap->TopAddress()), temp1);
|
|
|
|
__ addl(result, Immediate(kHeapObjectTag));
|
|
|
|
__ UpdateAllocationStatsWithSize(kContextCid, instance_size, kNoRegister);
|
|
|
|
|
|
|
|
// Calculate the size tag and write tags.
|
|
|
|
intptr_t size_tag = (instance_size > RawObject::SizeTag::kMaxSizeTag)
|
2014-04-30 01:26:14 +00:00
|
|
|
? 0 : instance_size << (RawObject::kSizeTagPos - kObjectAlignmentLog2);
|
2014-03-03 10:24:59 +00:00
|
|
|
|
|
|
|
intptr_t tags = size_tag | RawObject::ClassIdTag::encode(kContextCid);
|
|
|
|
__ movl(FieldAddress(result, Context::tags_offset()), Immediate(tags));
|
|
|
|
|
|
|
|
// Setup up number of context variables field.
|
|
|
|
// EAX: new object.
|
|
|
|
__ movl(FieldAddress(result, Context::num_variables_offset()),
|
|
|
|
Immediate(num_context_variables()));
|
|
|
|
|
|
|
|
// Setup isolate field.
|
|
|
|
__ movl(FieldAddress(result, Context::isolate_offset()),
|
|
|
|
Immediate(reinterpret_cast<int32_t>(isolate)));
|
|
|
|
|
|
|
|
// Setup the parent field.
|
|
|
|
const Immediate& raw_null =
|
|
|
|
Immediate(reinterpret_cast<intptr_t>(Object::null()));
|
|
|
|
__ movl(FieldAddress(result, Context::parent_offset()), raw_null);
|
|
|
|
|
|
|
|
// Initialize the context variables.
|
|
|
|
// EAX: new object.
|
|
|
|
if (num_context_variables() > 0) {
|
|
|
|
Label loop;
|
|
|
|
__ leal(temp1, FieldAddress(result, Context::variable_offset(0)));
|
|
|
|
__ movl(temp0, Immediate(num_context_variables()));
|
|
|
|
__ Bind(&loop);
|
|
|
|
__ decl(temp0);
|
|
|
|
__ movl(Address(temp1, temp0, TIMES_4, 0), raw_null);
|
|
|
|
__ j(NOT_ZERO, &loop, Assembler::kNearJump);
|
|
|
|
}
|
|
|
|
// EAX: new object.
|
|
|
|
__ Bind(slow_path->exit_label());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-06-04 15:54:56 +00:00
|
|
|
ASSERT(locs()->temp(0).reg() == EDX);
|
2014-03-21 14:40:30 +00:00
|
|
|
ASSERT(locs()->out(0).reg() == EAX);
|
2012-06-04 15:54:56 +00:00
|
|
|
|
|
|
|
__ movl(EDX, Immediate(num_context_variables()));
|
2014-05-27 10:15:50 +00:00
|
|
|
const ExternalLabel label(StubCode::AllocateContextEntryPoint());
|
2012-06-22 20:37:01 +00:00
|
|
|
compiler->GenerateCall(token_pos(),
|
2012-06-04 15:54:56 +00:00
|
|
|
&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
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* CloneContextInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2012-07-24 16:01:54 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* locs = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kCall);
|
2012-07-24 16:01:54 +00:00
|
|
|
locs->set_in(0, Location::RegisterLocation(EAX));
|
2014-03-21 14:40:30 +00:00
|
|
|
locs->set_out(0, Location::RegisterLocation(EAX));
|
2012-07-24 16:01:54 +00:00
|
|
|
return locs;
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void CloneContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-06-04 15:54:56 +00:00
|
|
|
Register context_value = locs()->in(0).reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
Register result = locs()->out(0).reg();
|
2012-06-04 15:54:56 +00:00
|
|
|
|
|
|
|
__ PushObject(Object::ZoneHandle()); // Make room for the result.
|
|
|
|
__ pushl(context_value);
|
2013-10-25 10:17:10 +00:00
|
|
|
compiler->GenerateRuntimeCall(token_pos(),
|
2013-01-29 12:38:27 +00:00
|
|
|
deopt_id(),
|
2012-08-14 06:59:24 +00:00
|
|
|
kCloneContextRuntimeEntry,
|
2013-08-28 23:07:14 +00:00
|
|
|
1,
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* CatchBlockEntryInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-08-08 08:20:10 +00:00
|
|
|
UNREACHABLE();
|
|
|
|
return NULL;
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-08 08:20:10 +00:00
|
|
|
void CatchBlockEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
__ Bind(compiler->GetJumpLabel(this));
|
|
|
|
compiler->AddExceptionHandler(catch_try_index(),
|
|
|
|
try_index(),
|
|
|
|
compiler->assembler()->CodeSize(),
|
2013-08-28 22:42:21 +00:00
|
|
|
catch_handler_types_,
|
|
|
|
needs_stacktrace());
|
2013-08-08 08:20:10 +00:00
|
|
|
if (HasParallelMove()) {
|
|
|
|
compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
|
|
|
|
}
|
|
|
|
|
2013-04-18 22:19:49 +00:00
|
|
|
// Restore ESP from EBP as we are coming from a throw and the code for
|
2012-06-07 18:06:15 +00:00
|
|
|
// popping arguments has not been run.
|
2013-04-18 22:19:49 +00:00
|
|
|
const intptr_t fp_sp_dist =
|
2013-05-07 18:06:21 +00:00
|
|
|
(kFirstLocalSlotFromFp + 1 - compiler->StackSize()) * kWordSize;
|
2013-04-18 22:19:49 +00:00
|
|
|
ASSERT(fp_sp_dist <= 0);
|
|
|
|
__ leal(ESP, Address(EBP, fp_sp_dist));
|
2012-06-07 18:06:15 +00:00
|
|
|
|
2013-08-08 08:20:10 +00:00
|
|
|
// Restore stack and initialize the two exception variables:
|
|
|
|
// exception and stack trace variables.
|
2012-06-07 18:06:15 +00:00
|
|
|
__ movl(Address(EBP, exception_var().index() * kWordSize),
|
|
|
|
kExceptionObjectReg);
|
|
|
|
__ movl(Address(EBP, stacktrace_var().index() * kWordSize),
|
|
|
|
kStackTraceObjectReg);
|
2012-05-30 16:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* CheckStackOverflowInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2012-07-25 00:25:00 +00:00
|
|
|
const intptr_t kNumInputs = 0;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs,
|
2012-08-14 12:47:42 +00:00
|
|
|
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:
|
2012-09-05 17:04:49 +00:00
|
|
|
explicit CheckStackOverflowSlowPath(CheckStackOverflowInstr* instruction)
|
|
|
|
: instruction_(instruction) { }
|
2012-08-14 12:47:42 +00:00
|
|
|
|
|
|
|
virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
|
2014-04-09 18:27:37 +00:00
|
|
|
if (FLAG_use_osr) {
|
|
|
|
uword flags_address = Isolate::Current()->stack_overflow_flags_address();
|
|
|
|
__ Comment("CheckStackOverflowSlowPathOsr");
|
|
|
|
__ Bind(osr_entry_label());
|
|
|
|
__ movl(Address::Absolute(flags_address),
|
|
|
|
Immediate(Isolate::kOsrRequest));
|
|
|
|
}
|
2012-12-07 21:45:37 +00:00
|
|
|
__ Comment("CheckStackOverflowSlowPath");
|
2012-08-14 12:47:42 +00:00
|
|
|
__ Bind(entry_label());
|
2012-09-05 17:04:49 +00:00
|
|
|
compiler->SaveLiveRegisters(instruction_->locs());
|
2013-01-29 12:38:27 +00:00
|
|
|
// pending_deoptimization_env_ is needed to generate a runtime call that
|
|
|
|
// may throw an exception.
|
|
|
|
ASSERT(compiler->pending_deoptimization_env_ == NULL);
|
2013-10-25 10:17:10 +00:00
|
|
|
Environment* env = compiler->SlowPathEnvironmentFor(instruction_);
|
|
|
|
compiler->pending_deoptimization_env_ = env;
|
|
|
|
compiler->GenerateRuntimeCall(instruction_->token_pos(),
|
2013-01-29 12:38:27 +00:00
|
|
|
instruction_->deopt_id(),
|
2012-08-14 12:47:42 +00:00
|
|
|
kStackOverflowRuntimeEntry,
|
2013-08-28 23:07:14 +00:00
|
|
|
0,
|
2012-09-05 17:04:49 +00:00
|
|
|
instruction_->locs());
|
2013-06-17 11:05:15 +00:00
|
|
|
|
|
|
|
if (FLAG_use_osr && !compiler->is_optimizing() && instruction_->in_loop()) {
|
|
|
|
// In unoptimized code, record loop stack checks as possible OSR entries.
|
|
|
|
compiler->AddCurrentDescriptor(PcDescriptors::kOsrEntry,
|
|
|
|
instruction_->deopt_id(),
|
|
|
|
0); // No token position.
|
|
|
|
}
|
2013-01-29 12:38:27 +00:00
|
|
|
compiler->pending_deoptimization_env_ = NULL;
|
2012-09-05 17:04:49 +00:00
|
|
|
compiler->RestoreLiveRegisters(instruction_->locs());
|
2012-08-14 12:47:42 +00:00
|
|
|
__ jmp(exit_label());
|
|
|
|
}
|
|
|
|
|
2014-04-09 18:27:37 +00:00
|
|
|
Label* osr_entry_label() {
|
|
|
|
ASSERT(FLAG_use_osr);
|
|
|
|
return &osr_entry_label_;
|
|
|
|
}
|
|
|
|
|
2012-08-14 12:47:42 +00:00
|
|
|
private:
|
2012-09-05 17:04:49 +00:00
|
|
|
CheckStackOverflowInstr* instruction_;
|
2014-04-09 18:27:37 +00:00
|
|
|
Label osr_entry_label_;
|
2012-08-14 12:47:42 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void CheckStackOverflowInstr::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());
|
2013-06-17 22:36:32 +00:00
|
|
|
if (compiler->CanOSRFunction() && in_loop()) {
|
2013-06-17 11:05:15 +00:00
|
|
|
// In unoptimized code check the usage counter to trigger OSR at loop
|
2013-06-19 09:21:25 +00:00
|
|
|
// stack checks. Use progressively higher thresholds for more deeply
|
|
|
|
// nested loops to attempt to hit outer loops with OSR when possible.
|
2013-06-17 11:05:15 +00:00
|
|
|
__ LoadObject(EDI, compiler->parsed_function().function());
|
2013-06-19 09:21:25 +00:00
|
|
|
intptr_t threshold =
|
|
|
|
FLAG_optimization_counter_threshold * (loop_depth() + 1);
|
2013-06-17 11:05:15 +00:00
|
|
|
__ cmpl(FieldAddress(EDI, Function::usage_counter_offset()),
|
2013-06-19 09:21:25 +00:00
|
|
|
Immediate(threshold));
|
2014-04-09 18:27:37 +00:00
|
|
|
__ j(GREATER_EQUAL, slow_path->osr_entry_label());
|
|
|
|
}
|
|
|
|
if (compiler->ForceSlowPathForStackOverflow()) {
|
|
|
|
// TODO(turnidge): Implement stack overflow count in assembly to
|
|
|
|
// make --stacktrace-every and --deoptimize-every faster.
|
|
|
|
__ jmp(slow_path->entry_label());
|
2013-06-17 11:05:15 +00:00
|
|
|
}
|
2012-08-14 12:47:42 +00:00
|
|
|
__ Bind(slow_path->exit_label());
|
2012-06-11 17:02:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-02-21 22:24:42 +00:00
|
|
|
static void EmitSmiShiftLeft(FlowGraphCompiler* compiler,
|
|
|
|
BinarySmiOpInstr* shift_left) {
|
|
|
|
const bool is_truncating = shift_left->is_truncating();
|
|
|
|
const LocationSummary& locs = *shift_left->locs();
|
|
|
|
Register left = locs.in(0).reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
Register result = locs.out(0).reg();
|
2013-02-21 22:24:42 +00:00
|
|
|
ASSERT(left == result);
|
|
|
|
Label* deopt = shift_left->CanDeoptimize() ?
|
2014-04-25 23:45:14 +00:00
|
|
|
compiler->AddDeoptStub(shift_left->deopt_id(), ICData::kDeoptBinarySmiOp)
|
|
|
|
: NULL;
|
2013-02-21 22:24:42 +00:00
|
|
|
if (locs.in(1).IsConstant()) {
|
|
|
|
const Object& constant = locs.in(1).constant();
|
|
|
|
ASSERT(constant.IsSmi());
|
|
|
|
// shll operation masks the count to 5 bits.
|
|
|
|
const intptr_t kCountLimit = 0x1F;
|
|
|
|
const intptr_t value = Smi::Cast(constant).Value();
|
|
|
|
if (value == 0) {
|
|
|
|
// No code needed.
|
|
|
|
} else if ((value < 0) || (value >= kCountLimit)) {
|
|
|
|
// This condition may not be known earlier in some cases because
|
|
|
|
// of constant propagation, inlining, etc.
|
|
|
|
if ((value >=kCountLimit) && is_truncating) {
|
|
|
|
__ xorl(result, result);
|
|
|
|
} else {
|
|
|
|
// Result is Mint or exception.
|
|
|
|
__ jmp(deopt);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!is_truncating) {
|
|
|
|
// Check for overflow.
|
|
|
|
Register temp = locs.temp(0).reg();
|
|
|
|
__ movl(temp, left);
|
|
|
|
__ shll(left, Immediate(value));
|
|
|
|
__ sarl(left, Immediate(value));
|
|
|
|
__ cmpl(left, temp);
|
|
|
|
__ j(NOT_EQUAL, deopt); // Overflow.
|
|
|
|
}
|
|
|
|
// Shift for result now we know there is no overflow.
|
|
|
|
__ shll(left, Immediate(value));
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Right (locs.in(1)) is not constant.
|
|
|
|
Register right = locs.in(1).reg();
|
|
|
|
Range* right_range = shift_left->right()->definition()->range();
|
|
|
|
if (shift_left->left()->BindsToConstant() && !is_truncating) {
|
|
|
|
// TODO(srdjan): Implement code below for is_truncating().
|
|
|
|
// If left is constant, we know the maximal allowed size for right.
|
|
|
|
const Object& obj = shift_left->left()->BoundConstant();
|
|
|
|
if (obj.IsSmi()) {
|
|
|
|
const intptr_t left_int = Smi::Cast(obj).Value();
|
|
|
|
if (left_int == 0) {
|
|
|
|
__ cmpl(right, Immediate(0));
|
|
|
|
__ j(NEGATIVE, deopt);
|
|
|
|
return;
|
|
|
|
}
|
2013-05-28 21:10:32 +00:00
|
|
|
const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int);
|
2013-02-21 22:24:42 +00:00
|
|
|
const bool right_needs_check =
|
|
|
|
(right_range == NULL) ||
|
|
|
|
!right_range->IsWithin(0, max_right - 1);
|
|
|
|
if (right_needs_check) {
|
|
|
|
__ cmpl(right,
|
|
|
|
Immediate(reinterpret_cast<int32_t>(Smi::New(max_right))));
|
|
|
|
__ j(ABOVE_EQUAL, deopt);
|
|
|
|
}
|
|
|
|
__ SmiUntag(right);
|
|
|
|
__ shll(left, right);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const bool right_needs_check =
|
|
|
|
(right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1));
|
|
|
|
ASSERT(right == ECX); // Count must be in ECX
|
|
|
|
if (is_truncating) {
|
|
|
|
if (right_needs_check) {
|
|
|
|
const bool right_may_be_negative =
|
|
|
|
(right_range == NULL) ||
|
|
|
|
!right_range->IsWithin(0, RangeBoundary::kPlusInfinity);
|
|
|
|
if (right_may_be_negative) {
|
|
|
|
ASSERT(shift_left->CanDeoptimize());
|
|
|
|
__ cmpl(right, Immediate(0));
|
|
|
|
__ j(NEGATIVE, deopt);
|
|
|
|
}
|
|
|
|
Label done, is_not_zero;
|
|
|
|
__ cmpl(right,
|
|
|
|
Immediate(reinterpret_cast<int32_t>(Smi::New(Smi::kBits))));
|
|
|
|
__ j(BELOW, &is_not_zero, Assembler::kNearJump);
|
|
|
|
__ xorl(left, left);
|
|
|
|
__ jmp(&done, Assembler::kNearJump);
|
|
|
|
__ Bind(&is_not_zero);
|
|
|
|
__ SmiUntag(right);
|
|
|
|
__ shll(left, right);
|
|
|
|
__ Bind(&done);
|
|
|
|
} else {
|
|
|
|
__ SmiUntag(right);
|
|
|
|
__ shll(left, right);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (right_needs_check) {
|
|
|
|
ASSERT(shift_left->CanDeoptimize());
|
|
|
|
__ cmpl(right,
|
|
|
|
Immediate(reinterpret_cast<int32_t>(Smi::New(Smi::kBits))));
|
|
|
|
__ j(ABOVE_EQUAL, deopt);
|
|
|
|
}
|
|
|
|
// Left is not a constant.
|
|
|
|
Register temp = locs.temp(0).reg();
|
|
|
|
// Check if count too large for handling it inlined.
|
|
|
|
__ movl(temp, left);
|
|
|
|
__ SmiUntag(right);
|
|
|
|
// Overflow test (preserve temp and right);
|
|
|
|
__ shll(left, right);
|
|
|
|
__ sarl(left, right);
|
|
|
|
__ cmpl(left, temp);
|
|
|
|
__ j(NOT_EQUAL, deopt); // Overflow.
|
|
|
|
// Shift for result now we know there is no overflow.
|
|
|
|
__ shll(left, right);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* BinarySmiOpInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) 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) {
|
2013-01-21 15:00:43 +00:00
|
|
|
const intptr_t kNumTemps = 1;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-02-04 20:29:58 +00:00
|
|
|
if (RightIsPowerOfTwoConstant()) {
|
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
|
|
|
ConstantInstr* right_constant = right()->definition()->AsConstant();
|
2013-10-30 11:38:39 +00:00
|
|
|
// The programmer only controls one bit, so the constant is safe.
|
2013-02-04 20:29:58 +00:00
|
|
|
summary->set_in(1, Location::Constant(right_constant->value()));
|
|
|
|
summary->set_temp(0, Location::RequiresRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2013-02-04 20:29:58 +00:00
|
|
|
} else {
|
|
|
|
// Both inputs must be writable because they will be untagged.
|
|
|
|
summary->set_in(0, Location::RegisterLocation(EAX));
|
|
|
|
summary->set_in(1, Location::WritableRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2013-02-04 20:29:58 +00:00
|
|
|
// Will be used for sign extension and division.
|
|
|
|
summary->set_temp(0, Location::RegisterLocation(EDX));
|
|
|
|
}
|
2012-06-08 16:59:49 +00:00
|
|
|
return summary;
|
2013-11-07 21:50:26 +00:00
|
|
|
} else if (op_kind() == Token::kMOD) {
|
|
|
|
const intptr_t kNumTemps = 1;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-11-07 21:50:26 +00:00
|
|
|
// Both inputs must be writable because they will be untagged.
|
|
|
|
summary->set_in(0, Location::RegisterLocation(EDX));
|
|
|
|
summary->set_in(1, Location::WritableRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2013-11-07 21:50:26 +00:00
|
|
|
// Will be used for sign extension and division.
|
|
|
|
summary->set_temp(0, Location::RegisterLocation(EAX));
|
|
|
|
return summary;
|
2012-06-08 16:59:49 +00:00
|
|
|
} else if (op_kind() == Token::kSHR) {
|
2012-08-23 08:24:29 +00:00
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2012-06-08 16:59:49 +00:00
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
2012-11-12 22:44:34 +00:00
|
|
|
summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX));
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2012-06-08 16:59:49 +00:00
|
|
|
return summary;
|
|
|
|
} else if (op_kind() == Token::kSHL) {
|
2014-06-03 16:40:30 +00:00
|
|
|
const intptr_t kNumTemps = !is_truncating() ? 1 : 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2012-11-09 19:54:55 +00:00
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
2012-11-12 22:44:34 +00:00
|
|
|
summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX));
|
2013-02-21 22:24:42 +00:00
|
|
|
if (!is_truncating()) {
|
2014-06-03 16:40:30 +00:00
|
|
|
summary->set_temp(0, Location::RequiresRegister());
|
2013-02-21 22:24:42 +00:00
|
|
|
}
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2012-06-08 16:59:49 +00:00
|
|
|
return summary;
|
|
|
|
} else {
|
2012-08-23 08:24:29 +00:00
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2012-06-08 16:59:49 +00:00
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
2013-05-28 10:44:02 +00:00
|
|
|
ConstantInstr* constant = right()->definition()->AsConstant();
|
|
|
|
if (constant != NULL) {
|
|
|
|
summary->set_in(1, Location::RegisterOrSmiConstant(right()));
|
|
|
|
} else {
|
|
|
|
summary->set_in(1, Location::PrefersRegister());
|
|
|
|
}
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2012-06-08 16:59:49 +00:00
|
|
|
return summary;
|
|
|
|
}
|
2012-05-31 17:24:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2013-02-21 22:24:42 +00:00
|
|
|
if (op_kind() == Token::kSHL) {
|
|
|
|
EmitSmiShiftLeft(compiler, this);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT(!is_truncating());
|
2012-08-22 11:17:57 +00:00
|
|
|
Register left = locs()->in(0).reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
Register result = locs()->out(0).reg();
|
2012-06-08 16:59:49 +00:00
|
|
|
ASSERT(left == result);
|
2012-08-23 08:24:29 +00:00
|
|
|
Label* deopt = NULL;
|
2012-09-21 20:06:31 +00:00
|
|
|
if (CanDeoptimize()) {
|
2014-04-25 23:45:14 +00:00
|
|
|
deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinarySmiOp);
|
2012-08-11 00:09:12 +00:00
|
|
|
}
|
2012-08-23 08:24:29 +00:00
|
|
|
|
2012-09-04 09:58:57 +00:00
|
|
|
if (locs()->in(1).IsConstant()) {
|
|
|
|
const Object& constant = locs()->in(1).constant();
|
|
|
|
ASSERT(constant.IsSmi());
|
2014-05-14 19:57:04 +00:00
|
|
|
const int32_t imm = reinterpret_cast<int32_t>(constant.raw());
|
2012-09-04 09:58:57 +00:00
|
|
|
switch (op_kind()) {
|
2014-05-14 19:57:04 +00:00
|
|
|
case Token::kADD:
|
|
|
|
if (imm != 0) {
|
|
|
|
// Checking overflow without emitting an instruction would be wrong.
|
|
|
|
__ addl(left, Immediate(imm));
|
|
|
|
if (deopt != NULL) __ j(OVERFLOW, deopt);
|
|
|
|
}
|
2012-09-04 09:58:57 +00:00
|
|
|
break;
|
|
|
|
case Token::kSUB: {
|
2014-05-14 19:57:04 +00:00
|
|
|
if (imm != 0) {
|
|
|
|
// Checking overflow without emitting an instruction would be wrong.
|
|
|
|
__ subl(left, Immediate(imm));
|
|
|
|
if (deopt != NULL) __ j(OVERFLOW, deopt);
|
|
|
|
}
|
2012-09-04 09:58:57 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token::kMUL: {
|
|
|
|
// Keep left value tagged and untag right value.
|
|
|
|
const intptr_t value = Smi::Cast(constant).Value();
|
2013-03-19 13:29:47 +00:00
|
|
|
if (value == 2) {
|
|
|
|
__ shll(left, Immediate(1));
|
|
|
|
} else {
|
|
|
|
__ imull(left, Immediate(value));
|
|
|
|
}
|
2012-09-21 20:06:31 +00:00
|
|
|
if (deopt != NULL) __ j(OVERFLOW, deopt);
|
2012-09-04 09:58:57 +00:00
|
|
|
break;
|
|
|
|
}
|
2013-02-04 20:29:58 +00:00
|
|
|
case Token::kTRUNCDIV: {
|
|
|
|
const intptr_t value = Smi::Cast(constant).Value();
|
|
|
|
if (value == 1) {
|
|
|
|
// Do nothing.
|
|
|
|
break;
|
|
|
|
} else if (value == -1) {
|
|
|
|
// Check the corner case of dividing the 'MIN_SMI' with -1, in which
|
|
|
|
// case we cannot negate the result.
|
|
|
|
__ cmpl(left, Immediate(0x80000000));
|
|
|
|
__ j(EQUAL, deopt);
|
|
|
|
__ negl(left);
|
|
|
|
break;
|
|
|
|
}
|
2013-09-03 09:28:34 +00:00
|
|
|
ASSERT(Utils::IsPowerOfTwo(Utils::Abs(value)));
|
2013-02-04 20:29:58 +00:00
|
|
|
const intptr_t shift_count =
|
|
|
|
Utils::ShiftForPowerOfTwo(Utils::Abs(value)) + kSmiTagSize;
|
|
|
|
ASSERT(kSmiTagSize == 1);
|
|
|
|
Register temp = locs()->temp(0).reg();
|
|
|
|
__ movl(temp, left);
|
|
|
|
__ sarl(temp, Immediate(31));
|
|
|
|
ASSERT(shift_count > 1); // 1, -1 case handled above.
|
|
|
|
__ shrl(temp, Immediate(32 - shift_count));
|
|
|
|
__ addl(left, temp);
|
|
|
|
ASSERT(shift_count > 0);
|
|
|
|
__ sarl(left, Immediate(shift_count));
|
|
|
|
if (value < 0) {
|
|
|
|
__ negl(left);
|
|
|
|
}
|
|
|
|
__ SmiTag(left);
|
|
|
|
break;
|
|
|
|
}
|
2012-09-04 09:58:57 +00:00
|
|
|
case Token::kBIT_AND: {
|
|
|
|
// No overflow check.
|
|
|
|
__ andl(left, Immediate(imm));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token::kBIT_OR: {
|
|
|
|
// No overflow check.
|
|
|
|
__ orl(left, Immediate(imm));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token::kBIT_XOR: {
|
|
|
|
// No overflow check.
|
|
|
|
__ xorl(left, Immediate(imm));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token::kSHR: {
|
|
|
|
// sarl operation masks the count to 5 bits.
|
|
|
|
const intptr_t kCountLimit = 0x1F;
|
|
|
|
intptr_t value = Smi::Cast(constant).Value();
|
|
|
|
|
|
|
|
if (value == 0) {
|
|
|
|
// TODO(vegorov): should be handled outside.
|
|
|
|
break;
|
|
|
|
} else if (value < 0) {
|
|
|
|
// TODO(vegorov): should be handled outside.
|
|
|
|
__ jmp(deopt);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
value = value + kSmiTagSize;
|
|
|
|
if (value >= kCountLimit) value = kCountLimit;
|
|
|
|
|
|
|
|
__ sarl(left, Immediate(value));
|
|
|
|
__ SmiTag(left);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return;
|
2013-05-28 10:44:02 +00:00
|
|
|
} // if locs()->in(1).IsConstant()
|
|
|
|
|
|
|
|
if (locs()->in(1).IsStackSlot()) {
|
|
|
|
const Address& right = locs()->in(1).ToStackSlotAddress();
|
|
|
|
switch (op_kind()) {
|
|
|
|
case Token::kADD: {
|
|
|
|
__ addl(left, right);
|
|
|
|
if (deopt != NULL) __ j(OVERFLOW, deopt);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token::kSUB: {
|
|
|
|
__ subl(left, right);
|
|
|
|
if (deopt != NULL) __ j(OVERFLOW, deopt);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token::kMUL: {
|
|
|
|
__ SmiUntag(left);
|
|
|
|
__ imull(left, right);
|
|
|
|
if (deopt != NULL) __ 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;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
} // if locs()->in(1).IsStackSlot.
|
2012-09-04 09:58:57 +00:00
|
|
|
|
2013-05-28 10:44:02 +00:00
|
|
|
// if locs()->in(1).IsRegister.
|
2012-09-04 09:58:57 +00:00
|
|
|
Register right = locs()->in(1).reg();
|
2013-11-26 18:18:24 +00:00
|
|
|
Range* right_range = this->right()->definition()->range();
|
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);
|
2012-09-21 20:06:31 +00:00
|
|
|
if (deopt != NULL) __ j(OVERFLOW, deopt);
|
2012-06-08 16:59:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token::kSUB: {
|
|
|
|
__ subl(left, right);
|
2012-09-21 20:06:31 +00:00
|
|
|
if (deopt != NULL) __ j(OVERFLOW, deopt);
|
2012-06-08 16:59:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token::kMUL: {
|
|
|
|
__ SmiUntag(left);
|
|
|
|
__ imull(left, right);
|
2012-09-21 20:06:31 +00:00
|
|
|
if (deopt != NULL) __ j(OVERFLOW, deopt);
|
2012-06-08 16:59:49 +00:00
|
|
|
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: {
|
2013-11-26 18:18:24 +00:00
|
|
|
if ((right_range == NULL) || right_range->Overlaps(0, 0)) {
|
|
|
|
// Handle divide by zero in runtime.
|
|
|
|
__ testl(right, right);
|
|
|
|
__ j(ZERO, deopt);
|
|
|
|
}
|
2012-06-08 16:59:49 +00:00
|
|
|
ASSERT(left == EAX);
|
|
|
|
ASSERT((right != EDX) && (right != EAX));
|
2013-01-21 15:00:43 +00:00
|
|
|
ASSERT(locs()->temp(0).reg() == EDX);
|
2012-06-08 16:59:49 +00:00
|
|
|
ASSERT(result == EAX);
|
|
|
|
__ SmiUntag(left);
|
2013-01-21 15:00:43 +00:00
|
|
|
__ SmiUntag(right);
|
2012-06-08 16:59:49 +00:00
|
|
|
__ cdq(); // Sign extend EAX -> EDX:EAX.
|
2013-01-21 15:00:43 +00:00
|
|
|
__ idivl(right); // EAX: quotient, EDX: remainder.
|
2012-06-08 16:59:49 +00:00
|
|
|
// 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;
|
|
|
|
}
|
2013-11-07 21:50:26 +00:00
|
|
|
case Token::kMOD: {
|
2013-11-26 18:18:24 +00:00
|
|
|
if ((right_range == NULL) || right_range->Overlaps(0, 0)) {
|
|
|
|
// Handle divide by zero in runtime.
|
|
|
|
__ testl(right, right);
|
|
|
|
__ j(ZERO, deopt);
|
|
|
|
}
|
2013-11-07 21:50:26 +00:00
|
|
|
ASSERT(left == EDX);
|
|
|
|
ASSERT((right != EDX) && (right != EAX));
|
|
|
|
ASSERT(locs()->temp(0).reg() == EAX);
|
|
|
|
ASSERT(result == EDX);
|
|
|
|
__ SmiUntag(left);
|
|
|
|
__ SmiUntag(right);
|
|
|
|
__ movl(EAX, EDX);
|
|
|
|
__ cdq(); // Sign extend EAX -> EDX:EAX.
|
|
|
|
__ idivl(right); // EAX: quotient, EDX: remainder.
|
|
|
|
// res = left % right;
|
|
|
|
// if (res < 0) {
|
|
|
|
// if (right < 0) {
|
|
|
|
// res = res - right;
|
|
|
|
// } else {
|
|
|
|
// res = res + right;
|
|
|
|
// }
|
|
|
|
// }
|
2013-11-26 18:18:24 +00:00
|
|
|
Label done;
|
2013-11-07 21:50:26 +00:00
|
|
|
__ cmpl(result, Immediate(0));
|
|
|
|
__ j(GREATER_EQUAL, &done, Assembler::kNearJump);
|
|
|
|
// Result is negative, adjust it.
|
2013-11-26 18:18:24 +00:00
|
|
|
if ((right_range == NULL) || right_range->Overlaps(-1, 1)) {
|
|
|
|
// Right can be positive and negative.
|
|
|
|
Label subtract;
|
|
|
|
__ cmpl(right, Immediate(0));
|
|
|
|
__ j(LESS, &subtract, Assembler::kNearJump);
|
|
|
|
__ addl(result, right);
|
|
|
|
__ jmp(&done, Assembler::kNearJump);
|
|
|
|
__ Bind(&subtract);
|
|
|
|
__ subl(result, right);
|
|
|
|
} else if (right_range->IsWithin(0, RangeBoundary::kPlusInfinity)) {
|
|
|
|
// Right is positive.
|
|
|
|
__ addl(result, right);
|
|
|
|
} else {
|
|
|
|
// Right is negative.
|
|
|
|
__ subl(result, right);
|
|
|
|
}
|
2013-11-07 21:50:26 +00:00
|
|
|
__ Bind(&done);
|
|
|
|
__ SmiTag(result);
|
|
|
|
break;
|
|
|
|
}
|
2012-06-08 16:59:49 +00:00
|
|
|
case Token::kSHR: {
|
2012-11-13 20:00:47 +00:00
|
|
|
if (CanDeoptimize()) {
|
|
|
|
__ cmpl(right, Immediate(0));
|
|
|
|
__ j(LESS, deopt);
|
|
|
|
}
|
2012-06-08 16:59:49 +00:00
|
|
|
__ SmiUntag(right);
|
2012-11-13 20:00:47 +00:00
|
|
|
// sarl operation masks the count to 5 bits.
|
|
|
|
const intptr_t kCountLimit = 0x1F;
|
|
|
|
if ((right_range == NULL) ||
|
|
|
|
!right_range->IsWithin(RangeBoundary::kMinusInfinity, kCountLimit)) {
|
2013-06-14 16:22:00 +00:00
|
|
|
__ cmpl(right, Immediate(kCountLimit));
|
2012-11-13 20:00:47 +00:00
|
|
|
Label count_ok;
|
|
|
|
__ j(LESS, &count_ok, Assembler::kNearJump);
|
|
|
|
__ movl(right, Immediate(kCountLimit));
|
|
|
|
__ Bind(&count_ok);
|
|
|
|
}
|
2012-06-08 16:59:49 +00:00
|
|
|
ASSERT(right == ECX); // Count must be in ECX
|
|
|
|
__ SmiUntag(left);
|
|
|
|
__ sarl(left, right);
|
|
|
|
__ SmiTag(left);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token::kDIV: {
|
|
|
|
// Dispatches to 'Double./'.
|
|
|
|
// TODO(srdjan): Implement as conversion to double and double division.
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-02-19 15:25:47 +00:00
|
|
|
intptr_t left_cid = left()->Type()->ToCid();
|
|
|
|
intptr_t right_cid = right()->Type()->ToCid();
|
|
|
|
ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid));
|
2012-08-24 14:45:42 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
2014-05-07 09:57:09 +00:00
|
|
|
const bool need_temp = (left()->definition() != right()->definition())
|
|
|
|
&&(left_cid != kSmiCid)
|
|
|
|
&& (right_cid != kSmiCid);
|
2013-02-19 15:25:47 +00:00
|
|
|
const intptr_t kNumTemps = need_temp ? 1 : 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2012-08-24 14:45:42 +00:00
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
|
|
|
summary->set_in(1, Location::RequiresRegister());
|
2013-02-19 15:25:47 +00:00
|
|
|
if (need_temp) summary->set_temp(0, Location::RequiresRegister());
|
2012-08-24 14:45:42 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void CheckEitherNonSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2014-04-25 23:45:14 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(deopt_id(),
|
|
|
|
ICData::kDeoptBinaryDoubleOp);
|
2013-02-19 15:25:47 +00:00
|
|
|
intptr_t left_cid = left()->Type()->ToCid();
|
|
|
|
intptr_t right_cid = right()->Type()->ToCid();
|
|
|
|
Register left = locs()->in(0).reg();
|
|
|
|
Register right = locs()->in(1).reg();
|
2014-05-07 09:57:09 +00:00
|
|
|
if (this->left()->definition() == this->right()->definition()) {
|
|
|
|
__ testl(left, Immediate(kSmiTagMask));
|
|
|
|
} else if (left_cid == kSmiCid) {
|
2013-02-19 15:25:47 +00:00
|
|
|
__ testl(right, Immediate(kSmiTagMask));
|
|
|
|
} else if (right_cid == kSmiCid) {
|
|
|
|
__ testl(left, Immediate(kSmiTagMask));
|
|
|
|
} else {
|
|
|
|
Register temp = locs()->temp(0).reg();
|
|
|
|
__ movl(temp, left);
|
|
|
|
__ orl(temp, right);
|
|
|
|
__ testl(temp, Immediate(kSmiTagMask));
|
|
|
|
}
|
2012-08-24 14:45:42 +00:00
|
|
|
__ j(ZERO, deopt);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-02-07 15:30:25 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* BoxDoubleInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2012-08-24 14:45:42 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kCallOnSlowPath);
|
2013-01-18 00:34:20 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::RequiresRegister());
|
2012-08-24 14:45:42 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void BoxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-08-24 14:45:42 +00:00
|
|
|
BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this);
|
|
|
|
compiler->AddSlowPathCode(slow_path);
|
|
|
|
|
2014-03-21 14:40:30 +00:00
|
|
|
Register out_reg = locs()->out(0).reg();
|
2013-01-18 00:34:20 +00:00
|
|
|
XmmRegister value = locs()->in(0).fpu_reg();
|
2012-08-24 14:45:42 +00:00
|
|
|
|
2013-03-05 00:04:32 +00:00
|
|
|
__ TryAllocate(compiler->double_class(),
|
|
|
|
slow_path->entry_label(),
|
|
|
|
Assembler::kFarJump,
|
2014-01-22 19:21:22 +00:00
|
|
|
out_reg,
|
|
|
|
kNoRegister);
|
2012-08-24 14:45:42 +00:00
|
|
|
__ Bind(slow_path->exit_label());
|
|
|
|
__ movsd(FieldAddress(out_reg, Double::value_offset()), value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* UnboxDoubleInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2012-08-24 14:45:42 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
2013-02-14 11:41:08 +00:00
|
|
|
const intptr_t value_cid = value()->Type()->ToCid();
|
|
|
|
const bool needs_temp = ((value_cid != kSmiCid) && (value_cid != kDoubleCid));
|
|
|
|
const bool needs_writable_input = (value_cid == kSmiCid);
|
|
|
|
const intptr_t kNumTemps = needs_temp ? 1 : 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-02-14 11:41:08 +00:00
|
|
|
summary->set_in(0, needs_writable_input
|
|
|
|
? Location::WritableRegister()
|
|
|
|
: Location::RequiresRegister());
|
|
|
|
if (needs_temp) summary->set_temp(0, Location::RequiresRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::RequiresFpuRegister());
|
2012-08-24 14:45:42 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void UnboxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2014-05-02 15:55:15 +00:00
|
|
|
CompileType* value_type = value()->Type();
|
|
|
|
const intptr_t value_cid = value_type->ToCid();
|
2012-08-24 14:45:42 +00:00
|
|
|
const Register value = locs()->in(0).reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
const XmmRegister result = locs()->out(0).fpu_reg();
|
2012-09-17 16:34:22 +00:00
|
|
|
|
|
|
|
if (value_cid == kDoubleCid) {
|
|
|
|
__ movsd(result, FieldAddress(value, Double::value_offset()));
|
|
|
|
} else if (value_cid == kSmiCid) {
|
|
|
|
__ SmiUntag(value); // Untag input before conversion.
|
|
|
|
__ cvtsi2sd(result, value);
|
|
|
|
} else {
|
2014-04-25 23:45:14 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(deopt_id_,
|
|
|
|
ICData::kDeoptBinaryDoubleOp);
|
2013-02-14 11:41:08 +00:00
|
|
|
Register temp = locs()->temp(0).reg();
|
2014-05-02 15:55:15 +00:00
|
|
|
if (value_type->is_nullable() &&
|
|
|
|
(value_type->ToNullableCid() == kDoubleCid)) {
|
|
|
|
const Immediate& raw_null =
|
|
|
|
Immediate(reinterpret_cast<intptr_t>(Object::null()));
|
|
|
|
__ cmpl(value, raw_null);
|
|
|
|
__ j(EQUAL, deopt);
|
|
|
|
// It must be double now.
|
|
|
|
__ movsd(result, FieldAddress(value, Double::value_offset()));
|
|
|
|
} else {
|
|
|
|
Label is_smi, done;
|
|
|
|
__ testl(value, Immediate(kSmiTagMask));
|
|
|
|
__ j(ZERO, &is_smi);
|
|
|
|
__ CompareClassId(value, kDoubleCid, temp);
|
|
|
|
__ j(NOT_EQUAL, deopt);
|
|
|
|
__ movsd(result, FieldAddress(value, Double::value_offset()));
|
|
|
|
__ jmp(&done);
|
|
|
|
__ Bind(&is_smi);
|
|
|
|
__ movl(temp, value);
|
|
|
|
__ SmiUntag(temp);
|
|
|
|
__ cvtsi2sd(result, temp);
|
|
|
|
__ Bind(&done);
|
|
|
|
}
|
2012-08-24 14:45:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* BoxFloat32x4Instr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-04-11 12:50:46 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs,
|
2013-04-11 12:50:46 +00:00
|
|
|
kNumTemps,
|
|
|
|
LocationSummary::kCallOnSlowPath);
|
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::RequiresRegister());
|
2013-04-11 12:50:46 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BoxFloat32x4Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
BoxFloat32x4SlowPath* slow_path = new BoxFloat32x4SlowPath(this);
|
|
|
|
compiler->AddSlowPathCode(slow_path);
|
|
|
|
|
2014-03-21 14:40:30 +00:00
|
|
|
Register out_reg = locs()->out(0).reg();
|
2013-04-11 12:50:46 +00:00
|
|
|
XmmRegister value = locs()->in(0).fpu_reg();
|
|
|
|
|
|
|
|
__ TryAllocate(compiler->float32x4_class(),
|
|
|
|
slow_path->entry_label(),
|
|
|
|
Assembler::kFarJump,
|
2014-01-22 19:21:22 +00:00
|
|
|
out_reg,
|
|
|
|
kNoRegister);
|
2013-04-11 12:50:46 +00:00
|
|
|
__ Bind(slow_path->exit_label());
|
|
|
|
__ movups(FieldAddress(out_reg, Float32x4::value_offset()), value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* UnboxFloat32x4Instr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-04-29 19:17:38 +00:00
|
|
|
const intptr_t value_cid = value()->Type()->ToCid();
|
2013-04-11 12:50:46 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
2013-04-29 19:17:38 +00:00
|
|
|
const intptr_t kNumTemps = value_cid == kFloat32x4Cid ? 0 : 1;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-04-11 12:50:46 +00:00
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
2013-04-29 19:17:38 +00:00
|
|
|
if (kNumTemps > 0) {
|
|
|
|
ASSERT(kNumTemps == 1);
|
|
|
|
summary->set_temp(0, Location::RequiresRegister());
|
|
|
|
}
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::RequiresFpuRegister());
|
2013-04-11 12:50:46 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UnboxFloat32x4Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
const intptr_t value_cid = value()->Type()->ToCid();
|
|
|
|
const Register value = locs()->in(0).reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
const XmmRegister result = locs()->out(0).fpu_reg();
|
2013-04-11 12:50:46 +00:00
|
|
|
|
2013-04-29 19:17:38 +00:00
|
|
|
if (value_cid != kFloat32x4Cid) {
|
|
|
|
const Register temp = locs()->temp(0).reg();
|
2014-04-25 23:45:14 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(deopt_id_, ICData::kDeoptCheckClass);
|
2013-04-29 19:17:38 +00:00
|
|
|
__ testl(value, Immediate(kSmiTagMask));
|
|
|
|
__ j(ZERO, deopt);
|
|
|
|
__ CompareClassId(value, kFloat32x4Cid, temp);
|
|
|
|
__ j(NOT_EQUAL, deopt);
|
|
|
|
}
|
2013-04-11 12:50:46 +00:00
|
|
|
__ movups(result, FieldAddress(value, Float32x4::value_offset()));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* BoxFloat64x2Instr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2014-02-20 20:41:54 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs,
|
2014-02-20 20:41:54 +00:00
|
|
|
kNumTemps,
|
|
|
|
LocationSummary::kCallOnSlowPath);
|
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::RequiresRegister());
|
2014-02-20 20:41:54 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BoxFloat64x2Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
BoxFloat64x2SlowPath* slow_path = new BoxFloat64x2SlowPath(this);
|
|
|
|
compiler->AddSlowPathCode(slow_path);
|
|
|
|
|
2014-03-21 14:40:30 +00:00
|
|
|
Register out_reg = locs()->out(0).reg();
|
2014-02-20 20:41:54 +00:00
|
|
|
XmmRegister value = locs()->in(0).fpu_reg();
|
|
|
|
|
|
|
|
__ TryAllocate(compiler->float64x2_class(),
|
|
|
|
slow_path->entry_label(),
|
|
|
|
Assembler::kFarJump,
|
|
|
|
out_reg,
|
|
|
|
kNoRegister);
|
|
|
|
__ Bind(slow_path->exit_label());
|
|
|
|
__ movups(FieldAddress(out_reg, Float64x2::value_offset()), value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* UnboxFloat64x2Instr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2014-02-20 20:41:54 +00:00
|
|
|
const intptr_t value_cid = value()->Type()->ToCid();
|
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = value_cid == kFloat64x2Cid ? 0 : 1;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2014-02-20 20:41:54 +00:00
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
|
|
|
if (kNumTemps > 0) {
|
|
|
|
ASSERT(kNumTemps == 1);
|
|
|
|
summary->set_temp(0, Location::RequiresRegister());
|
|
|
|
}
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::RequiresFpuRegister());
|
2014-02-20 20:41:54 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UnboxFloat64x2Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
const intptr_t value_cid = value()->Type()->ToCid();
|
|
|
|
const Register value = locs()->in(0).reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
const XmmRegister result = locs()->out(0).fpu_reg();
|
2014-02-20 20:41:54 +00:00
|
|
|
|
|
|
|
if (value_cid != kFloat64x2Cid) {
|
|
|
|
const Register temp = locs()->temp(0).reg();
|
2014-04-25 23:45:14 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(deopt_id_, ICData::kDeoptCheckClass);
|
2014-02-20 20:41:54 +00:00
|
|
|
__ testl(value, Immediate(kSmiTagMask));
|
|
|
|
__ j(ZERO, deopt);
|
|
|
|
__ CompareClassId(value, kFloat64x2Cid, temp);
|
|
|
|
__ j(NOT_EQUAL, deopt);
|
|
|
|
}
|
|
|
|
__ movups(result, FieldAddress(value, Float64x2::value_offset()));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* BoxInt32x4Instr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-04-29 19:17:38 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs,
|
2013-04-29 19:17:38 +00:00
|
|
|
kNumTemps,
|
|
|
|
LocationSummary::kCallOnSlowPath);
|
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::RequiresRegister());
|
2013-04-29 19:17:38 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-04 21:56:59 +00:00
|
|
|
class BoxInt32x4SlowPath : public SlowPathCode {
|
2013-04-29 19:17:38 +00:00
|
|
|
public:
|
2013-11-04 21:56:59 +00:00
|
|
|
explicit BoxInt32x4SlowPath(BoxInt32x4Instr* instruction)
|
2013-04-29 19:17:38 +00:00
|
|
|
: instruction_(instruction) { }
|
|
|
|
|
|
|
|
virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
|
2013-11-04 21:56:59 +00:00
|
|
|
__ Comment("BoxInt32x4SlowPath");
|
2013-04-29 19:17:38 +00:00
|
|
|
__ Bind(entry_label());
|
2013-11-04 21:56:59 +00:00
|
|
|
const Class& int32x4_class = compiler->int32x4_class();
|
2013-04-29 19:17:38 +00:00
|
|
|
const Code& stub =
|
2013-11-04 21:56:59 +00:00
|
|
|
Code::Handle(StubCode::GetAllocationStubForClass(int32x4_class));
|
2014-05-27 10:15:50 +00:00
|
|
|
const ExternalLabel label(stub.EntryPoint());
|
2013-04-29 19:17:38 +00:00
|
|
|
|
|
|
|
LocationSummary* locs = instruction_->locs();
|
2014-03-21 14:40:30 +00:00
|
|
|
locs->live_registers()->Remove(locs->out(0));
|
2013-04-29 19:17:38 +00:00
|
|
|
|
|
|
|
compiler->SaveLiveRegisters(locs);
|
2014-01-21 23:46:26 +00:00
|
|
|
compiler->GenerateCall(Scanner::kNoSourcePos, // No token position.
|
2013-04-29 19:17:38 +00:00
|
|
|
&label,
|
|
|
|
PcDescriptors::kOther,
|
|
|
|
locs);
|
2014-03-21 14:40:30 +00:00
|
|
|
__ MoveRegister(locs->out(0).reg(), EAX);
|
2013-04-29 19:17:38 +00:00
|
|
|
compiler->RestoreLiveRegisters(locs);
|
|
|
|
|
|
|
|
__ jmp(exit_label());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2013-11-04 21:56:59 +00:00
|
|
|
BoxInt32x4Instr* instruction_;
|
2013-04-29 19:17:38 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2013-11-04 21:56:59 +00:00
|
|
|
void BoxInt32x4Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
BoxInt32x4SlowPath* slow_path = new BoxInt32x4SlowPath(this);
|
2013-04-29 19:17:38 +00:00
|
|
|
compiler->AddSlowPathCode(slow_path);
|
|
|
|
|
2014-03-21 14:40:30 +00:00
|
|
|
Register out_reg = locs()->out(0).reg();
|
2013-04-29 19:17:38 +00:00
|
|
|
XmmRegister value = locs()->in(0).fpu_reg();
|
|
|
|
|
2013-11-04 21:56:59 +00:00
|
|
|
__ TryAllocate(compiler->int32x4_class(),
|
2013-04-29 19:17:38 +00:00
|
|
|
slow_path->entry_label(),
|
|
|
|
Assembler::kFarJump,
|
2014-01-22 19:21:22 +00:00
|
|
|
out_reg,
|
|
|
|
kNoRegister);
|
2013-04-29 19:17:38 +00:00
|
|
|
__ Bind(slow_path->exit_label());
|
2013-11-04 21:56:59 +00:00
|
|
|
__ movups(FieldAddress(out_reg, Int32x4::value_offset()), value);
|
2013-04-29 19:17:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* UnboxInt32x4Instr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-04-29 19:17:38 +00:00
|
|
|
const intptr_t value_cid = value()->Type()->ToCid();
|
|
|
|
const intptr_t kNumInputs = 1;
|
2013-11-04 21:56:59 +00:00
|
|
|
const intptr_t kNumTemps = value_cid == kInt32x4Cid ? 0 : 1;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-04-29 19:17:38 +00:00
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
|
|
|
if (kNumTemps > 0) {
|
|
|
|
ASSERT(kNumTemps == 1);
|
|
|
|
summary->set_temp(0, Location::RequiresRegister());
|
|
|
|
}
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::RequiresFpuRegister());
|
2013-04-29 19:17:38 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-04 21:56:59 +00:00
|
|
|
void UnboxInt32x4Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2013-04-29 19:17:38 +00:00
|
|
|
const intptr_t value_cid = value()->Type()->ToCid();
|
|
|
|
const Register value = locs()->in(0).reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
const XmmRegister result = locs()->out(0).fpu_reg();
|
2013-04-29 19:17:38 +00:00
|
|
|
|
2013-11-04 21:56:59 +00:00
|
|
|
if (value_cid != kInt32x4Cid) {
|
2013-04-29 19:17:38 +00:00
|
|
|
const Register temp = locs()->temp(0).reg();
|
2014-04-25 23:45:14 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(deopt_id_, ICData::kDeoptCheckClass);
|
2013-04-29 19:17:38 +00:00
|
|
|
__ testl(value, Immediate(kSmiTagMask));
|
|
|
|
__ j(ZERO, deopt);
|
2013-11-04 21:56:59 +00:00
|
|
|
__ CompareClassId(value, kInt32x4Cid, temp);
|
2013-04-29 19:17:38 +00:00
|
|
|
__ j(NOT_EQUAL, deopt);
|
|
|
|
}
|
2013-11-04 21:56:59 +00:00
|
|
|
__ movups(result, FieldAddress(value, Int32x4::value_offset()));
|
2013-04-29 19:17:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* BinaryDoubleOpInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2012-08-24 14:45:42 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-01-18 00:34:20 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
|
|
|
summary->set_in(1, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2012-08-24 14:45:42 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-04 15:54:16 +00:00
|
|
|
void BinaryDoubleOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2013-01-18 00:34:20 +00:00
|
|
|
XmmRegister left = locs()->in(0).fpu_reg();
|
|
|
|
XmmRegister right = locs()->in(1).fpu_reg();
|
2012-08-24 14:45:42 +00:00
|
|
|
|
2014-03-21 14:40:30 +00:00
|
|
|
ASSERT(locs()->out(0).fpu_reg() == left);
|
2012-08-24 14:45:42 +00:00
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* BinaryFloat32x4OpInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-04-16 10:04:34 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-04-16 10:04:34 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
|
|
|
summary->set_in(1, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2013-04-16 10:04:34 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BinaryFloat32x4OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
XmmRegister left = locs()->in(0).fpu_reg();
|
|
|
|
XmmRegister right = locs()->in(1).fpu_reg();
|
|
|
|
|
2014-03-21 14:40:30 +00:00
|
|
|
ASSERT(locs()->out(0).fpu_reg() == left);
|
2013-04-16 10:04:34 +00:00
|
|
|
|
|
|
|
switch (op_kind()) {
|
|
|
|
case Token::kADD: __ addps(left, right); break;
|
|
|
|
case Token::kSUB: __ subps(left, right); break;
|
|
|
|
case Token::kMUL: __ mulps(left, right); break;
|
|
|
|
case Token::kDIV: __ divps(left, right); break;
|
|
|
|
default: UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-23 17:52:10 +00:00
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* BinaryFloat64x2OpInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2014-03-07 21:43:49 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2014-03-07 21:43:49 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
|
|
|
summary->set_in(1, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2014-03-07 21:43:49 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BinaryFloat64x2OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
XmmRegister left = locs()->in(0).fpu_reg();
|
|
|
|
XmmRegister right = locs()->in(1).fpu_reg();
|
|
|
|
|
2014-03-21 14:40:30 +00:00
|
|
|
ASSERT(locs()->out(0).fpu_reg() == left);
|
2014-03-07 21:43:49 +00:00
|
|
|
|
|
|
|
switch (op_kind()) {
|
|
|
|
case Token::kADD: __ addpd(left, right); break;
|
|
|
|
case Token::kSUB: __ subpd(left, right); break;
|
|
|
|
case Token::kMUL: __ mulpd(left, right); break;
|
|
|
|
case Token::kDIV: __ divpd(left, right); break;
|
|
|
|
default: UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* Simd32x4ShuffleInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-04-23 17:52:10 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-04-23 17:52:10 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2013-04-23 17:52:10 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-01 07:09:54 +00:00
|
|
|
void Simd32x4ShuffleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2013-04-23 17:52:10 +00:00
|
|
|
XmmRegister value = locs()->in(0).fpu_reg();
|
|
|
|
|
2014-03-21 14:40:30 +00:00
|
|
|
ASSERT(locs()->out(0).fpu_reg() == value);
|
2013-04-23 17:52:10 +00:00
|
|
|
|
|
|
|
switch (op_kind()) {
|
|
|
|
case MethodRecognizer::kFloat32x4ShuffleX:
|
2014-03-11 17:59:45 +00:00
|
|
|
// Shuffle not necessary.
|
2013-04-23 17:52:10 +00:00
|
|
|
__ cvtss2sd(value, value);
|
|
|
|
break;
|
|
|
|
case MethodRecognizer::kFloat32x4ShuffleY:
|
|
|
|
__ shufps(value, value, Immediate(0x55));
|
|
|
|
__ cvtss2sd(value, value);
|
|
|
|
break;
|
|
|
|
case MethodRecognizer::kFloat32x4ShuffleZ:
|
|
|
|
__ shufps(value, value, Immediate(0xAA));
|
|
|
|
__ cvtss2sd(value, value);
|
|
|
|
break;
|
|
|
|
case MethodRecognizer::kFloat32x4ShuffleW:
|
|
|
|
__ shufps(value, value, Immediate(0xFF));
|
|
|
|
__ cvtss2sd(value, value);
|
|
|
|
break;
|
2013-07-19 17:03:09 +00:00
|
|
|
case MethodRecognizer::kFloat32x4Shuffle:
|
2013-11-04 21:56:59 +00:00
|
|
|
case MethodRecognizer::kInt32x4Shuffle:
|
2013-07-19 17:03:09 +00:00
|
|
|
__ shufps(value, value, Immediate(mask_));
|
|
|
|
break;
|
2013-04-23 17:52:10 +00:00
|
|
|
default: UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* Simd32x4ShuffleMixInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-11-01 07:09:54 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-11-01 07:09:54 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
|
|
|
summary->set_in(1, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2013-11-01 07:09:54 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Simd32x4ShuffleMixInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
XmmRegister left = locs()->in(0).fpu_reg();
|
|
|
|
XmmRegister right = locs()->in(1).fpu_reg();
|
|
|
|
|
2014-03-21 14:40:30 +00:00
|
|
|
ASSERT(locs()->out(0).fpu_reg() == left);
|
2013-11-01 07:09:54 +00:00
|
|
|
switch (op_kind()) {
|
|
|
|
case MethodRecognizer::kFloat32x4ShuffleMix:
|
2013-11-04 21:56:59 +00:00
|
|
|
case MethodRecognizer::kInt32x4ShuffleMix:
|
2013-11-01 07:09:54 +00:00
|
|
|
__ shufps(left, right, Immediate(mask_));
|
|
|
|
break;
|
|
|
|
default: UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* Simd32x4GetSignMaskInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-08-20 21:35:53 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-08-20 21:35:53 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::RequiresRegister());
|
2013-08-20 21:35:53 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Simd32x4GetSignMaskInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
XmmRegister value = locs()->in(0).fpu_reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
Register out = locs()->out(0).reg();
|
2013-08-20 21:35:53 +00:00
|
|
|
|
|
|
|
__ movmskps(out, value);
|
|
|
|
__ SmiTag(out);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-12-16 15:11:31 +00:00
|
|
|
LocationSummary* Float32x4ConstructorInstr::MakeLocationSummary(
|
2014-05-23 12:07:33 +00:00
|
|
|
Isolate* isolate, bool opt) const {
|
2013-04-25 22:03:05 +00:00
|
|
|
const intptr_t kNumInputs = 4;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-04-25 22:03:05 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
|
|
|
summary->set_in(1, Location::RequiresFpuRegister());
|
|
|
|
summary->set_in(2, Location::RequiresFpuRegister());
|
|
|
|
summary->set_in(3, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2013-04-25 22:03:05 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Float32x4ConstructorInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
XmmRegister v0 = locs()->in(0).fpu_reg();
|
|
|
|
XmmRegister v1 = locs()->in(1).fpu_reg();
|
|
|
|
XmmRegister v2 = locs()->in(2).fpu_reg();
|
|
|
|
XmmRegister v3 = locs()->in(3).fpu_reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
ASSERT(v0 == locs()->out(0).fpu_reg());
|
2013-04-25 22:03:05 +00:00
|
|
|
__ subl(ESP, Immediate(16));
|
|
|
|
__ cvtsd2ss(v0, v0);
|
2013-05-13 20:22:06 +00:00
|
|
|
__ movss(Address(ESP, 0), v0);
|
2013-04-25 22:03:05 +00:00
|
|
|
__ movsd(v0, v1);
|
|
|
|
__ cvtsd2ss(v0, v0);
|
2013-05-13 20:22:06 +00:00
|
|
|
__ movss(Address(ESP, 4), v0);
|
2013-04-25 22:03:05 +00:00
|
|
|
__ movsd(v0, v2);
|
|
|
|
__ cvtsd2ss(v0, v0);
|
2013-05-13 20:22:06 +00:00
|
|
|
__ movss(Address(ESP, 8), v0);
|
2013-04-25 22:03:05 +00:00
|
|
|
__ movsd(v0, v3);
|
|
|
|
__ cvtsd2ss(v0, v0);
|
2013-05-13 20:22:06 +00:00
|
|
|
__ movss(Address(ESP, 12), v0);
|
|
|
|
__ movups(v0, Address(ESP, 0));
|
2013-04-25 22:03:05 +00:00
|
|
|
__ addl(ESP, Immediate(16));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* Float32x4ZeroInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-04-25 22:03:05 +00:00
|
|
|
const intptr_t kNumInputs = 0;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::RequiresFpuRegister());
|
2013-04-25 22:03:05 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Float32x4ZeroInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2014-03-21 14:40:30 +00:00
|
|
|
XmmRegister value = locs()->out(0).fpu_reg();
|
2013-04-25 22:03:05 +00:00
|
|
|
__ xorps(value, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* Float32x4SplatInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-04-25 22:03:05 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-04-25 22:03:05 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2013-04-25 22:03:05 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Float32x4SplatInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2014-03-21 14:40:30 +00:00
|
|
|
XmmRegister value = locs()->out(0).fpu_reg();
|
|
|
|
ASSERT(locs()->in(0).fpu_reg() == locs()->out(0).fpu_reg());
|
2013-04-25 22:03:05 +00:00
|
|
|
// Convert to Float32.
|
|
|
|
__ cvtsd2ss(value, value);
|
|
|
|
// Splat across all lanes.
|
|
|
|
__ shufps(value, value, Immediate(0x00));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* Float32x4ComparisonInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-04-29 19:17:38 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-04-29 19:17:38 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
|
|
|
summary->set_in(1, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2013-04-29 19:17:38 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Float32x4ComparisonInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
XmmRegister left = locs()->in(0).fpu_reg();
|
|
|
|
XmmRegister right = locs()->in(1).fpu_reg();
|
|
|
|
|
2014-03-21 14:40:30 +00:00
|
|
|
ASSERT(locs()->out(0).fpu_reg() == left);
|
2013-04-29 19:17:38 +00:00
|
|
|
|
|
|
|
switch (op_kind()) {
|
|
|
|
case MethodRecognizer::kFloat32x4Equal:
|
|
|
|
__ cmppseq(left, right);
|
|
|
|
break;
|
|
|
|
case MethodRecognizer::kFloat32x4NotEqual:
|
|
|
|
__ cmppsneq(left, right);
|
|
|
|
break;
|
|
|
|
case MethodRecognizer::kFloat32x4GreaterThan:
|
|
|
|
__ cmppsnle(left, right);
|
|
|
|
break;
|
|
|
|
case MethodRecognizer::kFloat32x4GreaterThanOrEqual:
|
|
|
|
__ cmppsnlt(left, right);
|
|
|
|
break;
|
|
|
|
case MethodRecognizer::kFloat32x4LessThan:
|
|
|
|
__ cmppslt(left, right);
|
|
|
|
break;
|
|
|
|
case MethodRecognizer::kFloat32x4LessThanOrEqual:
|
|
|
|
__ cmppsle(left, right);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default: UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* Float32x4MinMaxInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-04-30 17:26:42 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-04-30 17:26:42 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
|
|
|
summary->set_in(1, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2013-04-30 17:26:42 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Float32x4MinMaxInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
XmmRegister left = locs()->in(0).fpu_reg();
|
|
|
|
XmmRegister right = locs()->in(1).fpu_reg();
|
|
|
|
|
2014-03-21 14:40:30 +00:00
|
|
|
ASSERT(locs()->out(0).fpu_reg() == left);
|
2013-04-30 17:26:42 +00:00
|
|
|
|
|
|
|
switch (op_kind()) {
|
|
|
|
case MethodRecognizer::kFloat32x4Min:
|
|
|
|
__ minps(left, right);
|
|
|
|
break;
|
|
|
|
case MethodRecognizer::kFloat32x4Max:
|
|
|
|
__ maxps(left, right);
|
|
|
|
break;
|
|
|
|
default: UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* Float32x4ScaleInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-04-30 17:26:42 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-04-30 17:26:42 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
|
|
|
summary->set_in(1, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2013-04-30 17:26:42 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Float32x4ScaleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
XmmRegister left = locs()->in(0).fpu_reg();
|
|
|
|
XmmRegister right = locs()->in(1).fpu_reg();
|
|
|
|
|
2014-03-21 14:40:30 +00:00
|
|
|
ASSERT(locs()->out(0).fpu_reg() == left);
|
2013-04-30 17:26:42 +00:00
|
|
|
|
|
|
|
switch (op_kind()) {
|
|
|
|
case MethodRecognizer::kFloat32x4Scale:
|
|
|
|
__ cvtsd2ss(left, left);
|
|
|
|
__ shufps(left, left, Immediate(0x00));
|
|
|
|
__ mulps(left, right);
|
|
|
|
break;
|
|
|
|
default: UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* Float32x4SqrtInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-04-30 17:26:42 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-04-30 17:26:42 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2013-04-30 17:26:42 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Float32x4SqrtInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
XmmRegister left = locs()->in(0).fpu_reg();
|
|
|
|
|
2014-03-21 14:40:30 +00:00
|
|
|
ASSERT(locs()->out(0).fpu_reg() == left);
|
2013-04-30 17:26:42 +00:00
|
|
|
|
|
|
|
switch (op_kind()) {
|
|
|
|
case MethodRecognizer::kFloat32x4Sqrt:
|
|
|
|
__ sqrtps(left);
|
|
|
|
break;
|
|
|
|
case MethodRecognizer::kFloat32x4Reciprocal:
|
|
|
|
__ reciprocalps(left);
|
|
|
|
break;
|
|
|
|
case MethodRecognizer::kFloat32x4ReciprocalSqrt:
|
|
|
|
__ rsqrtps(left);
|
|
|
|
break;
|
|
|
|
default: UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* Float32x4ZeroArgInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-05-01 20:40:24 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-05-01 20:40:24 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2013-05-01 20:40:24 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Float32x4ZeroArgInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
XmmRegister left = locs()->in(0).fpu_reg();
|
|
|
|
|
2014-03-21 14:40:30 +00:00
|
|
|
ASSERT(locs()->out(0).fpu_reg() == left);
|
2013-05-01 20:40:24 +00:00
|
|
|
switch (op_kind()) {
|
|
|
|
case MethodRecognizer::kFloat32x4Negate:
|
|
|
|
__ negateps(left);
|
|
|
|
break;
|
|
|
|
case MethodRecognizer::kFloat32x4Absolute:
|
|
|
|
__ absps(left);
|
|
|
|
break;
|
|
|
|
default: UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* Float32x4ClampInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-05-01 20:40:24 +00:00
|
|
|
const intptr_t kNumInputs = 3;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-05-01 20:40:24 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
|
|
|
summary->set_in(1, Location::RequiresFpuRegister());
|
|
|
|
summary->set_in(2, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2013-05-01 20:40:24 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Float32x4ClampInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
XmmRegister left = locs()->in(0).fpu_reg();
|
|
|
|
XmmRegister lower = locs()->in(1).fpu_reg();
|
|
|
|
XmmRegister upper = locs()->in(2).fpu_reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
ASSERT(locs()->out(0).fpu_reg() == left);
|
2013-05-01 20:40:24 +00:00
|
|
|
__ minps(left, upper);
|
|
|
|
__ maxps(left, lower);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* Float32x4WithInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-05-01 20:40:24 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-05-01 20:40:24 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
|
|
|
summary->set_in(1, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2013-05-01 20:40:24 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
2013-05-13 20:22:06 +00:00
|
|
|
|
2013-05-01 20:40:24 +00:00
|
|
|
void Float32x4WithInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
XmmRegister replacement = locs()->in(0).fpu_reg();
|
|
|
|
XmmRegister value = locs()->in(1).fpu_reg();
|
|
|
|
|
2014-03-21 14:40:30 +00:00
|
|
|
ASSERT(locs()->out(0).fpu_reg() == replacement);
|
2013-05-01 20:40:24 +00:00
|
|
|
|
|
|
|
switch (op_kind()) {
|
|
|
|
case MethodRecognizer::kFloat32x4WithX:
|
|
|
|
__ cvtsd2ss(replacement, replacement);
|
|
|
|
__ subl(ESP, Immediate(16));
|
|
|
|
// Move value to stack.
|
2013-05-13 20:22:06 +00:00
|
|
|
__ movups(Address(ESP, 0), value);
|
2013-05-01 20:40:24 +00:00
|
|
|
// Write over X value.
|
2013-05-13 20:22:06 +00:00
|
|
|
__ movss(Address(ESP, 0), replacement);
|
2013-05-01 20:40:24 +00:00
|
|
|
// Move updated value into output register.
|
2013-05-13 20:22:06 +00:00
|
|
|
__ movups(replacement, Address(ESP, 0));
|
2013-05-01 20:40:24 +00:00
|
|
|
__ addl(ESP, Immediate(16));
|
|
|
|
break;
|
|
|
|
case MethodRecognizer::kFloat32x4WithY:
|
|
|
|
__ cvtsd2ss(replacement, replacement);
|
|
|
|
__ subl(ESP, Immediate(16));
|
|
|
|
// Move value to stack.
|
2013-05-13 20:22:06 +00:00
|
|
|
__ movups(Address(ESP, 0), value);
|
2013-05-01 20:40:24 +00:00
|
|
|
// Write over Y value.
|
2013-05-13 20:22:06 +00:00
|
|
|
__ movss(Address(ESP, 4), replacement);
|
2013-05-01 20:40:24 +00:00
|
|
|
// Move updated value into output register.
|
2013-05-13 20:22:06 +00:00
|
|
|
__ movups(replacement, Address(ESP, 0));
|
2013-05-01 20:40:24 +00:00
|
|
|
__ addl(ESP, Immediate(16));
|
|
|
|
break;
|
|
|
|
case MethodRecognizer::kFloat32x4WithZ:
|
|
|
|
__ cvtsd2ss(replacement, replacement);
|
|
|
|
__ subl(ESP, Immediate(16));
|
|
|
|
// Move value to stack.
|
2013-05-13 20:22:06 +00:00
|
|
|
__ movups(Address(ESP, 0), value);
|
2013-05-01 20:40:24 +00:00
|
|
|
// Write over Z value.
|
2013-05-13 20:22:06 +00:00
|
|
|
__ movss(Address(ESP, 8), replacement);
|
2013-05-01 20:40:24 +00:00
|
|
|
// Move updated value into output register.
|
2013-05-13 20:22:06 +00:00
|
|
|
__ movups(replacement, Address(ESP, 0));
|
2013-05-01 20:40:24 +00:00
|
|
|
__ addl(ESP, Immediate(16));
|
|
|
|
break;
|
|
|
|
case MethodRecognizer::kFloat32x4WithW:
|
|
|
|
__ cvtsd2ss(replacement, replacement);
|
|
|
|
__ subl(ESP, Immediate(16));
|
|
|
|
// Move value to stack.
|
2013-05-13 20:22:06 +00:00
|
|
|
__ movups(Address(ESP, 0), value);
|
2013-05-01 20:40:24 +00:00
|
|
|
// Write over W value.
|
2013-05-13 20:22:06 +00:00
|
|
|
__ movss(Address(ESP, 12), replacement);
|
2013-05-01 20:40:24 +00:00
|
|
|
// Move updated value into output register.
|
2013-05-13 20:22:06 +00:00
|
|
|
__ movups(replacement, Address(ESP, 0));
|
2013-05-01 20:40:24 +00:00
|
|
|
__ addl(ESP, Immediate(16));
|
|
|
|
break;
|
|
|
|
default: UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* Float32x4ToInt32x4Instr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-05-01 20:40:24 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-05-01 20:40:24 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2013-05-01 20:40:24 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-04 21:56:59 +00:00
|
|
|
void Float32x4ToInt32x4Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2013-05-01 20:40:24 +00:00
|
|
|
// NOP.
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* Simd64x2ShuffleInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2014-03-07 21:43:49 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2014-03-07 21:43:49 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2014-03-07 21:43:49 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Simd64x2ShuffleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
XmmRegister value = locs()->in(0).fpu_reg();
|
|
|
|
|
2014-03-21 14:40:30 +00:00
|
|
|
ASSERT(locs()->out(0).fpu_reg() == value);
|
2014-03-07 21:43:49 +00:00
|
|
|
|
|
|
|
switch (op_kind()) {
|
|
|
|
case MethodRecognizer::kFloat64x2GetX:
|
2014-03-11 17:59:45 +00:00
|
|
|
// nop.
|
2014-03-07 21:43:49 +00:00
|
|
|
break;
|
|
|
|
case MethodRecognizer::kFloat64x2GetY:
|
|
|
|
__ shufpd(value, value, Immediate(0x33));
|
|
|
|
break;
|
|
|
|
default: UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* Float64x2ZeroInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2014-03-07 21:43:49 +00:00
|
|
|
const intptr_t kNumInputs = 0;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::RequiresFpuRegister());
|
2014-03-07 21:43:49 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Float64x2ZeroInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2014-03-21 14:40:30 +00:00
|
|
|
XmmRegister value = locs()->out(0).fpu_reg();
|
2014-03-07 21:43:49 +00:00
|
|
|
__ xorpd(value, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* Float64x2SplatInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2014-03-07 21:43:49 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2014-03-07 21:43:49 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2014-03-07 21:43:49 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Float64x2SplatInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2014-03-21 14:40:30 +00:00
|
|
|
XmmRegister value = locs()->out(0).fpu_reg();
|
2014-03-07 21:43:49 +00:00
|
|
|
__ shufpd(value, value, Immediate(0x0));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* Float64x2ConstructorInstr::MakeLocationSummary(
|
2014-05-23 12:07:33 +00:00
|
|
|
Isolate* isolate, bool opt) const {
|
2014-03-07 21:43:49 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2014-03-07 21:43:49 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
|
|
|
summary->set_in(1, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2014-03-07 21:43:49 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Float64x2ConstructorInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
XmmRegister v0 = locs()->in(0).fpu_reg();
|
|
|
|
XmmRegister v1 = locs()->in(1).fpu_reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
ASSERT(v0 == locs()->out(0).fpu_reg());
|
2014-03-07 21:43:49 +00:00
|
|
|
__ subl(ESP, Immediate(16));
|
|
|
|
__ movsd(Address(ESP, 0), v0);
|
|
|
|
__ movsd(Address(ESP, 8), v1);
|
|
|
|
__ movups(v0, Address(ESP, 0));
|
|
|
|
__ addl(ESP, Immediate(16));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* Float64x2ToFloat32x4Instr::MakeLocationSummary(
|
2014-05-23 12:07:33 +00:00
|
|
|
Isolate* isolate, bool opt) const {
|
2014-03-07 21:43:49 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2014-03-07 21:43:49 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2014-03-07 21:43:49 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Float64x2ToFloat32x4Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2014-03-21 14:40:30 +00:00
|
|
|
XmmRegister value = locs()->out(0).fpu_reg();
|
2014-03-07 21:43:49 +00:00
|
|
|
__ cvtpd2ps(value, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocationSummary* Float32x4ToFloat64x2Instr::MakeLocationSummary(
|
2014-05-23 12:07:33 +00:00
|
|
|
Isolate* isolate, bool opt) const {
|
2014-03-07 21:43:49 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2014-03-07 21:43:49 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2014-03-07 21:43:49 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Float32x4ToFloat64x2Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2014-03-21 14:40:30 +00:00
|
|
|
XmmRegister value = locs()->out(0).fpu_reg();
|
2014-03-07 21:43:49 +00:00
|
|
|
__ cvtps2pd(value, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* Float64x2ZeroArgInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2014-03-10 20:58:04 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2014-03-10 20:58:04 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
|
|
|
if (representation() == kTagged) {
|
|
|
|
ASSERT(op_kind() == MethodRecognizer::kFloat64x2GetSignMask);
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::RequiresRegister());
|
2014-03-10 20:58:04 +00:00
|
|
|
} else {
|
|
|
|
ASSERT(representation() == kUnboxedFloat64x2);
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2014-03-10 20:58:04 +00:00
|
|
|
}
|
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Float64x2ZeroArgInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
XmmRegister left = locs()->in(0).fpu_reg();
|
|
|
|
|
|
|
|
ASSERT((op_kind() == MethodRecognizer::kFloat64x2GetSignMask) ||
|
2014-03-21 14:40:30 +00:00
|
|
|
(locs()->out(0).fpu_reg() == left));
|
2014-03-10 20:58:04 +00:00
|
|
|
|
|
|
|
switch (op_kind()) {
|
|
|
|
case MethodRecognizer::kFloat64x2Negate:
|
|
|
|
__ negatepd(left);
|
|
|
|
break;
|
|
|
|
case MethodRecognizer::kFloat64x2Abs:
|
|
|
|
__ abspd(left);
|
|
|
|
break;
|
|
|
|
case MethodRecognizer::kFloat64x2Sqrt:
|
|
|
|
__ sqrtpd(left);
|
|
|
|
break;
|
|
|
|
case MethodRecognizer::kFloat64x2GetSignMask:
|
2014-03-21 14:40:30 +00:00
|
|
|
__ movmskpd(locs()->out(0).reg(), left);
|
|
|
|
__ SmiTag(locs()->out(0).reg());
|
2014-03-10 20:58:04 +00:00
|
|
|
break;
|
|
|
|
default: UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* Float64x2OneArgInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2014-03-10 22:34:56 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2014-03-10 22:34:56 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
|
|
|
summary->set_in(1, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2014-03-10 22:34:56 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Float64x2OneArgInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
XmmRegister left = locs()->in(0).fpu_reg();
|
|
|
|
XmmRegister right = locs()->in(1).fpu_reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
ASSERT((locs()->out(0).fpu_reg() == left));
|
2014-03-10 22:34:56 +00:00
|
|
|
|
|
|
|
switch (op_kind()) {
|
|
|
|
case MethodRecognizer::kFloat64x2Scale:
|
|
|
|
__ shufpd(right, right, Immediate(0x00));
|
|
|
|
__ mulpd(left, right);
|
|
|
|
break;
|
|
|
|
case MethodRecognizer::kFloat64x2WithX:
|
|
|
|
__ subl(ESP, Immediate(16));
|
|
|
|
// Move value to stack.
|
|
|
|
__ movups(Address(ESP, 0), left);
|
|
|
|
// Write over X value.
|
|
|
|
__ movsd(Address(ESP, 0), right);
|
|
|
|
// Move updated value into output register.
|
|
|
|
__ movups(left, Address(ESP, 0));
|
|
|
|
__ addl(ESP, Immediate(16));
|
|
|
|
break;
|
|
|
|
case MethodRecognizer::kFloat64x2WithY:
|
|
|
|
__ subl(ESP, Immediate(16));
|
|
|
|
// Move value to stack.
|
|
|
|
__ movups(Address(ESP, 0), left);
|
|
|
|
// Write over Y value.
|
|
|
|
__ movsd(Address(ESP, 8), right);
|
|
|
|
// Move updated value into output register.
|
|
|
|
__ movups(left, Address(ESP, 0));
|
|
|
|
__ addl(ESP, Immediate(16));
|
|
|
|
break;
|
|
|
|
case MethodRecognizer::kFloat64x2Min:
|
|
|
|
__ minpd(left, right);
|
|
|
|
break;
|
|
|
|
case MethodRecognizer::kFloat64x2Max:
|
|
|
|
__ maxpd(left, right);
|
|
|
|
break;
|
|
|
|
default: UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-12-16 15:11:31 +00:00
|
|
|
LocationSummary* Int32x4BoolConstructorInstr::MakeLocationSummary(
|
2014-05-23 12:07:33 +00:00
|
|
|
Isolate* isolate, bool opt) const {
|
2013-05-13 20:22:06 +00:00
|
|
|
const intptr_t kNumInputs = 4;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-05-13 20:22:06 +00:00
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
|
|
|
summary->set_in(1, Location::RequiresRegister());
|
|
|
|
summary->set_in(2, Location::RequiresRegister());
|
|
|
|
summary->set_in(3, Location::RequiresRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::RequiresFpuRegister());
|
2013-05-13 20:22:06 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-04 21:56:59 +00:00
|
|
|
void Int32x4BoolConstructorInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2013-05-13 20:22:06 +00:00
|
|
|
Register v0 = locs()->in(0).reg();
|
|
|
|
Register v1 = locs()->in(1).reg();
|
|
|
|
Register v2 = locs()->in(2).reg();
|
|
|
|
Register v3 = locs()->in(3).reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
XmmRegister result = locs()->out(0).fpu_reg();
|
2013-05-13 20:22:06 +00:00
|
|
|
Label x_false, x_done;
|
|
|
|
Label y_false, y_done;
|
|
|
|
Label z_false, z_done;
|
|
|
|
Label w_false, w_done;
|
|
|
|
__ subl(ESP, Immediate(16));
|
|
|
|
__ CompareObject(v0, Bool::True());
|
|
|
|
__ j(NOT_EQUAL, &x_false);
|
|
|
|
__ movl(Address(ESP, 0), Immediate(0xFFFFFFFF));
|
|
|
|
__ jmp(&x_done);
|
|
|
|
__ Bind(&x_false);
|
|
|
|
__ movl(Address(ESP, 0), Immediate(0x0));
|
|
|
|
__ Bind(&x_done);
|
|
|
|
|
|
|
|
__ CompareObject(v1, Bool::True());
|
|
|
|
__ j(NOT_EQUAL, &y_false);
|
|
|
|
__ movl(Address(ESP, 4), Immediate(0xFFFFFFFF));
|
|
|
|
__ jmp(&y_done);
|
|
|
|
__ Bind(&y_false);
|
|
|
|
__ movl(Address(ESP, 4), Immediate(0x0));
|
|
|
|
__ Bind(&y_done);
|
|
|
|
|
|
|
|
__ CompareObject(v2, Bool::True());
|
|
|
|
__ j(NOT_EQUAL, &z_false);
|
|
|
|
__ movl(Address(ESP, 8), Immediate(0xFFFFFFFF));
|
|
|
|
__ jmp(&z_done);
|
|
|
|
__ Bind(&z_false);
|
|
|
|
__ movl(Address(ESP, 8), Immediate(0x0));
|
|
|
|
__ Bind(&z_done);
|
|
|
|
|
|
|
|
__ CompareObject(v3, Bool::True());
|
|
|
|
__ j(NOT_EQUAL, &w_false);
|
|
|
|
__ movl(Address(ESP, 12), Immediate(0xFFFFFFFF));
|
|
|
|
__ jmp(&w_done);
|
|
|
|
__ Bind(&w_false);
|
|
|
|
__ movl(Address(ESP, 12), Immediate(0x0));
|
|
|
|
__ Bind(&w_done);
|
|
|
|
|
|
|
|
__ movups(result, Address(ESP, 0));
|
|
|
|
__ addl(ESP, Immediate(16));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* Int32x4GetFlagInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-05-13 20:22:06 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-05-13 20:22:06 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::RequiresRegister());
|
2013-05-13 20:22:06 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-04 21:56:59 +00:00
|
|
|
void Int32x4GetFlagInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2013-05-13 20:22:06 +00:00
|
|
|
XmmRegister value = locs()->in(0).fpu_reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
Register result = locs()->out(0).reg();
|
2013-05-13 20:22:06 +00:00
|
|
|
Label done;
|
|
|
|
Label non_zero;
|
|
|
|
__ subl(ESP, Immediate(16));
|
|
|
|
// Move value to stack.
|
|
|
|
__ movups(Address(ESP, 0), value);
|
|
|
|
switch (op_kind()) {
|
2013-11-04 21:56:59 +00:00
|
|
|
case MethodRecognizer::kInt32x4GetFlagX:
|
2013-05-13 20:22:06 +00:00
|
|
|
__ movl(result, Address(ESP, 0));
|
|
|
|
break;
|
2013-11-04 21:56:59 +00:00
|
|
|
case MethodRecognizer::kInt32x4GetFlagY:
|
2013-05-13 20:22:06 +00:00
|
|
|
__ movl(result, Address(ESP, 4));
|
|
|
|
break;
|
2013-11-04 21:56:59 +00:00
|
|
|
case MethodRecognizer::kInt32x4GetFlagZ:
|
2013-05-13 20:22:06 +00:00
|
|
|
__ movl(result, Address(ESP, 8));
|
|
|
|
break;
|
2013-11-04 21:56:59 +00:00
|
|
|
case MethodRecognizer::kInt32x4GetFlagW:
|
2013-05-13 20:22:06 +00:00
|
|
|
__ movl(result, Address(ESP, 12));
|
|
|
|
break;
|
|
|
|
default: UNREACHABLE();
|
|
|
|
}
|
|
|
|
__ addl(ESP, Immediate(16));
|
|
|
|
__ testl(result, result);
|
|
|
|
__ j(NOT_ZERO, &non_zero, Assembler::kNearJump);
|
|
|
|
__ LoadObject(result, Bool::False());
|
|
|
|
__ jmp(&done);
|
|
|
|
__ Bind(&non_zero);
|
|
|
|
__ LoadObject(result, Bool::True());
|
|
|
|
__ Bind(&done);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* Int32x4SelectInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-05-13 20:22:06 +00:00
|
|
|
const intptr_t kNumInputs = 3;
|
|
|
|
const intptr_t kNumTemps = 1;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-05-13 20:22:06 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
|
|
|
summary->set_in(1, Location::RequiresFpuRegister());
|
|
|
|
summary->set_in(2, Location::RequiresFpuRegister());
|
|
|
|
summary->set_temp(0, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2013-05-13 20:22:06 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-04 21:56:59 +00:00
|
|
|
void Int32x4SelectInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2013-05-13 20:22:06 +00:00
|
|
|
XmmRegister mask = locs()->in(0).fpu_reg();
|
|
|
|
XmmRegister trueValue = locs()->in(1).fpu_reg();
|
|
|
|
XmmRegister falseValue = locs()->in(2).fpu_reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
XmmRegister out = locs()->out(0).fpu_reg();
|
2013-05-13 20:22:06 +00:00
|
|
|
XmmRegister temp = locs()->temp(0).fpu_reg();
|
|
|
|
ASSERT(out == mask);
|
|
|
|
// Copy mask.
|
|
|
|
__ movaps(temp, mask);
|
|
|
|
// Invert it.
|
|
|
|
__ notps(temp);
|
|
|
|
// mask = mask & trueValue.
|
|
|
|
__ andps(mask, trueValue);
|
|
|
|
// temp = temp & falseValue.
|
|
|
|
__ andps(temp, falseValue);
|
|
|
|
// out = mask | temp.
|
|
|
|
__ orps(mask, temp);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* Int32x4SetFlagInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-05-13 20:22:06 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-05-13 20:22:06 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
|
|
|
summary->set_in(1, Location::RequiresRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2013-05-13 20:22:06 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-04 21:56:59 +00:00
|
|
|
void Int32x4SetFlagInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2013-05-13 20:22:06 +00:00
|
|
|
XmmRegister mask = locs()->in(0).fpu_reg();
|
|
|
|
Register flag = locs()->in(1).reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
ASSERT(mask == locs()->out(0).fpu_reg());
|
2013-05-13 20:22:06 +00:00
|
|
|
__ subl(ESP, Immediate(16));
|
|
|
|
// Copy mask to stack.
|
|
|
|
__ movups(Address(ESP, 0), mask);
|
|
|
|
Label falsePath, exitPath;
|
|
|
|
__ CompareObject(flag, Bool::True());
|
|
|
|
__ j(NOT_EQUAL, &falsePath);
|
|
|
|
switch (op_kind()) {
|
2013-11-04 21:56:59 +00:00
|
|
|
case MethodRecognizer::kInt32x4WithFlagX:
|
2013-05-13 20:22:06 +00:00
|
|
|
__ movl(Address(ESP, 0), Immediate(0xFFFFFFFF));
|
|
|
|
__ jmp(&exitPath);
|
|
|
|
__ Bind(&falsePath);
|
|
|
|
__ movl(Address(ESP, 0), Immediate(0x0));
|
|
|
|
break;
|
2013-11-04 21:56:59 +00:00
|
|
|
case MethodRecognizer::kInt32x4WithFlagY:
|
2013-05-13 20:22:06 +00:00
|
|
|
__ movl(Address(ESP, 4), Immediate(0xFFFFFFFF));
|
|
|
|
__ jmp(&exitPath);
|
|
|
|
__ Bind(&falsePath);
|
|
|
|
__ movl(Address(ESP, 4), Immediate(0x0));
|
|
|
|
break;
|
2013-11-04 21:56:59 +00:00
|
|
|
case MethodRecognizer::kInt32x4WithFlagZ:
|
2013-05-13 20:22:06 +00:00
|
|
|
__ movl(Address(ESP, 8), Immediate(0xFFFFFFFF));
|
|
|
|
__ jmp(&exitPath);
|
|
|
|
__ Bind(&falsePath);
|
|
|
|
__ movl(Address(ESP, 8), Immediate(0x0));
|
|
|
|
break;
|
2013-11-04 21:56:59 +00:00
|
|
|
case MethodRecognizer::kInt32x4WithFlagW:
|
2013-05-13 20:22:06 +00:00
|
|
|
__ movl(Address(ESP, 12), Immediate(0xFFFFFFFF));
|
|
|
|
__ jmp(&exitPath);
|
|
|
|
__ Bind(&falsePath);
|
|
|
|
__ movl(Address(ESP, 12), Immediate(0x0));
|
|
|
|
break;
|
|
|
|
default: UNREACHABLE();
|
|
|
|
}
|
|
|
|
__ Bind(&exitPath);
|
|
|
|
// Copy mask back to register.
|
|
|
|
__ movups(mask, Address(ESP, 0));
|
|
|
|
__ addl(ESP, Immediate(16));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* Int32x4ToFloat32x4Instr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-05-13 20:22:06 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-05-13 20:22:06 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2013-05-13 20:22:06 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-04 21:56:59 +00:00
|
|
|
void Int32x4ToFloat32x4Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2013-05-13 20:22:06 +00:00
|
|
|
// NOP.
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* BinaryInt32x4OpInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-05-13 20:22:06 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-05-13 20:22:06 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
|
|
|
summary->set_in(1, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2013-05-13 20:22:06 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-04 21:56:59 +00:00
|
|
|
void BinaryInt32x4OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2013-05-13 20:22:06 +00:00
|
|
|
XmmRegister left = locs()->in(0).fpu_reg();
|
|
|
|
XmmRegister right = locs()->in(1).fpu_reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
ASSERT(left == locs()->out(0).fpu_reg());
|
2013-05-13 20:22:06 +00:00
|
|
|
switch (op_kind()) {
|
|
|
|
case Token::kBIT_AND: {
|
|
|
|
__ andps(left, right);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token::kBIT_OR: {
|
|
|
|
__ orps(left, right);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token::kBIT_XOR: {
|
|
|
|
__ xorps(left, right);
|
|
|
|
break;
|
|
|
|
}
|
2013-08-20 14:34:06 +00:00
|
|
|
case Token::kADD:
|
|
|
|
__ addpl(left, right);
|
|
|
|
break;
|
|
|
|
case Token::kSUB:
|
|
|
|
__ subpl(left, right);
|
|
|
|
break;
|
2013-05-13 20:22:06 +00:00
|
|
|
default: UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* MathUnaryInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2014-05-02 22:38:18 +00:00
|
|
|
if ((kind() == MathUnaryInstr::kSin) || (kind() == MathUnaryInstr::kCos)) {
|
2013-09-06 18:14:53 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
2014-02-27 17:39:04 +00:00
|
|
|
const intptr_t kNumTemps = 1;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kCall);
|
2013-09-06 18:14:53 +00:00
|
|
|
summary->set_in(0, Location::FpuRegisterLocation(XMM1));
|
2014-02-27 17:39:04 +00:00
|
|
|
// EDI is chosen because it is callee saved so we do not need to back it
|
|
|
|
// up before calling into the runtime.
|
|
|
|
summary->set_temp(0, Location::RegisterLocation(EDI));
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::FpuRegisterLocation(XMM1));
|
2013-09-06 18:14:53 +00:00
|
|
|
return summary;
|
|
|
|
}
|
2014-05-02 22:38:18 +00:00
|
|
|
ASSERT((kind() == MathUnaryInstr::kSqrt) ||
|
|
|
|
(kind() == MathUnaryInstr::kDoubleSquare));
|
2012-09-11 14:52:32 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-01-18 00:34:20 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
2014-05-02 22:38:18 +00:00
|
|
|
if (kind() == MathUnaryInstr::kDoubleSquare) {
|
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
|
|
|
} else {
|
|
|
|
summary->set_out(0, Location::RequiresFpuRegister());
|
|
|
|
}
|
2012-09-11 14:52:32 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-06 15:46:28 +00:00
|
|
|
void MathUnaryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2014-05-02 22:38:18 +00:00
|
|
|
if (kind() == MathUnaryInstr::kSqrt) {
|
2014-03-21 14:40:30 +00:00
|
|
|
__ sqrtsd(locs()->out(0).fpu_reg(), locs()->in(0).fpu_reg());
|
2014-05-02 22:38:18 +00:00
|
|
|
} else if (kind() == MathUnaryInstr::kDoubleSquare) {
|
|
|
|
XmmRegister value_reg = locs()->in(0).fpu_reg();
|
|
|
|
__ mulsd(value_reg, value_reg);
|
|
|
|
ASSERT(value_reg == locs()->out(0).fpu_reg());
|
2013-09-06 18:14:53 +00:00
|
|
|
} else {
|
2014-05-02 22:38:18 +00:00
|
|
|
ASSERT((kind() == MathUnaryInstr::kSin) ||
|
|
|
|
(kind() == MathUnaryInstr::kCos));
|
2014-02-27 17:39:04 +00:00
|
|
|
// Save ESP.
|
|
|
|
__ movl(locs()->temp(0).reg(), ESP);
|
2013-09-06 18:14:53 +00:00
|
|
|
__ ReserveAlignedFrameSpace(kDoubleSize * InputCount());
|
2013-08-06 15:46:28 +00:00
|
|
|
__ movsd(Address(ESP, 0), locs()->in(0).fpu_reg());
|
2013-09-06 18:14:53 +00:00
|
|
|
__ CallRuntime(TargetFunction(), InputCount());
|
2013-08-06 15:46:28 +00:00
|
|
|
__ fstpl(Address(ESP, 0));
|
2014-03-21 14:40:30 +00:00
|
|
|
__ movsd(locs()->out(0).fpu_reg(), Address(ESP, 0));
|
2014-02-27 17:39:04 +00:00
|
|
|
// Restore ESP.
|
|
|
|
__ movl(ESP, locs()->temp(0).reg());
|
2013-08-06 15:46:28 +00:00
|
|
|
}
|
2012-09-11 14:52:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* MathMinMaxInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-07-22 17:27:45 +00:00
|
|
|
if (result_cid() == kDoubleCid) {
|
|
|
|
const intptr_t kNumInputs = 2;
|
2013-07-22 21:37:43 +00:00
|
|
|
const intptr_t kNumTemps = 1;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-07-22 17:27:45 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
|
|
|
summary->set_in(1, Location::RequiresFpuRegister());
|
2013-07-23 20:40:31 +00:00
|
|
|
// Reuse the left register so that code can be made shorter.
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2013-07-22 21:37:43 +00:00
|
|
|
summary->set_temp(0, Location::RequiresRegister());
|
2013-07-22 17:27:45 +00:00
|
|
|
return summary;
|
|
|
|
}
|
2013-07-31 22:57:33 +00:00
|
|
|
|
2013-07-22 17:27:45 +00:00
|
|
|
ASSERT(result_cid() == kSmiCid);
|
2013-07-23 20:40:31 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-07-23 20:40:31 +00:00
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
|
|
|
summary->set_in(1, Location::RequiresRegister());
|
|
|
|
// Reuse the left register so that code can be made shorter.
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2013-07-23 20:40:31 +00:00
|
|
|
return summary;
|
2013-07-22 17:27:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void MathMinMaxInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2013-07-22 21:37:43 +00:00
|
|
|
ASSERT((op_kind() == MethodRecognizer::kMathMin) ||
|
|
|
|
(op_kind() == MethodRecognizer::kMathMax));
|
2013-07-23 20:40:31 +00:00
|
|
|
const intptr_t is_min = (op_kind() == MethodRecognizer::kMathMin);
|
2013-07-22 17:27:45 +00:00
|
|
|
if (result_cid() == kDoubleCid) {
|
2013-07-23 20:40:31 +00:00
|
|
|
Label done, returns_nan, are_equal;
|
2013-07-22 17:27:45 +00:00
|
|
|
XmmRegister left = locs()->in(0).fpu_reg();
|
|
|
|
XmmRegister right = locs()->in(1).fpu_reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
XmmRegister result = locs()->out(0).fpu_reg();
|
2013-07-22 21:37:43 +00:00
|
|
|
Register temp = locs()->temp(0).reg();
|
2013-07-22 17:27:45 +00:00
|
|
|
__ comisd(left, right);
|
2013-07-22 21:37:43 +00:00
|
|
|
__ j(PARITY_EVEN, &returns_nan, Assembler::kNearJump);
|
|
|
|
__ j(EQUAL, &are_equal, Assembler::kNearJump);
|
|
|
|
const Condition double_condition =
|
|
|
|
is_min ? TokenKindToDoubleCondition(Token::kLT)
|
|
|
|
: TokenKindToDoubleCondition(Token::kGT);
|
2013-07-23 20:40:31 +00:00
|
|
|
ASSERT(left == result);
|
|
|
|
__ j(double_condition, &done, Assembler::kNearJump);
|
2013-07-22 17:27:45 +00:00
|
|
|
__ movsd(result, right);
|
|
|
|
__ jmp(&done, Assembler::kNearJump);
|
2013-07-22 21:37:43 +00:00
|
|
|
|
|
|
|
__ Bind(&returns_nan);
|
2013-07-22 17:27:45 +00:00
|
|
|
static double kNaN = NAN;
|
|
|
|
__ movsd(result, Address::Absolute(reinterpret_cast<uword>(&kNaN)));
|
2013-07-22 21:37:43 +00:00
|
|
|
__ jmp(&done, Assembler::kNearJump);
|
|
|
|
|
|
|
|
__ Bind(&are_equal);
|
|
|
|
Label left_is_negative;
|
|
|
|
// Check for negative zero: -0.0 is equal 0.0 but min or max must return
|
|
|
|
// -0.0 or 0.0 respectively.
|
|
|
|
// Check for negative left value (get the sign bit):
|
|
|
|
// - min -> left is negative ? left : right.
|
|
|
|
// - max -> left is negative ? right : left
|
|
|
|
// Check the sign bit.
|
|
|
|
__ movmskpd(temp, left);
|
|
|
|
__ testl(temp, Immediate(1));
|
2013-07-23 20:40:31 +00:00
|
|
|
ASSERT(left == result);
|
|
|
|
if (is_min) {
|
|
|
|
__ j(NOT_ZERO, &done, Assembler::kNearJump); // Negative -> return left.
|
|
|
|
} else {
|
|
|
|
__ j(ZERO, &done, Assembler::kNearJump); // Positive -> return left.
|
|
|
|
}
|
|
|
|
__ movsd(result, right);
|
2013-07-22 17:27:45 +00:00
|
|
|
__ Bind(&done);
|
|
|
|
return;
|
|
|
|
}
|
2013-07-23 20:40:31 +00:00
|
|
|
|
2013-07-22 17:27:45 +00:00
|
|
|
ASSERT(result_cid() == kSmiCid);
|
2013-07-23 20:40:31 +00:00
|
|
|
Register left = locs()->in(0).reg();
|
|
|
|
Register right = locs()->in(1).reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
Register result = locs()->out(0).reg();
|
2013-07-23 20:40:31 +00:00
|
|
|
__ cmpl(left, right);
|
2013-07-31 22:57:33 +00:00
|
|
|
ASSERT(result == left);
|
2013-07-23 20:40:31 +00:00
|
|
|
if (is_min) {
|
2013-07-31 22:57:33 +00:00
|
|
|
__ cmovgel(result, right);
|
2013-07-23 20:40:31 +00:00
|
|
|
} else {
|
2013-07-31 22:57:33 +00:00
|
|
|
__ cmovlessl(result, right);
|
2013-07-23 20:40:31 +00:00
|
|
|
}
|
2013-07-22 17:27:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* UnarySmiOpInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2012-06-01 18:38:35 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
2014-05-27 10:15:50 +00:00
|
|
|
return LocationSummary::Make(isolate,
|
|
|
|
kNumInputs,
|
2013-05-06 17:22:18 +00:00
|
|
|
Location::SameAsFirstInput(),
|
|
|
|
LocationSummary::kNoCall);
|
2012-05-31 20:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void UnarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-06-01 18:38:35 +00:00
|
|
|
Register value = locs()->in(0).reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
ASSERT(value == locs()->out(0).reg());
|
2012-08-27 16:10:04 +00:00
|
|
|
switch (op_kind()) {
|
|
|
|
case Token::kNEGATE: {
|
2014-04-25 23:45:14 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnaryOp);
|
2012-08-27 16:10:04 +00:00
|
|
|
__ negl(value);
|
|
|
|
__ j(OVERFLOW, deopt);
|
|
|
|
break;
|
2012-06-01 18:38:35 +00:00
|
|
|
}
|
2012-08-27 16:10:04 +00:00
|
|
|
case Token::kBIT_NOT:
|
|
|
|
__ notl(value);
|
|
|
|
__ andl(value, Immediate(~kSmiTagMask)); // Remove inverted smi-tag.
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
2012-06-01 18:38:35 +00:00
|
|
|
}
|
2012-05-31 20:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* UnaryDoubleOpInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-08-14 23:45:13 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-08-14 23:45:13 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2013-08-14 23:45:13 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UnaryDoubleOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
XmmRegister value = locs()->in(0).fpu_reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
ASSERT(locs()->out(0).fpu_reg() == value);
|
2013-08-14 23:45:13 +00:00
|
|
|
__ DoubleNegate(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* SmiToDoubleInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-04-26 18:10:59 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* result = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-04-26 18:10:59 +00:00
|
|
|
result->set_in(0, Location::WritableRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
result->set_out(0, Location::RequiresFpuRegister());
|
2013-04-26 18:10:59 +00:00
|
|
|
return result;
|
2012-08-15 11:31:51 +00:00
|
|
|
}
|
2012-06-13 08:29:40 +00:00
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void SmiToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2013-04-26 18:10:59 +00:00
|
|
|
Register value = locs()->in(0).reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
FpuRegister result = locs()->out(0).fpu_reg();
|
2012-06-13 08:29:40 +00:00
|
|
|
__ SmiUntag(value);
|
2013-04-26 18:10:59 +00:00
|
|
|
__ cvtsi2sd(result, value);
|
2012-06-13 08:29:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* DoubleToIntegerInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2012-10-09 21:43:10 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* result = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kCall);
|
2012-10-09 21:43:10 +00:00
|
|
|
result->set_in(0, Location::RegisterLocation(ECX));
|
2014-03-21 14:40:30 +00:00
|
|
|
result->set_out(0, Location::RegisterLocation(EAX));
|
2012-10-09 21:43:10 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DoubleToIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2014-03-21 14:40:30 +00:00
|
|
|
Register result = locs()->out(0).reg();
|
2012-10-09 21:43:10 +00:00
|
|
|
Register value_obj = locs()->in(0).reg();
|
|
|
|
XmmRegister value_double = XMM0;
|
|
|
|
ASSERT(result == EAX);
|
|
|
|
ASSERT(result != value_obj);
|
|
|
|
__ movsd(value_double, FieldAddress(value_obj, Double::value_offset()));
|
|
|
|
__ cvttsd2si(result, value_double);
|
|
|
|
// Overflow is signalled with minint.
|
|
|
|
Label do_call, done;
|
|
|
|
// Check for overflow and that it fits into Smi.
|
|
|
|
__ cmpl(result, Immediate(0xC0000000));
|
|
|
|
__ j(NEGATIVE, &do_call, Assembler::kNearJump);
|
|
|
|
__ SmiTag(result);
|
|
|
|
__ jmp(&done);
|
|
|
|
__ Bind(&do_call);
|
|
|
|
__ pushl(value_obj);
|
|
|
|
ASSERT(instance_call()->HasICData());
|
|
|
|
const ICData& ic_data = *instance_call()->ic_data();
|
|
|
|
ASSERT((ic_data.NumberOfChecks() == 1));
|
|
|
|
const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0));
|
|
|
|
|
|
|
|
const intptr_t kNumberOfArguments = 1;
|
2013-05-06 17:22:18 +00:00
|
|
|
compiler->GenerateStaticCall(deopt_id(),
|
2012-10-09 21:43:10 +00:00
|
|
|
instance_call()->token_pos(),
|
|
|
|
target,
|
|
|
|
kNumberOfArguments,
|
2013-06-20 16:29:39 +00:00
|
|
|
Object::null_array(), // No argument names.,
|
2012-10-09 21:43:10 +00:00
|
|
|
locs());
|
|
|
|
__ Bind(&done);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* DoubleToSmiInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2012-12-18 18:43:29 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* result = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-01-18 00:34:20 +00:00
|
|
|
result->set_in(0, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
result->set_out(0, Location::RequiresRegister());
|
2012-12-18 18:43:29 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DoubleToSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2014-04-25 23:45:14 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptDoubleToSmi);
|
2014-03-21 14:40:30 +00:00
|
|
|
Register result = locs()->out(0).reg();
|
2013-01-18 00:34:20 +00:00
|
|
|
XmmRegister value = locs()->in(0).fpu_reg();
|
2012-12-18 18:43:29 +00:00
|
|
|
__ cvttsd2si(result, value);
|
|
|
|
// Check for overflow and that it fits into Smi.
|
|
|
|
__ cmpl(result, Immediate(0xC0000000));
|
|
|
|
__ j(NEGATIVE, deopt);
|
|
|
|
__ SmiTag(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* DoubleToDoubleInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-01-11 20:42:47 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
2013-02-25 23:05:43 +00:00
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* result = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-01-18 00:34:20 +00:00
|
|
|
result->set_in(0, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
result->set_out(0, Location::RequiresFpuRegister());
|
2013-01-11 20:42:47 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DoubleToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2013-01-18 00:34:20 +00:00
|
|
|
XmmRegister value = locs()->in(0).fpu_reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
XmmRegister result = locs()->out(0).fpu_reg();
|
2013-01-18 14:28:25 +00:00
|
|
|
switch (recognized_kind()) {
|
|
|
|
case MethodRecognizer::kDoubleTruncate:
|
|
|
|
__ roundsd(result, value, Assembler::kRoundToZero);
|
|
|
|
break;
|
|
|
|
case MethodRecognizer::kDoubleFloor:
|
|
|
|
__ roundsd(result, value, Assembler::kRoundDown);
|
|
|
|
break;
|
|
|
|
case MethodRecognizer::kDoubleCeil:
|
|
|
|
__ roundsd(result, value, Assembler::kRoundUp);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
2013-01-11 20:42:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* DoubleToFloatInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2014-02-21 12:12:29 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* result = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2014-02-21 12:12:29 +00:00
|
|
|
result->set_in(0, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
result->set_out(0, Location::SameAsFirstInput());
|
2014-02-21 12:12:29 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DoubleToFloatInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2014-03-21 14:40:30 +00:00
|
|
|
__ cvtsd2ss(locs()->out(0).fpu_reg(), locs()->in(0).fpu_reg());
|
2014-02-21 12:12:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* FloatToDoubleInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2014-02-21 12:12:29 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* result = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2014-02-21 12:12:29 +00:00
|
|
|
result->set_in(0, Location::RequiresFpuRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
result->set_out(0, Location::SameAsFirstInput());
|
2014-02-21 12:12:29 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FloatToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2014-03-21 14:40:30 +00:00
|
|
|
__ cvtss2sd(locs()->out(0).fpu_reg(), locs()->in(0).fpu_reg());
|
2014-02-21 12:12:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* InvokeMathCFunctionInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-01-22 12:18:31 +00:00
|
|
|
ASSERT((InputCount() == 1) || (InputCount() == 2));
|
2014-06-03 16:40:30 +00:00
|
|
|
const intptr_t kNumTemps =
|
|
|
|
(recognized_kind() == MethodRecognizer::kMathDoublePow) ? 3 : 1;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* result = new(isolate) LocationSummary(
|
|
|
|
isolate, InputCount(), kNumTemps, LocationSummary::kCall);
|
2014-02-27 17:39:04 +00:00
|
|
|
// EDI is chosen because it is callee saved so we do not need to back it
|
|
|
|
// up before calling into the runtime.
|
|
|
|
result->set_temp(0, Location::RegisterLocation(EDI));
|
2013-04-09 12:23:46 +00:00
|
|
|
result->set_in(0, Location::FpuRegisterLocation(XMM1));
|
2013-01-22 12:18:31 +00:00
|
|
|
if (InputCount() == 2) {
|
2013-04-09 12:23:46 +00:00
|
|
|
result->set_in(1, Location::FpuRegisterLocation(XMM2));
|
2013-01-22 12:18:31 +00:00
|
|
|
}
|
2013-08-26 17:38:51 +00:00
|
|
|
if (recognized_kind() == MethodRecognizer::kMathDoublePow) {
|
2014-02-27 17:39:04 +00:00
|
|
|
// Temp index 1.
|
2014-06-03 16:40:30 +00:00
|
|
|
result->set_temp(1, Location::RegisterLocation(EAX));
|
2014-02-27 17:39:04 +00:00
|
|
|
// Temp index 2.
|
2014-06-03 16:40:30 +00:00
|
|
|
result->set_temp(2, Location::FpuRegisterLocation(XMM4));
|
2013-08-26 17:38:51 +00:00
|
|
|
}
|
2014-03-21 14:40:30 +00:00
|
|
|
result->set_out(0, Location::FpuRegisterLocation(XMM3));
|
2013-01-22 12:18:31 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-08 22:18:04 +00:00
|
|
|
// Pseudo code:
|
|
|
|
// if (exponent == 0.0) return 1.0;
|
|
|
|
// // Speed up simple cases.
|
|
|
|
// if (exponent == 1.0) return base;
|
|
|
|
// if (exponent == 2.0) return base * base;
|
|
|
|
// if (exponent == 3.0) return base * base * base;
|
|
|
|
// if (base == 1.0) return 1.0;
|
|
|
|
// if (base.isNaN || exponent.isNaN) {
|
|
|
|
// return double.NAN;
|
|
|
|
// }
|
|
|
|
// if (base != -Infinity && exponent == 0.5) {
|
|
|
|
// if (base == 0.0) return 0.0;
|
|
|
|
// return sqrt(value);
|
|
|
|
// }
|
|
|
|
// TODO(srdjan): Move into a stub?
|
|
|
|
static void InvokeDoublePow(FlowGraphCompiler* compiler,
|
|
|
|
InvokeMathCFunctionInstr* instr) {
|
|
|
|
ASSERT(instr->recognized_kind() == MethodRecognizer::kMathDoublePow);
|
|
|
|
const intptr_t kInputCount = 2;
|
|
|
|
ASSERT(instr->InputCount() == kInputCount);
|
|
|
|
LocationSummary* locs = instr->locs();
|
|
|
|
|
|
|
|
XmmRegister base = locs->in(0).fpu_reg();
|
|
|
|
XmmRegister exp = locs->in(1).fpu_reg();
|
|
|
|
XmmRegister result = locs->out(0).fpu_reg();
|
|
|
|
Register temp = locs->temp(InvokeMathCFunctionInstr::kObjectTempIndex).reg();
|
|
|
|
XmmRegister zero_temp =
|
|
|
|
locs->temp(InvokeMathCFunctionInstr::kDoubleTempIndex).fpu_reg();
|
|
|
|
|
|
|
|
__ xorps(zero_temp, zero_temp); // 0.0.
|
|
|
|
__ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(1.0)));
|
|
|
|
__ movsd(result, FieldAddress(temp, Double::value_offset()));
|
|
|
|
|
|
|
|
Label check_base, skip_call;
|
|
|
|
// exponent == 0.0 -> return 1.0;
|
|
|
|
__ comisd(exp, zero_temp);
|
|
|
|
__ j(PARITY_EVEN, &check_base);
|
|
|
|
__ j(EQUAL, &skip_call); // 'result' is 1.0.
|
|
|
|
|
|
|
|
// exponent == 1.0 ?
|
|
|
|
__ comisd(exp, result);
|
|
|
|
Label return_base;
|
|
|
|
__ j(EQUAL, &return_base, Assembler::kNearJump);
|
|
|
|
|
|
|
|
// exponent == 2.0 ?
|
|
|
|
__ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(2.0)));
|
|
|
|
__ movsd(XMM0, FieldAddress(temp, Double::value_offset()));
|
|
|
|
__ comisd(exp, XMM0);
|
|
|
|
Label return_base_times_2;
|
|
|
|
__ j(EQUAL, &return_base_times_2, Assembler::kNearJump);
|
|
|
|
|
|
|
|
// exponent == 3.0 ?
|
|
|
|
__ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(3.0)));
|
|
|
|
__ movsd(XMM0, FieldAddress(temp, Double::value_offset()));
|
|
|
|
__ comisd(exp, XMM0);
|
|
|
|
__ j(NOT_EQUAL, &check_base);
|
|
|
|
|
|
|
|
// Base times 3.
|
|
|
|
__ movsd(result, base);
|
|
|
|
__ mulsd(result, base);
|
|
|
|
__ mulsd(result, base);
|
|
|
|
__ jmp(&skip_call);
|
|
|
|
|
|
|
|
__ Bind(&return_base);
|
|
|
|
__ movsd(result, base);
|
|
|
|
__ jmp(&skip_call);
|
|
|
|
|
|
|
|
__ Bind(&return_base_times_2);
|
|
|
|
__ movsd(result, base);
|
|
|
|
__ mulsd(result, base);
|
|
|
|
__ jmp(&skip_call);
|
|
|
|
|
|
|
|
__ Bind(&check_base);
|
|
|
|
// Note: 'exp' could be NaN.
|
|
|
|
|
|
|
|
// base == 1.0 -> return 1.0;
|
|
|
|
__ comisd(base, result);
|
|
|
|
Label return_nan;
|
|
|
|
__ j(PARITY_EVEN, &return_nan, Assembler::kNearJump);
|
|
|
|
__ j(EQUAL, &skip_call, Assembler::kNearJump);
|
|
|
|
// Note: 'base' could be NaN.
|
|
|
|
__ comisd(exp, base);
|
|
|
|
// Neither 'exp' nor 'base' is NaN.
|
|
|
|
Label try_sqrt;
|
|
|
|
__ j(PARITY_ODD, &try_sqrt, Assembler::kNearJump);
|
|
|
|
// Return NaN.
|
|
|
|
__ Bind(&return_nan);
|
|
|
|
__ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(NAN)));
|
|
|
|
__ movsd(result, FieldAddress(temp, Double::value_offset()));
|
|
|
|
__ jmp(&skip_call);
|
|
|
|
|
|
|
|
Label do_pow, return_zero;
|
|
|
|
__ Bind(&try_sqrt);
|
|
|
|
// Before calling pow, check if we could use sqrt instead of pow.
|
|
|
|
__ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(-INFINITY)));
|
|
|
|
__ movsd(result, FieldAddress(temp, Double::value_offset()));
|
|
|
|
// base == -Infinity -> call pow;
|
|
|
|
__ comisd(base, result);
|
|
|
|
__ j(EQUAL, &do_pow, Assembler::kNearJump);
|
|
|
|
|
|
|
|
// exponent == 0.5 ?
|
|
|
|
__ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(0.5)));
|
|
|
|
__ movsd(result, FieldAddress(temp, Double::value_offset()));
|
|
|
|
__ comisd(exp, result);
|
|
|
|
__ j(NOT_EQUAL, &do_pow, Assembler::kNearJump);
|
|
|
|
|
|
|
|
// base == 0 -> return 0;
|
|
|
|
__ comisd(base, zero_temp);
|
|
|
|
__ j(EQUAL, &return_zero, Assembler::kNearJump);
|
|
|
|
|
|
|
|
__ sqrtsd(result, base);
|
|
|
|
__ jmp(&skip_call, Assembler::kNearJump);
|
|
|
|
|
|
|
|
__ Bind(&return_zero);
|
|
|
|
__ movsd(result, zero_temp);
|
|
|
|
__ jmp(&skip_call);
|
|
|
|
|
|
|
|
__ Bind(&do_pow);
|
|
|
|
// Save ESP.
|
|
|
|
__ movl(locs->temp(InvokeMathCFunctionInstr::kSavedSpTempIndex).reg(), ESP);
|
|
|
|
__ ReserveAlignedFrameSpace(kDoubleSize * kInputCount);
|
|
|
|
for (intptr_t i = 0; i < kInputCount; i++) {
|
|
|
|
__ movsd(Address(ESP, kDoubleSize * i), locs->in(i).fpu_reg());
|
|
|
|
}
|
|
|
|
__ CallRuntime(instr->TargetFunction(), kInputCount);
|
|
|
|
__ fstpl(Address(ESP, 0));
|
|
|
|
__ movsd(locs->out(0).fpu_reg(), Address(ESP, 0));
|
|
|
|
// Restore ESP.
|
|
|
|
__ movl(ESP, locs->temp(InvokeMathCFunctionInstr::kSavedSpTempIndex).reg());
|
|
|
|
__ Bind(&skip_call);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-01-22 12:18:31 +00:00
|
|
|
void InvokeMathCFunctionInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2014-05-08 22:18:04 +00:00
|
|
|
if (recognized_kind() == MethodRecognizer::kMathDoublePow) {
|
|
|
|
InvokeDoublePow(compiler, this);
|
|
|
|
return;
|
|
|
|
}
|
2014-02-27 17:39:04 +00:00
|
|
|
// Save ESP.
|
|
|
|
__ movl(locs()->temp(kSavedSpTempIndex).reg(), ESP);
|
2013-01-22 12:18:31 +00:00
|
|
|
__ ReserveAlignedFrameSpace(kDoubleSize * InputCount());
|
|
|
|
for (intptr_t i = 0; i < InputCount(); i++) {
|
|
|
|
__ movsd(Address(ESP, kDoubleSize * i), locs()->in(i).fpu_reg());
|
|
|
|
}
|
2014-04-01 23:25:06 +00:00
|
|
|
|
2013-08-28 23:07:14 +00:00
|
|
|
__ CallRuntime(TargetFunction(), InputCount());
|
2013-01-22 12:18:31 +00:00
|
|
|
__ fstpl(Address(ESP, 0));
|
2014-03-21 14:40:30 +00:00
|
|
|
__ movsd(locs()->out(0).fpu_reg(), Address(ESP, 0));
|
2014-02-27 17:39:04 +00:00
|
|
|
// Restore ESP.
|
|
|
|
__ movl(ESP, locs()->temp(kSavedSpTempIndex).reg());
|
2013-01-22 12:18:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* ExtractNthOutputInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2014-04-08 16:13:43 +00:00
|
|
|
// Only use this instruction in optimized code.
|
|
|
|
ASSERT(opt);
|
|
|
|
const intptr_t kNumInputs = 1;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, 0, LocationSummary::kNoCall);
|
2014-04-08 16:13:43 +00:00
|
|
|
if (representation() == kUnboxedDouble) {
|
|
|
|
if (index() == 0) {
|
|
|
|
summary->set_in(0, Location::Pair(Location::RequiresFpuRegister(),
|
|
|
|
Location::Any()));
|
|
|
|
} else {
|
|
|
|
ASSERT(index() == 1);
|
|
|
|
summary->set_in(0, Location::Pair(Location::Any(),
|
|
|
|
Location::RequiresFpuRegister()));
|
|
|
|
}
|
|
|
|
summary->set_out(0, Location::RequiresFpuRegister());
|
|
|
|
} else {
|
|
|
|
ASSERT(representation() == kTagged);
|
|
|
|
if (index() == 0) {
|
|
|
|
summary->set_in(0, Location::Pair(Location::RequiresRegister(),
|
|
|
|
Location::Any()));
|
|
|
|
} else {
|
|
|
|
ASSERT(index() == 1);
|
|
|
|
summary->set_in(0, Location::Pair(Location::Any(),
|
|
|
|
Location::RequiresRegister()));
|
|
|
|
}
|
|
|
|
summary->set_out(0, Location::RequiresRegister());
|
|
|
|
}
|
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ExtractNthOutputInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
ASSERT(locs()->in(0).IsPairLocation());
|
|
|
|
PairLocation* pair = locs()->in(0).AsPairLocation();
|
|
|
|
Location in_loc = pair->At(index());
|
|
|
|
if (representation() == kUnboxedDouble) {
|
|
|
|
XmmRegister out = locs()->out(0).fpu_reg();
|
|
|
|
XmmRegister in = in_loc.fpu_reg();
|
|
|
|
__ movaps(out, in);
|
|
|
|
} else {
|
|
|
|
ASSERT(representation() == kTagged);
|
|
|
|
Register out = locs()->out(0).reg();
|
|
|
|
Register in = in_loc.reg();
|
|
|
|
__ movl(out, in);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* MergedMathInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-11-21 17:56:54 +00:00
|
|
|
if (kind() == MergedMathInstr::kTruncDivMod) {
|
|
|
|
const intptr_t kNumInputs = 2;
|
2014-04-08 16:13:43 +00:00
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-11-21 17:56:54 +00:00
|
|
|
// Both inputs must be writable because they will be untagged.
|
|
|
|
summary->set_in(0, Location::RegisterLocation(EAX));
|
|
|
|
summary->set_in(1, Location::WritableRegister());
|
2014-04-08 16:13:43 +00:00
|
|
|
// Output is a pair of registers.
|
|
|
|
summary->set_out(0, Location::Pair(Location::RegisterLocation(EAX),
|
|
|
|
Location::RegisterLocation(EDX)));
|
2013-11-21 17:56:54 +00:00
|
|
|
return summary;
|
|
|
|
}
|
2013-12-03 22:00:27 +00:00
|
|
|
if (kind() == MergedMathInstr::kSinCos) {
|
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2014-04-08 16:13:43 +00:00
|
|
|
summary->set_in(0, Location::RequiresFpuRegister());
|
|
|
|
summary->set_out(0, Location::Pair(Location::RequiresFpuRegister(),
|
|
|
|
Location::RequiresFpuRegister()));
|
2013-12-03 22:00:27 +00:00
|
|
|
return summary;
|
|
|
|
}
|
2013-11-21 17:56:54 +00:00
|
|
|
UNIMPLEMENTED();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-12-03 22:00:27 +00:00
|
|
|
typedef void (*SinCosCFunction) (double x, double* res_sin, double* res_cos);
|
|
|
|
|
|
|
|
extern const RuntimeEntry kSinCosRuntimeEntry(
|
|
|
|
"libc_sincos", reinterpret_cast<RuntimeFunction>(
|
|
|
|
static_cast<SinCosCFunction>(&SinCos)), 1, true, true);
|
|
|
|
|
|
|
|
|
2013-11-21 17:56:54 +00:00
|
|
|
void MergedMathInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
Label* deopt = NULL;
|
|
|
|
if (CanDeoptimize()) {
|
2014-04-25 23:45:14 +00:00
|
|
|
deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinarySmiOp);
|
2013-11-21 17:56:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (kind() == MergedMathInstr::kTruncDivMod) {
|
|
|
|
Register left = locs()->in(0).reg();
|
|
|
|
Register right = locs()->in(1).reg();
|
2014-04-08 16:13:43 +00:00
|
|
|
ASSERT(locs()->out(0).IsPairLocation());
|
|
|
|
PairLocation* pair = locs()->out(0).AsPairLocation();
|
|
|
|
Register result1 = pair->At(0).reg();
|
|
|
|
Register result2 = pair->At(1).reg();
|
2013-11-26 18:18:24 +00:00
|
|
|
Range* right_range = InputAt(1)->definition()->range();
|
|
|
|
if ((right_range == NULL) || right_range->Overlaps(0, 0)) {
|
|
|
|
// Handle divide by zero in runtime.
|
|
|
|
__ testl(right, right);
|
|
|
|
__ j(ZERO, deopt);
|
|
|
|
}
|
2013-11-21 17:56:54 +00:00
|
|
|
ASSERT(left == EAX);
|
|
|
|
ASSERT((right != EDX) && (right != EAX));
|
2014-04-08 16:13:43 +00:00
|
|
|
ASSERT(result1 == EAX);
|
|
|
|
ASSERT(result2 == EDX);
|
2013-11-21 17:56:54 +00:00
|
|
|
__ SmiUntag(left);
|
|
|
|
__ SmiUntag(right);
|
|
|
|
__ cdq(); // Sign extend EAX -> EDX:EAX.
|
|
|
|
__ idivl(right); // EAX: quotient, EDX: remainder.
|
|
|
|
// Check the corner case of dividing the 'MIN_SMI' with -1, in which
|
|
|
|
// case we cannot tag the result.
|
|
|
|
// TODO(srdjan): We could store instead untagged intermediate results in a
|
|
|
|
// typed array, but then the load indexed instructions would need to be
|
|
|
|
// able to deoptimize.
|
|
|
|
__ cmpl(EAX, Immediate(0x40000000));
|
|
|
|
__ j(EQUAL, deopt);
|
|
|
|
// Modulo result (EDX) correction:
|
|
|
|
// res = left % right;
|
|
|
|
// if (res < 0) {
|
|
|
|
// if (right < 0) {
|
|
|
|
// res = res - right;
|
|
|
|
// } else {
|
|
|
|
// res = res + right;
|
|
|
|
// }
|
|
|
|
// }
|
2013-11-26 18:18:24 +00:00
|
|
|
Label done;
|
2013-11-21 17:56:54 +00:00
|
|
|
__ cmpl(EDX, Immediate(0));
|
|
|
|
__ j(GREATER_EQUAL, &done, Assembler::kNearJump);
|
|
|
|
// Result is negative, adjust it.
|
2013-11-26 18:18:24 +00:00
|
|
|
if ((right_range == NULL) || right_range->Overlaps(-1, 1)) {
|
|
|
|
Label subtract;
|
|
|
|
__ cmpl(right, Immediate(0));
|
|
|
|
__ j(LESS, &subtract, Assembler::kNearJump);
|
|
|
|
__ addl(EDX, right);
|
|
|
|
__ jmp(&done, Assembler::kNearJump);
|
|
|
|
__ Bind(&subtract);
|
|
|
|
__ subl(EDX, right);
|
|
|
|
} else if (right_range->IsWithin(0, RangeBoundary::kPlusInfinity)) {
|
|
|
|
// Right is positive.
|
|
|
|
__ addl(EDX, right);
|
|
|
|
} else {
|
|
|
|
// Right is negative.
|
|
|
|
__ subl(EDX, right);
|
|
|
|
}
|
2013-11-21 17:56:54 +00:00
|
|
|
__ Bind(&done);
|
|
|
|
|
|
|
|
__ SmiTag(EAX);
|
|
|
|
__ SmiTag(EDX);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-12-03 22:00:27 +00:00
|
|
|
if (kind() == MergedMathInstr::kSinCos) {
|
2014-04-08 16:13:43 +00:00
|
|
|
XmmRegister in = locs()->in(0).fpu_reg();
|
|
|
|
ASSERT(locs()->out(0).IsPairLocation());
|
|
|
|
PairLocation* pair = locs()->out(0).AsPairLocation();
|
|
|
|
XmmRegister out1 = pair->At(0).fpu_reg();
|
|
|
|
XmmRegister out2 = pair->At(1).fpu_reg();
|
|
|
|
|
2013-12-03 22:00:27 +00:00
|
|
|
// Do x87 sincos, since the ia32 compilers may not fuse sin/cos into
|
|
|
|
// sincos.
|
|
|
|
__ pushl(EAX);
|
|
|
|
__ pushl(EAX);
|
2014-04-08 16:13:43 +00:00
|
|
|
__ movsd(Address(ESP, 0), in);
|
2013-12-03 22:00:27 +00:00
|
|
|
__ fldl(Address(ESP, 0));
|
|
|
|
__ fsincos();
|
|
|
|
__ fstpl(Address(ESP, 0));
|
2014-04-08 16:13:43 +00:00
|
|
|
__ movsd(out1, Address(ESP, 0));
|
2013-12-03 22:00:27 +00:00
|
|
|
__ fstpl(Address(ESP, 0));
|
2014-04-08 16:13:43 +00:00
|
|
|
__ movsd(out2, Address(ESP, 0));
|
2013-12-03 22:00:27 +00:00
|
|
|
__ addl(ESP, Immediate(2 * kWordSize));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-21 17:56:54 +00:00
|
|
|
UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-12-16 15:11:31 +00:00
|
|
|
LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary(
|
2014-05-23 12:07:33 +00:00
|
|
|
Isolate* isolate, bool opt) const {
|
2012-06-14 18:07:43 +00:00
|
|
|
return MakeCallSummary();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2014-04-25 23:45:14 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(
|
|
|
|
deopt_id(), ICData::kDeoptPolymorphicInstanceCallTestFail);
|
2012-09-03 11:27:09 +00:00
|
|
|
if (ic_data().NumberOfChecks() == 0) {
|
2012-06-20 23:19:02 +00:00
|
|
|
__ jmp(deopt);
|
|
|
|
return;
|
|
|
|
}
|
2014-04-25 23:45:14 +00:00
|
|
|
ASSERT(ic_data().NumArgsTested() == 1);
|
2012-08-23 21:25:27 +00:00
|
|
|
if (!with_checks()) {
|
2013-01-18 11:54:45 +00:00
|
|
|
ASSERT(ic_data().HasOneTarget());
|
2012-09-03 11:27:09 +00:00
|
|
|
const Function& target = Function::ZoneHandle(ic_data().GetTargetAt(0));
|
2013-05-06 17:22:18 +00:00
|
|
|
compiler->GenerateStaticCall(deopt_id(),
|
2012-08-23 21:25:27 +00:00
|
|
|
instance_call()->token_pos(),
|
|
|
|
target,
|
|
|
|
instance_call()->ArgumentCount(),
|
|
|
|
instance_call()->argument_names(),
|
|
|
|
locs());
|
|
|
|
return;
|
|
|
|
}
|
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));
|
2012-08-27 21:06:30 +00:00
|
|
|
|
2013-03-19 20:15:10 +00:00
|
|
|
LoadValueCid(compiler, EDI, EAX,
|
|
|
|
(ic_data().GetReceiverClassIdAt(0) == kSmiCid) ? NULL : deopt);
|
2012-08-27 21:06:30 +00:00
|
|
|
|
2012-09-03 11:27:09 +00:00
|
|
|
compiler->EmitTestAndCall(ic_data(),
|
2012-06-20 23:19:02 +00:00
|
|
|
EDI, // Class id register.
|
|
|
|
instance_call()->ArgumentCount(),
|
|
|
|
instance_call()->argument_names(),
|
2012-07-10 18:22:45 +00:00
|
|
|
deopt,
|
2013-05-06 17:22:18 +00:00
|
|
|
deopt_id(),
|
2012-06-22 20:37:01 +00:00
|
|
|
instance_call()->token_pos(),
|
2012-08-23 10:08:37 +00:00
|
|
|
locs());
|
2012-06-14 18:07:43 +00:00
|
|
|
}
|
|
|
|
|
2012-07-19 15:52:44 +00:00
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* BranchInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
|
|
|
comparison()->InitializeLocationSummary(isolate, opt);
|
2013-12-16 15:11:31 +00:00
|
|
|
// Branches don't produce a result.
|
2014-03-21 14:40:30 +00:00
|
|
|
comparison()->locs()->set_out(0, Location::NoLocation());
|
2013-12-16 15:11:31 +00:00
|
|
|
return comparison()->locs();
|
2012-09-05 17:04:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-19 15:52:44 +00:00
|
|
|
void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-09-05 17:04:49 +00:00
|
|
|
comparison()->EmitBranchCode(compiler, this);
|
2012-08-27 09:30:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* CheckClassInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2012-08-20 12:40:14 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
2014-06-03 16:40:30 +00:00
|
|
|
const intptr_t kNumTemps = !IsNullCheck() ? 1 : 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2012-08-20 12:40:14 +00:00
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
2013-08-07 23:01:43 +00:00
|
|
|
if (!IsNullCheck()) {
|
2014-06-03 16:40:30 +00:00
|
|
|
summary->set_temp(0, Location::RequiresRegister());
|
2013-03-19 20:15:10 +00:00
|
|
|
}
|
2012-08-20 12:40:14 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2014-04-25 23:45:14 +00:00
|
|
|
const ICData::DeoptReasonId deopt_reason = licm_hoisted_ ?
|
|
|
|
ICData::kDeoptHoistedCheckClass : ICData::kDeoptCheckClass;
|
2013-08-07 23:01:43 +00:00
|
|
|
if (IsNullCheck()) {
|
2014-02-08 00:02:22 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(deopt_id(), deopt_reason);
|
2013-03-19 20:15:10 +00:00
|
|
|
const Immediate& raw_null =
|
|
|
|
Immediate(reinterpret_cast<intptr_t>(Object::null()));
|
|
|
|
__ cmpl(locs()->in(0).reg(), raw_null);
|
|
|
|
__ j(EQUAL, deopt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-10-25 20:18:54 +00:00
|
|
|
ASSERT((unary_checks().GetReceiverClassIdAt(0) != kSmiCid) ||
|
|
|
|
(unary_checks().NumberOfChecks() > 1));
|
2012-08-20 12:40:14 +00:00
|
|
|
Register value = locs()->in(0).reg();
|
|
|
|
Register temp = locs()->temp(0).reg();
|
2014-02-08 00:02:22 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(deopt_id(), deopt_reason);
|
2012-08-20 12:40:14 +00:00
|
|
|
Label is_ok;
|
2012-10-04 19:35:23 +00:00
|
|
|
intptr_t cix = 0;
|
|
|
|
if (unary_checks().GetReceiverClassIdAt(cix) == kSmiCid) {
|
|
|
|
__ testl(value, Immediate(kSmiTagMask));
|
|
|
|
__ j(ZERO, &is_ok);
|
|
|
|
cix++; // Skip first check.
|
|
|
|
} else {
|
|
|
|
__ testl(value, Immediate(kSmiTagMask));
|
|
|
|
__ j(ZERO, deopt);
|
|
|
|
}
|
|
|
|
__ LoadClassId(temp, value);
|
2012-09-03 11:27:09 +00:00
|
|
|
const intptr_t num_checks = unary_checks().NumberOfChecks();
|
2012-08-20 12:40:14 +00:00
|
|
|
const bool use_near_jump = num_checks < 5;
|
2012-10-04 19:35:23 +00:00
|
|
|
for (intptr_t i = cix; i < num_checks; i++) {
|
|
|
|
ASSERT(unary_checks().GetReceiverClassIdAt(i) != kSmiCid);
|
2012-09-03 11:27:09 +00:00
|
|
|
__ cmpl(temp, Immediate(unary_checks().GetReceiverClassIdAt(i)));
|
2012-08-20 12:40:14 +00:00
|
|
|
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
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* CheckSmiInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2012-08-23 08:24:29 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2012-08-23 08:24:29 +00:00
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void CheckSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-08-23 08:24:29 +00:00
|
|
|
Register value = locs()->in(0).reg();
|
2014-04-25 23:45:14 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptCheckSmi);
|
2012-08-23 08:24:29 +00:00
|
|
|
__ testl(value, Immediate(kSmiTagMask));
|
|
|
|
__ j(NOT_ZERO, deopt);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-02 20:11:41 +00:00
|
|
|
// Length: register or constant.
|
|
|
|
// Index: register, constant or stack slot.
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* CheckArrayBoundInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2012-09-04 15:15:36 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* locs = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-05-14 18:39:44 +00:00
|
|
|
locs->set_in(kLengthPos, Location::RegisterOrSmiConstant(length()));
|
2014-01-02 20:11:41 +00:00
|
|
|
ConstantInstr* index_constant = index()->definition()->AsConstant();
|
|
|
|
if (index_constant != NULL) {
|
|
|
|
locs->set_in(kIndexPos, Location::RegisterOrSmiConstant(index()));
|
|
|
|
} else {
|
|
|
|
locs->set_in(kIndexPos, Location::PrefersRegister());
|
|
|
|
}
|
2012-09-04 15:15:36 +00:00
|
|
|
return locs;
|
2012-08-28 09:14:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-05 17:04:49 +00:00
|
|
|
void CheckArrayBoundInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2014-04-25 23:45:14 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(deopt_id(),
|
|
|
|
ICData::kDeoptCheckArrayBound);
|
2013-05-14 18:39:44 +00:00
|
|
|
|
|
|
|
Location length_loc = locs()->in(kLengthPos);
|
|
|
|
Location index_loc = locs()->in(kIndexPos);
|
|
|
|
|
|
|
|
if (length_loc.IsConstant() && index_loc.IsConstant()) {
|
|
|
|
ASSERT((Smi::Cast(length_loc.constant()).Value() <=
|
|
|
|
Smi::Cast(index_loc.constant()).Value()) ||
|
|
|
|
(Smi::Cast(index_loc.constant()).Value() < 0));
|
2012-11-01 22:47:41 +00:00
|
|
|
// Unconditionally deoptimize for constant bounds checks because they
|
|
|
|
// only occur only when index is out-of-bounds.
|
|
|
|
__ jmp(deopt);
|
|
|
|
return;
|
2012-10-16 15:40:54 +00:00
|
|
|
}
|
2012-09-04 15:15:36 +00:00
|
|
|
|
2013-05-14 18:39:44 +00:00
|
|
|
if (index_loc.IsConstant()) {
|
|
|
|
Register length = length_loc.reg();
|
|
|
|
const Object& index = Smi::Cast(index_loc.constant());
|
|
|
|
__ cmpl(length, Immediate(reinterpret_cast<int32_t>(index.raw())));
|
2012-09-04 15:15:36 +00:00
|
|
|
__ j(BELOW_EQUAL, deopt);
|
2013-05-14 18:39:44 +00:00
|
|
|
} else if (length_loc.IsConstant()) {
|
|
|
|
const Smi& length = Smi::Cast(length_loc.constant());
|
2014-01-02 20:11:41 +00:00
|
|
|
if (index_loc.IsStackSlot()) {
|
|
|
|
const Address& index = index_loc.ToStackSlotAddress();
|
|
|
|
__ cmpl(index, Immediate(reinterpret_cast<int32_t>(length.raw())));
|
|
|
|
} else {
|
|
|
|
Register index = index_loc.reg();
|
|
|
|
__ cmpl(index, Immediate(reinterpret_cast<int32_t>(length.raw())));
|
|
|
|
}
|
2012-09-13 12:49:50 +00:00
|
|
|
__ j(ABOVE_EQUAL, deopt);
|
2014-01-02 20:11:41 +00:00
|
|
|
} else if (index_loc.IsStackSlot()) {
|
|
|
|
Register length = length_loc.reg();
|
|
|
|
const Address& index = index_loc.ToStackSlotAddress();
|
|
|
|
__ cmpl(length, index);
|
|
|
|
__ j(BELOW_EQUAL, deopt);
|
2012-09-04 15:15:36 +00:00
|
|
|
} else {
|
2013-05-14 18:39:44 +00:00
|
|
|
Register length = length_loc.reg();
|
|
|
|
Register index = index_loc.reg();
|
2013-02-01 15:10:24 +00:00
|
|
|
__ cmpl(index, length);
|
2012-09-04 15:15:36 +00:00
|
|
|
__ j(ABOVE_EQUAL, deopt);
|
2012-08-28 09:14:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* UnboxIntegerInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2012-10-02 11:25:53 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
2014-05-22 06:30:51 +00:00
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2014-05-22 06:30:51 +00:00
|
|
|
summary->set_in(0, Location::RequiresRegister());
|
|
|
|
summary->set_out(0, Location::Pair(Location::RegisterLocation(EAX),
|
|
|
|
Location::RegisterLocation(EDX)));
|
2012-10-02 11:25:53 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UnboxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2013-02-13 17:16:35 +00:00
|
|
|
const intptr_t value_cid = value()->Type()->ToCid();
|
2012-10-02 11:25:53 +00:00
|
|
|
const Register value = locs()->in(0).reg();
|
2014-05-22 06:30:51 +00:00
|
|
|
PairLocation* result_pair = locs()->out(0).AsPairLocation();
|
|
|
|
Register result_lo = result_pair->At(0).reg();
|
|
|
|
Register result_hi = result_pair->At(1).reg();
|
|
|
|
|
|
|
|
ASSERT(value != result_lo);
|
|
|
|
ASSERT(value != result_hi);
|
|
|
|
ASSERT(result_lo == EAX);
|
|
|
|
ASSERT(result_hi == EDX);
|
2012-10-02 11:25:53 +00:00
|
|
|
|
|
|
|
if (value_cid == kMintCid) {
|
2014-05-22 06:30:51 +00:00
|
|
|
__ movl(result_lo, FieldAddress(value, Mint::value_offset()));
|
|
|
|
__ movl(result_hi, FieldAddress(value, Mint::value_offset() + kWordSize));
|
2012-10-02 11:25:53 +00:00
|
|
|
} else if (value_cid == kSmiCid) {
|
2014-05-22 06:30:51 +00:00
|
|
|
__ movl(result_lo, value);
|
|
|
|
__ SmiUntag(result_lo);
|
|
|
|
// Sign extend into result_hi.
|
|
|
|
__ cdq();
|
2012-10-02 11:25:53 +00:00
|
|
|
} else {
|
2014-04-25 23:45:14 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(deopt_id_,
|
|
|
|
ICData::kDeoptUnboxInteger);
|
2012-10-02 11:25:53 +00:00
|
|
|
Label is_smi, done;
|
|
|
|
__ testl(value, Immediate(kSmiTagMask));
|
|
|
|
__ j(ZERO, &is_smi);
|
2014-05-22 06:30:51 +00:00
|
|
|
__ CompareClassId(value, kMintCid, result_lo);
|
2012-10-02 11:25:53 +00:00
|
|
|
__ j(NOT_EQUAL, deopt);
|
2014-05-22 06:30:51 +00:00
|
|
|
__ movl(result_lo, FieldAddress(value, Mint::value_offset()));
|
|
|
|
__ movl(result_hi, FieldAddress(value, Mint::value_offset() + kWordSize));
|
2012-10-02 11:25:53 +00:00
|
|
|
__ jmp(&done);
|
|
|
|
__ Bind(&is_smi);
|
2014-05-22 06:30:51 +00:00
|
|
|
__ movl(result_lo, value);
|
|
|
|
__ SmiUntag(result_lo);
|
|
|
|
// Sign extend into result_hi.
|
|
|
|
__ cdq();
|
2012-10-02 11:25:53 +00:00
|
|
|
__ Bind(&done);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* BoxIntegerInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2012-10-02 11:25:53 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
2014-05-22 06:30:51 +00:00
|
|
|
const intptr_t kNumTemps = 1;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs,
|
2012-10-02 11:25:53 +00:00
|
|
|
kNumTemps,
|
|
|
|
LocationSummary::kCallOnSlowPath);
|
2014-05-22 06:30:51 +00:00
|
|
|
summary->set_in(0, Location::Pair(Location::RequiresRegister(),
|
|
|
|
Location::RequiresRegister()));
|
|
|
|
summary->set_temp(0, Location::RequiresRegister());
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::RequiresRegister());
|
2012-10-02 11:25:53 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class BoxIntegerSlowPath : public SlowPathCode {
|
|
|
|
public:
|
|
|
|
explicit BoxIntegerSlowPath(BoxIntegerInstr* instruction)
|
|
|
|
: instruction_(instruction) { }
|
|
|
|
|
|
|
|
virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-12-07 21:45:37 +00:00
|
|
|
__ Comment("BoxIntegerSlowPath");
|
2012-10-02 11:25:53 +00:00
|
|
|
__ Bind(entry_label());
|
|
|
|
const Class& mint_class =
|
|
|
|
Class::ZoneHandle(Isolate::Current()->object_store()->mint_class());
|
|
|
|
const Code& stub =
|
|
|
|
Code::Handle(StubCode::GetAllocationStubForClass(mint_class));
|
2014-05-27 10:15:50 +00:00
|
|
|
const ExternalLabel label(stub.EntryPoint());
|
2012-10-02 11:25:53 +00:00
|
|
|
|
|
|
|
LocationSummary* locs = instruction_->locs();
|
2014-03-21 14:40:30 +00:00
|
|
|
locs->live_registers()->Remove(locs->out(0));
|
2012-10-02 11:25:53 +00:00
|
|
|
|
|
|
|
compiler->SaveLiveRegisters(locs);
|
2014-01-21 23:46:26 +00:00
|
|
|
compiler->GenerateCall(Scanner::kNoSourcePos, // No token position.
|
2012-10-02 11:25:53 +00:00
|
|
|
&label,
|
|
|
|
PcDescriptors::kOther,
|
|
|
|
locs);
|
2014-03-21 14:40:30 +00:00
|
|
|
__ MoveRegister(locs->out(0).reg(), EAX);
|
2012-10-02 11:25:53 +00:00
|
|
|
compiler->RestoreLiveRegisters(locs);
|
|
|
|
|
|
|
|
__ jmp(exit_label());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
BoxIntegerInstr* instruction_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
void BoxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
BoxIntegerSlowPath* slow_path = new BoxIntegerSlowPath(this);
|
|
|
|
compiler->AddSlowPathCode(slow_path);
|
2014-05-22 06:30:51 +00:00
|
|
|
PairLocation* value_pair = locs()->in(0).AsPairLocation();
|
|
|
|
Register value_lo = value_pair->At(0).reg();
|
|
|
|
Register value_hi = value_pair->At(1).reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
Register out_reg = locs()->out(0).reg();
|
2014-05-22 06:30:51 +00:00
|
|
|
|
|
|
|
// Copy value_hi into out_reg as a temporary.
|
|
|
|
// We modify value_lo but restore it before using it.
|
|
|
|
__ movl(out_reg, value_hi);
|
2012-10-02 11:25:53 +00:00
|
|
|
|
|
|
|
// Unboxed operations produce smis or mint-sized values.
|
|
|
|
// Check if value fits into a smi.
|
|
|
|
Label not_smi, done;
|
2014-05-22 06:30:51 +00:00
|
|
|
|
2012-10-02 11:25:53 +00:00
|
|
|
// 1. Compute (x + -kMinSmi) which has to be in the range
|
|
|
|
// 0 .. -kMinSmi+kMaxSmi for x to fit into a smi.
|
2014-05-22 06:30:51 +00:00
|
|
|
__ addl(value_lo, Immediate(0x40000000));
|
|
|
|
__ adcl(out_reg, Immediate(0));
|
2012-10-02 11:25:53 +00:00
|
|
|
// 2. Unsigned compare to -kMinSmi+kMaxSmi.
|
2014-05-22 06:30:51 +00:00
|
|
|
__ cmpl(value_lo, Immediate(0x80000000));
|
|
|
|
__ sbbl(out_reg, Immediate(0));
|
2012-10-02 11:25:53 +00:00
|
|
|
__ j(ABOVE_EQUAL, ¬_smi);
|
|
|
|
// 3. Restore lower half if result is a smi.
|
2014-05-22 06:30:51 +00:00
|
|
|
__ subl(value_lo, Immediate(0x40000000));
|
|
|
|
__ movl(out_reg, value_lo);
|
|
|
|
__ SmiTag(out_reg);
|
2012-10-02 11:25:53 +00:00
|
|
|
__ jmp(&done);
|
|
|
|
__ Bind(¬_smi);
|
2013-03-05 00:04:32 +00:00
|
|
|
__ TryAllocate(
|
2012-10-02 11:25:53 +00:00
|
|
|
Class::ZoneHandle(Isolate::Current()->object_store()->mint_class()),
|
|
|
|
slow_path->entry_label(),
|
|
|
|
Assembler::kFarJump,
|
2014-01-22 19:21:22 +00:00
|
|
|
out_reg,
|
|
|
|
kNoRegister);
|
2012-10-02 11:25:53 +00:00
|
|
|
__ Bind(slow_path->exit_label());
|
2014-05-22 06:30:51 +00:00
|
|
|
// 3. Restore lower half of input before using it.
|
|
|
|
__ subl(value_lo, Immediate(0x40000000));
|
|
|
|
__ movl(FieldAddress(out_reg, Mint::value_offset()), value_lo);
|
|
|
|
__ movl(FieldAddress(out_reg, Mint::value_offset() + kWordSize), value_hi);
|
2012-10-02 11:25:53 +00:00
|
|
|
__ Bind(&done);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* BinaryMintOpInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2012-10-02 11:25:53 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
2012-10-04 08:50:28 +00:00
|
|
|
switch (op_kind()) {
|
|
|
|
case Token::kBIT_AND:
|
|
|
|
case Token::kBIT_OR:
|
|
|
|
case Token::kBIT_XOR: {
|
2014-05-22 06:30:51 +00:00
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2014-05-22 06:30:51 +00:00
|
|
|
summary->set_in(0, Location::Pair(Location::RequiresRegister(),
|
|
|
|
Location::RequiresRegister()));
|
|
|
|
summary->set_in(1, Location::Pair(Location::RequiresRegister(),
|
|
|
|
Location::RequiresRegister()));
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2012-10-04 08:50:28 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
case Token::kADD:
|
|
|
|
case Token::kSUB: {
|
2014-05-22 06:30:51 +00:00
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2014-05-22 06:30:51 +00:00
|
|
|
summary->set_in(0, Location::Pair(Location::RequiresRegister(),
|
|
|
|
Location::RequiresRegister()));
|
|
|
|
summary->set_in(1, Location::Pair(Location::RequiresRegister(),
|
|
|
|
Location::RequiresRegister()));
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2012-10-04 08:50:28 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-10-02 11:25:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-04 15:54:16 +00:00
|
|
|
void BinaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2014-05-22 06:30:51 +00:00
|
|
|
PairLocation* left_pair = locs()->in(0).AsPairLocation();
|
|
|
|
Register left_lo = left_pair->At(0).reg();
|
|
|
|
Register left_hi = left_pair->At(1).reg();
|
|
|
|
PairLocation* right_pair = locs()->in(1).AsPairLocation();
|
|
|
|
Register right_lo = right_pair->At(0).reg();
|
|
|
|
Register right_hi = right_pair->At(1).reg();
|
|
|
|
PairLocation* out_pair = locs()->out(0).AsPairLocation();
|
|
|
|
Register out_lo = out_pair->At(0).reg();
|
|
|
|
Register out_hi = out_pair->At(1).reg();
|
|
|
|
ASSERT(out_lo == left_lo);
|
|
|
|
ASSERT(out_hi == left_hi);
|
2012-10-02 11:25:53 +00:00
|
|
|
|
2013-08-02 18:37:20 +00:00
|
|
|
Label* deopt = NULL;
|
|
|
|
if (FLAG_throw_on_javascript_int_overflow) {
|
2014-04-25 23:45:14 +00:00
|
|
|
deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinaryMintOp);
|
2013-08-02 18:37:20 +00:00
|
|
|
}
|
2012-10-02 11:25:53 +00:00
|
|
|
switch (op_kind()) {
|
2014-05-22 06:30:51 +00:00
|
|
|
case Token::kBIT_AND:
|
|
|
|
__ andl(left_lo, right_lo);
|
|
|
|
__ andl(left_hi, right_hi);
|
|
|
|
break;
|
|
|
|
case Token::kBIT_OR:
|
|
|
|
__ orl(left_lo, right_lo);
|
|
|
|
__ orl(left_hi, right_hi);
|
|
|
|
break;
|
|
|
|
case Token::kBIT_XOR:
|
|
|
|
__ xorl(left_lo, right_lo);
|
|
|
|
__ xorl(left_hi, right_hi);
|
|
|
|
break;
|
2012-10-04 08:50:28 +00:00
|
|
|
case Token::kADD:
|
|
|
|
case Token::kSUB: {
|
2013-08-02 18:37:20 +00:00
|
|
|
if (!FLAG_throw_on_javascript_int_overflow) {
|
2014-04-25 23:45:14 +00:00
|
|
|
deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinaryMintOp);
|
2013-08-02 18:37:20 +00:00
|
|
|
}
|
2012-10-04 08:50:28 +00:00
|
|
|
if (op_kind() == Token::kADD) {
|
2014-05-22 06:30:51 +00:00
|
|
|
__ addl(left_lo, right_lo);
|
|
|
|
__ adcl(left_hi, right_hi);
|
2012-10-04 08:50:28 +00:00
|
|
|
} else {
|
2014-05-22 06:30:51 +00:00
|
|
|
__ subl(left_lo, right_lo);
|
|
|
|
__ sbbl(left_hi, right_hi);
|
2012-10-04 08:50:28 +00:00
|
|
|
}
|
2014-05-22 06:30:51 +00:00
|
|
|
__ j(OVERFLOW, deopt);
|
2012-10-04 08:50:28 +00:00
|
|
|
break;
|
|
|
|
}
|
2012-10-02 11:25:53 +00:00
|
|
|
default: UNREACHABLE();
|
|
|
|
}
|
2013-08-02 18:37:20 +00:00
|
|
|
if (FLAG_throw_on_javascript_int_overflow) {
|
2014-05-22 06:30:51 +00:00
|
|
|
EmitJavascriptIntOverflowCheck(compiler, deopt, left_lo, left_hi);
|
2013-08-02 18:37:20 +00:00
|
|
|
}
|
2012-10-02 11:25:53 +00:00
|
|
|
}
|
|
|
|
|
2012-10-04 12:01:12 +00:00
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* ShiftMintOpInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2012-10-05 14:42:00 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
2014-05-22 06:30:51 +00:00
|
|
|
const intptr_t kNumTemps = op_kind() == Token::kSHL ? 2 : 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2014-05-22 06:30:51 +00:00
|
|
|
summary->set_in(0, Location::Pair(Location::RequiresRegister(),
|
|
|
|
Location::RequiresRegister()));
|
2012-10-05 14:42:00 +00:00
|
|
|
summary->set_in(1, Location::RegisterLocation(ECX));
|
2012-10-09 11:59:44 +00:00
|
|
|
if (op_kind() == Token::kSHL) {
|
2014-05-22 06:30:51 +00:00
|
|
|
summary->set_temp(0, Location::RequiresRegister());
|
2012-10-09 11:59:44 +00:00
|
|
|
summary->set_temp(1, Location::RequiresRegister());
|
|
|
|
}
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2012-10-05 14:42:00 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ShiftMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2014-05-22 06:30:51 +00:00
|
|
|
PairLocation* left_pair = locs()->in(0).AsPairLocation();
|
|
|
|
Register left_lo = left_pair->At(0).reg();
|
|
|
|
Register left_hi = left_pair->At(1).reg();
|
|
|
|
PairLocation* out_pair = locs()->out(0).AsPairLocation();
|
|
|
|
Register out_lo = out_pair->At(0).reg();
|
|
|
|
Register out_hi = out_pair->At(1).reg();
|
|
|
|
ASSERT(out_lo == left_lo);
|
|
|
|
ASSERT(out_hi == left_hi);
|
2012-10-05 14:42:00 +00:00
|
|
|
|
2014-04-25 23:45:14 +00:00
|
|
|
Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptShiftMintOp);
|
2012-10-09 11:59:44 +00:00
|
|
|
Label done;
|
|
|
|
__ testl(ECX, ECX);
|
|
|
|
__ j(ZERO, &done); // Shift by 0 is a nop.
|
|
|
|
// Deoptimize if shift count is > 31.
|
|
|
|
// sarl operation masks the count to 5 bits and
|
|
|
|
// shrd is undefined with count > operand size (32)
|
|
|
|
// TODO(fschneider): Support shift counts > 31 without deoptimization.
|
|
|
|
__ SmiUntag(ECX);
|
2013-01-18 00:34:20 +00:00
|
|
|
const Immediate& kCountLimit = Immediate(31);
|
2012-10-09 11:59:44 +00:00
|
|
|
__ cmpl(ECX, kCountLimit);
|
|
|
|
__ j(ABOVE, deopt);
|
2012-10-05 14:42:00 +00:00
|
|
|
switch (op_kind()) {
|
|
|
|
case Token::kSHR: {
|
2014-05-22 06:30:51 +00:00
|
|
|
__ shrd(left_lo, left_hi); // Shift count in CL.
|
|
|
|
__ sarl(left_hi, ECX); // Shift count in CL.
|
2012-10-05 14:42:00 +00:00
|
|
|
break;
|
|
|
|
}
|
2012-10-09 11:59:44 +00:00
|
|
|
case Token::kSHL: {
|
|
|
|
Register temp1 = locs()->temp(0).reg();
|
|
|
|
Register temp2 = locs()->temp(1).reg();
|
2014-05-22 06:30:51 +00:00
|
|
|
__ movl(temp1, left_lo); // Low 32 bits.
|
|
|
|
__ movl(temp2, left_hi); // High 32 bits.
|
|
|
|
__ shll(left_lo, ECX); // Shift count in CL.
|
|
|
|
__ shld(left_hi, temp1); // Shift count in CL.
|
2012-10-09 11:59:44 +00:00
|
|
|
// Check for overflow by shifting back the high 32 bits
|
|
|
|
// and comparing with the input.
|
|
|
|
__ movl(temp1, temp2);
|
2014-05-22 06:30:51 +00:00
|
|
|
__ movl(temp2, left_hi);
|
2012-10-09 11:59:44 +00:00
|
|
|
__ sarl(temp2, ECX);
|
|
|
|
__ cmpl(temp1, temp2);
|
|
|
|
__ j(NOT_EQUAL, deopt);
|
2012-10-05 14:42:00 +00:00
|
|
|
break;
|
2012-10-09 11:59:44 +00:00
|
|
|
}
|
2012-10-05 14:42:00 +00:00
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
break;
|
|
|
|
}
|
2012-10-09 11:59:44 +00:00
|
|
|
__ Bind(&done);
|
2013-08-02 18:37:20 +00:00
|
|
|
if (FLAG_throw_on_javascript_int_overflow) {
|
2014-05-22 06:30:51 +00:00
|
|
|
EmitJavascriptIntOverflowCheck(compiler, deopt, left_lo, left_hi);
|
2013-08-02 18:37:20 +00:00
|
|
|
}
|
2012-10-05 14:42:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* UnaryMintOpInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2012-10-04 12:01:12 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
2014-05-22 06:30:51 +00:00
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2014-05-22 06:30:51 +00:00
|
|
|
summary->set_in(0, Location::Pair(Location::RequiresRegister(),
|
|
|
|
Location::RequiresRegister()));
|
2014-03-21 14:40:30 +00:00
|
|
|
summary->set_out(0, Location::SameAsFirstInput());
|
2013-08-09 20:26:52 +00:00
|
|
|
if (FLAG_throw_on_javascript_int_overflow) {
|
|
|
|
summary->set_temp(0, Location::RequiresRegister());
|
|
|
|
}
|
2012-10-04 12:01:12 +00:00
|
|
|
return summary;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-04 15:54:16 +00:00
|
|
|
void UnaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2012-10-04 12:01:12 +00:00
|
|
|
ASSERT(op_kind() == Token::kBIT_NOT);
|
2014-05-22 06:30:51 +00:00
|
|
|
PairLocation* left_pair = locs()->in(0).AsPairLocation();
|
|
|
|
Register left_lo = left_pair->At(0).reg();
|
|
|
|
Register left_hi = left_pair->At(1).reg();
|
|
|
|
PairLocation* out_pair = locs()->out(0).AsPairLocation();
|
|
|
|
Register out_lo = out_pair->At(0).reg();
|
|
|
|
Register out_hi = out_pair->At(1).reg();
|
|
|
|
ASSERT(out_lo == left_lo);
|
|
|
|
ASSERT(out_hi == left_hi);
|
|
|
|
|
2013-08-02 18:37:20 +00:00
|
|
|
Label* deopt = NULL;
|
|
|
|
if (FLAG_throw_on_javascript_int_overflow) {
|
2014-04-25 23:45:14 +00:00
|
|
|
deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnaryMintOp);
|
2013-08-02 18:37:20 +00:00
|
|
|
}
|
2014-05-22 06:30:51 +00:00
|
|
|
|
|
|
|
__ notl(left_lo);
|
|
|
|
__ notl(left_hi);
|
|
|
|
|
2013-08-02 18:37:20 +00:00
|
|
|
if (FLAG_throw_on_javascript_int_overflow) {
|
2014-05-22 06:30:51 +00:00
|
|
|
EmitJavascriptIntOverflowCheck(compiler, deopt, left_lo, left_hi);
|
2013-08-02 18:37:20 +00:00
|
|
|
}
|
2012-10-04 12:01:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* ThrowInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
|
|
|
return new(isolate) LocationSummary(isolate, 0, 0, LocationSummary::kCall);
|
2013-01-18 00:34:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ThrowInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2013-10-25 10:17:10 +00:00
|
|
|
compiler->GenerateRuntimeCall(token_pos(),
|
2013-01-29 12:38:27 +00:00
|
|
|
deopt_id(),
|
2013-01-18 00:34:20 +00:00
|
|
|
kThrowRuntimeEntry,
|
2013-08-28 23:07:14 +00:00
|
|
|
1,
|
2013-01-18 00:34:20 +00:00
|
|
|
locs());
|
|
|
|
__ int3();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* ReThrowInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
|
|
|
return new(isolate) LocationSummary(isolate, 0, 0, LocationSummary::kCall);
|
2013-01-18 00:34:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ReThrowInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2013-08-31 00:26:47 +00:00
|
|
|
compiler->SetNeedsStacktrace(catch_try_index());
|
2013-10-25 10:17:10 +00:00
|
|
|
compiler->GenerateRuntimeCall(token_pos(),
|
2013-01-29 12:38:27 +00:00
|
|
|
deopt_id(),
|
2013-01-18 00:34:20 +00:00
|
|
|
kReThrowRuntimeEntry,
|
2013-08-28 23:07:14 +00:00
|
|
|
2,
|
2013-01-18 00:34:20 +00:00
|
|
|
locs());
|
|
|
|
__ int3();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-11 12:32:58 +00:00
|
|
|
void GraphEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
if (!compiler->CanFallThroughTo(normal_entry())) {
|
|
|
|
__ jmp(compiler->GetJumpLabel(normal_entry()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-28 09:17:07 +00:00
|
|
|
void TargetEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
__ Bind(compiler->GetJumpLabel(this));
|
|
|
|
if (!compiler->is_optimizing()) {
|
2014-05-22 23:47:20 +00:00
|
|
|
if (FLAG_emit_edge_counters) {
|
|
|
|
compiler->EmitEdgeCounter();
|
|
|
|
}
|
2013-10-01 10:22:47 +00:00
|
|
|
// The deoptimization descriptor points after the edge counter code for
|
|
|
|
// uniformity with ARM and MIPS, where we can reuse pattern matching
|
|
|
|
// code that matches backwards from the end of the pattern.
|
2013-08-28 09:17:07 +00:00
|
|
|
compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
|
|
|
|
deopt_id_,
|
2014-01-21 23:46:26 +00:00
|
|
|
Scanner::kNoSourcePos);
|
2013-08-28 09:17:07 +00:00
|
|
|
}
|
|
|
|
if (HasParallelMove()) {
|
|
|
|
compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* GotoInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
|
|
|
return new(isolate) LocationSummary(isolate, 0, 0, LocationSummary::kNoCall);
|
2013-01-18 00:34:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GotoInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2013-08-28 09:17:07 +00:00
|
|
|
if (!compiler->is_optimizing()) {
|
2014-05-22 23:47:20 +00:00
|
|
|
if (FLAG_emit_edge_counters) {
|
|
|
|
compiler->EmitEdgeCounter();
|
|
|
|
}
|
2013-10-01 10:22:47 +00:00
|
|
|
// Add a deoptimization descriptor for deoptimizing instructions that
|
|
|
|
// may be inserted before this instruction. This descriptor points
|
|
|
|
// after the edge counter for uniformity with ARM and MIPS, where we can
|
|
|
|
// reuse pattern matching that matches backwards from the end of the
|
|
|
|
// pattern.
|
2013-08-28 09:17:07 +00:00
|
|
|
compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
|
|
|
|
GetDeoptId(),
|
2014-01-21 23:46:26 +00:00
|
|
|
Scanner::kNoSourcePos);
|
2013-08-28 09:17:07 +00:00
|
|
|
}
|
2013-01-18 00:34:20 +00:00
|
|
|
if (HasParallelMove()) {
|
|
|
|
compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
|
|
|
|
}
|
|
|
|
|
|
|
|
// We can fall through if the successor is the next block in the list.
|
|
|
|
// Otherwise, we need a jump.
|
2013-03-08 19:09:48 +00:00
|
|
|
if (!compiler->CanFallThroughTo(successor())) {
|
|
|
|
__ jmp(compiler->GetJumpLabel(successor()));
|
2013-01-18 00:34:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* CurrentContextInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2014-05-27 10:15:50 +00:00
|
|
|
return LocationSummary::Make(isolate,
|
|
|
|
0,
|
2013-01-18 00:34:20 +00:00
|
|
|
Location::RequiresRegister(),
|
|
|
|
LocationSummary::kNoCall);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CurrentContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2014-03-21 14:40:30 +00:00
|
|
|
__ MoveRegister(locs()->out(0).reg(), CTX);
|
2013-01-18 00:34:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* StrictCompareInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-01-18 00:34:20 +00:00
|
|
|
const intptr_t kNumInputs = 2;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2013-11-07 17:27:16 +00:00
|
|
|
if (needs_number_check()) {
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* locs = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kCall);
|
2013-11-07 17:27:16 +00:00
|
|
|
locs->set_in(0, Location::RegisterLocation(EAX));
|
|
|
|
locs->set_in(1, Location::RegisterLocation(ECX));
|
2014-03-21 14:40:30 +00:00
|
|
|
locs->set_out(0, Location::RegisterLocation(EAX));
|
2013-11-07 17:27:16 +00:00
|
|
|
return locs;
|
|
|
|
}
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* locs = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
2013-01-18 00:34:20 +00:00
|
|
|
locs->set_in(0, Location::RegisterOrConstant(left()));
|
2013-11-11 13:01:54 +00:00
|
|
|
// Only one of the inputs can be a constant. Choose register if the first one
|
|
|
|
// is a constant.
|
|
|
|
locs->set_in(1, locs->in(0).IsConstant()
|
|
|
|
? Location::RequiresRegister()
|
|
|
|
: Location::RegisterOrConstant(right()));
|
2014-03-21 14:40:30 +00:00
|
|
|
locs->set_out(0, Location::RequiresRegister());
|
2013-01-18 00:34:20 +00:00
|
|
|
return locs;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-25 12:57:21 +00:00
|
|
|
Condition StrictCompareInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
|
|
|
|
BranchLabels labels) {
|
|
|
|
Location left = locs()->in(0);
|
|
|
|
Location right = locs()->in(1);
|
2013-11-11 13:01:54 +00:00
|
|
|
ASSERT(!left.IsConstant() || !right.IsConstant());
|
2013-01-18 00:34:20 +00:00
|
|
|
if (left.IsConstant()) {
|
|
|
|
compiler->EmitEqualityRegConstCompare(right.reg(),
|
|
|
|
left.constant(),
|
2013-11-25 12:57:21 +00:00
|
|
|
needs_number_check(),
|
|
|
|
token_pos());
|
2013-01-18 00:34:20 +00:00
|
|
|
} else if (right.IsConstant()) {
|
|
|
|
compiler->EmitEqualityRegConstCompare(left.reg(),
|
|
|
|
right.constant(),
|
2013-11-25 12:57:21 +00:00
|
|
|
needs_number_check(),
|
|
|
|
token_pos());
|
2013-01-18 00:34:20 +00:00
|
|
|
} else {
|
|
|
|
compiler->EmitEqualityRegRegCompare(left.reg(),
|
2013-11-13 18:21:27 +00:00
|
|
|
right.reg(),
|
2013-11-25 12:57:21 +00:00
|
|
|
needs_number_check(),
|
|
|
|
token_pos());
|
2013-01-18 00:34:20 +00:00
|
|
|
}
|
2013-11-25 12:57:21 +00:00
|
|
|
Condition true_condition = (kind() == Token::kEQ_STRICT) ? EQUAL : NOT_EQUAL;
|
|
|
|
return true_condition;
|
2013-11-13 18:21:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StrictCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
ASSERT(kind() == Token::kEQ_STRICT || kind() == Token::kNE_STRICT);
|
|
|
|
|
|
|
|
Label is_true, is_false;
|
|
|
|
BranchLabels labels = { &is_true, &is_false, &is_false };
|
2013-11-25 12:57:21 +00:00
|
|
|
Condition true_condition = EmitComparisonCode(compiler, labels);
|
|
|
|
EmitBranchOnCondition(compiler, true_condition, labels);
|
2013-01-18 00:34:20 +00:00
|
|
|
|
2014-03-21 14:40:30 +00:00
|
|
|
Register result = locs()->out(0).reg();
|
2013-11-13 18:21:27 +00:00
|
|
|
Label done;
|
|
|
|
__ Bind(&is_false);
|
2013-01-18 00:34:20 +00:00
|
|
|
__ LoadObject(result, Bool::False());
|
|
|
|
__ jmp(&done, Assembler::kNearJump);
|
2013-11-13 18:21:27 +00:00
|
|
|
__ Bind(&is_true);
|
2013-01-18 00:34:20 +00:00
|
|
|
__ LoadObject(result, Bool::True());
|
|
|
|
__ Bind(&done);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StrictCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler,
|
|
|
|
BranchInstr* branch) {
|
|
|
|
ASSERT(kind() == Token::kEQ_STRICT || kind() == Token::kNE_STRICT);
|
|
|
|
|
2013-11-13 18:21:27 +00:00
|
|
|
BranchLabels labels = compiler->CreateBranchLabels(branch);
|
2013-11-25 12:57:21 +00:00
|
|
|
Condition true_condition = EmitComparisonCode(compiler, labels);
|
|
|
|
EmitBranchOnCondition(compiler, true_condition, labels);
|
2013-04-10 15:09:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Detect pattern when one value is zero and another is a power of 2.
|
|
|
|
static bool IsPowerOfTwoKind(intptr_t v1, intptr_t v2) {
|
|
|
|
return (Utils::IsPowerOfTwo(v1) && (v2 == 0)) ||
|
|
|
|
(Utils::IsPowerOfTwo(v2) && (v1 == 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* IfThenElseInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
|
|
|
comparison()->InitializeLocationSummary(isolate, opt);
|
2013-04-10 15:09:46 +00:00
|
|
|
// TODO(vegorov): support byte register constraints in the register allocator.
|
2014-03-21 14:40:30 +00:00
|
|
|
comparison()->locs()->set_out(0, Location::RegisterLocation(EDX));
|
2013-12-16 15:11:31 +00:00
|
|
|
return comparison()->locs();
|
2013-04-10 15:09:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void IfThenElseInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2014-03-21 14:40:30 +00:00
|
|
|
ASSERT(locs()->out(0).reg() == EDX);
|
2013-04-10 15:09:46 +00:00
|
|
|
|
|
|
|
// Clear upper part of the out register. We are going to use setcc on it
|
|
|
|
// which is a byte move.
|
|
|
|
__ xorl(EDX, EDX);
|
|
|
|
|
2013-11-25 12:57:21 +00:00
|
|
|
// Emit comparison code. This must not overwrite the result register.
|
|
|
|
BranchLabels labels = { NULL, NULL, NULL };
|
|
|
|
Condition true_condition = comparison()->EmitComparisonCode(compiler, labels);
|
2013-04-10 15:09:46 +00:00
|
|
|
|
|
|
|
const bool is_power_of_two_kind = IsPowerOfTwoKind(if_true_, if_false_);
|
|
|
|
|
2013-04-12 15:28:29 +00:00
|
|
|
intptr_t true_value = if_true_;
|
|
|
|
intptr_t false_value = if_false_;
|
2013-04-10 15:09:46 +00:00
|
|
|
|
2013-04-12 15:28:29 +00:00
|
|
|
if (is_power_of_two_kind) {
|
|
|
|
if (true_value == 0) {
|
|
|
|
// We need to have zero in EDX on true_condition.
|
|
|
|
true_condition = NegateCondition(true_condition);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (true_value == 0) {
|
|
|
|
// Swap values so that false_value is zero.
|
|
|
|
intptr_t temp = true_value;
|
|
|
|
true_value = false_value;
|
|
|
|
false_value = temp;
|
|
|
|
} else {
|
|
|
|
true_condition = NegateCondition(true_condition);
|
|
|
|
}
|
2013-04-10 15:09:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
__ setcc(true_condition, DL);
|
|
|
|
|
|
|
|
if (is_power_of_two_kind) {
|
|
|
|
const intptr_t shift =
|
2013-04-12 15:28:29 +00:00
|
|
|
Utils::ShiftForPowerOfTwo(Utils::Maximum(true_value, false_value));
|
2013-04-10 15:09:46 +00:00
|
|
|
__ shll(EDX, Immediate(shift + kSmiTagSize));
|
|
|
|
} else {
|
2014-05-14 19:57:04 +00:00
|
|
|
__ decl(EDX);
|
2013-04-12 15:28:29 +00:00
|
|
|
__ andl(EDX, Immediate(
|
|
|
|
Smi::RawValue(true_value) - Smi::RawValue(false_value)));
|
|
|
|
if (false_value != 0) {
|
|
|
|
__ addl(EDX, Immediate(Smi::RawValue(false_value)));
|
|
|
|
}
|
2013-04-10 15:09:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* ClosureCallInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2014-04-30 20:14:02 +00:00
|
|
|
const intptr_t kNumInputs = 1;
|
|
|
|
const intptr_t kNumTemps = 0;
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* summary = new(isolate) LocationSummary(
|
|
|
|
isolate, kNumInputs, kNumTemps, LocationSummary::kCall);
|
2014-04-30 20:14:02 +00:00
|
|
|
summary->set_in(0, Location::RegisterLocation(EAX)); // Function.
|
|
|
|
summary->set_out(0, Location::RegisterLocation(EAX));
|
|
|
|
return summary;
|
2013-06-20 16:29:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-01-18 00:34:20 +00:00
|
|
|
void ClosureCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2014-04-10 10:56:00 +00:00
|
|
|
// Load arguments descriptors.
|
2014-04-30 20:14:02 +00:00
|
|
|
intptr_t argument_count = ArgumentCount();
|
2013-01-18 00:34:20 +00:00
|
|
|
const Array& arguments_descriptor =
|
|
|
|
Array::ZoneHandle(ArgumentsDescriptor::New(argument_count,
|
|
|
|
argument_names()));
|
2014-04-10 10:56:00 +00:00
|
|
|
__ LoadObject(EDX, arguments_descriptor);
|
|
|
|
|
|
|
|
// EBX: Code (compiled code or lazy compile stub).
|
2014-04-30 20:14:02 +00:00
|
|
|
ASSERT(locs()->in(0).reg() == EAX);
|
2014-04-10 10:56:00 +00:00
|
|
|
__ movl(EBX, FieldAddress(EAX, Function::code_offset()));
|
|
|
|
|
|
|
|
// EAX: Function.
|
|
|
|
// EDX: Arguments descriptor array.
|
|
|
|
// ECX: Smi 0 (no IC data; the lazy-compile stub expects a GC-safe value).
|
|
|
|
__ xorl(ECX, ECX);
|
|
|
|
__ movl(EBX, FieldAddress(EBX, Code::instructions_offset()));
|
|
|
|
__ addl(EBX, Immediate(Instructions::HeaderSize() - kHeapObjectTag));
|
|
|
|
__ call(EBX);
|
|
|
|
compiler->AddCurrentDescriptor(PcDescriptors::kClosureCall,
|
|
|
|
deopt_id(),
|
|
|
|
token_pos());
|
|
|
|
compiler->RecordSafepoint(locs());
|
|
|
|
// Marks either the continuation point in unoptimized code or the
|
|
|
|
// deoptimization point in optimized code, after call.
|
|
|
|
const intptr_t deopt_id_after = Isolate::ToDeoptAfter(deopt_id());
|
|
|
|
if (compiler->is_optimizing()) {
|
|
|
|
compiler->AddDeoptIndexAtCall(deopt_id_after, token_pos());
|
|
|
|
} else {
|
|
|
|
// Add deoptimization continuation point after the call and before the
|
|
|
|
// arguments are removed.
|
|
|
|
compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
|
|
|
|
deopt_id_after,
|
|
|
|
token_pos());
|
|
|
|
}
|
2013-01-18 00:34:20 +00:00
|
|
|
__ Drop(argument_count);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* BooleanNegateInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2014-05-27 10:15:50 +00:00
|
|
|
return LocationSummary::Make(isolate,
|
|
|
|
1,
|
2013-01-18 00:34:20 +00:00
|
|
|
Location::RequiresRegister(),
|
|
|
|
LocationSummary::kNoCall);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BooleanNegateInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|
|
|
Register value = locs()->in(0).reg();
|
2014-03-21 14:40:30 +00:00
|
|
|
Register result = locs()->out(0).reg();
|
2013-01-18 00:34:20 +00:00
|
|
|
|
|
|
|
Label done;
|
|
|
|
__ LoadObject(result, Bool::True());
|
|
|
|
__ CompareRegisters(result, value);
|
|
|
|
__ j(NOT_EQUAL, &done, Assembler::kNearJump);
|
|
|
|
__ LoadObject(result, Bool::False());
|
|
|
|
__ Bind(&done);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-23 12:07:33 +00:00
|
|
|
LocationSummary* AllocateObjectInstr::MakeLocationSummary(Isolate* isolate,
|
|
|
|
bool opt) const {
|
2013-01-18 00:34:20 +00:00
|
|
|
return MakeCallSummary();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AllocateObjectInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
2013-08-01 12:03:21 +00:00
|
|
|
const Code& stub = Code::Handle(StubCode::GetAllocationStubForClass(cls()));
|
2014-05-27 10:15:50 +00:00
|
|
|
const ExternalLabel label(stub.EntryPoint());
|
2013-01-18 00:34:20 +00:00
|
|
|
compiler->GenerateCall(token_pos(),
|
|
|
|
&label,
|
|
|
|
PcDescriptors::kOther,
|
|
|
|
locs());
|
|
|
|
__ Drop(ArgumentCount()); // Discard arguments.
|
|
|
|
}
|
|
|
|
|
2012-05-21 19:51:17 +00:00
|
|
|
} // namespace dart
|
|
|
|
|
|
|
|
#undef __
|
|
|
|
|
2013-01-18 00:34:20 +00:00
|
|
|
#endif // defined TARGET_ARCH_IA32
|