| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 import 'dart:collection'; | 5 import 'dart:collection'; |
| 6 | 6 |
| 7 import 'package:js_runtime/shared/embedded_names.dart'; | 7 import 'package:js_runtime/shared/embedded_names.dart'; |
| 8 | 8 |
| 9 import '../closure.dart'; | 9 import '../closure.dart'; |
| 10 import '../common.dart'; | 10 import '../common.dart'; |
| (...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 406 /** | 406 /** |
| 407 * Try to inline [element] within the correct context of the builder. The | 407 * Try to inline [element] within the correct context of the builder. The |
| 408 * insertion point is the state of the builder. | 408 * insertion point is the state of the builder. |
| 409 */ | 409 */ |
| 410 bool tryInlineMethod(MethodElement element, Selector selector, TypeMask mask, | 410 bool tryInlineMethod(MethodElement element, Selector selector, TypeMask mask, |
| 411 List<HInstruction> providedArguments, ast.Node currentNode, | 411 List<HInstruction> providedArguments, ast.Node currentNode, |
| 412 {ResolutionInterfaceType instanceType}) { | 412 {ResolutionInterfaceType instanceType}) { |
| 413 registry.addImpact( | 413 registry.addImpact( |
| 414 backend.codegenEnqueuerListener.registerUsedElement(element)); | 414 backend.codegenEnqueuerListener.registerUsedElement(element)); |
| 415 | 415 |
| 416 if (backend.isJsInterop(element) && !element.isFactoryConstructor) { | 416 if (backend.nativeData.isJsInterop(element) && |
| 417 !element.isFactoryConstructor) { |
| 417 // We only inline factory JavaScript interop constructors. | 418 // We only inline factory JavaScript interop constructors. |
| 418 return false; | 419 return false; |
| 419 } | 420 } |
| 420 | 421 |
| 421 // Ensure that [element] is an implementation element. | 422 // Ensure that [element] is an implementation element. |
| 422 element = element.implementation; | 423 element = element.implementation; |
| 423 | 424 |
| 424 if (compiler.elementHasCompileTimeError(element)) return false; | 425 if (compiler.elementHasCompileTimeError(element)) return false; |
| 425 | 426 |
| 426 MethodElement function = element; | 427 MethodElement function = element; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 442 Elements.isStaticOrTopLevel(function) || | 443 Elements.isStaticOrTopLevel(function) || |
| 443 function.isGenerativeConstructorBody, | 444 function.isGenerativeConstructorBody, |
| 444 message: "Missing selector for inlining of $function.")); | 445 message: "Missing selector for inlining of $function.")); |
| 445 if (selector != null) { | 446 if (selector != null) { |
| 446 if (!selector.applies(function)) return false; | 447 if (!selector.applies(function)) return false; |
| 447 if (mask != null && !mask.canHit(function, selector, closedWorld)) { | 448 if (mask != null && !mask.canHit(function, selector, closedWorld)) { |
| 448 return false; | 449 return false; |
| 449 } | 450 } |
| 450 } | 451 } |
| 451 | 452 |
| 452 if (backend.isJsInterop(function)) return false; | 453 if (backend.nativeData.isJsInterop(function)) return false; |
| 453 | 454 |
| 454 // Don't inline operator== methods if the parameter can be null. | 455 // Don't inline operator== methods if the parameter can be null. |
| 455 if (function.name == '==') { | 456 if (function.name == '==') { |
| 456 if (function.enclosingClass != commonElements.objectClass && | 457 if (function.enclosingClass != commonElements.objectClass && |
| 457 providedArguments[1].canBeNull()) { | 458 providedArguments[1].canBeNull()) { |
| 458 return false; | 459 return false; |
| 459 } | 460 } |
| 460 } | 461 } |
| 461 | 462 |
| 462 // Generative constructors of native classes should not be called directly | 463 // Generative constructors of native classes should not be called directly |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 686 * Invariant: [functionElement] must be an implementation element. | 687 * Invariant: [functionElement] must be an implementation element. |
| 687 */ | 688 */ |
| 688 HGraph buildMethod(MethodElement functionElement) { | 689 HGraph buildMethod(MethodElement functionElement) { |
| 689 assert(invariant(functionElement, functionElement.isImplementation)); | 690 assert(invariant(functionElement, functionElement.isImplementation)); |
| 690 graph.calledInLoop = closedWorld.isCalledInLoop(functionElement); | 691 graph.calledInLoop = closedWorld.isCalledInLoop(functionElement); |
| 691 ast.FunctionExpression function = resolvedAst.node; | 692 ast.FunctionExpression function = resolvedAst.node; |
| 692 assert(function != null); | 693 assert(function != null); |
| 693 assert(elements.getFunctionDefinition(function) != null); | 694 assert(elements.getFunctionDefinition(function) != null); |
| 694 openFunction(functionElement, function); | 695 openFunction(functionElement, function); |
| 695 String name = functionElement.name; | 696 String name = functionElement.name; |
| 696 if (backend.isJsInterop(functionElement)) { | 697 if (backend.nativeData.isJsInterop(functionElement)) { |
| 697 push(invokeJsInteropFunction(functionElement, parameters.values.toList(), | 698 push(invokeJsInteropFunction(functionElement, parameters.values.toList(), |
| 698 sourceInformationBuilder.buildGeneric(function))); | 699 sourceInformationBuilder.buildGeneric(function))); |
| 699 var value = pop(); | 700 var value = pop(); |
| 700 closeAndGotoExit(new HReturn( | 701 closeAndGotoExit(new HReturn( |
| 701 value, sourceInformationBuilder.buildReturn(functionElement.node))); | 702 value, sourceInformationBuilder.buildReturn(functionElement.node))); |
| 702 return closeFunction(); | 703 return closeFunction(); |
| 703 } | 704 } |
| 704 assert(invariant(functionElement, !function.modifiers.isExternal)); | 705 assert(invariant(functionElement, !function.modifiers.isExternal)); |
| 705 | 706 |
| 706 // If [functionElement] is `operator==` we explicitly add a null check at | 707 // If [functionElement] is `operator==` we explicitly add a null check at |
| (...skipping 466 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1173 * to, starting from the current constructor. | 1174 * to, starting from the current constructor. |
| 1174 * - Call the constructor bodies, starting from the constructor(s) in the | 1175 * - Call the constructor bodies, starting from the constructor(s) in the |
| 1175 * super class(es). | 1176 * super class(es). |
| 1176 */ | 1177 */ |
| 1177 HGraph buildFactory(ResolvedAst resolvedAst) { | 1178 HGraph buildFactory(ResolvedAst resolvedAst) { |
| 1178 ConstructorElement functionElement = resolvedAst.element; | 1179 ConstructorElement functionElement = resolvedAst.element; |
| 1179 functionElement = functionElement.implementation; | 1180 functionElement = functionElement.implementation; |
| 1180 ClassElement classElement = functionElement.enclosingClass.implementation; | 1181 ClassElement classElement = functionElement.enclosingClass.implementation; |
| 1181 bool isNativeUpgradeFactory = | 1182 bool isNativeUpgradeFactory = |
| 1182 backend.nativeData.isNativeOrExtendsNative(classElement) && | 1183 backend.nativeData.isNativeOrExtendsNative(classElement) && |
| 1183 !backend.isJsInterop(classElement); | 1184 !backend.nativeData.isJsInterop(classElement); |
| 1184 ast.FunctionExpression function; | 1185 ast.FunctionExpression function; |
| 1185 if (resolvedAst.kind == ResolvedAstKind.PARSED) { | 1186 if (resolvedAst.kind == ResolvedAstKind.PARSED) { |
| 1186 function = resolvedAst.node; | 1187 function = resolvedAst.node; |
| 1187 } | 1188 } |
| 1188 | 1189 |
| 1189 // Note that constructors (like any other static function) do not need | 1190 // Note that constructors (like any other static function) do not need |
| 1190 // to deal with optional arguments. It is the callers job to provide all | 1191 // to deal with optional arguments. It is the callers job to provide all |
| 1191 // arguments as if they were positional. | 1192 // arguments as if they were positional. |
| 1192 | 1193 |
| 1193 if (inliningStack.isEmpty) { | 1194 if (inliningStack.isEmpty) { |
| (...skipping 1309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2503 HInstruction compileArgument(ast.Node argument) { | 2504 HInstruction compileArgument(ast.Node argument) { |
| 2504 visit(argument); | 2505 visit(argument); |
| 2505 return pop(); | 2506 return pop(); |
| 2506 } | 2507 } |
| 2507 | 2508 |
| 2508 return Elements.makeArgumentsList<HInstruction>( | 2509 return Elements.makeArgumentsList<HInstruction>( |
| 2509 callStructure, | 2510 callStructure, |
| 2510 arguments, | 2511 arguments, |
| 2511 element, | 2512 element, |
| 2512 compileArgument, | 2513 compileArgument, |
| 2513 backend.isJsInterop(element) | 2514 backend.nativeData.isJsInterop(element) |
| 2514 ? handleConstantForOptionalParameterJsInterop | 2515 ? handleConstantForOptionalParameterJsInterop |
| 2515 : handleConstantForOptionalParameter); | 2516 : handleConstantForOptionalParameter); |
| 2516 } | 2517 } |
| 2517 | 2518 |
| 2518 void addGenericSendArgumentsToList( | 2519 void addGenericSendArgumentsToList( |
| 2519 Link<ast.Node> link, List<HInstruction> list) { | 2520 Link<ast.Node> link, List<HInstruction> list) { |
| 2520 for (; !link.isEmpty; link = link.tail) { | 2521 for (; !link.isEmpty; link = link.tail) { |
| 2521 visit(link.head); | 2522 visit(link.head); |
| 2522 list.add(pop()); | 2523 list.add(pop()); |
| 2523 } | 2524 } |
| (...skipping 783 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3307 } else if (isGrowableListConstructorCall) { | 3308 } else if (isGrowableListConstructorCall) { |
| 3308 TypeMask inferred = _inferredTypeOfNewList(send); | 3309 TypeMask inferred = _inferredTypeOfNewList(send); |
| 3309 return inferred.containsAll(closedWorld) | 3310 return inferred.containsAll(closedWorld) |
| 3310 ? commonMasks.extendableArrayType | 3311 ? commonMasks.extendableArrayType |
| 3311 : inferred; | 3312 : inferred; |
| 3312 } else if (Elements.isConstructorOfTypedArraySubclass( | 3313 } else if (Elements.isConstructorOfTypedArraySubclass( |
| 3313 originalElement, closedWorld)) { | 3314 originalElement, closedWorld)) { |
| 3314 isFixedList = true; | 3315 isFixedList = true; |
| 3315 TypeMask inferred = _inferredTypeOfNewList(send); | 3316 TypeMask inferred = _inferredTypeOfNewList(send); |
| 3316 ClassElement cls = element.enclosingClass; | 3317 ClassElement cls = element.enclosingClass; |
| 3317 assert(backend.isNative(cls.thisType.element)); | 3318 assert(backend.nativeData.isNativeClass(cls)); |
| 3318 return inferred.containsAll(closedWorld) | 3319 return inferred.containsAll(closedWorld) |
| 3319 ? new TypeMask.nonNullExact(cls.thisType.element, closedWorld) | 3320 ? new TypeMask.nonNullExact(cls, closedWorld) |
| 3320 : inferred; | 3321 : inferred; |
| 3321 } else if (element.isGenerativeConstructor) { | 3322 } else if (element.isGenerativeConstructor) { |
| 3322 ClassElement cls = element.enclosingClass; | 3323 ClassElement cls = element.enclosingClass; |
| 3323 if (cls.isAbstract) { | 3324 if (cls.isAbstract) { |
| 3324 // An error will be thrown. | 3325 // An error will be thrown. |
| 3325 return new TypeMask.nonNullEmpty(); | 3326 return new TypeMask.nonNullEmpty(); |
| 3326 } else { | 3327 } else { |
| 3327 return new TypeMask.nonNullExact(cls.thisType.element, closedWorld); | 3328 return new TypeMask.nonNullExact(cls, closedWorld); |
| 3328 } | 3329 } |
| 3329 } else { | 3330 } else { |
| 3330 return TypeMaskFactory.inferredReturnTypeForElement( | 3331 return TypeMaskFactory.inferredReturnTypeForElement( |
| 3331 originalElement, globalInferenceResults); | 3332 originalElement, globalInferenceResults); |
| 3332 } | 3333 } |
| 3333 } | 3334 } |
| 3334 | 3335 |
| 3335 CallStructure callStructure = elements.getSelector(send).callStructure; | 3336 CallStructure callStructure = elements.getSelector(send).callStructure; |
| 3336 ConstructorElement constructorDeclaration = constructor; | 3337 ConstructorElement constructorDeclaration = constructor; |
| 3337 ConstructorElement constructorImplementation = constructor.implementation; | 3338 ConstructorElement constructorImplementation = constructor.implementation; |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3397 if (constructorImplementation.isMalformed || | 3398 if (constructorImplementation.isMalformed || |
| 3398 !callStructure.signatureApplies(constructorImplementation.type)) { | 3399 !callStructure.signatureApplies(constructorImplementation.type)) { |
| 3399 generateWrongArgumentCountError(send, constructor, send.arguments); | 3400 generateWrongArgumentCountError(send, constructor, send.arguments); |
| 3400 return; | 3401 return; |
| 3401 } | 3402 } |
| 3402 | 3403 |
| 3403 List<HInstruction> inputs = <HInstruction>[]; | 3404 List<HInstruction> inputs = <HInstruction>[]; |
| 3404 if (constructor.isGenerativeConstructor && | 3405 if (constructor.isGenerativeConstructor && |
| 3405 backend.nativeData | 3406 backend.nativeData |
| 3406 .isNativeOrExtendsNative(constructor.enclosingClass) && | 3407 .isNativeOrExtendsNative(constructor.enclosingClass) && |
| 3407 !backend.isJsInterop(constructor)) { | 3408 !backend.nativeData.isJsInterop(constructor)) { |
| 3408 // Native class generative constructors take a pre-constructed object. | 3409 // Native class generative constructors take a pre-constructed object. |
| 3409 inputs.add(graph.addConstantNull(closedWorld)); | 3410 inputs.add(graph.addConstantNull(closedWorld)); |
| 3410 } | 3411 } |
| 3411 inputs.addAll(makeStaticArgumentList( | 3412 inputs.addAll(makeStaticArgumentList( |
| 3412 callStructure, send.arguments, constructorImplementation)); | 3413 callStructure, send.arguments, constructorImplementation)); |
| 3413 | 3414 |
| 3414 TypeMask elementType = computeType(constructor); | 3415 TypeMask elementType = computeType(constructor); |
| 3415 if (isFixedListConstructorCall) { | 3416 if (isFixedListConstructorCall) { |
| 3416 if (!inputs[0].isNumber(closedWorld)) { | 3417 if (!inputs[0].isNumber(closedWorld)) { |
| 3417 HTypeConversion conversion = new HTypeConversion( | 3418 HTypeConversion conversion = new HTypeConversion( |
| (...skipping 586 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4004 push(new HInvokeDynamicSetter(selector, mask, null, inputs, type) | 4005 push(new HInvokeDynamicSetter(selector, mask, null, inputs, type) |
| 4005 ..sourceInformation = sourceInformation); | 4006 ..sourceInformation = sourceInformation); |
| 4006 } else { | 4007 } else { |
| 4007 push(new HInvokeDynamicMethod(selector, mask, inputs, type, isIntercepted) | 4008 push(new HInvokeDynamicMethod(selector, mask, inputs, type, isIntercepted) |
| 4008 ..sourceInformation = sourceInformation); | 4009 ..sourceInformation = sourceInformation); |
| 4009 } | 4010 } |
| 4010 } | 4011 } |
| 4011 | 4012 |
| 4012 HForeignCode invokeJsInteropFunction(MethodElement element, | 4013 HForeignCode invokeJsInteropFunction(MethodElement element, |
| 4013 List<HInstruction> arguments, SourceInformation sourceInformation) { | 4014 List<HInstruction> arguments, SourceInformation sourceInformation) { |
| 4014 assert(backend.isJsInterop(element)); | 4015 assert(backend.nativeData.isJsInterop(element)); |
| 4015 nativeEmitter.nativeMethods.add(element); | 4016 nativeEmitter.nativeMethods.add(element); |
| 4016 | 4017 |
| 4017 if (element.isFactoryConstructor && | 4018 if (element.isFactoryConstructor && |
| 4018 backend.jsInteropAnalysis | 4019 backend.jsInteropAnalysis |
| 4019 .hasAnonymousAnnotation(element.contextClass)) { | 4020 .hasAnonymousAnnotation(element.contextClass)) { |
| 4020 // Factory constructor that is syntactic sugar for creating a JavaScript | 4021 // Factory constructor that is syntactic sugar for creating a JavaScript |
| 4021 // object literal. | 4022 // object literal. |
| 4022 ConstructorElement constructor = element; | 4023 ConstructorElement constructor = element; |
| 4023 FunctionSignature params = constructor.functionSignature; | 4024 FunctionSignature params = constructor.functionSignature; |
| 4024 int i = 0; | 4025 int i = 0; |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4073 // Native behavior effects here are similar to native/behavior.dart. | 4074 // Native behavior effects here are similar to native/behavior.dart. |
| 4074 // The return type is dynamic if we don't trust js-interop type | 4075 // The return type is dynamic if we don't trust js-interop type |
| 4075 // declarations. | 4076 // declarations. |
| 4076 nativeBehavior.typesReturned.add( | 4077 nativeBehavior.typesReturned.add( |
| 4077 compiler.options.trustJSInteropTypeAnnotations | 4078 compiler.options.trustJSInteropTypeAnnotations |
| 4078 ? type | 4079 ? type |
| 4079 : const ResolutionDynamicType()); | 4080 : const ResolutionDynamicType()); |
| 4080 | 4081 |
| 4081 // The allocation effects include the declared type if it is native (which | 4082 // The allocation effects include the declared type if it is native (which |
| 4082 // includes js interop types). | 4083 // includes js interop types). |
| 4083 if (type.element != null && backend.isNative(type.element)) { | 4084 if (type is ResolutionInterfaceType && |
| 4085 backend.nativeData.isNativeClass(type.element)) { |
| 4084 nativeBehavior.typesInstantiated.add(type); | 4086 nativeBehavior.typesInstantiated.add(type); |
| 4085 } | 4087 } |
| 4086 | 4088 |
| 4087 // It also includes any other JS interop type if we don't trust the | 4089 // It also includes any other JS interop type if we don't trust the |
| 4088 // annotation or if is declared too broad. | 4090 // annotation or if is declared too broad. |
| 4089 if (!compiler.options.trustJSInteropTypeAnnotations || | 4091 if (!compiler.options.trustJSInteropTypeAnnotations || |
| 4090 type.isObject || | 4092 type.isObject || |
| 4091 type.isDynamic) { | 4093 type.isDynamic) { |
| 4092 ClassElement cls = backend.helpers.jsJavaScriptObjectClass; | 4094 ClassElement cls = backend.helpers.jsJavaScriptObjectClass; |
| 4093 nativeBehavior.typesInstantiated.add(cls.thisType); | 4095 nativeBehavior.typesInstantiated.add(cls.thisType); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 4121 return; | 4123 return; |
| 4122 } | 4124 } |
| 4123 | 4125 |
| 4124 if (typeMask == null) { | 4126 if (typeMask == null) { |
| 4125 typeMask = TypeMaskFactory.inferredReturnTypeForElement( | 4127 typeMask = TypeMaskFactory.inferredReturnTypeForElement( |
| 4126 element, globalInferenceResults); | 4128 element, globalInferenceResults); |
| 4127 } | 4129 } |
| 4128 bool targetCanThrow = !closedWorld.getCannotThrow(element); | 4130 bool targetCanThrow = !closedWorld.getCannotThrow(element); |
| 4129 // TODO(5346): Try to avoid the need for calling [declaration] before | 4131 // TODO(5346): Try to avoid the need for calling [declaration] before |
| 4130 var instruction; | 4132 var instruction; |
| 4131 if (backend.isJsInterop(element)) { | 4133 if (backend.nativeData.isJsInterop(element)) { |
| 4132 instruction = | 4134 instruction = |
| 4133 invokeJsInteropFunction(element, arguments, sourceInformation); | 4135 invokeJsInteropFunction(element, arguments, sourceInformation); |
| 4134 } else { | 4136 } else { |
| 4135 // creating an [HInvokeStatic]. | 4137 // creating an [HInvokeStatic]. |
| 4136 instruction = new HInvokeStatic(element, arguments, typeMask, | 4138 instruction = new HInvokeStatic(element, arguments, typeMask, |
| 4137 targetCanThrow: targetCanThrow) | 4139 targetCanThrow: targetCanThrow) |
| 4138 ..sourceInformation = sourceInformation; | 4140 ..sourceInformation = sourceInformation; |
| 4139 if (currentInlinedInstantiations.isNotEmpty) { | 4141 if (currentInlinedInstantiations.isNotEmpty) { |
| 4140 instruction.instantiatedTypes = | 4142 instruction.instantiatedTypes = |
| 4141 new List<ResolutionDartType>.from(currentInlinedInstantiations); | 4143 new List<ResolutionDartType>.from(currentInlinedInstantiations); |
| (...skipping 2585 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6727 this.oldReturnLocal, | 6729 this.oldReturnLocal, |
| 6728 this.oldReturnType, | 6730 this.oldReturnType, |
| 6729 this.oldResolvedAst, | 6731 this.oldResolvedAst, |
| 6730 this.oldStack, | 6732 this.oldStack, |
| 6731 this.oldLocalsHandler, | 6733 this.oldLocalsHandler, |
| 6732 this.inTryStatement, | 6734 this.inTryStatement, |
| 6733 this.allFunctionsCalledOnce, | 6735 this.allFunctionsCalledOnce, |
| 6734 this.oldElementInferenceResults) | 6736 this.oldElementInferenceResults) |
| 6735 : super(function); | 6737 : super(function); |
| 6736 } | 6738 } |
| OLD | NEW |