| 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 part of ssa; | 5 part of ssa; |
| 6 | 6 |
| 7 class SsaCodeGeneratorTask extends CompilerTask { | 7 class SsaCodeGeneratorTask extends CompilerTask { |
| 8 | 8 |
| 9 final JavaScriptBackend backend; | 9 final JavaScriptBackend backend; |
| 10 | 10 |
| 11 SsaCodeGeneratorTask(JavaScriptBackend backend) | 11 SsaCodeGeneratorTask(JavaScriptBackend backend) |
| 12 : this.backend = backend, | 12 : this.backend = backend, |
| 13 super(backend.compiler); | 13 super(backend.compiler); |
| 14 String get name => 'SSA code generator'; | 14 String get name => 'SSA code generator'; |
| 15 NativeEmitter get nativeEmitter => backend.emitter.nativeEmitter; | 15 NativeEmitter get nativeEmitter => backend.emitter.nativeEmitter; |
| 16 | 16 |
| 17 | 17 |
| 18 js.Node attachPosition(js.Node node, Element element) { | 18 js.Node attachPosition(js.Node node, Element element) { |
| 19 // TODO(sra): Attaching positions might be cleaner if the source position | 19 // TODO(sra): Attaching positions might be cleaner if the source position |
| 20 // was on a wrapping node. | 20 // was on a wrapping node. |
| 21 SourceFile sourceFile = sourceFileOfElement(element); | 21 SourceFile sourceFile = sourceFileOfElement(element); |
| 22 ast.Node expression = element.implementation.parseNode(backend.compiler); | 22 ast.Node expression = element.implementation.parseNode(backend.compiler); |
| 23 Token beginToken; | 23 Token beginToken; |
| 24 Token endToken; | 24 Token endToken; |
| 25 if (expression == null) { | 25 if (expression == null) { |
| 26 // Synthesized node. Use the enclosing element for the location. | 26 // Synthesized node. Use the enclosing element for the location. |
| 27 beginToken = endToken = element.position(); | 27 beginToken = endToken = element.position; |
| 28 } else { | 28 } else { |
| 29 beginToken = expression.getBeginToken(); | 29 beginToken = expression.getBeginToken(); |
| 30 endToken = expression.getEndToken(); | 30 endToken = expression.getEndToken(); |
| 31 } | 31 } |
| 32 // TODO(podivilov): find the right sourceFile here and remove offset | 32 // TODO(podivilov): find the right sourceFile here and remove offset |
| 33 // checks below. | 33 // checks below. |
| 34 var sourcePosition, endSourcePosition; | 34 var sourcePosition, endSourcePosition; |
| 35 if (beginToken.charOffset < sourceFile.length) { | 35 if (beginToken.charOffset < sourceFile.length) { |
| 36 sourcePosition = new TokenSourceFileLocation(sourceFile, beginToken); | 36 sourcePosition = new TokenSourceFileLocation(sourceFile, beginToken); |
| 37 } | 37 } |
| 38 if (endToken.charOffset < sourceFile.length) { | 38 if (endToken.charOffset < sourceFile.length) { |
| 39 endSourcePosition = new TokenSourceFileLocation(sourceFile, endToken); | 39 endSourcePosition = new TokenSourceFileLocation(sourceFile, endToken); |
| 40 } | 40 } |
| 41 return node.withPosition(sourcePosition, endSourcePosition); | 41 return node.withPosition(sourcePosition, endSourcePosition); |
| 42 } | 42 } |
| 43 | 43 |
| 44 SourceFile sourceFileOfElement(Element element) { | 44 SourceFile sourceFileOfElement(Element element) { |
| 45 // TODO(johnniwinther): remove the 'element.patch' hack. | 45 // TODO(johnniwinther): remove the 'element.patch' hack. |
| 46 FunctionElement functionElement = element.asFunctionElement(); | 46 FunctionElement functionElement = element.asFunctionElement(); |
| 47 if (functionElement != null && functionElement.patch != null) { | 47 if (functionElement != null && functionElement.patch != null) { |
| 48 element = functionElement.patch; | 48 element = functionElement.patch; |
| 49 } | 49 } |
| 50 return element.getCompilationUnit().script.file; | 50 return element.compilationUnit.script.file; |
| 51 } | 51 } |
| 52 | 52 |
| 53 js.Fun buildJavaScriptFunction(FunctionElement element, | 53 js.Fun buildJavaScriptFunction(FunctionElement element, |
| 54 List<js.Parameter> parameters, | 54 List<js.Parameter> parameters, |
| 55 js.Block body) { | 55 js.Block body) { |
| 56 return attachPosition(new js.Fun(parameters, body), element); | 56 return attachPosition(new js.Fun(parameters, body), element); |
| 57 } | 57 } |
| 58 | 58 |
| 59 js.Expression generateCode(CodegenWorkItem work, HGraph graph) { | 59 js.Expression generateCode(CodegenWorkItem work, HGraph graph) { |
| 60 if (work.element.isField()) { | 60 if (work.element.isField) { |
| 61 return generateLazyInitializer(work, graph); | 61 return generateLazyInitializer(work, graph); |
| 62 } else { | 62 } else { |
| 63 return generateMethod(work, graph); | 63 return generateMethod(work, graph); |
| 64 } | 64 } |
| 65 } | 65 } |
| 66 | 66 |
| 67 js.Expression generateLazyInitializer(work, graph) { | 67 js.Expression generateLazyInitializer(work, graph) { |
| 68 return measure(() { | 68 return measure(() { |
| 69 compiler.tracer.traceGraph("codegen", graph); | 69 compiler.tracer.traceGraph("codegen", graph); |
| 70 SsaCodeGenerator codegen = new SsaCodeGenerator(backend, work); | 70 SsaCodeGenerator codegen = new SsaCodeGenerator(backend, work); |
| (...skipping 1412 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1483 if (target == backend.jsArrayAdd) { | 1483 if (target == backend.jsArrayAdd) { |
| 1484 methodName = 'push'; | 1484 methodName = 'push'; |
| 1485 } else if (target == backend.jsArrayRemoveLast) { | 1485 } else if (target == backend.jsArrayRemoveLast) { |
| 1486 methodName = 'pop'; | 1486 methodName = 'pop'; |
| 1487 } else if (target == backend.jsStringSplit) { | 1487 } else if (target == backend.jsStringSplit) { |
| 1488 methodName = 'split'; | 1488 methodName = 'split'; |
| 1489 // Split returns a List, so we make sure the backend knows the | 1489 // Split returns a List, so we make sure the backend knows the |
| 1490 // list class is instantiated. | 1490 // list class is instantiated. |
| 1491 world.registerInstantiatedClass( | 1491 world.registerInstantiatedClass( |
| 1492 compiler.listClass, work.resolutionTree); | 1492 compiler.listClass, work.resolutionTree); |
| 1493 } else if (target.isNative() && target.isFunction() | 1493 } else if (target.isNative && target.isFunction |
| 1494 && !node.isInterceptedCall) { | 1494 && !node.isInterceptedCall) { |
| 1495 // A direct (i.e. non-interceptor) native call is the result of | 1495 // A direct (i.e. non-interceptor) native call is the result of |
| 1496 // optimization. The optimization ensures any type checks or | 1496 // optimization. The optimization ensures any type checks or |
| 1497 // conversions have been satisified. | 1497 // conversions have been satisified. |
| 1498 methodName = target.fixedBackendName(); | 1498 methodName = target.fixedBackendName; |
| 1499 } | 1499 } |
| 1500 } | 1500 } |
| 1501 | 1501 |
| 1502 if (methodName == null) { | 1502 if (methodName == null) { |
| 1503 methodName = backend.namer.invocationName(node.selector); | 1503 methodName = backend.namer.invocationName(node.selector); |
| 1504 registerMethodInvoke(node); | 1504 registerMethodInvoke(node); |
| 1505 } | 1505 } |
| 1506 push(jsPropertyCall(object, methodName, arguments), node); | 1506 push(jsPropertyCall(object, methodName, arguments), node); |
| 1507 } | 1507 } |
| 1508 | 1508 |
| 1509 void visitInvokeConstructorBody(HInvokeConstructorBody node) { | 1509 void visitInvokeConstructorBody(HInvokeConstructorBody node) { |
| 1510 use(node.inputs[0]); | 1510 use(node.inputs[0]); |
| 1511 js.Expression object = pop(); | 1511 js.Expression object = pop(); |
| 1512 String methodName = backend.namer.getNameOfInstanceMember(node.element); | 1512 String methodName = backend.namer.getNameOfInstanceMember(node.element); |
| 1513 List<js.Expression> arguments = visitArguments(node.inputs); | 1513 List<js.Expression> arguments = visitArguments(node.inputs); |
| 1514 push(jsPropertyCall(object, methodName, arguments), node); | 1514 push(jsPropertyCall(object, methodName, arguments), node); |
| 1515 world.registerStaticUse(node.element); | 1515 world.registerStaticUse(node.element); |
| 1516 } | 1516 } |
| 1517 | 1517 |
| 1518 void visitOneShotInterceptor(HOneShotInterceptor node) { | 1518 void visitOneShotInterceptor(HOneShotInterceptor node) { |
| 1519 List<js.Expression> arguments = visitArguments(node.inputs); | 1519 List<js.Expression> arguments = visitArguments(node.inputs); |
| 1520 var isolate = new js.VariableUse( | 1520 var isolate = new js.VariableUse( |
| 1521 backend.namer.globalObjectFor(compiler.interceptorsLibrary)); | 1521 backend.namer.globalObjectFor(compiler.interceptorsLibrary)); |
| 1522 Selector selector = getOptimizedSelectorFor(node, node.selector); | 1522 Selector selector = getOptimizedSelectorFor(node, node.selector); |
| 1523 String methodName = backend.registerOneShotInterceptor(selector); | 1523 String methodName = backend.registerOneShotInterceptor(selector); |
| 1524 push(jsPropertyCall(isolate, methodName, arguments), node); | 1524 push(jsPropertyCall(isolate, methodName, arguments), node); |
| 1525 if (selector.isGetter()) { | 1525 if (selector.isGetter) { |
| 1526 registerGetter(node); | 1526 registerGetter(node); |
| 1527 } else if (selector.isSetter()) { | 1527 } else if (selector.isSetter) { |
| 1528 registerSetter(node); | 1528 registerSetter(node); |
| 1529 } else { | 1529 } else { |
| 1530 registerMethodInvoke(node); | 1530 registerMethodInvoke(node); |
| 1531 } | 1531 } |
| 1532 backend.registerUseInterceptor(world); | 1532 backend.registerUseInterceptor(world); |
| 1533 } | 1533 } |
| 1534 | 1534 |
| 1535 Selector getOptimizedSelectorFor(HInvokeDynamic node, Selector selector) { | 1535 Selector getOptimizedSelectorFor(HInvokeDynamic node, Selector selector) { |
| 1536 if (node.element != null) { | 1536 if (node.element != null) { |
| 1537 // Create an artificial type mask to make sure only | 1537 // Create an artificial type mask to make sure only |
| 1538 // [node.element] will be enqueued. We're not using the receiver | 1538 // [node.element] will be enqueued. We're not using the receiver |
| 1539 // type because our optimizations might end up in a state where the | 1539 // type because our optimizations might end up in a state where the |
| 1540 // invoke dynamic knows more than the receiver. | 1540 // invoke dynamic knows more than the receiver. |
| 1541 ClassElement enclosing = node.element.getEnclosingClass(); | 1541 ClassElement enclosing = node.element.enclosingClass; |
| 1542 TypeMask receiverType = new TypeMask.nonNullExact(enclosing.declaration); | 1542 TypeMask receiverType = new TypeMask.nonNullExact(enclosing.declaration); |
| 1543 return new TypedSelector(receiverType, selector); | 1543 return new TypedSelector(receiverType, selector); |
| 1544 } | 1544 } |
| 1545 // If [JSInvocationMirror._invokeOn] is enabled, and this call | 1545 // If [JSInvocationMirror._invokeOn] is enabled, and this call |
| 1546 // might hit a `noSuchMethod`, we register an untyped selector. | 1546 // might hit a `noSuchMethod`, we register an untyped selector. |
| 1547 return selector.extendIfReachesAll(compiler); | 1547 return selector.extendIfReachesAll(compiler); |
| 1548 } | 1548 } |
| 1549 | 1549 |
| 1550 void registerMethodInvoke(HInvokeDynamic node) { | 1550 void registerMethodInvoke(HInvokeDynamic node) { |
| 1551 Selector selector = getOptimizedSelectorFor(node, node.selector); | 1551 Selector selector = getOptimizedSelectorFor(node, node.selector); |
| 1552 | 1552 |
| 1553 // If we don't know what we're calling or if we are calling a getter, | 1553 // If we don't know what we're calling or if we are calling a getter, |
| 1554 // we need to register that fact that we may be calling a closure | 1554 // we need to register that fact that we may be calling a closure |
| 1555 // with the same arguments. | 1555 // with the same arguments. |
| 1556 Element target = node.element; | 1556 Element target = node.element; |
| 1557 if (target == null || target.isGetter()) { | 1557 if (target == null || target.isGetter) { |
| 1558 // TODO(kasperl): If we have a typed selector for the call, we | 1558 // TODO(kasperl): If we have a typed selector for the call, we |
| 1559 // may know something about the types of closures that need | 1559 // may know something about the types of closures that need |
| 1560 // the specific closure call method. | 1560 // the specific closure call method. |
| 1561 Selector call = new Selector.callClosureFrom(selector); | 1561 Selector call = new Selector.callClosureFrom(selector); |
| 1562 world.registerDynamicInvocation(call); | 1562 world.registerDynamicInvocation(call); |
| 1563 } | 1563 } |
| 1564 world.registerDynamicInvocation(selector); | 1564 world.registerDynamicInvocation(selector); |
| 1565 } | 1565 } |
| 1566 | 1566 |
| 1567 void registerSetter(HInvokeDynamic node) { | 1567 void registerSetter(HInvokeDynamic node) { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1593 use(node.receiver); | 1593 use(node.receiver); |
| 1594 push(jsPropertyCall(pop(), | 1594 push(jsPropertyCall(pop(), |
| 1595 backend.namer.invocationName(call), | 1595 backend.namer.invocationName(call), |
| 1596 visitArguments(node.inputs)), | 1596 visitArguments(node.inputs)), |
| 1597 node); | 1597 node); |
| 1598 world.registerDynamicInvocation(call); | 1598 world.registerDynamicInvocation(call); |
| 1599 } | 1599 } |
| 1600 | 1600 |
| 1601 visitInvokeStatic(HInvokeStatic node) { | 1601 visitInvokeStatic(HInvokeStatic node) { |
| 1602 Element element = node.element; | 1602 Element element = node.element; |
| 1603 ClassElement cls = element.getEnclosingClass(); | 1603 ClassElement cls = element.enclosingClass; |
| 1604 List<DartType> instantiatedTypes = node.instantiatedTypes; | 1604 List<DartType> instantiatedTypes = node.instantiatedTypes; |
| 1605 | 1605 |
| 1606 world.registerStaticUse(element); | 1606 world.registerStaticUse(element); |
| 1607 | 1607 |
| 1608 if (instantiatedTypes != null && !instantiatedTypes.isEmpty) { | 1608 if (instantiatedTypes != null && !instantiatedTypes.isEmpty) { |
| 1609 instantiatedTypes.forEach((type) { | 1609 instantiatedTypes.forEach((type) { |
| 1610 world.registerInstantiatedType(type, work.resolutionTree); | 1610 world.registerInstantiatedType(type, work.resolutionTree); |
| 1611 }); | 1611 }); |
| 1612 } | 1612 } |
| 1613 | 1613 |
| 1614 push(backend.namer.elementAccess(node.element)); | 1614 push(backend.namer.elementAccess(node.element)); |
| 1615 push(new js.Call(pop(), visitArguments(node.inputs, start: 0)), node); | 1615 push(new js.Call(pop(), visitArguments(node.inputs, start: 0)), node); |
| 1616 } | 1616 } |
| 1617 | 1617 |
| 1618 visitInvokeSuper(HInvokeSuper node) { | 1618 visitInvokeSuper(HInvokeSuper node) { |
| 1619 Element superMethod = node.element; | 1619 Element superMethod = node.element; |
| 1620 world.registerStaticUse(superMethod); | 1620 world.registerStaticUse(superMethod); |
| 1621 ClassElement superClass = superMethod.getEnclosingClass(); | 1621 ClassElement superClass = superMethod.enclosingClass; |
| 1622 if (superMethod.kind == ElementKind.FIELD) { | 1622 if (superMethod.kind == ElementKind.FIELD) { |
| 1623 String fieldName = backend.namer.instanceFieldPropertyName(superMethod); | 1623 String fieldName = backend.namer.instanceFieldPropertyName(superMethod); |
| 1624 use(node.inputs[0]); | 1624 use(node.inputs[0]); |
| 1625 js.PropertyAccess access = | 1625 js.PropertyAccess access = |
| 1626 new js.PropertyAccess.field(pop(), fieldName); | 1626 new js.PropertyAccess.field(pop(), fieldName); |
| 1627 if (node.isSetter) { | 1627 if (node.isSetter) { |
| 1628 use(node.value); | 1628 use(node.value); |
| 1629 push(new js.Assignment(access, pop()), node); | 1629 push(new js.Assignment(access, pop()), node); |
| 1630 } else { | 1630 } else { |
| 1631 push(access, node); | 1631 push(access, node); |
| 1632 } | 1632 } |
| 1633 } else { | 1633 } else { |
| 1634 Selector selector = node.selector; | 1634 Selector selector = node.selector; |
| 1635 String methodName; | 1635 String methodName; |
| 1636 if (selector.isGetter()) { | 1636 if (selector.isGetter) { |
| 1637 // If the selector we need to register a typed getter to the | 1637 // If the selector we need to register a typed getter to the |
| 1638 // [world]. The emitter needs to know if it needs to emit a | 1638 // [world]. The emitter needs to know if it needs to emit a |
| 1639 // bound closure for a method. | 1639 // bound closure for a method. |
| 1640 TypeMask receiverType = new TypeMask.nonNullExact(superClass); | 1640 TypeMask receiverType = new TypeMask.nonNullExact(superClass); |
| 1641 selector = new TypedSelector(receiverType, selector); | 1641 selector = new TypedSelector(receiverType, selector); |
| 1642 // TODO(floitsch): we know the target. We shouldn't register a | 1642 // TODO(floitsch): we know the target. We shouldn't register a |
| 1643 // dynamic getter. | 1643 // dynamic getter. |
| 1644 world.registerDynamicGetter(selector); | 1644 world.registerDynamicGetter(selector); |
| 1645 world.registerGetterForSuperMethod(node.element); | 1645 world.registerGetterForSuperMethod(node.element); |
| 1646 methodName = backend.namer.invocationName(selector); | 1646 methodName = backend.namer.invocationName(selector); |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1767 void generateConstant(Constant constant) { | 1767 void generateConstant(Constant constant) { |
| 1768 if (constant.isFunction) { | 1768 if (constant.isFunction) { |
| 1769 FunctionConstant function = constant; | 1769 FunctionConstant function = constant; |
| 1770 world.registerStaticUse(function.element); | 1770 world.registerStaticUse(function.element); |
| 1771 } | 1771 } |
| 1772 if (constant.isType) { | 1772 if (constant.isType) { |
| 1773 // If the type is a web component, we need to ensure the constructors are | 1773 // If the type is a web component, we need to ensure the constructors are |
| 1774 // available to 'upgrade' the native object. | 1774 // available to 'upgrade' the native object. |
| 1775 TypeConstant type = constant; | 1775 TypeConstant type = constant; |
| 1776 Element element = type.representedType.element; | 1776 Element element = type.representedType.element; |
| 1777 if (element != null && element.isClass()) { | 1777 if (element != null && element.isClass) { |
| 1778 backend.customElementsAnalysis.registerTypeConstant(element, world); | 1778 backend.customElementsAnalysis.registerTypeConstant(element, world); |
| 1779 } | 1779 } |
| 1780 } | 1780 } |
| 1781 push(backend.emitter.constantReference(constant)); | 1781 push(backend.emitter.constantReference(constant)); |
| 1782 } | 1782 } |
| 1783 | 1783 |
| 1784 visitConstant(HConstant node) { | 1784 visitConstant(HConstant node) { |
| 1785 assert(isGenerateAtUseSite(node)); | 1785 assert(isGenerateAtUseSite(node)); |
| 1786 generateConstant(node.constant); | 1786 generateConstant(node.constant); |
| 1787 | 1787 |
| (...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2019 value = attachLocation(value, argument); | 2019 value = attachLocation(value, argument); |
| 2020 push(value, node); | 2020 push(value, node); |
| 2021 } | 2021 } |
| 2022 | 2022 |
| 2023 void visitSwitch(HSwitch node) { | 2023 void visitSwitch(HSwitch node) { |
| 2024 // Switches are handled using [visitSwitchInfo]. | 2024 // Switches are handled using [visitSwitchInfo]. |
| 2025 } | 2025 } |
| 2026 | 2026 |
| 2027 void visitStatic(HStatic node) { | 2027 void visitStatic(HStatic node) { |
| 2028 Element element = node.element; | 2028 Element element = node.element; |
| 2029 if (element.isFunction()) { | 2029 if (element.isFunction) { |
| 2030 push(backend.namer.isolateStaticClosureAccess(node.element)); | 2030 push(backend.namer.isolateStaticClosureAccess(node.element)); |
| 2031 } else { | 2031 } else { |
| 2032 push(backend.namer.elementAccess(node.element)); | 2032 push(backend.namer.elementAccess(node.element)); |
| 2033 } | 2033 } |
| 2034 world.registerStaticUse(element); | 2034 world.registerStaticUse(element); |
| 2035 } | 2035 } |
| 2036 | 2036 |
| 2037 void visitLazyStatic(HLazyStatic node) { | 2037 void visitLazyStatic(HLazyStatic node) { |
| 2038 Element element = node.element; | 2038 Element element = node.element; |
| 2039 world.registerStaticUse(element); | 2039 world.registerStaticUse(element); |
| (...skipping 582 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2622 } | 2622 } |
| 2623 } | 2623 } |
| 2624 | 2624 |
| 2625 void visitReadTypeVariable(HReadTypeVariable node) { | 2625 void visitReadTypeVariable(HReadTypeVariable node) { |
| 2626 TypeVariableElement element = node.dartType.element; | 2626 TypeVariableElement element = node.dartType.element; |
| 2627 Element helperElement = compiler.findHelper('convertRtiToRuntimeType'); | 2627 Element helperElement = compiler.findHelper('convertRtiToRuntimeType'); |
| 2628 world.registerStaticUse(helperElement); | 2628 world.registerStaticUse(helperElement); |
| 2629 | 2629 |
| 2630 use(node.inputs[0]); | 2630 use(node.inputs[0]); |
| 2631 if (node.hasReceiver) { | 2631 if (node.hasReceiver) { |
| 2632 if (backend.isInterceptorClass(element.getEnclosingClass())) { | 2632 if (backend.isInterceptorClass(element.enclosingClass)) { |
| 2633 int index = RuntimeTypes.getTypeVariableIndex(element); | 2633 int index = RuntimeTypes.getTypeVariableIndex(element); |
| 2634 js.Expression receiver = pop(); | 2634 js.Expression receiver = pop(); |
| 2635 js.Expression helper = backend.namer.elementAccess(helperElement); | 2635 js.Expression helper = backend.namer.elementAccess(helperElement); |
| 2636 push(js.js(r'#(#.$builtinTypeInfo && #.$builtinTypeInfo[#])', | 2636 push(js.js(r'#(#.$builtinTypeInfo && #.$builtinTypeInfo[#])', |
| 2637 [helper, receiver, receiver, js.js.number(index)])); | 2637 [helper, receiver, receiver, js.js.number(index)])); |
| 2638 } else { | 2638 } else { |
| 2639 backend.emitter.registerReadTypeVariable(element); | 2639 backend.emitter.registerReadTypeVariable(element); |
| 2640 push(js.js('#.#()', | 2640 push(js.js('#.#()', |
| 2641 [pop(), backend.namer.readTypeVariableName(element)])); | 2641 [pop(), backend.namer.readTypeVariableName(element)])); |
| 2642 } | 2642 } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2674 js.PropertyAccess accessHelper(String name) { | 2674 js.PropertyAccess accessHelper(String name) { |
| 2675 Element helper = compiler.findHelper(name); | 2675 Element helper = compiler.findHelper(name); |
| 2676 if (helper == null) { | 2676 if (helper == null) { |
| 2677 // For mocked-up tests. | 2677 // For mocked-up tests. |
| 2678 return js.js('(void 0).$name'); | 2678 return js.js('(void 0).$name'); |
| 2679 } | 2679 } |
| 2680 world.registerStaticUse(helper); | 2680 world.registerStaticUse(helper); |
| 2681 return backend.namer.elementAccess(helper); | 2681 return backend.namer.elementAccess(helper); |
| 2682 } | 2682 } |
| 2683 } | 2683 } |
| OLD | NEW |