Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(671)

Unified Diff: runtime/vm/intermediate_language_arm64.cc

Issue 254673007: More stubs and instructions for arm64. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/compiler_test.cc ('k') | runtime/vm/simulator_arm64.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/intermediate_language_arm64.cc
===================================================================
--- runtime/vm/intermediate_language_arm64.cc (revision 35551)
+++ runtime/vm/intermediate_language_arm64.cc (working copy)
@@ -109,13 +109,54 @@
LocationSummary* ClosureCallInstr::MakeLocationSummary(bool opt) const {
- UNIMPLEMENTED();
- return NULL;
+ return MakeCallSummary();
}
void ClosureCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ // Load closure object (first argument) in R1.
+ int argument_count = ArgumentCount();
+ __ LoadFromOffset(R1, SP, (argument_count - 1) * kWordSize);
+
+ // Load arguments descriptor in R4.
+ const Array& arguments_descriptor =
+ Array::ZoneHandle(ArgumentsDescriptor::New(argument_count,
+ argument_names()));
+ __ LoadObject(R4, arguments_descriptor, PP);
+
+ // Load the closure function into R0.
+ __ LoadFieldFromOffset(R0, R1, Closure::function_offset());
+
+ // Load closure context in CTX; note that CTX has already been preserved.
+ __ LoadFieldFromOffset(CTX, R1, Closure::context_offset());
+
+ // R4: Arguments descriptor.
+ // R0: Function.
+ __ LoadFieldFromOffset(R2, R0, Function::code_offset());
+
+ // R2: code.
+ // R5: Smi 0 (no IC data; the lazy-compile stub expects a GC-safe value).
+ __ LoadImmediate(R5, 0, PP);
+ __ LoadFieldFromOffset(R2, R2, Code::instructions_offset());
+ __ AddImmediate(R2, R2, Instructions::HeaderSize() - kHeapObjectTag, PP);
+ __ blr(R2);
+ compiler->AddCurrentDescriptor(PcDescriptors::kClosureCall,
+ deopt_id(),
+ token_pos());
+ compiler->RecordSafepoint(locs());
+ // Marks either the continuation point in unoptimized code or the
+ // deoptimization point in optimized code, after call.
+ const intptr_t deopt_id_after = Isolate::ToDeoptAfter(deopt_id());
+ if (compiler->is_optimizing()) {
+ compiler->AddDeoptIndexAtCall(deopt_id_after, token_pos());
+ } else {
+ // Add deoptimization continuation point after the call and before the
+ // arguments are removed.
+ compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
+ deopt_id_after,
+ token_pos());
+ }
+ __ Drop(argument_count);
}
@@ -164,8 +205,15 @@
LocationSummary* AssertAssignableInstr::MakeLocationSummary(bool opt) const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 3;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
+ summary->set_in(0, Location::RegisterLocation(R0)); // Value.
+ summary->set_in(1, Location::RegisterLocation(R2)); // Instantiator.
+ summary->set_in(2, Location::RegisterLocation(R1)); // Type arguments.
+ summary->set_out(0, Location::RegisterLocation(R0));
+ return summary;
}
@@ -365,13 +413,28 @@
LocationSummary* StringInterpolateInstr::MakeLocationSummary(bool opt) const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
+ summary->set_in(0, Location::RegisterLocation(R0));
+ summary->set_out(0, Location::RegisterLocation(R0));
+ return summary;
}
void StringInterpolateInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Register array = locs()->in(0).reg();
+ __ Push(array);
+ const int kNumberOfArguments = 1;
+ const Array& kNoArgumentNames = Object::null_array();
+ compiler->GenerateStaticCall(deopt_id(),
+ token_pos(),
+ CallFunction(),
+ kNumberOfArguments,
+ kNoArgumentNames,
+ locs());
+ ASSERT(locs()->out(0).reg() == R0);
}
@@ -387,13 +450,25 @@
LocationSummary* LoadClassIdInstr::MakeLocationSummary(bool opt) const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 1;
+ return LocationSummary::Make(kNumInputs,
+ Location::RequiresRegister(),
+ LocationSummary::kNoCall);
}
void LoadClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Register object = locs()->in(0).reg();
+ Register result = locs()->out(0).reg();
+ Label load, done;
+ __ tsti(object, kSmiTagMask);
+ __ b(&load, NE);
+ __ LoadImmediate(result, Smi::RawValue(kSmiCid), PP);
+ __ b(&done);
+ __ Bind(&load);
+ __ LoadClassId(result, object);
+ __ SmiTag(result);
+ __ Bind(&done);
}
@@ -422,63 +497,756 @@
Representation StoreIndexedInstr::RequiredInputRepresentation(
intptr_t idx) const {
- UNIMPLEMENTED();
- return kTagged;
+ // Array can be a Dart object or a pointer to external data.
+ if (idx == 0) return kNoRepresentation; // Flexible input representation.
+ if (idx == 1) return kTagged; // Index is a smi.
+ ASSERT(idx == 2);
+ switch (class_id_) {
+ case kArrayCid:
+ case kOneByteStringCid:
+ case kTypedDataInt8ArrayCid:
+ case kTypedDataUint8ArrayCid:
+ case kExternalTypedDataUint8ArrayCid:
+ case kTypedDataUint8ClampedArrayCid:
+ case kExternalTypedDataUint8ClampedArrayCid:
+ case kTypedDataInt16ArrayCid:
+ case kTypedDataUint16ArrayCid:
+ return kTagged;
+ case kTypedDataInt32ArrayCid:
+ case kTypedDataUint32ArrayCid:
+ return value()->IsSmiValue() ? kTagged : kUnboxedMint;
+ case kTypedDataFloat32ArrayCid:
+ case kTypedDataFloat64ArrayCid:
+ return kUnboxedDouble;
+ case kTypedDataFloat32x4ArrayCid:
+ return kUnboxedFloat32x4;
+ case kTypedDataInt32x4ArrayCid:
+ return kUnboxedInt32x4;
+ case kTypedDataFloat64x2ArrayCid:
+ return kUnboxedFloat64x2;
+ default:
+ UNREACHABLE();
+ return kTagged;
+ }
}
LocationSummary* StoreIndexedInstr::MakeLocationSummary(bool opt) const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 3;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ locs->set_in(0, Location::RequiresRegister());
+ // The smi index is either untagged (element size == 1), or it is left smi
+ // tagged (for all element sizes > 1).
+ // TODO(regis): Revisit and see if the index can be immediate.
+ locs->set_in(1, Location::WritableRegister());
+ switch (class_id()) {
+ case kArrayCid:
+ locs->set_in(2, ShouldEmitStoreBarrier()
+ ? Location::WritableRegister()
+ : Location::RegisterOrConstant(value()));
+ break;
+ case kExternalTypedDataUint8ArrayCid:
+ case kExternalTypedDataUint8ClampedArrayCid:
+ case kTypedDataInt8ArrayCid:
+ case kTypedDataUint8ArrayCid:
+ case kTypedDataUint8ClampedArrayCid:
+ case kOneByteStringCid:
+ case kTypedDataInt16ArrayCid:
+ case kTypedDataUint16ArrayCid:
+ locs->set_in(2, Location::WritableRegister());
+ break;
+ case kTypedDataInt32ArrayCid:
+ case kTypedDataUint32ArrayCid:
+ // Mints are stored in Q registers. For smis, use a writable register
+ // because the value must be untagged before storing.
+ if (value()->IsSmiValue()) {
+ locs->set_in(2, Location::WritableRegister());
+ } else {
+ // TODO(zra): Implement when we add fpu loads and stores.
+ UNIMPLEMENTED();
+ }
+ break;
+ case kTypedDataFloat32ArrayCid:
+ case kTypedDataFloat64ArrayCid: // TODO(srdjan): Support Float64 constants.
+ case kTypedDataInt32x4ArrayCid:
+ case kTypedDataFloat32x4ArrayCid:
+ case kTypedDataFloat64x2ArrayCid:
+ // TODO(zra): Implement when we add fpu loads and stores.
+ UNIMPLEMENTED();
+ break;
+ default:
+ UNREACHABLE();
+ return NULL;
+ }
+ return locs;
}
void StoreIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Register array = locs()->in(0).reg();
+ Location index = locs()->in(1);
+
+ Address element_address(kNoRegister, 0);
+ ASSERT(index.IsRegister()); // TODO(regis): Revisit.
+ // Note that index is expected smi-tagged, (i.e, times 2) for all arrays
+ // with index scale factor > 1. E.g., for Uint8Array and OneByteString the
+ // index is expected to be untagged before accessing.
+ ASSERT(kSmiTagShift == 1);
+ switch (index_scale()) {
+ case 1: {
+ __ SmiUntag(index.reg());
+ break;
+ }
+ case 2: {
+ break;
+ }
+ case 4: {
+ __ Lsl(index.reg(), index.reg(), 1);
+ break;
+ }
+ case 8: {
+ __ Lsl(index.reg(), index.reg(), 2);
+ break;
+ }
+ case 16: {
+ __ Lsl(index.reg(), index.reg(), 3);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+ if (!IsExternal()) {
+ ASSERT(this->array()->definition()->representation() == kTagged);
+ __ AddImmediate(index.reg(), index.reg(),
+ FlowGraphCompiler::DataOffsetFor(class_id()) - kHeapObjectTag, PP);
+ }
+ element_address = Address(array, index.reg(), UXTX, Address::Unscaled);
+
+ switch (class_id()) {
+ case kArrayCid:
+ if (ShouldEmitStoreBarrier()) {
+ Register value = locs()->in(2).reg();
+ __ StoreIntoObject(array, element_address, value);
+ } else if (locs()->in(2).IsConstant()) {
+ const Object& constant = locs()->in(2).constant();
+ __ StoreIntoObjectNoBarrier(array, element_address, constant);
+ } else {
+ Register value = locs()->in(2).reg();
+ __ StoreIntoObjectNoBarrier(array, element_address, value);
+ }
+ break;
+ case kTypedDataInt8ArrayCid:
+ case kTypedDataUint8ArrayCid:
+ case kExternalTypedDataUint8ArrayCid:
+ case kOneByteStringCid: {
+ if (locs()->in(2).IsConstant()) {
+ const Smi& constant = Smi::Cast(locs()->in(2).constant());
+ __ LoadImmediate(TMP, static_cast<int8_t>(constant.Value()), PP);
+ __ str(TMP, element_address, kUnsignedByte);
+ } else {
+ Register value = locs()->in(2).reg();
+ __ SmiUntag(value);
+ __ str(value, element_address, kUnsignedByte);
+ }
+ break;
+ }
+ case kTypedDataUint8ClampedArrayCid:
+ case kExternalTypedDataUint8ClampedArrayCid: {
+ if (locs()->in(2).IsConstant()) {
+ const Smi& constant = Smi::Cast(locs()->in(2).constant());
+ intptr_t value = constant.Value();
+ // Clamp to 0x0 or 0xFF respectively.
+ if (value > 0xFF) {
+ value = 0xFF;
+ } else if (value < 0) {
+ value = 0;
+ }
+ __ LoadImmediate(TMP, static_cast<int8_t>(value), PP);
+ __ str(TMP, element_address, kUnsignedByte);
+ } else {
+ Register value = locs()->in(2).reg();
+ Label store_value;
+ __ SmiUntag(value);
+ __ CompareImmediate(value, 0xFF, PP);
+ // Clamp to 0x00 or 0xFF respectively.
+ __ b(&store_value, LS);
+ __ LoadImmediate(TMP, 0x00, PP);
+ __ LoadImmediate(TMP2, 0xFF, PP);
+ __ csel(value, TMP, value, LE);
+ __ csel(value, TMP2, value, GT);
+ __ Bind(&store_value);
+ __ str(value, element_address, kUnsignedByte);
+ }
+ break;
+ }
+ case kTypedDataInt16ArrayCid:
+ case kTypedDataUint16ArrayCid: {
+ Register value = locs()->in(2).reg();
+ __ SmiUntag(value);
+ __ str(value, element_address, kUnsignedHalfword);
+ break;
+ }
+ case kTypedDataInt32ArrayCid:
+ case kTypedDataUint32ArrayCid: {
+ if (value()->IsSmiValue()) {
+ ASSERT(RequiredInputRepresentation(2) == kTagged);
+ Register value = locs()->in(2).reg();
+ __ SmiUntag(value);
+ __ str(value, element_address);
+ } else {
+ // TODO(zra): Implement when we add fpu loads and stores.
+ UNIMPLEMENTED();
+ }
+ break;
+ }
+ case kTypedDataFloat32ArrayCid:
+ case kTypedDataFloat64ArrayCid:
+ case kTypedDataFloat64x2ArrayCid:
+ case kTypedDataInt32x4ArrayCid:
+ case kTypedDataFloat32x4ArrayCid: {
+ // TODO(zra): Implement when we add fpu loads and stores.
+ UNIMPLEMENTED();
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
}
+static void LoadValueCid(FlowGraphCompiler* compiler,
+ Register value_cid_reg,
+ Register value_reg,
+ Label* value_is_smi = NULL) {
+ Label done;
+ if (value_is_smi == NULL) {
+ __ LoadImmediate(value_cid_reg, kSmiCid, PP);
+ }
+ __ tsti(value_reg, kSmiTagMask);
+ if (value_is_smi == NULL) {
+ __ b(&done, EQ);
+ } else {
+ __ b(value_is_smi, EQ);
+ }
+ __ LoadClassId(value_cid_reg, value_reg);
+ __ Bind(&done);
+}
+
+
LocationSummary* GuardFieldInstr::MakeLocationSummary(bool opt) const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 1;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresRegister());
+ const bool field_has_length = field().needs_length_check();
+ summary->AddTemp(Location::RequiresRegister());
+ summary->AddTemp(Location::RequiresRegister());
+ const bool need_field_temp_reg =
+ field_has_length || (field().guarded_cid() == kIllegalCid);
+ if (need_field_temp_reg) {
+ summary->AddTemp(Location::RequiresRegister());
+ }
+ return summary;
}
void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ const intptr_t field_cid = field().guarded_cid();
+ const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid;
+ const intptr_t field_length = field().guarded_list_length();
+ const bool field_has_length = field().needs_length_check();
+ const bool needs_field_temp_reg =
+ field_has_length || (field().guarded_cid() == kIllegalCid);
+ if (field_has_length) {
+ // Currently, we should only see final fields that remember length.
+ ASSERT(field().is_final());
+ }
+
+ if (field_cid == kDynamicCid) {
+ ASSERT(!compiler->is_optimizing());
+ return; // Nothing to emit.
+ }
+
+ const intptr_t value_cid = value()->Type()->ToCid();
+
+ Register value_reg = locs()->in(0).reg();
+
+ Register value_cid_reg = locs()->temp(0).reg();
+
+ Register temp_reg = locs()->temp(1).reg();
+
+ Register field_reg = needs_field_temp_reg ?
+ locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister;
+
+ Label ok, fail_label;
+
+ Label* deopt = compiler->is_optimizing() ?
+ compiler->AddDeoptStub(deopt_id(), ICData::kDeoptGuardField) : NULL;
+
+ Label* fail = (deopt != NULL) ? deopt : &fail_label;
+
+ if (!compiler->is_optimizing() || (field_cid == kIllegalCid)) {
+ if (!compiler->is_optimizing() && (field_reg == kNoRegister)) {
+ // Currently we can't have different location summaries for optimized
+ // and non-optimized code. So instead we manually pick up a register
+ // that is known to be free because we know how non-optimizing compiler
+ // allocates registers.
+ field_reg = R2;
+ ASSERT((field_reg != value_reg) && (field_reg != value_cid_reg));
+ }
+
+ __ LoadObject(field_reg, Field::ZoneHandle(field().raw()), PP);
+
+ FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset());
+ FieldAddress field_nullability_operand(
+ field_reg, Field::is_nullable_offset());
+ FieldAddress field_length_operand(
+ field_reg, Field::guarded_list_length_offset());
+
+ ASSERT(value_cid_reg != kNoRegister);
+ ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
+
+ if (value_cid == kDynamicCid) {
+ LoadValueCid(compiler, value_cid_reg, value_reg);
+ Label skip_length_check;
+ __ ldr(TMP, field_cid_operand);
+ __ CompareRegisters(value_cid_reg, TMP);
+ __ b(&skip_length_check, NE);
+ if (field_has_length) {
+ ASSERT(temp_reg != kNoRegister);
+ // Field guard may have remembered list length, check it.
+ if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
+ __ LoadFieldFromOffset(temp_reg, value_reg, Array::length_offset());
+ __ CompareImmediate(temp_reg, Smi::RawValue(field_length), PP);
+ } else if (RawObject::IsTypedDataClassId(field_cid)) {
+ __ LoadFieldFromOffset(
+ temp_reg, value_reg, TypedData::length_offset());
+ __ CompareImmediate(temp_reg, Smi::RawValue(field_length), PP);
+ } else {
+ ASSERT(field_cid == kIllegalCid);
+ ASSERT(field_length == Field::kUnknownFixedLength);
+ // At compile time we do not know the type of the field nor its
+ // length. At execution time we may have set the class id and
+ // list length so we compare the guarded length with the
+ // list length here, without this check the list length could change
+ // without triggering a deoptimization.
+ Label check_array, length_compared, no_fixed_length;
+ // If length is negative the length guard is either disabled or
+ // has not been initialized, either way it is safe to skip the
+ // length check.
+ __ ldr(TMP, field_length_operand);
+ __ CompareImmediate(TMP, 0, PP);
+ __ b(&skip_length_check, LT);
+ __ CompareImmediate(value_cid_reg, kNullCid, PP);
+ __ b(&no_fixed_length, EQ);
+ // Check for typed data array.
+ __ CompareImmediate(value_cid_reg, kTypedDataInt32x4ArrayCid, PP);
+ __ b(&no_fixed_length, GT);
+ __ CompareImmediate(value_cid_reg, kTypedDataInt8ArrayCid, PP);
+ // Could still be a regular array.
+ __ b(&check_array, LT);
+ __ LoadFromOffset(temp_reg, value_reg, TypedData::length_offset());
+ __ ldr(TMP, field_length_operand);
+ __ CompareRegisters(temp_reg, TMP);
+ __ b(&length_compared);
+ // Check for regular array.
+ __ Bind(&check_array);
+ __ CompareImmediate(value_cid_reg, kImmutableArrayCid, PP);
+ __ b(&no_fixed_length, GT);
+ __ CompareImmediate(value_cid_reg, kArrayCid, PP);
+ __ b(&no_fixed_length, LT);
+ __ LoadFieldFromOffset(temp_reg, value_reg, Array::length_offset());
+ __ ldr(TMP, field_length_operand);
+ __ CompareRegisters(temp_reg, TMP);
+ __ b(&length_compared);
+ __ Bind(&no_fixed_length);
+ __ b(fail);
+ __ Bind(&length_compared);
+ // Following branch cannot not occur, fall through.
+ }
+ __ b(fail, NE);
+ }
+ __ Bind(&skip_length_check);
+ __ ldr(TMP, field_nullability_operand);
+ __ CompareRegisters(value_cid_reg, TMP);
+ } else if (value_cid == kNullCid) {
+ __ ldr(value_cid_reg, field_nullability_operand);
+ __ CompareImmediate(value_cid_reg, value_cid, PP);
+ } else {
+ Label skip_length_check;
+ __ ldr(value_cid_reg, field_cid_operand);
+ __ CompareImmediate(value_cid_reg, value_cid, PP);
+ __ b(&skip_length_check, NE);
+ if (field_has_length) {
+ ASSERT(value_cid_reg != kNoRegister);
+ ASSERT(temp_reg != kNoRegister);
+ if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) {
+ __ LoadFieldFromOffset(temp_reg, value_reg, Array::length_offset());
+ __ CompareImmediate(temp_reg, Smi::RawValue(field_length), PP);
+ } else if (RawObject::IsTypedDataClassId(value_cid)) {
+ __ LoadFieldFromOffset(
+ temp_reg, value_reg, TypedData::length_offset());
+ __ CompareImmediate(temp_reg, Smi::RawValue(field_length), PP);
+ } else if (field_cid != kIllegalCid) {
+ ASSERT(field_cid != value_cid);
+ ASSERT(field_length >= 0);
+ // Field has a known class id and length. At compile time it is
+ // known that the value's class id is not a fixed length list.
+ __ b(fail);
+ } else {
+ ASSERT(field_cid == kIllegalCid);
+ ASSERT(field_length == Field::kUnknownFixedLength);
+ // Following jump cannot not occur, fall through.
+ }
+ __ b(fail, NE);
+ }
+ // Not identical, possibly null.
+ __ Bind(&skip_length_check);
+ }
+ __ b(&ok, EQ);
+
+ __ ldr(TMP, field_cid_operand);
+ __ CompareImmediate(TMP, kIllegalCid, PP);
+ __ b(fail, NE);
+
+ if (value_cid == kDynamicCid) {
+ __ str(value_cid_reg, field_cid_operand);
+ __ str(value_cid_reg, field_nullability_operand);
+ if (field_has_length) {
+ Label check_array, length_set, no_fixed_length;
+ __ CompareImmediate(value_cid_reg, kNullCid, PP);
+ __ b(&no_fixed_length, EQ);
+ // Check for typed data array.
+ __ CompareImmediate(value_cid_reg, kTypedDataInt32x4ArrayCid, PP);
+ __ b(&no_fixed_length, GT);
+ __ CompareImmediate(value_cid_reg, kTypedDataInt8ArrayCid, PP);
+ // Could still be a regular array.
+ __ b(&check_array, LT);
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ LoadFieldFromOffset(
+ value_cid_reg, value_reg, TypedData::length_offset());
+ __ str(value_cid_reg, field_length_operand);
+ __ b(&length_set); // Updated field length typed data array.
+ // Check for regular array.
+ __ Bind(&check_array);
+ __ CompareImmediate(value_cid_reg, kImmutableArrayCid, PP);
+ __ b(&no_fixed_length, GT);
+ __ CompareImmediate(value_cid_reg, kArrayCid, PP);
+ __ b(&no_fixed_length, LT);
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ LoadFieldFromOffset(
+ value_cid_reg, value_reg, Array::length_offset());
+ __ str(value_cid_reg, field_length_operand);
+ // Updated field length from regular array.
+ __ b(&length_set);
+ __ Bind(&no_fixed_length);
+ __ LoadImmediate(TMP, Smi::RawValue(Field::kNoFixedLength), PP);
+ __ str(TMP, field_length_operand);
+ __ Bind(&length_set);
+ }
+ } else {
+ __ LoadImmediate(TMP, value_cid, PP);
+ __ str(TMP, field_cid_operand);
+ __ str(TMP, field_nullability_operand);
+ if (field_has_length) {
+ if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ LoadFieldFromOffset(
+ value_cid_reg, value_reg, Array::length_offset());
+ __ str(value_cid_reg, field_length_operand);
+ } else if (RawObject::IsTypedDataClassId(value_cid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ LoadFieldFromOffset(
+ value_cid_reg, value_reg, TypedData::length_offset());
+ __ str(value_cid_reg, field_length_operand);
+ } else {
+ __ LoadImmediate(TMP, Smi::RawValue(Field::kNoFixedLength), PP);
+ __ str(TMP, field_length_operand);
+ }
+ }
+ }
+
+ if (deopt == NULL) {
+ ASSERT(!compiler->is_optimizing());
+ __ b(&ok);
+ __ Bind(fail);
+
+ __ LoadFieldFromOffset(TMP, field_reg, Field::guarded_cid_offset());
+ __ CompareImmediate(TMP, kDynamicCid, PP);
+ __ b(&ok, EQ);
+
+ __ Push(field_reg);
+ __ Push(value_reg);
+ __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
+ __ Drop(2); // Drop the field and the value.
+ }
+ } else {
+ ASSERT(compiler->is_optimizing());
+ ASSERT(deopt != NULL);
+ // Field guard class has been initialized and is known.
+ if (field_reg != kNoRegister) {
+ __ LoadObject(field_reg, Field::ZoneHandle(field().raw()), PP);
+ }
+ if (value_cid == kDynamicCid) {
+ // Field's guarded class id is fixed by value's class id is not known.
+ __ tsti(value_reg, kSmiTagMask);
+
+ if (field_cid != kSmiCid) {
+ __ b(fail, EQ);
+ __ LoadClassId(value_cid_reg, value_reg);
+ __ CompareImmediate(value_cid_reg, field_cid, PP);
+ }
+
+ if (field_has_length) {
+ __ b(fail, NE);
+ // Classes are same, perform guarded list length check.
+ ASSERT(field_reg != kNoRegister);
+ ASSERT(value_cid_reg != kNoRegister);
+ FieldAddress field_length_operand(
+ field_reg, Field::guarded_list_length_offset());
+ if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ LoadFieldFromOffset(
+ value_cid_reg, value_reg, Array::length_offset());
+ } else if (RawObject::IsTypedDataClassId(field_cid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ LoadFieldFromOffset(
+ value_cid_reg, value_reg, TypedData::length_offset());
+ }
+ __ ldr(TMP, field_length_operand);
+ __ CompareRegisters(value_cid_reg, TMP);
+ }
+
+ if (field().is_nullable() && (field_cid != kNullCid)) {
+ __ b(&ok, EQ);
+ __ CompareObject(value_reg, Object::null_object(), PP);
+ }
+ __ b(fail, NE);
+ } else {
+ // Both value's and field's class id is known.
+ if ((value_cid != field_cid) && (value_cid != nullability)) {
+ __ b(fail);
+ } else if (field_has_length && (value_cid == field_cid)) {
+ ASSERT(value_cid_reg != kNoRegister);
+ if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ LoadFieldFromOffset(
+ value_cid_reg, value_reg, Array::length_offset());
+ } else if (RawObject::IsTypedDataClassId(field_cid)) {
+ // Destroy value_cid_reg (safe because we are finished with it).
+ __ LoadFieldFromOffset(
+ value_cid_reg, value_reg, TypedData::length_offset());
+ }
+ __ CompareImmediate(value_cid_reg, field_length, PP);
+ __ b(fail, NE);
+ } else {
+ UNREACHABLE();
+ }
+ }
+ }
+ __ Bind(&ok);
}
+class StoreInstanceFieldSlowPath : public SlowPathCode {
+ public:
+ StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction,
+ const Class& cls)
+ : instruction_(instruction), cls_(cls) { }
+
+ virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
+ __ Comment("StoreInstanceFieldSlowPath");
+ __ Bind(entry_label());
+
+ const Code& stub =
+ Code::Handle(StubCode::GetAllocationStubForClass(cls_));
+ const ExternalLabel label(cls_.ToCString(), stub.EntryPoint());
+
+ LocationSummary* locs = instruction_->locs();
+ locs->live_registers()->Remove(locs->out(0));
+
+ compiler->SaveLiveRegisters(locs);
+ compiler->GenerateCall(Scanner::kNoSourcePos, // No token position.
+ &label,
+ PcDescriptors::kOther,
+ locs);
+ __ mov(locs->temp(0).reg(), R0);
+ compiler->RestoreLiveRegisters(locs);
+
+ __ b(exit_label());
+ }
+
+ private:
+ StoreInstanceFieldInstr* instruction_;
+ const Class& cls_;
+};
+
+
LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary(bool opt) const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 2;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps,
+ !field().IsNull() &&
+ ((field().guarded_cid() == kIllegalCid) || is_initialization_)
+ ? LocationSummary::kCallOnSlowPath
+ : LocationSummary::kNoCall);
+
+ summary->set_in(0, Location::RequiresRegister());
+ if (IsUnboxedStore() && opt) {
+ // TODO(zra): Implement when we add fpu loads and stores.
+ UNIMPLEMENTED();
+ } else if (IsPotentialUnboxedStore()) {
+ summary->set_in(1, ShouldEmitStoreBarrier()
+ ? Location::WritableRegister()
+ : Location::RequiresRegister());
+ summary->AddTemp(Location::RequiresRegister());
+ summary->AddTemp(Location::RequiresRegister());
+ } else {
+ summary->set_in(1, ShouldEmitStoreBarrier()
+ ? Location::WritableRegister()
+ : Location::RegisterOrConstant(value()));
+ }
+ return summary;
}
void StoreInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Label skip_store;
+
+ Register instance_reg = locs()->in(0).reg();
+
+ if (IsUnboxedStore() && compiler->is_optimizing()) {
+ UNIMPLEMENTED();
+ }
+
+ if (IsPotentialUnboxedStore()) {
+ const Register temp = locs()->temp(0).reg();
+ const Register temp2 = locs()->temp(1).reg();
+
+ Label store_pointer;
+ Label store_double;
+ Label store_float32x4;
+ Label store_float64x2;
+
+ __ LoadObject(temp, Field::ZoneHandle(field().raw()), PP);
+
+ __ LoadFieldFromOffset(temp2, temp, Field::is_nullable_offset());
+ __ CompareImmediate(temp2, kNullCid, PP);
+ __ b(&store_pointer, EQ);
+
+ __ LoadFromOffset(
+ temp2, temp, Field::kind_bits_offset() - kHeapObjectTag, kUnsignedByte);
+ __ tsti(temp2, 1 << Field::kUnboxingCandidateBit);
+ __ b(&store_pointer, EQ);
+
+ __ LoadFieldFromOffset(temp2, temp, Field::guarded_cid_offset());
+ __ CompareImmediate(temp2, kDoubleCid, PP);
+ __ b(&store_double, EQ);
+
+ __ LoadFieldFromOffset(temp2, temp, Field::guarded_cid_offset());
+ __ CompareImmediate(temp2, kFloat32x4Cid, PP);
+ __ b(&store_float32x4, EQ);
+
+ __ LoadFieldFromOffset(temp2, temp, Field::guarded_cid_offset());
+ __ CompareImmediate(temp2, kFloat64x2Cid, PP);
+ __ b(&store_float64x2, EQ);
+
+ // Fall through.
+ __ b(&store_pointer);
+
+ if (!compiler->is_optimizing()) {
+ locs()->live_registers()->Add(locs()->in(0));
+ locs()->live_registers()->Add(locs()->in(1));
+ }
+
+ // TODO(zra): Implement these when we add fpu loads and stores.
+ {
+ __ Bind(&store_double);
+ __ hlt(0); // Unimplemented.
+ }
+
+ {
+ __ Bind(&store_float32x4);
+ __ hlt(0); // Unimplemented.
+ }
+
+ {
+ __ Bind(&store_float64x2);
+ __ hlt(0); // Unimplemented.
+ }
+
+ __ Bind(&store_pointer);
+ }
+
+ if (ShouldEmitStoreBarrier()) {
+ Register value_reg = locs()->in(1).reg();
+ __ StoreIntoObject(instance_reg,
+ FieldAddress(instance_reg, offset_in_bytes_),
+ value_reg,
+ CanValueBeSmi());
+ } else {
+ if (locs()->in(1).IsConstant()) {
+ __ StoreIntoObjectNoBarrier(
+ instance_reg,
+ FieldAddress(instance_reg, offset_in_bytes_),
+ locs()->in(1).constant());
+ } else {
+ Register value_reg = locs()->in(1).reg();
+ __ StoreIntoObjectNoBarrier(instance_reg,
+ FieldAddress(instance_reg, offset_in_bytes_), value_reg);
+ }
+ }
+ __ Bind(&skip_store);
}
LocationSummary* LoadStaticFieldInstr::MakeLocationSummary(bool opt) const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresRegister());
+ summary->set_out(0, Location::RequiresRegister());
+ return summary;
}
+// When the parser is building an implicit static getter for optimization,
+// it can generate a function body where deoptimization ids do not line up
+// with the unoptimized code.
+//
+// This is safe only so long as LoadStaticFieldInstr cannot deoptimize.
void LoadStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Register field = locs()->in(0).reg();
+ Register result = locs()->out(0).reg();
+ __ LoadFieldFromOffset(result, field, Field::value_offset());
}
LocationSummary* StoreStaticFieldInstr::MakeLocationSummary(bool opt) const {
- UNIMPLEMENTED();
- return NULL;
+ LocationSummary* locs = new LocationSummary(1, 1, LocationSummary::kNoCall);
+ locs->set_in(0, value()->NeedsStoreBuffer() ? Location::WritableRegister()
+ : Location::RequiresRegister());
+ locs->set_temp(0, Location::RequiresRegister());
+ return locs;
}
void StoreStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Register value = locs()->in(0).reg();
+ Register temp = locs()->temp(0).reg();
+
+ __ LoadObject(temp, field(), PP);
+ if (this->value()->NeedsStoreBuffer()) {
+ __ StoreIntoObject(temp,
+ FieldAddress(temp, Field::value_offset()), value, CanValueBeSmi());
+ } else {
+ __ StoreIntoObjectNoBarrier(
+ temp, FieldAddress(temp, Field::value_offset()), value);
+ }
}
@@ -494,24 +1262,118 @@
LocationSummary* CreateArrayInstr::MakeLocationSummary(bool opt) const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 2;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
+ locs->set_in(kElementTypePos, Location::RegisterLocation(R1));
+ locs->set_in(kLengthPos, Location::RegisterLocation(R2));
+ locs->set_out(0, Location::RegisterLocation(R0));
+ return locs;
}
void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ // Allocate the array. R2 = length, R1 = element type.
+ ASSERT(locs()->in(kElementTypePos).reg() == R1);
+ ASSERT(locs()->in(kLengthPos).reg() == R2);
+ compiler->GenerateCall(token_pos(),
+ &StubCode::AllocateArrayLabel(),
+ PcDescriptors::kOther,
+ locs());
+ ASSERT(locs()->out(0).reg() == R0);
}
LocationSummary* LoadFieldInstr::MakeLocationSummary(bool opt) const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs =
+ new LocationSummary(
+ kNumInputs, kNumTemps,
+ (opt && !IsPotentialUnboxedLoad())
+ ? LocationSummary::kNoCall
+ : LocationSummary::kCallOnSlowPath);
+
+ locs->set_in(0, Location::RequiresRegister());
+
+ if (IsUnboxedLoad() && opt) {
+ // TODO(zra): Implement when we add fpu loads and stores.
+ UNIMPLEMENTED();
+ } else if (IsPotentialUnboxedLoad()) {
+ locs->AddTemp(Location::RequiresRegister());
+ }
+ locs->set_out(0, Location::RequiresRegister());
+ return locs;
}
void LoadFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Register instance_reg = locs()->in(0).reg();
+ if (IsUnboxedLoad() && compiler->is_optimizing()) {
+ UNIMPLEMENTED();
+ }
+
+ Label done;
+ Register result_reg = locs()->out(0).reg();
+ if (IsPotentialUnboxedLoad()) {
+ const Register temp = locs()->temp(0).reg();
+
+ Label load_pointer;
+ Label load_double;
+ Label load_float32x4;
+ Label load_float64x2;
+
+ __ LoadObject(result_reg, Field::ZoneHandle(field()->raw()), PP);
+
+ FieldAddress field_cid_operand(result_reg, Field::guarded_cid_offset());
+ FieldAddress field_nullability_operand(result_reg,
+ Field::is_nullable_offset());
+
+ __ ldr(temp, field_nullability_operand);
+ __ CompareImmediate(temp, kNullCid, PP);
+ __ b(&load_pointer, EQ);
+
+ __ ldr(temp, field_cid_operand);
+ __ CompareImmediate(temp, kDoubleCid, PP);
+ __ b(&load_double, EQ);
+
+ __ ldr(temp, field_cid_operand);
+ __ CompareImmediate(temp, kFloat32x4Cid, PP);
+ __ b(&load_float32x4, EQ);
+
+ __ ldr(temp, field_cid_operand);
+ __ CompareImmediate(temp, kFloat64x2Cid, PP);
+ __ b(&load_float64x2, EQ);
+
+ // Fall through.
+ __ b(&load_pointer);
+
+ if (!compiler->is_optimizing()) {
+ locs()->live_registers()->Add(locs()->in(0));
+ }
+
+ // TODO(zra): Implement these when we add fpu loads and stores.
+ {
+ __ Bind(&load_double);
+ __ hlt(0); // Unimplemented.
+ }
+
+ {
+ __ Bind(&load_float32x4);
+ __ hlt(0); // Unimplemented.
+ }
+
+ {
+ __ Bind(&load_float64x2);
+ __ hlt(0); // Unimplemented.
+ }
+
+ __ Bind(&load_pointer);
+ }
+ __ LoadFromOffset(
+ result_reg, instance_reg, offset_in_bytes() - kHeapObjectTag);
+ __ Bind(&done);
}
@@ -540,13 +1402,27 @@
LocationSummary* AllocateContextInstr::MakeLocationSummary(bool opt) const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 0;
+ const intptr_t kNumTemps = 1;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
+ locs->set_temp(0, Location::RegisterLocation(R1));
+ locs->set_out(0, Location::RegisterLocation(R0));
+ return locs;
}
void AllocateContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ ASSERT(locs()->temp(0).reg() == R1);
+ ASSERT(locs()->out(0).reg() == R0);
+
+ __ LoadImmediate(R1, num_context_variables(), PP);
+ const ExternalLabel label("alloc_context",
+ StubCode::AllocateContextEntryPoint());
+ compiler->GenerateCall(token_pos(),
+ &label,
+ PcDescriptors::kOther,
+ locs());
}
@@ -562,13 +1438,39 @@
LocationSummary* CatchBlockEntryInstr::MakeLocationSummary(bool opt) const {
- UNIMPLEMENTED();
+ UNREACHABLE();
return NULL;
}
void CatchBlockEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ __ Bind(compiler->GetJumpLabel(this));
+ compiler->AddExceptionHandler(catch_try_index(),
+ try_index(),
+ compiler->assembler()->CodeSize(),
+ catch_handler_types_,
+ needs_stacktrace());
+
+ // Restore the pool pointer.
+ __ LoadPoolPointer(PP);
+
+ if (HasParallelMove()) {
+ compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
+ }
+
+ // Restore SP from FP as we are coming from a throw and the code for
+ // popping arguments has not been run.
+ const intptr_t fp_sp_dist =
+ (kFirstLocalSlotFromFp + 1 - compiler->StackSize()) * kWordSize;
+ ASSERT(fp_sp_dist <= 0);
+ __ AddImmediate(SP, FP, fp_sp_dist, PP);
+
+ // Restore stack and initialize the two exception variables:
+ // exception and stack trace variables.
+ __ StoreToOffset(kExceptionObjectReg,
+ FP, exception_var().index() * kWordSize);
+ __ StoreToOffset(kStackTraceObjectReg,
+ FP, stacktrace_var().index() * kWordSize);
}
@@ -1390,13 +2292,18 @@
LocationSummary* ReThrowInstr::MakeLocationSummary(bool opt) const {
- UNIMPLEMENTED();
- return NULL;
+ return new LocationSummary(0, 0, LocationSummary::kCall);
}
void ReThrowInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ compiler->SetNeedsStacktrace(catch_try_index());
+ compiler->GenerateRuntimeCall(token_pos(),
+ deopt_id(),
+ kReThrowRuntimeEntry,
+ 2,
+ locs());
+ __ hlt(0);
}
@@ -1455,13 +2362,14 @@
LocationSummary* CurrentContextInstr::MakeLocationSummary(bool opt) const {
- UNIMPLEMENTED();
- return NULL;
+ return LocationSummary::Make(0,
+ Location::RequiresRegister(),
+ LocationSummary::kNoCall);
}
void CurrentContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ __ mov(locs()->out(0).reg(), CTX);
}
« no previous file with comments | « runtime/vm/compiler_test.cc ('k') | runtime/vm/simulator_arm64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698