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 class Interceptors { | 5 class Interceptors { |
6 Compiler compiler; | 6 Compiler compiler; |
7 Interceptors(Compiler this.compiler); | 7 Interceptors(Compiler this.compiler); |
8 | 8 |
9 SourceString mapOperatorToMethodName(Operator op) { | 9 SourceString mapOperatorToMethodName(Operator op) { |
10 String name = op.source.stringValue; | 10 String name = op.source.stringValue; |
(...skipping 794 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
805 HGraph graph; | 805 HGraph graph; |
806 LocalsHandler localsHandler; | 806 LocalsHandler localsHandler; |
807 HInstruction rethrowableException; | 807 HInstruction rethrowableException; |
808 Map<Element, HParameterValue> parameters; | 808 Map<Element, HParameterValue> parameters; |
809 | 809 |
810 Map<TargetElement, JumpHandler> jumpTargets; | 810 Map<TargetElement, JumpHandler> jumpTargets; |
811 | 811 |
812 /** | 812 /** |
813 * Variables stored in the current activation. These variables are | 813 * Variables stored in the current activation. These variables are |
814 * being updated in try/catch blocks, and should be | 814 * being updated in try/catch blocks, and should be |
815 * accessed indirectly through HFieldGet and HFieldSet. | 815 * accessed indirectly through [HLocalGet] and [HLocalSet]. |
816 */ | 816 */ |
817 Map<Element, HLocalValue> activationVariables; | 817 Map<Element, HLocalValue> activationVariables; |
818 | 818 |
819 // We build the Ssa graph by simulating a stack machine. | 819 // We build the Ssa graph by simulating a stack machine. |
820 List<HInstruction> stack; | 820 List<HInstruction> stack; |
821 | 821 |
822 // The current block to add instructions to. Might be null, if we are | 822 // The current block to add instructions to. Might be null, if we are |
823 // visiting dead code. | 823 // visiting dead code. |
824 HBasicBlock current; | 824 HBasicBlock current; |
825 // The most recently opened block. Has the same value as [current] while | 825 // The most recently opened block. Has the same value as [current] while |
(...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1219 // these selectors. Maybe the resolver can do more of the work | 1219 // these selectors. Maybe the resolver can do more of the work |
1220 // for us here? | 1220 // for us here? |
1221 LibraryElement library = body.getLibrary(); | 1221 LibraryElement library = body.getLibrary(); |
1222 Selector selector = new Selector.call(name, library, arity); | 1222 Selector selector = new Selector.call(name, library, arity); |
1223 add(new HInvokeDynamicMethod(selector, bodyCallInputs)); | 1223 add(new HInvokeDynamicMethod(selector, bodyCallInputs)); |
1224 } | 1224 } |
1225 close(new HReturn(newObject)).addSuccessor(graph.exit); | 1225 close(new HReturn(newObject)).addSuccessor(graph.exit); |
1226 return closeFunction(); | 1226 return closeFunction(); |
1227 } | 1227 } |
1228 | 1228 |
| 1229 void addParameterCheckInstruction(Element element) { |
| 1230 // This is the code we emit for a parameter that is being checked |
| 1231 // on whether it was given at value at the call site: |
| 1232 // |
| 1233 // foo([a = 42) { |
| 1234 // if (?a) print('parameter passed $a'); |
| 1235 // } |
| 1236 // |
| 1237 // foo([a = 42]) { |
| 1238 // var t1 = a === sentinel; |
| 1239 // if (t1) a = 42; |
| 1240 // if (!t1) print('parameter passed ' + a); |
| 1241 // } |
| 1242 |
| 1243 // Fetch the original default value of [element]; |
| 1244 ConstantHandler handler = compiler.constantHandler; |
| 1245 Constant constant = handler.compileVariable(element); |
| 1246 HConstant defaultValue = constant == null |
| 1247 ? graph.addConstantNull() |
| 1248 : graph.addConstant(constant); |
| 1249 |
| 1250 // Emit the equality check with the sentinel. |
| 1251 HConstant sentinel = graph.addConstant(SentinelConstant.SENTINEL); |
| 1252 Element equalsHelper = interceptors.getTripleEqualsInterceptor(); |
| 1253 HInstruction target = new HStatic(equalsHelper); |
| 1254 add(target); |
| 1255 HInstruction operand = parameters[element]; |
| 1256 HInstruction check = new HIdentity(target, sentinel, operand); |
| 1257 add(check); |
| 1258 |
| 1259 // If the check succeeds, we must update the parameter with the |
| 1260 // default value. |
| 1261 handleIf(element.parseNode(compiler), |
| 1262 () => stack.add(check), |
| 1263 () => localsHandler.updateLocal(element, defaultValue), |
| 1264 null); |
| 1265 |
| 1266 // Create the instruction that parameter checks will use. |
| 1267 check = new HNot(check); |
| 1268 add(check); |
| 1269 |
| 1270 ClosureClassMap closureData = localsHandler.closureData; |
| 1271 Element checkResultElement = closureData.parametersWithSentinel[element]; |
| 1272 localsHandler.updateLocal(checkResultElement, check); |
| 1273 } |
| 1274 |
1229 void openFunction(FunctionElement functionElement, | 1275 void openFunction(FunctionElement functionElement, |
1230 FunctionExpression node) { | 1276 FunctionExpression node) { |
1231 HBasicBlock block = graph.addNewBlock(); | 1277 HBasicBlock block = graph.addNewBlock(); |
1232 open(graph.entry); | 1278 open(graph.entry); |
1233 | 1279 |
1234 localsHandler.startFunction(functionElement, node); | 1280 localsHandler.startFunction(functionElement, node); |
1235 close(new HGoto()).addSuccessor(block); | 1281 close(new HGoto()).addSuccessor(block); |
1236 | 1282 |
1237 open(block); | 1283 open(block); |
1238 | 1284 |
| 1285 FunctionSignature params = functionElement.computeSignature(compiler); |
| 1286 params.forEachParameter((Element element) { |
| 1287 if (elements.isParameterChecked(element)) { |
| 1288 addParameterCheckInstruction(element); |
| 1289 } |
| 1290 }); |
| 1291 |
1239 // Put the type checks in the first successor of the entry, | 1292 // Put the type checks in the first successor of the entry, |
1240 // because that is where the type guards will also be inserted. | 1293 // because that is where the type guards will also be inserted. |
1241 // This way we ensure that a type guard will dominate the type | 1294 // This way we ensure that a type guard will dominate the type |
1242 // check. | 1295 // check. |
1243 FunctionSignature params = functionElement.computeSignature(compiler); | |
1244 params.forEachParameter((Element element) { | 1296 params.forEachParameter((Element element) { |
1245 HInstruction newParameter = potentiallyCheckType( | 1297 HInstruction newParameter = potentiallyCheckType( |
1246 localsHandler.directLocals[element], element); | 1298 localsHandler.directLocals[element], element); |
1247 localsHandler.directLocals[element] = newParameter; | 1299 localsHandler.directLocals[element] = newParameter; |
1248 }); | 1300 }); |
1249 | 1301 |
1250 // Add the type parameters of the class as parameters of this | 1302 // Add the type parameters of the class as parameters of this |
1251 // method. | 1303 // method. |
1252 if (functionElement.isFactoryConstructor() | 1304 if (functionElement.isFactoryConstructor() |
1253 || functionElement.isGenerativeConstructor()) { | 1305 || functionElement.isGenerativeConstructor()) { |
(...skipping 517 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1771 | 1823 |
1772 | 1824 |
1773 void visitLogicalNot(Send node) { | 1825 void visitLogicalNot(Send node) { |
1774 assert(node.argumentsNode is Prefix); | 1826 assert(node.argumentsNode is Prefix); |
1775 visit(node.receiver); | 1827 visit(node.receiver); |
1776 HNot not = new HNot(popBoolified()); | 1828 HNot not = new HNot(popBoolified()); |
1777 pushWithPosition(not, node); | 1829 pushWithPosition(not, node); |
1778 } | 1830 } |
1779 | 1831 |
1780 void visitUnary(Send node, Operator op) { | 1832 void visitUnary(Send node, Operator op) { |
1781 String value = op.source.stringValue; | 1833 if (node.isParameterCheck) { |
1782 if (value === '?') { | 1834 Element element = elements[node.receiver]; |
1783 // TODO(ahe): Implement argument definition test. | 1835 Node function = element.enclosingElement.parseNode(compiler); |
1784 stack.add(graph.addConstantBool(true)); | 1836 ClosureClassMap parameterClosureData = |
| 1837 compiler.closureToClassMapper.getMappingForNestedFunction(function); |
| 1838 Element fieldCheck = |
| 1839 parameterClosureData.parametersWithSentinel[element]; |
| 1840 stack.add(localsHandler.readLocal(fieldCheck)); |
1785 return; | 1841 return; |
1786 } | 1842 } |
1787 assert(node.argumentsNode is Prefix); | 1843 assert(node.argumentsNode is Prefix); |
1788 visit(node.receiver); | 1844 visit(node.receiver); |
1789 assert(op.token.kind !== PLUS_TOKEN); | 1845 assert(op.token.kind !== PLUS_TOKEN); |
1790 HInstruction operand = pop(); | 1846 HInstruction operand = pop(); |
1791 | 1847 |
1792 HInstruction target = | 1848 HInstruction target = |
1793 new HStatic(interceptors.getPrefixOperatorInterceptor(op)); | 1849 new HStatic(interceptors.getPrefixOperatorInterceptor(op)); |
1794 add(target); | 1850 add(target); |
1795 HInvokeUnary result; | 1851 HInvokeUnary result; |
| 1852 String value = op.source.stringValue; |
1796 switch (value) { | 1853 switch (value) { |
1797 case "-": result = new HNegate(target, operand); break; | 1854 case "-": result = new HNegate(target, operand); break; |
1798 case "~": result = new HBitNot(target, operand); break; | 1855 case "~": result = new HBitNot(target, operand); break; |
1799 default: | 1856 default: |
1800 compiler.internalError('Unexpected unary operator: $value.', node: op); | 1857 compiler.internalError('Unexpected unary operator: $value.', node: op); |
1801 break; | 1858 break; |
1802 } | 1859 } |
1803 // See if we can constant-fold right away. This avoids rewrites later on. | 1860 // See if we can constant-fold right away. This avoids rewrites later on. |
1804 if (operand is HConstant) { | 1861 if (operand is HConstant) { |
1805 HConstant constant = operand; | 1862 HConstant constant = operand; |
(...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2158 */ | 2215 */ |
2159 bool addStaticSendArgumentsToList(Selector selector, | 2216 bool addStaticSendArgumentsToList(Selector selector, |
2160 Link<Node> arguments, | 2217 Link<Node> arguments, |
2161 FunctionElement element, | 2218 FunctionElement element, |
2162 List<HInstruction> list) { | 2219 List<HInstruction> list) { |
2163 HInstruction compileArgument(Node argument) { | 2220 HInstruction compileArgument(Node argument) { |
2164 visit(argument); | 2221 visit(argument); |
2165 return pop(); | 2222 return pop(); |
2166 } | 2223 } |
2167 | 2224 |
2168 HInstruction compileConstant(Element constantElement) { | 2225 HInstruction compileConstant(Element parameter) { |
2169 Constant constant = compiler.compileVariable(constantElement); | 2226 Constant constant; |
| 2227 TreeElements calleeElements = |
| 2228 compiler.enqueuer.resolution.getCachedElements(element); |
| 2229 if (calleeElements.isParameterChecked(parameter)) { |
| 2230 constant = SentinelConstant.SENTINEL; |
| 2231 } else { |
| 2232 constant = compiler.compileVariable(parameter); |
| 2233 } |
2170 return graph.addConstant(constant); | 2234 return graph.addConstant(constant); |
2171 } | 2235 } |
2172 | 2236 |
2173 return selector.addArgumentsToList(arguments, | 2237 return selector.addArgumentsToList(arguments, |
2174 list, | 2238 list, |
2175 element, | 2239 element, |
2176 compileArgument, | 2240 compileArgument, |
2177 compileConstant, | 2241 compileConstant, |
2178 compiler); | 2242 compiler); |
2179 } | 2243 } |
(...skipping 1482 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3662 } | 3726 } |
3663 | 3727 |
3664 void visitFunctionExpression(Node node) { | 3728 void visitFunctionExpression(Node node) { |
3665 tooDifficult = true; | 3729 tooDifficult = true; |
3666 } | 3730 } |
3667 | 3731 |
3668 void visitFunctionDeclaration(Node node) { | 3732 void visitFunctionDeclaration(Node node) { |
3669 tooDifficult = true; | 3733 tooDifficult = true; |
3670 } | 3734 } |
3671 | 3735 |
3672 void visitSend(Node node) { | 3736 void visitSend(Send node) { |
| 3737 if (node.isParameterCheck) { |
| 3738 tooDifficult = true; |
| 3739 return; |
| 3740 } |
3673 node.visitChildren(this); | 3741 node.visitChildren(this); |
3674 } | 3742 } |
3675 | 3743 |
3676 visitLoop(Node node) { | 3744 visitLoop(Node node) { |
3677 node.visitChildren(this); | 3745 node.visitChildren(this); |
3678 if (seenReturn) tooDifficult = true; | 3746 if (seenReturn) tooDifficult = true; |
3679 } | 3747 } |
3680 | 3748 |
3681 void visitReturn(Node node) { | 3749 void visitReturn(Node node) { |
3682 if (seenReturn || node.getBeginToken().stringValue === 'native') { | 3750 if (seenReturn || node.getBeginToken().stringValue === 'native') { |
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3933 new HSubGraphBlockInformation(elseBranch.graph)); | 4001 new HSubGraphBlockInformation(elseBranch.graph)); |
3934 | 4002 |
3935 HBasicBlock conditionStartBlock = conditionBranch.block; | 4003 HBasicBlock conditionStartBlock = conditionBranch.block; |
3936 conditionStartBlock.setBlockFlow(info, joinBlock); | 4004 conditionStartBlock.setBlockFlow(info, joinBlock); |
3937 SubGraph conditionGraph = conditionBranch.graph; | 4005 SubGraph conditionGraph = conditionBranch.graph; |
3938 HIf branch = conditionGraph.end.last; | 4006 HIf branch = conditionGraph.end.last; |
3939 assert(branch is HIf); | 4007 assert(branch is HIf); |
3940 branch.blockInformation = conditionStartBlock.blockFlow; | 4008 branch.blockInformation = conditionStartBlock.blockFlow; |
3941 } | 4009 } |
3942 } | 4010 } |
OLD | NEW |