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:
fschneider@google.com 2013-01-14 17:00:34 +00:00
parent 260c80a4bb
commit 339ac7f288
7 changed files with 127 additions and 81 deletions

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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:

View file

@ -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:

View file

@ -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()));

View file

@ -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()));