diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc index ff7c0417f66..bd45b11db0b 100644 --- a/runtime/vm/flow_graph_compiler.cc +++ b/runtime/vm/flow_graph_compiler.cc @@ -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(index) * ElementSizeFor(cid) + DataOffsetFor(cid); + ASSERT(Utils::IsInt(32, disp)); + return FieldAddress(array, static_cast(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); diff --git a/runtime/vm/flow_graph_compiler_ia32.h b/runtime/vm/flow_graph_compiler_ia32.h index 13633290fd4..3f7cf0e5fc7 100644 --- a/runtime/vm/flow_graph_compiler_ia32.h +++ b/runtime/vm/flow_graph_compiler_ia32.h @@ -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); diff --git a/runtime/vm/flow_graph_compiler_x64.h b/runtime/vm/flow_graph_compiler_x64.h index 9f8528f09f2..4c9f6901b58 100644 --- a/runtime/vm/flow_graph_compiler_x64.h +++ b/runtime/vm/flow_graph_compiler_x64.h @@ -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); diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc index 9cfdf09206b..9172a5c0ce9 100644 --- a/runtime/vm/intermediate_language_ia32.cc +++ b/runtime/vm/intermediate_language_ia32.cc @@ -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: diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc index db7a2e7f896..2ac35d3bcbd 100644 --- a/runtime/vm/intermediate_language_x64.cc +++ b/runtime/vm/intermediate_language_x64.cc @@ -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: diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc index 30eda52adb6..3022eab2624 100644 --- a/runtime/vm/intrinsifier_ia32.cc +++ b/runtime/vm/intrinsifier_ia32.cc @@ -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(Object::null())); diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc index 49d10fc2ca1..24602564d5f 100644 --- a/runtime/vm/intrinsifier_x64.cc +++ b/runtime/vm/intrinsifier_x64.cc @@ -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(Object::null()));