OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 library tree_ir_builder; | 5 library tree_ir_builder; |
6 | 6 |
7 import '../dart2jslib.dart' as dart2js; | 7 import '../dart2jslib.dart' as dart2js; |
8 import '../dart_types.dart'; | 8 import '../dart_types.dart'; |
9 import '../elements/elements.dart'; | 9 import '../elements/elements.dart'; |
10 import '../cps_ir/cps_ir_nodes.dart' as cps_ir; | 10 import '../cps_ir/cps_ir_nodes.dart' as cps_ir; |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
112 /// referred to by [reference]. | 112 /// referred to by [reference]. |
113 /// This increments the reference count for the given variable, so the | 113 /// This increments the reference count for the given variable, so the |
114 /// returned expression must be used in the tree. | 114 /// returned expression must be used in the tree. |
115 Expression getVariableUse(cps_ir.Reference<cps_ir.Primitive> reference) { | 115 Expression getVariableUse(cps_ir.Reference<cps_ir.Primitive> reference) { |
116 if (thisParameter != null && reference.definition == thisParameter) { | 116 if (thisParameter != null && reference.definition == thisParameter) { |
117 return new This(); | 117 return new This(); |
118 } | 118 } |
119 return new VariableUse(getVariable(reference.definition)); | 119 return new VariableUse(getVariable(reference.definition)); |
120 } | 120 } |
121 | 121 |
122 RootNode build(cps_ir.RootNode node) { | |
123 // TODO(asgerf): Don't have build AND buildXXX as public API. | |
124 if (node is cps_ir.FieldDefinition) { | |
125 return buildField(node); | |
126 } else if (node is cps_ir.ConstructorDefinition) { | |
127 return buildConstructor(node); | |
128 } else { | |
129 assert(dart2js.invariant( | |
130 CURRENT_ELEMENT_SPANNABLE, | |
131 node is cps_ir.FunctionDefinition, | |
132 message: 'expected FunctionDefinition or FieldDefinition, ' | |
133 ' found $node')); | |
134 return buildFunction(node); | |
135 } | |
136 } | |
137 | |
138 FieldDefinition buildField(cps_ir.FieldDefinition node) { | |
139 Statement body; | |
140 if (!node.isEmpty) { | |
141 currentElement = node.element; | |
142 returnContinuation = node.body.returnContinuation; | |
143 | |
144 phiTempVar = new Variable(node.element, null); | |
145 | |
146 body = visit(node.body); | |
147 } | |
148 return new FieldDefinition(node.element, body); | |
149 } | |
150 | |
151 Variable addFunctionParameter(cps_ir.Definition variable) { | 122 Variable addFunctionParameter(cps_ir.Definition variable) { |
152 if (variable is cps_ir.Parameter) { | 123 if (variable is cps_ir.Parameter) { |
153 return getVariable(variable); | 124 return getVariable(variable); |
154 } else { | 125 } else { |
155 return addMutableVariable(variable as cps_ir.MutableVariable) | 126 return addMutableVariable(variable as cps_ir.MutableVariable) |
156 ..isCaptured = true; | 127 ..isCaptured = true; |
157 } | 128 } |
158 } | 129 } |
159 | 130 |
160 FunctionDefinition buildFunction(cps_ir.FunctionDefinition node) { | 131 FunctionDefinition buildFunction(cps_ir.FunctionDefinition node) { |
161 currentElement = node.element; | 132 currentElement = node.element; |
162 if (parent != null) { | 133 if (parent != null) { |
163 // Local function's 'this' refers to enclosing method's 'this' | 134 // Local function's 'this' refers to enclosing method's 'this' |
164 thisParameter = parent.thisParameter; | 135 thisParameter = parent.thisParameter; |
165 } else { | 136 } else { |
166 thisParameter = node.thisParameter; | 137 thisParameter = node.thisParameter; |
167 } | 138 } |
168 List<Variable> parameters = | 139 List<Variable> parameters = |
169 node.parameters.map(addFunctionParameter).toList(); | 140 node.parameters.map(addFunctionParameter).toList(); |
170 Statement body; | 141 returnContinuation = node.returnContinuation; |
171 if (!node.isEmpty) { | 142 phiTempVar = new Variable(node.element, null); |
172 returnContinuation = node.body.returnContinuation; | 143 Statement body = visit(node.body); |
173 phiTempVar = new Variable(node.element, null); | 144 return new FunctionDefinition(node.element, parameters, body); |
174 body = visit(node.body); | |
175 } | |
176 | |
177 return new FunctionDefinition(node.element, parameters, | |
178 body, node.localConstants, node.defaultParameterValues); | |
179 } | |
180 | |
181 ConstructorDefinition buildConstructor(cps_ir.ConstructorDefinition node) { | |
182 currentElement = node.element; | |
183 thisParameter = node.thisParameter; | |
184 List<Variable> parameters = | |
185 node.parameters.map(addFunctionParameter).toList(); | |
186 List<Initializer> initializers; | |
187 Statement body; | |
188 if (!node.isEmpty) { | |
189 initializers = node.initializers.map(visit).toList(); | |
190 returnContinuation = node.body.returnContinuation; | |
191 | |
192 phiTempVar = new Variable(node.element, null); | |
193 body = visit(node.body); | |
194 } | |
195 | |
196 return new ConstructorDefinition(node.element, parameters, | |
197 body, initializers, node.localConstants, node.defaultParameterValues); | |
198 } | 145 } |
199 | 146 |
200 /// Returns a list of variables corresponding to the arguments to a method | 147 /// Returns a list of variables corresponding to the arguments to a method |
201 /// call or similar construct. | 148 /// call or similar construct. |
202 /// | 149 /// |
203 /// The `readCount` for these variables will be incremented. | 150 /// The `readCount` for these variables will be incremented. |
204 /// | 151 /// |
205 /// The list will be typed as a list of [Expression] to allow inplace updates | 152 /// The list will be typed as a list of [Expression] to allow inplace updates |
206 /// on the list during the rewrite phases. | 153 /// on the list during the rewrite phases. |
207 List<Expression> translateArguments(List<cps_ir.Reference> args) { | 154 List<Expression> translateArguments(List<cps_ir.Reference> args) { |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
327 visitInterceptor(cps_ir.Interceptor node) => unexpectedNode(node); | 274 visitInterceptor(cps_ir.Interceptor node) => unexpectedNode(node); |
328 visitCreateInstance(cps_ir.CreateInstance node) => unexpectedNode(node); | 275 visitCreateInstance(cps_ir.CreateInstance node) => unexpectedNode(node); |
329 visitGetField(cps_ir.GetField node) => unexpectedNode(node); | 276 visitGetField(cps_ir.GetField node) => unexpectedNode(node); |
330 visitCreateBox(cps_ir.CreateBox node) => unexpectedNode(node); | 277 visitCreateBox(cps_ir.CreateBox node) => unexpectedNode(node); |
331 visitCreateInvocationMirror(cps_ir.CreateInvocationMirror node) { | 278 visitCreateInvocationMirror(cps_ir.CreateInvocationMirror node) { |
332 return unexpectedNode(node); | 279 return unexpectedNode(node); |
333 } | 280 } |
334 | 281 |
335 // Executable definitions are not visited directly. They have 'build' | 282 // Executable definitions are not visited directly. They have 'build' |
336 // functions as entry points. | 283 // functions as entry points. |
337 visitFieldDefinition(cps_ir.FieldDefinition node) { | |
338 return unexpectedNode(node); | |
339 } | |
340 visitFunctionDefinition(cps_ir.FunctionDefinition node) { | 284 visitFunctionDefinition(cps_ir.FunctionDefinition node) { |
341 return unexpectedNode(node); | 285 return unexpectedNode(node); |
342 } | 286 } |
343 visitConstructorDefinition(cps_ir.ConstructorDefinition node) { | |
344 return unexpectedNode(node); | |
345 } | |
346 | |
347 Initializer visitFieldInitializer(cps_ir.FieldInitializer node) { | |
348 returnContinuation = node.body.returnContinuation; | |
349 return new FieldInitializer(node.element, visit(node.body.body)); | |
350 } | |
351 | |
352 Initializer visitSuperInitializer(cps_ir.SuperInitializer node) { | |
353 List<Statement> arguments = | |
354 node.arguments.map((cps_ir.Body argument) { | |
355 returnContinuation = argument.returnContinuation; | |
356 return visit(argument.body); | |
357 }).toList(); | |
358 return new SuperInitializer(node.target, node.selector, arguments); | |
359 } | |
360 | 287 |
361 Statement visitLetPrim(cps_ir.LetPrim node) { | 288 Statement visitLetPrim(cps_ir.LetPrim node) { |
362 Variable variable = getVariable(node.primitive); | 289 Variable variable = getVariable(node.primitive); |
363 | 290 |
364 // Don't translate unused primitives. | 291 // Don't translate unused primitives. |
365 if (variable == null) return visit(node.body); | 292 if (variable == null) return visit(node.body); |
366 | 293 |
367 Node definition = visit(node.primitive); | 294 Expression value = visit(node.primitive); |
368 | 295 return Assign.makeStatement(variable, value, visit(node.body)); |
369 // visitPrimitive returns a Statement without successor if it cannot occur | |
370 // in expression context (currently only the case for FunctionDeclarations). | |
371 if (definition is Statement) { | |
372 definition.next = visit(node.body); | |
373 return definition; | |
374 } else { | |
375 return Assign.makeStatement(variable, definition, visit(node.body)); | |
376 } | |
377 } | |
378 | |
379 Statement visitBody(cps_ir.Body node) { | |
380 return visit(node.body); | |
381 } | 296 } |
382 | 297 |
383 Statement visitLetCont(cps_ir.LetCont node) { | 298 Statement visitLetCont(cps_ir.LetCont node) { |
384 // Introduce labels for continuations that need them. | 299 // Introduce labels for continuations that need them. |
385 int safeForInliningLengthOnEntry = safeForInlining.length; | 300 int safeForInliningLengthOnEntry = safeForInlining.length; |
386 for (cps_ir.Continuation continuation in node.continuations) { | 301 for (cps_ir.Continuation continuation in node.continuations) { |
387 if (continuation.hasMultipleUses) { | 302 if (continuation.hasMultipleUses) { |
388 labels[continuation] = new Label(); | 303 labels[continuation] = new Label(); |
389 } else { | 304 } else { |
390 safeForInlining.add(continuation); | 305 safeForInlining.add(continuation); |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
479 () => visit(cont.body) : () => new Break(labels[cont]); | 394 () => visit(cont.body) : () => new Break(labels[cont]); |
480 return buildContinuationAssignment(cont.parameters.single, expression, | 395 return buildContinuationAssignment(cont.parameters.single, expression, |
481 nextBuilder); | 396 nextBuilder); |
482 } | 397 } |
483 } | 398 } |
484 | 399 |
485 Statement visitLetMutable(cps_ir.LetMutable node) { | 400 Statement visitLetMutable(cps_ir.LetMutable node) { |
486 Variable variable = addMutableVariable(node.variable); | 401 Variable variable = addMutableVariable(node.variable); |
487 Expression value = getVariableUse(node.value); | 402 Expression value = getVariableUse(node.value); |
488 Statement body = visit(node.body); | 403 Statement body = visit(node.body); |
489 // If the variable was captured by an inner function in the body, this | |
490 // must be declared here so we assign to a fresh copy of the variable. | |
491 if (variable.isCaptured) { | |
492 return new VariableDeclaration(variable, value, body); | |
493 } | |
494 return Assign.makeStatement(variable, value, body); | 404 return Assign.makeStatement(variable, value, body); |
495 } | 405 } |
496 | 406 |
497 Expression visitGetMutableVariable(cps_ir.GetMutableVariable node) { | 407 Expression visitGetMutableVariable(cps_ir.GetMutableVariable node) { |
498 return getMutableVariableUse(node.variable); | 408 return getMutableVariableUse(node.variable); |
499 } | 409 } |
500 | 410 |
501 Statement visitSetMutableVariable(cps_ir.SetMutableVariable node) { | 411 Statement visitSetMutableVariable(cps_ir.SetMutableVariable node) { |
502 Variable variable = getMutableVariable(node.variable.definition); | 412 Variable variable = getMutableVariable(node.variable.definition); |
503 Expression value = getVariableUse(node.value); | 413 Expression value = getVariableUse(node.value); |
504 return Assign.makeStatement(variable, value, visit(node.body)); | 414 return Assign.makeStatement(variable, value, visit(node.body)); |
505 } | 415 } |
506 | 416 |
507 Statement visitDeclareFunction(cps_ir.DeclareFunction node) { | |
508 Variable variable = addMutableVariable(node.variable); | |
509 FunctionDefinition function = makeSubFunction(node.definition); | |
510 return new FunctionDeclaration(variable, function, visit(node.body)); | |
511 } | |
512 | |
513 Statement visitTypeOperator(cps_ir.TypeOperator node) { | 417 Statement visitTypeOperator(cps_ir.TypeOperator node) { |
514 Expression value = getVariableUse(node.value); | 418 Expression value = getVariableUse(node.value); |
515 List<Expression> typeArgs = translateArguments(node.typeArguments); | 419 List<Expression> typeArgs = translateArguments(node.typeArguments); |
516 Expression concat = | 420 Expression concat = |
517 new TypeOperator(value, node.type, typeArgs, | 421 new TypeOperator(value, node.type, typeArgs, |
518 isTypeTest: node.isTypeTest); | 422 isTypeTest: node.isTypeTest); |
519 return continueWithExpression(node.continuation, concat); | 423 return continueWithExpression(node.continuation, concat); |
520 } | 424 } |
521 | 425 |
522 Statement visitInvokeConstructor(cps_ir.InvokeConstructor node) { | 426 Statement visitInvokeConstructor(cps_ir.InvokeConstructor node) { |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
582 assert(cont.parameters.isEmpty); | 486 assert(cont.parameters.isEmpty); |
583 elseStatement = | 487 elseStatement = |
584 cont.hasExactlyOneUse ? visit(cont.body) : new Break(labels[cont]); | 488 cont.hasExactlyOneUse ? visit(cont.body) : new Break(labels[cont]); |
585 return new If(condition, thenStatement, elseStatement); | 489 return new If(condition, thenStatement, elseStatement); |
586 } | 490 } |
587 | 491 |
588 Expression visitConstant(cps_ir.Constant node) { | 492 Expression visitConstant(cps_ir.Constant node) { |
589 return new Constant(node.expression); | 493 return new Constant(node.expression); |
590 } | 494 } |
591 | 495 |
592 Expression visitReifyTypeVar(cps_ir.ReifyTypeVar node) { | |
593 return new ReifyTypeVar(node.typeVariable); | |
594 } | |
595 | |
596 Expression visitLiteralList(cps_ir.LiteralList node) { | 496 Expression visitLiteralList(cps_ir.LiteralList node) { |
597 return new LiteralList( | 497 return new LiteralList( |
598 node.type, | 498 node.type, |
599 translateArguments(node.values)); | 499 translateArguments(node.values)); |
600 } | 500 } |
601 | 501 |
602 Expression visitLiteralMap(cps_ir.LiteralMap node) { | 502 Expression visitLiteralMap(cps_ir.LiteralMap node) { |
603 return new LiteralMap( | 503 return new LiteralMap( |
604 node.type, | 504 node.type, |
605 new List<LiteralMapEntry>.generate(node.entries.length, (int index) { | 505 new List<LiteralMapEntry>.generate(node.entries.length, (int index) { |
606 return new LiteralMapEntry( | 506 return new LiteralMapEntry( |
607 getVariableUse(node.entries[index].key), | 507 getVariableUse(node.entries[index].key), |
608 getVariableUse(node.entries[index].value)); | 508 getVariableUse(node.entries[index].value)); |
609 }) | 509 }) |
610 ); | 510 ); |
611 } | 511 } |
612 | 512 |
613 FunctionDefinition makeSubFunction(cps_ir.FunctionDefinition function) { | 513 FunctionDefinition makeSubFunction(cps_ir.FunctionDefinition function) { |
614 return createInnerBuilder().buildFunction(function); | 514 return createInnerBuilder().buildFunction(function); |
615 } | 515 } |
616 | 516 |
617 Node visitCreateFunction(cps_ir.CreateFunction node) { | 517 Expression visitCreateFunction(cps_ir.CreateFunction node) { |
618 FunctionDefinition def = makeSubFunction(node.definition); | 518 FunctionDefinition def = makeSubFunction(node.definition); |
619 FunctionType type = node.definition.element.type; | 519 FunctionType type = node.definition.element.type; |
620 bool hasReturnType = !type.returnType.treatAsDynamic; | 520 bool hasReturnType = !type.returnType.treatAsDynamic; |
621 if (hasReturnType) { | 521 return new FunctionExpression(def); |
622 // This function cannot occur in expression context. | |
623 // The successor will be filled in by visitLetPrim. | |
624 return new FunctionDeclaration(getVariable(node), def, null); | |
625 } else { | |
626 return new FunctionExpression(def); | |
627 } | |
628 } | 522 } |
629 | 523 |
630 visitParameter(cps_ir.Parameter node) { | 524 visitParameter(cps_ir.Parameter node) { |
631 // Continuation parameters are not visited (continuations themselves are | 525 // Continuation parameters are not visited (continuations themselves are |
632 // not visited yet). | 526 // not visited yet). |
633 unexpectedNode(node); | 527 unexpectedNode(node); |
634 } | 528 } |
635 | 529 |
636 visitContinuation(cps_ir.Continuation node) { | 530 visitContinuation(cps_ir.Continuation node) { |
637 // Until continuations with multiple uses are supported, they are not | 531 // Until continuations with multiple uses are supported, they are not |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
677 | 571 |
678 Statement visitSetStatic(cps_ir.SetStatic node) { | 572 Statement visitSetStatic(cps_ir.SetStatic node) { |
679 SetStatic setStatic = new SetStatic( | 573 SetStatic setStatic = new SetStatic( |
680 node.element, | 574 node.element, |
681 getVariableUse(node.value), | 575 getVariableUse(node.value), |
682 node.sourceInformation); | 576 node.sourceInformation); |
683 return new ExpressionStatement(setStatic, visit(node.body)); | 577 return new ExpressionStatement(setStatic, visit(node.body)); |
684 } | 578 } |
685 } | 579 } |
686 | 580 |
OLD | NEW |