| OLD | NEW |
| 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/code_generator.h" | 8 #include "vm/code_generator.h" |
| 9 | 9 |
| 10 #include "lib/error.h" | 10 #include "lib/error.h" |
| (...skipping 837 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 848 node->scope()->PreserveOuterScope(current_context_level)); | 848 node->scope()->PreserveOuterScope(current_context_level)); |
| 849 ASSERT(!function.HasCode()); | 849 ASSERT(!function.HasCode()); |
| 850 ASSERT(function.context_scope() == ContextScope::null()); | 850 ASSERT(function.context_scope() == ContextScope::null()); |
| 851 function.set_context_scope(context_scope); | 851 function.set_context_scope(context_scope); |
| 852 } else { | 852 } else { |
| 853 ASSERT(function.context_scope() != ContextScope::null()); | 853 ASSERT(function.context_scope() != ContextScope::null()); |
| 854 if (function.IsImplicitInstanceClosureFunction()) { | 854 if (function.IsImplicitInstanceClosureFunction()) { |
| 855 node->receiver()->Visit(this); | 855 node->receiver()->Visit(this); |
| 856 } | 856 } |
| 857 } | 857 } |
| 858 // The function type of a closure may be parameterized. In that case, pass | 858 // The function type of a closure may have type arguments. In that case, pass |
| 859 // the type arguments of the instantiator. | 859 // the type arguments of the instantiator. |
| 860 const Class& cls = Class::Handle(function.signature_class()); | 860 const Class& cls = Class::Handle(function.signature_class()); |
| 861 ASSERT(!cls.IsNull()); | 861 ASSERT(!cls.IsNull()); |
| 862 const bool is_cls_parameterized = cls.NumTypeArguments() > 0; | 862 const bool requires_type_arguments = cls.HasTypeArguments(); |
| 863 if (is_cls_parameterized) { | 863 if (requires_type_arguments) { |
| 864 ASSERT(!function.IsImplicitStaticClosureFunction()); | 864 ASSERT(!function.IsImplicitStaticClosureFunction()); |
| 865 GenerateInstantiatorTypeArguments(); | 865 GenerateInstantiatorTypeArguments(); |
| 866 } | 866 } |
| 867 const Code& stub = Code::Handle( | 867 const Code& stub = Code::Handle( |
| 868 StubCode::GetAllocationStubForClosure(function)); | 868 StubCode::GetAllocationStubForClosure(function)); |
| 869 const ExternalLabel label(function.ToCString(), stub.EntryPoint()); | 869 const ExternalLabel label(function.ToCString(), stub.EntryPoint()); |
| 870 GenerateCall(node->token_index(), &label); | 870 GenerateCall(node->token_index(), &label); |
| 871 if (is_cls_parameterized) { | 871 if (requires_type_arguments) { |
| 872 __ popl(ECX); // Pop type arguments. | 872 __ popl(ECX); // Pop type arguments. |
| 873 } | 873 } |
| 874 if (function.IsImplicitInstanceClosureFunction()) { | 874 if (function.IsImplicitInstanceClosureFunction()) { |
| 875 __ popl(ECX); // Pop receiver. | 875 __ popl(ECX); // Pop receiver. |
| 876 } | 876 } |
| 877 if (IsResultNeeded(node)) { | 877 if (IsResultNeeded(node)) { |
| 878 __ pushl(EAX); | 878 __ pushl(EAX); |
| 879 } | 879 } |
| 880 } | 880 } |
| 881 | 881 |
| (...skipping 490 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1372 __ cmpl(EAX, raw_null); | 1372 __ cmpl(EAX, raw_null); |
| 1373 __ j(NOT_EQUAL, &non_null, Assembler::kNearJump); | 1373 __ j(NOT_EQUAL, &non_null, Assembler::kNearJump); |
| 1374 __ PushObject(negate_result ? bool_true : bool_false); | 1374 __ PushObject(negate_result ? bool_true : bool_false); |
| 1375 __ jmp(&done, Assembler::kNearJump); | 1375 __ jmp(&done, Assembler::kNearJump); |
| 1376 | 1376 |
| 1377 __ Bind(&non_null); | 1377 __ Bind(&non_null); |
| 1378 // If type is instantiated and non-parameterized, we can inline code | 1378 // If type is instantiated and non-parameterized, we can inline code |
| 1379 // checking whether the tested instance is a Smi. | 1379 // checking whether the tested instance is a Smi. |
| 1380 if (type.IsInstantiated()) { | 1380 if (type.IsInstantiated()) { |
| 1381 const Class& type_class = Class::ZoneHandle(type.type_class()); | 1381 const Class& type_class = Class::ZoneHandle(type.type_class()); |
| 1382 const bool is_type_class_parameterized = type_class.NumTypeArguments() > 0; | 1382 const bool requires_type_arguments = type_class.HasTypeArguments(); |
| 1383 // A Smi object cannot be the instance of a parameterized class. | 1383 // A Smi object cannot be the instance of a parameterized class. |
| 1384 // A class equality check is only applicable to a non-parameterized class. | 1384 // A class equality check is only applicable to a non-parameterized class. |
| 1385 // TODO(regis): Should we still inline a Smi type check when checking for a | 1385 // TODO(regis): Should we still inline a Smi type check when checking for a |
| 1386 // parameterized type and return false for a Smi's without calling the | 1386 // parameterized type and return false for a Smi's without calling the |
| 1387 // runtime? | 1387 // runtime? |
| 1388 if (!is_type_class_parameterized) { | 1388 if (!requires_type_arguments) { |
| 1389 Label compare_classes; | 1389 Label compare_classes; |
| 1390 __ testl(EAX, Immediate(kSmiTagMask)); | 1390 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1391 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump); | 1391 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump); |
| 1392 // Object is Smi. | 1392 // Object is Smi. |
| 1393 const Class& smi_class = Class::Handle(Smi::Class()); | 1393 const Class& smi_class = Class::Handle(Smi::Class()); |
| 1394 // TODO(regis): We should introduce a SmiType. | 1394 // TODO(regis): We should introduce a SmiType. |
| 1395 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), | 1395 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), |
| 1396 type_class, | 1396 type_class, |
| 1397 TypeArguments::Handle())) { | 1397 TypeArguments::Handle())) { |
| 1398 __ PushObject(negate_result ? bool_false : bool_true); | 1398 __ PushObject(negate_result ? bool_false : bool_true); |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1491 const Immediate raw_null = | 1491 const Immediate raw_null = |
| 1492 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1492 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1493 Label done, runtime_call; | 1493 Label done, runtime_call; |
| 1494 __ cmpl(EAX, raw_null); | 1494 __ cmpl(EAX, raw_null); |
| 1495 __ j(EQUAL, &done, Assembler::kNearJump); | 1495 __ j(EQUAL, &done, Assembler::kNearJump); |
| 1496 | 1496 |
| 1497 // If dst_type is instantiated and non-parameterized, we can inline code | 1497 // If dst_type is instantiated and non-parameterized, we can inline code |
| 1498 // checking whether the assigned instance is a Smi. | 1498 // checking whether the assigned instance is a Smi. |
| 1499 if (dst_type.IsInstantiated()) { | 1499 if (dst_type.IsInstantiated()) { |
| 1500 const Class& dst_type_class = Class::ZoneHandle(dst_type.type_class()); | 1500 const Class& dst_type_class = Class::ZoneHandle(dst_type.type_class()); |
| 1501 const bool is_dst_type_parameterized = | 1501 const bool dst_has_type_arguments = dst_type_class.HasTypeArguments(); |
| 1502 dst_type_class.NumTypeArguments() > 0; | |
| 1503 // A Smi object cannot be the instance of a parameterized class. | 1502 // A Smi object cannot be the instance of a parameterized class. |
| 1504 // A class equality check is only applicable to a non-parameterized class. | 1503 // A class equality check is only applicable to a non-parameterized class. |
| 1505 if (!is_dst_type_parameterized) { | 1504 if (!dst_has_type_arguments) { |
| 1506 Label compare_classes; | 1505 Label compare_classes; |
| 1507 __ testl(EAX, Immediate(kSmiTagMask)); | 1506 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1508 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump); | 1507 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump); |
| 1509 // Object is Smi. | 1508 // Object is Smi. |
| 1510 const Class& smi_class = Class::Handle(Smi::Class()); | 1509 const Class& smi_class = Class::Handle(Smi::Class()); |
| 1511 // TODO(regis): We should introduce a SmiType. | 1510 // TODO(regis): We should introduce a SmiType. |
| 1512 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), | 1511 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), |
| 1513 dst_type_class, | 1512 dst_type_class, |
| 1514 TypeArguments::Handle())) { | 1513 TypeArguments::Handle())) { |
| 1515 // Successful assignable type check: return object in EAX. | 1514 // Successful assignable type check: return object in EAX. |
| (...skipping 672 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2188 // call) and pushes the type argument vector that will be passed as implicit | 2187 // call) and pushes the type argument vector that will be passed as implicit |
| 2189 // first parameter to the factory. | 2188 // first parameter to the factory. |
| 2190 // For a constructor call allocating an object of a parameterized class, pushes | 2189 // For a constructor call allocating an object of a parameterized class, pushes |
| 2191 // the type arguments and the type arguments of the instantiator, without ever | 2190 // the type arguments and the type arguments of the instantiator, without ever |
| 2192 // generating an additional run time call. | 2191 // generating an additional run time call. |
| 2193 // Does nothing for a constructor call allocating an object of a non | 2192 // Does nothing for a constructor call allocating an object of a non |
| 2194 // parameterized class. | 2193 // parameterized class. |
| 2195 // Note that a class without proper type parameters may still be parameterized, | 2194 // Note that a class without proper type parameters may still be parameterized, |
| 2196 // e.g. class A extends Array<int>. | 2195 // e.g. class A extends Array<int>. |
| 2197 void CodeGenerator::GenerateTypeArguments(ConstructorCallNode* node, | 2196 void CodeGenerator::GenerateTypeArguments(ConstructorCallNode* node, |
| 2198 bool is_cls_parameterized) { | 2197 bool requires_type_arguments) { |
| 2199 const Immediate raw_null = | 2198 const Immediate raw_null = |
| 2200 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 2199 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 2201 // Instantiate the type arguments if necessary. | 2200 // Instantiate the type arguments if necessary. |
| 2202 if (node->type_arguments().IsNull() || | 2201 if (node->type_arguments().IsNull() || |
| 2203 node->type_arguments().IsInstantiated()) { | 2202 node->type_arguments().IsInstantiated()) { |
| 2204 if (node->constructor().IsFactory() || is_cls_parameterized) { | 2203 if (node->constructor().IsFactory() || requires_type_arguments) { |
| 2205 // A factory requires the type arguments as first parameter. | 2204 // A factory requires the type arguments as first parameter. |
| 2206 __ PushObject(node->type_arguments()); | 2205 __ PushObject(node->type_arguments()); |
| 2207 if (!node->constructor().IsFactory()) { | 2206 if (!node->constructor().IsFactory()) { |
| 2208 // The allocator additionally requires the instantiator type arguments. | 2207 // The allocator additionally requires the instantiator type arguments. |
| 2209 __ pushl(raw_null); // Null instantiator. | 2208 __ pushl(raw_null); // Null instantiator. |
| 2210 } | 2209 } |
| 2211 } | 2210 } |
| 2212 } else { | 2211 } else { |
| 2213 // The type arguments are uninstantiated. | 2212 // The type arguments are uninstantiated. |
| 2214 ASSERT(node->constructor().IsFactory() || is_cls_parameterized); | 2213 ASSERT(node->constructor().IsFactory() || requires_type_arguments); |
| 2215 GenerateInstantiatorTypeArguments(); | 2214 GenerateInstantiatorTypeArguments(); |
| 2216 __ popl(EAX); // Pop instantiator. | 2215 __ popl(EAX); // Pop instantiator. |
| 2217 // EAX is the instantiator TypeArguments object (or null). | 2216 // EAX is the instantiator TypeArguments object (or null). |
| 2218 // If EAX is null, no need to instantiate the type arguments, use null, and | 2217 // If EAX is null, no need to instantiate the type arguments, use null, and |
| 2219 // allocate an object of a raw type. | 2218 // allocate an object of a raw type. |
| 2220 Label type_arguments_instantiated, type_arguments_uninstantiated; | 2219 Label type_arguments_instantiated, type_arguments_uninstantiated; |
| 2221 __ cmpl(EAX, raw_null); | 2220 __ cmpl(EAX, raw_null); |
| 2222 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); | 2221 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); |
| 2223 | 2222 |
| 2224 // Instantiate non-null type arguments. | 2223 // Instantiate non-null type arguments. |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2260 __ pushl(EAX); // Instantiated type arguments. | 2259 __ pushl(EAX); // Instantiated type arguments. |
| 2261 __ pushl(raw_null); // Null instantiator. | 2260 __ pushl(raw_null); // Null instantiator. |
| 2262 __ Bind(&type_arguments_pushed); | 2261 __ Bind(&type_arguments_pushed); |
| 2263 } | 2262 } |
| 2264 } | 2263 } |
| 2265 } | 2264 } |
| 2266 | 2265 |
| 2267 | 2266 |
| 2268 void CodeGenerator::VisitConstructorCallNode(ConstructorCallNode* node) { | 2267 void CodeGenerator::VisitConstructorCallNode(ConstructorCallNode* node) { |
| 2269 const Class& cls = Class::ZoneHandle(node->constructor().owner()); | 2268 const Class& cls = Class::ZoneHandle(node->constructor().owner()); |
| 2270 const bool is_cls_parameterized = cls.NumTypeArguments() > 0; | 2269 const bool requires_type_arguments = cls.HasTypeArguments(); |
| 2271 GenerateTypeArguments(node, is_cls_parameterized); | 2270 GenerateTypeArguments(node, requires_type_arguments); |
| 2272 if (node->constructor().IsFactory()) { | 2271 if (node->constructor().IsFactory()) { |
| 2273 // The top of stack is an instantiated TypeArguments object (or null). | 2272 // The top of stack is an instantiated TypeArguments object (or null). |
| 2274 int num_args = node->arguments()->length() + 1; // +1 to include type args. | 2273 int num_args = node->arguments()->length() + 1; // +1 to include type args. |
| 2275 node->arguments()->Visit(this); | 2274 node->arguments()->Visit(this); |
| 2276 // Call the factory. | 2275 // Call the factory. |
| 2277 __ LoadObject(ECX, node->constructor()); | 2276 __ LoadObject(ECX, node->constructor()); |
| 2278 __ LoadObject(EDX, ArgumentsDescriptor(num_args, | 2277 __ LoadObject(EDX, ArgumentsDescriptor(num_args, |
| 2279 node->arguments()->names())); | 2278 node->arguments()->names())); |
| 2280 GenerateCall(node->token_index(), &StubCode::CallStaticFunctionLabel()); | 2279 GenerateCall(node->token_index(), &StubCode::CallStaticFunctionLabel()); |
| 2281 // Factory constructor returns object in EAX. | 2280 // Factory constructor returns object in EAX. |
| 2282 __ addl(ESP, Immediate(num_args * kWordSize)); | 2281 __ addl(ESP, Immediate(num_args * kWordSize)); |
| 2283 if (IsResultNeeded(node)) { | 2282 if (IsResultNeeded(node)) { |
| 2284 __ pushl(EAX); | 2283 __ pushl(EAX); |
| 2285 } | 2284 } |
| 2286 return; | 2285 return; |
| 2287 } | 2286 } |
| 2288 | 2287 |
| 2289 // If cls is parameterized, the type arguments and the instantiator's | 2288 // If cls is parameterized, the type arguments and the instantiator's |
| 2290 // type arguments are on the stack. | 2289 // type arguments are on the stack. |
| 2291 const Code& stub = Code::Handle(StubCode::GetAllocationStubForClass(cls)); | 2290 const Code& stub = Code::Handle(StubCode::GetAllocationStubForClass(cls)); |
| 2292 const ExternalLabel label(cls.ToCString(), stub.EntryPoint()); | 2291 const ExternalLabel label(cls.ToCString(), stub.EntryPoint()); |
| 2293 GenerateCall(node->token_index(), &label); | 2292 GenerateCall(node->token_index(), &label); |
| 2294 if (is_cls_parameterized) { | 2293 if (requires_type_arguments) { |
| 2295 __ popl(ECX); // Pop type arguments. | 2294 __ popl(ECX); // Pop type arguments. |
| 2296 __ popl(ECX); // Pop instantiator type arguments. | 2295 __ popl(ECX); // Pop instantiator type arguments. |
| 2297 } | 2296 } |
| 2298 | 2297 |
| 2299 if (IsResultNeeded(node)) { | 2298 if (IsResultNeeded(node)) { |
| 2300 __ pushl(EAX); // Set up return value from allocate. | 2299 __ pushl(EAX); // Set up return value from allocate. |
| 2301 } | 2300 } |
| 2302 __ pushl(EAX); // First argument(this) for constructor call which follows. | 2301 __ pushl(EAX); // First argument(this) for constructor call which follows. |
| 2303 | 2302 |
| 2304 // Now setup rest of the arguments for the constructor call. | 2303 // Now setup rest of the arguments for the constructor call. |
| (...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2622 const Class& cls = Class::Handle(parsed_function_.function().owner()); | 2621 const Class& cls = Class::Handle(parsed_function_.function().owner()); |
| 2623 const Script& script = Script::Handle(cls.script()); | 2622 const Script& script = Script::Handle(cls.script()); |
| 2624 Parser::ReportMsg(script, token_index, "Error", error_msg, format, args); | 2623 Parser::ReportMsg(script, token_index, "Error", error_msg, format, args); |
| 2625 Isolate::Current()->long_jump_base()->Jump(1, error_msg); | 2624 Isolate::Current()->long_jump_base()->Jump(1, error_msg); |
| 2626 UNREACHABLE(); | 2625 UNREACHABLE(); |
| 2627 } | 2626 } |
| 2628 | 2627 |
| 2629 } // namespace dart | 2628 } // namespace dart |
| 2630 | 2629 |
| 2631 #endif // defined TARGET_ARCH_IA32 | 2630 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |