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

Unified Diff: runtime/vm/opt_code_generator_ia32.cc

Issue 8945002: Optimize instance setters for non-implicit-setters and for setters with multiple targets. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: '' Created 9 years 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/opt_code_generator_ia32.h ('k') | tests/language/src/OptimizedSetterTest.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/opt_code_generator_ia32.cc
===================================================================
--- runtime/vm/opt_code_generator_ia32.cc (revision 2450)
+++ runtime/vm/opt_code_generator_ia32.cc (working copy)
@@ -1537,14 +1537,6 @@
}
-// Return true if all targets in 'ic_data' point to same
-// inlineable getter target.
-static bool ICDataToSameInlineableInstanceSetter(const ICData& ic_data) {
- const Function& target = Function::Handle(GetUniqueTarget(ic_data));
- return !target.IsNull() && (target.kind() == RawFunction::kImplicitSetter);
-}
-
-
void OptimizingCodeGenerator::InlineInstanceGetter(AstNode* node,
intptr_t id,
AstNode* receiver,
@@ -1598,73 +1590,128 @@
}
-// Clobber EBX leave 'value_reg' untouched.
-void OptimizingCodeGenerator::InlineInstanceSettersWithSameTarget(
- AstNode* node,
- intptr_t id,
- AstNode* receiver,
- const String& field_name,
- Register recv_reg,
- Register value_reg) {
+// Helper struct to pass arguments to 'GenerateInstanceSetter'.
+struct InstanceSetterArgs {
+ const Class* cls;
+ const Function* target;
+ const String* field_name;
+ Register recv_reg;
+ Register value_reg;
+ intptr_t id;
+ intptr_t token_index;
+};
+
+
+// Preserves 'args.value_reg'. Either stores instance field directly or
+// calls the setter method.
+void OptimizingCodeGenerator::GenerateInstanceSetter(
+ const InstanceSetterArgs& args) {
+ if (args.target->kind() == RawFunction::kImplicitSetter) {
+ intptr_t field_offset = GetFieldOffset(*(args.cls), *(args.field_name));
+ ASSERT(field_offset >= 0);
+ __ StoreIntoObject(args.recv_reg,
+ FieldAddress(args.recv_reg, field_offset), args.value_reg);
+ } else {
+ __ pushl(args.value_reg);
+ __ pushl(args.recv_reg);
+ __ pushl(args.value_reg);
+ const Array& no_optional_argument_names = Array::Handle();
+ GenerateDirectCall(args.id,
+ args.token_index,
+ *(args.target),
+ 2,
+ no_optional_argument_names);
+ __ popl(args.value_reg);
+ }
+}
+
+
+// Returns value in 'value_reg', clobbers EBX.
+void OptimizingCodeGenerator::InlineInstanceSetter(AstNode* node,
+ intptr_t id,
+ AstNode* receiver,
+ const String& field_name,
+ Register recv_reg,
+ Register value_reg) {
+ // EBX is used as temporary register for class.
ASSERT((recv_reg != EBX) && (value_reg != EBX));
+ GrowableArray<Class*> classes;
+ GrowableArray<Function*> targets;
+ bool unique_target = true;
+ {
+ const ICData& ic_data = node->ICDataAtId(id);
+ ASSERT(ic_data.NumberOfChecks() > 0);
+ ASSERT(ic_data.NumberOfArgumentsChecked() == 1);
+ for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) {
+ Class& cls = Class::ZoneHandle();
+ Function& target = Function::ZoneHandle();
+ ic_data.GetOneClassCheckAt(i, &cls, &target);
+ classes.Add(&cls);
+ targets.Add(&target);
+ }
+ for (intptr_t i = 1; i < targets.length(); i++) {
+ if (targets[i - 1]->raw() != targets[i]->raw()) {
+ unique_target = false;
+ break;
+ }
+ }
+ }
+ // TODO(srdjan): sort classes/target by their invocation count.
DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(
node, recv_reg, value_reg, kDeoptInstanceSetterSameTarget);
+ // Deoptimize if Smi, since they do not have setters.
if (NodeMayBeSmi(receiver)) {
__ testl(recv_reg, Immediate(kSmiTagMask));
__ j(ZERO, deopt_blob->label());
}
__ movl(EBX, FieldAddress(recv_reg, Object::class_offset()));
- const ICData& ic_data = node->ICDataAtId(id);
- Function& target = Function::Handle();
- Label store_field;
- for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) {
- Class& cls = Class::ZoneHandle();
- ic_data.GetOneClassCheckAt(i, &cls, &target);
- __ CompareObject(EBX, cls);
- if (i == (ic_data.NumberOfChecks() - 1)) {
+ // Initialize setter arguments, but leave the class and target fields NULL.
+ InstanceSetterArgs setter_args =
+ {NULL, NULL, &field_name, recv_reg, value_reg, id, node->token_index()};
+
+ if (unique_target) {
+ Label store_field;
+ for (intptr_t i = 0; i < classes.length(); i++) {
+ __ CompareObject(EBX, *classes[i]);
+ if (i == (classes.length() - 1)) {
+ __ j(NOT_EQUAL, deopt_blob->label());
+ } else {
+ __ j(EQUAL, &store_field);
+ }
+ }
+ __ Bind(&store_field);
+ setter_args.cls = classes[0];
+ setter_args.target = targets[0];
+ GenerateInstanceSetter(setter_args);
+ return;
+ }
+ // Targets are different.
+ Label done;
+ for (intptr_t i = 0; i < classes.length(); i++) {
+ setter_args.cls = classes[i];
+ setter_args.target = targets[i];
+ __ CompareObject(EBX, *classes[i]);
+ if (i == (classes.length() - 1)) {
__ j(NOT_EQUAL, deopt_blob->label());
+ GenerateInstanceSetter(setter_args);
} else {
- __ j(EQUAL, &store_field);
+ Label next_check;
+ __ j(NOT_EQUAL, &next_check);
+ GenerateInstanceSetter(setter_args);
+ __ jmp(&done);
+ __ Bind(&next_check);
}
}
- Class& cls = Class::Handle();
- ic_data.GetOneClassCheckAt(0, &cls, &target);
-
- __ Bind(&store_field);
- ASSERT(target.kind() == RawFunction::kImplicitSetter);
- intptr_t field_offset = GetFieldOffset(cls, field_name);
- ASSERT(field_offset >= 0);
- __ StoreIntoObject(recv_reg, FieldAddress(recv_reg, field_offset), value_reg);
+ __ Bind(&done);
}
-// Returns value in 'value_reg'.
-void OptimizingCodeGenerator::InlineInstanceSetter(AstNode* node,
- intptr_t id,
- AstNode* receiver,
- const String& field_name,
- Register recv_reg,
- Register value_reg) {
- if (ICDataToSameInlineableInstanceSetter(node->ICDataAtId(id))) {
- InlineInstanceSettersWithSameTarget(node,
- id,
- receiver,
- field_name,
- recv_reg,
- value_reg);
- } else {
- UNIMPLEMENTED();
- }
-}
-
-
// The call to the instance setter implements the assignment to a field.
// The result of the assignment to a field is the value being stored.
void OptimizingCodeGenerator::VisitInstanceSetterNode(
InstanceSetterNode* node) {
// TODO(srdjan): inline setters to different targets as well.
- if (FLAG_enable_type_checks ||
- !ICDataToSameInlineableInstanceSetter(node->ICDataAtId(node->id()))) {
+ if (FLAG_enable_type_checks) {
CodeGenerator::VisitInstanceSetterNode(node);
return;
}
« no previous file with comments | « runtime/vm/opt_code_generator_ia32.h ('k') | tests/language/src/OptimizedSetterTest.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698