mirror of
https://github.com/dart-lang/sdk
synced 2024-09-20 01:19:15 +00:00
Inline recognized List factory in the flow graph optimizer.
The call to the native List factory is lowered into IL instructions if the length is known to be a valid smi. This is mostly performance neutral. The acutal allocation now takes place in the array allocation stub instead of the intrinsic code (and the runtime List_allocate in case the fast case path fails). This is a preparation for enabling allocation sinking for arrays and will be extended to handle type list allocation as well. This way the allocation site is explicitly represented as a CreateArrayInstr, instead of just being a static call. Another benefit is that this allows to simplify the special handling of recognized factory calls in the optimizer once all array types are handled this way. R=johnmccutchan@google.com, srdjan@google.com Review URL: https://codereview.chromium.org//138523004 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@32194 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
d0651286c6
commit
bb4869e3bb
|
@ -2173,14 +2173,15 @@ void EffectGraphVisitor::VisitArrayNode(ArrayNode* node) {
|
|||
AbstractTypeArguments::ZoneHandle(node->type().arguments());
|
||||
Value* element_type = BuildInstantiatedTypeArguments(node->token_pos(),
|
||||
type_args);
|
||||
Value* num_elements =
|
||||
Bind(new ConstantInstr(Smi::ZoneHandle(Smi::New(node->length()))));
|
||||
CreateArrayInstr* create = new CreateArrayInstr(node->token_pos(),
|
||||
node->length(),
|
||||
node->type(),
|
||||
element_type);
|
||||
element_type,
|
||||
num_elements);
|
||||
Value* array_val = Bind(create);
|
||||
|
||||
{ LocalVariable* tmp_var = EnterTempLocalScope(array_val);
|
||||
const intptr_t class_id = create->Type()->ToCid();
|
||||
const intptr_t class_id = kArrayCid;
|
||||
const intptr_t deopt_id = Isolate::kNoDeoptId;
|
||||
for (int i = 0; i < node->length(); ++i) {
|
||||
Value* array = Bind(new LoadLocalInstr(*tmp_var));
|
||||
|
@ -2553,32 +2554,6 @@ void EffectGraphVisitor::BuildConstructorCall(
|
|||
}
|
||||
|
||||
|
||||
// Class that recognizes factories and returns corresponding result cid.
|
||||
class FactoryRecognizer : public AllStatic {
|
||||
public:
|
||||
// Return kDynamicCid if factory is not recognized.
|
||||
static intptr_t ResultCid(const Function& factory) {
|
||||
ASSERT(factory.IsFactory());
|
||||
const Class& function_class = Class::Handle(factory.Owner());
|
||||
const Library& lib = Library::Handle(function_class.library());
|
||||
ASSERT((lib.raw() == Library::CoreLibrary()) ||
|
||||
(lib.raw() == Library::TypedDataLibrary()));
|
||||
const String& factory_name = String::Handle(factory.name());
|
||||
#define RECOGNIZE_FACTORY(test_factory_symbol, cid, fp) \
|
||||
if (String::EqualsIgnoringPrivateKey( \
|
||||
factory_name, Symbols::test_factory_symbol())) { \
|
||||
ASSERT(factory.CheckSourceFingerprint(fp)); \
|
||||
return cid; \
|
||||
} \
|
||||
|
||||
RECOGNIZED_LIST_FACTORY_LIST(RECOGNIZE_FACTORY);
|
||||
#undef RECOGNIZE_FACTORY
|
||||
|
||||
return kDynamicCid;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static intptr_t GetResultCidOfListFactory(ConstructorCallNode* node) {
|
||||
const Function& function = node->constructor();
|
||||
const Class& function_class = Class::Handle(function.Owner());
|
||||
|
|
|
@ -49,6 +49,32 @@ class TestGraphVisitor;
|
|||
V(_Float32x4ArrayFactory, kTypedDataFloat32x4ArrayCid, 879975401) \
|
||||
|
||||
|
||||
// Class that recognizes factories and returns corresponding result cid.
|
||||
class FactoryRecognizer : public AllStatic {
|
||||
public:
|
||||
// Return kDynamicCid if factory is not recognized.
|
||||
static intptr_t ResultCid(const Function& factory) {
|
||||
ASSERT(factory.IsFactory());
|
||||
const Class& function_class = Class::Handle(factory.Owner());
|
||||
const Library& lib = Library::Handle(function_class.library());
|
||||
ASSERT((lib.raw() == Library::CoreLibrary()) ||
|
||||
(lib.raw() == Library::TypedDataLibrary()));
|
||||
const String& factory_name = String::Handle(factory.name());
|
||||
#define RECOGNIZE_FACTORY(test_factory_symbol, cid, fp) \
|
||||
if (String::EqualsIgnoringPrivateKey( \
|
||||
factory_name, Symbols::test_factory_symbol())) { \
|
||||
ASSERT(factory.CheckSourceFingerprint(fp)); \
|
||||
return cid; \
|
||||
} \
|
||||
|
||||
RECOGNIZED_LIST_FACTORY_LIST(RECOGNIZE_FACTORY);
|
||||
#undef RECOGNIZE_FACTORY
|
||||
|
||||
return kDynamicCid;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// A class to collect the exits from an inlined function during graph
|
||||
// construction so they can be plugged into the caller's flow graph.
|
||||
class InlineExitCollector: public ZoneAllocated {
|
||||
|
|
|
@ -271,9 +271,7 @@ class CallSites : public ValueObject {
|
|||
}
|
||||
StaticCallInstr* static_call = current->AsStaticCall();
|
||||
if (static_call != NULL) {
|
||||
if (static_call->function().IsInlineable()) {
|
||||
static_calls_.Add(StaticCallInfo(static_call));
|
||||
}
|
||||
static_calls_.Add(StaticCallInfo(static_call));
|
||||
continue;
|
||||
}
|
||||
PolymorphicInstanceCallInstr* instance_call =
|
||||
|
|
|
@ -3680,6 +3680,31 @@ void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* call) {
|
|||
ConstantInstr* cid_instr = new ConstantInstr(Smi::Handle(Smi::New(cid)));
|
||||
ReplaceCall(call, cid_instr);
|
||||
}
|
||||
|
||||
if (call->function().IsFactory()) {
|
||||
const Class& function_class = Class::Handle(call->function().Owner());
|
||||
if ((function_class.library() == Library::CoreLibrary()) ||
|
||||
(function_class.library() == Library::TypedDataLibrary())) {
|
||||
intptr_t cid = FactoryRecognizer::ResultCid(call->function());
|
||||
switch (cid) {
|
||||
case kArrayCid: {
|
||||
Value* type = new Value(call->ArgumentAt(0));
|
||||
Value* num_elements = new Value(call->ArgumentAt(1));
|
||||
if (num_elements->BindsToConstant() &&
|
||||
num_elements->BoundConstant().IsSmi()) {
|
||||
intptr_t length = Smi::Cast(num_elements->BoundConstant()).Value();
|
||||
if (length >= 0 && length <= Array::kMaxElements) {
|
||||
CreateArrayInstr* create_array =
|
||||
new CreateArrayInstr(call->token_pos(), type, num_elements);
|
||||
ReplaceCall(call, create_array);
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -7119,11 +7144,15 @@ void ConstantPropagator::VisitLoadClassId(LoadClassIdInstr* instr) {
|
|||
void ConstantPropagator::VisitLoadField(LoadFieldInstr* instr) {
|
||||
if ((instr->recognized_kind() == MethodRecognizer::kObjectArrayLength) &&
|
||||
(instr->instance()->definition()->IsCreateArray())) {
|
||||
const intptr_t length =
|
||||
Value* num_elements =
|
||||
instr->instance()->definition()->AsCreateArray()->num_elements();
|
||||
const Object& result = Smi::ZoneHandle(Smi::New(length));
|
||||
SetValue(instr, result);
|
||||
return;
|
||||
if (num_elements->BindsToConstant() &&
|
||||
num_elements->BoundConstant().IsSmi()) {
|
||||
intptr_t length = Smi::Cast(num_elements->BoundConstant()).Value();
|
||||
const Object& result = Smi::ZoneHandle(Smi::New(length));
|
||||
SetValue(instr, result);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (instr->IsImmutableLengthLoad()) {
|
||||
|
|
|
@ -922,7 +922,8 @@ CompileType* StoreStaticFieldInstr::ComputeInitialType() const {
|
|||
|
||||
|
||||
CompileType CreateArrayInstr::ComputeType() const {
|
||||
return CompileType::FromAbstractType(type(), CompileType::kNonNullable);
|
||||
// TODO(fschneider): Add abstract type and type arguments to the compile type.
|
||||
return CompileType::FromCid(kArrayCid);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2917,8 +2917,14 @@ Definition* StringInterpolateInstr::Canonicalize(FlowGraph* flow_graph) {
|
|||
CreateArrayInstr* create_array = value()->definition()->AsCreateArray();
|
||||
ASSERT(create_array != NULL);
|
||||
// Check if the string interpolation has only constant inputs.
|
||||
GrowableArray<ConstantInstr*> constants(create_array->num_elements());
|
||||
for (intptr_t i = 0; i < create_array->num_elements(); i++) {
|
||||
Value* num_elements = create_array->num_elements();
|
||||
if (!num_elements->BindsToConstant() ||
|
||||
!num_elements->BoundConstant().IsSmi()) {
|
||||
return this;
|
||||
}
|
||||
intptr_t length = Smi::Cast(num_elements->BoundConstant()).Value();
|
||||
GrowableArray<ConstantInstr*> constants(length);
|
||||
for (intptr_t i = 0; i < length; i++) {
|
||||
constants.Add(NULL);
|
||||
}
|
||||
for (Value::Iterator it(create_array->input_use_list());
|
||||
|
@ -2944,7 +2950,7 @@ Definition* StringInterpolateInstr::Canonicalize(FlowGraph* flow_graph) {
|
|||
}
|
||||
// Interpolate string at compile time.
|
||||
const Array& array_argument =
|
||||
Array::Handle(Array::New(create_array->num_elements()));
|
||||
Array::Handle(Array::New(length));
|
||||
for (intptr_t i = 0; i < constants.length(); i++) {
|
||||
array_argument.SetAt(i, constants[i]->value());
|
||||
}
|
||||
|
|
|
@ -4095,29 +4095,28 @@ class AllocateObjectWithBoundsCheckInstr : public TemplateDefinition<0> {
|
|||
};
|
||||
|
||||
|
||||
class CreateArrayInstr : public TemplateDefinition<1> {
|
||||
class CreateArrayInstr : public TemplateDefinition<2> {
|
||||
public:
|
||||
CreateArrayInstr(intptr_t token_pos,
|
||||
intptr_t num_elements,
|
||||
const AbstractType& type,
|
||||
Value* element_type)
|
||||
: token_pos_(token_pos),
|
||||
num_elements_(num_elements),
|
||||
type_(type) {
|
||||
ASSERT(type_.IsZoneHandle());
|
||||
ASSERT(!type_.IsNull());
|
||||
ASSERT(type_.IsFinalized());
|
||||
SetInputAt(0, element_type);
|
||||
Value* element_type,
|
||||
Value* num_elements)
|
||||
: token_pos_(token_pos) {
|
||||
SetInputAt(kElementTypePos, element_type);
|
||||
SetInputAt(kLengthPos, num_elements);
|
||||
}
|
||||
|
||||
enum {
|
||||
kElementTypePos = 0,
|
||||
kLengthPos = 1
|
||||
};
|
||||
|
||||
DECLARE_INSTRUCTION(CreateArray)
|
||||
virtual CompileType ComputeType() const;
|
||||
|
||||
intptr_t num_elements() const { return num_elements_; }
|
||||
|
||||
intptr_t token_pos() const { return token_pos_; }
|
||||
const AbstractType& type() const { return type_; }
|
||||
Value* element_type() const { return inputs_[0]; }
|
||||
Value* element_type() const { return inputs_[kElementTypePos]; }
|
||||
Value* num_elements() const { return inputs_[kLengthPos]; }
|
||||
|
||||
virtual void PrintOperandsTo(BufferFormatter* f) const;
|
||||
|
||||
|
@ -4129,8 +4128,6 @@ class CreateArrayInstr : public TemplateDefinition<1> {
|
|||
|
||||
private:
|
||||
const intptr_t token_pos_;
|
||||
const intptr_t num_elements_;
|
||||
const AbstractType& type_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CreateArrayInstr);
|
||||
};
|
||||
|
|
|
@ -1822,11 +1822,12 @@ void InstanceOfInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
|
||||
|
||||
LocationSummary* CreateArrayInstr::MakeLocationSummary(bool opt) const {
|
||||
const intptr_t kNumInputs = 1;
|
||||
const intptr_t kNumInputs = 2;
|
||||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* locs =
|
||||
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
|
||||
locs->set_in(0, Location::RegisterLocation(R1));
|
||||
locs->set_in(kElementTypePos, Location::RegisterLocation(R1));
|
||||
locs->set_in(kLengthPos, Location::RegisterLocation(R2));
|
||||
locs->set_out(Location::RegisterLocation(R0));
|
||||
return locs;
|
||||
}
|
||||
|
@ -1834,8 +1835,8 @@ LocationSummary* CreateArrayInstr::MakeLocationSummary(bool opt) const {
|
|||
|
||||
void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
// Allocate the array. R2 = length, R1 = element type.
|
||||
ASSERT(locs()->in(0).reg() == R1);
|
||||
__ LoadImmediate(R2, Smi::RawValue(num_elements()));
|
||||
ASSERT(locs()->in(kElementTypePos).reg() == R1);
|
||||
ASSERT(locs()->in(kLengthPos).reg() == R2);
|
||||
compiler->GenerateCall(token_pos(),
|
||||
&StubCode::AllocateArrayLabel(),
|
||||
PcDescriptors::kOther,
|
||||
|
|
|
@ -1835,11 +1835,12 @@ void InstanceOfInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
|
||||
|
||||
LocationSummary* CreateArrayInstr::MakeLocationSummary(bool opt) const {
|
||||
const intptr_t kNumInputs = 1;
|
||||
const intptr_t kNumInputs = 2;
|
||||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* locs =
|
||||
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
|
||||
locs->set_in(0, Location::RegisterLocation(ECX));
|
||||
locs->set_in(1, Location::RegisterLocation(EDX));
|
||||
locs->set_out(Location::RegisterLocation(EAX));
|
||||
return locs;
|
||||
}
|
||||
|
@ -1848,7 +1849,7 @@ LocationSummary* CreateArrayInstr::MakeLocationSummary(bool opt) const {
|
|||
void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
// Allocate the array. EDX = length, ECX = element type.
|
||||
ASSERT(locs()->in(0).reg() == ECX);
|
||||
__ movl(EDX, Immediate(Smi::RawValue(num_elements())));
|
||||
ASSERT(locs()->in(1).reg() == EDX);
|
||||
compiler->GenerateCall(token_pos(),
|
||||
&StubCode::AllocateArrayLabel(),
|
||||
PcDescriptors::kOther,
|
||||
|
|
|
@ -1897,11 +1897,12 @@ void InstanceOfInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
|
||||
|
||||
LocationSummary* CreateArrayInstr::MakeLocationSummary(bool opt) const {
|
||||
const intptr_t kNumInputs = 1;
|
||||
const intptr_t kNumInputs = 2;
|
||||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* locs =
|
||||
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
|
||||
locs->set_in(0, Location::RegisterLocation(A0));
|
||||
locs->set_in(1, Location::RegisterLocation(A1));
|
||||
locs->set_out(Location::RegisterLocation(V0));
|
||||
return locs;
|
||||
}
|
||||
|
@ -1911,7 +1912,7 @@ void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
__ TraceSimMsg("CreateArrayInstr");
|
||||
// Allocate the array. A1 = length, A0 = element type.
|
||||
ASSERT(locs()->in(0).reg() == A0);
|
||||
__ LoadImmediate(A1, Smi::RawValue(num_elements()));
|
||||
ASSERT(locs()->in(1).reg() == A1);
|
||||
compiler->GenerateCall(token_pos(),
|
||||
&StubCode::AllocateArrayLabel(),
|
||||
PcDescriptors::kOther,
|
||||
|
|
|
@ -1728,11 +1728,12 @@ void InstanceOfInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
|
||||
|
||||
LocationSummary* CreateArrayInstr::MakeLocationSummary(bool opt) const {
|
||||
const intptr_t kNumInputs = 1;
|
||||
const intptr_t kNumInputs = 2;
|
||||
const intptr_t kNumTemps = 0;
|
||||
LocationSummary* locs =
|
||||
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
|
||||
locs->set_in(0, Location::RegisterLocation(RBX));
|
||||
locs->set_in(1, Location::RegisterLocation(R10));
|
||||
locs->set_out(Location::RegisterLocation(RAX));
|
||||
return locs;
|
||||
}
|
||||
|
@ -1741,7 +1742,7 @@ LocationSummary* CreateArrayInstr::MakeLocationSummary(bool opt) const {
|
|||
void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
// Allocate the array. R10 = length, RBX = element type.
|
||||
ASSERT(locs()->in(0).reg() == RBX);
|
||||
__ LoadImmediate(R10, Immediate(Smi::RawValue(num_elements())), PP);
|
||||
ASSERT(locs()->in(1).reg() == R10);
|
||||
compiler->GenerateCall(token_pos(),
|
||||
&StubCode::AllocateArrayLabel(),
|
||||
PcDescriptors::kOther,
|
||||
|
|
Loading…
Reference in a new issue