Chromium Code Reviews| Index: runtime/vm/intermediate_language_arm.cc |
| =================================================================== |
| --- runtime/vm/intermediate_language_arm.cc (revision 21565) |
| +++ 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. |
|
zra
2013/04/16 21:12:29
This sounds a bit hack-y. How would I know what re
regis
2013/04/16 21:43:39
Agreed. As the comment explains (copied from the I
|
| + 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; |
|
zra
2013/04/16 21:12:29
Same here, I guess?
regis
2013/04/16 21:43:39
Yes. A1 on MIPS. As the TODO below indicates, we m
|
| + 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 |