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.isolateStaticClosureAccess(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 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2481 pushStatement(new js.Throw(call)); | 2463 pushStatement(new js.Throw(call)); |
2482 } | 2464 } |
2483 currentContainer = oldContainer; | 2465 currentContainer = oldContainer; |
2484 body = unwrapStatement(body); | 2466 body = unwrapStatement(body); |
2485 pushStatement(new js.If.noElse(test, body), node); | 2467 pushStatement(new js.If.noElse(test, body), node); |
2486 return; | 2468 return; |
2487 } | 2469 } |
2488 | 2470 |
2489 assert(node.isCheckedModeCheck || node.isCastTypeCheck); | 2471 assert(node.isCheckedModeCheck || node.isCastTypeCheck); |
2490 DartType type = node.typeExpression; | 2472 DartType type = node.typeExpression; |
| 2473 if (type.kind == TypeKind.FUNCTION) { |
| 2474 // TODO(5022): We currently generate $isFunction checks for |
| 2475 // function types. |
| 2476 world.registerIsCheck( |
| 2477 compiler.functionClass.computeType(compiler), work.resolutionTree); |
| 2478 } |
2491 world.registerIsCheck(type, work.resolutionTree); | 2479 world.registerIsCheck(type, work.resolutionTree); |
2492 | 2480 |
2493 // TODO(kasperl): For now, we ignore type checks against type | 2481 // TODO(kasperl): For now, we ignore type checks against type |
2494 // variables. This is clearly wrong. | 2482 // variables. This is clearly wrong. |
2495 if (type.kind == TypeKind.TYPE_VARIABLE) { | 2483 if (type.kind == TypeKind.TYPE_VARIABLE) { |
2496 use(node.checkedInput); | 2484 use(node.checkedInput); |
2497 return; | 2485 return; |
2498 } | 2486 } |
2499 | 2487 |
2500 FunctionElement helperElement; | 2488 FunctionElement helperElement; |
(...skipping 473 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2974 if (leftType.canBeNull() && rightType.canBeNull()) { | 2962 if (leftType.canBeNull() && rightType.canBeNull()) { |
2975 if (left.isConstantNull() || right.isConstantNull() || | 2963 if (left.isConstantNull() || right.isConstantNull() || |
2976 (leftType.isPrimitive() && leftType == rightType)) { | 2964 (leftType.isPrimitive() && leftType == rightType)) { |
2977 return '=='; | 2965 return '=='; |
2978 } | 2966 } |
2979 return null; | 2967 return null; |
2980 } else { | 2968 } else { |
2981 return '==='; | 2969 return '==='; |
2982 } | 2970 } |
2983 } | 2971 } |
OLD | NEW |