Chromium Code Reviews| 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 |