Index: runtime/vm/intermediate_language_dbc.cc |
diff --git a/runtime/vm/intermediate_language_dbc.cc b/runtime/vm/intermediate_language_dbc.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..7f533e697f2c3ca74d9714b84d57a7dee6af3cd6 |
--- /dev/null |
+++ b/runtime/vm/intermediate_language_dbc.cc |
@@ -0,0 +1,704 @@ |
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+#include "vm/globals.h" // Needed here to get TARGET_ARCH_DBC. |
+#if defined(TARGET_ARCH_DBC) |
+ |
+#include "vm/intermediate_language.h" |
+ |
+#include "vm/cpu.h" |
+#include "vm/compiler.h" |
+#include "vm/dart_entry.h" |
+#include "vm/flow_graph.h" |
+#include "vm/flow_graph_compiler.h" |
+#include "vm/flow_graph_range_analysis.h" |
+#include "vm/locations.h" |
+#include "vm/object_store.h" |
+#include "vm/parser.h" |
+#include "vm/simulator.h" |
+#include "vm/stack_frame.h" |
+#include "vm/stub_code.h" |
+#include "vm/symbols.h" |
+ |
+#define __ compiler->assembler()-> |
+ |
+namespace dart { |
+ |
+DECLARE_FLAG(bool, allow_absolute_addresses); |
+DECLARE_FLAG(bool, emit_edge_counters); |
+DECLARE_FLAG(int, optimization_counter_threshold); |
+ |
+// List of instructions that are still unimplemented by DBC backend. |
+#define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M) \ |
+ M(Stop) \ |
+ M(IndirectGoto) \ |
+ M(LoadCodeUnits) \ |
+ M(InstanceOf) \ |
+ M(LoadUntagged) \ |
+ M(AllocateUninitializedContext) \ |
+ M(BinaryInt32Op) \ |
+ M(UnarySmiOp) \ |
+ M(UnaryDoubleOp) \ |
+ M(SmiToDouble) \ |
+ M(Int32ToDouble) \ |
+ M(MintToDouble) \ |
+ M(DoubleToInteger) \ |
+ M(DoubleToSmi) \ |
+ M(DoubleToDouble) \ |
+ M(DoubleToFloat) \ |
+ M(FloatToDouble) \ |
+ M(UnboxedConstant) \ |
+ M(CheckEitherNonSmi) \ |
+ M(BinaryDoubleOp) \ |
+ M(MathUnary) \ |
+ M(MathMinMax) \ |
+ M(Box) \ |
+ M(Unbox) \ |
+ M(BoxInt64) \ |
+ M(CaseInsensitiveCompareUC16) \ |
+ M(BinaryMintOp) \ |
+ M(ShiftMintOp) \ |
+ M(UnaryMintOp) \ |
+ M(StringToCharCode) \ |
+ M(StringFromCharCode) \ |
+ M(InvokeMathCFunction) \ |
+ M(MergedMath) \ |
+ M(GuardFieldClass) \ |
+ M(GuardFieldLength) \ |
+ M(IfThenElse) \ |
+ M(BinaryFloat32x4Op) \ |
+ M(Simd32x4Shuffle) \ |
+ M(Simd32x4ShuffleMix) \ |
+ M(Simd32x4GetSignMask) \ |
+ M(Float32x4Constructor) \ |
+ M(Float32x4Zero) \ |
+ M(Float32x4Splat) \ |
+ M(Float32x4Comparison) \ |
+ M(Float32x4MinMax) \ |
+ M(Float32x4Scale) \ |
+ M(Float32x4Sqrt) \ |
+ M(Float32x4ZeroArg) \ |
+ M(Float32x4Clamp) \ |
+ M(Float32x4With) \ |
+ M(Float32x4ToInt32x4) \ |
+ M(Int32x4Constructor) \ |
+ M(Int32x4BoolConstructor) \ |
+ M(Int32x4GetFlag) \ |
+ M(Int32x4Select) \ |
+ M(Int32x4SetFlag) \ |
+ M(Int32x4ToFloat32x4) \ |
+ M(BinaryInt32x4Op) \ |
+ M(TestCids) \ |
+ M(BinaryFloat64x2Op) \ |
+ M(Float64x2Zero) \ |
+ M(Float64x2Constructor) \ |
+ M(Float64x2Splat) \ |
+ M(Float32x4ToFloat64x2) \ |
+ M(Float64x2ToFloat32x4) \ |
+ M(Simd64x2Shuffle) \ |
+ M(Float64x2ZeroArg) \ |
+ M(Float64x2OneArg) \ |
+ M(ExtractNthOutput) \ |
+ M(BinaryUint32Op) \ |
+ M(ShiftUint32Op) \ |
+ M(UnaryUint32Op) \ |
+ M(UnboxedIntConverter) \ |
+ M(GrowRegExpStack) \ |
+ M(BoxInteger32) \ |
+ M(UnboxInteger32) \ |
+ M(CheckedSmiOp) \ |
+ M(CheckArrayBound) \ |
+ M(CheckSmi) \ |
+ M(LoadClassId) \ |
+ M(CheckClassId) \ |
+ M(CheckClass) \ |
+ M(BinarySmiOp) \ |
+ M(TestSmi) \ |
+ M(RelationalOp) \ |
+ M(EqualityCompare) \ |
+ M(LoadIndexed) \ |
+// Location summaries actually are not used by the unoptimizing DBC compiler |
+// because we don't allocate any registers. |
+static LocationSummary* CreateLocationSummary(Zone* zone, |
+ intptr_t num_inputs, |
+ bool has_result) { |
+ const intptr_t kNumTemps = 0; |
+ LocationSummary* locs = new(zone) LocationSummary( |
+ zone, num_inputs, kNumTemps, LocationSummary::kNoCall); |
+ for (intptr_t i = 0; i < num_inputs; i++) { |
+ locs->set_in(i, Location::RequiresRegister()); |
+ } |
+ if (has_result) { |
+ locs->set_out(0, Location::RequiresRegister()); |
+ } |
+ return locs; |
+} |
+ |
+ |
+#define DEFINE_MAKE_LOCATION_SUMMARY(Name, In, Out) \ |
+ LocationSummary* Name##Instr::MakeLocationSummary(Zone* zone, bool opt) \ |
+ const { \ |
+ return CreateLocationSummary(zone, In, Out); \ |
+ } \ |
+ |
+#define EMIT_NATIVE_CODE(Name, In, Out) \ |
+ DEFINE_MAKE_LOCATION_SUMMARY(Name, In, Out); \ |
+ void Name##Instr::EmitNativeCode(FlowGraphCompiler* compiler) \ |
+ |
+#define DEFINE_UNIMPLEMENTED_MAKE_LOCATION_SUMMARY(Name) \ |
+ LocationSummary* Name##Instr::MakeLocationSummary(Zone* zone, bool opt) \ |
+ const { \ |
+ UNIMPLEMENTED(); \ |
+ return NULL; \ |
+ } \ |
+ |
+#define DEFINE_UNIMPLEMENTED_EMIT_NATIVE_CODE(Name) \ |
+ void Name##Instr::EmitNativeCode(FlowGraphCompiler* compiler) { \ |
+ UNIMPLEMENTED(); \ |
+ } |
+ |
+#define DEFINE_UNIMPLEMENTED_EMIT_BRANCH_CODE(Name) \ |
+ void Name##Instr::EmitBranchCode(FlowGraphCompiler*, BranchInstr*) { \ |
+ UNIMPLEMENTED(); \ |
+ } \ |
+ Condition Name##Instr::EmitComparisonCode(FlowGraphCompiler*, \ |
+ BranchLabels) { \ |
+ UNIMPLEMENTED(); \ |
+ return EQ; \ |
+ } |
+ |
+#define DEFINE_UNIMPLEMENTED(Name) \ |
+ DEFINE_UNIMPLEMENTED_MAKE_LOCATION_SUMMARY(Name) \ |
+ DEFINE_UNIMPLEMENTED_EMIT_NATIVE_CODE(Name) \ |
+ |
+FOR_EACH_UNIMPLEMENTED_INSTRUCTION(DEFINE_UNIMPLEMENTED) |
+ |
+#undef DEFINE_UNIMPLEMENTED |
+ |
+DEFINE_UNIMPLEMENTED_EMIT_BRANCH_CODE(TestCids) |
+DEFINE_UNIMPLEMENTED_EMIT_BRANCH_CODE(TestSmi) |
+DEFINE_UNIMPLEMENTED_EMIT_BRANCH_CODE(RelationalOp) |
+DEFINE_UNIMPLEMENTED_EMIT_BRANCH_CODE(EqualityCompare) |
+ |
+ |
+DEFINE_MAKE_LOCATION_SUMMARY(AssertAssignable, 2, true); |
+ |
+ |
+EMIT_NATIVE_CODE(AssertBoolean, 1, true) { |
+ __ AssertBoolean(Isolate::Current()->type_checks() ? 1 : 0); |
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, |
+ deopt_id(), |
+ token_pos()); |
+} |
+ |
+ |
+LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary(Zone* zone, |
+ bool optimizing) const { |
+ return MakeCallSummary(zone); |
+} |
+ |
+ |
+void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
+ UNIMPLEMENTED(); |
+} |
+ |
+ |
+EMIT_NATIVE_CODE(CheckStackOverflow, 0, false) { |
+ __ CheckStack(); |
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, |
+ Thread::kNoDeoptId, |
+ token_pos()); |
+} |
+ |
+ |
+EMIT_NATIVE_CODE(PushArgument, 1, false) { |
+ if (compiler->is_optimizing()) { |
+ __ Push(locs()->in(0).reg()); |
+ } |
+} |
+ |
+ |
+EMIT_NATIVE_CODE(LoadLocal, 0, false) { |
+ ASSERT(!compiler->is_optimizing()); |
+ ASSERT(local().index() != 0); |
+ __ Push((local().index() > 0) ? (-local().index()) : (-local().index() - 1)); |
+} |
+ |
+ |
+EMIT_NATIVE_CODE(StoreLocal, 0, false) { |
+ ASSERT(!compiler->is_optimizing()); |
+ ASSERT(local().index() != 0); |
+ if (HasTemp()) { |
+ __ StoreLocal( |
+ (local().index() > 0) ? (-local().index()) : (-local().index() - 1)); |
+ } else { |
+ __ PopLocal( |
+ (local().index() > 0) ? (-local().index()) : (-local().index() - 1)); |
+ } |
+} |
+ |
+ |
+EMIT_NATIVE_CODE(Constant, 0, true) { |
+ const intptr_t kidx = __ AddConstant(value()); |
+ if (compiler->is_optimizing()) { |
+ __ LoadConstant(locs()->out(0).reg(), kidx); |
+ } else { |
+ __ PushConstant(kidx); |
+ } |
+} |
+ |
+ |
+EMIT_NATIVE_CODE(Return, 1, false) { |
+ __ ReturnTOS(); |
+} |
+ |
+ |
+EMIT_NATIVE_CODE(StoreStaticField, 1, false) { |
+ const intptr_t kidx = __ AddConstant(field()); |
+ __ StoreStaticTOS(kidx); |
+} |
+ |
+ |
+EMIT_NATIVE_CODE(LoadStaticField, 1, true) { |
+ const intptr_t kidx = __ AddConstant(StaticField()); |
+ __ PushStatic(kidx); |
+} |
+ |
+ |
+EMIT_NATIVE_CODE(InitStaticField, 0, false) { |
+ ASSERT(!compiler->is_optimizing()); |
+ __ InitStaticTOS(); |
+} |
+ |
+ |
+EMIT_NATIVE_CODE(ClosureCall, 0, false) { |
+ intptr_t argument_count = ArgumentCount(); |
+ const Array& arguments_descriptor = |
+ Array::ZoneHandle(ArgumentsDescriptor::New(argument_count, |
+ argument_names())); |
+ const intptr_t argdesc_kidx = |
+ compiler->assembler()->AddConstant(arguments_descriptor); |
+ __ StaticCall(argument_count, argdesc_kidx); |
+ |
+ 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 = Thread::ToDeoptAfter(deopt_id()); |
+ if (compiler->is_optimizing()) { |
+ compiler->AddDeoptIndexAtCall(deopt_id_after, token_pos()); |
+ } |
+ // Add deoptimization continuation point after the call and before the |
+ // arguments are removed. |
+ // In optimized code this descriptor is needed for exception handling. |
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt, |
+ deopt_id_after, |
+ token_pos()); |
+} |
+ |
+ |
+static void EmitBranchOnCondition(FlowGraphCompiler* compiler, |
+ Condition true_condition, |
+ BranchLabels labels) { |
+ if (labels.fall_through == labels.false_label) { |
+ // If the next block is the false successor, fall through to it. |
+ __ Jump(labels.true_label); |
+ } else { |
+ // If the next block is not the false successor, branch to it. |
+ __ Jump(labels.false_label); |
+ |
+ // Fall through or jump to the true successor. |
+ if (labels.fall_through != labels.true_label) { |
+ __ Jump(labels.true_label); |
+ } |
+ } |
+} |
+ |
+ |
+Condition StrictCompareInstr::EmitComparisonCode(FlowGraphCompiler* compiler, |
+ BranchLabels labels) { |
+ ASSERT((kind() == Token::kNE_STRICT) || |
+ (kind() == Token::kEQ_STRICT)); |
+ const Bytecode::Opcode eq_op = needs_number_check() ? |
+ Bytecode::kIfEqStrictNumTOS : Bytecode::kIfEqStrictTOS; |
+ const Bytecode::Opcode ne_op = needs_number_check() ? |
+ Bytecode::kIfNeStrictNumTOS : Bytecode::kIfNeStrictTOS; |
+ |
+ if (kind() == Token::kEQ_STRICT) { |
+ __ Emit((labels.fall_through == labels.false_label) ? eq_op : ne_op); |
+ } else { |
+ __ Emit((labels.fall_through == labels.false_label) ? ne_op : eq_op); |
+ } |
+ |
+ if (needs_number_check() && token_pos().IsReal()) { |
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, |
+ Thread::kNoDeoptId, |
+ token_pos()); |
+ } |
+ return EQ; |
+} |
+ |
+ |
+void StrictCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
+ BranchInstr* branch) { |
+ ASSERT((kind() == Token::kEQ_STRICT) || |
+ (kind() == Token::kNE_STRICT)); |
+ |
+ BranchLabels labels = compiler->CreateBranchLabels(branch); |
+ Condition true_condition = EmitComparisonCode(compiler, labels); |
+ EmitBranchOnCondition(compiler, true_condition, labels); |
+} |
+ |
+ |
+EMIT_NATIVE_CODE(StrictCompare, 2, true) { |
+ ASSERT((kind() == Token::kEQ_STRICT) || |
+ (kind() == Token::kNE_STRICT)); |
+ |
+ Label is_true, is_false; |
+ BranchLabels labels = { &is_true, &is_false, &is_false }; |
+ Condition true_condition = EmitComparisonCode(compiler, labels); |
+ EmitBranchOnCondition(compiler, true_condition, labels); |
+ Label done; |
+ __ Bind(&is_false); |
+ __ PushConstant(Bool::False()); |
+ __ Jump(&done); |
+ __ Bind(&is_true); |
+ __ PushConstant(Bool::True()); |
+ __ Bind(&done); |
+} |
+ |
+ |
+LocationSummary* BranchInstr::MakeLocationSummary(Zone* zone, |
+ bool opt) const { |
+ comparison()->InitializeLocationSummary(zone, opt); |
+ // Branches don't produce a result. |
+ comparison()->locs()->set_out(0, Location::NoLocation()); |
+ return comparison()->locs(); |
+} |
+ |
+ |
+void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
+ comparison()->EmitBranchCode(compiler, this); |
+} |
+ |
+ |
+EMIT_NATIVE_CODE(Goto, 0, false) { |
+ if (HasParallelMove()) { |
+ compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); |
+ } |
+ // We can fall through if the successor is the next block in the list. |
+ // Otherwise, we need a jump. |
+ if (!compiler->CanFallThroughTo(successor())) { |
+ __ Jump(compiler->GetJumpLabel(successor())); |
+ } |
+} |
+ |
+ |
+EMIT_NATIVE_CODE(CreateArray, 2, true) { |
+ __ CreateArrayTOS(); |
+} |
+ |
+ |
+EMIT_NATIVE_CODE(StoreIndexed, 3, false) { |
+ ASSERT(class_id() == kArrayCid); |
+ __ StoreIndexedTOS(); |
+} |
+ |
+ |
+EMIT_NATIVE_CODE(StringInterpolate, 0, false) { |
+ const intptr_t kArgumentCount = 1; |
+ const Array& arguments_descriptor = Array::Handle( |
+ ArgumentsDescriptor::New(kArgumentCount, Object::null_array())); |
+ __ PushConstant(CallFunction()); |
+ const intptr_t argdesc_kidx = __ AddConstant(arguments_descriptor); |
+ __ StaticCall(kArgumentCount, argdesc_kidx); |
+} |
+ |
+ |
+EMIT_NATIVE_CODE(NativeCall, 0, false) { |
+ SetupNative(); |
+ |
+ const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function()); |
+ |
+ ASSERT(!link_lazily()); |
+ const ExternalLabel label(reinterpret_cast<uword>(native_c_function())); |
+ const intptr_t target_kidx = |
+ __ object_pool_wrapper().FindImmediate(label.address()); |
+ const intptr_t argc_tag_kidx = |
+ __ object_pool_wrapper().FindImmediate(static_cast<uword>(argc_tag)); |
+ __ PushConstant(target_kidx); |
+ __ PushConstant(argc_tag_kidx); |
+ if (is_bootstrap_native()) { |
+ __ NativeBootstrapCall(); |
+ } else { |
+ __ NativeCall(); |
+ } |
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, |
+ Thread::kNoDeoptId, |
+ token_pos()); |
+} |
+ |
+ |
+EMIT_NATIVE_CODE(AllocateObject, 0, true) { |
+ if (ArgumentCount() == 1) { |
+ __ PushConstant(cls()); |
+ __ AllocateT(); |
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, |
+ Thread::kNoDeoptId, |
+ token_pos()); |
+ } else { |
+ const intptr_t kidx = __ AddConstant(cls()); |
+ __ Allocate(kidx); |
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, |
+ Thread::kNoDeoptId, |
+ token_pos()); |
+ } |
+} |
+ |
+ |
+EMIT_NATIVE_CODE(StoreInstanceField, 2, false) { |
+ ASSERT(!HasTemp()); |
+ ASSERT(offset_in_bytes() % kWordSize == 0); |
+ if (compiler->is_optimizing()) { |
+ const Register value = locs()->in(1).reg(); |
+ const Register instance = locs()->in(0).reg(); |
+ __ StoreField(instance, offset_in_bytes() / kWordSize, value); |
+ } else { |
+ __ StoreFieldTOS(offset_in_bytes() / kWordSize); |
+ } |
+} |
+ |
+ |
+EMIT_NATIVE_CODE(LoadField, 1, true) { |
+ ASSERT(offset_in_bytes() % kWordSize == 0); |
+ __ LoadFieldTOS(offset_in_bytes() / kWordSize); |
+} |
+ |
+ |
+EMIT_NATIVE_CODE(BooleanNegate, 1, true) { |
+ __ BooleanNegateTOS(); |
+} |
+ |
+ |
+EMIT_NATIVE_CODE(AllocateContext, 0, false) { |
+ __ AllocateContext(num_context_variables()); |
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, |
+ Thread::kNoDeoptId, |
+ token_pos()); |
+} |
+ |
+ |
+EMIT_NATIVE_CODE(CloneContext, 0, false) { |
+ __ CloneContext(); |
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, |
+ Thread::kNoDeoptId, |
+ token_pos()); |
+} |
+ |
+ |
+EMIT_NATIVE_CODE(CatchBlockEntry, 0, false) { |
+ __ Bind(compiler->GetJumpLabel(this)); |
+ compiler->AddExceptionHandler(catch_try_index(), |
+ try_index(), |
+ compiler->assembler()->CodeSize(), |
+ catch_handler_types_, |
+ needs_stacktrace()); |
+ __ MoveSpecial(-exception_var().index()-1, |
+ Simulator::kExceptionSpecialIndex); |
+ __ MoveSpecial(-stacktrace_var().index()-1, |
+ Simulator::kStacktraceSpecialIndex); |
+ __ SetFrame(compiler->StackSize()); |
+} |
+ |
+ |
+EMIT_NATIVE_CODE(Throw, 0, false) { |
+ __ Throw(0); |
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, |
+ deopt_id(), |
+ token_pos()); |
+ __ Trap(); |
+} |
+ |
+ |
+EMIT_NATIVE_CODE(ReThrow, 0, false) { |
+ compiler->SetNeedsStacktrace(catch_try_index()); |
+ __ Throw(1); |
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, |
+ deopt_id(), |
+ token_pos()); |
+ __ Trap(); |
+} |
+ |
+EMIT_NATIVE_CODE(InstantiateType, 1, true) { |
+ __ InstantiateType(__ AddConstant(type())); |
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, |
+ deopt_id(), |
+ token_pos()); |
+} |
+ |
+EMIT_NATIVE_CODE(InstantiateTypeArguments, 1, true) { |
+ __ InstantiateTypeArgumentsTOS( |
+ type_arguments().IsRawInstantiatedRaw(type_arguments().Length()), |
+ __ AddConstant(type_arguments())); |
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, |
+ deopt_id(), |
+ token_pos()); |
+} |
+ |
+ |
+void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
+ __ DebugStep(); |
+ compiler->AddCurrentDescriptor(stub_kind_, Thread::kNoDeoptId, token_pos()); |
+} |
+ |
+ |
+void GraphEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
+ if (!compiler->CanFallThroughTo(normal_entry())) { |
+ __ Jump(compiler->GetJumpLabel(normal_entry())); |
+ } |
+} |
+ |
+ |
+LocationSummary* Instruction::MakeCallSummary(Zone* zone) { |
+ LocationSummary* result = new(zone) LocationSummary( |
+ zone, 0, 0, LocationSummary::kCall); |
+ result->set_out(0, Location::RequiresRegister()); |
+ return result; |
+} |
+ |
+ |
+CompileType BinaryUint32OpInstr::ComputeType() const { |
+ return CompileType::Int(); |
+} |
+ |
+ |
+CompileType ShiftUint32OpInstr::ComputeType() const { |
+ return CompileType::Int(); |
+} |
+ |
+ |
+CompileType UnaryUint32OpInstr::ComputeType() const { |
+ return CompileType::Int(); |
+} |
+ |
+ |
+static const intptr_t kMintShiftCountLimit = 63; |
+ |
+ |
+bool ShiftMintOpInstr::has_shift_count_check() const { |
+ return !RangeUtils::IsWithin( |
+ right()->definition()->range(), 0, kMintShiftCountLimit); |
+} |
+ |
+ |
+CompileType LoadIndexedInstr::ComputeType() const { |
+ switch (class_id_) { |
+ case kArrayCid: |
+ case kImmutableArrayCid: |
+ return CompileType::Dynamic(); |
+ |
+ case kTypedDataFloat32ArrayCid: |
+ case kTypedDataFloat64ArrayCid: |
+ return CompileType::FromCid(kDoubleCid); |
+ case kTypedDataFloat32x4ArrayCid: |
+ return CompileType::FromCid(kFloat32x4Cid); |
+ case kTypedDataInt32x4ArrayCid: |
+ return CompileType::FromCid(kInt32x4Cid); |
+ case kTypedDataFloat64x2ArrayCid: |
+ return CompileType::FromCid(kFloat64x2Cid); |
+ |
+ case kTypedDataInt8ArrayCid: |
+ case kTypedDataUint8ArrayCid: |
+ case kTypedDataUint8ClampedArrayCid: |
+ case kExternalTypedDataUint8ArrayCid: |
+ case kExternalTypedDataUint8ClampedArrayCid: |
+ case kTypedDataInt16ArrayCid: |
+ case kTypedDataUint16ArrayCid: |
+ case kOneByteStringCid: |
+ case kTwoByteStringCid: |
+ return CompileType::FromCid(kSmiCid); |
+ |
+ case kTypedDataInt32ArrayCid: |
+ case kTypedDataUint32ArrayCid: |
+ return CompileType::Int(); |
+ |
+ default: |
+ UNREACHABLE(); |
+ return CompileType::Dynamic(); |
+ } |
+} |
+ |
+ |
+Representation LoadIndexedInstr::representation() const { |
+ switch (class_id_) { |
+ case kArrayCid: |
+ case kImmutableArrayCid: |
+ case kTypedDataInt8ArrayCid: |
+ case kTypedDataUint8ArrayCid: |
+ case kTypedDataUint8ClampedArrayCid: |
+ case kExternalTypedDataUint8ArrayCid: |
+ case kExternalTypedDataUint8ClampedArrayCid: |
+ case kTypedDataInt16ArrayCid: |
+ case kTypedDataUint16ArrayCid: |
+ case kOneByteStringCid: |
+ case kTwoByteStringCid: |
+ return kTagged; |
+ case kTypedDataInt32ArrayCid: |
+ return kUnboxedInt32; |
+ case kTypedDataUint32ArrayCid: |
+ return kUnboxedUint32; |
+ case kTypedDataFloat32ArrayCid: |
+ case kTypedDataFloat64ArrayCid: |
+ return kUnboxedDouble; |
+ case kTypedDataInt32x4ArrayCid: |
+ return kUnboxedInt32x4; |
+ case kTypedDataFloat32x4ArrayCid: |
+ return kUnboxedFloat32x4; |
+ case kTypedDataFloat64x2ArrayCid: |
+ return kUnboxedFloat64x2; |
+ default: |
+ UNREACHABLE(); |
+ return kTagged; |
+ } |
+} |
+ |
+ |
+Representation StoreIndexedInstr::RequiredInputRepresentation( |
+ intptr_t idx) const { |
+ // 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: |
+ return kUnboxedInt32; |
+ case kTypedDataUint32ArrayCid: |
+ return kUnboxedUint32; |
+ case kTypedDataFloat32ArrayCid: |
+ case kTypedDataFloat64ArrayCid: |
+ return kUnboxedDouble; |
+ case kTypedDataFloat32x4ArrayCid: |
+ return kUnboxedFloat32x4; |
+ case kTypedDataInt32x4ArrayCid: |
+ return kUnboxedInt32x4; |
+ case kTypedDataFloat64x2ArrayCid: |
+ return kUnboxedFloat64x2; |
+ default: |
+ UNREACHABLE(); |
+ return kTagged; |
+ } |
+} |
+ |
+} // namespace dart |
+ |
+#endif // defined TARGET_ARCH_DBC |