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 SsaFunctionCompiler implements FunctionCompiler { | 7 class SsaFunctionCompiler implements FunctionCompiler { |
8 SsaCodeGeneratorTask generator; | 8 SsaCodeGeneratorTask generator; |
9 SsaBuilderTask builder; | 9 SsaBuilderTask builder; |
10 SsaOptimizerTask optimizer; | 10 SsaOptimizerTask optimizer; |
11 | 11 |
12 SsaFunctionCompiler(JavaScriptBackend backend, bool generateSourceMap) | 12 SsaFunctionCompiler(JavaScriptBackend backend, |
13 : generator = new SsaCodeGeneratorTask(backend), | 13 SourceInformationFactory sourceInformationFactory) |
14 builder = new SsaBuilderTask(backend, generateSourceMap), | 14 : generator = new SsaCodeGeneratorTask(backend, sourceInformationFactory), |
| 15 builder = new SsaBuilderTask(backend, sourceInformationFactory), |
15 optimizer = new SsaOptimizerTask(backend); | 16 optimizer = new SsaOptimizerTask(backend); |
16 | 17 |
17 /// Generates JavaScript code for `work.element`. | 18 /// Generates JavaScript code for `work.element`. |
18 /// Using the ssa builder, optimizer and codegenerator. | 19 /// Using the ssa builder, optimizer and codegenerator. |
19 js.Fun compile(CodegenWorkItem work) { | 20 js.Fun compile(CodegenWorkItem work) { |
20 HGraph graph = builder.build(work); | 21 HGraph graph = builder.build(work); |
21 optimizer.optimize(work, graph); | 22 optimizer.optimize(work, graph); |
22 Element element = work.element; | 23 Element element = work.element; |
23 js.Expression result = generator.generateCode(work, graph); | 24 js.Expression result = generator.generateCode(work, graph); |
24 if (element is FunctionElement) { | 25 if (element is FunctionElement) { |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
89 final ExecutableElement executableContext; | 90 final ExecutableElement executableContext; |
90 | 91 |
91 SyntheticLocal(this.name, this.executableContext); | 92 SyntheticLocal(this.name, this.executableContext); |
92 | 93 |
93 toString() => 'SyntheticLocal($name)'; | 94 toString() => 'SyntheticLocal($name)'; |
94 } | 95 } |
95 | 96 |
96 class SsaBuilderTask extends CompilerTask { | 97 class SsaBuilderTask extends CompilerTask { |
97 final CodeEmitterTask emitter; | 98 final CodeEmitterTask emitter; |
98 final JavaScriptBackend backend; | 99 final JavaScriptBackend backend; |
99 final bool generateSourceMap; | 100 final SourceInformationFactory sourceInformationFactory; |
100 | 101 |
101 String get name => 'SSA builder'; | 102 String get name => 'SSA builder'; |
102 | 103 |
103 SsaBuilderTask(JavaScriptBackend backend, this.generateSourceMap) | 104 SsaBuilderTask(JavaScriptBackend backend, this.sourceInformationFactory) |
104 : emitter = backend.emitter, | 105 : emitter = backend.emitter, |
105 backend = backend, | 106 backend = backend, |
106 super(backend.compiler); | 107 super(backend.compiler); |
107 | 108 |
108 HGraph build(CodegenWorkItem work) { | 109 HGraph build(CodegenWorkItem work) { |
109 return measure(() { | 110 return measure(() { |
110 Element element = work.element.implementation; | 111 Element element = work.element.implementation; |
111 return compiler.withCurrentElement(element, () { | 112 return compiler.withCurrentElement(element, () { |
112 HInstruction.idCounter = 0; | 113 HInstruction.idCounter = 0; |
113 SsaBuilder builder = | 114 SsaBuilder builder = |
114 new SsaBuilder( | 115 new SsaBuilder( |
115 backend, work, emitter.nativeEmitter, generateSourceMap); | 116 backend, work, emitter.nativeEmitter, |
| 117 sourceInformationFactory); |
116 HGraph graph; | 118 HGraph graph; |
117 ElementKind kind = element.kind; | 119 ElementKind kind = element.kind; |
118 if (kind == ElementKind.GENERATIVE_CONSTRUCTOR) { | 120 if (kind == ElementKind.GENERATIVE_CONSTRUCTOR) { |
119 graph = compileConstructor(builder, work); | 121 graph = compileConstructor(builder, work); |
120 } else if (kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY || | 122 } else if (kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY || |
121 kind == ElementKind.FUNCTION || | 123 kind == ElementKind.FUNCTION || |
122 kind == ElementKind.GETTER || | 124 kind == ElementKind.GETTER || |
123 kind == ElementKind.SETTER) { | 125 kind == ElementKind.SETTER) { |
124 graph = builder.buildMethod(element); | 126 graph = builder.buildMethod(element); |
125 } else if (kind == ElementKind.FIELD) { | 127 } else if (kind == ElementKind.FIELD) { |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
192 SsaBuilder builder; | 194 SsaBuilder builder; |
193 ClosureClassMap closureData; | 195 ClosureClassMap closureData; |
194 Map<TypeVariableType, TypeVariableLocal> typeVariableLocals = | 196 Map<TypeVariableType, TypeVariableLocal> typeVariableLocals = |
195 new Map<TypeVariableType, TypeVariableLocal>(); | 197 new Map<TypeVariableType, TypeVariableLocal>(); |
196 final ExecutableElement executableContext; | 198 final ExecutableElement executableContext; |
197 | 199 |
198 /// The class that defines the current type environment or null if no type | 200 /// The class that defines the current type environment or null if no type |
199 /// variables are in scope. | 201 /// variables are in scope. |
200 ClassElement get contextClass => executableContext.contextClass; | 202 ClassElement get contextClass => executableContext.contextClass; |
201 | 203 |
| 204 SourceInformationBuilder get sourceInformationBuilder { |
| 205 return builder.sourceInformationBuilder; |
| 206 } |
| 207 |
202 LocalsHandler(this.builder, this.executableContext); | 208 LocalsHandler(this.builder, this.executableContext); |
203 | 209 |
204 /// Substituted type variables occurring in [type] into the context of | 210 /// Substituted type variables occurring in [type] into the context of |
205 /// [contextClass]. | 211 /// [contextClass]. |
206 DartType substInContext(DartType type) { | 212 DartType substInContext(DartType type) { |
207 if (contextClass != null) { | 213 if (contextClass != null) { |
208 ClassElement typeContext = Types.getClassContext(type); | 214 ClassElement typeContext = Types.getClassContext(type); |
209 if (typeContext != null) { | 215 if (typeContext != null) { |
210 type = type.substByContext( | 216 type = type.substByContext( |
211 contextClass.asInstanceOf(typeContext)); | 217 contextClass.asInstanceOf(typeContext)); |
(...skipping 774 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
986 | 992 |
987 /** | 993 /** |
988 * This class builds SSA nodes for functions represented in AST. | 994 * This class builds SSA nodes for functions represented in AST. |
989 */ | 995 */ |
990 class SsaBuilder extends NewResolvedVisitor { | 996 class SsaBuilder extends NewResolvedVisitor { |
991 final Compiler compiler; | 997 final Compiler compiler; |
992 final JavaScriptBackend backend; | 998 final JavaScriptBackend backend; |
993 final ConstantSystem constantSystem; | 999 final ConstantSystem constantSystem; |
994 final CodegenWorkItem work; | 1000 final CodegenWorkItem work; |
995 final RuntimeTypes rti; | 1001 final RuntimeTypes rti; |
996 final bool generateSourceMap; | 1002 SourceInformationBuilder sourceInformationBuilder; |
997 bool inLazyInitializerExpression = false; | 1003 bool inLazyInitializerExpression = false; |
998 | 1004 |
999 /* This field is used by the native handler. */ | 1005 /* This field is used by the native handler. */ |
1000 final NativeEmitter nativeEmitter; | 1006 final NativeEmitter nativeEmitter; |
1001 | 1007 |
1002 final HGraph graph = new HGraph(); | 1008 final HGraph graph = new HGraph(); |
1003 | 1009 |
1004 /** | 1010 /** |
1005 * The current block to add instructions to. Might be null, if we are | 1011 * The current block to add instructions to. Might be null, if we are |
1006 * visiting dead code, but see [isReachable]. | 1012 * visiting dead code, but see [isReachable]. |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1074 /// Returns `true` if the current element is an `async` function. | 1080 /// Returns `true` if the current element is an `async` function. |
1075 bool get isBuildingAsyncFunction { | 1081 bool get isBuildingAsyncFunction { |
1076 Element element = sourceElement; | 1082 Element element = sourceElement; |
1077 return (element is FunctionElement && | 1083 return (element is FunctionElement && |
1078 element.asyncMarker == AsyncMarker.ASYNC); | 1084 element.asyncMarker == AsyncMarker.ASYNC); |
1079 } | 1085 } |
1080 | 1086 |
1081 SsaBuilder(JavaScriptBackend backend, | 1087 SsaBuilder(JavaScriptBackend backend, |
1082 CodegenWorkItem work, | 1088 CodegenWorkItem work, |
1083 this.nativeEmitter, | 1089 this.nativeEmitter, |
1084 this.generateSourceMap) | 1090 SourceInformationFactory sourceInformationFactory) |
1085 : this.compiler = backend.compiler, | 1091 : this.compiler = backend.compiler, |
1086 this.backend = backend, | 1092 this.backend = backend, |
1087 this.constantSystem = backend.constantSystem, | 1093 this.constantSystem = backend.constantSystem, |
1088 this.work = work, | 1094 this.work = work, |
1089 this.rti = backend.rti, | 1095 this.rti = backend.rti, |
1090 super(work.resolutionTree) { | 1096 super(work.resolutionTree) { |
1091 localsHandler = new LocalsHandler(this, work.element); | 1097 localsHandler = new LocalsHandler(this, work.element); |
1092 sourceElementStack.add(work.element); | 1098 sourceElementStack.add(work.element); |
| 1099 sourceInformationBuilder = |
| 1100 sourceInformationFactory.forContext(work.element.implementation); |
1093 } | 1101 } |
1094 | 1102 |
1095 CodegenRegistry get registry => work.registry; | 1103 CodegenRegistry get registry => work.registry; |
1096 | 1104 |
1097 /// Returns the current source element. | 1105 /// Returns the current source element. |
1098 /// | 1106 /// |
1099 /// The returned element is a declaration element. | 1107 /// The returned element is a declaration element. |
1100 // TODO(johnniwinther): Check that all usages of sourceElement agree on | 1108 // TODO(johnniwinther): Check that all usages of sourceElement agree on |
1101 // implementation/declaration distinction. | 1109 // implementation/declaration distinction. |
1102 Element get sourceElement => sourceElementStack.last; | 1110 Element get sourceElement => sourceElementStack.last; |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1153 } | 1161 } |
1154 | 1162 |
1155 void add(HInstruction instruction) { | 1163 void add(HInstruction instruction) { |
1156 current.add(instruction); | 1164 current.add(instruction); |
1157 } | 1165 } |
1158 | 1166 |
1159 void addWithPosition(HInstruction instruction, ast.Node node) { | 1167 void addWithPosition(HInstruction instruction, ast.Node node) { |
1160 add(attachPosition(instruction, node)); | 1168 add(attachPosition(instruction, node)); |
1161 } | 1169 } |
1162 | 1170 |
1163 SourceFile currentSourceFile() { | |
1164 return sourceElement.implementation.compilationUnit.script.file; | |
1165 } | |
1166 | |
1167 void checkValidSourceFileLocation( | |
1168 SourceLocation location, SourceFile sourceFile, int offset) { | |
1169 if (!location.isValid) { | |
1170 throw MessageKind.INVALID_SOURCE_FILE_LOCATION.message( | |
1171 {'offset': offset, | |
1172 'fileName': sourceFile.filename, | |
1173 'length': sourceFile.length}); | |
1174 } | |
1175 } | |
1176 | |
1177 /** | 1171 /** |
1178 * Returns a complete argument list for a call of [function]. | 1172 * Returns a complete argument list for a call of [function]. |
1179 */ | 1173 */ |
1180 List<HInstruction> completeSendArgumentsList( | 1174 List<HInstruction> completeSendArgumentsList( |
1181 FunctionElement function, | 1175 FunctionElement function, |
1182 Selector selector, | 1176 Selector selector, |
1183 List<HInstruction> providedArguments, | 1177 List<HInstruction> providedArguments, |
1184 ast.Node currentNode) { | 1178 ast.Node currentNode) { |
1185 assert(invariant(function, function.isImplementation)); | 1179 assert(invariant(function, function.isImplementation)); |
1186 assert(providedArguments != null); | 1180 assert(providedArguments != null); |
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1453 bool isCalledOnce(Element element) { | 1447 bool isCalledOnce(Element element) { |
1454 if (!allInlinedFunctionsCalledOnce) return false; | 1448 if (!allInlinedFunctionsCalledOnce) return false; |
1455 TypesInferrer inferrer = compiler.typesTask.typesInferrer; | 1449 TypesInferrer inferrer = compiler.typesTask.typesInferrer; |
1456 return inferrer.isCalledOnce(element); | 1450 return inferrer.isCalledOnce(element); |
1457 } | 1451 } |
1458 | 1452 |
1459 inlinedFrom(Element element, f()) { | 1453 inlinedFrom(Element element, f()) { |
1460 assert(element is FunctionElement || element is VariableElement); | 1454 assert(element is FunctionElement || element is VariableElement); |
1461 return compiler.withCurrentElement(element, () { | 1455 return compiler.withCurrentElement(element, () { |
1462 // The [sourceElementStack] contains declaration elements. | 1456 // The [sourceElementStack] contains declaration elements. |
| 1457 SourceInformationBuilder oldSourceInformationBuilder = |
| 1458 sourceInformationBuilder; |
| 1459 sourceInformationBuilder = |
| 1460 sourceInformationBuilder.forContext(element.implementation); |
1463 sourceElementStack.add(element.declaration); | 1461 sourceElementStack.add(element.declaration); |
1464 var result = f(); | 1462 var result = f(); |
| 1463 sourceInformationBuilder = oldSourceInformationBuilder; |
1465 sourceElementStack.removeLast(); | 1464 sourceElementStack.removeLast(); |
1466 return result; | 1465 return result; |
1467 }); | 1466 }); |
1468 } | 1467 } |
1469 | 1468 |
1470 HInstruction handleConstantForOptionalParameter(Element parameter) { | 1469 HInstruction handleConstantForOptionalParameter(Element parameter) { |
1471 ConstantExpression constant = | 1470 ConstantExpression constant = |
1472 backend.constants.getConstantForVariable(parameter); | 1471 backend.constants.getConstantForVariable(parameter); |
1473 assert(invariant(parameter, constant != null, | 1472 assert(invariant(parameter, constant != null, |
1474 message: 'No constant computed for $parameter')); | 1473 message: 'No constant computed for $parameter')); |
(...skipping 1031 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2506 value, | 2505 value, |
2507 compiler.boolClass.rawType, | 2506 compiler.boolClass.rawType, |
2508 kind: HTypeConversion.BOOLEAN_CONVERSION_CHECK); | 2507 kind: HTypeConversion.BOOLEAN_CONVERSION_CHECK); |
2509 } | 2508 } |
2510 HInstruction result = new HBoolify(value, backend.boolType); | 2509 HInstruction result = new HBoolify(value, backend.boolType); |
2511 add(result); | 2510 add(result); |
2512 return result; | 2511 return result; |
2513 } | 2512 } |
2514 | 2513 |
2515 HInstruction attachPosition(HInstruction target, ast.Node node) { | 2514 HInstruction attachPosition(HInstruction target, ast.Node node) { |
2516 if (generateSourceMap && node != null) { | 2515 if (node != null) { |
2517 target.sourceInformation = sourceInformationForBeginToken(node); | 2516 target.sourceInformation = sourceInformationBuilder.buildGeneric(node); |
2518 } | 2517 } |
2519 return target; | 2518 return target; |
2520 } | 2519 } |
2521 | 2520 |
2522 SourceInformation sourceInformationForBeginToken(ast.Node node) { | |
2523 return new StartEndSourceInformation(sourceFileLocationForBeginToken(node)); | |
2524 } | |
2525 | |
2526 SourceInformation sourceInformationForBeginEndToken(ast.Node node) { | |
2527 return new StartEndSourceInformation( | |
2528 sourceFileLocationForBeginToken(node), | |
2529 sourceFileLocationForEndToken(node)); | |
2530 } | |
2531 | |
2532 SourceLocation sourceFileLocationForBeginToken(ast.Node node) => | |
2533 sourceFileLocationForToken(node, node.getBeginToken()); | |
2534 | |
2535 SourceLocation sourceFileLocationForEndToken(ast.Node node) => | |
2536 sourceFileLocationForToken(node, node.getEndToken()); | |
2537 | |
2538 SourceLocation sourceFileLocationForToken(ast.Node node, Token token) { | |
2539 SourceFile sourceFile = currentSourceFile(); | |
2540 SourceLocation location = | |
2541 new TokenSourceLocation(sourceFile, token, sourceElement.name); | |
2542 checkValidSourceFileLocation(location, sourceFile, token.charOffset); | |
2543 return location; | |
2544 } | |
2545 | |
2546 void visit(ast.Node node) { | 2521 void visit(ast.Node node) { |
2547 if (node != null) node.accept(this); | 2522 if (node != null) node.accept(this); |
2548 } | 2523 } |
2549 | 2524 |
2550 visitBlock(ast.Block node) { | 2525 visitBlock(ast.Block node) { |
2551 assert(!isAborted()); | 2526 assert(!isAborted()); |
2552 if (!isReachable) return; // This can only happen when inlining. | 2527 if (!isReachable) return; // This can only happen when inlining. |
2553 for (Link<ast.Node> link = node.statements.nodes; | 2528 for (Link<ast.Node> link = node.statements.nodes; |
2554 !link.isEmpty; | 2529 !link.isEmpty; |
2555 link = link.tail) { | 2530 link = link.tail) { |
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2805 conditionBlock.postProcessLoopHeader(); | 2780 conditionBlock.postProcessLoopHeader(); |
2806 HLoopBlockInformation info = | 2781 HLoopBlockInformation info = |
2807 new HLoopBlockInformation( | 2782 new HLoopBlockInformation( |
2808 HLoopBlockInformation.loopType(loop), | 2783 HLoopBlockInformation.loopType(loop), |
2809 wrapExpressionGraph(initializerGraph), | 2784 wrapExpressionGraph(initializerGraph), |
2810 wrapExpressionGraph(conditionExpression), | 2785 wrapExpressionGraph(conditionExpression), |
2811 wrapStatementGraph(bodyGraph), | 2786 wrapStatementGraph(bodyGraph), |
2812 wrapExpressionGraph(updateGraph), | 2787 wrapExpressionGraph(updateGraph), |
2813 conditionBlock.loopInformation.target, | 2788 conditionBlock.loopInformation.target, |
2814 conditionBlock.loopInformation.labels, | 2789 conditionBlock.loopInformation.labels, |
2815 sourceInformationForBeginEndToken(loop)); | 2790 sourceInformationBuilder.buildLoop(loop)); |
2816 | 2791 |
2817 startBlock.setBlockFlow(info, current); | 2792 startBlock.setBlockFlow(info, current); |
2818 loopInfo.loopBlockInformation = info; | 2793 loopInfo.loopBlockInformation = info; |
2819 } else { | 2794 } else { |
2820 // The body of the for/while loop always aborts, so there is no back edge. | 2795 // The body of the for/while loop always aborts, so there is no back edge. |
2821 // We turn the code into: | 2796 // We turn the code into: |
2822 // if (condition) { | 2797 // if (condition) { |
2823 // body; | 2798 // body; |
2824 // } else { | 2799 // } else { |
2825 // // We always create an empty else block to avoid critical edges. | 2800 // // We always create an empty else block to avoid critical edges. |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3022 SubGraph bodyGraph = new SubGraph(loopEntryBlock, bodyExitBlock); | 2997 SubGraph bodyGraph = new SubGraph(loopEntryBlock, bodyExitBlock); |
3023 HLoopBlockInformation loopBlockInfo = | 2998 HLoopBlockInformation loopBlockInfo = |
3024 new HLoopBlockInformation( | 2999 new HLoopBlockInformation( |
3025 HLoopBlockInformation.DO_WHILE_LOOP, | 3000 HLoopBlockInformation.DO_WHILE_LOOP, |
3026 null, | 3001 null, |
3027 wrapExpressionGraph(conditionExpression), | 3002 wrapExpressionGraph(conditionExpression), |
3028 wrapStatementGraph(bodyGraph), | 3003 wrapStatementGraph(bodyGraph), |
3029 null, | 3004 null, |
3030 loopEntryBlock.loopInformation.target, | 3005 loopEntryBlock.loopInformation.target, |
3031 loopEntryBlock.loopInformation.labels, | 3006 loopEntryBlock.loopInformation.labels, |
3032 sourceInformationForBeginEndToken(node)); | 3007 sourceInformationBuilder.buildLoop(node)); |
3033 loopEntryBlock.setBlockFlow(loopBlockInfo, current); | 3008 loopEntryBlock.setBlockFlow(loopBlockInfo, current); |
3034 loopInfo.loopBlockInformation = loopBlockInfo; | 3009 loopInfo.loopBlockInformation = loopBlockInfo; |
3035 } else { | 3010 } else { |
3036 // Since the loop has no back edge, we remove the loop information on the | 3011 // Since the loop has no back edge, we remove the loop information on the |
3037 // header. | 3012 // header. |
3038 loopEntryBlock.loopInformation = null; | 3013 loopEntryBlock.loopInformation = null; |
3039 | 3014 |
3040 if (jumpHandler.hasAnyBreak()) { | 3015 if (jumpHandler.hasAnyBreak()) { |
3041 // Null branchBlock because the body of the do-while loop always aborts, | 3016 // Null branchBlock because the body of the do-while loop always aborts, |
3042 // so we never get to the condition. | 3017 // so we never get to the condition. |
(...skipping 4090 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7133 if (unaliased is TypedefType) throw 'unable to unalias $type'; | 7108 if (unaliased is TypedefType) throw 'unable to unalias $type'; |
7134 unaliased.accept(this, builder); | 7109 unaliased.accept(this, builder); |
7135 } | 7110 } |
7136 | 7111 |
7137 void visitDynamicType(DynamicType type, SsaBuilder builder) { | 7112 void visitDynamicType(DynamicType type, SsaBuilder builder) { |
7138 JavaScriptBackend backend = builder.compiler.backend; | 7113 JavaScriptBackend backend = builder.compiler.backend; |
7139 ClassElement cls = backend.findHelper('DynamicRuntimeType'); | 7114 ClassElement cls = backend.findHelper('DynamicRuntimeType'); |
7140 builder.push(new HDynamicType(type, new TypeMask.exact(cls, classWorld))); | 7115 builder.push(new HDynamicType(type, new TypeMask.exact(cls, classWorld))); |
7141 } | 7116 } |
7142 } | 7117 } |
OLD | NEW |