OLD | NEW |
---|---|
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 import 'package:kernel/ast.dart' as ir; | 5 import 'package:kernel/ast.dart' as ir; |
6 | 6 |
7 import '../common.dart'; | 7 import '../common.dart'; |
8 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; | 8 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; |
9 import '../common/tasks.dart' show CompilerTask; | 9 import '../common/tasks.dart' show CompilerTask; |
10 import '../compiler.dart'; | 10 import '../compiler.dart'; |
11 import '../dart_types.dart'; | |
11 import '../elements/elements.dart'; | 12 import '../elements/elements.dart'; |
12 import '../io/source_information.dart'; | 13 import '../io/source_information.dart'; |
13 import '../js_backend/backend.dart' show JavaScriptBackend; | 14 import '../js_backend/backend.dart' show JavaScriptBackend; |
14 import '../kernel/kernel.dart'; | 15 import '../kernel/kernel.dart'; |
15 import '../kernel/kernel_visitor.dart'; | |
16 import '../resolution/tree_elements.dart'; | |
17 import '../tree/dartstring.dart'; | 16 import '../tree/dartstring.dart'; |
18 import '../types/masks.dart'; | 17 import '../types/masks.dart'; |
18 import '../universe/selector.dart'; | |
19 | 19 |
20 import 'graph_builder.dart'; | 20 import 'graph_builder.dart'; |
21 import 'kernel_ast_adapter.dart'; | 21 import 'kernel_ast_adapter.dart'; |
22 import 'locals_handler.dart'; | 22 import 'locals_handler.dart'; |
23 import 'nodes.dart'; | 23 import 'nodes.dart'; |
24 import 'ssa_branch_builder.dart'; | 24 import 'ssa_branch_builder.dart'; |
25 | 25 |
26 class SsaKernelBuilderTask extends CompilerTask { | 26 class SsaKernelBuilderTask extends CompilerTask { |
27 final JavaScriptBackend backend; | 27 final JavaScriptBackend backend; |
28 final SourceInformationStrategy sourceInformationFactory; | 28 final SourceInformationStrategy sourceInformationFactory; |
29 | 29 |
30 String get name => 'SSA kernel builder'; | 30 String get name => 'SSA kernel builder'; |
31 | 31 |
32 SsaKernelBuilderTask(JavaScriptBackend backend, this.sourceInformationFactory) | 32 SsaKernelBuilderTask(JavaScriptBackend backend, this.sourceInformationFactory) |
33 : backend = backend, | 33 : backend = backend, |
34 super(backend.compiler.measurer); | 34 super(backend.compiler.measurer); |
35 | 35 |
36 HGraph build(CodegenWorkItem work) { | 36 HGraph build(CodegenWorkItem work) { |
37 return measure(() { | 37 return measure(() { |
38 AstElement element = work.element.implementation; | 38 AstElement element = work.element.implementation; |
39 Kernel kernel = backend.kernelTask.kernel; | 39 Kernel kernel = backend.kernelTask.kernel; |
40 ir.Procedure function = kernel.functions[element]; | 40 KernelSsaBuilder builder = new KernelSsaBuilder(element, work.resolvedAst, |
41 KernelSsaBuilder builder = new KernelSsaBuilder( | 41 backend.compiler, work.registry, sourceInformationFactory, kernel); |
42 function, | |
43 element, | |
44 work.resolvedAst, | |
45 backend.compiler, | |
46 work.registry, | |
47 sourceInformationFactory, | |
48 kernel); | |
49 return builder.build(); | 42 return builder.build(); |
50 }); | 43 }); |
51 } | 44 } |
52 } | 45 } |
53 | 46 |
54 class KernelSsaBuilder extends ir.Visitor with GraphBuilder { | 47 class KernelSsaBuilder extends ir.Visitor with GraphBuilder { |
55 final ir.Procedure function; | 48 ir.Node target; |
56 final FunctionElement functionElement; | 49 final AstElement targetElement; |
57 final ResolvedAst resolvedAst; | 50 final ResolvedAst resolvedAst; |
58 final Compiler compiler; | 51 final Compiler compiler; |
59 final CodegenRegistry registry; | 52 final CodegenRegistry registry; |
60 | 53 |
61 JavaScriptBackend get backend => compiler.backend; | 54 JavaScriptBackend get backend => compiler.backend; |
62 | 55 |
63 SourceInformationBuilder sourceInformationBuilder; | 56 SourceInformationBuilder sourceInformationBuilder; |
64 KernelAstAdapter astAdapter; | 57 KernelAstAdapter astAdapter; |
65 | 58 |
66 KernelSsaBuilder( | 59 KernelSsaBuilder( |
67 this.function, | 60 this.targetElement, |
68 this.functionElement, | |
69 this.resolvedAst, | 61 this.resolvedAst, |
70 this.compiler, | 62 this.compiler, |
71 this.registry, | 63 this.registry, |
72 SourceInformationStrategy sourceInformationFactory, | 64 SourceInformationStrategy sourceInformationFactory, |
73 Kernel kernel) { | 65 Kernel kernel) { |
74 graph.element = functionElement; | 66 graph.element = targetElement; |
75 // TODO(het): Should sourceInformationBuilder be in GraphBuilder? | 67 // TODO(het): Should sourceInformationBuilder be in GraphBuilder? |
76 this.sourceInformationBuilder = | 68 this.sourceInformationBuilder = |
77 sourceInformationFactory.createBuilderForContext(resolvedAst); | 69 sourceInformationFactory.createBuilderForContext(resolvedAst); |
78 graph.sourceInformation = | 70 graph.sourceInformation = |
79 sourceInformationBuilder.buildVariableDeclaration(); | 71 sourceInformationBuilder.buildVariableDeclaration(); |
80 this.localsHandler = | 72 this.localsHandler = new LocalsHandler(this, targetElement, null, compiler); |
81 new LocalsHandler(this, functionElement, null, compiler); | |
82 this.astAdapter = new KernelAstAdapter( | 73 this.astAdapter = new KernelAstAdapter( |
83 compiler.backend, | 74 compiler.backend, |
84 resolvedAst, | 75 resolvedAst, |
85 kernel.nodeToAst, | 76 kernel.nodeToAst, |
86 kernel.nodeToElement, | 77 kernel.nodeToElement, |
78 kernel.fields, | |
87 kernel.functions, | 79 kernel.functions, |
88 kernel.classes, | 80 kernel.classes, |
89 kernel.libraries); | 81 kernel.libraries); |
82 Element originTarget = targetElement; | |
83 if (originTarget.isPatch) { | |
84 originTarget = originTarget.origin; | |
85 } | |
86 if (originTarget is FunctionElement) { | |
87 target = kernel.functions[originTarget]; | |
88 } else if (originTarget is FieldElement) { | |
89 target = kernel.fields[originTarget]; | |
90 } | |
90 } | 91 } |
91 | 92 |
92 HGraph build() { | 93 HGraph build() { |
93 // TODO(het): no reason to do this here... | 94 // TODO(het): no reason to do this here... |
94 HInstruction.idCounter = 0; | 95 HInstruction.idCounter = 0; |
95 if (function.kind == ir.ProcedureKind.Method || | 96 if (target is ir.Procedure) { |
96 function.kind == ir.ProcedureKind.Operator) { | 97 buildProcedure(target); |
97 buildMethod(function, functionElement); | 98 } else if (target is ir.Field) { |
98 } else { | 99 buildField(target); |
99 compiler.reporter.internalError( | 100 } else if (target is ir.Constructor) { |
100 functionElement, | 101 // TODO(het): Actually handle this correctly |
101 "Unable to convert this kind of Kernel " | 102 HBasicBlock block = graph.addNewBlock(); |
102 "procedure to SSA: ${function.kind}"); | 103 open(graph.entry); |
104 close(new HGoto()).addSuccessor(block); | |
105 open(block); | |
106 closeAndGotoExit(new HGoto()); | |
107 graph.finalize(); | |
103 } | 108 } |
104 assert(graph.isValid()); | 109 assert(graph.isValid()); |
105 return graph; | 110 return graph; |
106 } | 111 } |
107 | 112 |
113 void buildProcedure(ir.Procedure procedure) { | |
114 if (procedure.kind == ir.ProcedureKind.Method || | |
115 procedure.kind == ir.ProcedureKind.Operator || | |
116 procedure.kind == ir.ProcedureKind.Getter || | |
117 procedure.kind == ir.ProcedureKind.Factory) { | |
118 buildMethod(procedure); | |
119 } else { | |
120 compiler.reporter.internalError( | |
121 targetElement, | |
122 "Unable to convert this kind of Kernel " | |
123 "procedure to SSA: ${procedure.kind}"); | |
124 } | |
125 } | |
126 | |
127 void buildField(ir.Field field) { | |
128 openFunction(); | |
129 field.initializer.accept(this); | |
130 HInstruction value = pop(); | |
131 closeAndGotoExit(new HReturn(value, null)); | |
132 closeFunction(); | |
133 } | |
134 | |
108 @override | 135 @override |
109 HInstruction popBoolified() { | 136 HInstruction popBoolified() { |
110 HInstruction value = pop(); | 137 HInstruction value = pop(); |
111 // TODO(het): add boolean conversion type check | 138 // TODO(het): add boolean conversion type check |
112 HInstruction result = new HBoolify(value, backend.boolType); | 139 HInstruction result = new HBoolify(value, backend.boolType); |
113 add(result); | 140 add(result); |
114 return result; | 141 return result; |
115 } | 142 } |
116 | 143 |
117 // TODO(het): This implementation is shared with [SsaBuilder]. Should we just | 144 // TODO(het): This implementation is shared with [SsaBuilder]. Should we just |
118 // allow [GraphBuilder] to access `compiler`? | 145 // allow [GraphBuilder] to access `compiler`? |
119 @override | 146 @override |
120 pushCheckNull(HInstruction expression) { | 147 pushCheckNull(HInstruction expression) { |
121 push(new HIdentity( | 148 push(new HIdentity( |
122 expression, graph.addConstantNull(compiler), null, backend.boolType)); | 149 expression, graph.addConstantNull(compiler), null, backend.boolType)); |
123 } | 150 } |
124 | 151 |
125 /// Builds a SSA graph for [method]. | 152 /// Builds a SSA graph for [method]. |
126 void buildMethod(ir.Procedure method, FunctionElement functionElement) { | 153 void buildMethod(ir.Procedure method) { |
127 openFunction(functionElement); | 154 openFunction(); |
128 method.function.body.accept(this); | 155 method.function.body.accept(this); |
129 closeFunction(); | 156 closeFunction(); |
130 } | 157 } |
131 | 158 |
132 // TODO(het): get function element from astAdapter? | 159 void openFunction() { |
133 void openFunction(FunctionElement functionElement) { | |
134 HBasicBlock block = graph.addNewBlock(); | 160 HBasicBlock block = graph.addNewBlock(); |
135 open(graph.entry); | 161 open(graph.entry); |
136 localsHandler.startFunction(functionElement, resolvedAst.node); | 162 localsHandler.startFunction(targetElement, resolvedAst.node); |
137 close(new HGoto()).addSuccessor(block); | 163 close(new HGoto()).addSuccessor(block); |
138 | 164 |
139 open(block); | 165 open(block); |
140 } | 166 } |
141 | 167 |
142 void closeFunction() { | 168 void closeFunction() { |
143 if (!isAborted()) closeAndGotoExit(new HGoto()); | 169 if (!isAborted()) closeAndGotoExit(new HGoto()); |
144 graph.finalize(); | 170 graph.finalize(); |
145 } | 171 } |
146 | 172 |
147 @override | 173 @override |
174 void defaultExpression(ir.Expression expression) { | |
175 // TODO(het): This is only to get tests working | |
176 stack.add(graph.addConstantNull(compiler)); | |
177 } | |
178 | |
179 @override | |
148 void visitBlock(ir.Block block) { | 180 void visitBlock(ir.Block block) { |
149 assert(!isAborted()); | 181 assert(!isAborted()); |
150 for (ir.Statement statement in block.statements) { | 182 for (ir.Statement statement in block.statements) { |
151 statement.accept(this); | 183 statement.accept(this); |
152 if (!isReachable) { | 184 if (!isReachable) { |
153 // The block has been aborted by a return or a throw. | 185 // The block has been aborted by a return or a throw. |
154 if (stack.isNotEmpty) { | 186 if (stack.isNotEmpty) { |
155 compiler.reporter.internalError( | 187 compiler.reporter.internalError( |
156 NO_LOCATION_SPANNABLE, 'Non-empty instruction stack.'); | 188 NO_LOCATION_SPANNABLE, 'Non-empty instruction stack.'); |
157 } | 189 } |
158 return; | 190 return; |
159 } | 191 } |
160 } | 192 } |
161 assert(!current.isClosed()); | 193 assert(!current.isClosed()); |
162 if (stack.isNotEmpty) { | 194 if (stack.isNotEmpty) { |
163 compiler.reporter | 195 compiler.reporter |
164 .internalError(NO_LOCATION_SPANNABLE, 'Non-empty instruction stack'); | 196 .internalError(NO_LOCATION_SPANNABLE, 'Non-empty instruction stack'); |
165 } | 197 } |
166 } | 198 } |
167 | 199 |
168 @override | 200 @override |
169 visitExpressionStatement(ir.ExpressionStatement exprStatement) { | 201 void visitExpressionStatement(ir.ExpressionStatement exprStatement) { |
170 exprStatement.expression.accept(this); | 202 exprStatement.expression.accept(this); |
171 pop(); | 203 pop(); |
172 } | 204 } |
173 | 205 |
174 @override | 206 @override |
175 void visitReturnStatement(ir.ReturnStatement returnStatement) { | 207 void visitReturnStatement(ir.ReturnStatement returnStatement) { |
176 HInstruction value; | 208 HInstruction value; |
177 if (returnStatement.expression == null) { | 209 if (returnStatement.expression == null) { |
178 value = graph.addConstantNull(compiler); | 210 value = graph.addConstantNull(compiler); |
179 } else { | 211 } else { |
180 returnStatement.expression.accept(this); | 212 returnStatement.expression.accept(this); |
181 value = pop(); | 213 value = pop(); |
182 // TODO(het): Check or trust the type of value | 214 // TODO(het): Check or trust the type of value |
183 } | 215 } |
184 // TODO(het): Add source information | 216 // TODO(het): Add source information |
185 // TODO(het): Set a return value instead of closing the function when we | 217 // TODO(het): Set a return value instead of closing the function when we |
186 // support inlining. | 218 // support inlining. |
187 closeAndGotoExit(new HReturn(value, null)); | 219 closeAndGotoExit(new HReturn(value, null)); |
188 } | 220 } |
189 | 221 |
190 @override | 222 @override |
191 void visitIfStatement(ir.IfStatement ifStatement) { | 223 void visitIfStatement(ir.IfStatement ifStatement) { |
192 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, compiler); | 224 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler); |
193 branchBuilder.handleIf( | 225 brancher.handleIf( |
194 () => ifStatement.condition.accept(this), | 226 () => ifStatement.condition.accept(this), |
195 () => ifStatement.then.accept(this), | 227 () => ifStatement.then.accept(this), |
196 () => ifStatement.otherwise?.accept(this)); | 228 () => ifStatement.otherwise?.accept(this)); |
197 } | 229 } |
198 | 230 |
199 @override | 231 @override |
232 void visitConditionalExpression(ir.ConditionalExpression conditional) { | |
233 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler); | |
234 brancher.handleConditional( | |
235 () => conditional.condition.accept(this), | |
236 () => conditional.then.accept(this), | |
237 () => conditional.otherwise.accept(this)); | |
238 } | |
239 | |
240 @override | |
241 void visitLogicalExpression(ir.LogicalExpression logicalExpression) { | |
242 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler); | |
243 brancher.handleLogicalBinary(() => logicalExpression.left.accept(this), | |
244 () => logicalExpression.right.accept(this), | |
245 isAnd: logicalExpression.operator == '&&'); | |
246 } | |
247 | |
248 @override | |
200 void visitIntLiteral(ir.IntLiteral intLiteral) { | 249 void visitIntLiteral(ir.IntLiteral intLiteral) { |
201 stack.add(graph.addConstantInt(intLiteral.value, compiler)); | 250 stack.add(graph.addConstantInt(intLiteral.value, compiler)); |
202 } | 251 } |
203 | 252 |
204 @override | 253 @override |
205 visitDoubleLiteral(ir.DoubleLiteral doubleLiteral) { | 254 void visitDoubleLiteral(ir.DoubleLiteral doubleLiteral) { |
206 stack.add(graph.addConstantDouble(doubleLiteral.value, compiler)); | 255 stack.add(graph.addConstantDouble(doubleLiteral.value, compiler)); |
207 } | 256 } |
208 | 257 |
209 @override | 258 @override |
210 visitBoolLiteral(ir.BoolLiteral boolLiteral) { | 259 void visitBoolLiteral(ir.BoolLiteral boolLiteral) { |
211 stack.add(graph.addConstantBool(boolLiteral.value, compiler)); | 260 stack.add(graph.addConstantBool(boolLiteral.value, compiler)); |
212 } | 261 } |
213 | 262 |
214 @override | 263 @override |
215 visitStringLiteral(ir.StringLiteral stringLiteral) { | 264 void visitStringLiteral(ir.StringLiteral stringLiteral) { |
216 stack.add(graph.addConstantString( | 265 stack.add(graph.addConstantString( |
217 new DartString.literal(stringLiteral.value), compiler)); | 266 new DartString.literal(stringLiteral.value), compiler)); |
218 } | 267 } |
219 | 268 |
220 @override | 269 @override |
221 visitSymbolLiteral(ir.SymbolLiteral symbolLiteral) { | 270 void visitSymbolLiteral(ir.SymbolLiteral symbolLiteral) { |
222 stack.add(graph.addConstant( | 271 stack.add(graph.addConstant( |
223 astAdapter.getConstantForSymbol(symbolLiteral), compiler)); | 272 astAdapter.getConstantForSymbol(symbolLiteral), compiler)); |
224 registry?.registerConstSymbol(symbolLiteral.value); | 273 registry?.registerConstSymbol(symbolLiteral.value); |
225 } | 274 } |
226 | 275 |
227 @override | 276 @override |
228 visitNullLiteral(ir.NullLiteral nullLiteral) { | 277 void visitNullLiteral(ir.NullLiteral nullLiteral) { |
229 stack.add(graph.addConstantNull(compiler)); | 278 stack.add(graph.addConstantNull(compiler)); |
230 } | 279 } |
231 | 280 |
232 @override | 281 @override |
233 visitVariableGet(ir.VariableGet variableGet) { | 282 void visitStaticGet(ir.StaticGet staticGet) { |
283 Element element = astAdapter.getElement(staticGet.target); | |
Siggi Cherem (dart-lang)
2016/09/13 23:48:19
nit: consider adding a variable for target
Membe
Harry Terkelsen
2016/09/14 00:07:24
Done.
| |
284 if (staticGet.target is ir.Procedure) { | |
285 element = element.declaration; | |
286 ir.Procedure target = staticGet.target; | |
Siggi Cherem (dart-lang)
2016/09/13 23:48:19
(with a variable above, type promotion would work
Harry Terkelsen
2016/09/14 00:07:24
Done.
| |
287 if (target.kind == ir.ProcedureKind.Getter) { | |
288 // We must invoke the getter | |
289 _pushStaticInvocation( | |
290 target, const <HInstruction>[], astAdapter.returnTypeOf(target)); | |
291 } else { | |
292 push(new HStatic(element, astAdapter.inferredTypeOf(staticGet.target))); | |
Siggi Cherem (dart-lang)
2016/09/13 23:48:19
nit: maybe add a comment that this is a tear-off?
Harry Terkelsen
2016/09/14 00:07:24
Done.
| |
293 } | |
294 } else { | |
295 push(new HStatic(element, astAdapter.inferredTypeOf(staticGet.target))); | |
Siggi Cherem (dart-lang)
2016/09/13 23:48:19
A couple questions here:
(a) shouldn't this elemen
Harry Terkelsen
2016/09/14 00:07:24
a) Yes. Done
b) Yes, there are more cases that ne
| |
296 } | |
297 } | |
298 | |
299 @override | |
300 void visitStaticSet(ir.StaticSet staticSet) { | |
301 VariableElement field = astAdapter.getElement(staticSet.target); | |
302 staticSet.value.accept(this); | |
303 HInstruction value = pop(); | |
304 add(new HStaticStore(field, value)); | |
305 stack.add(value); | |
306 } | |
307 | |
308 @override | |
309 void visitPropertyGet(ir.PropertyGet propertyGet) { | |
310 propertyGet.receiver.accept(this); | |
311 HInstruction receiver = pop(); | |
312 | |
313 List<HInstruction> inputs = <HInstruction>[]; | |
314 bool isIntercepted = astAdapter.isIntercepted(propertyGet); | |
315 if (isIntercepted) { | |
316 HInterceptor interceptor = _interceptorFor(receiver); | |
317 inputs.add(interceptor); | |
318 } | |
319 inputs.add(receiver); | |
320 | |
321 TypeMask type = astAdapter.selectorGetterTypeOf(propertyGet); | |
322 | |
323 push(new HInvokeDynamicGetter(astAdapter.getGetterSelector(propertyGet), | |
324 astAdapter.typeOfGet(propertyGet), null, inputs, type)); | |
325 } | |
326 | |
327 @override | |
328 void visitVariableGet(ir.VariableGet variableGet) { | |
234 LocalElement local = astAdapter.getElement(variableGet.variable); | 329 LocalElement local = astAdapter.getElement(variableGet.variable); |
235 stack.add(localsHandler.readLocal(local)); | 330 stack.add(localsHandler.readLocal(local)); |
236 } | 331 } |
237 | 332 |
333 @override | |
334 void visitVariableSet(ir.VariableSet variableSet) { | |
335 variableSet.value.accept(this); | |
336 HInstruction value = pop(); | |
337 _visitLocalSetter(variableSet.variable, value); | |
338 } | |
339 | |
340 @override | |
341 void visitVariableDeclaration(ir.VariableDeclaration declaration) { | |
342 LocalElement local = astAdapter.getElement(declaration); | |
343 if (declaration.initializer == null) { | |
344 HInstruction initialValue = graph.addConstantNull(compiler); | |
345 localsHandler.updateLocal(local, initialValue); | |
346 } else { | |
347 // TODO(het): handle case where the variable is top-level or static | |
348 declaration.initializer.accept(this); | |
349 HInstruction initialValue = pop(); | |
350 | |
351 _visitLocalSetter(declaration, initialValue); | |
352 | |
353 // Ignore value | |
354 pop(); | |
355 } | |
356 } | |
357 | |
358 void _visitLocalSetter(ir.VariableDeclaration variable, HInstruction value) { | |
359 // TODO(het): handle case where the variable is top-level or static | |
360 LocalElement local = astAdapter.getElement(variable); | |
361 | |
362 // Give the value a name if it doesn't have one already. | |
363 if (value.sourceElement == null) { | |
364 value.sourceElement = local; | |
365 } | |
366 | |
367 stack.add(value); | |
368 // TODO(het): check or trust type | |
369 localsHandler.updateLocal(local, value); | |
370 } | |
371 | |
238 // TODO(het): Also extract type arguments | 372 // TODO(het): Also extract type arguments |
239 /// Extracts the list of instructions for the expressions in the arguments. | 373 /// Extracts the list of instructions for the expressions in the arguments. |
240 List<HInstruction> _visitArguments(ir.Arguments arguments) { | 374 List<HInstruction> _visitArguments(ir.Arguments arguments) { |
241 List<HInstruction> result = <HInstruction>[]; | 375 List<HInstruction> result = <HInstruction>[]; |
242 | 376 |
243 for (ir.Expression argument in arguments.positional) { | 377 for (ir.Expression argument in arguments.positional) { |
244 argument.accept(this); | 378 argument.accept(this); |
245 result.add(pop()); | 379 result.add(pop()); |
246 } | 380 } |
247 for (ir.NamedExpression argument in arguments.named) { | 381 for (ir.NamedExpression argument in arguments.named) { |
248 argument.value.accept(this); | 382 argument.value.accept(this); |
249 result.add(pop()); | 383 result.add(pop()); |
250 } | 384 } |
251 | 385 |
252 return result; | 386 return result; |
253 } | 387 } |
254 | 388 |
255 @override | 389 @override |
256 visitStaticInvocation(ir.StaticInvocation invocation) { | 390 void visitStaticInvocation(ir.StaticInvocation invocation) { |
257 ir.Procedure target = invocation.target; | 391 ir.Procedure target = invocation.target; |
258 bool targetCanThrow = astAdapter.getCanThrow(target); | |
259 TypeMask typeMask = astAdapter.returnTypeOf(target); | 392 TypeMask typeMask = astAdapter.returnTypeOf(target); |
260 | 393 |
261 var arguments = _visitArguments(invocation.arguments); | 394 List<HInstruction> arguments = _visitArguments(invocation.arguments); |
395 | |
396 _pushStaticInvocation(target, arguments, typeMask); | |
397 } | |
398 | |
399 void _pushStaticInvocation( | |
400 ir.Node target, List<HInstruction> arguments, TypeMask typeMask) { | |
401 bool targetCanThrow = astAdapter.getCanThrow(target); | |
262 | 402 |
263 HInstruction instruction = new HInvokeStatic( | 403 HInstruction instruction = new HInvokeStatic( |
264 astAdapter.getElement(target).declaration, arguments, typeMask, | 404 astAdapter.getElement(target).declaration, arguments, typeMask, |
265 targetCanThrow: targetCanThrow); | 405 targetCanThrow: targetCanThrow); |
266 instruction.sideEffects = astAdapter.getSideEffects(target); | 406 instruction.sideEffects = astAdapter.getSideEffects(target); |
267 | 407 |
268 push(instruction); | 408 push(instruction); |
269 } | 409 } |
270 | 410 |
271 // TODO(het): Decide when to inline | 411 // TODO(het): Decide when to inline |
272 @override | 412 @override |
273 visitMethodInvocation(ir.MethodInvocation invocation) { | 413 void visitMethodInvocation(ir.MethodInvocation invocation) { |
274 invocation.receiver.accept(this); | 414 invocation.receiver.accept(this); |
275 HInstruction receiver = pop(); | 415 HInstruction receiver = pop(); |
276 | 416 |
277 List<HInstruction> arguments = <HInstruction>[receiver] | 417 List<HInstruction> arguments = <HInstruction>[receiver] |
278 ..addAll(_visitArguments(invocation.arguments)); | 418 ..addAll(_visitArguments(invocation.arguments)); |
279 | 419 |
280 List<HInstruction> inputs = <HInstruction>[]; | 420 List<HInstruction> inputs = <HInstruction>[]; |
281 | 421 |
282 bool isIntercepted = astAdapter.isIntercepted(invocation); | 422 bool isIntercepted = astAdapter.isIntercepted(invocation); |
283 if (isIntercepted) { | 423 if (isIntercepted) { |
284 HInterceptor interceptor = | 424 HInterceptor interceptor = _interceptorFor(receiver); |
285 new HInterceptor(receiver, backend.nonNullType); | |
286 add(interceptor); | |
287 inputs.add(interceptor); | 425 inputs.add(interceptor); |
288 } | 426 } |
289 inputs.addAll(arguments); | 427 inputs.addAll(arguments); |
290 | 428 |
291 TypeMask type = astAdapter.selectorTypeOf(invocation); | 429 TypeMask type = astAdapter.selectorTypeOf(invocation); |
292 | 430 |
293 push(new HInvokeDynamicMethod(astAdapter.getSelector(invocation), | 431 push(new HInvokeDynamicMethod(astAdapter.getSelector(invocation), |
294 astAdapter.typeOfInvocation(invocation), inputs, type, isIntercepted)); | 432 astAdapter.typeOfInvocation(invocation), inputs, type, isIntercepted)); |
295 } | 433 } |
296 | 434 |
435 HInterceptor _interceptorFor(HInstruction intercepted) { | |
436 HInterceptor interceptor = | |
437 new HInterceptor(intercepted, backend.nonNullType); | |
438 add(interceptor); | |
439 return interceptor; | |
440 } | |
441 | |
442 ir.Class containingClass(ir.TreeNode node) { | |
Siggi Cherem (dart-lang)
2016/09/13 23:48:19
nit => make static and private?
Harry Terkelsen
2016/09/14 00:07:24
Done.
| |
443 while (node != null) { | |
444 if (node is ir.Class) return node; | |
445 node = node.parent; | |
446 } | |
447 return null; | |
448 } | |
449 | |
297 @override | 450 @override |
298 visitThisExpression(ir.ThisExpression thisExpression) { | 451 void visitSuperMethodInvocation(ir.SuperMethodInvocation invocation) { |
452 List<HInstruction> arguments = _visitArguments(invocation.arguments); | |
453 HInstruction receiver = localsHandler.readThis(); | |
454 Selector selector = astAdapter.getSelector(invocation); | |
455 ir.Class surroundingClass = containingClass(invocation); | |
456 | |
457 List<HInstruction> inputs = <HInstruction>[]; | |
458 if (astAdapter.isIntercepted(invocation)) { | |
459 inputs.add(_interceptorFor(receiver)); | |
460 } | |
461 inputs.add(receiver); | |
462 inputs.addAll(arguments); | |
463 | |
464 HInstruction instruction = new HInvokeSuper( | |
465 astAdapter.getElement(invocation.interfaceTarget), | |
466 astAdapter.getElement(surroundingClass), | |
467 selector, | |
468 inputs, | |
469 astAdapter.returnTypeOf(invocation.interfaceTarget), | |
470 null, | |
471 isSetter: selector.isSetter || selector.isIndexSet); | |
472 instruction.sideEffects = | |
473 compiler.world.getSideEffectsOfSelector(selector, null); | |
474 push(instruction); | |
475 } | |
476 | |
477 @override | |
478 void visitConstructorInvocation(ir.ConstructorInvocation invocation) { | |
479 ir.Constructor target = invocation.target; | |
480 List<HInstruction> arguments = _visitArguments(invocation.arguments); | |
481 TypeMask typeMask = new TypeMask.nonNullExact( | |
482 astAdapter.getElement(target.enclosingClass), compiler.world); | |
483 _pushStaticInvocation(target, arguments, typeMask); | |
484 } | |
485 | |
486 @override | |
487 void visitIsExpression(ir.IsExpression isExpression) { | |
488 isExpression.operand.accept(this); | |
489 HInstruction expression = pop(); | |
490 | |
491 DartType type = astAdapter.getDartType(isExpression.type); | |
492 | |
493 if (backend.hasDirectCheckFor(type)) { | |
494 push(new HIs.direct(type, expression, backend.boolType)); | |
495 return; | |
496 } | |
497 | |
498 // The interceptor is not always needed. It is removed by optimization | |
499 // when the receiver type or tested type permit. | |
500 HInterceptor interceptor = _interceptorFor(expression); | |
501 push(new HIs.raw(type, expression, interceptor, backend.boolType)); | |
502 } | |
503 | |
504 @override | |
505 void visitThrow(ir.Throw throwNode) { | |
506 throwNode.expression.accept(this); | |
507 HInstruction expression = pop(); | |
508 if (isReachable) { | |
509 push(new HThrowExpression(expression, null)); | |
510 isReachable = false; | |
511 } | |
512 } | |
513 | |
514 @override | |
515 void visitThisExpression(ir.ThisExpression thisExpression) { | |
299 stack.add(localsHandler.readThis()); | 516 stack.add(localsHandler.readThis()); |
300 } | 517 } |
301 | 518 |
302 @override | 519 @override |
303 visitNot(ir.Not not) { | 520 void visitNot(ir.Not not) { |
304 not.operand.accept(this); | 521 not.operand.accept(this); |
305 push(new HNot(popBoolified(), backend.boolType)); | 522 push(new HNot(popBoolified(), backend.boolType)); |
306 } | 523 } |
307 } | 524 } |
OLD | NEW |