| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 dart2js.ir_builder; | 5 library dart2js.ir_builder; |
| 6 | 6 |
| 7 import 'ir_nodes.dart' as ir; | 7 import 'ir_nodes.dart' as ir; |
| 8 import '../elements/elements.dart'; | 8 import '../elements/elements.dart'; |
| 9 import '../dart2jslib.dart'; | 9 import '../dart2jslib.dart'; |
| 10 import '../dart_types.dart'; | 10 import '../dart_types.dart'; |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 143 } | 143 } |
| 144 return element.getCompilationUnit().script.file; | 144 return element.getCompilationUnit().script.file; |
| 145 } | 145 } |
| 146 } | 146 } |
| 147 | 147 |
| 148 /** | 148 /** |
| 149 * A tree visitor that builds [IrNodes]. The visit methods add statements using | 149 * A tree visitor that builds [IrNodes]. The visit methods add statements using |
| 150 * to the [builder] and return the last added statement for trees that represent | 150 * to the [builder] and return the last added statement for trees that represent |
| 151 * an expression. | 151 * an expression. |
| 152 */ | 152 */ |
| 153 class IrBuilder extends ResolvedVisitor<ir.Definition> { | 153 class IrBuilder extends ResolvedVisitor<ir.Primitive> { |
| 154 final SourceFile sourceFile; | 154 final SourceFile sourceFile; |
| 155 ir.Continuation returnContinuation = null; | 155 final ir.Continuation returnContinuation; |
| 156 List<ir.Parameter> parameters = <ir.Parameter>[]; | 156 final List<ir.Parameter> parameters; |
| 157 | 157 |
| 158 // The IR builder maintains a context, which is an expression with a hole in | 158 // The IR builder maintains a context, which is an expression with a hole in |
| 159 // it. The hole represents the focus where new expressions can be added. | 159 // it. The hole represents the focus where new expressions can be added. |
| 160 // The context is implemented by 'root' which is the root of the expression | 160 // The context is implemented by 'root' which is the root of the expression |
| 161 // and 'current' which is the expression that immediately contains the hole. | 161 // and 'current' which is the expression that immediately contains the hole. |
| 162 // Not all expressions have a hole (e.g., invocations, which always occur in | 162 // Not all expressions have a hole (e.g., invocations, which always occur in |
| 163 // tail position, do not have a hole). Expressions with a hole have a plug | 163 // tail position, do not have a hole). Expressions with a hole have a plug |
| 164 // method. | 164 // method. |
| 165 // | 165 // |
| 166 // Conceptually, visiting a statement takes a context as input and returns | 166 // Conceptually, visiting a statement takes a context as input and returns |
| 167 // either a new context or else an expression without a hole if all | 167 // either a new context or else an expression without a hole if all |
| 168 // control-flow paths through the statement have exited. An expression | 168 // control-flow paths through the statement have exited. An expression |
| 169 // without a hole is represented by a (root, current) pair where root is the | 169 // without a hole is represented by a (root, current) pair where root is the |
| 170 // expression and current is null. | 170 // expression and current is null. |
| 171 // | 171 // |
| 172 // Conceptually again, visiting an expression takes a context as input and | 172 // Conceptually again, visiting an expression takes a context as input and |
| 173 // returns either a pair of a new context and a definition denoting | 173 // returns either a pair of a new context and a definition denoting |
| 174 // the expression's value, or else an expression without a hole if all | 174 // the expression's value, or else an expression without a hole if all |
| 175 // control-flow paths through the expression have exited. | 175 // control-flow paths through the expression have exited. |
| 176 // | 176 // |
| 177 // We do not pass and return contexts, rather we use the current context | 177 // We do not pass contexts as arguments or return them. Rather we use the |
| 178 // (root, current) as the visitor state and mutate current. Visiting a | 178 // current context (root, current) as the visitor state and mutate current. |
| 179 // statement returns null; visiting an expression optionally returns the | 179 // Visiting a statement returns null; visiting an expression returns the |
| 180 // definition denoting its value. | 180 // primitive denoting its value. |
| 181 |
| 181 ir.Expression root = null; | 182 ir.Expression root = null; |
| 182 ir.Expression current = null; | 183 ir.Expression current = null; |
| 183 | 184 |
| 184 Map<Element, int> variableIndex = <Element, int>{}; | 185 // In SSA terms, join-point continuation parameters are the phis and the |
| 185 List<ir.Definition> assignedVars = <ir.Definition>[]; | 186 // continuation invocation arguments are the corresponding phi inputs. To |
| 187 // support name introduction and renaming for source level variables, we use |
| 188 // nested (delimited) visitors for constructing subparts of the IR that will |
| 189 // need renaming. Each source variable is assigned an index. |
| 190 // |
| 191 // Each nested visitor maintains a list of free variable uses in the body. |
| 192 // These are implemented as a list of parameters, each with their own use |
| 193 // list of references. When the delimited subexpression is plugged into the |
| 194 // surrounding context, the free occurrences can be captured or become free |
| 195 // occurrences in the next outer delimited subexpression. |
| 196 // |
| 197 // Each nested visitor maintains a list that maps indexes of variables |
| 198 // assigned in the delimited subexpression to their reaching definition --- |
| 199 // that is, the definition in effect at the hole in 'current'. These are |
| 200 // used to determine if a join-point continuation needs to be passed |
| 201 // arguments, and what the arguments are. |
| 202 final Map<Element, int> variableIndex; |
| 203 final List<ir.Parameter> freeVars; |
| 204 final List<ir.Primitive> assignedVars; |
| 186 | 205 |
| 206 /// Construct a top-level visitor. |
| 187 IrBuilder(TreeElements elements, Compiler compiler, this.sourceFile) | 207 IrBuilder(TreeElements elements, Compiler compiler, this.sourceFile) |
| 188 : super(elements, compiler); | 208 : returnContinuation = new ir.Continuation.retrn(), |
| 209 parameters = <ir.Parameter>[], |
| 210 variableIndex = <Element, int>{}, |
| 211 freeVars = null, |
| 212 assignedVars = <ir.Primitive>[], |
| 213 super(elements, compiler); |
| 214 |
| 215 /// Construct a delimited visitor. |
| 216 IrBuilder.delimited(IrBuilder parent) |
| 217 : sourceFile = parent.sourceFile, |
| 218 returnContinuation = parent.returnContinuation, |
| 219 parameters = parent.parameters, |
| 220 variableIndex = parent.variableIndex, |
| 221 freeVars = new List<ir.Parameter>.generate( |
| 222 parent.assignedVars.length, (_) => new ir.Parameter(null), |
| 223 growable: false), |
| 224 assignedVars = new List<ir.Primitive>.generate( |
| 225 parent.assignedVars.length, (_) => null), |
| 226 super(parent.elements, parent.compiler); |
| 189 | 227 |
| 190 /** | 228 /** |
| 191 * Builds the [ir.FunctionDefinition] for a function element. In case the | 229 * Builds the [ir.FunctionDefinition] for a function element. In case the |
| 192 * function uses features that cannot be expressed in the IR, this function | 230 * function uses features that cannot be expressed in the IR, this function |
| 193 * returns `null`. | 231 * returns `null`. |
| 194 */ | 232 */ |
| 195 ir.FunctionDefinition buildFunction(FunctionElement functionElement) { | 233 ir.FunctionDefinition buildFunction(FunctionElement functionElement) { |
| 196 return nullIfGiveup(() => buildFunctionInternal(functionElement)); | 234 return nullIfGiveup(() => buildFunctionInternal(functionElement)); |
| 197 } | 235 } |
| 198 | 236 |
| 199 ir.FunctionDefinition buildFunctionInternal(FunctionElement element) { | 237 ir.FunctionDefinition buildFunctionInternal(FunctionElement element) { |
| 200 assert(invariant(element, element.isImplementation)); | 238 assert(invariant(element, element.isImplementation)); |
| 201 ast.FunctionExpression function = element.parseNode(compiler); | 239 ast.FunctionExpression function = element.parseNode(compiler); |
| 202 assert(function != null); | 240 assert(function != null); |
| 203 assert(!function.modifiers.isExternal()); | 241 assert(!function.modifiers.isExternal()); |
| 204 assert(elements[function] != null); | 242 assert(elements[function] != null); |
| 205 | 243 |
| 206 returnContinuation = new ir.Continuation.retrn(); | |
| 207 root = current = null; | 244 root = current = null; |
| 208 | 245 |
| 209 FunctionSignature signature = element.functionSignature; | 246 FunctionSignature signature = element.functionSignature; |
| 210 signature.orderedForEachParameter((parameterElement) { | 247 signature.orderedForEachParameter((parameterElement) { |
| 211 ir.Parameter parameter = new ir.Parameter(parameterElement); | 248 ir.Parameter parameter = new ir.Parameter(parameterElement); |
| 212 parameters.add(parameter); | 249 parameters.add(parameter); |
| 213 variableIndex[parameterElement] = assignedVars.length; | 250 variableIndex[parameterElement] = assignedVars.length; |
| 214 assignedVars.add(parameter); | 251 assignedVars.add(parameter); |
| 215 }); | 252 }); |
| 216 | 253 |
| 217 visit(function.body); | 254 visit(function.body); |
| 218 ensureReturn(function); | 255 ensureReturn(function); |
| 219 return new ir.FunctionDefinition(returnContinuation, parameters, root); | 256 return new ir.FunctionDefinition(returnContinuation, parameters, root); |
| 220 } | 257 } |
| 221 | 258 |
| 222 ConstantSystem get constantSystem => compiler.backend.constantSystem; | 259 ConstantSystem get constantSystem => compiler.backend.constantSystem; |
| 223 | 260 |
| 224 bool get isOpen => root == null || current != null; | 261 bool get isOpen => root == null || current != null; |
| 225 | 262 |
| 226 // Plug an expression into the 'hole' in the context being accumulated. The | 263 // Plug an expression into the 'hole' in the context being accumulated. The |
| 227 // empty context (just a hole) is represented by root (and current) being | 264 // empty context (just a hole) is represented by root (and current) being |
| 228 // null. Since the hole in the current context is filled by this function, | 265 // null. Since the hole in the current context is filled by this function, |
| 229 // the new hole must be in the newly added expression---which becomes the | 266 // the new hole must be in the newly added expression---which becomes the |
| 230 // new value of current. | 267 // new value of current. |
| 231 void add(ir.Expression expr) { | 268 void add(ir.Expression expr) { |
| 269 assert(isOpen); |
| 232 if (root == null) { | 270 if (root == null) { |
| 233 root = current = expr; | 271 root = current = expr; |
| 234 } else if (current != null) { | 272 } else { |
| 235 current = current.plug(expr); | 273 current = current.plug(expr); |
| 236 } | 274 } |
| 237 } | 275 } |
| 238 | 276 |
| 239 /** | 277 /** |
| 240 * Add an explicit `return null` for functions that don't have a return | 278 * Add an explicit `return null` for functions that don't have a return |
| 241 * statement on each branch. This includes functions with an empty body, | 279 * statement on each branch. This includes functions with an empty body, |
| 242 * such as `foo(){ }`. | 280 * such as `foo(){ }`. |
| 243 */ | 281 */ |
| 244 void ensureReturn(ast.FunctionExpression node) { | 282 void ensureReturn(ast.FunctionExpression node) { |
| 245 if (!isOpen) return; | 283 if (!isOpen) return; |
| 246 ir.Constant constant = new ir.Constant(constantSystem.createNull()); | 284 ir.Constant constant = new ir.Constant(constantSystem.createNull()); |
| 247 add(new ir.LetPrim(constant)); | 285 add(new ir.LetPrim(constant)); |
| 248 add(new ir.InvokeContinuation(returnContinuation, constant)); | 286 add(new ir.InvokeContinuation(returnContinuation, [constant])); |
| 249 current = null; | 287 current = null; |
| 250 } | 288 } |
| 251 | 289 |
| 252 ir.Definition visit(ast.Node node) => node.accept(this); | 290 ir.Primitive visit(ast.Node node) => node.accept(this); |
| 253 | 291 |
| 254 // ==== Statements ==== | 292 // ==== Statements ==== |
| 255 // Build(Block(stamements), C) = C' | 293 // Build(Block(stamements), C) = C' |
| 256 // where C' = statements.fold(Build, C) | 294 // where C' = statements.fold(Build, C) |
| 257 ir.Definition visitBlock(ast.Block node) { | 295 ir.Primitive visitBlock(ast.Block node) { |
| 258 assert(isOpen); | 296 assert(isOpen); |
| 259 for (ast.Node n in node.statements.nodes) { | 297 for (ast.Node n in node.statements.nodes) { |
| 260 visit(n); | 298 visit(n); |
| 261 if (!isOpen) return null; | 299 if (!isOpen) return null; |
| 262 } | 300 } |
| 263 return null; | 301 return null; |
| 264 } | 302 } |
| 265 | 303 |
| 266 // Build(EmptyStatement, C) = C | 304 // Build(EmptyStatement, C) = C |
| 267 ir.Definition visitEmptyStatement(ast.EmptyStatement node) { | 305 ir.Primitive visitEmptyStatement(ast.EmptyStatement node) { |
| 268 assert(isOpen); | 306 assert(isOpen); |
| 269 return null; | 307 return null; |
| 270 } | 308 } |
| 271 | 309 |
| 272 // Build(ExpressionStatement(e), C) = C' | 310 // Build(ExpressionStatement(e), C) = C' |
| 273 // where (C', _) = Build(e, C) | 311 // where (C', _) = Build(e, C) |
| 274 ir.Definition visitExpressionStatement(ast.ExpressionStatement node) { | 312 ir.Primitive visitExpressionStatement(ast.ExpressionStatement node) { |
| 275 assert(isOpen); | 313 assert(isOpen); |
| 276 visit(node.expression); | 314 visit(node.expression); |
| 277 return null; | 315 return null; |
| 278 } | 316 } |
| 279 | 317 |
| 280 ir.Definition visitIf(ast.If node) { | 318 ir.Primitive visitIf(ast.If node) { |
| 281 assert(isOpen); | 319 assert(isOpen); |
| 282 return giveup(); | 320 ir.Primitive condition = visit(node.condition); |
| 321 |
| 322 // The then and else parts are delimited. |
| 323 IrBuilder thenBuilder = new IrBuilder.delimited(this); |
| 324 thenBuilder.visit(node.thenPart); |
| 325 IrBuilder elseBuilder = new IrBuilder.delimited(this); |
| 326 if (node.hasElsePart) elseBuilder.visit(node.elsePart); |
| 327 |
| 328 // The free variables in the then and else parts are uses of definitions |
| 329 // from an outer builder. Capture them or propagate them outward. The |
| 330 // assigned variables in the then and else parts are arguments to the join |
| 331 // point continuation if any. |
| 332 |
| 333 // FreeVars is initially the length of assignedVars of the parent, and it |
| 334 // does not grow. AssignedVars can grow. |
| 335 assert(assignedVars.length == thenBuilder.freeVars.length); |
| 336 assert(assignedVars.length == elseBuilder.freeVars.length); |
| 337 assert(assignedVars.length <= thenBuilder.assignedVars.length); |
| 338 assert(assignedVars.length <= elseBuilder.assignedVars.length); |
| 339 List<ir.Parameter> parameters = <ir.Parameter>[]; |
| 340 List<ir.Primitive> thenArguments = <ir.Primitive>[]; |
| 341 List<ir.Primitive> elseArguments = <ir.Primitive>[]; |
| 342 for (int i = 0; i < assignedVars.length; ++i) { |
| 343 // These are the last assignments, if any, in the then and else |
| 344 // continuations respectively (if they can reach the join point). If a |
| 345 // variable is assigned in either branch reaching the join point, it has |
| 346 // different values that must be passed as an argument to the join point |
| 347 // continuation. |
| 348 ir.Definition thenAssignment = |
| 349 thenBuilder.isOpen ? thenBuilder.assignedVars[i] : null; |
| 350 ir.Definition elseAssignment = |
| 351 elseBuilder.isOpen ? elseBuilder.assignedVars[i] : null; |
| 352 if (thenAssignment != null || elseAssignment != null) { |
| 353 // In the case that not both then and else parts can reach the join |
| 354 // point, there will still be a join-point continuation possibly with |
| 355 // arguments passed to it. Such singly-used continuations should be |
| 356 // eliminated by shrinking conversions (because they can arise |
| 357 // otherwise as the result of optimization). |
| 358 ir.Parameter parameter = new ir.Parameter(null); |
| 359 parameters.add(parameter); |
| 360 thenArguments.add(thenAssignment == null |
| 361 ? thenBuilder.freeVars[i] |
| 362 : thenAssignment); |
| 363 elseArguments.add(elseAssignment == null |
| 364 ? elseBuilder.freeVars[i] |
| 365 : elseAssignment); |
| 366 } |
| 367 } |
| 368 |
| 369 // Create a then and else continuations and a join continuation if |
| 370 // necessary. Jump to the join continuation from the exits of the then |
| 371 // and else continuations. |
| 372 ir.Continuation joinContinuation; |
| 373 ir.Continuation thenContinuation = new ir.Continuation([]); |
| 374 ir.Continuation elseContinuation = new ir.Continuation([]); |
| 375 if (thenBuilder.isOpen || elseBuilder.isOpen) { |
| 376 joinContinuation = new ir.Continuation(parameters); |
| 377 if (thenBuilder.isOpen) { |
| 378 thenBuilder.add( |
| 379 new ir.InvokeContinuation(joinContinuation, thenArguments)); |
| 380 } |
| 381 if (elseBuilder.isOpen) { |
| 382 elseBuilder.add( |
| 383 new ir.InvokeContinuation(joinContinuation, elseArguments)); |
| 384 } |
| 385 } |
| 386 thenContinuation.body = thenBuilder.root; |
| 387 elseContinuation.body = elseBuilder.root; |
| 388 |
| 389 // Capture free occurrences in the then and else bodies. This is done |
| 390 // after creating invocations of the join continuation so free join |
| 391 // continuation arguments are properly captured. |
| 392 // |
| 393 // Also add join continuation parameters as assignments for the join body. |
| 394 // This is done last because the assigned variables are updated in place. |
| 395 int parameterIndex = 0; |
| 396 for (int i = 0; i < assignedVars.length; ++i) { |
| 397 // This is the definition that reaches the then and else continuations. |
| 398 // All free uses in either continuation are uses of this definition. |
| 399 ir.Definition reachingDefinition = |
| 400 assignedVars[i] == null ? freeVars[i] : assignedVars[i]; |
| 401 reachingDefinition |
| 402 ..substituteFor(thenBuilder.freeVars[i]) |
| 403 ..substituteFor(elseBuilder.freeVars[i]); |
| 404 |
| 405 if ((thenBuilder.isOpen && thenBuilder.assignedVars[i] != null) || |
| 406 (elseBuilder.isOpen && elseBuilder.assignedVars[i] != null)) { |
| 407 assignedVars[i] = parameters[parameterIndex++]; |
| 408 } |
| 409 } |
| 410 |
| 411 ir.Expression branch = |
| 412 new ir.LetCont(thenContinuation, |
| 413 new ir.LetCont(elseContinuation, |
| 414 new ir.Branch(new ir.IsTrue(condition), |
| 415 thenContinuation, |
| 416 elseContinuation))); |
| 417 if (joinContinuation == null) { |
| 418 add(branch); |
| 419 current = null; |
| 420 } else { |
| 421 add(new ir.LetCont(joinContinuation, branch)); |
| 422 } |
| 423 return null; |
| 283 } | 424 } |
| 284 | 425 |
| 285 ir.Definition visitVariableDefinitions(ast.VariableDefinitions node) { | 426 ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) { |
| 286 assert(isOpen); | 427 assert(isOpen); |
| 287 for (ast.Node definition in node.definitions.nodes) { | 428 for (ast.Node definition in node.definitions.nodes) { |
| 288 Element element = elements[definition]; | 429 Element element = elements[definition]; |
| 289 // Definitions are either SendSets if there is an initializer, or | 430 // Definitions are either SendSets if there is an initializer, or |
| 290 // Identifiers if there is no initializer. | 431 // Identifiers if there is no initializer. |
| 291 if (definition is ast.SendSet) { | 432 if (definition is ast.SendSet) { |
| 292 assert(!definition.arguments.isEmpty); | 433 assert(!definition.arguments.isEmpty); |
| 293 assert(definition.arguments.tail.isEmpty); | 434 assert(definition.arguments.tail.isEmpty); |
| 294 ir.Definition initialValue = visit(definition.arguments.head); | 435 ir.Primitive initialValue = visit(definition.arguments.head); |
| 295 // Do not continue adding instructions if the initializer throws. | |
| 296 if (!isOpen) return null; | |
| 297 variableIndex[element] = assignedVars.length; | 436 variableIndex[element] = assignedVars.length; |
| 298 assignedVars.add(initialValue); | 437 assignedVars.add(initialValue); |
| 299 } else { | 438 } else { |
| 300 assert(definition is ast.Identifier); | 439 assert(definition is ast.Identifier); |
| 301 // The initial value is null. | 440 // The initial value is null. |
| 302 // TODO(kmillikin): Consider pooling constants. | 441 // TODO(kmillikin): Consider pooling constants. |
| 303 ir.Constant constant = new ir.Constant(constantSystem.createNull()); | 442 ir.Constant constant = new ir.Constant(constantSystem.createNull()); |
| 304 add(new ir.LetPrim(constant)); | 443 add(new ir.LetPrim(constant)); |
| 305 variableIndex[element] = assignedVars.length; | 444 variableIndex[element] = assignedVars.length; |
| 306 assignedVars.add(constant); | 445 assignedVars.add(constant); |
| 307 } | 446 } |
| 308 } | 447 } |
| 309 return null; | 448 return null; |
| 310 } | 449 } |
| 311 | 450 |
| 312 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] | 451 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] |
| 313 // where (C', x) = Build(e, C) | 452 // where (C', x) = Build(e, C) |
| 314 // | 453 // |
| 315 // Return without a subexpression is translated as if it were return null. | 454 // Return without a subexpression is translated as if it were return null. |
| 316 ir.Definition visitReturn(ast.Return node) { | 455 ir.Primitive visitReturn(ast.Return node) { |
| 317 assert(isOpen); | 456 assert(isOpen); |
| 318 // TODO(lry): support native returns. | 457 // TODO(lry): support native returns. |
| 319 if (node.beginToken.value == 'native') return giveup(); | 458 if (node.beginToken.value == 'native') return giveup(); |
| 320 ir.Definition value; | 459 ir.Primitive value; |
| 321 if (node.expression == null) { | 460 if (node.expression == null) { |
| 322 value = new ir.Constant(constantSystem.createNull()); | 461 value = new ir.Constant(constantSystem.createNull()); |
| 323 add(new ir.LetPrim(value)); | 462 add(new ir.LetPrim(value)); |
| 324 } else { | 463 } else { |
| 325 value = visit(node.expression); | 464 value = visit(node.expression); |
| 326 if (!isOpen) return null; | |
| 327 } | 465 } |
| 328 add(new ir.InvokeContinuation(returnContinuation, value)); | 466 add(new ir.InvokeContinuation(returnContinuation, [value])); |
| 329 current = null; | 467 current = null; |
| 330 return null; | 468 return null; |
| 331 } | 469 } |
| 332 | 470 |
| 333 // ==== Expressions ==== | 471 // ==== Expressions ==== |
| 334 // For all simple literals: | 472 // For all simple literals: |
| 335 // Build(Literal(c), C) = C[let val x = Constant(c) in [], x] | 473 // Build(Literal(c), C) = C[let val x = Constant(c) in [], x] |
| 336 ir.Definition visitLiteralBool(ast.LiteralBool node) { | 474 ir.Primitive visitLiteralBool(ast.LiteralBool node) { |
| 337 assert(isOpen); | 475 assert(isOpen); |
| 338 ir.Constant constant = | 476 ir.Constant constant = |
| 339 new ir.Constant(constantSystem.createBool(node.value)); | 477 new ir.Constant(constantSystem.createBool(node.value)); |
| 340 add(new ir.LetPrim(constant)); | 478 add(new ir.LetPrim(constant)); |
| 341 return constant; | 479 return constant; |
| 342 } | 480 } |
| 343 | 481 |
| 344 ir.Definition visitLiteralDouble(ast.LiteralDouble node) { | 482 ir.Primitive visitLiteralDouble(ast.LiteralDouble node) { |
| 345 assert(isOpen); | 483 assert(isOpen); |
| 346 ir.Constant constant = | 484 ir.Constant constant = |
| 347 new ir.Constant(constantSystem.createDouble(node.value)); | 485 new ir.Constant(constantSystem.createDouble(node.value)); |
| 348 add(new ir.LetPrim(constant)); | 486 add(new ir.LetPrim(constant)); |
| 349 return constant; | 487 return constant; |
| 350 } | 488 } |
| 351 | 489 |
| 352 ir.Definition visitLiteralInt(ast.LiteralInt node) { | 490 ir.Primitive visitLiteralInt(ast.LiteralInt node) { |
| 353 assert(isOpen); | 491 assert(isOpen); |
| 354 ir.Constant constant = | 492 ir.Constant constant = |
| 355 new ir.Constant(constantSystem.createInt(node.value)); | 493 new ir.Constant(constantSystem.createInt(node.value)); |
| 356 add(new ir.LetPrim(constant)); | 494 add(new ir.LetPrim(constant)); |
| 357 return constant; | 495 return constant; |
| 358 } | 496 } |
| 359 | 497 |
| 360 | 498 |
| 361 ir.Definition visitLiteralNull(ast.LiteralNull node) { | 499 ir.Primitive visitLiteralNull(ast.LiteralNull node) { |
| 362 assert(isOpen); | 500 assert(isOpen); |
| 363 ir.Constant constant = new ir.Constant(constantSystem.createNull()); | 501 ir.Constant constant = new ir.Constant(constantSystem.createNull()); |
| 364 add(new ir.LetPrim(constant)); | 502 add(new ir.LetPrim(constant)); |
| 365 return constant; | 503 return constant; |
| 366 } | 504 } |
| 367 | 505 |
| 368 // TODO(kmillikin): other literals. Strings require quoting and escaping | 506 // TODO(kmillikin): other literals. Strings require quoting and escaping |
| 369 // in the Dart backend. | 507 // in the Dart backend. |
| 370 // LiteralString | 508 // LiteralString |
| 371 // LiteralList | 509 // LiteralList |
| 372 // LiteralMap | 510 // LiteralMap |
| 373 // LiteralMapEntry | 511 // LiteralMapEntry |
| 374 // LiteralSymbol | 512 // LiteralSymbol |
| 375 | 513 |
| 376 ir.Definition visitParenthesizedExpression( | 514 ir.Primitive visitParenthesizedExpression( |
| 377 ast.ParenthesizedExpression node) { | 515 ast.ParenthesizedExpression node) { |
| 516 assert(isOpen); |
| 378 return visit(node.expression); | 517 return visit(node.expression); |
| 379 } | 518 } |
| 380 | 519 |
| 381 // ==== Sends ==== | 520 // ==== Sends ==== |
| 382 ir.Definition visitAssert(ast.Send node) { | 521 ir.Primitive visitAssert(ast.Send node) { |
| 522 assert(isOpen); |
| 383 return giveup(); | 523 return giveup(); |
| 384 } | 524 } |
| 385 | 525 |
| 386 ir.Definition visitClosureSend(ast.Send node) { | 526 ir.Primitive visitClosureSend(ast.Send node) { |
| 527 assert(isOpen); |
| 387 return giveup(); | 528 return giveup(); |
| 388 } | 529 } |
| 389 | 530 |
| 390 ir.Definition visitDynamicSend(ast.Send node) { | 531 ir.Primitive visitDynamicSend(ast.Send node) { |
| 532 assert(isOpen); |
| 391 return giveup(); | 533 return giveup(); |
| 392 } | 534 } |
| 393 | 535 |
| 394 ir.Definition visitGetterSend(ast.Send node) { | 536 ir.Primitive visitGetterSend(ast.Send node) { |
| 537 assert(isOpen); |
| 395 Element element = elements[node]; | 538 Element element = elements[node]; |
| 396 if (!Elements.isLocal(element)) return giveup(); | 539 if (!Elements.isLocal(element)) return giveup(); |
| 397 return assignedVars[variableIndex[element]]; | 540 int index = variableIndex[element]; |
| 541 ir.Primitive value = assignedVars[index]; |
| 542 return value == null ? freeVars[index] : value; |
| 398 } | 543 } |
| 399 | 544 |
| 400 ir.Definition visitOperatorSend(ast.Send node) { | 545 ir.Primitive visitOperatorSend(ast.Send node) { |
| 546 assert(isOpen); |
| 401 return giveup(); | 547 return giveup(); |
| 402 } | 548 } |
| 403 | 549 |
| 404 // Build(StaticSend(f, arguments), C) = C[C'[InvokeStatic(f, xs)]] | 550 // Build(StaticSend(f, arguments), C) = C[C'[InvokeStatic(f, xs)]] |
| 405 // where (C', xs) = arguments.fold(Build, C) | 551 // where (C', xs) = arguments.fold(Build, C) |
| 406 ir.Definition visitStaticSend(ast.Send node) { | 552 ir.Primitive visitStaticSend(ast.Send node) { |
| 407 assert(isOpen); | 553 assert(isOpen); |
| 408 Element element = elements[node]; | 554 Element element = elements[node]; |
| 409 // TODO(lry): support static fields. (separate IR instruction?) | 555 // TODO(lry): support static fields. (separate IR instruction?) |
| 410 if (element.isField() || element.isGetter()) return giveup(); | 556 if (element.isField() || element.isGetter()) return giveup(); |
| 411 // TODO(kmillikin): support static setters. | 557 // TODO(kmillikin): support static setters. |
| 412 if (element.isSetter()) return giveup(); | 558 if (element.isSetter()) return giveup(); |
| 413 // TODO(lry): support constructors / factory calls. | 559 // TODO(lry): support constructors / factory calls. |
| 414 if (element.isConstructor()) return giveup(); | 560 if (element.isConstructor()) return giveup(); |
| 415 // TODO(lry): support foreign functions. | 561 // TODO(lry): support foreign functions. |
| 416 if (element.isForeign(compiler)) return giveup(); | 562 if (element.isForeign(compiler)) return giveup(); |
| 417 // TODO(lry): for elements that could not be resolved emit code to throw a | 563 // TODO(lry): for elements that could not be resolved emit code to throw a |
| 418 // [NoSuchMethodError]. | 564 // [NoSuchMethodError]. |
| 419 if (element.isErroneous()) return giveup(); | 565 if (element.isErroneous()) return giveup(); |
| 420 // TODO(lry): generate IR for object identicality. | 566 // TODO(lry): generate IR for object identicality. |
| 421 if (element == compiler.identicalFunction) giveup(); | 567 if (element == compiler.identicalFunction) giveup(); |
| 422 | 568 |
| 423 Selector selector = elements.getSelector(node); | 569 Selector selector = elements.getSelector(node); |
| 424 // TODO(lry): support named arguments | 570 // TODO(lry): support named arguments |
| 425 if (selector.namedArgumentCount != 0) return giveup(); | 571 if (selector.namedArgumentCount != 0) return giveup(); |
| 426 | 572 |
| 427 // TODO(kmillikin): support a receiver: A.m(). | 573 // TODO(kmillikin): support a receiver: A.m(). |
| 428 if (node.receiver != null) return giveup(); | 574 if (node.receiver != null) return giveup(); |
| 429 | 575 |
| 430 List arguments = []; | 576 List arguments = []; |
| 431 // TODO(lry): support default arguments, need support for locals. | 577 // TODO(lry): support default arguments, need support for locals. |
| 432 bool succeeded = selector.addArgumentsToList( | 578 bool succeeded = selector.addArgumentsToList( |
| 433 node.arguments, arguments, element.implementation, | 579 node.arguments, arguments, element.implementation, visit, |
| 434 // Guard against visiting arguments after an argument expression throws. | 580 (node) => giveup(), compiler); |
| 435 (node) => isOpen ? visit(node) : null, | |
| 436 (node) => giveup(), | |
| 437 compiler); | |
| 438 if (!succeeded) { | 581 if (!succeeded) { |
| 439 // TODO(lry): generate code to throw a [WrongArgumentCountError]. | 582 // TODO(lry): generate code to throw a [WrongArgumentCountError]. |
| 440 return giveup(); | 583 return giveup(); |
| 441 } | 584 } |
| 442 if (!isOpen) return null; | |
| 443 ir.Parameter v = new ir.Parameter(null); | 585 ir.Parameter v = new ir.Parameter(null); |
| 444 ir.Continuation k = new ir.Continuation([v]); | 586 ir.Continuation k = new ir.Continuation([v]); |
| 445 ir.Expression invoke = | 587 ir.Expression invoke = |
| 446 new ir.InvokeStatic(element, selector, k, arguments); | 588 new ir.InvokeStatic(element, selector, k, arguments); |
| 447 add(new ir.LetCont(k, invoke)); | 589 add(new ir.LetCont(k, invoke)); |
| 448 return v; | 590 return v; |
| 449 } | 591 } |
| 450 | 592 |
| 451 ir.Definition visitSuperSend(ast.Send node) { | 593 ir.Primitive visitSuperSend(ast.Send node) { |
| 594 assert(isOpen); |
| 452 return giveup(); | 595 return giveup(); |
| 453 } | 596 } |
| 454 | 597 |
| 455 ir.Definition visitTypeReferenceSend(ast.Send node) { | 598 ir.Primitive visitTypeReferenceSend(ast.Send node) { |
| 599 assert(isOpen); |
| 456 return giveup(); | 600 return giveup(); |
| 457 } | 601 } |
| 458 | 602 |
| 459 ir.Definition visitSendSet(ast.SendSet node) { | 603 ir.Primitive visitSendSet(ast.SendSet node) { |
| 604 assert(isOpen); |
| 460 Element element = elements[node]; | 605 Element element = elements[node]; |
| 461 if (!Elements.isLocal(element)) return giveup(); | 606 if (!Elements.isLocal(element)) return giveup(); |
| 462 if (node.assignmentOperator.source != '=') return giveup(); | 607 if (node.assignmentOperator.source != '=') return giveup(); |
| 463 // Exactly one argument expected for a simple assignment. | 608 // Exactly one argument expected for a simple assignment. |
| 464 assert(!node.arguments.isEmpty); | 609 assert(!node.arguments.isEmpty); |
| 465 assert(node.arguments.tail.isEmpty); | 610 assert(node.arguments.tail.isEmpty); |
| 466 ir.Definition result = visit(node.arguments.head); | 611 ir.Primitive result = visit(node.arguments.head); |
| 467 assignedVars[variableIndex[element]] = result; | 612 assignedVars[variableIndex[element]] = result; |
| 468 return result; | 613 return result; |
| 469 } | 614 } |
| 470 | 615 |
| 471 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; | 616 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; |
| 472 | 617 |
| 473 ir.Definition giveup() => throw ABORT_IRNODE_BUILDER; | 618 ir.Primitive giveup() => throw ABORT_IRNODE_BUILDER; |
| 474 | 619 |
| 475 ir.FunctionDefinition nullIfGiveup(ir.FunctionDefinition action()) { | 620 ir.FunctionDefinition nullIfGiveup(ir.FunctionDefinition action()) { |
| 476 try { | 621 try { |
| 477 return action(); | 622 return action(); |
| 478 } catch(e) { | 623 } catch(e) { |
| 479 if (e == ABORT_IRNODE_BUILDER) return null; | 624 if (e == ABORT_IRNODE_BUILDER) return null; |
| 480 rethrow; | 625 rethrow; |
| 481 } | 626 } |
| 482 } | 627 } |
| 483 | 628 |
| 484 void internalError(String reason, {ast.Node node}) { | 629 void internalError(String reason, {ast.Node node}) { |
| 485 giveup(); | 630 giveup(); |
| 486 } | 631 } |
| 487 } | 632 } |
| 488 | 633 |
| 489 // Verify that types are ones that can be reconstructed by the type emitter. | 634 // Verify that types are ones that can be reconstructed by the type emitter. |
| 490 class SupportedTypeVerifier extends DartTypeVisitor<bool, Null> { | 635 class SupportedTypeVerifier extends DartTypeVisitor<bool, Null> { |
| 491 bool visit(DartType type, Null _) => type.accept(this, null); | 636 bool visit(DartType type, Null _) => type.accept(this, null); |
| 492 | 637 |
| 493 bool visitType(DartType type, Null _) => false; | 638 bool visitType(DartType type, Null _) => false; |
| 494 | 639 |
| 495 bool visitVoidType(VoidType type, Null _) => true; | 640 bool visitVoidType(VoidType type, Null _) => true; |
| 496 | 641 |
| 497 // Currently, InterfaceType and TypedefType are supported so long as they | 642 // Currently, InterfaceType and TypedefType are supported so long as they |
| 498 // do not have type parameters. They are subclasses of GenericType. | 643 // do not have type parameters. They are subclasses of GenericType. |
| 499 bool visitGenericType(GenericType type, Null _) => !type.isGeneric; | 644 bool visitGenericType(GenericType type, Null _) => !type.isGeneric; |
| 500 } | 645 } |
| OLD | NEW |