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

Side by Side Diff: vm/opt_code_generator_ia32.cc

Issue 8404009: Restructure instance calls in optimizing compiler. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/runtime/
Patch Set: '' Created 9 years, 1 month 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « vm/opt_code_generator_ia32.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32.
6 #if defined(TARGET_ARCH_IA32) 6 #if defined(TARGET_ARCH_IA32)
7 7
8 #include "vm/opt_code_generator.h" 8 #include "vm/opt_code_generator.h"
9 9
10 #include "vm/assembler_macros.h" 10 #include "vm/assembler_macros.h"
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after
271 static const ZoneGrowableArray<const Class*>* 271 static const ZoneGrowableArray<const Class*>*
272 CollectedClassesAtNode(AstNode* node) { 272 CollectedClassesAtNode(AstNode* node) {
273 ZoneGrowableArray<const Class*>* result = 273 ZoneGrowableArray<const Class*>* result =
274 new ZoneGrowableArray<const Class*>(); 274 new ZoneGrowableArray<const Class*>();
275 const ICData& ic_data = node->ICDataAtId(node->id()); 275 const ICData& ic_data = node->ICDataAtId(node->id());
276 if (ic_data.NumberOfChecks() == 0) { 276 if (ic_data.NumberOfChecks() == 0) {
277 return result; 277 return result;
278 } 278 }
279 ASSERT(ic_data.NumberOfArgumentsChecked() == 1); 279 ASSERT(ic_data.NumberOfArgumentsChecked() == 1);
280 Function& target = Function::Handle(); 280 Function& target = Function::Handle();
281 GrowableArray<const Class*> classes;
282 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { 281 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) {
283 ic_data.GetCheckAt(i, &classes, &target); 282 Class& cls = Class::ZoneHandle();
284 ASSERT(classes.length() == 1); 283 ic_data.GetOneClassCheckAt(i, &cls, &target);
285 result->Add(classes[0]); 284 result->Add(&cls);
286 } 285 }
287 return result; 286 return result;
288 } 287 }
289 288
290 289
291 // Debugging helper function. 290 // Debugging helper function.
292 void OptimizingCodeGenerator::PrintCollectedClasses(AstNode* node) { 291 void OptimizingCodeGenerator::PrintCollectedClasses(AstNode* node) {
293 const ZoneGrowableArray<const Class*>* classes = CollectedClassesAtNode(node); 292 const ZoneGrowableArray<const Class*>* classes = CollectedClassesAtNode(node);
294 for (intptr_t i = 0; i < classes->length(); i++) { 293 for (intptr_t i = 0; i < classes->length(); i++) {
295 OS::Print("- %s\n", (*classes)[i]->ToCString()); 294 OS::Print("- %s\n", (*classes)[i]->ToCString());
(...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after
679 // Operator is called either if one of the arguments is not Smi or 678 // Operator is called either if one of the arguments is not Smi or
680 // if we hit an overflow in an arithmetic operation. 679 // if we hit an overflow in an arithmetic operation.
681 __ Bind(&call_operator); 680 __ Bind(&call_operator);
682 // Restore arguments on stack, and dispatch to operator, thus preventing 681 // Restore arguments on stack, and dispatch to operator, thus preventing
683 // deoptimization in case of smi/non-smi operations. At exit we do not 682 // deoptimization in case of smi/non-smi operations. At exit we do not
684 // know the result is Smi or not. 683 // know the result is Smi or not.
685 // TODO(srdjan): Handle type feedback for both arguments instead of for 684 // TODO(srdjan): Handle type feedback for both arguments instead of for
686 // receiver only, deoptimize if the type changes. 685 // receiver only, deoptimize if the type changes.
687 __ pushl(ECX); 686 __ pushl(ECX);
688 __ pushl(EDX); 687 __ pushl(EDX);
689 GenerateBinaryOperatorCall(node->id(), node->token_index(), node->Name()); 688 GenerateBinaryOperatorCall(node->id(),
689 node->token_index(),
690 node->Name());
690 __ jmp(&done); 691 __ jmp(&done);
691 __ Bind(&two_smis); 692 __ Bind(&two_smis);
692 // Restore left operand. EAX will be 'destroyed', ECX holds the left 693 // Restore left operand. EAX will be 'destroyed', ECX holds the left
693 // argument, which may be needed for deoptimization. 694 // argument, which may be needed for deoptimization.
694 __ movl(EAX, ECX); 695 __ movl(EAX, ECX);
695 } 696 }
696 switch (kind) { 697 switch (kind) {
697 case Token::kADD: { 698 case Token::kADD: {
698 __ addl(EAX, EDX); 699 __ addl(EAX, EDX);
699 __ j(OVERFLOW, overflow_label); 700 __ j(OVERFLOW, overflow_label);
(...skipping 549 matching lines...) Expand 10 before | Expand all | Expand 10 after
1249 all_same_target = false; 1250 all_same_target = false;
1250 } 1251 }
1251 if (!IsInlineableInstanceGetter(target)) { 1252 if (!IsInlineableInstanceGetter(target)) {
1252 all_inlineable = false; 1253 all_inlineable = false;
1253 } 1254 }
1254 } 1255 }
1255 // TODO(srdjan): implement other variants. 1256 // TODO(srdjan): implement other variants.
1256 if (all_inlineable && all_same_target) { 1257 if (all_inlineable && all_same_target) {
1257 InlineInstanceGettersWithSameTarget(node, *targets[0]); 1258 InlineInstanceGettersWithSameTarget(node, *targets[0]);
1258 } else { 1259 } else {
1260 // TODO(srdjan): Inline access.
1259 TraceNotOpt(node, kMessage); 1261 TraceNotOpt(node, kMessage);
1260 node->receiver()->Visit(this); 1262 node->receiver()->Visit(this);
1261 GenerateInstanceGetterCall(node->id(), 1263 const int kNumberOfArguments = 1;
1262 node->token_index(), 1264 const Array& kNoArgumentNames = Array::Handle();
1263 node->field_name()); 1265 GenerateCheckedInstanceCalls(node,
1266 node->receiver(),
1267 node->id(),
1268 node->token_index(),
1269 kNumberOfArguments,
1270 kNoArgumentNames);
1264 } 1271 }
1265 if (CodeGenerator::IsResultNeeded(node)) { 1272 if (CodeGenerator::IsResultNeeded(node)) {
1266 __ pushl(EAX); 1273 __ pushl(EAX);
1267 } 1274 }
1268 } 1275 }
1269 1276
1270 1277
1271 // The call to the instance setter implements the assignment to a field. 1278 // The call to the instance setter implements the assignment to a field.
1272 // The result of the assignment to a field is the value being stored. 1279 // The result of the assignment to a field is the value being stored.
1273 void OptimizingCodeGenerator::VisitInstanceSetterNode( 1280 void OptimizingCodeGenerator::VisitInstanceSetterNode(
(...skipping 653 matching lines...) Expand 10 before | Expand all | Expand 10 after
1927 __ Bind(&false_label); 1934 __ Bind(&false_label);
1928 node->false_branch()->Visit(this); 1935 node->false_branch()->Visit(this);
1929 __ Bind(&done); 1936 __ Bind(&done);
1930 } else { 1937 } else {
1931 __ Bind(&false_label); 1938 __ Bind(&false_label);
1932 } 1939 }
1933 __ Bind(&done); 1940 __ Bind(&done);
1934 } 1941 }
1935 1942
1936 1943
1937 // Return index where 'cls' is contained within 'classes' or -1 if not found. 1944 void OptimizingCodeGenerator::GenerateDirectCall(
1938 static intptr_t IndexOfClassInArray( 1945 intptr_t node_id,
1939 const ZoneGrowableArray<const Class*>& classes, 1946 intptr_t token_index,
1940 const Class& cls) { 1947 Function& target,
1941 for (int i = 0; i < classes.length(); i++) { 1948 intptr_t arg_count,
1942 if (classes[i]->raw() == cls.raw()) { 1949 const Array& optional_argument_names) {
1943 return i;
1944 }
1945 }
1946 return -1;
1947 }
1948
1949
1950 // Use static call pattern to call an instance method directly.
1951 void OptimizingCodeGenerator::GenerateDirectInstanceCall(
1952 InstanceCallNode* node, const Class& cls) {
1953 ASSERT(node != NULL);
1954 ASSERT(!cls.IsNull());
1955 intptr_t arg_count = node->arguments()->length() + 1;
1956 const int num_named_arguments = node->arguments()->names().IsNull() ?
1957 0 : node->arguments()->names().Length();
1958 const Function& target = Function::ZoneHandle(
1959 Resolver::ResolveDynamicForReceiverClass(
1960 cls, node->function_name(), arg_count, num_named_arguments));
1961 ASSERT(!target.IsNull()); 1950 ASSERT(!target.IsNull());
1962 const Code& code = Code::Handle(target.code()); 1951 const Code& code = Code::Handle(target.code());
1963 ASSERT(!code.IsNull()); 1952 ASSERT(!code.IsNull());
1964 ExternalLabel target_label("DirectInstanceCall", code.EntryPoint()); 1953 ExternalLabel target_label("DirectInstanceCall", code.EntryPoint());
1965 1954
1966 __ LoadObject(ECX, target); 1955 __ LoadObject(ECX, target);
1967 __ LoadObject(EDX, ArgumentsDescriptor(arg_count, 1956 __ LoadObject(EDX, ArgumentsDescriptor(arg_count, optional_argument_names));
1968 node->arguments()->names()));
1969
1970 __ call(&target_label); 1957 __ call(&target_label);
1971 AddCurrentDescriptor(PcDescriptors::kOther, node->id(), node->token_index()); 1958 AddCurrentDescriptor(PcDescriptors::kOther, node_id, token_index);
1972 __ addl(ESP, Immediate(arg_count * kWordSize)); 1959 __ addl(ESP, Immediate(arg_count * kWordSize));
1973 } 1960 }
1974 1961
1975 1962
1976 // Using collected type feedback, inline class checks and call the targets 1963 // Use ICData in 'node' to issues checks and calls.
1977 // directly instead of via inline cache stub. TODO(srdjan): Use type propagation 1964 void OptimizingCodeGenerator::GenerateCheckedInstanceCalls(
1978 // and CHA to eliminate checks. 1965 AstNode* node,
1979 // Return false if no code was generated (because no type feedback was found). 1966 AstNode* receiver,
1980 bool OptimizingCodeGenerator::GenerateCheckedInstanceCalls( 1967 intptr_t node_id,
1981 InstanceCallNode* node) { 1968 intptr_t token_index,
1982 const ZoneGrowableArray<const Class*>* classes = CollectedClassesAtNode(node); 1969 intptr_t num_args,
1983 if ((classes == NULL) || classes->is_empty()) { 1970 const Array& optional_argument_names) {
1984 return false; 1971 ASSERT(node != NULL);
1972 ASSERT(receiver != NULL);
1973 ASSERT(num_args > 0);
1974 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node);
1975 const ICData& ic_data = node->ICDataAtId(node_id);
1976 if (ic_data.NumberOfChecks() == 0) {
1977 // No type feedback means node was never executed.
1978 __ jmp(deopt_blob->label());
1979 return;
1980 }
1981 ASSERT(ic_data.NumberOfArgumentsChecked() == 1);
1982
1983 // First test for Smi. Null object will cause deoptimization.
1984 intptr_t smi_class_index = -1;
1985 Class& smi_test_class = Class::Handle();
1986 Function& smi_target = Function::ZoneHandle();
1987 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) {
1988 ic_data.GetOneClassCheckAt(i, &smi_test_class, &smi_target);
1989 if (smi_test_class.raw() == smi_class_.raw()) {
1990 smi_class_index = i;
1991 break;
1992 }
1985 } 1993 }
1986 1994
1987 const int arg_count = node->arguments()->length() + 1; // With receiver.
1988 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node);
1989 ASSERT(arg_count > 0);
1990 __ movl(EAX, Address(ESP, (arg_count - 1) * kWordSize)); // Load receiver.
1991
1992 Label done; 1995 Label done;
1993 // If needed, Smi test must come first. 1996 __ movl(EAX, Address(ESP, (num_args - 1) * kWordSize)); // Load receiver.
1994 const intptr_t smi_class_index = IndexOfClassInArray(*classes, smi_class_);
1995 if (smi_class_index >= 0) { 1997 if (smi_class_index >= 0) {
1996 // Smi test is needed. 1998 // Smi test is needed.
1997 __ testl(EAX, Immediate(kSmiTagMask)); 1999 __ testl(EAX, Immediate(kSmiTagMask));
1998 if (classes->length() == 1) { 2000 if (ic_data.NumberOfChecks() == 1) {
1999 // Only the Smi test. 2001 // Only the Smi test.
2000 __ j(NOT_ZERO, deopt_blob->label()); 2002 __ j(NOT_ZERO, deopt_blob->label());
2001 GenerateDirectInstanceCall(node, smi_class_); 2003 GenerateDirectCall(node_id,
2002 return true; 2004 token_index,
2005 smi_target,
2006 num_args,
2007 optional_argument_names);
2008 return;
2003 } 2009 }
2004 Label not_smi; 2010 Label not_smi;
2005 __ j(NOT_ZERO, &not_smi); 2011 __ j(NOT_ZERO, &not_smi);
2006 GenerateDirectInstanceCall(node, smi_class_); 2012 GenerateDirectCall(node_id,
2013 token_index,
2014 smi_target,
2015 num_args,
2016 optional_argument_names);
2007 __ jmp(&done); 2017 __ jmp(&done);
2008 __ Bind(&not_smi); // Continue with other test below. 2018 __ Bind(&not_smi); // Continue with other test below.
2009 } else if (NodeMayBeSmi(node->receiver())) { 2019 } else if (NodeMayBeSmi(receiver)) {
2010 __ testl(EAX, Immediate(kSmiTagMask)); 2020 __ testl(EAX, Immediate(kSmiTagMask));
2011 __ j(ZERO, deopt_blob->label()); 2021 __ j(ZERO, deopt_blob->label());
2022 } else {
2023 // Receiver cannot be Smi, no need to test it.
2012 } 2024 }
2013 2025
2014 // We need to generate special test for last class exclusive Smi class. 2026 intptr_t last_check_at = (smi_class_index == ic_data.NumberOfChecks() - 1) ?
2015 intptr_t last_check_at = (smi_class_index == classes->length() - 1) ? 2027 ic_data.NumberOfChecks() - 2 : ic_data.NumberOfChecks() - 1;
2016 classes->length() - 2 : classes->length() - 1;
2017 // Every class may appear only once in the 'classes' array. Therefore, if 2028 // Every class may appear only once in the 'classes' array. Therefore, if
2018 // Smi class is last, it cannot be the second to last. 2029 // Smi class is last, it cannot be the second to last.
2019 ASSERT(!(*classes)[last_check_at]->IsSmi());
2020 __ movl(EAX, FieldAddress(EAX, Object::class_offset())); // Receiver's class. 2030 __ movl(EAX, FieldAddress(EAX, Object::class_offset())); // Receiver's class.
2021 for (intptr_t i = 0; i <= last_check_at; i++) { 2031 for (intptr_t i = 0; i <= last_check_at; i++) {
2022 const Class& test_class = *((*classes)[i]); 2032 Function& target = Function::ZoneHandle();
2023 ASSERT(!test_class.IsNullClass()); 2033 Class& cls = Class::ZoneHandle();
2024 if (test_class.raw() == smi_class_.raw()) { 2034 ic_data.GetOneClassCheckAt(i, &cls, &target);
2035 ASSERT(!cls.IsNullClass());
2036 if (cls.raw() == smi_class_.raw()) {
2037 ASSERT(i < last_check_at); // Smi class may not be last.
2025 continue; // Skip Smi test. 2038 continue; // Skip Smi test.
2026 } 2039 }
2027 __ CompareObject(EAX, test_class); 2040 __ CompareObject(EAX, cls);
2028 if (i == last_check_at) { 2041 if (i == last_check_at) {
2029 __ j(NOT_EQUAL, deopt_blob->label()); 2042 __ j(NOT_EQUAL, deopt_blob->label());
2030 GenerateDirectInstanceCall(node, test_class); 2043 GenerateDirectCall(node_id,
2044 token_index,
2045 target,
2046 num_args,
2047 optional_argument_names);
2031 } else { 2048 } else {
2032 Label next; 2049 Label next;
2033 __ j(NOT_EQUAL, &next); 2050 __ j(NOT_EQUAL, &next);
2034 GenerateDirectInstanceCall(node, test_class); 2051 GenerateDirectCall(node_id,
2052 token_index,
2053 target,
2054 num_args,
2055 optional_argument_names);
2035 __ jmp(&done); 2056 __ jmp(&done);
2036 __ Bind(&next); 2057 __ Bind(&next);
2037 } 2058 }
2038 } 2059 }
2039 __ Bind(&done); 2060 __ Bind(&done);
2040
2041 return true;
2042 } 2061 }
2043 2062
2044 2063
2045 void OptimizingCodeGenerator::VisitInstanceCallNode(InstanceCallNode* node) { 2064 void OptimizingCodeGenerator::VisitInstanceCallNode(InstanceCallNode* node) {
2046 const int number_of_arguments = node->arguments()->length() + 1; 2065 const int number_of_arguments = node->arguments()->length() + 1;
2047 // Compute the receiver object and pass it as first argument to call. 2066 // Compute the receiver object and pass it as first argument to call.
2048 node->receiver()->Visit(this); 2067 node->receiver()->Visit(this);
2049 // Now compute rest of the arguments to the call. 2068 // Now compute rest of the arguments to the call.
2050 node->arguments()->Visit(this); 2069 node->arguments()->Visit(this);
2051 if (TryInlineInstanceCall(node)) { 2070 if (TryInlineInstanceCall(node)) {
2052 // Instance call is inlined. 2071 // Instance call is inlined.
2053 } else { 2072 } else {
2054 // Inline checks if possible and call function directly. 2073 GenerateCheckedInstanceCalls(node,
2055 if (!GenerateCheckedInstanceCalls(node)) { 2074 node->receiver(),
2056 GenerateInstanceCall(node->id(), 2075 node->id(),
2057 node->token_index(), 2076 node->token_index(),
2058 node->function_name(), 2077 number_of_arguments,
2059 number_of_arguments, 2078 node->arguments()->names());
2060 node->arguments()->names());
2061 }
2062 } 2079 }
2063 // Result is in EAX. 2080 // Result is in EAX.
2064 if (IsResultNeeded(node)) { 2081 if (IsResultNeeded(node)) {
2065 __ pushl(EAX); 2082 __ pushl(EAX);
2066 } 2083 }
2067 } 2084 }
2068 2085
2069 2086
2070 // Returns true if an instance call was replaced with its intrinsic. 2087 // Returns true if an instance call was replaced with its intrinsic.
2071 // Returns result in EAX. 2088 // Returns result in EAX.
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
2160 __ addl(ESP, Immediate(node->arguments()->length() * kWordSize)); 2177 __ addl(ESP, Immediate(node->arguments()->length() * kWordSize));
2161 // Result is in EAX. 2178 // Result is in EAX.
2162 if (IsResultNeeded(node)) { 2179 if (IsResultNeeded(node)) {
2163 __ pushl(EAX); 2180 __ pushl(EAX);
2164 } 2181 }
2165 } 2182 }
2166 2183
2167 } // namespace dart 2184 } // namespace dart
2168 2185
2169 #endif // defined TARGET_ARCH_IA32 2186 #endif // defined TARGET_ARCH_IA32
OLDNEW
« no previous file with comments | « vm/opt_code_generator_ia32.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698