| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. |
| 6 #if defined(TARGET_ARCH_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
| 7 | 7 |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 | 9 |
| 10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 48 // where PushArgument is handled by BindInstr::EmitNativeCode. | 48 // where PushArgument is handled by BindInstr::EmitNativeCode. |
| 49 if (compiler->is_optimizing()) { | 49 if (compiler->is_optimizing()) { |
| 50 Location value = locs()->in(0); | 50 Location value = locs()->in(0); |
| 51 if (value.IsRegister()) { | 51 if (value.IsRegister()) { |
| 52 __ Push(value.reg()); | 52 __ Push(value.reg()); |
| 53 } else if (value.IsConstant()) { | 53 } else if (value.IsConstant()) { |
| 54 __ PushObject(value.constant(), PP); | 54 __ PushObject(value.constant(), PP); |
| 55 } else { | 55 } else { |
| 56 ASSERT(value.IsStackSlot()); | 56 ASSERT(value.IsStackSlot()); |
| 57 const intptr_t value_offset = value.ToStackSlotOffset(); | 57 const intptr_t value_offset = value.ToStackSlotOffset(); |
| 58 __ LoadFromOffset(TMP, FP, value_offset); | 58 __ LoadFromOffset(TMP, FP, value_offset, PP); |
| 59 __ Push(TMP); | 59 __ Push(TMP); |
| 60 } | 60 } |
| 61 } | 61 } |
| 62 } | 62 } |
| 63 | 63 |
| 64 | 64 |
| 65 LocationSummary* ReturnInstr::MakeLocationSummary(bool opt) const { | 65 LocationSummary* ReturnInstr::MakeLocationSummary(bool opt) const { |
| 66 const intptr_t kNumInputs = 1; | 66 const intptr_t kNumInputs = 1; |
| 67 const intptr_t kNumTemps = 0; | 67 const intptr_t kNumTemps = 0; |
| 68 LocationSummary* locs = | 68 LocationSummary* locs = |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 194 // Load arguments descriptor in R4. | 194 // Load arguments descriptor in R4. |
| 195 int argument_count = ArgumentCount(); | 195 int argument_count = ArgumentCount(); |
| 196 const Array& arguments_descriptor = | 196 const Array& arguments_descriptor = |
| 197 Array::ZoneHandle(ArgumentsDescriptor::New(argument_count, | 197 Array::ZoneHandle(ArgumentsDescriptor::New(argument_count, |
| 198 argument_names())); | 198 argument_names())); |
| 199 __ LoadObject(R4, arguments_descriptor, PP); | 199 __ LoadObject(R4, arguments_descriptor, PP); |
| 200 | 200 |
| 201 // R4: Arguments descriptor. | 201 // R4: Arguments descriptor. |
| 202 // R0: Function. | 202 // R0: Function. |
| 203 ASSERT(locs()->in(0).reg() == R0); | 203 ASSERT(locs()->in(0).reg() == R0); |
| 204 __ LoadFieldFromOffset(R2, R0, Function::code_offset()); | 204 __ LoadFieldFromOffset(R2, R0, Function::code_offset(), PP); |
| 205 | 205 |
| 206 // R2: code. | 206 // R2: code. |
| 207 // R5: Smi 0 (no IC data; the lazy-compile stub expects a GC-safe value). | 207 // R5: Smi 0 (no IC data; the lazy-compile stub expects a GC-safe value). |
| 208 __ LoadImmediate(R5, 0, PP); | 208 __ LoadImmediate(R5, 0, PP); |
| 209 __ LoadFieldFromOffset(R2, R2, Code::instructions_offset()); | 209 __ LoadFieldFromOffset(R2, R2, Code::instructions_offset(), PP); |
| 210 __ AddImmediate(R2, R2, Instructions::HeaderSize() - kHeapObjectTag, PP); | 210 __ AddImmediate(R2, R2, Instructions::HeaderSize() - kHeapObjectTag, PP); |
| 211 __ blr(R2); | 211 __ blr(R2); |
| 212 compiler->AddCurrentDescriptor(PcDescriptors::kClosureCall, | 212 compiler->AddCurrentDescriptor(PcDescriptors::kClosureCall, |
| 213 deopt_id(), | 213 deopt_id(), |
| 214 token_pos()); | 214 token_pos()); |
| 215 compiler->RecordSafepoint(locs()); | 215 compiler->RecordSafepoint(locs()); |
| 216 // Marks either the continuation point in unoptimized code or the | 216 // Marks either the continuation point in unoptimized code or the |
| 217 // deoptimization point in optimized code, after call. | 217 // deoptimization point in optimized code, after call. |
| 218 const intptr_t deopt_id_after = Isolate::ToDeoptAfter(deopt_id()); | 218 const intptr_t deopt_id_after = Isolate::ToDeoptAfter(deopt_id()); |
| 219 if (compiler->is_optimizing()) { | 219 if (compiler->is_optimizing()) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 231 | 231 |
| 232 LocationSummary* LoadLocalInstr::MakeLocationSummary(bool opt) const { | 232 LocationSummary* LoadLocalInstr::MakeLocationSummary(bool opt) const { |
| 233 return LocationSummary::Make(0, | 233 return LocationSummary::Make(0, |
| 234 Location::RequiresRegister(), | 234 Location::RequiresRegister(), |
| 235 LocationSummary::kNoCall); | 235 LocationSummary::kNoCall); |
| 236 } | 236 } |
| 237 | 237 |
| 238 | 238 |
| 239 void LoadLocalInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 239 void LoadLocalInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 240 Register result = locs()->out(0).reg(); | 240 Register result = locs()->out(0).reg(); |
| 241 __ LoadFromOffset(result, FP, local().index() * kWordSize); | 241 __ LoadFromOffset(result, FP, local().index() * kWordSize, PP); |
| 242 } | 242 } |
| 243 | 243 |
| 244 | 244 |
| 245 LocationSummary* StoreLocalInstr::MakeLocationSummary(bool opt) const { | 245 LocationSummary* StoreLocalInstr::MakeLocationSummary(bool opt) const { |
| 246 return LocationSummary::Make(1, | 246 return LocationSummary::Make(1, |
| 247 Location::SameAsFirstInput(), | 247 Location::SameAsFirstInput(), |
| 248 LocationSummary::kNoCall); | 248 LocationSummary::kNoCall); |
| 249 } | 249 } |
| 250 | 250 |
| 251 | 251 |
| 252 void StoreLocalInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 252 void StoreLocalInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 253 Register value = locs()->in(0).reg(); | 253 Register value = locs()->in(0).reg(); |
| 254 Register result = locs()->out(0).reg(); | 254 Register result = locs()->out(0).reg(); |
| 255 ASSERT(result == value); // Assert that register assignment is correct. | 255 ASSERT(result == value); // Assert that register assignment is correct. |
| 256 __ StoreToOffset(value, FP, local().index() * kWordSize); | 256 __ StoreToOffset(value, FP, local().index() * kWordSize, PP); |
| 257 } | 257 } |
| 258 | 258 |
| 259 | 259 |
| 260 LocationSummary* ConstantInstr::MakeLocationSummary(bool opt) const { | 260 LocationSummary* ConstantInstr::MakeLocationSummary(bool opt) const { |
| 261 return LocationSummary::Make(0, | 261 return LocationSummary::Make(0, |
| 262 Location::RequiresRegister(), | 262 Location::RequiresRegister(), |
| 263 LocationSummary::kNoCall); | 263 LocationSummary::kNoCall); |
| 264 } | 264 } |
| 265 | 265 |
| 266 | 266 |
| (...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 584 | 584 |
| 585 Label* deopt = CanDeoptimize() ? | 585 Label* deopt = CanDeoptimize() ? |
| 586 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptTestCids) : NULL; | 586 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptTestCids) : NULL; |
| 587 | 587 |
| 588 const intptr_t true_result = (kind() == Token::kIS) ? 1 : 0; | 588 const intptr_t true_result = (kind() == Token::kIS) ? 1 : 0; |
| 589 const ZoneGrowableArray<intptr_t>& data = cid_results(); | 589 const ZoneGrowableArray<intptr_t>& data = cid_results(); |
| 590 ASSERT(data[0] == kSmiCid); | 590 ASSERT(data[0] == kSmiCid); |
| 591 bool result = data[1] == true_result; | 591 bool result = data[1] == true_result; |
| 592 __ tsti(val_reg, kSmiTagMask); | 592 __ tsti(val_reg, kSmiTagMask); |
| 593 __ b(result ? labels.true_label : labels.false_label, EQ); | 593 __ b(result ? labels.true_label : labels.false_label, EQ); |
| 594 __ LoadClassId(cid_reg, val_reg); | 594 __ LoadClassId(cid_reg, val_reg, PP); |
| 595 | 595 |
| 596 for (intptr_t i = 2; i < data.length(); i += 2) { | 596 for (intptr_t i = 2; i < data.length(); i += 2) { |
| 597 const intptr_t test_cid = data[i]; | 597 const intptr_t test_cid = data[i]; |
| 598 ASSERT(test_cid != kSmiCid); | 598 ASSERT(test_cid != kSmiCid); |
| 599 result = data[i + 1] == true_result; | 599 result = data[i + 1] == true_result; |
| 600 __ CompareImmediate(cid_reg, test_cid, PP); | 600 __ CompareImmediate(cid_reg, test_cid, PP); |
| 601 __ b(result ? labels.true_label : labels.false_label, EQ); | 601 __ b(result ? labels.true_label : labels.false_label, EQ); |
| 602 } | 602 } |
| 603 // No match found, deoptimize or false. | 603 // No match found, deoptimize or false. |
| 604 if (deopt == NULL) { | 604 if (deopt == NULL) { |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 787 return LocationSummary::Make(kNumInputs, | 787 return LocationSummary::Make(kNumInputs, |
| 788 Location::RequiresRegister(), | 788 Location::RequiresRegister(), |
| 789 LocationSummary::kNoCall); | 789 LocationSummary::kNoCall); |
| 790 } | 790 } |
| 791 | 791 |
| 792 | 792 |
| 793 void StringToCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 793 void StringToCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 794 ASSERT(cid_ == kOneByteStringCid); | 794 ASSERT(cid_ == kOneByteStringCid); |
| 795 Register str = locs()->in(0).reg(); | 795 Register str = locs()->in(0).reg(); |
| 796 Register result = locs()->out(0).reg(); | 796 Register result = locs()->out(0).reg(); |
| 797 __ LoadFieldFromOffset(result, str, String::length_offset()); | 797 __ LoadFieldFromOffset(result, str, String::length_offset(), PP); |
| 798 __ CompareImmediate(result, Smi::RawValue(1), PP); | 798 __ CompareImmediate(result, Smi::RawValue(1), PP); |
| 799 __ LoadImmediate(TMP, Smi::RawValue(-1), PP); | 799 __ LoadImmediate(TMP, Smi::RawValue(-1), PP); |
| 800 __ ldr(TMP2, FieldAddress(str, OneByteString::data_offset()), kUnsignedByte); | 800 __ ldr(TMP2, FieldAddress(str, OneByteString::data_offset()), kUnsignedByte); |
| 801 __ csel(result, TMP, result, NE); | 801 __ csel(result, TMP, result, NE); |
| 802 __ csel(result, TMP2, result, EQ); | 802 __ csel(result, TMP2, result, EQ); |
| 803 __ SmiTag(result); | 803 __ SmiTag(result); |
| 804 } | 804 } |
| 805 | 805 |
| 806 | 806 |
| 807 LocationSummary* StringInterpolateInstr::MakeLocationSummary(bool opt) const { | 807 LocationSummary* StringInterpolateInstr::MakeLocationSummary(bool opt) const { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 851 | 851 |
| 852 void LoadClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 852 void LoadClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 853 Register object = locs()->in(0).reg(); | 853 Register object = locs()->in(0).reg(); |
| 854 Register result = locs()->out(0).reg(); | 854 Register result = locs()->out(0).reg(); |
| 855 Label load, done; | 855 Label load, done; |
| 856 __ tsti(object, kSmiTagMask); | 856 __ tsti(object, kSmiTagMask); |
| 857 __ b(&load, NE); | 857 __ b(&load, NE); |
| 858 __ LoadImmediate(result, Smi::RawValue(kSmiCid), PP); | 858 __ LoadImmediate(result, Smi::RawValue(kSmiCid), PP); |
| 859 __ b(&done); | 859 __ b(&done); |
| 860 __ Bind(&load); | 860 __ Bind(&load); |
| 861 __ LoadClassId(result, object); | 861 __ LoadClassId(result, object, PP); |
| 862 __ SmiTag(result); | 862 __ SmiTag(result); |
| 863 __ Bind(&done); | 863 __ Bind(&done); |
| 864 } | 864 } |
| 865 | 865 |
| 866 | 866 |
| 867 CompileType LoadIndexedInstr::ComputeType() const { | 867 CompileType LoadIndexedInstr::ComputeType() const { |
| 868 switch (class_id_) { | 868 switch (class_id_) { |
| 869 case kArrayCid: | 869 case kArrayCid: |
| 870 case kImmutableArrayCid: | 870 case kImmutableArrayCid: |
| 871 return CompileType::Dynamic(); | 871 return CompileType::Dynamic(); |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1002 (representation() == kUnboxedFloat64x2)) { | 1002 (representation() == kUnboxedFloat64x2)) { |
| 1003 const VRegister result = locs()->out(0).fpu_reg(); | 1003 const VRegister result = locs()->out(0).fpu_reg(); |
| 1004 switch (class_id()) { | 1004 switch (class_id()) { |
| 1005 case kTypedDataInt32ArrayCid: | 1005 case kTypedDataInt32ArrayCid: |
| 1006 case kTypedDataUint32ArrayCid: | 1006 case kTypedDataUint32ArrayCid: |
| 1007 // TODO(zra): Add when we have simd. | 1007 // TODO(zra): Add when we have simd. |
| 1008 UNIMPLEMENTED(); | 1008 UNIMPLEMENTED(); |
| 1009 break; | 1009 break; |
| 1010 case kTypedDataFloat32ArrayCid: | 1010 case kTypedDataFloat32ArrayCid: |
| 1011 // Load single precision float. | 1011 // Load single precision float. |
| 1012 // TODO(zra): Add when we add single precision floats. | 1012 __ fldrs(result, element_address); |
| 1013 UNIMPLEMENTED(); | |
| 1014 break; | 1013 break; |
| 1015 case kTypedDataFloat64ArrayCid: | 1014 case kTypedDataFloat64ArrayCid: |
| 1016 // Load double precision float. | 1015 // Load double precision float. |
| 1017 __ fldrd(result, element_address); | 1016 __ fldrd(result, element_address); |
| 1018 break; | 1017 break; |
| 1019 case kTypedDataFloat64x2ArrayCid: | 1018 case kTypedDataFloat64x2ArrayCid: |
| 1020 case kTypedDataInt32x4ArrayCid: | 1019 case kTypedDataInt32x4ArrayCid: |
| 1021 case kTypedDataFloat32x4ArrayCid: | 1020 case kTypedDataFloat32x4ArrayCid: |
| 1022 // TODO(zra): Add when we have simd. | 1021 // TODO(zra): Add when we have simd. |
| 1023 UNIMPLEMENTED(); | 1022 UNIMPLEMENTED(); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1134 // Mints are stored in Q registers. For smis, use a writable register | 1133 // Mints are stored in Q registers. For smis, use a writable register |
| 1135 // because the value must be untagged before storing. | 1134 // because the value must be untagged before storing. |
| 1136 if (value()->IsSmiValue()) { | 1135 if (value()->IsSmiValue()) { |
| 1137 locs->set_in(2, Location::WritableRegister()); | 1136 locs->set_in(2, Location::WritableRegister()); |
| 1138 } else { | 1137 } else { |
| 1139 // TODO(zra): Implement when we add simd loads and stores. | 1138 // TODO(zra): Implement when we add simd loads and stores. |
| 1140 UNIMPLEMENTED(); | 1139 UNIMPLEMENTED(); |
| 1141 } | 1140 } |
| 1142 break; | 1141 break; |
| 1143 case kTypedDataFloat32ArrayCid: | 1142 case kTypedDataFloat32ArrayCid: |
| 1144 // TODO(zra): Implement when we add float store. | |
| 1145 UNIMPLEMENTED(); | |
| 1146 break; | |
| 1147 case kTypedDataFloat64ArrayCid: // TODO(srdjan): Support Float64 constants. | 1143 case kTypedDataFloat64ArrayCid: // TODO(srdjan): Support Float64 constants. |
| 1148 locs->set_in(2, Location::RequiresFpuRegister()); | 1144 locs->set_in(2, Location::RequiresFpuRegister()); |
| 1149 break; | 1145 break; |
| 1150 case kTypedDataInt32x4ArrayCid: | 1146 case kTypedDataInt32x4ArrayCid: |
| 1151 case kTypedDataFloat32x4ArrayCid: | 1147 case kTypedDataFloat32x4ArrayCid: |
| 1152 case kTypedDataFloat64x2ArrayCid: | 1148 case kTypedDataFloat64x2ArrayCid: |
| 1153 // TODO(zra): Implement when we add simd loads and stores. | 1149 // TODO(zra): Implement when we add simd loads and stores. |
| 1154 UNIMPLEMENTED(); | 1150 UNIMPLEMENTED(); |
| 1155 break; | 1151 break; |
| 1156 default: | 1152 default: |
| 1157 UNREACHABLE(); | 1153 UNREACHABLE(); |
| 1158 return NULL; | 1154 return NULL; |
| 1159 } | 1155 } |
| 1160 return locs; | 1156 return locs; |
| 1161 } | 1157 } |
| 1162 | 1158 |
| 1163 | 1159 |
| 1164 void StoreIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 1160 void StoreIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1165 Register array = locs()->in(0).reg(); | 1161 const Register array = locs()->in(0).reg(); |
| 1166 Location index = locs()->in(1); | 1162 Location index = locs()->in(1); |
| 1167 | 1163 |
| 1168 Address element_address(kNoRegister, 0); | 1164 Address element_address(kNoRegister, 0); |
| 1169 ASSERT(index.IsRegister()); // TODO(regis): Revisit. | 1165 ASSERT(index.IsRegister()); // TODO(regis): Revisit. |
| 1170 // Note that index is expected smi-tagged, (i.e, times 2) for all arrays | 1166 // Note that index is expected smi-tagged, (i.e, times 2) for all arrays |
| 1171 // with index scale factor > 1. E.g., for Uint8Array and OneByteString the | 1167 // with index scale factor > 1. E.g., for Uint8Array and OneByteString the |
| 1172 // index is expected to be untagged before accessing. | 1168 // index is expected to be untagged before accessing. |
| 1173 ASSERT(kSmiTagShift == 1); | 1169 ASSERT(kSmiTagShift == 1); |
| 1174 switch (index_scale()) { | 1170 switch (index_scale()) { |
| 1175 case 1: { | 1171 case 1: { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1197 if (!IsExternal()) { | 1193 if (!IsExternal()) { |
| 1198 ASSERT(this->array()->definition()->representation() == kTagged); | 1194 ASSERT(this->array()->definition()->representation() == kTagged); |
| 1199 __ AddImmediate(index.reg(), index.reg(), | 1195 __ AddImmediate(index.reg(), index.reg(), |
| 1200 FlowGraphCompiler::DataOffsetFor(class_id()) - kHeapObjectTag, PP); | 1196 FlowGraphCompiler::DataOffsetFor(class_id()) - kHeapObjectTag, PP); |
| 1201 } | 1197 } |
| 1202 element_address = Address(array, index.reg(), UXTX, Address::Unscaled); | 1198 element_address = Address(array, index.reg(), UXTX, Address::Unscaled); |
| 1203 | 1199 |
| 1204 switch (class_id()) { | 1200 switch (class_id()) { |
| 1205 case kArrayCid: | 1201 case kArrayCid: |
| 1206 if (ShouldEmitStoreBarrier()) { | 1202 if (ShouldEmitStoreBarrier()) { |
| 1207 Register value = locs()->in(2).reg(); | 1203 const Register value = locs()->in(2).reg(); |
| 1208 __ StoreIntoObject(array, element_address, value); | 1204 __ StoreIntoObject(array, element_address, value); |
| 1209 } else if (locs()->in(2).IsConstant()) { | 1205 } else if (locs()->in(2).IsConstant()) { |
| 1210 const Object& constant = locs()->in(2).constant(); | 1206 const Object& constant = locs()->in(2).constant(); |
| 1211 __ StoreIntoObjectNoBarrier(array, element_address, constant); | 1207 __ StoreIntoObjectNoBarrier(array, element_address, constant); |
| 1212 } else { | 1208 } else { |
| 1213 Register value = locs()->in(2).reg(); | 1209 const Register value = locs()->in(2).reg(); |
| 1214 __ StoreIntoObjectNoBarrier(array, element_address, value); | 1210 __ StoreIntoObjectNoBarrier(array, element_address, value); |
| 1215 } | 1211 } |
| 1216 break; | 1212 break; |
| 1217 case kTypedDataInt8ArrayCid: | 1213 case kTypedDataInt8ArrayCid: |
| 1218 case kTypedDataUint8ArrayCid: | 1214 case kTypedDataUint8ArrayCid: |
| 1219 case kExternalTypedDataUint8ArrayCid: | 1215 case kExternalTypedDataUint8ArrayCid: |
| 1220 case kOneByteStringCid: { | 1216 case kOneByteStringCid: { |
| 1221 if (locs()->in(2).IsConstant()) { | 1217 if (locs()->in(2).IsConstant()) { |
| 1222 const Smi& constant = Smi::Cast(locs()->in(2).constant()); | 1218 const Smi& constant = Smi::Cast(locs()->in(2).constant()); |
| 1223 __ LoadImmediate(TMP, static_cast<int8_t>(constant.Value()), PP); | 1219 __ LoadImmediate(TMP, static_cast<int8_t>(constant.Value()), PP); |
| 1224 __ str(TMP, element_address, kUnsignedByte); | 1220 __ str(TMP, element_address, kUnsignedByte); |
| 1225 } else { | 1221 } else { |
| 1226 Register value = locs()->in(2).reg(); | 1222 const Register value = locs()->in(2).reg(); |
| 1227 __ SmiUntag(value); | 1223 __ SmiUntag(value); |
| 1228 __ str(value, element_address, kUnsignedByte); | 1224 __ str(value, element_address, kUnsignedByte); |
| 1229 } | 1225 } |
| 1230 break; | 1226 break; |
| 1231 } | 1227 } |
| 1232 case kTypedDataUint8ClampedArrayCid: | 1228 case kTypedDataUint8ClampedArrayCid: |
| 1233 case kExternalTypedDataUint8ClampedArrayCid: { | 1229 case kExternalTypedDataUint8ClampedArrayCid: { |
| 1234 if (locs()->in(2).IsConstant()) { | 1230 if (locs()->in(2).IsConstant()) { |
| 1235 const Smi& constant = Smi::Cast(locs()->in(2).constant()); | 1231 const Smi& constant = Smi::Cast(locs()->in(2).constant()); |
| 1236 intptr_t value = constant.Value(); | 1232 intptr_t value = constant.Value(); |
| 1237 // Clamp to 0x0 or 0xFF respectively. | 1233 // Clamp to 0x0 or 0xFF respectively. |
| 1238 if (value > 0xFF) { | 1234 if (value > 0xFF) { |
| 1239 value = 0xFF; | 1235 value = 0xFF; |
| 1240 } else if (value < 0) { | 1236 } else if (value < 0) { |
| 1241 value = 0; | 1237 value = 0; |
| 1242 } | 1238 } |
| 1243 __ LoadImmediate(TMP, static_cast<int8_t>(value), PP); | 1239 __ LoadImmediate(TMP, static_cast<int8_t>(value), PP); |
| 1244 __ str(TMP, element_address, kUnsignedByte); | 1240 __ str(TMP, element_address, kUnsignedByte); |
| 1245 } else { | 1241 } else { |
| 1246 Register value = locs()->in(2).reg(); | 1242 const Register value = locs()->in(2).reg(); |
| 1247 Label store_value; | 1243 Label store_value; |
| 1248 __ SmiUntag(value); | 1244 __ SmiUntag(value); |
| 1249 __ CompareImmediate(value, 0xFF, PP); | 1245 __ CompareImmediate(value, 0xFF, PP); |
| 1250 // Clamp to 0x00 or 0xFF respectively. | 1246 // Clamp to 0x00 or 0xFF respectively. |
| 1251 __ b(&store_value, LS); | 1247 __ b(&store_value, LS); |
| 1252 __ LoadImmediate(TMP, 0x00, PP); | 1248 __ LoadImmediate(TMP, 0x00, PP); |
| 1253 __ LoadImmediate(TMP2, 0xFF, PP); | 1249 __ LoadImmediate(TMP2, 0xFF, PP); |
| 1254 __ csel(value, TMP, value, LE); | 1250 __ csel(value, TMP, value, LE); |
| 1255 __ csel(value, TMP2, value, GT); | 1251 __ csel(value, TMP2, value, GT); |
| 1256 __ Bind(&store_value); | 1252 __ Bind(&store_value); |
| 1257 __ str(value, element_address, kUnsignedByte); | 1253 __ str(value, element_address, kUnsignedByte); |
| 1258 } | 1254 } |
| 1259 break; | 1255 break; |
| 1260 } | 1256 } |
| 1261 case kTypedDataInt16ArrayCid: | 1257 case kTypedDataInt16ArrayCid: |
| 1262 case kTypedDataUint16ArrayCid: { | 1258 case kTypedDataUint16ArrayCid: { |
| 1263 Register value = locs()->in(2).reg(); | 1259 const Register value = locs()->in(2).reg(); |
| 1264 __ SmiUntag(value); | 1260 __ SmiUntag(value); |
| 1265 __ str(value, element_address, kUnsignedHalfword); | 1261 __ str(value, element_address, kUnsignedHalfword); |
| 1266 break; | 1262 break; |
| 1267 } | 1263 } |
| 1268 case kTypedDataInt32ArrayCid: | 1264 case kTypedDataInt32ArrayCid: |
| 1269 case kTypedDataUint32ArrayCid: { | 1265 case kTypedDataUint32ArrayCid: { |
| 1270 if (value()->IsSmiValue()) { | 1266 if (value()->IsSmiValue()) { |
| 1271 ASSERT(RequiredInputRepresentation(2) == kTagged); | 1267 ASSERT(RequiredInputRepresentation(2) == kTagged); |
| 1272 Register value = locs()->in(2).reg(); | 1268 const Register value = locs()->in(2).reg(); |
| 1273 __ SmiUntag(value); | 1269 __ SmiUntag(value); |
| 1274 __ str(value, element_address); | 1270 __ str(value, element_address, kUnsignedWord); |
| 1275 } else { | 1271 } else { |
| 1276 // TODO(zra): Implement when we add simd loads and stores. | 1272 // TODO(zra): Implement when we add simd loads and stores. |
| 1277 UNIMPLEMENTED(); | 1273 UNIMPLEMENTED(); |
| 1278 } | 1274 } |
| 1279 break; | 1275 break; |
| 1280 } | 1276 } |
| 1281 case kTypedDataFloat32ArrayCid: | 1277 case kTypedDataFloat32ArrayCid: { |
| 1282 // TODO(zra): Implement when we add float store. | 1278 const VRegister in2 = locs()->in(2).fpu_reg(); |
| 1283 UNIMPLEMENTED(); | 1279 __ add(index.reg(), index.reg(), Operand(array)); |
| 1280 __ fstrs(in2, Address(index.reg())); |
| 1284 break; | 1281 break; |
| 1282 } |
| 1285 case kTypedDataFloat64ArrayCid: { | 1283 case kTypedDataFloat64ArrayCid: { |
| 1286 VRegister in2 = locs()->in(2).fpu_reg(); | 1284 const VRegister in2 = locs()->in(2).fpu_reg(); |
| 1287 __ add(index.reg(), index.reg(), Operand(array)); | 1285 __ add(index.reg(), index.reg(), Operand(array)); |
| 1288 __ StoreDToOffset(in2, index.reg(), 0); | 1286 __ StoreDToOffset(in2, index.reg(), 0, PP); |
| 1289 break; | 1287 break; |
| 1290 } | 1288 } |
| 1291 case kTypedDataFloat64x2ArrayCid: | 1289 case kTypedDataFloat64x2ArrayCid: |
| 1292 case kTypedDataInt32x4ArrayCid: | 1290 case kTypedDataInt32x4ArrayCid: |
| 1293 case kTypedDataFloat32x4ArrayCid: { | 1291 case kTypedDataFloat32x4ArrayCid: { |
| 1294 // TODO(zra): Implement when we add simd loads and stores. | 1292 // TODO(zra): Implement when we add simd loads and stores. |
| 1295 UNIMPLEMENTED(); | 1293 UNIMPLEMENTED(); |
| 1296 break; | 1294 break; |
| 1297 } | 1295 } |
| 1298 default: | 1296 default: |
| 1299 UNREACHABLE(); | 1297 UNREACHABLE(); |
| 1300 } | 1298 } |
| 1301 } | 1299 } |
| 1302 | 1300 |
| 1303 | 1301 |
| 1304 static void LoadValueCid(FlowGraphCompiler* compiler, | 1302 static void LoadValueCid(FlowGraphCompiler* compiler, |
| 1305 Register value_cid_reg, | 1303 Register value_cid_reg, |
| 1306 Register value_reg, | 1304 Register value_reg, |
| 1307 Label* value_is_smi = NULL) { | 1305 Label* value_is_smi = NULL) { |
| 1308 Label done; | 1306 Label done; |
| 1309 if (value_is_smi == NULL) { | 1307 if (value_is_smi == NULL) { |
| 1310 __ LoadImmediate(value_cid_reg, kSmiCid, PP); | 1308 __ LoadImmediate(value_cid_reg, kSmiCid, PP); |
| 1311 } | 1309 } |
| 1312 __ tsti(value_reg, kSmiTagMask); | 1310 __ tsti(value_reg, kSmiTagMask); |
| 1313 if (value_is_smi == NULL) { | 1311 if (value_is_smi == NULL) { |
| 1314 __ b(&done, EQ); | 1312 __ b(&done, EQ); |
| 1315 } else { | 1313 } else { |
| 1316 __ b(value_is_smi, EQ); | 1314 __ b(value_is_smi, EQ); |
| 1317 } | 1315 } |
| 1318 __ LoadClassId(value_cid_reg, value_reg); | 1316 __ LoadClassId(value_cid_reg, value_reg, PP); |
| 1319 __ Bind(&done); | 1317 __ Bind(&done); |
| 1320 } | 1318 } |
| 1321 | 1319 |
| 1322 | 1320 |
| 1323 LocationSummary* GuardFieldInstr::MakeLocationSummary(bool opt) const { | 1321 LocationSummary* GuardFieldInstr::MakeLocationSummary(bool opt) const { |
| 1324 const intptr_t kNumInputs = 1; | 1322 const intptr_t kNumInputs = 1; |
| 1325 LocationSummary* summary = | 1323 LocationSummary* summary = |
| 1326 new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall); | 1324 new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall); |
| 1327 summary->set_in(0, Location::RequiresRegister()); | 1325 summary->set_in(0, Location::RequiresRegister()); |
| 1328 const bool field_has_length = field().needs_length_check(); | 1326 const bool field_has_length = field().needs_length_check(); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1396 if (value_cid == kDynamicCid) { | 1394 if (value_cid == kDynamicCid) { |
| 1397 LoadValueCid(compiler, value_cid_reg, value_reg); | 1395 LoadValueCid(compiler, value_cid_reg, value_reg); |
| 1398 Label skip_length_check; | 1396 Label skip_length_check; |
| 1399 __ ldr(TMP, field_cid_operand); | 1397 __ ldr(TMP, field_cid_operand); |
| 1400 __ CompareRegisters(value_cid_reg, TMP); | 1398 __ CompareRegisters(value_cid_reg, TMP); |
| 1401 __ b(&skip_length_check, NE); | 1399 __ b(&skip_length_check, NE); |
| 1402 if (field_has_length) { | 1400 if (field_has_length) { |
| 1403 ASSERT(temp_reg != kNoRegister); | 1401 ASSERT(temp_reg != kNoRegister); |
| 1404 // Field guard may have remembered list length, check it. | 1402 // Field guard may have remembered list length, check it. |
| 1405 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) { | 1403 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) { |
| 1406 __ LoadFieldFromOffset(temp_reg, value_reg, Array::length_offset()); | 1404 __ LoadFieldFromOffset( |
| 1405 temp_reg, value_reg, Array::length_offset(), PP); |
| 1407 __ CompareImmediate(temp_reg, Smi::RawValue(field_length), PP); | 1406 __ CompareImmediate(temp_reg, Smi::RawValue(field_length), PP); |
| 1408 } else if (RawObject::IsTypedDataClassId(field_cid)) { | 1407 } else if (RawObject::IsTypedDataClassId(field_cid)) { |
| 1409 __ LoadFieldFromOffset( | 1408 __ LoadFieldFromOffset( |
| 1410 temp_reg, value_reg, TypedData::length_offset()); | 1409 temp_reg, value_reg, TypedData::length_offset(), PP); |
| 1411 __ CompareImmediate(temp_reg, Smi::RawValue(field_length), PP); | 1410 __ CompareImmediate(temp_reg, Smi::RawValue(field_length), PP); |
| 1412 } else { | 1411 } else { |
| 1413 ASSERT(field_cid == kIllegalCid); | 1412 ASSERT(field_cid == kIllegalCid); |
| 1414 ASSERT(field_length == Field::kUnknownFixedLength); | 1413 ASSERT(field_length == Field::kUnknownFixedLength); |
| 1415 // At compile time we do not know the type of the field nor its | 1414 // At compile time we do not know the type of the field nor its |
| 1416 // length. At execution time we may have set the class id and | 1415 // length. At execution time we may have set the class id and |
| 1417 // list length so we compare the guarded length with the | 1416 // list length so we compare the guarded length with the |
| 1418 // list length here, without this check the list length could change | 1417 // list length here, without this check the list length could change |
| 1419 // without triggering a deoptimization. | 1418 // without triggering a deoptimization. |
| 1420 Label check_array, length_compared, no_fixed_length; | 1419 Label check_array, length_compared, no_fixed_length; |
| 1421 // If length is negative the length guard is either disabled or | 1420 // If length is negative the length guard is either disabled or |
| 1422 // has not been initialized, either way it is safe to skip the | 1421 // has not been initialized, either way it is safe to skip the |
| 1423 // length check. | 1422 // length check. |
| 1424 __ ldr(TMP, field_length_operand); | 1423 __ ldr(TMP, field_length_operand); |
| 1425 __ CompareImmediate(TMP, 0, PP); | 1424 __ CompareImmediate(TMP, 0, PP); |
| 1426 __ b(&skip_length_check, LT); | 1425 __ b(&skip_length_check, LT); |
| 1427 __ CompareImmediate(value_cid_reg, kNullCid, PP); | 1426 __ CompareImmediate(value_cid_reg, kNullCid, PP); |
| 1428 __ b(&no_fixed_length, EQ); | 1427 __ b(&no_fixed_length, EQ); |
| 1429 // Check for typed data array. | 1428 // Check for typed data array. |
| 1430 __ CompareImmediate(value_cid_reg, kTypedDataInt32x4ArrayCid, PP); | 1429 __ CompareImmediate(value_cid_reg, kTypedDataInt32x4ArrayCid, PP); |
| 1431 __ b(&no_fixed_length, GT); | 1430 __ b(&no_fixed_length, GT); |
| 1432 __ CompareImmediate(value_cid_reg, kTypedDataInt8ArrayCid, PP); | 1431 __ CompareImmediate(value_cid_reg, kTypedDataInt8ArrayCid, PP); |
| 1433 // Could still be a regular array. | 1432 // Could still be a regular array. |
| 1434 __ b(&check_array, LT); | 1433 __ b(&check_array, LT); |
| 1435 __ LoadFieldFromOffset( | 1434 __ LoadFieldFromOffset( |
| 1436 temp_reg, value_reg, TypedData::length_offset()); | 1435 temp_reg, value_reg, TypedData::length_offset(), PP); |
| 1437 __ ldr(TMP, field_length_operand); | 1436 __ ldr(TMP, field_length_operand); |
| 1438 __ CompareRegisters(temp_reg, TMP); | 1437 __ CompareRegisters(temp_reg, TMP); |
| 1439 __ b(&length_compared); | 1438 __ b(&length_compared); |
| 1440 // Check for regular array. | 1439 // Check for regular array. |
| 1441 __ Bind(&check_array); | 1440 __ Bind(&check_array); |
| 1442 __ CompareImmediate(value_cid_reg, kImmutableArrayCid, PP); | 1441 __ CompareImmediate(value_cid_reg, kImmutableArrayCid, PP); |
| 1443 __ b(&no_fixed_length, GT); | 1442 __ b(&no_fixed_length, GT); |
| 1444 __ CompareImmediate(value_cid_reg, kArrayCid, PP); | 1443 __ CompareImmediate(value_cid_reg, kArrayCid, PP); |
| 1445 __ b(&no_fixed_length, LT); | 1444 __ b(&no_fixed_length, LT); |
| 1446 __ LoadFieldFromOffset(temp_reg, value_reg, Array::length_offset()); | 1445 __ LoadFieldFromOffset( |
| 1446 temp_reg, value_reg, Array::length_offset(), PP); |
| 1447 __ ldr(TMP, field_length_operand); | 1447 __ ldr(TMP, field_length_operand); |
| 1448 __ CompareRegisters(temp_reg, TMP); | 1448 __ CompareRegisters(temp_reg, TMP); |
| 1449 __ b(&length_compared); | 1449 __ b(&length_compared); |
| 1450 __ Bind(&no_fixed_length); | 1450 __ Bind(&no_fixed_length); |
| 1451 __ b(fail); | 1451 __ b(fail); |
| 1452 __ Bind(&length_compared); | 1452 __ Bind(&length_compared); |
| 1453 // Following branch cannot not occur, fall through. | 1453 // Following branch cannot not occur, fall through. |
| 1454 } | 1454 } |
| 1455 __ b(fail, NE); | 1455 __ b(fail, NE); |
| 1456 } | 1456 } |
| 1457 __ Bind(&skip_length_check); | 1457 __ Bind(&skip_length_check); |
| 1458 __ ldr(TMP, field_nullability_operand); | 1458 __ ldr(TMP, field_nullability_operand); |
| 1459 __ CompareRegisters(value_cid_reg, TMP); | 1459 __ CompareRegisters(value_cid_reg, TMP); |
| 1460 } else if (value_cid == kNullCid) { | 1460 } else if (value_cid == kNullCid) { |
| 1461 __ ldr(value_cid_reg, field_nullability_operand); | 1461 __ ldr(value_cid_reg, field_nullability_operand); |
| 1462 __ CompareImmediate(value_cid_reg, value_cid, PP); | 1462 __ CompareImmediate(value_cid_reg, value_cid, PP); |
| 1463 } else { | 1463 } else { |
| 1464 Label skip_length_check; | 1464 Label skip_length_check; |
| 1465 __ ldr(value_cid_reg, field_cid_operand); | 1465 __ ldr(value_cid_reg, field_cid_operand); |
| 1466 __ CompareImmediate(value_cid_reg, value_cid, PP); | 1466 __ CompareImmediate(value_cid_reg, value_cid, PP); |
| 1467 __ b(&skip_length_check, NE); | 1467 __ b(&skip_length_check, NE); |
| 1468 if (field_has_length) { | 1468 if (field_has_length) { |
| 1469 ASSERT(value_cid_reg != kNoRegister); | 1469 ASSERT(value_cid_reg != kNoRegister); |
| 1470 ASSERT(temp_reg != kNoRegister); | 1470 ASSERT(temp_reg != kNoRegister); |
| 1471 if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) { | 1471 if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) { |
| 1472 __ LoadFieldFromOffset(temp_reg, value_reg, Array::length_offset()); | 1472 __ LoadFieldFromOffset( |
| 1473 temp_reg, value_reg, Array::length_offset(), PP); |
| 1473 __ CompareImmediate(temp_reg, Smi::RawValue(field_length), PP); | 1474 __ CompareImmediate(temp_reg, Smi::RawValue(field_length), PP); |
| 1474 } else if (RawObject::IsTypedDataClassId(value_cid)) { | 1475 } else if (RawObject::IsTypedDataClassId(value_cid)) { |
| 1475 __ LoadFieldFromOffset( | 1476 __ LoadFieldFromOffset( |
| 1476 temp_reg, value_reg, TypedData::length_offset()); | 1477 temp_reg, value_reg, TypedData::length_offset(), PP); |
| 1477 __ CompareImmediate(temp_reg, Smi::RawValue(field_length), PP); | 1478 __ CompareImmediate(temp_reg, Smi::RawValue(field_length), PP); |
| 1478 } else if (field_cid != kIllegalCid) { | 1479 } else if (field_cid != kIllegalCid) { |
| 1479 ASSERT(field_cid != value_cid); | 1480 ASSERT(field_cid != value_cid); |
| 1480 ASSERT(field_length >= 0); | 1481 ASSERT(field_length >= 0); |
| 1481 // Field has a known class id and length. At compile time it is | 1482 // Field has a known class id and length. At compile time it is |
| 1482 // known that the value's class id is not a fixed length list. | 1483 // known that the value's class id is not a fixed length list. |
| 1483 __ b(fail); | 1484 __ b(fail); |
| 1484 } else { | 1485 } else { |
| 1485 ASSERT(field_cid == kIllegalCid); | 1486 ASSERT(field_cid == kIllegalCid); |
| 1486 ASSERT(field_length == Field::kUnknownFixedLength); | 1487 ASSERT(field_length == Field::kUnknownFixedLength); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1505 __ CompareImmediate(value_cid_reg, kNullCid, PP); | 1506 __ CompareImmediate(value_cid_reg, kNullCid, PP); |
| 1506 __ b(&no_fixed_length, EQ); | 1507 __ b(&no_fixed_length, EQ); |
| 1507 // Check for typed data array. | 1508 // Check for typed data array. |
| 1508 __ CompareImmediate(value_cid_reg, kTypedDataInt32x4ArrayCid, PP); | 1509 __ CompareImmediate(value_cid_reg, kTypedDataInt32x4ArrayCid, PP); |
| 1509 __ b(&no_fixed_length, GT); | 1510 __ b(&no_fixed_length, GT); |
| 1510 __ CompareImmediate(value_cid_reg, kTypedDataInt8ArrayCid, PP); | 1511 __ CompareImmediate(value_cid_reg, kTypedDataInt8ArrayCid, PP); |
| 1511 // Could still be a regular array. | 1512 // Could still be a regular array. |
| 1512 __ b(&check_array, LT); | 1513 __ b(&check_array, LT); |
| 1513 // Destroy value_cid_reg (safe because we are finished with it). | 1514 // Destroy value_cid_reg (safe because we are finished with it). |
| 1514 __ LoadFieldFromOffset( | 1515 __ LoadFieldFromOffset( |
| 1515 value_cid_reg, value_reg, TypedData::length_offset()); | 1516 value_cid_reg, value_reg, TypedData::length_offset(), PP); |
| 1516 __ str(value_cid_reg, field_length_operand); | 1517 __ str(value_cid_reg, field_length_operand); |
| 1517 __ b(&length_set); // Updated field length typed data array. | 1518 __ b(&length_set); // Updated field length typed data array. |
| 1518 // Check for regular array. | 1519 // Check for regular array. |
| 1519 __ Bind(&check_array); | 1520 __ Bind(&check_array); |
| 1520 __ CompareImmediate(value_cid_reg, kImmutableArrayCid, PP); | 1521 __ CompareImmediate(value_cid_reg, kImmutableArrayCid, PP); |
| 1521 __ b(&no_fixed_length, GT); | 1522 __ b(&no_fixed_length, GT); |
| 1522 __ CompareImmediate(value_cid_reg, kArrayCid, PP); | 1523 __ CompareImmediate(value_cid_reg, kArrayCid, PP); |
| 1523 __ b(&no_fixed_length, LT); | 1524 __ b(&no_fixed_length, LT); |
| 1524 // Destroy value_cid_reg (safe because we are finished with it). | 1525 // Destroy value_cid_reg (safe because we are finished with it). |
| 1525 __ LoadFieldFromOffset( | 1526 __ LoadFieldFromOffset( |
| 1526 value_cid_reg, value_reg, Array::length_offset()); | 1527 value_cid_reg, value_reg, Array::length_offset(), PP); |
| 1527 __ str(value_cid_reg, field_length_operand); | 1528 __ str(value_cid_reg, field_length_operand); |
| 1528 // Updated field length from regular array. | 1529 // Updated field length from regular array. |
| 1529 __ b(&length_set); | 1530 __ b(&length_set); |
| 1530 __ Bind(&no_fixed_length); | 1531 __ Bind(&no_fixed_length); |
| 1531 __ LoadImmediate(TMP, Smi::RawValue(Field::kNoFixedLength), PP); | 1532 __ LoadImmediate(TMP, Smi::RawValue(Field::kNoFixedLength), PP); |
| 1532 __ str(TMP, field_length_operand); | 1533 __ str(TMP, field_length_operand); |
| 1533 __ Bind(&length_set); | 1534 __ Bind(&length_set); |
| 1534 } | 1535 } |
| 1535 } else { | 1536 } else { |
| 1536 __ LoadImmediate(TMP, value_cid, PP); | 1537 __ LoadImmediate(TMP, value_cid, PP); |
| 1537 __ str(TMP, field_cid_operand); | 1538 __ str(TMP, field_cid_operand); |
| 1538 __ str(TMP, field_nullability_operand); | 1539 __ str(TMP, field_nullability_operand); |
| 1539 if (field_has_length) { | 1540 if (field_has_length) { |
| 1540 if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) { | 1541 if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) { |
| 1541 // Destroy value_cid_reg (safe because we are finished with it). | 1542 // Destroy value_cid_reg (safe because we are finished with it). |
| 1542 __ LoadFieldFromOffset( | 1543 __ LoadFieldFromOffset( |
| 1543 value_cid_reg, value_reg, Array::length_offset()); | 1544 value_cid_reg, value_reg, Array::length_offset(), PP); |
| 1544 __ str(value_cid_reg, field_length_operand); | 1545 __ str(value_cid_reg, field_length_operand); |
| 1545 } else if (RawObject::IsTypedDataClassId(value_cid)) { | 1546 } else if (RawObject::IsTypedDataClassId(value_cid)) { |
| 1546 // Destroy value_cid_reg (safe because we are finished with it). | 1547 // Destroy value_cid_reg (safe because we are finished with it). |
| 1547 __ LoadFieldFromOffset( | 1548 __ LoadFieldFromOffset( |
| 1548 value_cid_reg, value_reg, TypedData::length_offset()); | 1549 value_cid_reg, value_reg, TypedData::length_offset(), PP); |
| 1549 __ str(value_cid_reg, field_length_operand); | 1550 __ str(value_cid_reg, field_length_operand); |
| 1550 } else { | 1551 } else { |
| 1551 __ LoadImmediate(TMP, Smi::RawValue(Field::kNoFixedLength), PP); | 1552 __ LoadImmediate(TMP, Smi::RawValue(Field::kNoFixedLength), PP); |
| 1552 __ str(TMP, field_length_operand); | 1553 __ str(TMP, field_length_operand); |
| 1553 } | 1554 } |
| 1554 } | 1555 } |
| 1555 } | 1556 } |
| 1556 | 1557 |
| 1557 if (deopt == NULL) { | 1558 if (deopt == NULL) { |
| 1558 ASSERT(!compiler->is_optimizing()); | 1559 ASSERT(!compiler->is_optimizing()); |
| 1559 __ b(&ok); | 1560 __ b(&ok); |
| 1560 __ Bind(fail); | 1561 __ Bind(fail); |
| 1561 | 1562 |
| 1562 __ LoadFieldFromOffset(TMP, field_reg, Field::guarded_cid_offset()); | 1563 __ LoadFieldFromOffset(TMP, field_reg, Field::guarded_cid_offset(), PP); |
| 1563 __ CompareImmediate(TMP, kDynamicCid, PP); | 1564 __ CompareImmediate(TMP, kDynamicCid, PP); |
| 1564 __ b(&ok, EQ); | 1565 __ b(&ok, EQ); |
| 1565 | 1566 |
| 1566 __ Push(field_reg); | 1567 __ Push(field_reg); |
| 1567 __ Push(value_reg); | 1568 __ Push(value_reg); |
| 1568 __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2); | 1569 __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2); |
| 1569 __ Drop(2); // Drop the field and the value. | 1570 __ Drop(2); // Drop the field and the value. |
| 1570 } | 1571 } |
| 1571 } else { | 1572 } else { |
| 1572 ASSERT(compiler->is_optimizing()); | 1573 ASSERT(compiler->is_optimizing()); |
| 1573 ASSERT(deopt != NULL); | 1574 ASSERT(deopt != NULL); |
| 1574 // Field guard class has been initialized and is known. | 1575 // Field guard class has been initialized and is known. |
| 1575 if (field_reg != kNoRegister) { | 1576 if (field_reg != kNoRegister) { |
| 1576 __ LoadObject(field_reg, Field::ZoneHandle(field().raw()), PP); | 1577 __ LoadObject(field_reg, Field::ZoneHandle(field().raw()), PP); |
| 1577 } | 1578 } |
| 1578 if (value_cid == kDynamicCid) { | 1579 if (value_cid == kDynamicCid) { |
| 1579 // Field's guarded class id is fixed by value's class id is not known. | 1580 // Field's guarded class id is fixed by value's class id is not known. |
| 1580 __ tsti(value_reg, kSmiTagMask); | 1581 __ tsti(value_reg, kSmiTagMask); |
| 1581 | 1582 |
| 1582 if (field_cid != kSmiCid) { | 1583 if (field_cid != kSmiCid) { |
| 1583 __ b(fail, EQ); | 1584 __ b(fail, EQ); |
| 1584 __ LoadClassId(value_cid_reg, value_reg); | 1585 __ LoadClassId(value_cid_reg, value_reg, PP); |
| 1585 __ CompareImmediate(value_cid_reg, field_cid, PP); | 1586 __ CompareImmediate(value_cid_reg, field_cid, PP); |
| 1586 } | 1587 } |
| 1587 | 1588 |
| 1588 if (field_has_length) { | 1589 if (field_has_length) { |
| 1589 __ b(fail, NE); | 1590 __ b(fail, NE); |
| 1590 // Classes are same, perform guarded list length check. | 1591 // Classes are same, perform guarded list length check. |
| 1591 ASSERT(field_reg != kNoRegister); | 1592 ASSERT(field_reg != kNoRegister); |
| 1592 ASSERT(value_cid_reg != kNoRegister); | 1593 ASSERT(value_cid_reg != kNoRegister); |
| 1593 FieldAddress field_length_operand( | 1594 FieldAddress field_length_operand( |
| 1594 field_reg, Field::guarded_list_length_offset()); | 1595 field_reg, Field::guarded_list_length_offset()); |
| 1595 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) { | 1596 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) { |
| 1596 // Destroy value_cid_reg (safe because we are finished with it). | 1597 // Destroy value_cid_reg (safe because we are finished with it). |
| 1597 __ LoadFieldFromOffset( | 1598 __ LoadFieldFromOffset( |
| 1598 value_cid_reg, value_reg, Array::length_offset()); | 1599 value_cid_reg, value_reg, Array::length_offset(), PP); |
| 1599 } else if (RawObject::IsTypedDataClassId(field_cid)) { | 1600 } else if (RawObject::IsTypedDataClassId(field_cid)) { |
| 1600 // Destroy value_cid_reg (safe because we are finished with it). | 1601 // Destroy value_cid_reg (safe because we are finished with it). |
| 1601 __ LoadFieldFromOffset( | 1602 __ LoadFieldFromOffset( |
| 1602 value_cid_reg, value_reg, TypedData::length_offset()); | 1603 value_cid_reg, value_reg, TypedData::length_offset(), PP); |
| 1603 } | 1604 } |
| 1604 __ ldr(TMP, field_length_operand); | 1605 __ ldr(TMP, field_length_operand); |
| 1605 __ CompareRegisters(value_cid_reg, TMP); | 1606 __ CompareRegisters(value_cid_reg, TMP); |
| 1606 } | 1607 } |
| 1607 | 1608 |
| 1608 if (field().is_nullable() && (field_cid != kNullCid)) { | 1609 if (field().is_nullable() && (field_cid != kNullCid)) { |
| 1609 __ b(&ok, EQ); | 1610 __ b(&ok, EQ); |
| 1610 __ CompareObject(value_reg, Object::null_object(), PP); | 1611 __ CompareObject(value_reg, Object::null_object(), PP); |
| 1611 } | 1612 } |
| 1612 __ b(fail, NE); | 1613 __ b(fail, NE); |
| 1613 } else { | 1614 } else { |
| 1614 // Both value's and field's class id is known. | 1615 // Both value's and field's class id is known. |
| 1615 if ((value_cid != field_cid) && (value_cid != nullability)) { | 1616 if ((value_cid != field_cid) && (value_cid != nullability)) { |
| 1616 __ b(fail); | 1617 __ b(fail); |
| 1617 } else if (field_has_length && (value_cid == field_cid)) { | 1618 } else if (field_has_length && (value_cid == field_cid)) { |
| 1618 ASSERT(value_cid_reg != kNoRegister); | 1619 ASSERT(value_cid_reg != kNoRegister); |
| 1619 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) { | 1620 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) { |
| 1620 // Destroy value_cid_reg (safe because we are finished with it). | 1621 // Destroy value_cid_reg (safe because we are finished with it). |
| 1621 __ LoadFieldFromOffset( | 1622 __ LoadFieldFromOffset( |
| 1622 value_cid_reg, value_reg, Array::length_offset()); | 1623 value_cid_reg, value_reg, Array::length_offset(), PP); |
| 1623 } else if (RawObject::IsTypedDataClassId(field_cid)) { | 1624 } else if (RawObject::IsTypedDataClassId(field_cid)) { |
| 1624 // Destroy value_cid_reg (safe because we are finished with it). | 1625 // Destroy value_cid_reg (safe because we are finished with it). |
| 1625 __ LoadFieldFromOffset( | 1626 __ LoadFieldFromOffset( |
| 1626 value_cid_reg, value_reg, TypedData::length_offset()); | 1627 value_cid_reg, value_reg, TypedData::length_offset(), PP); |
| 1627 } | 1628 } |
| 1628 __ CompareImmediate(value_cid_reg, field_length, PP); | 1629 __ CompareImmediate(value_cid_reg, field_length, PP); |
| 1629 __ b(fail, NE); | 1630 __ b(fail, NE); |
| 1630 } else { | 1631 } else { |
| 1631 UNREACHABLE(); | 1632 UNREACHABLE(); |
| 1632 } | 1633 } |
| 1633 } | 1634 } |
| 1634 } | 1635 } |
| 1635 __ Bind(&ok); | 1636 __ Bind(&ok); |
| 1636 } | 1637 } |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1712 const Register temp = locs()->temp(0).reg(); | 1713 const Register temp = locs()->temp(0).reg(); |
| 1713 const Register temp2 = locs()->temp(1).reg(); | 1714 const Register temp2 = locs()->temp(1).reg(); |
| 1714 const intptr_t cid = field().UnboxedFieldCid(); | 1715 const intptr_t cid = field().UnboxedFieldCid(); |
| 1715 | 1716 |
| 1716 if (is_initialization_) { | 1717 if (is_initialization_) { |
| 1717 const Class* cls = NULL; | 1718 const Class* cls = NULL; |
| 1718 switch (cid) { | 1719 switch (cid) { |
| 1719 case kDoubleCid: | 1720 case kDoubleCid: |
| 1720 cls = &compiler->double_class(); | 1721 cls = &compiler->double_class(); |
| 1721 break; | 1722 break; |
| 1722 // TODO(zra): Implement these when we add fpu loads and stores. | |
| 1723 case kFloat32x4Cid: | 1723 case kFloat32x4Cid: |
| 1724 cls = &compiler->float32x4_class(); |
| 1725 break; |
| 1724 case kFloat64x2Cid: | 1726 case kFloat64x2Cid: |
| 1725 UNIMPLEMENTED(); | 1727 cls = &compiler->float64x2_class(); |
| 1726 break; | 1728 break; |
| 1727 default: | 1729 default: |
| 1728 UNREACHABLE(); | 1730 UNREACHABLE(); |
| 1729 } | 1731 } |
| 1730 | 1732 |
| 1731 StoreInstanceFieldSlowPath* slow_path = | 1733 StoreInstanceFieldSlowPath* slow_path = |
| 1732 new StoreInstanceFieldSlowPath(this, *cls); | 1734 new StoreInstanceFieldSlowPath(this, *cls); |
| 1733 compiler->AddSlowPathCode(slow_path); | 1735 compiler->AddSlowPathCode(slow_path); |
| 1734 | 1736 |
| 1735 __ TryAllocate(*cls, | 1737 __ TryAllocate(*cls, |
| 1736 slow_path->entry_label(), | 1738 slow_path->entry_label(), |
| 1737 temp, | 1739 temp, |
| 1738 temp2, | 1740 temp2, |
| 1739 PP); | 1741 PP); |
| 1740 __ Bind(slow_path->exit_label()); | 1742 __ Bind(slow_path->exit_label()); |
| 1741 __ mov(temp2, temp); | 1743 __ mov(temp2, temp); |
| 1742 __ StoreIntoObject(instance_reg, | 1744 __ StoreIntoObjectOffset(instance_reg, offset_in_bytes_, temp2, PP); |
| 1743 FieldAddress(instance_reg, offset_in_bytes_), | |
| 1744 temp2); | |
| 1745 } else { | 1745 } else { |
| 1746 __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes_); | 1746 __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes_, PP); |
| 1747 } | 1747 } |
| 1748 switch (cid) { | 1748 switch (cid) { |
| 1749 case kDoubleCid: | 1749 case kDoubleCid: |
| 1750 __ Comment("UnboxedDoubleStoreInstanceFieldInstr"); | 1750 __ Comment("UnboxedDoubleStoreInstanceFieldInstr"); |
| 1751 __ StoreDFieldToOffset(value, temp, Double::value_offset()); | 1751 __ StoreDFieldToOffset(value, temp, Double::value_offset(), PP); |
| 1752 break; | 1752 break; |
| 1753 case kFloat32x4Cid: | 1753 case kFloat32x4Cid: |
| 1754 __ Comment("UnboxedFloat32x4StoreInstanceFieldInstr"); |
| 1755 __ StoreQFieldToOffset(value, temp, Float32x4::value_offset(), PP); |
| 1756 break; |
| 1754 case kFloat64x2Cid: | 1757 case kFloat64x2Cid: |
| 1755 UNIMPLEMENTED(); | 1758 __ Comment("UnboxedFloat64x2StoreInstanceFieldInstr"); |
| 1759 __ StoreQFieldToOffset(value, temp, Float64x2::value_offset(), PP); |
| 1756 break; | 1760 break; |
| 1757 default: | 1761 default: |
| 1758 UNREACHABLE(); | 1762 UNREACHABLE(); |
| 1759 } | 1763 } |
| 1760 | 1764 |
| 1761 return; | 1765 return; |
| 1762 } | 1766 } |
| 1763 | 1767 |
| 1764 if (IsPotentialUnboxedStore()) { | 1768 if (IsPotentialUnboxedStore()) { |
| 1765 const Register value_reg = locs()->in(1).reg(); | 1769 const Register value_reg = locs()->in(1).reg(); |
| 1766 const Register temp = locs()->temp(0).reg(); | 1770 const Register temp = locs()->temp(0).reg(); |
| 1767 const Register temp2 = locs()->temp(1).reg(); | 1771 const Register temp2 = locs()->temp(1).reg(); |
| 1768 const VRegister fpu_temp = locs()->temp(2).fpu_reg(); | 1772 const VRegister fpu_temp = locs()->temp(2).fpu_reg(); |
| 1769 | 1773 |
| 1770 Label store_pointer; | 1774 Label store_pointer; |
| 1771 Label store_double; | 1775 Label store_double; |
| 1772 Label store_float32x4; | 1776 Label store_float32x4; |
| 1773 Label store_float64x2; | 1777 Label store_float64x2; |
| 1774 | 1778 |
| 1775 __ LoadObject(temp, Field::ZoneHandle(field().raw()), PP); | 1779 __ LoadObject(temp, Field::ZoneHandle(field().raw()), PP); |
| 1776 | 1780 |
| 1777 __ LoadFieldFromOffset(temp2, temp, Field::is_nullable_offset()); | 1781 __ LoadFieldFromOffset(temp2, temp, Field::is_nullable_offset(), PP); |
| 1778 __ CompareImmediate(temp2, kNullCid, PP); | 1782 __ CompareImmediate(temp2, kNullCid, PP); |
| 1779 __ b(&store_pointer, EQ); | 1783 __ b(&store_pointer, EQ); |
| 1780 | 1784 |
| 1781 __ LoadFromOffset( | 1785 __ LoadFromOffset( |
| 1782 temp2, temp, Field::kind_bits_offset() - kHeapObjectTag, kUnsignedByte); | 1786 temp2, temp, Field::kind_bits_offset() - kHeapObjectTag, |
| 1787 PP, kUnsignedByte); |
| 1783 __ tsti(temp2, 1 << Field::kUnboxingCandidateBit); | 1788 __ tsti(temp2, 1 << Field::kUnboxingCandidateBit); |
| 1784 __ b(&store_pointer, EQ); | 1789 __ b(&store_pointer, EQ); |
| 1785 | 1790 |
| 1786 __ LoadFieldFromOffset(temp2, temp, Field::guarded_cid_offset()); | 1791 __ LoadFieldFromOffset(temp2, temp, Field::guarded_cid_offset(), PP); |
| 1787 __ CompareImmediate(temp2, kDoubleCid, PP); | 1792 __ CompareImmediate(temp2, kDoubleCid, PP); |
| 1788 __ b(&store_double, EQ); | 1793 __ b(&store_double, EQ); |
| 1789 | 1794 |
| 1790 __ LoadFieldFromOffset(temp2, temp, Field::guarded_cid_offset()); | 1795 __ LoadFieldFromOffset(temp2, temp, Field::guarded_cid_offset(), PP); |
| 1791 __ CompareImmediate(temp2, kFloat32x4Cid, PP); | 1796 __ CompareImmediate(temp2, kFloat32x4Cid, PP); |
| 1792 __ b(&store_float32x4, EQ); | 1797 __ b(&store_float32x4, EQ); |
| 1793 | 1798 |
| 1794 __ LoadFieldFromOffset(temp2, temp, Field::guarded_cid_offset()); | 1799 __ LoadFieldFromOffset(temp2, temp, Field::guarded_cid_offset(), PP); |
| 1795 __ CompareImmediate(temp2, kFloat64x2Cid, PP); | 1800 __ CompareImmediate(temp2, kFloat64x2Cid, PP); |
| 1796 __ b(&store_float64x2, EQ); | 1801 __ b(&store_float64x2, EQ); |
| 1797 | 1802 |
| 1798 // Fall through. | 1803 // Fall through. |
| 1799 __ b(&store_pointer); | 1804 __ b(&store_pointer); |
| 1800 | 1805 |
| 1801 if (!compiler->is_optimizing()) { | 1806 if (!compiler->is_optimizing()) { |
| 1802 locs()->live_registers()->Add(locs()->in(0)); | 1807 locs()->live_registers()->Add(locs()->in(0)); |
| 1803 locs()->live_registers()->Add(locs()->in(1)); | 1808 locs()->live_registers()->Add(locs()->in(1)); |
| 1804 } | 1809 } |
| 1805 | 1810 |
| 1806 { | 1811 { |
| 1807 __ Bind(&store_double); | 1812 __ Bind(&store_double); |
| 1808 Label copy_double; | 1813 Label copy_double; |
| 1809 StoreInstanceFieldSlowPath* slow_path = | 1814 StoreInstanceFieldSlowPath* slow_path = |
| 1810 new StoreInstanceFieldSlowPath(this, compiler->double_class()); | 1815 new StoreInstanceFieldSlowPath(this, compiler->double_class()); |
| 1811 compiler->AddSlowPathCode(slow_path); | 1816 compiler->AddSlowPathCode(slow_path); |
| 1812 | 1817 |
| 1813 __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes_); | 1818 __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes_, PP); |
| 1814 __ CompareObject(temp, Object::null_object(), PP); | 1819 __ CompareObject(temp, Object::null_object(), PP); |
| 1815 __ b(©_double, NE); | 1820 __ b(©_double, NE); |
| 1816 | 1821 |
| 1817 __ TryAllocate(compiler->double_class(), | 1822 __ TryAllocate(compiler->double_class(), |
| 1818 slow_path->entry_label(), | 1823 slow_path->entry_label(), |
| 1819 temp, | 1824 temp, |
| 1820 temp2, | 1825 temp2, |
| 1821 PP); | 1826 PP); |
| 1822 __ Bind(slow_path->exit_label()); | 1827 __ Bind(slow_path->exit_label()); |
| 1823 __ mov(temp2, temp); | 1828 __ mov(temp2, temp); |
| 1824 __ StoreIntoObject(instance_reg, | 1829 __ StoreIntoObjectOffset(instance_reg, offset_in_bytes_, temp2, PP); |
| 1825 FieldAddress(instance_reg, offset_in_bytes_), | |
| 1826 temp2); | |
| 1827 __ Bind(©_double); | 1830 __ Bind(©_double); |
| 1828 __ LoadDFieldFromOffset(fpu_temp, value_reg, Double::value_offset()); | 1831 __ LoadDFieldFromOffset(fpu_temp, value_reg, Double::value_offset(), PP); |
| 1829 __ StoreDFieldToOffset(fpu_temp, temp, Double::value_offset()); | 1832 __ StoreDFieldToOffset(fpu_temp, temp, Double::value_offset(), PP); |
| 1830 __ b(&skip_store); | 1833 __ b(&skip_store); |
| 1831 } | 1834 } |
| 1832 | 1835 |
| 1833 // TODO(zra): Implement these when we add simd loads and stores. | |
| 1834 { | 1836 { |
| 1835 __ Bind(&store_float32x4); | 1837 __ Bind(&store_float32x4); |
| 1836 __ Stop("Float32x4 Unimplemented"); | 1838 Label copy_float32x4; |
| 1839 StoreInstanceFieldSlowPath* slow_path = |
| 1840 new StoreInstanceFieldSlowPath(this, compiler->float32x4_class()); |
| 1841 compiler->AddSlowPathCode(slow_path); |
| 1842 |
| 1843 __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes_, PP); |
| 1844 __ CompareObject(temp, Object::null_object(), PP); |
| 1845 __ b(©_float32x4, NE); |
| 1846 |
| 1847 __ TryAllocate(compiler->float32x4_class(), |
| 1848 slow_path->entry_label(), |
| 1849 temp, |
| 1850 temp2, |
| 1851 PP); |
| 1852 __ Bind(slow_path->exit_label()); |
| 1853 __ mov(temp2, temp); |
| 1854 __ StoreIntoObjectOffset(instance_reg, offset_in_bytes_, temp2, PP); |
| 1855 __ Bind(©_float32x4); |
| 1856 __ LoadQFieldFromOffset( |
| 1857 fpu_temp, value_reg, Float32x4::value_offset(), PP); |
| 1858 __ StoreQFieldToOffset( |
| 1859 fpu_temp, value_reg, Float32x4::value_offset(), PP); |
| 1860 __ b(&skip_store); |
| 1837 } | 1861 } |
| 1838 | 1862 |
| 1839 { | 1863 { |
| 1840 __ Bind(&store_float64x2); | 1864 __ Bind(&store_float64x2); |
| 1841 __ Stop("Float64x2 Unimplemented"); | 1865 Label copy_float64x2; |
| 1866 StoreInstanceFieldSlowPath* slow_path = |
| 1867 new StoreInstanceFieldSlowPath(this, compiler->float64x2_class()); |
| 1868 compiler->AddSlowPathCode(slow_path); |
| 1869 |
| 1870 __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes_, PP); |
| 1871 __ CompareObject(temp, Object::null_object(), PP); |
| 1872 __ b(©_float64x2, NE); |
| 1873 |
| 1874 __ TryAllocate(compiler->float64x2_class(), |
| 1875 slow_path->entry_label(), |
| 1876 temp, |
| 1877 temp2, |
| 1878 PP); |
| 1879 __ Bind(slow_path->exit_label()); |
| 1880 __ mov(temp2, temp); |
| 1881 __ StoreIntoObjectOffset(instance_reg, offset_in_bytes_, temp2, PP); |
| 1882 __ Bind(©_float64x2); |
| 1883 __ LoadQFieldFromOffset( |
| 1884 fpu_temp, value_reg, Float64x2::value_offset(), PP); |
| 1885 __ StoreQFieldToOffset( |
| 1886 fpu_temp, value_reg, Float64x2::value_offset(), PP); |
| 1887 __ b(&skip_store); |
| 1842 } | 1888 } |
| 1843 | 1889 |
| 1844 __ Bind(&store_pointer); | 1890 __ Bind(&store_pointer); |
| 1845 } | 1891 } |
| 1846 | 1892 |
| 1847 if (ShouldEmitStoreBarrier()) { | 1893 if (ShouldEmitStoreBarrier()) { |
| 1848 Register value_reg = locs()->in(1).reg(); | 1894 const Register value_reg = locs()->in(1).reg(); |
| 1849 __ StoreIntoObject(instance_reg, | 1895 __ StoreIntoObjectOffset( |
| 1850 FieldAddress(instance_reg, offset_in_bytes_), | 1896 instance_reg, offset_in_bytes_, value_reg, PP, CanValueBeSmi()); |
| 1851 value_reg, | |
| 1852 CanValueBeSmi()); | |
| 1853 } else { | 1897 } else { |
| 1854 if (locs()->in(1).IsConstant()) { | 1898 if (locs()->in(1).IsConstant()) { |
| 1855 __ StoreIntoObjectNoBarrier( | 1899 __ StoreIntoObjectOffsetNoBarrier( |
| 1856 instance_reg, | 1900 instance_reg, |
| 1857 FieldAddress(instance_reg, offset_in_bytes_), | 1901 offset_in_bytes_, |
| 1858 locs()->in(1).constant()); | 1902 locs()->in(1).constant(), |
| 1903 PP); |
| 1859 } else { | 1904 } else { |
| 1860 Register value_reg = locs()->in(1).reg(); | 1905 const Register value_reg = locs()->in(1).reg(); |
| 1861 __ StoreIntoObjectNoBarrier(instance_reg, | 1906 __ StoreIntoObjectOffsetNoBarrier( |
| 1862 FieldAddress(instance_reg, offset_in_bytes_), value_reg); | 1907 instance_reg, |
| 1908 offset_in_bytes_, |
| 1909 value_reg, |
| 1910 PP); |
| 1863 } | 1911 } |
| 1864 } | 1912 } |
| 1865 __ Bind(&skip_store); | 1913 __ Bind(&skip_store); |
| 1866 } | 1914 } |
| 1867 | 1915 |
| 1868 | 1916 |
| 1869 LocationSummary* LoadStaticFieldInstr::MakeLocationSummary(bool opt) const { | 1917 LocationSummary* LoadStaticFieldInstr::MakeLocationSummary(bool opt) const { |
| 1870 const intptr_t kNumInputs = 1; | 1918 const intptr_t kNumInputs = 1; |
| 1871 const intptr_t kNumTemps = 0; | 1919 const intptr_t kNumTemps = 0; |
| 1872 LocationSummary* summary = | 1920 LocationSummary* summary = |
| 1873 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 1921 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 1874 summary->set_in(0, Location::RequiresRegister()); | 1922 summary->set_in(0, Location::RequiresRegister()); |
| 1875 summary->set_out(0, Location::RequiresRegister()); | 1923 summary->set_out(0, Location::RequiresRegister()); |
| 1876 return summary; | 1924 return summary; |
| 1877 } | 1925 } |
| 1878 | 1926 |
| 1879 | 1927 |
| 1880 // When the parser is building an implicit static getter for optimization, | 1928 // When the parser is building an implicit static getter for optimization, |
| 1881 // it can generate a function body where deoptimization ids do not line up | 1929 // it can generate a function body where deoptimization ids do not line up |
| 1882 // with the unoptimized code. | 1930 // with the unoptimized code. |
| 1883 // | 1931 // |
| 1884 // This is safe only so long as LoadStaticFieldInstr cannot deoptimize. | 1932 // This is safe only so long as LoadStaticFieldInstr cannot deoptimize. |
| 1885 void LoadStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 1933 void LoadStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1886 Register field = locs()->in(0).reg(); | 1934 Register field = locs()->in(0).reg(); |
| 1887 Register result = locs()->out(0).reg(); | 1935 Register result = locs()->out(0).reg(); |
| 1888 __ LoadFieldFromOffset(result, field, Field::value_offset()); | 1936 __ LoadFieldFromOffset(result, field, Field::value_offset(), PP); |
| 1889 } | 1937 } |
| 1890 | 1938 |
| 1891 | 1939 |
| 1892 LocationSummary* StoreStaticFieldInstr::MakeLocationSummary(bool opt) const { | 1940 LocationSummary* StoreStaticFieldInstr::MakeLocationSummary(bool opt) const { |
| 1893 LocationSummary* locs = new LocationSummary(1, 1, LocationSummary::kNoCall); | 1941 LocationSummary* locs = new LocationSummary(1, 1, LocationSummary::kNoCall); |
| 1894 locs->set_in(0, value()->NeedsStoreBuffer() ? Location::WritableRegister() | 1942 locs->set_in(0, value()->NeedsStoreBuffer() ? Location::WritableRegister() |
| 1895 : Location::RequiresRegister()); | 1943 : Location::RequiresRegister()); |
| 1896 locs->set_temp(0, Location::RequiresRegister()); | 1944 locs->set_temp(0, Location::RequiresRegister()); |
| 1897 return locs; | 1945 return locs; |
| 1898 } | 1946 } |
| 1899 | 1947 |
| 1900 | 1948 |
| 1901 void StoreStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 1949 void StoreStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1902 Register value = locs()->in(0).reg(); | 1950 Register value = locs()->in(0).reg(); |
| 1903 Register temp = locs()->temp(0).reg(); | 1951 Register temp = locs()->temp(0).reg(); |
| 1904 | 1952 |
| 1905 __ LoadObject(temp, field(), PP); | 1953 __ LoadObject(temp, field(), PP); |
| 1906 if (this->value()->NeedsStoreBuffer()) { | 1954 if (this->value()->NeedsStoreBuffer()) { |
| 1907 __ StoreIntoObject(temp, | 1955 __ StoreIntoObjectOffset( |
| 1908 FieldAddress(temp, Field::value_offset()), value, CanValueBeSmi()); | 1956 temp, Field::value_offset(), value, PP, CanValueBeSmi()); |
| 1909 } else { | 1957 } else { |
| 1910 __ StoreIntoObjectNoBarrier( | 1958 __ StoreIntoObjectOffsetNoBarrier(temp, Field::value_offset(), value, PP); |
| 1911 temp, FieldAddress(temp, Field::value_offset()), value); | |
| 1912 } | 1959 } |
| 1913 } | 1960 } |
| 1914 | 1961 |
| 1915 | 1962 |
| 1916 LocationSummary* InstanceOfInstr::MakeLocationSummary(bool opt) const { | 1963 LocationSummary* InstanceOfInstr::MakeLocationSummary(bool opt) const { |
| 1917 const intptr_t kNumInputs = 3; | 1964 const intptr_t kNumInputs = 3; |
| 1918 const intptr_t kNumTemps = 0; | 1965 const intptr_t kNumTemps = 0; |
| 1919 LocationSummary* summary = | 1966 LocationSummary* summary = |
| 1920 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); | 1967 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); |
| 1921 summary->set_in(0, Location::RegisterLocation(R0)); | 1968 summary->set_in(0, Location::RegisterLocation(R0)); |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2018 locs->set_out(0, Location::RequiresRegister()); | 2065 locs->set_out(0, Location::RequiresRegister()); |
| 2019 return locs; | 2066 return locs; |
| 2020 } | 2067 } |
| 2021 | 2068 |
| 2022 | 2069 |
| 2023 void LoadFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2070 void LoadFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2024 Register instance_reg = locs()->in(0).reg(); | 2071 Register instance_reg = locs()->in(0).reg(); |
| 2025 if (IsUnboxedLoad() && compiler->is_optimizing()) { | 2072 if (IsUnboxedLoad() && compiler->is_optimizing()) { |
| 2026 const VRegister result = locs()->out(0).fpu_reg(); | 2073 const VRegister result = locs()->out(0).fpu_reg(); |
| 2027 const Register temp = locs()->temp(0).reg(); | 2074 const Register temp = locs()->temp(0).reg(); |
| 2028 __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes()); | 2075 __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes(), PP); |
| 2029 const intptr_t cid = field()->UnboxedFieldCid(); | 2076 const intptr_t cid = field()->UnboxedFieldCid(); |
| 2030 switch (cid) { | 2077 switch (cid) { |
| 2031 case kDoubleCid: | 2078 case kDoubleCid: |
| 2032 __ Comment("UnboxedDoubleLoadFieldInstr"); | 2079 __ Comment("UnboxedDoubleLoadFieldInstr"); |
| 2033 __ LoadDFieldFromOffset(result, temp, Double::value_offset()); | 2080 __ LoadDFieldFromOffset(result, temp, Double::value_offset(), PP); |
| 2034 break; | 2081 break; |
| 2035 case kFloat32x4Cid: | 2082 case kFloat32x4Cid: |
| 2036 case kFloat64x2Cid: | 2083 case kFloat64x2Cid: |
| 2037 UNIMPLEMENTED(); | 2084 UNIMPLEMENTED(); |
| 2038 break; | 2085 break; |
| 2039 default: | 2086 default: |
| 2040 UNREACHABLE(); | 2087 UNREACHABLE(); |
| 2041 } | 2088 } |
| 2042 return; | 2089 return; |
| 2043 } | 2090 } |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2086 __ Bind(&load_double); | 2133 __ Bind(&load_double); |
| 2087 BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this); | 2134 BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this); |
| 2088 compiler->AddSlowPathCode(slow_path); | 2135 compiler->AddSlowPathCode(slow_path); |
| 2089 | 2136 |
| 2090 __ TryAllocate(compiler->double_class(), | 2137 __ TryAllocate(compiler->double_class(), |
| 2091 slow_path->entry_label(), | 2138 slow_path->entry_label(), |
| 2092 result_reg, | 2139 result_reg, |
| 2093 temp, | 2140 temp, |
| 2094 PP); | 2141 PP); |
| 2095 __ Bind(slow_path->exit_label()); | 2142 __ Bind(slow_path->exit_label()); |
| 2096 __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes()); | 2143 __ LoadFieldFromOffset(temp, instance_reg, offset_in_bytes(), PP); |
| 2097 __ LoadDFieldFromOffset(value, temp, Double::value_offset()); | 2144 __ LoadDFieldFromOffset(value, temp, Double::value_offset(), PP); |
| 2098 __ StoreDFieldToOffset(value, result_reg, Double::value_offset()); | 2145 __ StoreDFieldToOffset(value, result_reg, Double::value_offset(), PP); |
| 2099 __ b(&done); | 2146 __ b(&done); |
| 2100 } | 2147 } |
| 2101 | 2148 |
| 2102 // TODO(zra): Implement these when we add simd loads and stores. | 2149 // TODO(zra): Implement these when we add simd loads and stores. |
| 2103 { | 2150 { |
| 2104 __ Bind(&load_float32x4); | 2151 __ Bind(&load_float32x4); |
| 2105 __ Stop("Float32x4 Unimplemented"); | 2152 __ Stop("Float32x4 Unimplemented"); |
| 2106 } | 2153 } |
| 2107 | 2154 |
| 2108 { | 2155 { |
| 2109 __ Bind(&load_float64x2); | 2156 __ Bind(&load_float64x2); |
| 2110 __ Stop("Float64x2 Unimplemented"); | 2157 __ Stop("Float64x2 Unimplemented"); |
| 2111 } | 2158 } |
| 2112 | 2159 |
| 2113 __ Bind(&load_pointer); | 2160 __ Bind(&load_pointer); |
| 2114 } | 2161 } |
| 2115 __ LoadFieldFromOffset(result_reg, instance_reg, offset_in_bytes()); | 2162 __ LoadFieldFromOffset(result_reg, instance_reg, offset_in_bytes(), PP); |
| 2116 __ Bind(&done); | 2163 __ Bind(&done); |
| 2117 } | 2164 } |
| 2118 | 2165 |
| 2119 | 2166 |
| 2120 LocationSummary* InstantiateTypeInstr::MakeLocationSummary(bool opt) const { | 2167 LocationSummary* InstantiateTypeInstr::MakeLocationSummary(bool opt) const { |
| 2121 const intptr_t kNumInputs = 1; | 2168 const intptr_t kNumInputs = 1; |
| 2122 const intptr_t kNumTemps = 0; | 2169 const intptr_t kNumTemps = 0; |
| 2123 LocationSummary* locs = | 2170 LocationSummary* locs = |
| 2124 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); | 2171 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); |
| 2125 locs->set_in(0, Location::RegisterLocation(R0)); | 2172 locs->set_in(0, Location::RegisterLocation(R0)); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2175 // instantiated from null becomes a vector of dynamic, then use null as | 2222 // instantiated from null becomes a vector of dynamic, then use null as |
| 2176 // the type arguments. | 2223 // the type arguments. |
| 2177 Label type_arguments_instantiated; | 2224 Label type_arguments_instantiated; |
| 2178 const intptr_t len = type_arguments().Length(); | 2225 const intptr_t len = type_arguments().Length(); |
| 2179 if (type_arguments().IsRawInstantiatedRaw(len)) { | 2226 if (type_arguments().IsRawInstantiatedRaw(len)) { |
| 2180 __ CompareObject(instantiator_reg, Object::null_object(), PP); | 2227 __ CompareObject(instantiator_reg, Object::null_object(), PP); |
| 2181 __ b(&type_arguments_instantiated, EQ); | 2228 __ b(&type_arguments_instantiated, EQ); |
| 2182 } | 2229 } |
| 2183 | 2230 |
| 2184 __ LoadObject(R2, type_arguments(), PP); | 2231 __ LoadObject(R2, type_arguments(), PP); |
| 2185 __ LoadFieldFromOffset(R2, R2, TypeArguments::instantiations_offset()); | 2232 __ LoadFieldFromOffset(R2, R2, TypeArguments::instantiations_offset(), PP); |
| 2186 __ AddImmediate(R2, R2, Array::data_offset() - kHeapObjectTag, PP); | 2233 __ AddImmediate(R2, R2, Array::data_offset() - kHeapObjectTag, PP); |
| 2187 // The instantiations cache is initialized with Object::zero_array() and is | 2234 // The instantiations cache is initialized with Object::zero_array() and is |
| 2188 // therefore guaranteed to contain kNoInstantiator. No length check needed. | 2235 // therefore guaranteed to contain kNoInstantiator. No length check needed. |
| 2189 Label loop, found, slow_case; | 2236 Label loop, found, slow_case; |
| 2190 __ Bind(&loop); | 2237 __ Bind(&loop); |
| 2191 __ LoadFromOffset(R1, R2, 0 * kWordSize); // Cached instantiator. | 2238 __ LoadFromOffset(R1, R2, 0 * kWordSize, PP); // Cached instantiator. |
| 2192 __ CompareRegisters(R1, R0); | 2239 __ CompareRegisters(R1, R0); |
| 2193 __ b(&found, EQ); | 2240 __ b(&found, EQ); |
| 2194 __ AddImmediate(R2, R2, 2 * kWordSize, PP); | 2241 __ AddImmediate(R2, R2, 2 * kWordSize, PP); |
| 2195 __ CompareImmediate(R1, Smi::RawValue(StubCode::kNoInstantiator), PP); | 2242 __ CompareImmediate(R1, Smi::RawValue(StubCode::kNoInstantiator), PP); |
| 2196 __ b(&loop, NE); | 2243 __ b(&loop, NE); |
| 2197 __ b(&slow_case); | 2244 __ b(&slow_case); |
| 2198 __ Bind(&found); | 2245 __ Bind(&found); |
| 2199 __ LoadFromOffset(R0, R2, 1 * kWordSize); // Cached instantiated args. | 2246 __ LoadFromOffset(R0, R2, 1 * kWordSize, PP); // Cached instantiated args. |
| 2200 __ b(&type_arguments_instantiated); | 2247 __ b(&type_arguments_instantiated); |
| 2201 | 2248 |
| 2202 __ Bind(&slow_case); | 2249 __ Bind(&slow_case); |
| 2203 // Instantiate non-null type arguments. | 2250 // Instantiate non-null type arguments. |
| 2204 // A runtime call to instantiate the type arguments is required. | 2251 // A runtime call to instantiate the type arguments is required. |
| 2205 __ PushObject(Object::ZoneHandle(), PP); // Make room for the result. | 2252 __ PushObject(Object::ZoneHandle(), PP); // Make room for the result. |
| 2206 __ PushObject(type_arguments(), PP); | 2253 __ PushObject(type_arguments(), PP); |
| 2207 __ Push(instantiator_reg); // Push instantiator type arguments. | 2254 __ Push(instantiator_reg); // Push instantiator type arguments. |
| 2208 compiler->GenerateRuntimeCall(token_pos(), | 2255 compiler->GenerateRuntimeCall(token_pos(), |
| 2209 deopt_id(), | 2256 deopt_id(), |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2292 // Restore SP from FP as we are coming from a throw and the code for | 2339 // Restore SP from FP as we are coming from a throw and the code for |
| 2293 // popping arguments has not been run. | 2340 // popping arguments has not been run. |
| 2294 const intptr_t fp_sp_dist = | 2341 const intptr_t fp_sp_dist = |
| 2295 (kFirstLocalSlotFromFp + 1 - compiler->StackSize()) * kWordSize; | 2342 (kFirstLocalSlotFromFp + 1 - compiler->StackSize()) * kWordSize; |
| 2296 ASSERT(fp_sp_dist <= 0); | 2343 ASSERT(fp_sp_dist <= 0); |
| 2297 __ AddImmediate(SP, FP, fp_sp_dist, PP); | 2344 __ AddImmediate(SP, FP, fp_sp_dist, PP); |
| 2298 | 2345 |
| 2299 // Restore stack and initialize the two exception variables: | 2346 // Restore stack and initialize the two exception variables: |
| 2300 // exception and stack trace variables. | 2347 // exception and stack trace variables. |
| 2301 __ StoreToOffset(kExceptionObjectReg, | 2348 __ StoreToOffset(kExceptionObjectReg, |
| 2302 FP, exception_var().index() * kWordSize); | 2349 FP, exception_var().index() * kWordSize, PP); |
| 2303 __ StoreToOffset(kStackTraceObjectReg, | 2350 __ StoreToOffset(kStackTraceObjectReg, |
| 2304 FP, stacktrace_var().index() * kWordSize); | 2351 FP, stacktrace_var().index() * kWordSize, PP); |
| 2305 } | 2352 } |
| 2306 | 2353 |
| 2307 | 2354 |
| 2308 LocationSummary* CheckStackOverflowInstr::MakeLocationSummary(bool opt) const { | 2355 LocationSummary* CheckStackOverflowInstr::MakeLocationSummary(bool opt) const { |
| 2309 const intptr_t kNumInputs = 0; | 2356 const intptr_t kNumInputs = 0; |
| 2310 const intptr_t kNumTemps = 1; | 2357 const intptr_t kNumTemps = 1; |
| 2311 LocationSummary* summary = | 2358 LocationSummary* summary = |
| 2312 new LocationSummary(kNumInputs, | 2359 new LocationSummary(kNumInputs, |
| 2313 kNumTemps, | 2360 kNumTemps, |
| 2314 LocationSummary::kCallOnSlowPath); | 2361 LocationSummary::kCallOnSlowPath); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2377 __ CompareRegisters(SP, TMP); | 2424 __ CompareRegisters(SP, TMP); |
| 2378 __ b(slow_path->entry_label(), LS); | 2425 __ b(slow_path->entry_label(), LS); |
| 2379 if (compiler->CanOSRFunction() && in_loop()) { | 2426 if (compiler->CanOSRFunction() && in_loop()) { |
| 2380 Register temp = locs()->temp(0).reg(); | 2427 Register temp = locs()->temp(0).reg(); |
| 2381 // In unoptimized code check the usage counter to trigger OSR at loop | 2428 // In unoptimized code check the usage counter to trigger OSR at loop |
| 2382 // stack checks. Use progressively higher thresholds for more deeply | 2429 // stack checks. Use progressively higher thresholds for more deeply |
| 2383 // nested loops to attempt to hit outer loops with OSR when possible. | 2430 // nested loops to attempt to hit outer loops with OSR when possible. |
| 2384 __ LoadObject(temp, compiler->parsed_function().function(), PP); | 2431 __ LoadObject(temp, compiler->parsed_function().function(), PP); |
| 2385 intptr_t threshold = | 2432 intptr_t threshold = |
| 2386 FLAG_optimization_counter_threshold * (loop_depth() + 1); | 2433 FLAG_optimization_counter_threshold * (loop_depth() + 1); |
| 2387 __ LoadFieldFromOffset(temp, temp, Function::usage_counter_offset()); | 2434 __ LoadFieldFromOffset(temp, temp, Function::usage_counter_offset(), PP); |
| 2388 __ CompareImmediate(temp, threshold, PP); | 2435 __ CompareImmediate(temp, threshold, PP); |
| 2389 __ b(slow_path->osr_entry_label(), GE); | 2436 __ b(slow_path->osr_entry_label(), GE); |
| 2390 } | 2437 } |
| 2391 if (compiler->ForceSlowPathForStackOverflow()) { | 2438 if (compiler->ForceSlowPathForStackOverflow()) { |
| 2392 __ b(slow_path->entry_label()); | 2439 __ b(slow_path->entry_label()); |
| 2393 } | 2440 } |
| 2394 __ Bind(slow_path->exit_label()); | 2441 __ Bind(slow_path->exit_label()); |
| 2395 } | 2442 } |
| 2396 | 2443 |
| 2397 | 2444 |
| (...skipping 472 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2870 | 2917 |
| 2871 const Register out_reg = locs()->out(0).reg(); | 2918 const Register out_reg = locs()->out(0).reg(); |
| 2872 const VRegister value = locs()->in(0).fpu_reg(); | 2919 const VRegister value = locs()->in(0).fpu_reg(); |
| 2873 | 2920 |
| 2874 __ TryAllocate(compiler->double_class(), | 2921 __ TryAllocate(compiler->double_class(), |
| 2875 slow_path->entry_label(), | 2922 slow_path->entry_label(), |
| 2876 out_reg, | 2923 out_reg, |
| 2877 locs()->temp(0).reg(), | 2924 locs()->temp(0).reg(), |
| 2878 PP); | 2925 PP); |
| 2879 __ Bind(slow_path->exit_label()); | 2926 __ Bind(slow_path->exit_label()); |
| 2880 __ StoreDFieldToOffset(value, out_reg, Double::value_offset()); | 2927 __ StoreDFieldToOffset(value, out_reg, Double::value_offset(), PP); |
| 2881 } | 2928 } |
| 2882 | 2929 |
| 2883 | 2930 |
| 2884 LocationSummary* UnboxDoubleInstr::MakeLocationSummary(bool opt) const { | 2931 LocationSummary* UnboxDoubleInstr::MakeLocationSummary(bool opt) const { |
| 2885 const intptr_t kNumInputs = 1; | 2932 const intptr_t kNumInputs = 1; |
| 2886 const intptr_t kNumTemps = 0; | 2933 const intptr_t kNumTemps = 0; |
| 2887 LocationSummary* summary = | 2934 LocationSummary* summary = |
| 2888 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2935 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2889 summary->set_in(0, Location::RequiresRegister()); | 2936 summary->set_in(0, Location::RequiresRegister()); |
| 2890 summary->set_out(0, Location::RequiresFpuRegister()); | 2937 summary->set_out(0, Location::RequiresFpuRegister()); |
| 2891 return summary; | 2938 return summary; |
| 2892 } | 2939 } |
| 2893 | 2940 |
| 2894 | 2941 |
| 2895 void UnboxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2942 void UnboxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2896 CompileType* value_type = value()->Type(); | 2943 CompileType* value_type = value()->Type(); |
| 2897 const intptr_t value_cid = value_type->ToCid(); | 2944 const intptr_t value_cid = value_type->ToCid(); |
| 2898 const Register value = locs()->in(0).reg(); | 2945 const Register value = locs()->in(0).reg(); |
| 2899 const VRegister result = locs()->out(0).fpu_reg(); | 2946 const VRegister result = locs()->out(0).fpu_reg(); |
| 2900 | 2947 |
| 2901 if (value_cid == kDoubleCid) { | 2948 if (value_cid == kDoubleCid) { |
| 2902 __ LoadDFieldFromOffset(result, value, Double::value_offset()); | 2949 __ LoadDFieldFromOffset(result, value, Double::value_offset(), PP); |
| 2903 } else if (value_cid == kSmiCid) { | 2950 } else if (value_cid == kSmiCid) { |
| 2904 __ Asr(TMP, value, kSmiTagSize); // Untag input before conversion. | 2951 __ Asr(TMP, value, kSmiTagSize); // Untag input before conversion. |
| 2905 __ scvtfd(result, TMP); | 2952 __ scvtfd(result, TMP); |
| 2906 } else { | 2953 } else { |
| 2907 Label* deopt = compiler->AddDeoptStub(deopt_id_, | 2954 Label* deopt = compiler->AddDeoptStub(deopt_id_, |
| 2908 ICData::kDeoptBinaryDoubleOp); | 2955 ICData::kDeoptBinaryDoubleOp); |
| 2909 if (value_type->is_nullable() && | 2956 if (value_type->is_nullable() && |
| 2910 (value_type->ToNullableCid() == kDoubleCid)) { | 2957 (value_type->ToNullableCid() == kDoubleCid)) { |
| 2911 __ CompareObject(value, Object::null_object(), PP); | 2958 __ CompareObject(value, Object::null_object(), PP); |
| 2912 __ b(deopt, EQ); | 2959 __ b(deopt, EQ); |
| 2913 // It must be double now. | 2960 // It must be double now. |
| 2914 __ LoadDFieldFromOffset(result, value, Double::value_offset()); | 2961 __ LoadDFieldFromOffset(result, value, Double::value_offset(), PP); |
| 2915 } else { | 2962 } else { |
| 2916 Label is_smi, done; | 2963 Label is_smi, done; |
| 2917 __ tsti(value, kSmiTagMask); | 2964 __ tsti(value, kSmiTagMask); |
| 2918 __ b(&is_smi, EQ); | 2965 __ b(&is_smi, EQ); |
| 2919 __ CompareClassId(value, kDoubleCid); | 2966 __ CompareClassId(value, kDoubleCid, PP); |
| 2920 __ b(deopt, NE); | 2967 __ b(deopt, NE); |
| 2921 __ LoadDFieldFromOffset(result, value, Double::value_offset()); | 2968 __ LoadDFieldFromOffset(result, value, Double::value_offset(), PP); |
| 2922 __ b(&done); | 2969 __ b(&done); |
| 2923 __ Bind(&is_smi); | 2970 __ Bind(&is_smi); |
| 2924 __ Asr(TMP, value, kSmiTagSize); // Copy and untag. | 2971 __ Asr(TMP, value, kSmiTagSize); // Copy and untag. |
| 2925 __ scvtfd(result, TMP); | 2972 __ scvtfd(result, TMP); |
| 2926 __ Bind(&done); | 2973 __ Bind(&done); |
| 2927 } | 2974 } |
| 2928 } | 2975 } |
| 2929 } | 2976 } |
| 2930 | 2977 |
| 2931 | 2978 |
| (...skipping 554 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3486 result->set_out(0, Location::RegisterLocation(R0)); | 3533 result->set_out(0, Location::RegisterLocation(R0)); |
| 3487 return result; | 3534 return result; |
| 3488 } | 3535 } |
| 3489 | 3536 |
| 3490 | 3537 |
| 3491 void DoubleToIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3538 void DoubleToIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 3492 const Register result = locs()->out(0).reg(); | 3539 const Register result = locs()->out(0).reg(); |
| 3493 const Register value_obj = locs()->in(0).reg(); | 3540 const Register value_obj = locs()->in(0).reg(); |
| 3494 ASSERT(result == R0); | 3541 ASSERT(result == R0); |
| 3495 ASSERT(result != value_obj); | 3542 ASSERT(result != value_obj); |
| 3496 __ LoadDFieldFromOffset(VTMP, value_obj, Double::value_offset()); | 3543 __ LoadDFieldFromOffset(VTMP, value_obj, Double::value_offset(), PP); |
| 3497 | 3544 |
| 3498 Label do_call, done; | 3545 Label do_call, done; |
| 3499 // First check for NaN. Checking for minint after the conversion doesn't work | 3546 // First check for NaN. Checking for minint after the conversion doesn't work |
| 3500 // on ARM64 because fcvtzds gives 0 for NaN. | 3547 // on ARM64 because fcvtzds gives 0 for NaN. |
| 3501 __ fcmpd(VTMP, VTMP); | 3548 __ fcmpd(VTMP, VTMP); |
| 3502 __ b(&do_call, VS); | 3549 __ b(&do_call, VS); |
| 3503 | 3550 |
| 3504 __ fcvtzds(result, VTMP); | 3551 __ fcvtzds(result, VTMP); |
| 3505 // Overflow is signaled with minint. | 3552 // Overflow is signaled with minint. |
| 3506 | 3553 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3561 return NULL; | 3608 return NULL; |
| 3562 } | 3609 } |
| 3563 | 3610 |
| 3564 | 3611 |
| 3565 void DoubleToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3612 void DoubleToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 3566 UNIMPLEMENTED(); | 3613 UNIMPLEMENTED(); |
| 3567 } | 3614 } |
| 3568 | 3615 |
| 3569 | 3616 |
| 3570 LocationSummary* DoubleToFloatInstr::MakeLocationSummary(bool opt) const { | 3617 LocationSummary* DoubleToFloatInstr::MakeLocationSummary(bool opt) const { |
| 3571 UNIMPLEMENTED(); | 3618 const intptr_t kNumInputs = 1; |
| 3572 return NULL; | 3619 const intptr_t kNumTemps = 0; |
| 3620 LocationSummary* result = |
| 3621 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 3622 result->set_in(0, Location::RequiresFpuRegister()); |
| 3623 result->set_out(0, Location::RequiresFpuRegister()); |
| 3624 return result; |
| 3573 } | 3625 } |
| 3574 | 3626 |
| 3575 | 3627 |
| 3576 void DoubleToFloatInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3628 void DoubleToFloatInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 3577 UNIMPLEMENTED(); | 3629 const VRegister value = locs()->in(0).fpu_reg(); |
| 3630 const VRegister result = locs()->out(0).fpu_reg(); |
| 3631 __ fcvtsd(result, value); |
| 3578 } | 3632 } |
| 3579 | 3633 |
| 3580 | 3634 |
| 3581 LocationSummary* FloatToDoubleInstr::MakeLocationSummary(bool opt) const { | 3635 LocationSummary* FloatToDoubleInstr::MakeLocationSummary(bool opt) const { |
| 3582 UNIMPLEMENTED(); | 3636 const intptr_t kNumInputs = 1; |
| 3583 return NULL; | 3637 const intptr_t kNumTemps = 0; |
| 3638 LocationSummary* result = |
| 3639 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 3640 result->set_in(0, Location::RequiresFpuRegister()); |
| 3641 result->set_out(0, Location::RequiresFpuRegister()); |
| 3642 return result; |
| 3584 } | 3643 } |
| 3585 | 3644 |
| 3586 | 3645 |
| 3587 void FloatToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3646 void FloatToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 3588 UNIMPLEMENTED(); | 3647 const VRegister value = locs()->in(0).fpu_reg(); |
| 3648 const VRegister result = locs()->out(0).fpu_reg(); |
| 3649 __ fcvtds(result, value); |
| 3589 } | 3650 } |
| 3590 | 3651 |
| 3591 | 3652 |
| 3592 LocationSummary* InvokeMathCFunctionInstr::MakeLocationSummary(bool opt) const { | 3653 LocationSummary* InvokeMathCFunctionInstr::MakeLocationSummary(bool opt) const { |
| 3593 ASSERT((InputCount() == 1) || (InputCount() == 2)); | 3654 ASSERT((InputCount() == 1) || (InputCount() == 2)); |
| 3594 const intptr_t kNumTemps = 0; | 3655 const intptr_t kNumTemps = 0; |
| 3595 LocationSummary* result = | 3656 LocationSummary* result = |
| 3596 new LocationSummary(InputCount(), kNumTemps, LocationSummary::kCall); | 3657 new LocationSummary(InputCount(), kNumTemps, LocationSummary::kCall); |
| 3597 result->set_in(0, Location::FpuRegisterLocation(V0)); | 3658 result->set_in(0, Location::FpuRegisterLocation(V0)); |
| 3598 if (InputCount() == 2) { | 3659 if (InputCount() == 2) { |
| (...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3832 instance_call()->token_pos(), | 3893 instance_call()->token_pos(), |
| 3833 target, | 3894 target, |
| 3834 instance_call()->ArgumentCount(), | 3895 instance_call()->ArgumentCount(), |
| 3835 instance_call()->argument_names(), | 3896 instance_call()->argument_names(), |
| 3836 locs()); | 3897 locs()); |
| 3837 return; | 3898 return; |
| 3838 } | 3899 } |
| 3839 | 3900 |
| 3840 // Load receiver into R0. | 3901 // Load receiver into R0. |
| 3841 __ LoadFromOffset( | 3902 __ LoadFromOffset( |
| 3842 R0, SP, (instance_call()->ArgumentCount() - 1) * kWordSize); | 3903 R0, SP, (instance_call()->ArgumentCount() - 1) * kWordSize, PP); |
| 3843 | 3904 |
| 3844 LoadValueCid(compiler, R2, R0, | 3905 LoadValueCid(compiler, R2, R0, |
| 3845 (ic_data().GetReceiverClassIdAt(0) == kSmiCid) ? NULL : deopt); | 3906 (ic_data().GetReceiverClassIdAt(0) == kSmiCid) ? NULL : deopt); |
| 3846 | 3907 |
| 3847 compiler->EmitTestAndCall(ic_data(), | 3908 compiler->EmitTestAndCall(ic_data(), |
| 3848 R2, // Class id register. | 3909 R2, // Class id register. |
| 3849 instance_call()->ArgumentCount(), | 3910 instance_call()->ArgumentCount(), |
| 3850 instance_call()->argument_names(), | 3911 instance_call()->argument_names(), |
| 3851 deopt, | 3912 deopt, |
| 3852 deopt_id(), | 3913 deopt_id(), |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3899 Label is_ok; | 3960 Label is_ok; |
| 3900 intptr_t cix = 0; | 3961 intptr_t cix = 0; |
| 3901 if (unary_checks().GetReceiverClassIdAt(cix) == kSmiCid) { | 3962 if (unary_checks().GetReceiverClassIdAt(cix) == kSmiCid) { |
| 3902 __ tsti(value, kSmiTagMask); | 3963 __ tsti(value, kSmiTagMask); |
| 3903 __ b(&is_ok, EQ); | 3964 __ b(&is_ok, EQ); |
| 3904 cix++; // Skip first check. | 3965 cix++; // Skip first check. |
| 3905 } else { | 3966 } else { |
| 3906 __ tsti(value, kSmiTagMask); | 3967 __ tsti(value, kSmiTagMask); |
| 3907 __ b(deopt, EQ); | 3968 __ b(deopt, EQ); |
| 3908 } | 3969 } |
| 3909 __ LoadClassId(temp, value); | 3970 __ LoadClassId(temp, value, PP); |
| 3910 const intptr_t num_checks = unary_checks().NumberOfChecks(); | 3971 const intptr_t num_checks = unary_checks().NumberOfChecks(); |
| 3911 for (intptr_t i = cix; i < num_checks; i++) { | 3972 for (intptr_t i = cix; i < num_checks; i++) { |
| 3912 ASSERT(unary_checks().GetReceiverClassIdAt(i) != kSmiCid); | 3973 ASSERT(unary_checks().GetReceiverClassIdAt(i) != kSmiCid); |
| 3913 __ CompareImmediate(temp, unary_checks().GetReceiverClassIdAt(i), PP); | 3974 __ CompareImmediate(temp, unary_checks().GetReceiverClassIdAt(i), PP); |
| 3914 if (i == (num_checks - 1)) { | 3975 if (i == (num_checks - 1)) { |
| 3915 __ b(deopt, NE); | 3976 __ b(deopt, NE); |
| 3916 } else { | 3977 } else { |
| 3917 __ b(&is_ok, EQ); | 3978 __ b(&is_ok, EQ); |
| 3918 } | 3979 } |
| 3919 } | 3980 } |
| (...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4254 compiler->GenerateCall(token_pos(), | 4315 compiler->GenerateCall(token_pos(), |
| 4255 &label, | 4316 &label, |
| 4256 PcDescriptors::kOther, | 4317 PcDescriptors::kOther, |
| 4257 locs()); | 4318 locs()); |
| 4258 __ Drop(ArgumentCount()); // Discard arguments. | 4319 __ Drop(ArgumentCount()); // Discard arguments. |
| 4259 } | 4320 } |
| 4260 | 4321 |
| 4261 } // namespace dart | 4322 } // namespace dart |
| 4262 | 4323 |
| 4263 #endif // defined TARGET_ARCH_ARM64 | 4324 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |