| 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 |
| (...skipping 509 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 520 } else if (sequenceElements.length == 1) { | 520 } else if (sequenceElements.length == 1) { |
| 521 return sequenceElements[0]; | 521 return sequenceElements[0]; |
| 522 } else { | 522 } else { |
| 523 return new js.Sequence(sequenceElements); | 523 return new js.Sequence(sequenceElements); |
| 524 } | 524 } |
| 525 } | 525 } |
| 526 | 526 |
| 527 /** | 527 /** |
| 528 * Only visits the arguments starting at inputs[HInvoke.ARGUMENTS_OFFSET]. | 528 * Only visits the arguments starting at inputs[HInvoke.ARGUMENTS_OFFSET]. |
| 529 */ | 529 */ |
| 530 List<js.Expression> visitArguments(List<HInstruction> inputs) { | 530 List<js.Expression> visitArguments(List<HInstruction> inputs, |
| 531 assert(inputs.length >= HInvoke.ARGUMENTS_OFFSET); | 531 {int start: HInvoke.ARGUMENTS_OFFSET}) { |
| 532 assert(inputs.length >= start); |
| 532 List<js.Expression> result = <js.Expression>[]; | 533 List<js.Expression> result = <js.Expression>[]; |
| 533 for (int i = HInvoke.ARGUMENTS_OFFSET; i < inputs.length; i++) { | 534 for (int i = start; i < inputs.length; i++) { |
| 534 use(inputs[i]); | 535 use(inputs[i]); |
| 535 result.add(pop()); | 536 result.add(pop()); |
| 536 } | 537 } |
| 537 return result; | 538 return result; |
| 538 } | 539 } |
| 539 | 540 |
| 540 bool isVariableDeclared(String variableName) { | 541 bool isVariableDeclared(String variableName) { |
| 541 return declaredLocals.contains(variableName) || | 542 return declaredLocals.contains(variableName) || |
| 542 collectedVariableDeclarations.contains(variableName); | 543 collectedVariableDeclarations.contains(variableName); |
| 543 } | 544 } |
| (...skipping 1061 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1605 visitArguments(node.inputs)), | 1606 visitArguments(node.inputs)), |
| 1606 node); | 1607 node); |
| 1607 world.registerDynamicInvocation(call.name, call); | 1608 world.registerDynamicInvocation(call.name, call); |
| 1608 } | 1609 } |
| 1609 | 1610 |
| 1610 visitInvokeStatic(HInvokeStatic node) { | 1611 visitInvokeStatic(HInvokeStatic node) { |
| 1611 if (node.typeCode() == HInstruction.INVOKE_STATIC_TYPECODE) { | 1612 if (node.typeCode() == HInstruction.INVOKE_STATIC_TYPECODE) { |
| 1612 // Register this invocation to collect the types used at all call sites. | 1613 // Register this invocation to collect the types used at all call sites. |
| 1613 backend.registerStaticInvocation(node); | 1614 backend.registerStaticInvocation(node); |
| 1614 } | 1615 } |
| 1615 use(node.target); | 1616 Element element = node.element; |
| 1616 push(new js.Call(pop(), visitArguments(node.inputs)), node); | 1617 world.registerStaticUse(element); |
| 1618 ClassElement cls = element.getEnclosingClass(); |
| 1619 if (element.isGenerativeConstructor() |
| 1620 || (element.isFactoryConstructor() && cls == compiler.listClass)) { |
| 1621 world.registerInstantiatedClass(cls, work.resolutionTree); |
| 1622 } |
| 1623 push(new js.VariableUse(backend.namer.isolateAccess(node.element))); |
| 1624 push(new js.Call(pop(), visitArguments(node.inputs, start: 0)), node); |
| 1617 } | 1625 } |
| 1618 | 1626 |
| 1619 visitInvokeSuper(HInvokeSuper node) { | 1627 visitInvokeSuper(HInvokeSuper node) { |
| 1620 Element superMethod = node.element; | 1628 Element superMethod = node.element; |
| 1629 world.registerStaticUse(superMethod); |
| 1621 Element superClass = superMethod.getEnclosingClass(); | 1630 Element superClass = superMethod.getEnclosingClass(); |
| 1622 if (superMethod.kind == ElementKind.FIELD) { | 1631 if (superMethod.kind == ElementKind.FIELD) { |
| 1623 String fieldName = node.caller.isShadowedByField(superMethod) | 1632 String fieldName = node.caller.isShadowedByField(superMethod) |
| 1624 ? backend.namer.shadowedFieldName(superMethod) | 1633 ? backend.namer.shadowedFieldName(superMethod) |
| 1625 : backend.namer.instanceFieldName(superMethod); | 1634 : backend.namer.instanceFieldName(superMethod); |
| 1626 use(node.inputs[1]); | 1635 use(node.inputs[0]); |
| 1627 js.PropertyAccess access = | 1636 js.PropertyAccess access = |
| 1628 new js.PropertyAccess.field(pop(), fieldName); | 1637 new js.PropertyAccess.field(pop(), fieldName); |
| 1629 if (node.isSetter) { | 1638 if (node.isSetter) { |
| 1630 use(node.value); | 1639 use(node.value); |
| 1631 push(new js.Assignment(access, pop()), node); | 1640 push(new js.Assignment(access, pop()), node); |
| 1632 } else { | 1641 } else { |
| 1633 push(access, node); | 1642 push(access, node); |
| 1634 } | 1643 } |
| 1635 } else { | 1644 } else { |
| 1636 String methodName = backend.namer.getName(superMethod); | 1645 String methodName = backend.namer.getName(superMethod); |
| 1637 String className = backend.namer.isolateAccess(superClass); | 1646 String className = backend.namer.isolateAccess(superClass); |
| 1638 js.VariableUse classReference = new js.VariableUse(className); | 1647 js.VariableUse classReference = new js.VariableUse(className); |
| 1639 js.PropertyAccess prototype = | 1648 js.PropertyAccess prototype = |
| 1640 new js.PropertyAccess.field(classReference, "prototype"); | 1649 new js.PropertyAccess.field(classReference, "prototype"); |
| 1641 js.PropertyAccess method = | 1650 js.PropertyAccess method = |
| 1642 new js.PropertyAccess.field(prototype, methodName); | 1651 new js.PropertyAccess.field(prototype, methodName); |
| 1643 push(jsPropertyCall(method, "call", visitArguments(node.inputs)), node); | 1652 push(jsPropertyCall( |
| 1653 method, "call", visitArguments(node.inputs, start: 0)), node); |
| 1644 } | 1654 } |
| 1645 world.registerStaticUse(superMethod); | 1655 world.registerStaticUse(superMethod); |
| 1646 } | 1656 } |
| 1647 | 1657 |
| 1648 visitFieldGet(HFieldGet node) { | 1658 visitFieldGet(HFieldGet node) { |
| 1649 use(node.receiver); | 1659 use(node.receiver); |
| 1650 Element element = node.element; | 1660 Element element = node.element; |
| 1651 if (element == backend.jsIndexableLength) { | 1661 if (element == backend.jsIndexableLength) { |
| 1652 // We're accessing a native JavaScript property called 'length' | 1662 // We're accessing a native JavaScript property called 'length' |
| 1653 // on a JS String or a JS array. Therefore, the name of that | 1663 // on a JS String or a JS array. Therefore, the name of that |
| (...skipping 327 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1981 js.Call value = new js.Call(jsHelper, [pop()]); | 1991 js.Call value = new js.Call(jsHelper, [pop()]); |
| 1982 attachLocation(value, argument); | 1992 attachLocation(value, argument); |
| 1983 push(value, node); | 1993 push(value, node); |
| 1984 } | 1994 } |
| 1985 | 1995 |
| 1986 void visitSwitch(HSwitch node) { | 1996 void visitSwitch(HSwitch node) { |
| 1987 // Switches are handled using [visitSwitchInfo]. | 1997 // Switches are handled using [visitSwitchInfo]. |
| 1988 } | 1998 } |
| 1989 | 1999 |
| 1990 void visitStatic(HStatic node) { | 2000 void visitStatic(HStatic node) { |
| 1991 // Check whether this static is used for anything else than as a target in | |
| 1992 // a static call. | |
| 1993 node.usedBy.forEach((HInstruction instr) { | |
| 1994 if (instr is !HInvokeStatic) { | |
| 1995 backend.registerNonCallStaticUse(node); | |
| 1996 if (node.element.isFunction()) { | |
| 1997 world.registerInstantiatedClass( | |
| 1998 compiler.functionClass, work.resolutionTree); | |
| 1999 } | |
| 2000 } else if (instr.target != node) { | |
| 2001 backend.registerNonCallStaticUse(node); | |
| 2002 } | |
| 2003 }); | |
| 2004 Element element = node.element; | 2001 Element element = node.element; |
| 2002 if (element.isFunction()) { |
| 2003 backend.registerNonCallStaticUse(node); |
| 2004 world.registerInstantiatedClass( |
| 2005 compiler.functionClass, work.resolutionTree); |
| 2006 push(new js.VariableUse( |
| 2007 backend.namer.isolateStaticTearOffClosureAccess(node.element))); |
| 2008 } else { |
| 2009 push(new js.VariableUse(backend.namer.isolateAccess(node.element))); |
| 2010 } |
| 2005 world.registerStaticUse(element); | 2011 world.registerStaticUse(element); |
| 2006 ClassElement cls = element.getEnclosingClass(); | |
| 2007 if (element.isGenerativeConstructor() | |
| 2008 || (element.isFactoryConstructor() && cls == compiler.listClass)) { | |
| 2009 world.registerInstantiatedClass(cls, work.resolutionTree); | |
| 2010 } | |
| 2011 push(new js.VariableUse(backend.namer.isolateAccess(node.element))); | |
| 2012 } | 2012 } |
| 2013 | 2013 |
| 2014 void visitLazyStatic(HLazyStatic node) { | 2014 void visitLazyStatic(HLazyStatic node) { |
| 2015 Element element = node.element; | 2015 Element element = node.element; |
| 2016 world.registerStaticUse(element); | 2016 world.registerStaticUse(element); |
| 2017 String lazyGetter = backend.namer.isolateLazyInitializerAccess(element); | 2017 String lazyGetter = backend.namer.isolateLazyInitializerAccess(element); |
| 2018 js.VariableUse target = new js.VariableUse(lazyGetter); | 2018 js.VariableUse target = new js.VariableUse(lazyGetter); |
| 2019 js.Call call = new js.Call(target, <js.Expression>[]); | 2019 js.Call call = new js.Call(target, <js.Expression>[]); |
| 2020 push(call, node); | 2020 push(call, node); |
| 2021 } | 2021 } |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2175 void checkNull(HInstruction input) { | 2175 void checkNull(HInstruction input) { |
| 2176 use(input); | 2176 use(input); |
| 2177 push(new js.Binary('==', pop(), new js.LiteralNull())); | 2177 push(new js.Binary('==', pop(), new js.LiteralNull())); |
| 2178 } | 2178 } |
| 2179 | 2179 |
| 2180 void checkNonNull(HInstruction input) { | 2180 void checkNonNull(HInstruction input) { |
| 2181 use(input); | 2181 use(input); |
| 2182 push(new js.Binary('!=', pop(), new js.LiteralNull())); | 2182 push(new js.Binary('!=', pop(), new js.LiteralNull())); |
| 2183 } | 2183 } |
| 2184 | 2184 |
| 2185 void checkFunction(HInstruction input, | |
| 2186 DartType type, | |
| 2187 { bool negative: false}) { | |
| 2188 String relation = negative ? '!==' : '==='; | |
| 2189 checkTypeOf(input, relation, 'function'); | |
| 2190 js.Expression functionTest = pop(); | |
| 2191 checkObject(input, relation); | |
| 2192 js.Expression objectTest = pop(); | |
| 2193 checkType(input, type, negative: negative); | |
| 2194 String combiner = negative ? '||' : '&&'; | |
| 2195 push(new js.Binary(negative ? '&&' : '||', | |
| 2196 functionTest, | |
| 2197 new js.Binary(combiner, objectTest, pop()))); | |
| 2198 } | |
| 2199 | |
| 2200 void checkType(HInstruction input, DartType type, {bool negative: false}) { | 2185 void checkType(HInstruction input, DartType type, {bool negative: false}) { |
| 2201 assert(invariant(input, !type.isMalformed, | 2186 assert(invariant(input, !type.isMalformed, |
| 2202 message: 'Attempt to check malformed type $type')); | 2187 message: 'Attempt to check malformed type $type')); |
| 2203 world.registerIsCheck(type, work.resolutionTree); | 2188 world.registerIsCheck(type, work.resolutionTree); |
| 2204 Element element = type.element; | 2189 Element element = type.element; |
| 2205 use(input); | 2190 use(input); |
| 2206 | 2191 |
| 2207 // Hack in interceptor. Ideally the interceptor would occur at the | 2192 // Hack in interceptor. Ideally the interceptor would occur at the |
| 2208 // instruction level to allow optimizations, and checks would be broken into | 2193 // instruction level to allow optimizations, and checks would be broken into |
| 2209 // several smaller tests. | 2194 // several smaller tests. |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2331 attachLocationToLast(node); | 2316 attachLocationToLast(node); |
| 2332 } else if (element == compiler.doubleClass) { | 2317 } else if (element == compiler.doubleClass) { |
| 2333 checkDouble(input, relation); | 2318 checkDouble(input, relation); |
| 2334 attachLocationToLast(node); | 2319 attachLocationToLast(node); |
| 2335 } else if (element == compiler.numClass) { | 2320 } else if (element == compiler.numClass) { |
| 2336 checkNum(input, relation); | 2321 checkNum(input, relation); |
| 2337 attachLocationToLast(node); | 2322 attachLocationToLast(node); |
| 2338 } else if (element == compiler.boolClass) { | 2323 } else if (element == compiler.boolClass) { |
| 2339 checkBool(input, relation); | 2324 checkBool(input, relation); |
| 2340 attachLocationToLast(node); | 2325 attachLocationToLast(node); |
| 2341 } else if (element == compiler.functionClass) { | |
| 2342 checkFunction(input, type, negative: negative); | |
| 2343 attachLocationToLast(node); | |
| 2344 } else if (element == compiler.intClass) { | 2326 } else if (element == compiler.intClass) { |
| 2345 // The is check in the code tells us that it might not be an | 2327 // The is check in the code tells us that it might not be an |
| 2346 // int. So we do a typeof first to avoid possible | 2328 // int. So we do a typeof first to avoid possible |
| 2347 // deoptimizations on the JS engine due to the Math.floor check. | 2329 // deoptimizations on the JS engine due to the Math.floor check. |
| 2348 checkNum(input, relation); | 2330 checkNum(input, relation); |
| 2349 js.Expression numTest = pop(); | 2331 js.Expression numTest = pop(); |
| 2350 checkBigInt(input, relation); | 2332 checkBigInt(input, relation); |
| 2351 push(new js.Binary(negative ? '||' : '&&', numTest, pop()), node); | 2333 push(new js.Binary(negative ? '||' : '&&', numTest, pop()), node); |
| 2352 } else if (Elements.isNumberOrStringSupertype(element, compiler)) { | 2334 } else if (Elements.isNumberOrStringSupertype(element, compiler)) { |
| 2353 handleNumberOrStringSupertypeCheck(input, type, negative: negative); | 2335 handleNumberOrStringSupertypeCheck(input, type, negative: negative); |
| (...skipping 620 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2974 if (leftType.canBeNull() && rightType.canBeNull()) { | 2956 if (leftType.canBeNull() && rightType.canBeNull()) { |
| 2975 if (left.isConstantNull() || right.isConstantNull() || | 2957 if (left.isConstantNull() || right.isConstantNull() || |
| 2976 (leftType.isPrimitive() && leftType == rightType)) { | 2958 (leftType.isPrimitive() && leftType == rightType)) { |
| 2977 return '=='; | 2959 return '=='; |
| 2978 } | 2960 } |
| 2979 return null; | 2961 return null; |
| 2980 } else { | 2962 } else { |
| 2981 return '==='; | 2963 return '==='; |
| 2982 } | 2964 } |
| 2983 } | 2965 } |
| OLD | NEW |