| Index: runtime/vm/intermediate_language_arm.cc
|
| ===================================================================
|
| --- runtime/vm/intermediate_language_arm.cc (revision 21581)
|
| +++ runtime/vm/intermediate_language_arm.cc (working copy)
|
| @@ -128,11 +128,34 @@
|
|
|
|
|
| LocationSummary* ClosureCallInstr::MakeLocationSummary() const {
|
| - UNIMPLEMENTED();
|
| - return NULL;
|
| + const intptr_t kNumInputs = 0;
|
| + const intptr_t kNumTemps = 1;
|
| + LocationSummary* result =
|
| + new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
|
| + result->set_out(Location::RegisterLocation(R0));
|
| + result->set_temp(0, Location::RegisterLocation(R4)); // Arg. descriptor.
|
| + return result;
|
| }
|
|
|
|
|
| +void ClosureCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| + // The arguments to the stub include the closure, as does the arguments
|
| + // descriptor.
|
| + Register temp_reg = locs()->temp(0).reg();
|
| + int argument_count = ArgumentCount();
|
| + const Array& arguments_descriptor =
|
| + Array::ZoneHandle(ArgumentsDescriptor::New(argument_count,
|
| + argument_names()));
|
| + __ LoadObject(temp_reg, arguments_descriptor);
|
| + compiler->GenerateDartCall(deopt_id(),
|
| + token_pos(),
|
| + &StubCode::CallClosureFunctionLabel(),
|
| + PcDescriptors::kOther,
|
| + locs());
|
| + __ Drop(argument_count);
|
| +}
|
| +
|
| +
|
| LocationSummary* LoadLocalInstr::MakeLocationSummary() const {
|
| return LocationSummary::Make(0,
|
| Location::RequiresRegister(),
|
| @@ -842,57 +865,345 @@
|
|
|
|
|
| LocationSummary* StoreIndexedInstr::MakeLocationSummary() 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 kTypedDataInt16ArrayCid:
|
| + case kTypedDataUint16ArrayCid:
|
| + case kTypedDataInt32ArrayCid:
|
| + case kTypedDataUint32ArrayCid:
|
| + case kTypedDataFloat32ArrayCid:
|
| + case kTypedDataFloat64ArrayCid:
|
| + case kTypedDataFloat32x4ArrayCid:
|
| + 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);
|
| + if (IsExternal()) {
|
| + UNIMPLEMENTED();
|
| + } else {
|
| + ASSERT(this->array()->definition()->representation() == kTagged);
|
| + 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: {
|
| + __ mov(index.reg(), ShifterOperand(index.reg(), LSL, 1));
|
| + break;
|
| + }
|
| + case 8: {
|
| + __ mov(index.reg(), ShifterOperand(index.reg(), LSL, 2));
|
| + break;
|
| + }
|
| + case 16: {
|
| + __ mov(index.reg(), ShifterOperand(index.reg(), LSL, 3));
|
| + break;
|
| + }
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| + __ AddImmediate(index.reg(),
|
| + FlowGraphCompiler::DataOffsetFor(class_id()) - kHeapObjectTag);
|
| + element_address = Address(array, index.reg(), LSL, 0);
|
| + }
|
| +
|
| + 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 kTypedDataUint8ClampedArrayCid:
|
| + case kExternalTypedDataUint8ClampedArrayCid:
|
| + case kTypedDataInt16ArrayCid:
|
| + case kTypedDataUint16ArrayCid:
|
| + case kTypedDataInt32ArrayCid:
|
| + case kTypedDataUint32ArrayCid:
|
| + case kTypedDataFloat32ArrayCid:
|
| + case kTypedDataFloat64ArrayCid:
|
| + case kTypedDataFloat32x4ArrayCid:
|
| + UNIMPLEMENTED();
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| }
|
|
|
|
|
| LocationSummary* GuardFieldInstr::MakeLocationSummary() const {
|
| - UNIMPLEMENTED();
|
| - return NULL;
|
| + const intptr_t kNumInputs = 1;
|
| + LocationSummary* summary =
|
| + new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall);
|
| + summary->set_in(0, Location::RequiresRegister());
|
| + if ((value()->Type()->ToCid() == kDynamicCid) &&
|
| + (field().guarded_cid() != kSmiCid)) {
|
| + summary->AddTemp(Location::RequiresRegister());
|
| + }
|
| + if (field().guarded_cid() == kIllegalCid) {
|
| + 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;
|
| +
|
| + 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 = ((value_cid == kDynamicCid) &&
|
| + (field_cid != kSmiCid)) ? locs()->temp(0).reg() : kNoRegister;
|
| +
|
| + Register field_reg = (field_cid == kIllegalCid) ?
|
| + locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister;
|
| +
|
| + Label ok, fail_label;
|
| +
|
| + Label* deopt = compiler->is_optimizing() ?
|
| + compiler->AddDeoptStub(deopt_id(), kDeoptGuardField) : NULL;
|
| +
|
| + Label* fail = (deopt != NULL) ? deopt : &fail_label;
|
| +
|
| + const bool ok_is_fall_through = (deopt != NULL);
|
| +
|
| + if (!compiler->is_optimizing() || (field_cid == kIllegalCid)) {
|
| + if (!compiler->is_optimizing()) {
|
| + // 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()));
|
| +
|
| + FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset());
|
| + FieldAddress field_nullability_operand(
|
| + field_reg, Field::is_nullable_offset());
|
| +
|
| + if (value_cid == kDynamicCid) {
|
| + if (value_cid_reg == kNoRegister) {
|
| + ASSERT(!compiler->is_optimizing());
|
| + value_cid_reg = R3;
|
| + ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
|
| + }
|
| +
|
| + LoadValueCid(compiler, value_cid_reg, value_reg);
|
| +
|
| + __ ldr(IP, field_cid_operand);
|
| + __ cmp(value_cid_reg, ShifterOperand(IP));
|
| + __ b(&ok, EQ);
|
| + __ ldr(IP, field_nullability_operand);
|
| + __ cmp(value_cid_reg, ShifterOperand(IP));
|
| + } else if (value_cid == kNullCid) {
|
| + // TODO(regis): IP may conflict. Revisit.
|
| + __ ldr(IP, field_nullability_operand);
|
| + __ CompareImmediate(IP, value_cid);
|
| + } else {
|
| + // TODO(regis): IP may conflict. Revisit.
|
| + __ ldr(IP, field_cid_operand);
|
| + __ CompareImmediate(IP, value_cid);
|
| + }
|
| + __ b(&ok, EQ);
|
| +
|
| + __ ldr(IP, field_cid_operand);
|
| + __ CompareImmediate(IP, kIllegalCid);
|
| + __ b(fail, NE);
|
| +
|
| + if (value_cid == kDynamicCid) {
|
| + __ str(value_cid_reg, field_cid_operand);
|
| + __ str(value_cid_reg, field_nullability_operand);
|
| + } else {
|
| + __ LoadImmediate(IP, value_cid);
|
| + __ str(IP, field_cid_operand);
|
| + __ str(IP, field_nullability_operand);
|
| + }
|
| +
|
| + if (!ok_is_fall_through) {
|
| + __ b(&ok);
|
| + }
|
| + } else {
|
| + if (value_cid == kDynamicCid) {
|
| + // Field's guarded class id is fixed by value's class id is not known.
|
| + __ tst(value_reg, ShifterOperand(kSmiTagMask));
|
| +
|
| + if (field_cid != kSmiCid) {
|
| + __ b(fail, EQ);
|
| + __ LoadClassId(value_cid_reg, value_reg);
|
| + __ CompareImmediate(value_cid_reg, field_cid);
|
| + }
|
| +
|
| + if (field().is_nullable() && (field_cid != kNullCid)) {
|
| + __ b(&ok, EQ);
|
| + __ CompareImmediate(value_reg,
|
| + reinterpret_cast<intptr_t>(Object::null()));
|
| + }
|
| +
|
| + if (ok_is_fall_through) {
|
| + __ b(fail, NE);
|
| + } else {
|
| + __ b(&ok, EQ);
|
| + }
|
| + } else {
|
| + // Both value's and field's class id is known.
|
| + if ((value_cid != field_cid) && (value_cid != nullability)) {
|
| + if (ok_is_fall_through) {
|
| + __ b(fail);
|
| + }
|
| + } else {
|
| + // Nothing to emit.
|
| + ASSERT(!compiler->is_optimizing());
|
| + return;
|
| + }
|
| + }
|
| + }
|
| +
|
| + if (deopt == NULL) {
|
| + ASSERT(!compiler->is_optimizing());
|
| + __ Bind(fail);
|
| +
|
| + __ ldr(IP, FieldAddress(field_reg, Field::guarded_cid_offset()));
|
| + __ CompareImmediate(IP, kDynamicCid);
|
| + __ b(&ok, EQ);
|
| +
|
| + __ Push(field_reg);
|
| + __ Push(value_reg);
|
| + __ CallRuntime(kUpdateFieldCidRuntimeEntry);
|
| + __ Drop(2); // Drop the field and the value.
|
| + }
|
| +
|
| + __ Bind(&ok);
|
| }
|
|
|
|
|
| LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const {
|
| - UNIMPLEMENTED();
|
| - return NULL;
|
| + const intptr_t kNumInputs = 2;
|
| + const intptr_t num_temps = 0;
|
| + LocationSummary* summary =
|
| + new LocationSummary(kNumInputs, num_temps, LocationSummary::kNoCall);
|
| + summary->set_in(0, Location::RequiresRegister());
|
| + summary->set_in(1, ShouldEmitStoreBarrier()
|
| + ? Location::WritableRegister()
|
| + : Location::RegisterOrConstant(value()));
|
| + return summary;
|
| }
|
|
|
|
|
| void StoreInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| - UNIMPLEMENTED();
|
| + Register instance_reg = locs()->in(0).reg();
|
| + if (ShouldEmitStoreBarrier()) {
|
| + Register value_reg = locs()->in(1).reg();
|
| + __ StoreIntoObject(instance_reg,
|
| + FieldAddress(instance_reg, field().Offset()),
|
| + value_reg,
|
| + CanValueBeSmi());
|
| + } else {
|
| + if (locs()->in(1).IsConstant()) {
|
| + __ StoreIntoObjectNoBarrier(
|
| + instance_reg,
|
| + FieldAddress(instance_reg, field().Offset()),
|
| + locs()->in(1).constant());
|
| + } else {
|
| + Register value_reg = locs()->in(1).reg();
|
| + __ StoreIntoObjectNoBarrier(instance_reg,
|
| + FieldAddress(instance_reg, field().Offset()), value_reg);
|
| + }
|
| + }
|
| }
|
|
|
|
|
| LocationSummary* LoadStaticFieldInstr::MakeLocationSummary() const {
|
| - UNIMPLEMENTED();
|
| - return NULL;
|
| + return LocationSummary::Make(0,
|
| + Location::RequiresRegister(),
|
| + LocationSummary::kNoCall);
|
| }
|
|
|
|
|
| void LoadStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| - UNIMPLEMENTED();
|
| + Register result = locs()->out().reg();
|
| + __ LoadObject(result, field());
|
| + __ LoadFromOffset(kLoadWord, result,
|
| + result, Field::value_offset() - kHeapObjectTag);
|
| }
|
|
|
|
|
| LocationSummary* StoreStaticFieldInstr::MakeLocationSummary() 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());
|
| + if (this->value()->NeedsStoreBuffer()) {
|
| + __ StoreIntoObject(temp,
|
| + FieldAddress(temp, Field::value_offset()), value, CanValueBeSmi());
|
| + } else {
|
| + __ StoreIntoObjectNoBarrier(
|
| + temp, FieldAddress(temp, Field::value_offset()), value);
|
| + }
|
| }
|
|
|
|
|
| @@ -908,13 +1219,25 @@
|
|
|
|
|
| LocationSummary* CreateArrayInstr::MakeLocationSummary() const {
|
| - UNIMPLEMENTED();
|
| - return NULL;
|
| + const intptr_t kNumInputs = 1;
|
| + const intptr_t kNumTemps = 0;
|
| + LocationSummary* locs =
|
| + new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
|
| + locs->set_in(0, Location::RegisterLocation(R1));
|
| + locs->set_out(Location::RegisterLocation(R0));
|
| + return locs;
|
| }
|
|
|
|
|
| void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| - UNIMPLEMENTED();
|
| + // Allocate the array. R2 = length, R1 = element type.
|
| + ASSERT(locs()->in(0).reg() == R1);
|
| + __ LoadImmediate(R2, Smi::RawValue(num_elements()));
|
| + compiler->GenerateCall(token_pos(),
|
| + &StubCode::AllocateArrayLabel(),
|
| + PcDescriptors::kOther,
|
| + locs());
|
| + ASSERT(locs()->out().reg() == R0);
|
| }
|
|
|
|
|
| @@ -932,51 +1255,202 @@
|
|
|
|
|
| LocationSummary* LoadFieldInstr::MakeLocationSummary() const {
|
| - UNIMPLEMENTED();
|
| - return NULL;
|
| + return LocationSummary::Make(1,
|
| + Location::RequiresRegister(),
|
| + LocationSummary::kNoCall);
|
| }
|
|
|
|
|
| void LoadFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| - UNIMPLEMENTED();
|
| + Register instance_reg = locs()->in(0).reg();
|
| + Register result_reg = locs()->out().reg();
|
| +
|
| + __ LoadFromOffset(kLoadWord, result_reg,
|
| + instance_reg, offset_in_bytes() - kHeapObjectTag);
|
| }
|
|
|
|
|
| LocationSummary* InstantiateTypeArgumentsInstr::MakeLocationSummary() const {
|
| - UNIMPLEMENTED();
|
| - return NULL;
|
| + const intptr_t kNumInputs = 1;
|
| + const intptr_t kNumTemps = 1;
|
| + LocationSummary* locs =
|
| + new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
|
| + locs->set_in(0, Location::RegisterLocation(R0));
|
| + locs->set_temp(0, Location::RegisterLocation(R1));
|
| + locs->set_out(Location::RegisterLocation(R0));
|
| + return locs;
|
| }
|
|
|
|
|
| void InstantiateTypeArgumentsInstr::EmitNativeCode(
|
| FlowGraphCompiler* compiler) {
|
| - UNIMPLEMENTED();
|
| + Register instantiator_reg = locs()->in(0).reg();
|
| + Register temp = locs()->temp(0).reg();
|
| + Register result_reg = locs()->out().reg();
|
| +
|
| + // 'instantiator_reg' is the instantiator AbstractTypeArguments object
|
| + // (or null).
|
| + // If the instantiator is null and if the type argument vector
|
| + // instantiated from null becomes a vector of dynamic, then use null as
|
| + // the type arguments.
|
| + Label type_arguments_instantiated;
|
| + const intptr_t len = type_arguments().Length();
|
| + if (type_arguments().IsRawInstantiatedRaw(len)) {
|
| + __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null()));
|
| + __ cmp(instantiator_reg, ShifterOperand(IP));
|
| + __ b(&type_arguments_instantiated, EQ);
|
| + }
|
| + // Instantiate non-null type arguments.
|
| + if (type_arguments().IsUninstantiatedIdentity()) {
|
| + // Check if the instantiator type argument vector is a TypeArguments of a
|
| + // matching length and, if so, use it as the instantiated type_arguments.
|
| + // No need to check the instantiator ('instantiator_reg') for null here,
|
| + // because a null instantiator will have the wrong class (Null instead of
|
| + // TypeArguments).
|
| + Label type_arguments_uninstantiated;
|
| + __ CompareClassId(instantiator_reg, kTypeArgumentsCid, temp);
|
| + __ b(&type_arguments_uninstantiated, NE);
|
| + __ ldr(temp,
|
| + FieldAddress(instantiator_reg, TypeArguments::length_offset()));
|
| + __ CompareImmediate(temp, Smi::RawValue(len));
|
| + __ b(&type_arguments_instantiated, EQ);
|
| + __ Bind(&type_arguments_uninstantiated);
|
| + }
|
| + // A runtime call to instantiate the type arguments is required.
|
| + __ PushObject(Object::ZoneHandle()); // Make room for the result.
|
| + __ PushObject(type_arguments());
|
| + __ Push(instantiator_reg); // Push instantiator type arguments.
|
| + compiler->GenerateCallRuntime(token_pos(),
|
| + deopt_id(),
|
| + kInstantiateTypeArgumentsRuntimeEntry,
|
| + locs());
|
| + __ Drop(2); // Drop instantiator and uninstantiated type arguments.
|
| + __ Pop(result_reg); // Pop instantiated type arguments.
|
| + __ Bind(&type_arguments_instantiated);
|
| + ASSERT(instantiator_reg == result_reg);
|
| + // 'result_reg': Instantiated type arguments.
|
| }
|
|
|
|
|
| LocationSummary*
|
| ExtractConstructorTypeArgumentsInstr::MakeLocationSummary() const {
|
| - UNIMPLEMENTED();
|
| - return NULL;
|
| + const intptr_t kNumInputs = 1;
|
| + const intptr_t kNumTemps = 1;
|
| + LocationSummary* locs =
|
| + new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
| + locs->set_in(0, Location::RequiresRegister());
|
| + locs->set_out(Location::SameAsFirstInput());
|
| + locs->set_temp(0, Location::RequiresRegister());
|
| + return locs;
|
| }
|
|
|
|
|
| void ExtractConstructorTypeArgumentsInstr::EmitNativeCode(
|
| FlowGraphCompiler* compiler) {
|
| - UNIMPLEMENTED();
|
| + Register instantiator_reg = locs()->in(0).reg();
|
| + Register result_reg = locs()->out().reg();
|
| + ASSERT(instantiator_reg == result_reg);
|
| + Register temp_reg = locs()->temp(0).reg();
|
| +
|
| + // instantiator_reg is the instantiator type argument vector, i.e. an
|
| + // AbstractTypeArguments object (or null).
|
| + // If the instantiator is null and if the type argument vector
|
| + // instantiated from null becomes a vector of dynamic, then use null as
|
| + // the type arguments.
|
| + Label type_arguments_instantiated;
|
| + const intptr_t len = type_arguments().Length();
|
| + if (type_arguments().IsRawInstantiatedRaw(len)) {
|
| + __ CompareImmediate(instantiator_reg,
|
| + reinterpret_cast<intptr_t>(Object::null()));
|
| + __ b(&type_arguments_instantiated, EQ);
|
| + }
|
| + // Instantiate non-null type arguments.
|
| + if (type_arguments().IsUninstantiatedIdentity()) {
|
| + // Check if the instantiator type argument vector is a TypeArguments of a
|
| + // matching length and, if so, use it as the instantiated type_arguments.
|
| + // No need to check instantiator_reg for null here, because a null
|
| + // instantiator will have the wrong class (Null instead of TypeArguments).
|
| + Label type_arguments_uninstantiated;
|
| + __ CompareClassId(instantiator_reg, kTypeArgumentsCid, temp_reg);
|
| + __ b(&type_arguments_uninstantiated, NE);
|
| + __ ldr(temp_reg,
|
| + FieldAddress(instantiator_reg, TypeArguments::length_offset()));
|
| + __ CompareImmediate(temp_reg, Smi::RawValue(type_arguments().Length()));
|
| + __ b(&type_arguments_instantiated, EQ);
|
| + __ Bind(&type_arguments_uninstantiated);
|
| + }
|
| + // In the non-factory case, we rely on the allocation stub to
|
| + // instantiate the type arguments.
|
| + __ LoadObject(result_reg, type_arguments());
|
| + // result_reg: uninstantiated type arguments.
|
| + __ Bind(&type_arguments_instantiated);
|
| + // result_reg: uninstantiated or instantiated type arguments.
|
| }
|
|
|
|
|
| LocationSummary*
|
| ExtractConstructorInstantiatorInstr::MakeLocationSummary() const {
|
| - UNIMPLEMENTED();
|
| - return NULL;
|
| + const intptr_t kNumInputs = 1;
|
| + const intptr_t kNumTemps = 1;
|
| + LocationSummary* locs =
|
| + new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
|
| + locs->set_in(0, Location::RequiresRegister());
|
| + locs->set_out(Location::SameAsFirstInput());
|
| + locs->set_temp(0, Location::RequiresRegister());
|
| + return locs;
|
| }
|
|
|
|
|
| void ExtractConstructorInstantiatorInstr::EmitNativeCode(
|
| FlowGraphCompiler* compiler) {
|
| - UNIMPLEMENTED();
|
| + Register instantiator_reg = locs()->in(0).reg();
|
| + ASSERT(locs()->out().reg() == instantiator_reg);
|
| + Register temp_reg = locs()->temp(0).reg();
|
| +
|
| + // instantiator_reg is the instantiator AbstractTypeArguments object
|
| + // (or null). If the instantiator is null and if the type argument vector
|
| + // instantiated from null becomes a vector of dynamic, then use null as
|
| + // the type arguments and do not pass the instantiator.
|
| + Label done;
|
| + const intptr_t len = type_arguments().Length();
|
| + if (type_arguments().IsRawInstantiatedRaw(len)) {
|
| + Label instantiator_not_null;
|
| + __ CompareImmediate(instantiator_reg,
|
| + reinterpret_cast<intptr_t>(Object::null()));
|
| + __ b(&instantiator_not_null, NE);
|
| + // Null was used in VisitExtractConstructorTypeArguments as the
|
| + // instantiated type arguments, no proper instantiator needed.
|
| + __ LoadImmediate(instantiator_reg,
|
| + Smi::RawValue(StubCode::kNoInstantiator));
|
| + __ b(&done);
|
| + __ Bind(&instantiator_not_null);
|
| + }
|
| + // Instantiate non-null type arguments.
|
| + if (type_arguments().IsUninstantiatedIdentity()) {
|
| + // TODO(regis): The following emitted code is duplicated in
|
| + // VisitExtractConstructorTypeArguments above. The reason is that the code
|
| + // is split between two computations, so that each one produces a
|
| + // single value, rather than producing a pair of values.
|
| + // If this becomes an issue, we should expose these tests at the IL level.
|
| +
|
| + // Check if the instantiator type argument vector is a TypeArguments of a
|
| + // matching length and, if so, use it as the instantiated type_arguments.
|
| + // No need to check the instantiator ('instantiator_reg') for null here,
|
| + // because a null instantiator will have the wrong class (Null instead of
|
| + // TypeArguments).
|
| + __ CompareClassId(instantiator_reg, kTypeArgumentsCid, temp_reg);
|
| + __ b(&done, NE);
|
| + __ ldr(temp_reg,
|
| + FieldAddress(instantiator_reg, TypeArguments::length_offset()));
|
| + __ CompareImmediate(temp_reg, Smi::RawValue(type_arguments().Length()));
|
| + __ b(&done, NE);
|
| + // The instantiator was used in VisitExtractConstructorTypeArguments as the
|
| + // instantiated type arguments, no proper instantiator needed.
|
| + __ LoadImmediate(instantiator_reg,
|
| + Smi::RawValue(StubCode::kNoInstantiator));
|
| + }
|
| + __ Bind(&done);
|
| + // instantiator_reg: instantiator or kNoInstantiator.
|
| }
|
|
|
|
|
| @@ -1559,14 +2033,17 @@
|
|
|
|
|
| LocationSummary* ThrowInstr::MakeLocationSummary() const {
|
| - UNIMPLEMENTED();
|
| - return NULL;
|
| + return new LocationSummary(0, 0, LocationSummary::kCall);
|
| }
|
|
|
|
|
|
|
| void ThrowInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| - UNIMPLEMENTED();
|
| + compiler->GenerateCallRuntime(token_pos(),
|
| + deopt_id(),
|
| + kThrowRuntimeEntry,
|
| + locs());
|
| + __ bkpt(0);
|
| }
|
|
|
|
|
| @@ -1657,13 +2134,14 @@
|
|
|
|
|
| LocationSummary* CurrentContextInstr::MakeLocationSummary() const {
|
| - UNIMPLEMENTED();
|
| - return NULL;
|
| + return LocationSummary::Make(0,
|
| + Location::RequiresRegister(),
|
| + LocationSummary::kNoCall);
|
| }
|
|
|
|
|
| void CurrentContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| - UNIMPLEMENTED();
|
| + __ mov(locs()->out().reg(), ShifterOperand(CTX));
|
| }
|
|
|
|
|
| @@ -1750,11 +2228,6 @@
|
| }
|
|
|
|
|
| -void ClosureCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| - UNIMPLEMENTED();
|
| -}
|
| -
|
| -
|
| LocationSummary* BooleanNegateInstr::MakeLocationSummary() const {
|
| UNIMPLEMENTED();
|
| return NULL;
|
| @@ -1806,13 +2279,21 @@
|
|
|
|
|
| LocationSummary* CreateClosureInstr::MakeLocationSummary() const {
|
| - UNIMPLEMENTED();
|
| - return NULL;
|
| + return MakeCallSummary();
|
| }
|
|
|
|
|
| void CreateClosureInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
| - UNIMPLEMENTED();
|
| + const Function& closure_function = function();
|
| + ASSERT(!closure_function.IsImplicitStaticClosureFunction());
|
| + const Code& stub = Code::Handle(
|
| + StubCode::GetAllocationStubForClosure(closure_function));
|
| + const ExternalLabel label(closure_function.ToCString(), stub.EntryPoint());
|
| + compiler->GenerateCall(token_pos(),
|
| + &label,
|
| + PcDescriptors::kOther,
|
| + locs());
|
| + __ Drop(2); // Discard type arguments and receiver.
|
| }
|
|
|
| } // namespace dart
|
|
|