mirror of
https://github.com/dart-lang/sdk
synced 2024-09-20 02:39:27 +00:00
Immediate index operand for string [] and streamline code for generating array ops.
Replace sizeof(RawArray) with Array::data_offset where it is used to compute the start of the array data. Refactor helpers for generating array addressing mode and use them for string [] operations as well. Review URL: https://codereview.chromium.org//11880022 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@17019 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
260c80a4bb
commit
339ac7f288
|
@ -1027,54 +1027,76 @@ bool FlowGraphCompiler::EvaluateCondition(Condition condition,
|
|||
}
|
||||
|
||||
|
||||
FieldAddress FlowGraphCompiler::ElementAddressForIntIndex(intptr_t cid,
|
||||
Register array,
|
||||
intptr_t offset) {
|
||||
intptr_t FlowGraphCompiler::ElementSizeFor(intptr_t cid) {
|
||||
switch (cid) {
|
||||
case kArrayCid:
|
||||
case kImmutableArrayCid: {
|
||||
const intptr_t disp = offset * kWordSize + sizeof(RawArray);
|
||||
ASSERT(Utils::IsInt(31, disp));
|
||||
return FieldAddress(array, disp);
|
||||
}
|
||||
case kFloat32ArrayCid: {
|
||||
const intptr_t disp =
|
||||
offset * kFloatSize + Float32Array::data_offset();
|
||||
ASSERT(Utils::IsInt(31, disp));
|
||||
return FieldAddress(array, disp);
|
||||
}
|
||||
case kFloat64ArrayCid: {
|
||||
const intptr_t disp =
|
||||
offset * kDoubleSize + Float64Array::data_offset();
|
||||
ASSERT(Utils::IsInt(31, disp));
|
||||
return FieldAddress(array, disp);
|
||||
}
|
||||
case kUint8ArrayCid: {
|
||||
const intptr_t disp = offset + Uint8Array::data_offset();
|
||||
ASSERT(Utils::IsInt(31, disp));
|
||||
return FieldAddress(array, disp);
|
||||
}
|
||||
case kUint8ClampedArrayCid: {
|
||||
const intptr_t disp = offset + Uint8ClampedArray::data_offset();
|
||||
ASSERT(Utils::IsInt(31, disp));
|
||||
return FieldAddress(array, disp);
|
||||
}
|
||||
case kImmutableArrayCid:
|
||||
return Array::kBytesPerElement;
|
||||
case kFloat32ArrayCid:
|
||||
return Float32Array::kBytesPerElement;
|
||||
case kFloat64ArrayCid:
|
||||
return Float64Array::kBytesPerElement;
|
||||
case kUint8ArrayCid:
|
||||
return Uint8Array::kBytesPerElement;
|
||||
case kUint8ClampedArrayCid:
|
||||
return Uint8ClampedArray::kBytesPerElement;
|
||||
case kOneByteStringCid:
|
||||
return OneByteString::kBytesPerElement;
|
||||
case kTwoByteStringCid:
|
||||
return TwoByteString::kBytesPerElement;
|
||||
default:
|
||||
UNIMPLEMENTED();
|
||||
return FieldAddress(SPREG, 0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
intptr_t FlowGraphCompiler::DataOffsetFor(intptr_t cid) {
|
||||
switch (cid) {
|
||||
case kArrayCid:
|
||||
case kImmutableArrayCid:
|
||||
return Array::data_offset();
|
||||
case kFloat32ArrayCid:
|
||||
return Float32Array::data_offset();
|
||||
case kFloat64ArrayCid:
|
||||
return Float64Array::data_offset();
|
||||
case kUint8ArrayCid:
|
||||
return Uint8Array::data_offset();
|
||||
case kUint8ClampedArrayCid:
|
||||
return Uint8ClampedArray::data_offset();
|
||||
case kOneByteStringCid:
|
||||
return OneByteString::data_offset();
|
||||
case kTwoByteStringCid:
|
||||
return TwoByteString::data_offset();
|
||||
default:
|
||||
UNIMPLEMENTED();
|
||||
return Array::data_offset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FieldAddress FlowGraphCompiler::ElementAddressForIntIndex(intptr_t cid,
|
||||
Register array,
|
||||
intptr_t index) {
|
||||
const int64_t disp =
|
||||
static_cast<int64_t>(index) * ElementSizeFor(cid) + DataOffsetFor(cid);
|
||||
ASSERT(Utils::IsInt(32, disp));
|
||||
return FieldAddress(array, static_cast<int32_t>(disp));
|
||||
}
|
||||
|
||||
|
||||
FieldAddress FlowGraphCompiler::ElementAddressForRegIndex(intptr_t cid,
|
||||
Register array,
|
||||
Register index) {
|
||||
// Note that index is Smi, i.e, times 2.
|
||||
// Note that index is smi-tagged, (i.e, times 2) for all arrays with element
|
||||
// size > 1. For Uint8Array and OneByteString the index is expected to be
|
||||
// untagged before accessing.
|
||||
ASSERT(kSmiTagShift == 1);
|
||||
switch (cid) {
|
||||
case kArrayCid:
|
||||
case kImmutableArrayCid:
|
||||
return FieldAddress(array, index, TIMES_HALF_WORD_SIZE, sizeof(RawArray));
|
||||
return FieldAddress(
|
||||
array, index, TIMES_HALF_WORD_SIZE, Array::data_offset());
|
||||
case kFloat32ArrayCid:
|
||||
return FieldAddress(array, index, TIMES_2, Float32Array::data_offset());
|
||||
case kFloat64ArrayCid:
|
||||
|
@ -1084,6 +1106,10 @@ FieldAddress FlowGraphCompiler::ElementAddressForRegIndex(intptr_t cid,
|
|||
case kUint8ClampedArrayCid:
|
||||
return
|
||||
FieldAddress(array, index, TIMES_1, Uint8ClampedArray::data_offset());
|
||||
case kOneByteStringCid:
|
||||
return FieldAddress(array, index, TIMES_1, OneByteString::data_offset());
|
||||
case kTwoByteStringCid:
|
||||
return FieldAddress(array, index, TIMES_1, TwoByteString::data_offset());
|
||||
default:
|
||||
UNIMPLEMENTED();
|
||||
return FieldAddress(SPREG, 0);
|
||||
|
|
|
@ -232,6 +232,8 @@ class FlowGraphCompiler : public ValueObject {
|
|||
static bool EvaluateCondition(Condition condition, intptr_t l, intptr_t r);
|
||||
|
||||
// Array/list element address computations.
|
||||
static intptr_t DataOffsetFor(intptr_t cid);
|
||||
static intptr_t ElementSizeFor(intptr_t cid);
|
||||
static FieldAddress ElementAddressForIntIndex(intptr_t cid,
|
||||
Register array,
|
||||
intptr_t offset);
|
||||
|
|
|
@ -232,6 +232,8 @@ class FlowGraphCompiler : public ValueObject {
|
|||
static bool EvaluateCondition(Condition condition, intptr_t l, intptr_t r);
|
||||
|
||||
// Array/list element address computations.
|
||||
static intptr_t DataOffsetFor(intptr_t cid);
|
||||
static intptr_t ElementSizeFor(intptr_t cid);
|
||||
static FieldAddress ElementAddressForIntIndex(intptr_t cid,
|
||||
Register array,
|
||||
intptr_t offset);
|
||||
|
|
|
@ -1054,12 +1054,14 @@ void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
}
|
||||
|
||||
|
||||
static bool CanBeImmediateIndex(Value* index) {
|
||||
static bool CanBeImmediateIndex(Value* index, intptr_t cid) {
|
||||
if (!index->definition()->IsConstant()) return false;
|
||||
const Object& constant = index->definition()->AsConstant()->value();
|
||||
if (!constant.IsSmi()) return false;
|
||||
const Smi& smi_const = Smi::Cast(constant);
|
||||
int64_t disp = smi_const.AsInt64Value() * kWordSize + sizeof(RawArray);
|
||||
const intptr_t scale = FlowGraphCompiler::ElementSizeFor(cid);
|
||||
const intptr_t data_offset = FlowGraphCompiler::DataOffsetFor(cid);
|
||||
const int64_t disp = smi_const.AsInt64Value() * scale + data_offset;
|
||||
return Utils::IsInt(32, disp);
|
||||
}
|
||||
|
||||
|
@ -1070,8 +1072,9 @@ LocationSummary* StringCharCodeAtInstr::MakeLocationSummary() const {
|
|||
LocationSummary* locs =
|
||||
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
||||
locs->set_in(0, Location::RequiresRegister());
|
||||
// TODO(fschneider): Allow immediate operands for the index.
|
||||
locs->set_in(1, Location::RequiresRegister());
|
||||
locs->set_in(1, CanBeImmediateIndex(index(), class_id())
|
||||
? Location::RegisterOrSmiConstant(index())
|
||||
: Location::RequiresRegister());
|
||||
locs->set_out(Location::RequiresRegister());
|
||||
return locs;
|
||||
}
|
||||
|
@ -1079,25 +1082,30 @@ LocationSummary* StringCharCodeAtInstr::MakeLocationSummary() const {
|
|||
|
||||
void StringCharCodeAtInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
Register str = locs()->in(0).reg();
|
||||
Register index = locs()->in(1).reg();
|
||||
Location index = locs()->in(1);
|
||||
Register result = locs()->out().reg();
|
||||
|
||||
ASSERT((class_id() == kOneByteStringCid) ||
|
||||
(class_id() == kTwoByteStringCid));
|
||||
|
||||
FieldAddress element_address = index.IsRegister() ?
|
||||
FlowGraphCompiler::ElementAddressForRegIndex(
|
||||
class_id(), str, index.reg()) :
|
||||
FlowGraphCompiler::ElementAddressForIntIndex(
|
||||
class_id(), str, Smi::Cast(index.constant()).Value());
|
||||
|
||||
if (class_id() == kOneByteStringCid) {
|
||||
__ SmiUntag(index);
|
||||
__ movzxb(result, FieldAddress(str,
|
||||
index,
|
||||
TIMES_1,
|
||||
OneByteString::data_offset()));
|
||||
__ SmiTag(index); // Retag index.
|
||||
if (index.IsRegister()) {
|
||||
__ SmiUntag(index.reg());
|
||||
}
|
||||
__ movzxb(result, element_address);
|
||||
if (index.IsRegister()) {
|
||||
__ SmiTag(index.reg()); // Retag index.
|
||||
}
|
||||
__ SmiTag(result);
|
||||
} else {
|
||||
// Don't untag smi-index and use TIMES_1 for two byte strings.
|
||||
__ movzxw(result, FieldAddress(str,
|
||||
index,
|
||||
TIMES_1,
|
||||
TwoByteString::data_offset()));
|
||||
__ movzxw(result, element_address);
|
||||
__ SmiTag(result);
|
||||
}
|
||||
}
|
||||
|
@ -1133,8 +1141,8 @@ LocationSummary* LoadIndexedInstr::MakeLocationSummary() const {
|
|||
LocationSummary* locs =
|
||||
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
||||
locs->set_in(0, Location::RequiresRegister());
|
||||
locs->set_in(1, CanBeImmediateIndex(index())
|
||||
? Location::RegisterOrConstant(index())
|
||||
locs->set_in(1, CanBeImmediateIndex(index(), class_id())
|
||||
? Location::RegisterOrSmiConstant(index())
|
||||
: Location::RequiresRegister());
|
||||
if (representation() == kUnboxedDouble) {
|
||||
locs->set_out(Location::RequiresXmmRegister());
|
||||
|
@ -1214,8 +1222,8 @@ LocationSummary* StoreIndexedInstr::MakeLocationSummary() const {
|
|||
LocationSummary* locs =
|
||||
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
||||
locs->set_in(0, Location::RequiresRegister());
|
||||
locs->set_in(1, CanBeImmediateIndex(index())
|
||||
? Location::RegisterOrConstant(index())
|
||||
locs->set_in(1, CanBeImmediateIndex(index(), class_id())
|
||||
? Location::RegisterOrSmiConstant(index())
|
||||
: Location::RequiresRegister());
|
||||
switch (class_id()) {
|
||||
case kArrayCid:
|
||||
|
|
|
@ -918,12 +918,14 @@ void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
}
|
||||
|
||||
|
||||
static bool CanBeImmediateIndex(Value* index) {
|
||||
static bool CanBeImmediateIndex(Value* index, intptr_t cid) {
|
||||
if (!index->definition()->IsConstant()) return false;
|
||||
const Object& constant = index->definition()->AsConstant()->value();
|
||||
if (!constant.IsSmi()) return false;
|
||||
const Smi& smi_const = Smi::Cast(constant);
|
||||
int64_t disp = smi_const.AsInt64Value() * kWordSize + sizeof(RawArray);
|
||||
const intptr_t scale = FlowGraphCompiler::ElementSizeFor(cid);
|
||||
const intptr_t data_offset = FlowGraphCompiler::DataOffsetFor(cid);
|
||||
const int64_t disp = smi_const.AsInt64Value() * scale + data_offset;
|
||||
return Utils::IsInt(32, disp);
|
||||
}
|
||||
|
||||
|
@ -934,8 +936,9 @@ LocationSummary* StringCharCodeAtInstr::MakeLocationSummary() const {
|
|||
LocationSummary* locs =
|
||||
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
||||
locs->set_in(0, Location::RequiresRegister());
|
||||
// TODO(fschneider): Allow immediate operands for the index.
|
||||
locs->set_in(1, Location::RequiresRegister());
|
||||
locs->set_in(1, CanBeImmediateIndex(index(), class_id())
|
||||
? Location::RegisterOrSmiConstant(index())
|
||||
: Location::RequiresRegister());
|
||||
locs->set_out(Location::RequiresRegister());
|
||||
return locs;
|
||||
}
|
||||
|
@ -943,25 +946,30 @@ LocationSummary* StringCharCodeAtInstr::MakeLocationSummary() const {
|
|||
|
||||
void StringCharCodeAtInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
Register str = locs()->in(0).reg();
|
||||
Register index = locs()->in(1).reg();
|
||||
Location index = locs()->in(1);
|
||||
Register result = locs()->out().reg();
|
||||
|
||||
ASSERT((class_id() == kOneByteStringCid) ||
|
||||
(class_id() == kTwoByteStringCid));
|
||||
|
||||
FieldAddress element_address = index.IsRegister() ?
|
||||
FlowGraphCompiler::ElementAddressForRegIndex(
|
||||
class_id(), str, index.reg()) :
|
||||
FlowGraphCompiler::ElementAddressForIntIndex(
|
||||
class_id(), str, Smi::Cast(index.constant()).Value());
|
||||
|
||||
if (class_id() == kOneByteStringCid) {
|
||||
__ SmiUntag(index);
|
||||
__ movzxb(result, FieldAddress(str,
|
||||
index,
|
||||
TIMES_1,
|
||||
OneByteString::data_offset()));
|
||||
__ SmiTag(index); // Retag index.
|
||||
if (index.IsRegister()) {
|
||||
__ SmiUntag(index.reg());
|
||||
}
|
||||
__ movzxb(result, element_address);
|
||||
if (index.IsRegister()) {
|
||||
__ SmiTag(index.reg()); // Retag index.
|
||||
}
|
||||
__ SmiTag(result);
|
||||
} else {
|
||||
// Don't untag smi-index and use TIMES_1 for two byte strings.
|
||||
__ movzxw(result, FieldAddress(str,
|
||||
index,
|
||||
TIMES_1,
|
||||
TwoByteString::data_offset()));
|
||||
__ movzxw(result, element_address);
|
||||
__ SmiTag(result);
|
||||
}
|
||||
}
|
||||
|
@ -997,8 +1005,8 @@ LocationSummary* LoadIndexedInstr::MakeLocationSummary() const {
|
|||
LocationSummary* locs =
|
||||
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
||||
locs->set_in(0, Location::RequiresRegister());
|
||||
locs->set_in(1, CanBeImmediateIndex(index())
|
||||
? Location::RegisterOrConstant(index())
|
||||
locs->set_in(1, CanBeImmediateIndex(index(), class_id())
|
||||
? Location::RegisterOrSmiConstant(index())
|
||||
: Location::RequiresRegister());
|
||||
if (representation() == kUnboxedDouble) {
|
||||
locs->set_out(Location::RequiresXmmRegister());
|
||||
|
@ -1078,8 +1086,8 @@ LocationSummary* StoreIndexedInstr::MakeLocationSummary() const {
|
|||
LocationSummary* locs =
|
||||
new LocationSummary(kNumInputs, numTemps, LocationSummary::kNoCall);
|
||||
locs->set_in(0, Location::RequiresRegister());
|
||||
locs->set_in(1, CanBeImmediateIndex(index())
|
||||
? Location::RegisterOrConstant(index())
|
||||
locs->set_in(1, CanBeImmediateIndex(index(), class_id())
|
||||
? Location::RegisterOrSmiConstant(index())
|
||||
: Location::RequiresRegister());
|
||||
switch (class_id()) {
|
||||
case kArrayCid:
|
||||
|
|
|
@ -161,7 +161,7 @@ bool Intrinsifier::Array_getIndexed(Assembler* assembler) {
|
|||
__ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump);
|
||||
// Note that EBX is Smi, i.e, times 2.
|
||||
ASSERT(kSmiTagShift == 1);
|
||||
__ movl(EAX, FieldAddress(EAX, EBX, TIMES_2, sizeof(RawArray)));
|
||||
__ movl(EAX, FieldAddress(EAX, EBX, TIMES_2, Array::data_offset()));
|
||||
__ ret();
|
||||
__ Bind(&fall_through);
|
||||
return false;
|
||||
|
@ -238,7 +238,7 @@ bool Intrinsifier::Array_setIndexed(Assembler* assembler) {
|
|||
// Destroy ECX as we will not continue in the function.
|
||||
__ movl(ECX, Address(ESP, + 1 * kWordSize)); // Value.
|
||||
__ StoreIntoObject(EAX,
|
||||
FieldAddress(EAX, EBX, TIMES_2, sizeof(RawArray)),
|
||||
FieldAddress(EAX, EBX, TIMES_2, Array::data_offset()),
|
||||
ECX);
|
||||
// Caller is responsible of preserving the value if necessary.
|
||||
__ ret();
|
||||
|
@ -350,7 +350,7 @@ bool Intrinsifier::GrowableArray_getIndexed(Assembler* assembler) {
|
|||
|
||||
// Note that EBX is Smi, i.e, times 2.
|
||||
ASSERT(kSmiTagShift == 1);
|
||||
__ movl(EAX, FieldAddress(EAX, EBX, TIMES_2, sizeof(RawArray)));
|
||||
__ movl(EAX, FieldAddress(EAX, EBX, TIMES_2, Array::data_offset()));
|
||||
__ ret();
|
||||
__ Bind(&fall_through);
|
||||
return false;
|
||||
|
@ -377,7 +377,7 @@ bool Intrinsifier::GrowableArray_setIndexed(Assembler* assembler) {
|
|||
// Note that EBX is Smi, i.e, times 2.
|
||||
ASSERT(kSmiTagShift == 1);
|
||||
__ StoreIntoObject(EAX,
|
||||
FieldAddress(EAX, EBX, TIMES_2, sizeof(RawArray)),
|
||||
FieldAddress(EAX, EBX, TIMES_2, Array::data_offset()),
|
||||
EDI);
|
||||
__ ret();
|
||||
__ Bind(&fall_through);
|
||||
|
@ -447,7 +447,7 @@ bool Intrinsifier::GrowableArray_add(Assembler* assembler) {
|
|||
__ movl(EAX, Address(ESP, + 1 * kWordSize)); // Value
|
||||
ASSERT(kSmiTagShift == 1);
|
||||
__ StoreIntoObject(EDI,
|
||||
FieldAddress(EDI, EBX, TIMES_2, sizeof(RawArray)),
|
||||
FieldAddress(EDI, EBX, TIMES_2, Array::data_offset()),
|
||||
EAX);
|
||||
const Immediate raw_null =
|
||||
Immediate(reinterpret_cast<int32_t>(Object::null()));
|
||||
|
|
|
@ -161,7 +161,7 @@ bool Intrinsifier::Array_getIndexed(Assembler* assembler) {
|
|||
__ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump);
|
||||
// Note that RBX is Smi, i.e, times 2.
|
||||
ASSERT(kSmiTagShift == 1);
|
||||
__ movq(RAX, FieldAddress(RAX, RCX, TIMES_4, sizeof(RawArray)));
|
||||
__ movq(RAX, FieldAddress(RAX, RCX, TIMES_4, Array::data_offset()));
|
||||
__ ret();
|
||||
__ Bind(&fall_through);
|
||||
return false;
|
||||
|
@ -191,7 +191,7 @@ bool Intrinsifier::Array_setIndexed(Assembler* assembler) {
|
|||
ASSERT(kSmiTagShift == 1);
|
||||
// Destroy RCX as we will not continue in the function.
|
||||
__ StoreIntoObject(RAX,
|
||||
FieldAddress(RAX, RCX, TIMES_4, sizeof(RawArray)),
|
||||
FieldAddress(RAX, RCX, TIMES_4, Array::data_offset()),
|
||||
RDX);
|
||||
// Caller is responsible of preserving the value if necessary.
|
||||
__ ret();
|
||||
|
@ -304,7 +304,7 @@ bool Intrinsifier::GrowableArray_getIndexed(Assembler* assembler) {
|
|||
|
||||
// Note that RCX is Smi, i.e, times 4.
|
||||
ASSERT(kSmiTagShift == 1);
|
||||
__ movq(RAX, FieldAddress(RAX, RCX, TIMES_4, sizeof(RawArray)));
|
||||
__ movq(RAX, FieldAddress(RAX, RCX, TIMES_4, Array::data_offset()));
|
||||
__ ret();
|
||||
__ Bind(&fall_through);
|
||||
return false;
|
||||
|
@ -331,7 +331,7 @@ bool Intrinsifier::GrowableArray_setIndexed(Assembler* assembler) {
|
|||
// Note that RCX is Smi, i.e, times 4.
|
||||
ASSERT(kSmiTagShift == 1);
|
||||
__ StoreIntoObject(RAX,
|
||||
FieldAddress(RAX, RCX, TIMES_4, sizeof(RawArray)),
|
||||
FieldAddress(RAX, RCX, TIMES_4, Array::data_offset()),
|
||||
RDX);
|
||||
__ ret();
|
||||
__ Bind(&fall_through);
|
||||
|
@ -400,7 +400,7 @@ bool Intrinsifier::GrowableArray_add(Assembler* assembler) {
|
|||
__ movq(RAX, Address(RSP, + 1 * kWordSize)); // Value
|
||||
ASSERT(kSmiTagShift == 1);
|
||||
__ StoreIntoObject(RDX,
|
||||
FieldAddress(RDX, RCX, TIMES_4, sizeof(RawArray)),
|
||||
FieldAddress(RDX, RCX, TIMES_4, Array::data_offset()),
|
||||
RAX);
|
||||
const Immediate raw_null =
|
||||
Immediate(reinterpret_cast<int64_t>(Object::null()));
|
||||
|
|
Loading…
Reference in a new issue