Chromium Code Reviews| 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 '../constants/expressions.dart'; | 7 import '../constants/expressions.dart'; |
| 8 import '../constants/values.dart' show PrimitiveConstantValue; | 8 import '../constants/values.dart' show PrimitiveConstantValue; |
| 9 import '../dart_backend/dart_backend.dart' show DartBackend; | 9 import '../dart_backend/dart_backend.dart' show DartBackend; |
| 10 import '../dart_types.dart'; | 10 import '../dart_types.dart'; |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 208 final List<ir.InvokeContinuation> _invocations = <ir.InvokeContinuation>[]; | 208 final List<ir.InvokeContinuation> _invocations = <ir.InvokeContinuation>[]; |
| 209 final List<Environment> _environments = <Environment>[]; | 209 final List<Environment> _environments = <Environment>[]; |
| 210 | 210 |
| 211 JumpCollector(this.target); | 211 JumpCollector(this.target); |
| 212 | 212 |
| 213 bool get isEmpty => _invocations.isEmpty; | 213 bool get isEmpty => _invocations.isEmpty; |
| 214 int get length => _invocations.length; | 214 int get length => _invocations.length; |
| 215 List<ir.InvokeContinuation> get invocations => _invocations; | 215 List<ir.InvokeContinuation> get invocations => _invocations; |
| 216 List<Environment> get environments => _environments; | 216 List<Environment> get environments => _environments; |
| 217 | 217 |
| 218 void addJump(IrBuilderVisitor builder) { | 218 void addJump(IrBuilder builder) { |
| 219 ir.InvokeContinuation invoke = new ir.InvokeContinuation.uninitialized(); | 219 ir.InvokeContinuation invoke = new ir.InvokeContinuation.uninitialized(); |
| 220 builder.add(invoke); | 220 builder.add(invoke); |
| 221 _invocations.add(invoke); | 221 _invocations.add(invoke); |
| 222 _environments.add(builder.environment); | 222 _environments.add(builder.environment); |
| 223 builder._current = null; | 223 builder._current = null; |
| 224 // TODO(kmillikin): Can we set builder.environment to null to make it | 224 // TODO(kmillikin): Can we set builder.environment to null to make it |
| 225 // less likely to mutate it? | 225 // less likely to mutate it? |
| 226 } | 226 } |
| 227 } | 227 } |
| 228 | 228 |
| 229 /// Mixin that provided encapsulated access to nested builders. | |
| 230 class IrBuilderMixin { | |
| 231 IrBuilder _irBuilder; | |
| 232 | |
| 233 /// Execute [f] with [builder] as the current builder. | |
| 234 withBuilder(IrBuilder builder, f()) { | |
| 235 assert(builder != null); | |
| 236 IrBuilder prev = _irBuilder; | |
| 237 _irBuilder = builder; | |
| 238 var result = f(); | |
| 239 _irBuilder = prev; | |
| 240 return result; | |
| 241 } | |
| 242 | |
| 243 /// The current builder. | |
| 244 IrBuilder get irBuilder { | |
| 245 assert(_irBuilder != null); | |
| 246 return _irBuilder; | |
| 247 } | |
| 248 } | |
| 249 | |
| 250 | |
| 251 /// Shared state between nested builders. | |
| 252 class IrBuilderSharedState { | |
| 253 final ConstantSystem constantSystem; | |
| 254 | |
| 255 /// A stack of collectors for breaks. | |
| 256 final List<JumpCollector> breakCollectors = <JumpCollector>[]; | |
| 257 | |
| 258 /// A stack of collectors for continues. | |
| 259 final List<JumpCollector> continueCollectors = <JumpCollector>[]; | |
| 260 | |
| 261 final List<ConstDeclaration> localConstants = <ConstDeclaration>[]; | |
| 262 | |
| 263 final Iterable<Entity> closureLocals; | |
| 264 | |
| 265 final FunctionElement currentFunction; | |
| 266 | |
| 267 final ir.Continuation returnContinuation = new ir.Continuation.retrn(); | |
| 268 | |
| 269 IrBuilderSharedState(this.constantSystem, | |
| 270 this.currentFunction, | |
| 271 this.closureLocals); | |
| 272 } | |
| 273 | |
| 229 /// A factory for building the cps IR. | 274 /// A factory for building the cps IR. |
| 230 class IrBuilder { | 275 class IrBuilder { |
| 231 // TODO(johnniwinther): Make these field final and remove the default values | 276 // TODO(johnniwinther): Make these field final and remove the default values |
| 232 // when [IrBuilder] is a property of [IrBuilderVisitor] instead of a mixin. | 277 // when [IrBuilder] is a property of [IrBuilderVisitor] instead of a mixin. |
| 233 ConstantSystem constantSystem = DART_CONSTANT_SYSTEM; | |
| 234 | 278 |
| 235 ir.Continuation returnContinuation = new ir.Continuation.retrn(); | 279 final List<ir.Parameter> _parameters = <ir.Parameter>[]; |
| 236 | 280 |
| 237 List<ir.Parameter> _parameters = <ir.Parameter>[]; | 281 final IrBuilderSharedState state; |
| 238 | 282 |
| 239 /// A map from variable indexes to their values. | 283 /// A map from variable indexes to their values. |
| 240 Environment environment = new Environment.empty(); | 284 Environment environment; |
| 241 | |
| 242 List<ConstDeclaration> _localConstants = <ConstDeclaration>[]; | |
| 243 | 285 |
| 244 // The IR builder maintains a context, which is an expression with a hole in | 286 // The IR builder maintains a context, which is an expression with a hole in |
| 245 // it. The hole represents the focus where new expressions can be added. | 287 // it. The hole represents the focus where new expressions can be added. |
| 246 // The context is implemented by 'root' which is the root of the expression | 288 // The context is implemented by 'root' which is the root of the expression |
| 247 // and 'current' which is the expression that immediately contains the hole. | 289 // and 'current' which is the expression that immediately contains the hole. |
| 248 // Not all expressions have a hole (e.g., invocations, which always occur in | 290 // Not all expressions have a hole (e.g., invocations, which always occur in |
| 249 // tail position, do not have a hole). Expressions with a hole have a plug | 291 // tail position, do not have a hole). Expressions with a hole have a plug |
| 250 // method. | 292 // method. |
| 251 // | 293 // |
| 252 // Conceptually, visiting a statement takes a context as input and returns | 294 // Conceptually, visiting a statement takes a context as input and returns |
| 253 // either a new context or else an expression without a hole if all | 295 // either a new context or else an expression without a hole if all |
| 254 // control-flow paths through the statement have exited. An expression | 296 // control-flow paths through the statement have exited. An expression |
| 255 // without a hole is represented by a (root, current) pair where root is the | 297 // without a hole is represented by a (root, current) pair where root is the |
| 256 // expression and current is null. | 298 // expression and current is null. |
| 257 // | 299 // |
| 258 // Conceptually again, visiting an expression takes a context as input and | 300 // Conceptually again, visiting an expression takes a context as input and |
| 259 // returns either a pair of a new context and a definition denoting | 301 // returns either a pair of a new context and a definition denoting |
| 260 // the expression's value, or else an expression without a hole if all | 302 // the expression's value, or else an expression without a hole if all |
| 261 // control-flow paths through the expression have exited. | 303 // control-flow paths through the expression have exited. |
| 262 // | 304 // |
| 263 // We do not pass contexts as arguments or return them. Rather we use the | 305 // We do not pass contexts as arguments or return them. Rather we use the |
| 264 // current context (root, current) as the visitor state and mutate current. | 306 // current context (root, current) as the visitor state and mutate current. |
| 265 // Visiting a statement returns null; visiting an expression returns the | 307 // Visiting a statement returns null; visiting an expression returns the |
| 266 // primitive denoting its value. | 308 // primitive denoting its value. |
| 267 | 309 |
| 268 ir.Expression _root = null; | 310 ir.Expression _root = null; |
| 269 ir.Expression _current = null; | 311 ir.Expression _current = null; |
| 270 | 312 |
| 313 IrBuilder(ConstantSystem constantSystem, | |
| 314 FunctionElement currentFunction, | |
| 315 Iterable<Entity> closureLocals) | |
| 316 : this.state = new IrBuilderSharedState( | |
| 317 constantSystem, currentFunction, closureLocals), | |
| 318 this.environment = new Environment.empty(); | |
| 319 | |
| 320 /// Construct a delimited visitor for visiting a subtree. | |
| 321 /// | |
| 322 /// The delimited visitor has its own compile-time environment mapping | |
| 323 /// local variables to their values, which is initially a copy of the parent | |
| 324 /// environment. It has its own context for building an IR expression, so | |
| 325 /// the built expression is not plugged into the parent's context. | |
| 326 IrBuilder.delimited(IrBuilder parent) | |
| 327 : this.state = parent.state, | |
| 328 this.environment = new Environment.from(parent.environment); | |
| 329 | |
| 330 /// Construct a visitor for a recursive continuation. | |
| 331 /// | |
| 332 /// The recursive continuation builder has fresh parameters (i.e. SSA phis) | |
| 333 /// for all the local variables in the parent, because the invocation sites | |
| 334 /// of the continuation are not all known when the builder is created. The | |
| 335 /// recursive invocations will be passed values for all the local variables, | |
| 336 /// which may be eliminated later if they are redundant---if they take on | |
| 337 /// the same value at all invocation sites. | |
| 338 IrBuilder.recursive(IrBuilder parent) | |
| 339 : this.state = parent.state, | |
| 340 this.environment = new Environment.empty() { | |
| 341 parent.environment.index2variable.forEach(createParameter); | |
| 342 } | |
| 343 | |
| 344 | |
| 271 bool get isOpen => _root == null || _current != null; | 345 bool get isOpen => _root == null || _current != null; |
| 272 | 346 |
| 273 /// Create a parameter for [parameterElement] and add it to the current | 347 /// Create a parameter for [parameterElement] and add it to the current |
| 274 /// environment. If [isClosureVariable] marks whether [parameterElement] is | 348 /// environment. If [isClosureVariable] marks whether [parameterElement] is |
| 275 /// accessed from an inner function. | 349 /// accessed from an inner function. |
| 276 void createParameter(LocalElement parameterElement, | 350 void createParameter(LocalElement parameterElement, |
| 277 {bool isClosureVariable: false}) { | 351 {bool isClosureVariable: false}) { |
| 278 ir.Parameter parameter = new ir.Parameter(parameterElement); | 352 ir.Parameter parameter = new ir.Parameter(parameterElement); |
| 279 _parameters.add(parameter); | 353 _parameters.add(parameter); |
| 280 if (isClosureVariable) { | 354 if (isClosureVariable) { |
| 281 add(new ir.SetClosureVariable(parameterElement, parameter)); | 355 add(new ir.SetClosureVariable(parameterElement, parameter)); |
| 282 } else { | 356 } else { |
| 283 environment.extend(parameterElement, parameter); | 357 environment.extend(parameterElement, parameter); |
| 284 } | 358 } |
| 285 } | 359 } |
| 286 | 360 |
| 287 void declareLocalConstant(LocalVariableElement variableElement, | 361 void declareLocalConstant(LocalVariableElement variableElement, |
| 288 ConstantExpression value) { | 362 ConstantExpression value) { |
| 289 _localConstants.add(new ConstDeclaration(variableElement, value)); | 363 state.localConstants.add(new ConstDeclaration(variableElement, value)); |
| 290 } | 364 } |
| 291 | 365 |
| 292 void declareLocalVariable(LocalVariableElement variableElement, | 366 void declareLocalVariable(LocalVariableElement variableElement, |
| 293 {ir.Primitive initialValue, | 367 {ir.Primitive initialValue, |
| 294 bool isClosureVariable: false}) { | 368 bool isClosureVariable: false}) { |
| 295 assert(isOpen); | 369 assert(isOpen); |
| 296 if (initialValue == null) { | 370 if (initialValue == null) { |
| 297 // TODO(kmillikin): Consider pooling constants. | 371 // TODO(kmillikin): Consider pooling constants. |
| 298 // The initial value is null. | 372 // The initial value is null. |
| 299 initialValue = makePrimConst(constantSystem.createNull()); | 373 initialValue = makePrimConst(state.constantSystem.createNull()); |
| 300 add(new ir.LetPrim(initialValue)); | 374 add(new ir.LetPrim(initialValue)); |
| 301 } | 375 } |
| 302 if (isClosureVariable) { | 376 if (isClosureVariable) { |
| 303 add(new ir.SetClosureVariable(variableElement, | 377 add(new ir.SetClosureVariable(variableElement, |
| 304 initialValue, | 378 initialValue, |
| 305 isDeclaration: true)); | 379 isDeclaration: true)); |
| 306 } else { | 380 } else { |
| 307 // In case a primitive was introduced for the initializer expression, | 381 // In case a primitive was introduced for the initializer expression, |
| 308 // use this variable element to help derive a good name for it. | 382 // use this variable element to help derive a good name for it. |
| 309 initialValue.useElementAsHint(variableElement); | 383 initialValue.useElementAsHint(variableElement); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 345 // are created from analyzer2dart. | 419 // are created from analyzer2dart. |
| 346 ir.Node buildPrimConst(PrimitiveConstantValue constant) { | 420 ir.Node buildPrimConst(PrimitiveConstantValue constant) { |
| 347 assert(isOpen); | 421 assert(isOpen); |
| 348 ir.Node prim = makePrimConst(constant); | 422 ir.Node prim = makePrimConst(constant); |
| 349 add(new ir.LetPrim(prim)); | 423 add(new ir.LetPrim(prim)); |
| 350 return prim; | 424 return prim; |
| 351 } | 425 } |
| 352 | 426 |
| 353 /// Create an integer literal. | 427 /// Create an integer literal. |
| 354 ir.Constant buildIntegerLiteral(int value) { | 428 ir.Constant buildIntegerLiteral(int value) { |
| 355 return buildPrimConst(constantSystem.createInt(value)); | 429 return buildPrimConst(state.constantSystem.createInt(value)); |
| 356 } | 430 } |
| 357 | 431 |
| 358 /// Create an double literal. | 432 /// Create an double literal. |
| 359 ir.Constant buildDoubleLiteral(double value) { | 433 ir.Constant buildDoubleLiteral(double value) { |
| 360 return buildPrimConst(constantSystem.createDouble(value)); | 434 return buildPrimConst(state.constantSystem.createDouble(value)); |
| 361 } | 435 } |
| 362 | 436 |
| 363 /// Create an bool literal. | 437 /// Create an bool literal. |
| 364 ir.Constant buildBooleanLiteral(bool value) { | 438 ir.Constant buildBooleanLiteral(bool value) { |
| 365 return buildPrimConst(constantSystem.createBool(value)); | 439 return buildPrimConst(state.constantSystem.createBool(value)); |
| 366 } | 440 } |
| 367 | 441 |
| 368 /// Create an null literal. | 442 /// Create an null literal. |
| 369 ir.Constant buildNullLiteral() { | 443 ir.Constant buildNullLiteral() { |
| 370 return buildPrimConst(constantSystem.createNull()); | 444 return buildPrimConst(state.constantSystem.createNull()); |
| 371 } | 445 } |
| 372 | 446 |
| 373 /// Create a string literal. | 447 /// Create a string literal. |
| 374 ir.Constant buildStringLiteral(String value) { | 448 ir.Constant buildStringLiteral(String value) { |
| 375 return buildPrimConst( | 449 return buildPrimConst( |
| 376 constantSystem.createString(new ast.DartString.literal(value))); | 450 state.constantSystem.createString(new ast.DartString.literal(value))); |
| 377 } | 451 } |
| 378 | 452 |
| 379 /// Create a get access of [local]. | 453 /// Create a get access of [local]. |
| 380 ir.Primitive buildGetLocal(Element local) { | 454 ir.Primitive buildGetLocal(Element local) { |
| 381 assert(isOpen); | 455 assert(isOpen); |
| 382 return environment.lookup(local); | 456 return environment.lookup(local); |
| 383 } | 457 } |
| 384 | 458 |
| 385 /// Create a get access of the static [element]. | 459 /// Create a get access of the static [element]. |
| 386 ir.Primitive buildGetStatic(Element element, Selector selector) { | 460 ir.Primitive buildGetStatic(Element element, Selector selector) { |
| 387 assert(isOpen); | 461 assert(isOpen); |
| 388 assert(selector.isGetter); | 462 assert(selector.isGetter); |
| 389 return continueWithExpression( | 463 return continueWithExpression( |
| 390 (k) => new ir.InvokeStatic(element, selector, k, [])); | 464 (k) => new ir.InvokeStatic(element, selector, k, [])); |
| 391 } | 465 } |
| 392 | 466 |
| 393 /** | 467 /** |
| 394 * Add an explicit `return null` for functions that don't have a return | 468 * Add an explicit `return null` for functions that don't have a return |
| 395 * statement on each branch. This includes functions with an empty body, | 469 * statement on each branch. This includes functions with an empty body, |
| 396 * such as `foo(){ }`. | 470 * such as `foo(){ }`. |
| 397 */ | 471 */ |
| 398 void ensureReturn() { | 472 void ensureReturn() { |
| 399 if (!isOpen) return; | 473 if (!isOpen) return; |
| 400 ir.Constant constant = makePrimConst(constantSystem.createNull()); | 474 ir.Constant constant = makePrimConst(state.constantSystem.createNull()); |
| 401 add(new ir.LetPrim(constant)); | 475 add(new ir.LetPrim(constant)); |
| 402 add(new ir.InvokeContinuation(returnContinuation, [constant])); | 476 add(new ir.InvokeContinuation(state.returnContinuation, [constant])); |
| 403 _current = null; | 477 _current = null; |
| 404 } | 478 } |
| 405 | 479 |
| 406 /// Create a [ir.FunctionDefinition] for [element] using [_root] as the body. | 480 /// Create a [ir.FunctionDefinition] for [element] using [_root] as the body. |
| 407 /// | 481 /// |
| 408 /// Parameters must be created before the construction of the body using | 482 /// Parameters must be created before the construction of the body using |
| 409 /// [createParameter]. | 483 /// [createParameter]. |
| 410 ir.FunctionDefinition buildFunctionDefinition( | 484 ir.FunctionDefinition buildFunctionDefinition( |
| 411 FunctionElement element, | 485 FunctionElement element, |
| 412 List<ConstantExpression> defaults) { | 486 List<ConstantExpression> defaults) { |
| 413 if (!element.isAbstract) { | 487 if (!element.isAbstract) { |
| 414 ensureReturn(); | 488 ensureReturn(); |
| 415 return new ir.FunctionDefinition( | 489 return new ir.FunctionDefinition( |
| 416 element, returnContinuation, _parameters, _root, | 490 element, state.returnContinuation, _parameters, _root, |
| 417 _localConstants, defaults); | 491 state.localConstants, defaults); |
| 418 } else { | 492 } else { |
| 419 assert(invariant(element, _root == null, | 493 assert(invariant(element, _root == null, |
| 420 message: "Non-empty body for abstract method $element: $_root")); | 494 message: "Non-empty body for abstract method $element: $_root")); |
| 421 assert(invariant(element, _localConstants.isEmpty, | 495 assert(invariant(element, state.localConstants.isEmpty, |
| 422 message: "Local constants for abstract method $element: " | 496 message: "Local constants for abstract method $element: " |
| 423 "$_localConstants")); | 497 "${state.localConstants}")); |
| 424 return new ir.FunctionDefinition.abstract( | 498 return new ir.FunctionDefinition.abstract( |
| 425 element, _parameters, defaults); | 499 element, _parameters, defaults); |
| 426 } | 500 } |
| 427 } | 501 } |
| 428 | 502 |
| 429 /// Create a static invocation of [element] with arguments structure defined | 503 /// Create a static invocation of [element] with arguments structure defined |
| 430 /// by [selector] and argument values defined by [arguments]. | 504 /// by [selector] and argument values defined by [arguments]. |
| 431 ir.Primitive buildStaticInvocation(Element element, | 505 ir.Primitive buildStaticInvocation(Element element, |
| 432 Selector selector, | 506 Selector selector, |
| 433 List<ir.Definition> arguments) { | 507 List<ir.Definition> arguments) { |
| 434 return continueWithExpression( | 508 return continueWithExpression( |
| 435 (k) => new ir.InvokeStatic(element, selector, k, arguments)); | 509 (k) => new ir.InvokeStatic(element, selector, k, arguments)); |
| 436 } | 510 } |
| 437 | 511 |
| 438 /// Create a return statement `return value;` or `return;` if [value] is | 512 /// Create a return statement `return value;` or `return;` if [value] is |
| 439 /// null. | 513 /// null. |
| 440 void buildReturn([ir.Primitive value]) { | 514 void buildReturn([ir.Primitive value]) { |
| 441 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] | 515 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] |
| 442 // where (C', x) = Build(e, C) | 516 // where (C', x) = Build(e, C) |
| 443 // | 517 // |
| 444 // Return without a subexpression is translated as if it were return null. | 518 // Return without a subexpression is translated as if it were return null. |
| 445 assert(isOpen); | 519 assert(isOpen); |
| 446 if (value == null) { | 520 if (value == null) { |
| 447 value = makePrimConst(constantSystem.createNull()); | 521 value = makePrimConst(state.constantSystem.createNull()); |
| 448 add(new ir.LetPrim(value)); | 522 add(new ir.LetPrim(value)); |
| 449 } | 523 } |
| 450 add(new ir.InvokeContinuation(returnContinuation, [value])); | 524 add(new ir.InvokeContinuation(state.returnContinuation, [value])); |
| 451 _current = null; | 525 _current = null; |
| 452 } | 526 } |
| 453 | 527 |
| 528 // Build(BreakStatement L, C) = C[InvokeContinuation(...)] | |
|
Johnni Winther
2014/10/17 10:13:46
A lot more functionality should be moved to the Ir
| |
| 529 // | |
| 530 // The continuation and arguments are filled in later after translating | |
| 531 // the body containing the break. | |
| 532 bool buildBreak(JumpTarget target) { | |
| 533 return buildJumpInternal(target, state.breakCollectors); | |
| 534 } | |
| 535 | |
| 536 // Build(ContinueStatement L, C) = C[InvokeContinuation(...)] | |
| 537 // | |
| 538 // The continuation and arguments are filled in later after translating | |
| 539 // the body containing the continue. | |
| 540 bool buildContinue(JumpTarget target) { | |
| 541 return buildJumpInternal(target, state.continueCollectors); | |
| 542 } | |
| 543 | |
| 544 bool buildJumpInternal(JumpTarget target, | |
| 545 Iterable<JumpCollector> collectors) { | |
| 546 assert(isOpen); | |
| 547 for (JumpCollector collector in collectors) { | |
| 548 if (target == collector.target) { | |
| 549 collector.addJump(this); | |
| 550 return true; | |
| 551 } | |
| 552 } | |
| 553 return false; | |
| 554 } | |
| 454 } | 555 } |
| 455 | 556 |
| 456 /** | 557 /** |
| 457 * A tree visitor that builds [IrNodes]. The visit methods add statements using | 558 * A tree visitor that builds [IrNodes]. The visit methods add statements using |
| 458 * to the [builder] and return the last added statement for trees that represent | 559 * to the [builder] and return the last added statement for trees that represent |
| 459 * an expression. | 560 * an expression. |
| 460 */ | 561 */ |
| 461 class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive> with IrBuilder { | 562 class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive> |
| 563 with IrBuilderMixin { | |
| 462 final Compiler compiler; | 564 final Compiler compiler; |
| 463 final SourceFile sourceFile; | 565 final SourceFile sourceFile; |
| 464 | 566 |
| 465 // In SSA terms, join-point continuation parameters are the phis and the | 567 // In SSA terms, join-point continuation parameters are the phis and the |
| 466 // continuation invocation arguments are the corresponding phi inputs. To | 568 // continuation invocation arguments are the corresponding phi inputs. To |
| 467 // support name introduction and renaming for source level variables, we use | 569 // support name introduction and renaming for source level variables, we use |
| 468 // nested (delimited) visitors for constructing subparts of the IR that will | 570 // nested (delimited) visitors for constructing subparts of the IR that will |
| 469 // need renaming. Each source variable is assigned an index. | 571 // need renaming. Each source variable is assigned an index. |
| 470 // | 572 // |
| 471 // Each nested visitor maintains a list of free variable uses in the body. | 573 // Each nested visitor maintains a list of free variable uses in the body. |
| 472 // These are implemented as a list of parameters, each with their own use | 574 // These are implemented as a list of parameters, each with their own use |
| 473 // list of references. When the delimited subexpression is plugged into the | 575 // list of references. When the delimited subexpression is plugged into the |
| 474 // surrounding context, the free occurrences can be captured or become free | 576 // surrounding context, the free occurrences can be captured or become free |
| 475 // occurrences in the next outer delimited subexpression. | 577 // occurrences in the next outer delimited subexpression. |
| 476 // | 578 // |
| 477 // Each nested visitor maintains a list that maps indexes of variables | 579 // Each nested visitor maintains a list that maps indexes of variables |
| 478 // assigned in the delimited subexpression to their reaching definition --- | 580 // assigned in the delimited subexpression to their reaching definition --- |
| 479 // that is, the definition in effect at the hole in 'current'. These are | 581 // that is, the definition in effect at the hole in 'current'. These are |
| 480 // used to determine if a join-point continuation needs to be passed | 582 // used to determine if a join-point continuation needs to be passed |
| 481 // arguments, and what the arguments are. | 583 // arguments, and what the arguments are. |
| 482 | 584 |
| 483 /// A stack of collectors for breaks. | |
| 484 final List<JumpCollector> breakCollectors; | |
| 485 /// A stack of collectors for continues. | |
| 486 final List<JumpCollector> continueCollectors; | |
| 487 | |
| 488 FunctionElement currentFunction; | |
| 489 final DetectClosureVariables closureLocals; | |
| 490 | |
| 491 /// Construct a top-level visitor. | 585 /// Construct a top-level visitor. |
| 492 IrBuilderVisitor(TreeElements elements, this.compiler, this.sourceFile) | 586 IrBuilderVisitor(TreeElements elements, this.compiler, this.sourceFile) |
| 493 : breakCollectors = <JumpCollector>[], | 587 : super(elements); |
| 494 continueCollectors = <JumpCollector>[], | |
| 495 closureLocals = new DetectClosureVariables(elements), | |
| 496 super(elements) { | |
| 497 constantSystem = compiler.backend.constantSystem; | |
| 498 } | |
| 499 | |
| 500 /// Construct a delimited visitor for visiting a subtree. | |
| 501 /// | |
| 502 /// The delimited visitor has its own compile-time environment mapping | |
| 503 /// local variables to their values, which is initially a copy of the parent | |
| 504 /// environment. It has its own context for building an IR expression, so | |
| 505 /// the built expression is not plugged into the parent's context. | |
| 506 IrBuilderVisitor.delimited(IrBuilderVisitor parent) | |
| 507 : compiler = parent.compiler, | |
| 508 sourceFile = parent.sourceFile, | |
| 509 breakCollectors = parent.breakCollectors, | |
| 510 continueCollectors = parent.continueCollectors, | |
| 511 currentFunction = parent.currentFunction, | |
| 512 closureLocals = parent.closureLocals, | |
| 513 super(parent.elements) { | |
| 514 constantSystem = parent.constantSystem; | |
| 515 returnContinuation = parent.returnContinuation; | |
| 516 _localConstants = parent._localConstants; | |
| 517 environment = new Environment.from(parent.environment); | |
| 518 } | |
| 519 | |
| 520 /// Construct a visitor for a recursive continuation. | |
| 521 /// | |
| 522 /// The recursive continuation builder has fresh parameters (i.e. SSA phis) | |
| 523 /// for all the local variables in the parent, because the invocation sites | |
| 524 /// of the continuation are not all known when the builder is created. The | |
| 525 /// recursive invocations will be passed values for all the local variables, | |
| 526 /// which may be eliminated later if they are redundant---if they take on | |
| 527 /// the same value at all invocation sites. | |
| 528 IrBuilderVisitor.recursive(IrBuilderVisitor parent) | |
| 529 : compiler = parent.compiler, | |
| 530 sourceFile = parent.sourceFile, | |
| 531 breakCollectors = parent.breakCollectors, | |
| 532 continueCollectors = parent.continueCollectors, | |
| 533 currentFunction = parent.currentFunction, | |
| 534 closureLocals = parent.closureLocals, | |
| 535 super(parent.elements) { | |
| 536 constantSystem = parent.constantSystem; | |
| 537 returnContinuation = parent.returnContinuation; | |
| 538 _localConstants = parent._localConstants; | |
| 539 parent.environment.index2variable.forEach(createParameter); | |
| 540 } | |
| 541 | 588 |
| 542 /** | 589 /** |
| 543 * Builds the [ir.FunctionDefinition] for a function element. In case the | 590 * Builds the [ir.FunctionDefinition] for a function element. In case the |
| 544 * function uses features that cannot be expressed in the IR, this function | 591 * function uses features that cannot be expressed in the IR, this function |
| 545 * returns `null`. | 592 * returns `null`. |
| 546 */ | 593 */ |
| 547 ir.FunctionDefinition buildFunction(FunctionElement functionElement) { | 594 ir.FunctionDefinition buildFunction(FunctionElement functionElement) { |
| 548 return nullIfGiveup(() => buildFunctionInternal(functionElement)); | 595 return nullIfGiveup(() => buildFunctionInternal(functionElement)); |
| 549 } | 596 } |
| 550 | 597 |
| 551 ir.FunctionDefinition buildFunctionInternal(FunctionElement element) { | 598 ir.FunctionDefinition buildFunctionInternal(FunctionElement element) { |
| 552 assert(invariant(element, element.isImplementation)); | 599 assert(invariant(element, element.isImplementation)); |
| 553 currentFunction = element; | |
| 554 ast.FunctionExpression function = element.node; | 600 ast.FunctionExpression function = element.node; |
| 555 assert(function != null); | 601 assert(function != null); |
| 556 assert(!function.modifiers.isExternal); | 602 assert(!function.modifiers.isExternal); |
| 557 assert(elements[function] != null); | 603 assert(elements[function] != null); |
| 558 | 604 |
| 605 DetectClosureVariables closureLocals = new DetectClosureVariables(elements); | |
| 559 closureLocals.visit(function); | 606 closureLocals.visit(function); |
| 560 | 607 |
| 561 _root = _current = null; | 608 return withBuilder( |
| 609 new IrBuilder(compiler.backend.constantSystem, | |
| 610 element, closureLocals.usedFromClosure), | |
| 611 () { | |
| 612 FunctionSignature signature = element.functionSignature; | |
| 613 signature.orderedForEachParameter((ParameterElement parameterElement) { | |
| 614 irBuilder.createParameter( | |
| 615 parameterElement, | |
| 616 isClosureVariable: isClosureVariable(parameterElement)); | |
| 617 }); | |
| 562 | 618 |
| 563 FunctionSignature signature = element.functionSignature; | 619 List<ConstantExpression> defaults = new List<ConstantExpression>(); |
| 564 signature.orderedForEachParameter((ParameterElement parameterElement) { | 620 signature.orderedOptionalParameters.forEach((ParameterElement element) { |
| 565 createParameter(parameterElement, | 621 defaults.add(getConstantForVariable(element)); |
| 566 isClosureVariable: isClosureVariable(parameterElement)); | 622 }); |
| 623 | |
| 624 visit(function.body); | |
| 625 return irBuilder.buildFunctionDefinition(element, defaults); | |
| 567 }); | 626 }); |
| 568 | |
| 569 List<ConstantExpression> defaults = new List<ConstantExpression>(); | |
| 570 signature.orderedOptionalParameters.forEach((ParameterElement element) { | |
| 571 defaults.add(getConstantForVariable(element)); | |
| 572 }); | |
| 573 | |
| 574 visit(function.body); | |
| 575 return buildFunctionDefinition(element, defaults); | |
| 576 } | 627 } |
| 577 | 628 |
| 578 ir.Primitive visit(ast.Node node) => node.accept(this); | 629 ir.Primitive visit(ast.Node node) => node.accept(this); |
| 579 | 630 |
| 580 // ==== Statements ==== | 631 // ==== Statements ==== |
| 581 // Build(Block(stamements), C) = C' | 632 // Build(Block(stamements), C) = C' |
| 582 // where C' = statements.fold(Build, C) | 633 // where C' = statements.fold(Build, C) |
| 583 ir.Primitive visitBlock(ast.Block node) { | 634 ir.Primitive visitBlock(ast.Block node) { |
| 584 assert(isOpen); | 635 assert(irBuilder.isOpen); |
| 585 for (ast.Node n in node.statements.nodes) { | 636 for (ast.Node n in node.statements.nodes) { |
| 586 visit(n); | 637 visit(n); |
| 587 if (!isOpen) return null; | 638 if (!irBuilder.isOpen) return null; |
| 588 } | 639 } |
| 589 return null; | 640 return null; |
| 590 } | 641 } |
| 591 | 642 |
| 592 // Build(BreakStatement L, C) = C[InvokeContinuation(...)] | |
| 593 // | |
| 594 // The continuation and arguments are filled in later after translating | |
| 595 // the body containing the break. | |
| 596 ir.Primitive visitBreakStatement(ast.BreakStatement node) { | 643 ir.Primitive visitBreakStatement(ast.BreakStatement node) { |
| 597 assert(isOpen); | 644 if (!irBuilder.buildBreak(elements.getTargetOf(node))) { |
| 598 JumpTarget target = elements.getTargetOf(node); | 645 compiler.internalError(node, "'break' target not found"); |
| 599 for (JumpCollector collector in breakCollectors) { | |
| 600 if (target == collector.target) { | |
| 601 collector.addJump(this); | |
| 602 return null; | |
| 603 } | |
| 604 } | 646 } |
| 605 compiler.internalError(node, "'break' target not found"); | |
| 606 return null; | 647 return null; |
| 607 } | 648 } |
| 608 | 649 |
| 609 // Build(ContinueStatement L, C) = C[InvokeContinuation(...)] | |
| 610 // | |
| 611 // The continuation and arguments are filled in later after translating | |
| 612 // the body containing the continue. | |
| 613 ir.Primitive visitContinueStatement(ast.ContinueStatement node) { | 650 ir.Primitive visitContinueStatement(ast.ContinueStatement node) { |
| 614 assert(isOpen); | 651 if (!irBuilder.buildContinue(elements.getTargetOf(node))) { |
| 615 JumpTarget target = elements.getTargetOf(node); | 652 compiler.internalError(node, "'continue' target not found"); |
| 616 for (JumpCollector collector in continueCollectors) { | |
| 617 if (target == collector.target) { | |
| 618 collector.addJump(this); | |
| 619 return null; | |
| 620 } | |
| 621 } | 653 } |
| 622 compiler.internalError(node, "'continue' target not found"); | |
| 623 return null; | 654 return null; |
| 624 } | 655 } |
| 625 | 656 |
| 626 // Build(EmptyStatement, C) = C | 657 // Build(EmptyStatement, C) = C |
| 627 ir.Primitive visitEmptyStatement(ast.EmptyStatement node) { | 658 ir.Primitive visitEmptyStatement(ast.EmptyStatement node) { |
| 628 assert(isOpen); | 659 assert(irBuilder.isOpen); |
| 629 return null; | 660 return null; |
| 630 } | 661 } |
| 631 | 662 |
| 632 // Build(ExpressionStatement(e), C) = C' | 663 // Build(ExpressionStatement(e), C) = C' |
| 633 // where (C', _) = Build(e, C) | 664 // where (C', _) = Build(e, C) |
| 634 ir.Primitive visitExpressionStatement(ast.ExpressionStatement node) { | 665 ir.Primitive visitExpressionStatement(ast.ExpressionStatement node) { |
| 635 assert(isOpen); | 666 assert(irBuilder.isOpen); |
| 636 visit(node.expression); | 667 visit(node.expression); |
| 637 return null; | 668 return null; |
| 638 } | 669 } |
| 639 | 670 |
| 640 | 671 |
| 641 /// Create a non-recursive join-point continuation. | 672 /// Create a non-recursive join-point continuation. |
| 642 /// | 673 /// |
| 643 /// Given the environment length at the join point and a list of | 674 /// Given the environment length at the join point and a list of |
| 644 /// jumps that should reach the join point, create a join-point | 675 /// jumps that should reach the join point, create a join-point |
| 645 /// continuation. The join-point continuation has a parameter for each | 676 /// continuation. The join-point continuation has a parameter for each |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 727 | 758 |
| 728 // Mutate this.environment to be the environment at the join point. Do | 759 // Mutate this.environment to be the environment at the join point. Do |
| 729 // this after adding the continuation invocations, because this.environment | 760 // this after adding the continuation invocations, because this.environment |
| 730 // might be collected by the jump collector and so the old environment | 761 // might be collected by the jump collector and so the old environment |
| 731 // values are needed for the continuation invocation. | 762 // values are needed for the continuation invocation. |
| 732 // | 763 // |
| 733 // Iterate to environment.length because environmentLength includes values | 764 // Iterate to environment.length because environmentLength includes values |
| 734 // outside the environment which are 'phantom' variables used for the | 765 // outside the environment which are 'phantom' variables used for the |
| 735 // values of expressions like &&, ||, and ?:. | 766 // values of expressions like &&, ||, and ?:. |
| 736 index = 0; | 767 index = 0; |
| 737 for (int i = 0; i < environment.length; ++i) { | 768 for (int i = 0; i < irBuilder.environment.length; ++i) { |
| 738 if (common[i] == null) { | 769 if (common[i] == null) { |
| 739 environment.index2value[i] = parameters[index++]; | 770 irBuilder.environment.index2value[i] = parameters[index++]; |
| 740 } | 771 } |
| 741 } | 772 } |
| 742 | 773 |
| 743 return join; | 774 return join; |
| 744 } | 775 } |
| 745 | 776 |
| 746 /// Invoke a join-point continuation that contains arguments for all local | 777 /// Invoke a join-point continuation that contains arguments for all local |
| 747 /// variables. | 778 /// variables. |
| 748 /// | 779 /// |
| 749 /// Given the continuation and a list of uninitialized invocations, fill | 780 /// Given the continuation and a list of uninitialized invocations, fill |
| 750 /// in each invocation with the continuation and appropriate arguments. | 781 /// in each invocation with the continuation and appropriate arguments. |
| 751 void invokeFullJoin(ir.Continuation join, | 782 void invokeFullJoin(ir.Continuation join, |
| 752 JumpCollector jumps, | 783 JumpCollector jumps, |
| 753 {recursive: false}) { | 784 {recursive: false}) { |
| 754 join.isRecursive = recursive; | 785 join.isRecursive = recursive; |
| 755 for (int i = 0; i < jumps.length; ++i) { | 786 for (int i = 0; i < jumps.length; ++i) { |
| 756 Environment currentEnvironment = jumps.environments[i]; | 787 Environment currentEnvironment = jumps.environments[i]; |
| 757 ir.InvokeContinuation invoke = jumps.invocations[i]; | 788 ir.InvokeContinuation invoke = jumps.invocations[i]; |
| 758 invoke.continuation = new ir.Reference(join); | 789 invoke.continuation = new ir.Reference(join); |
| 759 invoke.arguments = new List<ir.Reference>.generate( | 790 invoke.arguments = new List<ir.Reference>.generate( |
| 760 join.parameters.length, | 791 join.parameters.length, |
| 761 (i) => new ir.Reference(currentEnvironment[i])); | 792 (i) => new ir.Reference(currentEnvironment[i])); |
| 762 invoke.isRecursive = recursive; | 793 invoke.isRecursive = recursive; |
| 763 } | 794 } |
| 764 } | 795 } |
| 765 | 796 |
| 766 ir.Primitive visitFor(ast.For node) { | 797 ir.Primitive visitFor(ast.For node) { |
| 767 assert(isOpen); | 798 assert(irBuilder.isOpen); |
| 768 // TODO(kmillikin,sigurdm): Handle closure variables declared in a for-loop. | 799 // TODO(kmillikin,sigurdm): Handle closure variables declared in a for-loop. |
| 769 if (node.initializer is ast.VariableDefinitions) { | 800 if (node.initializer is ast.VariableDefinitions) { |
| 770 ast.VariableDefinitions definitions = node.initializer; | 801 ast.VariableDefinitions definitions = node.initializer; |
| 771 for (ast.Node definition in definitions.definitions.nodes) { | 802 for (ast.Node definition in definitions.definitions.nodes) { |
| 772 Element element = elements[definition]; | 803 Element element = elements[definition]; |
| 773 if (isClosureVariable(element)) { | 804 if (isClosureVariable(element)) { |
| 774 return giveup(definition, 'Closure variable in for loop initializer'); | 805 return giveup(definition, 'Closure variable in for loop initializer'); |
| 775 } | 806 } |
| 776 } | 807 } |
| 777 } | 808 } |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 793 // loop(v, ...) | 824 // loop(v, ...) |
| 794 // | 825 // |
| 795 // If there are no breaks in the body, the break continuation is inlined | 826 // If there are no breaks in the body, the break continuation is inlined |
| 796 // in the exit continuation (i.e., the translation of the successor | 827 // in the exit continuation (i.e., the translation of the successor |
| 797 // statement occurs in the exit continuation). If there is only one | 828 // statement occurs in the exit continuation). If there is only one |
| 798 // invocation of the continue continuation (i.e., no continues in the | 829 // invocation of the continue continuation (i.e., no continues in the |
| 799 // body), the continue continuation is inlined in the body. | 830 // body), the continue continuation is inlined in the body. |
| 800 | 831 |
| 801 if (node.initializer != null) visit(node.initializer); | 832 if (node.initializer != null) visit(node.initializer); |
| 802 | 833 |
| 803 IrBuilderVisitor condBuilder = new IrBuilderVisitor.recursive(this); | 834 IrBuilder condBuilder = new IrBuilder.recursive(irBuilder); |
| 804 ir.Primitive condition; | 835 ir.Primitive condition; |
| 805 if (node.condition == null) { | 836 if (node.condition == null) { |
| 806 // If the condition is empty then the body is entered unconditionally. | 837 // If the condition is empty then the body is entered unconditionally. |
| 807 condition = makePrimConst(constantSystem.createBool(true)); | 838 condition = irBuilder.makePrimConst( |
| 839 irBuilder.state.constantSystem.createBool(true)); | |
| 808 condBuilder.add(new ir.LetPrim(condition)); | 840 condBuilder.add(new ir.LetPrim(condition)); |
| 809 } else { | 841 } else { |
| 810 condition = condBuilder.visit(node.condition); | 842 condition = withBuilder(condBuilder, () => visit(node.condition)); |
| 811 } | 843 } |
| 812 | 844 |
| 813 JumpTarget target = elements.getTargetDefinition(node); | 845 JumpTarget target = elements.getTargetDefinition(node); |
| 814 JumpCollector breakCollector = new JumpCollector(target); | 846 JumpCollector breakCollector = new JumpCollector(target); |
| 815 JumpCollector continueCollector = new JumpCollector(target); | 847 JumpCollector continueCollector = new JumpCollector(target); |
| 816 breakCollectors.add(breakCollector); | 848 irBuilder.state.breakCollectors.add(breakCollector); |
| 817 continueCollectors.add(continueCollector); | 849 irBuilder.state.continueCollectors.add(continueCollector); |
| 818 | 850 |
| 819 IrBuilderVisitor bodyBuilder = new IrBuilderVisitor.delimited(condBuilder); | 851 IrBuilder bodyBuilder = new IrBuilder.delimited(condBuilder); |
| 820 bodyBuilder.visit(node.body); | 852 withBuilder(bodyBuilder, () => visit(node.body)); |
| 821 assert(breakCollectors.last == breakCollector); | 853 assert(irBuilder.state.breakCollectors.last == breakCollector); |
| 822 assert(continueCollectors.last == continueCollector); | 854 assert(irBuilder.state.continueCollectors.last == continueCollector); |
| 823 breakCollectors.removeLast(); | 855 irBuilder.state.breakCollectors.removeLast(); |
| 824 continueCollectors.removeLast(); | 856 irBuilder.state.continueCollectors.removeLast(); |
| 825 | 857 |
| 826 // The binding of the continue continuation should occur as late as | 858 // The binding of the continue continuation should occur as late as |
| 827 // possible, that is, at the nearest common ancestor of all the continue | 859 // possible, that is, at the nearest common ancestor of all the continue |
| 828 // sites in the body. However, that is difficult to compute here, so it | 860 // sites in the body. However, that is difficult to compute here, so it |
| 829 // is instead placed just outside the body of the body continuation. | 861 // is instead placed just outside the body of the body continuation. |
| 830 bool hasContinues = !continueCollector.isEmpty; | 862 bool hasContinues = !continueCollector.isEmpty; |
| 831 IrBuilderVisitor updateBuilder = hasContinues | 863 IrBuilder updateBuilder = hasContinues |
| 832 ? new IrBuilderVisitor.recursive(condBuilder) | 864 ? new IrBuilder.recursive(condBuilder) |
| 833 : bodyBuilder; | 865 : bodyBuilder; |
| 834 for (ast.Node n in node.update) { | 866 for (ast.Node n in node.update) { |
| 835 if (!updateBuilder.isOpen) break; | 867 if (!updateBuilder.isOpen) break; |
| 836 updateBuilder.visit(n); | 868 withBuilder(updateBuilder, () => visit(n)); |
| 837 } | 869 } |
| 838 | 870 |
| 839 // Create body entry and loop exit continuations and a branch to them. | 871 // Create body entry and loop exit continuations and a branch to them. |
| 840 ir.Continuation bodyContinuation = new ir.Continuation([]); | 872 ir.Continuation bodyContinuation = new ir.Continuation([]); |
| 841 ir.Continuation exitContinuation = new ir.Continuation([]); | 873 ir.Continuation exitContinuation = new ir.Continuation([]); |
| 842 ir.LetCont branch = | 874 ir.LetCont branch = |
| 843 new ir.LetCont(exitContinuation, | 875 new ir.LetCont(exitContinuation, |
| 844 new ir.LetCont(bodyContinuation, | 876 new ir.LetCont(bodyContinuation, |
| 845 new ir.Branch(new ir.IsTrue(condition), | 877 new ir.Branch(new ir.IsTrue(condition), |
| 846 bodyContinuation, | 878 bodyContinuation, |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 876 // only after it is guaranteed that they are not empty. | 908 // only after it is guaranteed that they are not empty. |
| 877 if (hasContinues) { | 909 if (hasContinues) { |
| 878 continueContinuation.body = updateBuilder._root; | 910 continueContinuation.body = updateBuilder._root; |
| 879 bodyContinuation.body = | 911 bodyContinuation.body = |
| 880 new ir.LetCont(continueContinuation, bodyBuilder._root); | 912 new ir.LetCont(continueContinuation, bodyBuilder._root); |
| 881 } else { | 913 } else { |
| 882 bodyContinuation.body = bodyBuilder._root; | 914 bodyContinuation.body = bodyBuilder._root; |
| 883 } | 915 } |
| 884 | 916 |
| 885 loopContinuation.body = condBuilder._root; | 917 loopContinuation.body = condBuilder._root; |
| 886 add(new ir.LetCont(loopContinuation, | 918 irBuilder.add(new ir.LetCont(loopContinuation, |
| 887 new ir.InvokeContinuation(loopContinuation, | 919 new ir.InvokeContinuation(loopContinuation, |
| 888 environment.index2value))); | 920 irBuilder.environment.index2value))); |
| 889 if (hasBreaks) { | 921 if (hasBreaks) { |
| 890 _current = branch; | 922 irBuilder._current = branch; |
| 891 environment = condBuilder.environment; | 923 irBuilder.environment = condBuilder.environment; |
| 892 breakCollector.addJump(this); | 924 breakCollector.addJump(irBuilder); |
| 893 letJoin.continuation = createJoin(environment.length, breakCollector); | 925 letJoin.continuation = |
| 894 _current = letJoin; | 926 createJoin(irBuilder.environment.length, breakCollector); |
| 927 irBuilder._current = letJoin; | |
| 895 } else { | 928 } else { |
| 896 _current = condBuilder._current; | 929 irBuilder._current = condBuilder._current; |
| 897 environment = condBuilder.environment; | 930 irBuilder.environment = condBuilder.environment; |
| 898 } | 931 } |
| 899 return null; | 932 return null; |
| 900 } | 933 } |
| 901 | 934 |
| 902 ir.Primitive visitIf(ast.If node) { | 935 ir.Primitive visitIf(ast.If node) { |
| 903 assert(isOpen); | 936 assert(irBuilder.isOpen); |
| 904 ir.Primitive condition = visit(node.condition); | 937 ir.Primitive condition = visit(node.condition); |
| 905 | 938 |
| 906 // The then and else parts are delimited. | 939 // The then and else parts are delimited. |
| 907 IrBuilderVisitor thenBuilder = new IrBuilderVisitor.delimited(this); | 940 IrBuilder thenBuilder = new IrBuilder.delimited(irBuilder); |
| 908 IrBuilderVisitor elseBuilder = new IrBuilderVisitor.delimited(this); | 941 IrBuilder elseBuilder = new IrBuilder.delimited(irBuilder); |
| 909 thenBuilder.visit(node.thenPart); | 942 withBuilder(thenBuilder, () => visit(node.thenPart)); |
| 910 if (node.hasElsePart) elseBuilder.visit(node.elsePart); | 943 if (node.hasElsePart) { |
| 944 withBuilder(elseBuilder, () => visit(node.elsePart)); | |
| 945 } | |
| 911 | 946 |
| 912 // Build the term | 947 // Build the term |
| 913 // (Result =) let cont then() = [[thenPart]] in | 948 // (Result =) let cont then() = [[thenPart]] in |
| 914 // let cont else() = [[elsePart]] in | 949 // let cont else() = [[elsePart]] in |
| 915 // if condition (then, else) | 950 // if condition (then, else) |
| 916 ir.Continuation thenContinuation = new ir.Continuation([]); | 951 ir.Continuation thenContinuation = new ir.Continuation([]); |
| 917 ir.Continuation elseContinuation = new ir.Continuation([]); | 952 ir.Continuation elseContinuation = new ir.Continuation([]); |
| 918 ir.Expression letElse = | 953 ir.Expression letElse = |
| 919 new ir.LetCont(elseContinuation, | 954 new ir.LetCont(elseContinuation, |
| 920 new ir.Branch(new ir.IsTrue(condition), | 955 new ir.Branch(new ir.IsTrue(condition), |
| 921 thenContinuation, | 956 thenContinuation, |
| 922 elseContinuation)); | 957 elseContinuation)); |
| 923 ir.Expression letThen = new ir.LetCont(thenContinuation, letElse); | 958 ir.Expression letThen = new ir.LetCont(thenContinuation, letElse); |
| 924 ir.Expression result = letThen; | 959 ir.Expression result = letThen; |
| 925 | 960 |
| 926 ir.Continuation joinContinuation; // Null if there is no join. | 961 ir.Continuation joinContinuation; // Null if there is no join. |
| 927 if (thenBuilder.isOpen && elseBuilder.isOpen) { | 962 if (thenBuilder.isOpen && elseBuilder.isOpen) { |
| 928 // There is a join-point continuation. Build the term | 963 // There is a join-point continuation. Build the term |
| 929 // 'let cont join(x, ...) = [] in Result' and plug invocations of the | 964 // 'let cont join(x, ...) = [] in Result' and plug invocations of the |
| 930 // join-point continuation into the then and else continuations. | 965 // join-point continuation into the then and else continuations. |
| 931 JumpCollector jumps = new JumpCollector(null); | 966 JumpCollector jumps = new JumpCollector(null); |
| 932 jumps.addJump(thenBuilder); | 967 jumps.addJump(thenBuilder); |
| 933 jumps.addJump(elseBuilder); | 968 jumps.addJump(elseBuilder); |
| 934 joinContinuation = createJoin(environment.length, jumps); | 969 joinContinuation = createJoin(irBuilder.environment.length, jumps); |
| 935 result = new ir.LetCont(joinContinuation, result); | 970 result = new ir.LetCont(joinContinuation, result); |
| 936 } | 971 } |
| 937 | 972 |
| 938 // The then or else term root could be null, but not both. If there is | 973 // The then or else term root could be null, but not both. If there is |
| 939 // a join then an InvokeContinuation was just added to both of them. If | 974 // a join then an InvokeContinuation was just added to both of them. If |
| 940 // there is no join, then at least one of them is closed and thus has a | 975 // there is no join, then at least one of them is closed and thus has a |
| 941 // non-null root by the definition of the predicate isClosed. In the | 976 // non-null root by the definition of the predicate isClosed. In the |
| 942 // case that one of them is null, it must be the only one that is open | 977 // case that one of them is null, it must be the only one that is open |
| 943 // and thus contains the new hole in the context. This case is handled | 978 // and thus contains the new hole in the context. This case is handled |
| 944 // after the branch is plugged into the current hole. | 979 // after the branch is plugged into the current hole. |
| 945 thenContinuation.body = thenBuilder._root; | 980 thenContinuation.body = thenBuilder._root; |
| 946 elseContinuation.body = elseBuilder._root; | 981 elseContinuation.body = elseBuilder._root; |
| 947 | 982 |
| 948 add(result); | 983 irBuilder.add(result); |
| 949 if (joinContinuation == null) { | 984 if (joinContinuation == null) { |
| 950 // At least one subexpression is closed. | 985 // At least one subexpression is closed. |
| 951 if (thenBuilder.isOpen) { | 986 if (thenBuilder.isOpen) { |
| 952 _current = (thenBuilder._root == null) ? letThen : thenBuilder._current; | 987 irBuilder._current = |
| 953 environment = thenBuilder.environment; | 988 (thenBuilder._root == null) ? letThen : thenBuilder._current; |
| 989 irBuilder.environment = thenBuilder.environment; | |
| 954 } else if (elseBuilder.isOpen) { | 990 } else if (elseBuilder.isOpen) { |
| 955 _current = (elseBuilder._root == null) ? letElse : elseBuilder._current; | 991 irBuilder._current = |
| 956 environment = elseBuilder.environment; | 992 (elseBuilder._root == null) ? letElse : elseBuilder._current; |
| 993 irBuilder.environment = elseBuilder.environment; | |
| 957 } else { | 994 } else { |
| 958 _current = null; | 995 irBuilder._current = null; |
| 959 } | 996 } |
| 960 } | 997 } |
| 961 return null; | 998 return null; |
| 962 } | 999 } |
| 963 | 1000 |
| 964 ir.Primitive visitLabeledStatement(ast.LabeledStatement node) { | 1001 ir.Primitive visitLabeledStatement(ast.LabeledStatement node) { |
| 965 ast.Statement body = node.statement; | 1002 ast.Statement body = node.statement; |
| 966 return body is ast.Loop | 1003 return body is ast.Loop |
| 967 ? visit(body) | 1004 ? visit(body) |
| 968 : giveup(node, 'labeled statement'); | 1005 : giveup(node, 'labeled statement'); |
| 969 } | 1006 } |
| 970 | 1007 |
| 971 ir.Primitive visitWhile(ast.While node) { | 1008 ir.Primitive visitWhile(ast.While node) { |
| 972 assert(isOpen); | 1009 assert(irBuilder.isOpen); |
| 973 // While loops use four named continuations: the entry to the body, the | 1010 // While loops use four named continuations: the entry to the body, the |
| 974 // loop exit, the loop back edge (continue), and the loop exit (break). | 1011 // loop exit, the loop back edge (continue), and the loop exit (break). |
| 975 // The CPS translation of [[while (condition) body; successor]] is: | 1012 // The CPS translation of [[while (condition) body; successor]] is: |
| 976 // | 1013 // |
| 977 // let cont continue(x, ...) = | 1014 // let cont continue(x, ...) = |
| 978 // let prim cond = [[condition]] in | 1015 // let prim cond = [[condition]] in |
| 979 // let cont break() = [[successor]] in | 1016 // let cont break() = [[successor]] in |
| 980 // let cont exit() = break(v, ...) in | 1017 // let cont exit() = break(v, ...) in |
| 981 // let cont body() = [[body]]; continue(v, ...) in | 1018 // let cont body() = [[body]]; continue(v, ...) in |
| 982 // branch cond (body, exit) in | 1019 // branch cond (body, exit) in |
| 983 // continue(v, ...) | 1020 // continue(v, ...) |
| 984 // | 1021 // |
| 985 // If there are no breaks in the body, the break continuation is inlined | 1022 // If there are no breaks in the body, the break continuation is inlined |
| 986 // in the exit continuation (i.e., the translation of the successor | 1023 // in the exit continuation (i.e., the translation of the successor |
| 987 // statement occurs in the exit continuation). | 1024 // statement occurs in the exit continuation). |
| 988 | 1025 |
| 989 // The condition and body are delimited. | 1026 // The condition and body are delimited. |
| 990 IrBuilderVisitor condBuilder = new IrBuilderVisitor.recursive(this); | 1027 IrBuilder condBuilder = new IrBuilder.recursive(irBuilder); |
| 991 ir.Primitive condition = condBuilder.visit(node.condition); | 1028 ir.Primitive condition = |
| 1029 withBuilder(condBuilder, () => visit(node.condition)); | |
| 992 | 1030 |
| 993 JumpTarget target = elements.getTargetDefinition(node); | 1031 JumpTarget target = elements.getTargetDefinition(node); |
| 994 JumpCollector breakCollector = new JumpCollector(target); | 1032 JumpCollector breakCollector = new JumpCollector(target); |
| 995 JumpCollector continueCollector = new JumpCollector(target); | 1033 JumpCollector continueCollector = new JumpCollector(target); |
| 996 breakCollectors.add(breakCollector); | 1034 irBuilder.state.breakCollectors.add(breakCollector); |
| 997 continueCollectors.add(continueCollector); | 1035 irBuilder.state.continueCollectors.add(continueCollector); |
| 998 | 1036 |
| 999 IrBuilderVisitor bodyBuilder = new IrBuilderVisitor.delimited(condBuilder); | 1037 IrBuilder bodyBuilder = new IrBuilder.delimited(condBuilder); |
| 1000 bodyBuilder.visit(node.body); | 1038 withBuilder(bodyBuilder, () => visit(node.body)); |
| 1001 assert(breakCollectors.last == breakCollector); | 1039 assert(irBuilder.state.breakCollectors.last == breakCollector); |
| 1002 assert(continueCollectors.last == continueCollector); | 1040 assert(irBuilder.state.continueCollectors.last == continueCollector); |
| 1003 breakCollectors.removeLast(); | 1041 irBuilder.state.breakCollectors.removeLast(); |
| 1004 continueCollectors.removeLast(); | 1042 irBuilder.state.continueCollectors.removeLast(); |
| 1005 | 1043 |
| 1006 // Create body entry and loop exit continuations and a branch to them. | 1044 // Create body entry and loop exit continuations and a branch to them. |
| 1007 ir.Continuation bodyContinuation = new ir.Continuation([]); | 1045 ir.Continuation bodyContinuation = new ir.Continuation([]); |
| 1008 ir.Continuation exitContinuation = new ir.Continuation([]); | 1046 ir.Continuation exitContinuation = new ir.Continuation([]); |
| 1009 ir.LetCont branch = | 1047 ir.LetCont branch = |
| 1010 new ir.LetCont(exitContinuation, | 1048 new ir.LetCont(exitContinuation, |
| 1011 new ir.LetCont(bodyContinuation, | 1049 new ir.LetCont(bodyContinuation, |
| 1012 new ir.Branch(new ir.IsTrue(condition), | 1050 new ir.Branch(new ir.IsTrue(condition), |
| 1013 bodyContinuation, | 1051 bodyContinuation, |
| 1014 exitContinuation))); | 1052 exitContinuation))); |
| 1015 // If there are breaks in the body, then there must be a join-point | 1053 // If there are breaks in the body, then there must be a join-point |
| 1016 // continuation for the normal exit and the breaks. | 1054 // continuation for the normal exit and the breaks. |
| 1017 bool hasBreaks = !breakCollector.isEmpty; | 1055 bool hasBreaks = !breakCollector.isEmpty; |
| 1018 ir.LetCont letJoin; | 1056 ir.LetCont letJoin; |
| 1019 if (hasBreaks) { | 1057 if (hasBreaks) { |
| 1020 letJoin = new ir.LetCont(null, branch); | 1058 letJoin = new ir.LetCont(null, branch); |
| 1021 condBuilder.add(letJoin); | 1059 condBuilder.add(letJoin); |
| 1022 condBuilder._current = branch; | 1060 condBuilder._current = branch; |
| 1023 } else { | 1061 } else { |
| 1024 condBuilder.add(branch); | 1062 condBuilder.add(branch); |
| 1025 } | 1063 } |
| 1026 ir.Continuation loopContinuation = | 1064 ir.Continuation loopContinuation = |
| 1027 new ir.Continuation(condBuilder._parameters); | 1065 new ir.Continuation(condBuilder._parameters); |
| 1028 if (bodyBuilder.isOpen) continueCollector.addJump(bodyBuilder); | 1066 if (bodyBuilder.isOpen) continueCollector.addJump(bodyBuilder); |
| 1029 invokeFullJoin(loopContinuation, continueCollector, recursive: true); | 1067 invokeFullJoin(loopContinuation, continueCollector, recursive: true); |
| 1030 bodyContinuation.body = bodyBuilder._root; | 1068 bodyContinuation.body = bodyBuilder._root; |
| 1031 | 1069 |
| 1032 loopContinuation.body = condBuilder._root; | 1070 loopContinuation.body = condBuilder._root; |
| 1033 add(new ir.LetCont(loopContinuation, | 1071 irBuilder.add(new ir.LetCont(loopContinuation, |
| 1034 new ir.InvokeContinuation(loopContinuation, | 1072 new ir.InvokeContinuation(loopContinuation, |
| 1035 environment.index2value))); | 1073 irBuilder.environment.index2value))); |
| 1036 if (hasBreaks) { | 1074 if (hasBreaks) { |
| 1037 _current = branch; | 1075 irBuilder._current = branch; |
| 1038 environment = condBuilder.environment; | 1076 irBuilder.environment = condBuilder.environment; |
| 1039 breakCollector.addJump(this); | 1077 breakCollector.addJump(irBuilder); |
| 1040 letJoin.continuation = createJoin(environment.length, breakCollector); | 1078 letJoin.continuation = |
| 1041 _current = letJoin; | 1079 createJoin(irBuilder.environment.length, breakCollector); |
| 1080 irBuilder._current = letJoin; | |
| 1042 } else { | 1081 } else { |
| 1043 _current = condBuilder._current; | 1082 irBuilder._current = condBuilder._current; |
| 1044 environment = condBuilder.environment; | 1083 irBuilder.environment = condBuilder.environment; |
| 1045 } | 1084 } |
| 1046 return null; | 1085 return null; |
| 1047 } | 1086 } |
| 1048 | 1087 |
| 1049 ir.Primitive visitForIn(ast.ForIn node) { | 1088 ir.Primitive visitForIn(ast.ForIn node) { |
| 1050 // The for-in loop | 1089 // The for-in loop |
| 1051 // | 1090 // |
| 1052 // for (a in e) s; | 1091 // for (a in e) s; |
| 1053 // | 1092 // |
| 1054 // Is compiled analogously to: | 1093 // Is compiled analogously to: |
| 1055 // | 1094 // |
| 1056 // a = e.iterator; | 1095 // a = e.iterator; |
| 1057 // while (a.moveNext()) { | 1096 // while (a.moveNext()) { |
| 1058 // var n0 = a.current; | 1097 // var n0 = a.current; |
| 1059 // s; | 1098 // s; |
| 1060 // } | 1099 // } |
| 1061 | 1100 |
| 1062 // The condition and body are delimited. | 1101 // The condition and body are delimited. |
| 1063 IrBuilderVisitor condBuilder = new IrBuilderVisitor.recursive(this); | 1102 IrBuilder condBuilder = new IrBuilder.recursive(irBuilder); |
| 1064 | 1103 |
| 1065 ir.Primitive expressionReceiver = visit(node.expression); | 1104 ir.Primitive expressionReceiver = visit(node.expression); |
| 1066 List<ir.Primitive> emptyArguments = new List<ir.Primitive>(); | 1105 List<ir.Primitive> emptyArguments = new List<ir.Primitive>(); |
| 1067 | 1106 |
| 1068 ir.Parameter iterator = new ir.Parameter(null); | 1107 ir.Parameter iterator = new ir.Parameter(null); |
| 1069 ir.Continuation iteratorInvoked = new ir.Continuation([iterator]); | 1108 ir.Continuation iteratorInvoked = new ir.Continuation([iterator]); |
| 1070 add(new ir.LetCont(iteratorInvoked, | 1109 irBuilder.add(new ir.LetCont(iteratorInvoked, |
| 1071 new ir.InvokeMethod(expressionReceiver, | 1110 new ir.InvokeMethod(expressionReceiver, |
| 1072 new Selector.getter("iterator", null), iteratorInvoked, | 1111 new Selector.getter("iterator", null), iteratorInvoked, |
| 1073 emptyArguments))); | 1112 emptyArguments))); |
| 1074 | 1113 |
| 1075 ir.Parameter condition = new ir.Parameter(null); | 1114 ir.Parameter condition = new ir.Parameter(null); |
| 1076 ir.Continuation moveNextInvoked = new ir.Continuation([condition]); | 1115 ir.Continuation moveNextInvoked = new ir.Continuation([condition]); |
| 1077 condBuilder.add(new ir.LetCont(moveNextInvoked, | 1116 condBuilder.add(new ir.LetCont(moveNextInvoked, |
| 1078 new ir.InvokeMethod(iterator, | 1117 new ir.InvokeMethod(iterator, |
| 1079 new Selector.call("moveNext", null, 0), | 1118 new Selector.call("moveNext", null, 0), |
| 1080 moveNextInvoked, emptyArguments))); | 1119 moveNextInvoked, emptyArguments))); |
| 1081 | 1120 |
| 1082 JumpTarget target = elements.getTargetDefinition(node); | 1121 JumpTarget target = elements.getTargetDefinition(node); |
| 1083 JumpCollector breakCollector = new JumpCollector(target); | 1122 JumpCollector breakCollector = new JumpCollector(target); |
| 1084 JumpCollector continueCollector = new JumpCollector(target); | 1123 JumpCollector continueCollector = new JumpCollector(target); |
| 1085 breakCollectors.add(breakCollector); | 1124 irBuilder.state.breakCollectors.add(breakCollector); |
| 1086 continueCollectors.add(continueCollector); | 1125 irBuilder.state.continueCollectors.add(continueCollector); |
| 1087 | 1126 |
| 1088 IrBuilderVisitor bodyBuilder = new IrBuilderVisitor.delimited(condBuilder); | 1127 IrBuilder bodyBuilder = new IrBuilder.delimited(condBuilder); |
| 1089 ast.Node identifier = node.declaredIdentifier; | 1128 ast.Node identifier = node.declaredIdentifier; |
| 1090 Element variableElement = elements.getForInVariable(node); | 1129 Element variableElement = elements.getForInVariable(node); |
| 1091 Selector selector = elements.getSelector(identifier); | 1130 Selector selector = elements.getSelector(identifier); |
| 1092 | 1131 |
| 1093 // node.declaredIdentifier can be either an ast.VariableDefinitions | 1132 // node.declaredIdentifier can be either an ast.VariableDefinitions |
| 1094 // (defining a new local variable) or a send designating some existing | 1133 // (defining a new local variable) or a send designating some existing |
| 1095 // variable. | 1134 // variable. |
| 1096 ast.Node declaredIdentifier = node.declaredIdentifier; | 1135 ast.Node declaredIdentifier = node.declaredIdentifier; |
| 1097 | 1136 |
| 1098 if (declaredIdentifier is ast.VariableDefinitions) { | 1137 if (declaredIdentifier is ast.VariableDefinitions) { |
| 1099 bodyBuilder.visit(declaredIdentifier); | 1138 withBuilder(bodyBuilder, () => visit(declaredIdentifier)); |
| 1100 } | 1139 } |
| 1101 | 1140 |
| 1102 ir.Parameter currentValue = new ir.Parameter(null); | 1141 ir.Parameter currentValue = new ir.Parameter(null); |
| 1103 ir.Continuation currentInvoked = new ir.Continuation([currentValue]); | 1142 ir.Continuation currentInvoked = new ir.Continuation([currentValue]); |
| 1104 bodyBuilder.add(new ir.LetCont(currentInvoked, | 1143 bodyBuilder.add(new ir.LetCont(currentInvoked, |
| 1105 new ir.InvokeMethod(iterator, new Selector.getter("current", null), | 1144 new ir.InvokeMethod(iterator, new Selector.getter("current", null), |
| 1106 currentInvoked, emptyArguments))); | 1145 currentInvoked, emptyArguments))); |
| 1107 if (Elements.isLocal(variableElement)) { | 1146 if (Elements.isLocal(variableElement)) { |
| 1108 bodyBuilder.setLocal(variableElement, currentValue); | 1147 withBuilder(bodyBuilder, () => setLocal(variableElement, currentValue)); |
| 1109 } else if (Elements.isStaticOrTopLevel(variableElement)) { | 1148 } else if (Elements.isStaticOrTopLevel(variableElement)) { |
| 1110 bodyBuilder.setStatic(variableElement, selector, currentValue); | 1149 withBuilder(bodyBuilder, |
| 1150 () => setStatic(variableElement, selector, currentValue)); | |
| 1111 } else { | 1151 } else { |
| 1112 ir.Primitive receiver = bodyBuilder.lookupThis(); | 1152 ir.Primitive receiver = |
| 1113 bodyBuilder.setDynamic(null, receiver, selector, currentValue); | 1153 withBuilder(bodyBuilder, () => lookupThis()); |
| 1154 withBuilder(bodyBuilder, | |
| 1155 () => setDynamic(null, receiver, selector, currentValue)); | |
| 1114 } | 1156 } |
| 1115 | 1157 |
| 1116 bodyBuilder.visit(node.body); | 1158 withBuilder(bodyBuilder, () => visit(node.body)); |
| 1117 assert(breakCollectors.last == breakCollector); | 1159 assert(irBuilder.state.breakCollectors.last == breakCollector); |
| 1118 assert(continueCollectors.last == continueCollector); | 1160 assert(irBuilder.state.continueCollectors.last == continueCollector); |
| 1119 breakCollectors.removeLast(); | 1161 irBuilder.state.breakCollectors.removeLast(); |
| 1120 continueCollectors.removeLast(); | 1162 irBuilder.state.continueCollectors.removeLast(); |
| 1121 | 1163 |
| 1122 // Create body entry and loop exit continuations and a branch to them. | 1164 // Create body entry and loop exit continuations and a branch to them. |
| 1123 ir.Continuation bodyContinuation = new ir.Continuation([]); | 1165 ir.Continuation bodyContinuation = new ir.Continuation([]); |
| 1124 ir.Continuation exitContinuation = new ir.Continuation([]); | 1166 ir.Continuation exitContinuation = new ir.Continuation([]); |
| 1125 ir.LetCont branch = | 1167 ir.LetCont branch = |
| 1126 new ir.LetCont(exitContinuation, | 1168 new ir.LetCont(exitContinuation, |
| 1127 new ir.LetCont(bodyContinuation, | 1169 new ir.LetCont(bodyContinuation, |
| 1128 new ir.Branch(new ir.IsTrue(condition), | 1170 new ir.Branch(new ir.IsTrue(condition), |
| 1129 bodyContinuation, | 1171 bodyContinuation, |
| 1130 exitContinuation))); | 1172 exitContinuation))); |
| 1131 // If there are breaks in the body, then there must be a join-point | 1173 // If there are breaks in the body, then there must be a join-point |
| 1132 // continuation for the normal exit and the breaks. | 1174 // continuation for the normal exit and the breaks. |
| 1133 bool hasBreaks = !breakCollector.isEmpty; | 1175 bool hasBreaks = !breakCollector.isEmpty; |
| 1134 ir.LetCont letJoin; | 1176 ir.LetCont letJoin; |
| 1135 if (hasBreaks) { | 1177 if (hasBreaks) { |
| 1136 letJoin = new ir.LetCont(null, branch); | 1178 letJoin = new ir.LetCont(null, branch); |
| 1137 condBuilder.add(letJoin); | 1179 condBuilder.add(letJoin); |
| 1138 condBuilder._current = branch; | 1180 condBuilder._current = branch; |
| 1139 } else { | 1181 } else { |
| 1140 condBuilder.add(branch); | 1182 condBuilder.add(branch); |
| 1141 } | 1183 } |
| 1142 ir.Continuation loopContinuation = | 1184 ir.Continuation loopContinuation = |
| 1143 new ir.Continuation(condBuilder._parameters); | 1185 new ir.Continuation(condBuilder._parameters); |
| 1144 if (bodyBuilder.isOpen) continueCollector.addJump(bodyBuilder); | 1186 if (bodyBuilder.isOpen) continueCollector.addJump(bodyBuilder); |
| 1145 invokeFullJoin(loopContinuation, continueCollector, recursive: true); | 1187 invokeFullJoin(loopContinuation, continueCollector, recursive: true); |
| 1146 bodyContinuation.body = bodyBuilder._root; | 1188 bodyContinuation.body = bodyBuilder._root; |
| 1147 | 1189 |
| 1148 loopContinuation.body = condBuilder._root; | 1190 loopContinuation.body = condBuilder._root; |
| 1149 add(new ir.LetCont(loopContinuation, | 1191 irBuilder.add(new ir.LetCont(loopContinuation, |
| 1150 new ir.InvokeContinuation(loopContinuation, | 1192 new ir.InvokeContinuation(loopContinuation, |
| 1151 environment.index2value))); | 1193 irBuilder.environment.index2value))); |
| 1152 if (hasBreaks) { | 1194 if (hasBreaks) { |
| 1153 _current = branch; | 1195 irBuilder._current = branch; |
| 1154 environment = condBuilder.environment; | 1196 irBuilder.environment = condBuilder.environment; |
| 1155 breakCollector.addJump(this); | 1197 breakCollector.addJump(irBuilder); |
| 1156 letJoin.continuation = createJoin(environment.length, breakCollector); | 1198 letJoin.continuation = |
| 1157 _current = letJoin; | 1199 createJoin(irBuilder.environment.length, breakCollector); |
| 1200 irBuilder._current = letJoin; | |
| 1158 } else { | 1201 } else { |
| 1159 _current = condBuilder._current; | 1202 irBuilder._current = condBuilder._current; |
| 1160 environment = condBuilder.environment; | 1203 irBuilder.environment = condBuilder.environment; |
| 1161 } | 1204 } |
| 1162 return null; | 1205 return null; |
| 1163 } | 1206 } |
| 1164 | 1207 |
| 1165 ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) { | 1208 ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) { |
| 1166 assert(isOpen); | 1209 assert(irBuilder.isOpen); |
| 1167 if (node.modifiers.isConst) { | 1210 if (node.modifiers.isConst) { |
| 1168 for (ast.SendSet definition in node.definitions.nodes) { | 1211 for (ast.SendSet definition in node.definitions.nodes) { |
| 1169 assert(!definition.arguments.isEmpty); | 1212 assert(!definition.arguments.isEmpty); |
| 1170 assert(definition.arguments.tail.isEmpty); | 1213 assert(definition.arguments.tail.isEmpty); |
| 1171 VariableElement element = elements[definition]; | 1214 VariableElement element = elements[definition]; |
| 1172 ConstantExpression value = getConstantForVariable(element); | 1215 ConstantExpression value = getConstantForVariable(element); |
| 1173 declareLocalConstant(element, value); | 1216 irBuilder.declareLocalConstant(element, value); |
| 1174 } | 1217 } |
| 1175 } else { | 1218 } else { |
| 1176 for (ast.Node definition in node.definitions.nodes) { | 1219 for (ast.Node definition in node.definitions.nodes) { |
| 1177 Element element = elements[definition]; | 1220 Element element = elements[definition]; |
| 1178 ir.Primitive initialValue; | 1221 ir.Primitive initialValue; |
| 1179 // Definitions are either SendSets if there is an initializer, or | 1222 // Definitions are either SendSets if there is an initializer, or |
| 1180 // Identifiers if there is no initializer. | 1223 // Identifiers if there is no initializer. |
| 1181 if (definition is ast.SendSet) { | 1224 if (definition is ast.SendSet) { |
| 1182 assert(!definition.arguments.isEmpty); | 1225 assert(!definition.arguments.isEmpty); |
| 1183 assert(definition.arguments.tail.isEmpty); | 1226 assert(definition.arguments.tail.isEmpty); |
| 1184 initialValue = visit(definition.arguments.head); | 1227 initialValue = visit(definition.arguments.head); |
| 1185 } else { | 1228 } else { |
| 1186 assert(definition is ast.Identifier); | 1229 assert(definition is ast.Identifier); |
| 1187 } | 1230 } |
| 1188 declareLocalVariable(element, | 1231 irBuilder.declareLocalVariable(element, |
| 1189 initialValue: initialValue, | 1232 initialValue: initialValue, |
| 1190 isClosureVariable: isClosureVariable(element)); | 1233 isClosureVariable: isClosureVariable(element)); |
| 1191 } | 1234 } |
| 1192 } | 1235 } |
| 1193 return null; | 1236 return null; |
| 1194 } | 1237 } |
| 1195 | 1238 |
| 1196 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] | 1239 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] |
| 1197 // where (C', x) = Build(e, C) | 1240 // where (C', x) = Build(e, C) |
| 1198 // | 1241 // |
| 1199 // Return without a subexpression is translated as if it were return null. | 1242 // Return without a subexpression is translated as if it were return null. |
| 1200 ir.Primitive visitReturn(ast.Return node) { | 1243 ir.Primitive visitReturn(ast.Return node) { |
| 1201 assert(isOpen); | 1244 assert(irBuilder.isOpen); |
| 1202 assert(invariant(node, node.beginToken.value != 'native')); | 1245 assert(invariant(node, node.beginToken.value != 'native')); |
| 1203 if (node.expression == null) { | 1246 if (node.expression == null) { |
| 1204 buildReturn(); | 1247 irBuilder.buildReturn(); |
| 1205 } else { | 1248 } else { |
| 1206 buildReturn(visit(node.expression)); | 1249 irBuilder.buildReturn(visit(node.expression)); |
| 1207 } | 1250 } |
| 1208 return null; | 1251 return null; |
| 1209 } | 1252 } |
| 1210 | 1253 |
| 1211 // ==== Expressions ==== | 1254 // ==== Expressions ==== |
| 1212 ir.Primitive visitConditional(ast.Conditional node) { | 1255 ir.Primitive visitConditional(ast.Conditional node) { |
| 1213 assert(isOpen); | 1256 assert(irBuilder.isOpen); |
| 1214 ir.Primitive condition = visit(node.condition); | 1257 ir.Primitive condition = visit(node.condition); |
| 1215 | 1258 |
| 1216 // The then and else expressions are delimited. | 1259 // The then and else expressions are delimited. |
| 1217 IrBuilderVisitor thenBuilder = new IrBuilderVisitor.delimited(this); | 1260 IrBuilder thenBuilder = new IrBuilder.delimited(irBuilder); |
| 1218 IrBuilderVisitor elseBuilder = new IrBuilderVisitor.delimited(this); | 1261 IrBuilder elseBuilder = new IrBuilder.delimited(irBuilder); |
| 1219 ir.Primitive thenValue = thenBuilder.visit(node.thenExpression); | 1262 ir.Primitive thenValue = |
| 1220 ir.Primitive elseValue = elseBuilder.visit(node.elseExpression); | 1263 withBuilder(thenBuilder, () => visit(node.thenExpression)); |
| 1264 ir.Primitive elseValue = | |
| 1265 withBuilder(elseBuilder, () => visit(node.elseExpression)); | |
| 1221 | 1266 |
| 1222 // Treat the values of the subexpressions as named values in the | 1267 // Treat the values of the subexpressions as named values in the |
| 1223 // environment, so they will be treated as arguments to the join-point | 1268 // environment, so they will be treated as arguments to the join-point |
| 1224 // continuation. | 1269 // continuation. |
| 1225 assert(environment.length == thenBuilder.environment.length); | 1270 assert(irBuilder.environment.length == thenBuilder.environment.length); |
| 1226 assert(environment.length == elseBuilder.environment.length); | 1271 assert(irBuilder.environment.length == elseBuilder.environment.length); |
| 1227 thenBuilder.environment.extend(null, thenValue); | 1272 thenBuilder.environment.extend(null, thenValue); |
| 1228 elseBuilder.environment.extend(null, elseValue); | 1273 elseBuilder.environment.extend(null, elseValue); |
| 1229 JumpCollector jumps = new JumpCollector(null); | 1274 JumpCollector jumps = new JumpCollector(null); |
| 1230 jumps.addJump(thenBuilder); | 1275 jumps.addJump(thenBuilder); |
| 1231 jumps.addJump(elseBuilder); | 1276 jumps.addJump(elseBuilder); |
| 1232 ir.Continuation joinContinuation = | 1277 ir.Continuation joinContinuation = |
| 1233 createJoin(environment.length + 1, jumps); | 1278 createJoin(irBuilder.environment.length + 1, jumps); |
| 1234 | 1279 |
| 1235 // Build the term | 1280 // Build the term |
| 1236 // let cont join(x, ..., result) = [] in | 1281 // let cont join(x, ..., result) = [] in |
| 1237 // let cont then() = [[thenPart]]; join(v, ...) in | 1282 // let cont then() = [[thenPart]]; join(v, ...) in |
| 1238 // let cont else() = [[elsePart]]; join(v, ...) in | 1283 // let cont else() = [[elsePart]]; join(v, ...) in |
| 1239 // if condition (then, else) | 1284 // if condition (then, else) |
| 1240 ir.Continuation thenContinuation = new ir.Continuation([]); | 1285 ir.Continuation thenContinuation = new ir.Continuation([]); |
| 1241 ir.Continuation elseContinuation = new ir.Continuation([]); | 1286 ir.Continuation elseContinuation = new ir.Continuation([]); |
| 1242 thenContinuation.body = thenBuilder._root; | 1287 thenContinuation.body = thenBuilder._root; |
| 1243 elseContinuation.body = elseBuilder._root; | 1288 elseContinuation.body = elseBuilder._root; |
| 1244 add(new ir.LetCont(joinContinuation, | 1289 irBuilder.add(new ir.LetCont(joinContinuation, |
| 1245 new ir.LetCont(thenContinuation, | 1290 new ir.LetCont(thenContinuation, |
| 1246 new ir.LetCont(elseContinuation, | 1291 new ir.LetCont(elseContinuation, |
| 1247 new ir.Branch(new ir.IsTrue(condition), | 1292 new ir.Branch(new ir.IsTrue(condition), |
| 1248 thenContinuation, | 1293 thenContinuation, |
| 1249 elseContinuation))))); | 1294 elseContinuation))))); |
| 1250 return (thenValue == elseValue) | 1295 return (thenValue == elseValue) |
| 1251 ? thenValue | 1296 ? thenValue |
| 1252 : joinContinuation.parameters.last; | 1297 : joinContinuation.parameters.last; |
| 1253 } | 1298 } |
| 1254 | 1299 |
| 1255 // For all simple literals: | 1300 // For all simple literals: |
| 1256 // Build(Literal(c), C) = C[let val x = Constant(c) in [], x] | 1301 // Build(Literal(c), C) = C[let val x = Constant(c) in [], x] |
| 1257 ir.Primitive visitLiteralBool(ast.LiteralBool node) { | 1302 ir.Primitive visitLiteralBool(ast.LiteralBool node) { |
| 1258 assert(isOpen); | 1303 assert(irBuilder.isOpen); |
| 1259 return translateConstant(node); | 1304 return translateConstant(node); |
| 1260 } | 1305 } |
| 1261 | 1306 |
| 1262 ir.Primitive visitLiteralDouble(ast.LiteralDouble node) { | 1307 ir.Primitive visitLiteralDouble(ast.LiteralDouble node) { |
| 1263 assert(isOpen); | 1308 assert(irBuilder.isOpen); |
| 1264 return translateConstant(node); | 1309 return translateConstant(node); |
| 1265 } | 1310 } |
| 1266 | 1311 |
| 1267 ir.Primitive visitLiteralInt(ast.LiteralInt node) { | 1312 ir.Primitive visitLiteralInt(ast.LiteralInt node) { |
| 1268 assert(isOpen); | 1313 assert(irBuilder.isOpen); |
| 1269 return translateConstant(node); | 1314 return translateConstant(node); |
| 1270 } | 1315 } |
| 1271 | 1316 |
| 1272 ir.Primitive visitLiteralNull(ast.LiteralNull node) { | 1317 ir.Primitive visitLiteralNull(ast.LiteralNull node) { |
| 1273 assert(isOpen); | 1318 assert(irBuilder.isOpen); |
| 1274 return translateConstant(node); | 1319 return translateConstant(node); |
| 1275 } | 1320 } |
| 1276 | 1321 |
| 1277 ir.Primitive visitLiteralString(ast.LiteralString node) { | 1322 ir.Primitive visitLiteralString(ast.LiteralString node) { |
| 1278 assert(isOpen); | 1323 assert(irBuilder.isOpen); |
| 1279 return translateConstant(node); | 1324 return translateConstant(node); |
| 1280 } | 1325 } |
| 1281 | 1326 |
| 1282 ConstantExpression getConstantForNode(ast.Node node) { | 1327 ConstantExpression getConstantForNode(ast.Node node) { |
| 1283 ConstantExpression constant = | 1328 ConstantExpression constant = |
| 1284 compiler.backend.constantCompilerTask.compileNode(node, elements); | 1329 compiler.backend.constantCompilerTask.compileNode(node, elements); |
| 1285 assert(invariant(node, constant != null, | 1330 assert(invariant(node, constant != null, |
| 1286 message: 'No constant computed for $node')); | 1331 message: 'No constant computed for $node')); |
| 1287 return constant; | 1332 return constant; |
| 1288 } | 1333 } |
| 1289 | 1334 |
| 1290 ConstantExpression getConstantForVariable(VariableElement element) { | 1335 ConstantExpression getConstantForVariable(VariableElement element) { |
| 1291 ConstantExpression constant = | 1336 ConstantExpression constant = |
| 1292 compiler.backend.constants.getConstantForVariable(element); | 1337 compiler.backend.constants.getConstantForVariable(element); |
| 1293 assert(invariant(element, constant != null, | 1338 assert(invariant(element, constant != null, |
| 1294 message: 'No constant computed for $element')); | 1339 message: 'No constant computed for $element')); |
| 1295 return constant; | 1340 return constant; |
| 1296 } | 1341 } |
| 1297 | 1342 |
| 1298 ir.Primitive visitLiteralList(ast.LiteralList node) { | 1343 ir.Primitive visitLiteralList(ast.LiteralList node) { |
| 1299 assert(isOpen); | 1344 assert(irBuilder.isOpen); |
| 1300 if (node.isConst) { | 1345 if (node.isConst) { |
| 1301 return translateConstant(node); | 1346 return translateConstant(node); |
| 1302 } | 1347 } |
| 1303 List<ir.Primitive> values = node.elements.nodes.mapToList(visit); | 1348 List<ir.Primitive> values = node.elements.nodes.mapToList(visit); |
| 1304 GenericType type = elements.getType(node); | 1349 GenericType type = elements.getType(node); |
| 1305 ir.Primitive result = new ir.LiteralList(type, values); | 1350 ir.Primitive result = new ir.LiteralList(type, values); |
| 1306 add(new ir.LetPrim(result)); | 1351 irBuilder.add(new ir.LetPrim(result)); |
| 1307 return result; | 1352 return result; |
| 1308 } | 1353 } |
| 1309 | 1354 |
| 1310 ir.Primitive visitLiteralMap(ast.LiteralMap node) { | 1355 ir.Primitive visitLiteralMap(ast.LiteralMap node) { |
| 1311 assert(isOpen); | 1356 assert(irBuilder.isOpen); |
| 1312 if (node.isConst) { | 1357 if (node.isConst) { |
| 1313 return translateConstant(node); | 1358 return translateConstant(node); |
| 1314 } | 1359 } |
| 1315 List<ir.Primitive> keys = new List<ir.Primitive>(); | 1360 List<ir.Primitive> keys = new List<ir.Primitive>(); |
| 1316 List<ir.Primitive> values = new List<ir.Primitive>(); | 1361 List<ir.Primitive> values = new List<ir.Primitive>(); |
| 1317 node.entries.nodes.forEach((ast.LiteralMapEntry node) { | 1362 node.entries.nodes.forEach((ast.LiteralMapEntry node) { |
| 1318 keys.add(visit(node.key)); | 1363 keys.add(visit(node.key)); |
| 1319 values.add(visit(node.value)); | 1364 values.add(visit(node.value)); |
| 1320 }); | 1365 }); |
| 1321 GenericType type = elements.getType(node); | 1366 GenericType type = elements.getType(node); |
| 1322 ir.Primitive result = new ir.LiteralMap(type, keys, values); | 1367 ir.Primitive result = new ir.LiteralMap(type, keys, values); |
| 1323 add(new ir.LetPrim(result)); | 1368 irBuilder.add(new ir.LetPrim(result)); |
| 1324 return result; | 1369 return result; |
| 1325 } | 1370 } |
| 1326 | 1371 |
| 1327 ir.Primitive visitLiteralSymbol(ast.LiteralSymbol node) { | 1372 ir.Primitive visitLiteralSymbol(ast.LiteralSymbol node) { |
| 1328 assert(isOpen); | 1373 assert(irBuilder.isOpen); |
| 1329 return translateConstant(node); | 1374 return translateConstant(node); |
| 1330 } | 1375 } |
| 1331 | 1376 |
| 1332 ir.Primitive visitIdentifier(ast.Identifier node) { | 1377 ir.Primitive visitIdentifier(ast.Identifier node) { |
| 1333 assert(isOpen); | 1378 assert(irBuilder.isOpen); |
| 1334 // "this" is the only identifier that should be met by the visitor. | 1379 // "this" is the only identifier that should be met by the visitor. |
| 1335 assert(node.isThis()); | 1380 assert(node.isThis()); |
| 1336 return lookupThis(); | 1381 return lookupThis(); |
| 1337 } | 1382 } |
| 1338 | 1383 |
| 1339 ir.Primitive visitParenthesizedExpression( | 1384 ir.Primitive visitParenthesizedExpression( |
| 1340 ast.ParenthesizedExpression node) { | 1385 ast.ParenthesizedExpression node) { |
| 1341 assert(isOpen); | 1386 assert(irBuilder.isOpen); |
| 1342 return visit(node.expression); | 1387 return visit(node.expression); |
| 1343 } | 1388 } |
| 1344 | 1389 |
| 1345 // Stores the result of visiting a CascadeReceiver, so we can return it from | 1390 // Stores the result of visiting a CascadeReceiver, so we can return it from |
| 1346 // its enclosing Cascade. | 1391 // its enclosing Cascade. |
| 1347 ir.Primitive _currentCascadeReceiver; | 1392 ir.Primitive _currentCascadeReceiver; |
| 1348 | 1393 |
| 1349 ir.Primitive visitCascadeReceiver(ast.CascadeReceiver node) { | 1394 ir.Primitive visitCascadeReceiver(ast.CascadeReceiver node) { |
| 1350 assert(isOpen); | 1395 assert(irBuilder.isOpen); |
| 1351 return _currentCascadeReceiver = visit(node.expression); | 1396 return _currentCascadeReceiver = visit(node.expression); |
| 1352 } | 1397 } |
| 1353 | 1398 |
| 1354 ir.Primitive visitCascade(ast.Cascade node) { | 1399 ir.Primitive visitCascade(ast.Cascade node) { |
| 1355 assert(isOpen); | 1400 assert(irBuilder.isOpen); |
| 1356 var oldCascadeReceiver = _currentCascadeReceiver; | 1401 var oldCascadeReceiver = _currentCascadeReceiver; |
| 1357 // Throw away the result of visiting the expression. | 1402 // Throw away the result of visiting the expression. |
| 1358 // Instead we return the result of visiting the CascadeReceiver. | 1403 // Instead we return the result of visiting the CascadeReceiver. |
| 1359 this.visit(node.expression); | 1404 this.visit(node.expression); |
| 1360 ir.Primitive receiver = _currentCascadeReceiver; | 1405 ir.Primitive receiver = _currentCascadeReceiver; |
| 1361 _currentCascadeReceiver = oldCascadeReceiver; | 1406 _currentCascadeReceiver = oldCascadeReceiver; |
| 1362 return receiver; | 1407 return receiver; |
| 1363 } | 1408 } |
| 1364 | 1409 |
| 1365 ir.Primitive lookupThis() { | 1410 ir.Primitive lookupThis() { |
| 1366 ir.Primitive result = new ir.This(); | 1411 ir.Primitive result = new ir.This(); |
| 1367 add(new ir.LetPrim(result)); | 1412 irBuilder.add(new ir.LetPrim(result)); |
| 1368 return result; | 1413 return result; |
| 1369 } | 1414 } |
| 1370 | 1415 |
| 1371 // ==== Sends ==== | 1416 // ==== Sends ==== |
| 1372 ir.Primitive visitAssert(ast.Send node) { | 1417 ir.Primitive visitAssert(ast.Send node) { |
| 1373 assert(isOpen); | 1418 assert(irBuilder.isOpen); |
| 1374 return giveup(node, 'Assert'); | 1419 return giveup(node, 'Assert'); |
| 1375 } | 1420 } |
| 1376 | 1421 |
| 1377 ir.Primitive visitNamedArgument(ast.NamedArgument node) { | 1422 ir.Primitive visitNamedArgument(ast.NamedArgument node) { |
| 1378 assert(isOpen); | 1423 assert(irBuilder.isOpen); |
| 1379 return visit(node.expression); | 1424 return visit(node.expression); |
| 1380 } | 1425 } |
| 1381 | 1426 |
| 1382 ir.Primitive translateClosureCall(ir.Primitive receiver, | 1427 ir.Primitive translateClosureCall(ir.Primitive receiver, |
| 1383 Selector closureSelector, | 1428 Selector closureSelector, |
| 1384 ast.NodeList arguments) { | 1429 ast.NodeList arguments) { |
| 1385 Selector namedCallSelector = new Selector(closureSelector.kind, | 1430 Selector namedCallSelector = new Selector(closureSelector.kind, |
| 1386 "call", | 1431 "call", |
| 1387 closureSelector.library, | 1432 closureSelector.library, |
| 1388 closureSelector.argumentCount, | 1433 closureSelector.argumentCount, |
| 1389 closureSelector.namedArguments); | 1434 closureSelector.namedArguments); |
| 1390 List<ir.Primitive> args = arguments.nodes.mapToList(visit, growable:false); | 1435 List<ir.Primitive> args = arguments.nodes.mapToList(visit, growable:false); |
| 1391 return continueWithExpression( | 1436 return irBuilder.continueWithExpression( |
| 1392 (k) => new ir.InvokeMethod(receiver, namedCallSelector, k, args)); | 1437 (k) => new ir.InvokeMethod(receiver, namedCallSelector, k, args)); |
| 1393 } | 1438 } |
| 1394 | 1439 |
| 1395 ir.Primitive visitClosureSend(ast.Send node) { | 1440 ir.Primitive visitClosureSend(ast.Send node) { |
| 1396 assert(isOpen); | 1441 assert(irBuilder.isOpen); |
| 1397 Element element = elements[node]; | 1442 Element element = elements[node]; |
| 1398 ir.Primitive closureTarget; | 1443 ir.Primitive closureTarget; |
| 1399 if (element == null) { | 1444 if (element == null) { |
| 1400 closureTarget = visit(node.selector); | 1445 closureTarget = visit(node.selector); |
| 1401 } else if (isClosureVariable(element)) { | 1446 } else if (isClosureVariable(element)) { |
| 1402 LocalElement local = element; | 1447 LocalElement local = element; |
| 1403 closureTarget = new ir.GetClosureVariable(local); | 1448 closureTarget = new ir.GetClosureVariable(local); |
| 1404 add(new ir.LetPrim(closureTarget)); | 1449 irBuilder.add(new ir.LetPrim(closureTarget)); |
| 1405 } else { | 1450 } else { |
| 1406 assert(Elements.isLocal(element)); | 1451 assert(Elements.isLocal(element)); |
| 1407 closureTarget = environment.lookup(element); | 1452 closureTarget = irBuilder.environment.lookup(element); |
| 1408 } | 1453 } |
| 1409 Selector closureSelector = elements.getSelector(node); | 1454 Selector closureSelector = elements.getSelector(node); |
| 1410 return translateClosureCall(closureTarget, closureSelector, | 1455 return translateClosureCall(closureTarget, closureSelector, |
| 1411 node.argumentsNode); | 1456 node.argumentsNode); |
| 1412 } | 1457 } |
| 1413 | 1458 |
| 1414 /// If [node] is null, returns this. | 1459 /// If [node] is null, returns this. |
| 1415 /// If [node] is super, returns null (for special handling) | 1460 /// If [node] is super, returns null (for special handling) |
| 1416 /// Otherwise visits [node] and returns the result. | 1461 /// Otherwise visits [node] and returns the result. |
| 1417 ir.Primitive visitReceiver(ast.Expression node) { | 1462 ir.Primitive visitReceiver(ast.Expression node) { |
| 1418 if (node == null) return lookupThis(); | 1463 if (node == null) return lookupThis(); |
| 1419 if (node.isSuper()) return null; | 1464 if (node.isSuper()) return null; |
| 1420 return visit(node); | 1465 return visit(node); |
| 1421 } | 1466 } |
| 1422 | 1467 |
| 1423 /// Makes an [InvokeMethod] unless [node.receiver.isSuper()], in that case | 1468 /// Makes an [InvokeMethod] unless [node.receiver.isSuper()], in that case |
| 1424 /// makes an [InvokeSuperMethod] ignoring [receiver]. | 1469 /// makes an [InvokeSuperMethod] ignoring [receiver]. |
| 1425 ir.Expression createDynamicInvoke(ast.Send node, | 1470 ir.Expression createDynamicInvoke(ast.Send node, |
| 1426 Selector selector, | 1471 Selector selector, |
| 1427 ir.Definition receiver, | 1472 ir.Definition receiver, |
| 1428 ir.Continuation k, | 1473 ir.Continuation k, |
| 1429 List<ir.Definition> arguments) { | 1474 List<ir.Definition> arguments) { |
| 1430 return node != null && node.receiver != null && node.receiver.isSuper() | 1475 return node != null && node.receiver != null && node.receiver.isSuper() |
| 1431 ? new ir.InvokeSuperMethod(selector, k, arguments) | 1476 ? new ir.InvokeSuperMethod(selector, k, arguments) |
| 1432 : new ir.InvokeMethod(receiver, selector, k, arguments); | 1477 : new ir.InvokeMethod(receiver, selector, k, arguments); |
| 1433 } | 1478 } |
| 1434 | 1479 |
| 1435 ir.Primitive visitDynamicSend(ast.Send node) { | 1480 ir.Primitive visitDynamicSend(ast.Send node) { |
| 1436 assert(isOpen); | 1481 assert(irBuilder.isOpen); |
| 1437 Selector selector = elements.getSelector(node); | 1482 Selector selector = elements.getSelector(node); |
| 1438 ir.Primitive receiver = visitReceiver(node.receiver); | 1483 ir.Primitive receiver = visitReceiver(node.receiver); |
| 1439 List<ir.Primitive> arguments = new List<ir.Primitive>(); | 1484 List<ir.Primitive> arguments = new List<ir.Primitive>(); |
| 1440 for (ast.Node n in node.arguments) { | 1485 for (ast.Node n in node.arguments) { |
| 1441 arguments.add(visit(n)); | 1486 arguments.add(visit(n)); |
| 1442 } | 1487 } |
| 1443 return continueWithExpression( | 1488 return irBuilder.continueWithExpression( |
| 1444 (k) => createDynamicInvoke(node, selector, receiver, k, arguments)); | 1489 (k) => createDynamicInvoke(node, selector, receiver, k, arguments)); |
| 1445 } | 1490 } |
| 1446 | 1491 |
| 1447 _GetterElements translateGetter(ast.Send node, Selector selector) { | 1492 _GetterElements translateGetter(ast.Send node, Selector selector) { |
| 1448 Element element = elements[node]; | 1493 Element element = elements[node]; |
| 1449 ir.Primitive result; | 1494 ir.Primitive result; |
| 1450 ir.Primitive receiver; | 1495 ir.Primitive receiver; |
| 1451 ir.Primitive index; | 1496 ir.Primitive index; |
| 1452 | 1497 |
| 1453 if (element != null && element.isConst) { | 1498 if (element != null && element.isConst) { |
| 1454 // Reference to constant local, top-level or static field | 1499 // Reference to constant local, top-level or static field |
| 1455 result = translateConstant(node); | 1500 result = translateConstant(node); |
| 1456 } else if (isClosureVariable(element)) { | 1501 } else if (isClosureVariable(element)) { |
| 1457 LocalElement local = element; | 1502 LocalElement local = element; |
| 1458 result = new ir.GetClosureVariable(local); | 1503 result = new ir.GetClosureVariable(local); |
| 1459 add(new ir.LetPrim(result)); | 1504 irBuilder.add(new ir.LetPrim(result)); |
| 1460 } else if (Elements.isLocal(element)) { | 1505 } else if (Elements.isLocal(element)) { |
| 1461 // Reference to local variable | 1506 // Reference to local variable |
| 1462 result = buildGetLocal(element); | 1507 result = irBuilder.buildGetLocal(element); |
| 1463 } else if (element == null || | 1508 } else if (element == null || |
| 1464 Elements.isInstanceField(element) || | 1509 Elements.isInstanceField(element) || |
| 1465 Elements.isInstanceMethod(element) || | 1510 Elements.isInstanceMethod(element) || |
| 1466 selector.isIndex || | 1511 selector.isIndex || |
| 1467 // TODO(johnniwinther): clean up semantics of resolution. | 1512 // TODO(johnniwinther): clean up semantics of resolution. |
| 1468 node.isSuperCall) { | 1513 node.isSuperCall) { |
| 1469 // Dynamic dispatch to a getter. Sometimes resolution will suggest a | 1514 // Dynamic dispatch to a getter. Sometimes resolution will suggest a |
| 1470 // target element, but in these cases we must still emit a dynamic | 1515 // target element, but in these cases we must still emit a dynamic |
| 1471 // dispatch. The target element may be an instance method in case we are | 1516 // dispatch. The target element may be an instance method in case we are |
| 1472 // converting a method to a function object. | 1517 // converting a method to a function object. |
| 1473 | 1518 |
| 1474 receiver = visitReceiver(node.receiver); | 1519 receiver = visitReceiver(node.receiver); |
| 1475 List<ir.Primitive> arguments = new List<ir.Primitive>(); | 1520 List<ir.Primitive> arguments = new List<ir.Primitive>(); |
| 1476 if (selector.isIndex) { | 1521 if (selector.isIndex) { |
| 1477 index = visit(node.arguments.head); | 1522 index = visit(node.arguments.head); |
| 1478 arguments.add(index); | 1523 arguments.add(index); |
| 1479 } | 1524 } |
| 1480 | 1525 |
| 1481 assert(selector.kind == SelectorKind.GETTER || | 1526 assert(selector.kind == SelectorKind.GETTER || |
| 1482 selector.kind == SelectorKind.INDEX); | 1527 selector.kind == SelectorKind.INDEX); |
| 1483 result = continueWithExpression( | 1528 result = irBuilder.continueWithExpression( |
| 1484 (k) => createDynamicInvoke(node, selector, receiver, k, arguments)); | 1529 (k) => createDynamicInvoke(node, selector, receiver, k, arguments)); |
| 1485 } else if (element.isField || element.isGetter || element.isErroneous || | 1530 } else if (element.isField || element.isGetter || element.isErroneous || |
| 1486 element.isSetter) { | 1531 element.isSetter) { |
| 1487 // TODO(johnniwinther): Change handling of setter selectors. | 1532 // TODO(johnniwinther): Change handling of setter selectors. |
| 1488 // Access to a static field or getter (non-static case handled above). | 1533 // Access to a static field or getter (non-static case handled above). |
| 1489 // Even if there is only a setter, we compile as if it was a getter, | 1534 // Even if there is only a setter, we compile as if it was a getter, |
| 1490 // so the vm can fail at runtime. | 1535 // so the vm can fail at runtime. |
| 1491 assert(selector.kind == SelectorKind.GETTER || | 1536 assert(selector.kind == SelectorKind.GETTER || |
| 1492 selector.kind == SelectorKind.SETTER); | 1537 selector.kind == SelectorKind.SETTER); |
| 1493 result = buildGetStatic(element, selector); | 1538 result = irBuilder.buildGetStatic(element, selector); |
| 1494 } else if (Elements.isStaticOrTopLevelFunction(element)) { | 1539 } else if (Elements.isStaticOrTopLevelFunction(element)) { |
| 1495 // Convert a top-level or static function to a function object. | 1540 // Convert a top-level or static function to a function object. |
| 1496 result = translateConstant(node); | 1541 result = translateConstant(node); |
| 1497 } else { | 1542 } else { |
| 1498 throw "Unexpected SendSet getter: $node, $element"; | 1543 throw "Unexpected SendSet getter: $node, $element"; |
| 1499 } | 1544 } |
| 1500 return new _GetterElements( | 1545 return new _GetterElements( |
| 1501 result: result,index: index, receiver: receiver); | 1546 result: result,index: index, receiver: receiver); |
| 1502 } | 1547 } |
| 1503 | 1548 |
| 1504 ir.Primitive visitGetterSend(ast.Send node) { | 1549 ir.Primitive visitGetterSend(ast.Send node) { |
| 1505 assert(isOpen); | 1550 assert(irBuilder.isOpen); |
| 1506 return translateGetter(node, elements.getSelector(node)).result; | 1551 return translateGetter(node, elements.getSelector(node)).result; |
| 1507 | 1552 |
| 1508 } | 1553 } |
| 1509 | 1554 |
| 1510 ir.Primitive buildNegation(ir.Primitive condition) { | 1555 ir.Primitive buildNegation(ir.Primitive condition) { |
| 1511 // ! e is translated as e ? false : true | 1556 // ! e is translated as e ? false : true |
| 1512 | 1557 |
| 1513 // Add a continuation parameter for the result of the expression. | 1558 // Add a continuation parameter for the result of the expression. |
| 1514 ir.Parameter resultParameter = new ir.Parameter(null); | 1559 ir.Parameter resultParameter = new ir.Parameter(null); |
| 1515 | 1560 |
| 1516 ir.Continuation joinContinuation = new ir.Continuation([resultParameter]); | 1561 ir.Continuation joinContinuation = new ir.Continuation([resultParameter]); |
| 1517 ir.Continuation thenContinuation = new ir.Continuation([]); | 1562 ir.Continuation thenContinuation = new ir.Continuation([]); |
| 1518 ir.Continuation elseContinuation = new ir.Continuation([]); | 1563 ir.Continuation elseContinuation = new ir.Continuation([]); |
| 1519 | 1564 |
| 1520 ir.Constant trueConstant = makePrimConst(constantSystem.createBool(true)); | 1565 ir.Constant trueConstant = irBuilder.makePrimConst( |
| 1521 ir.Constant falseConstant = makePrimConst(constantSystem.createBool(false)); | 1566 irBuilder.state.constantSystem.createBool(true)); |
| 1567 ir.Constant falseConstant = irBuilder.makePrimConst( | |
| 1568 irBuilder.state.constantSystem.createBool(false)); | |
| 1522 | 1569 |
| 1523 thenContinuation.body = new ir.LetPrim(falseConstant) | 1570 thenContinuation.body = new ir.LetPrim(falseConstant) |
| 1524 ..plug(new ir.InvokeContinuation(joinContinuation, [falseConstant])); | 1571 ..plug(new ir.InvokeContinuation(joinContinuation, [falseConstant])); |
| 1525 elseContinuation.body = new ir.LetPrim(trueConstant) | 1572 elseContinuation.body = new ir.LetPrim(trueConstant) |
| 1526 ..plug(new ir.InvokeContinuation(joinContinuation, [trueConstant])); | 1573 ..plug(new ir.InvokeContinuation(joinContinuation, [trueConstant])); |
| 1527 | 1574 |
| 1528 add(new ir.LetCont(joinContinuation, | 1575 irBuilder.add(new ir.LetCont(joinContinuation, |
| 1529 new ir.LetCont(thenContinuation, | 1576 new ir.LetCont(thenContinuation, |
| 1530 new ir.LetCont(elseContinuation, | 1577 new ir.LetCont(elseContinuation, |
| 1531 new ir.Branch(new ir.IsTrue(condition), | 1578 new ir.Branch(new ir.IsTrue(condition), |
| 1532 thenContinuation, | 1579 thenContinuation, |
| 1533 elseContinuation))))); | 1580 elseContinuation))))); |
| 1534 return resultParameter; | 1581 return resultParameter; |
| 1535 } | 1582 } |
| 1536 | 1583 |
| 1537 ir.Primitive translateLogicalOperator(ast.Operator op, | 1584 ir.Primitive translateLogicalOperator(ast.Operator op, |
| 1538 ast.Expression left, | 1585 ast.Expression left, |
| 1539 ast.Expression right) { | 1586 ast.Expression right) { |
| 1540 // e0 && e1 is translated as if e0 ? (e1 == true) : false. | 1587 // e0 && e1 is translated as if e0 ? (e1 == true) : false. |
| 1541 // e0 || e1 is translated as if e0 ? true : (e1 == true). | 1588 // e0 || e1 is translated as if e0 ? true : (e1 == true). |
| 1542 // The translation must convert both e0 and e1 to booleans and handle | 1589 // The translation must convert both e0 and e1 to booleans and handle |
| 1543 // local variable assignments in e1. | 1590 // local variable assignments in e1. |
| 1544 | 1591 |
| 1545 ir.Primitive leftValue = visit(left); | 1592 ir.Primitive leftValue = visit(left); |
| 1546 IrBuilderVisitor rightBuilder = new IrBuilderVisitor.delimited(this); | 1593 IrBuilder rightBuilder = new IrBuilder.delimited(irBuilder); |
| 1547 ir.Primitive rightValue = rightBuilder.visit(right); | 1594 ir.Primitive rightValue = |
| 1595 withBuilder(rightBuilder, () => visit(right)); | |
| 1548 // A dummy empty target for the branch on the left subexpression branch. | 1596 // A dummy empty target for the branch on the left subexpression branch. |
| 1549 // This enables using the same infrastructure for join-point continuations | 1597 // This enables using the same infrastructure for join-point continuations |
| 1550 // as in visitIf and visitConditional. It will hold a definition of the | 1598 // as in visitIf and visitConditional. It will hold a definition of the |
| 1551 // appropriate constant and an invocation of the join-point continuation. | 1599 // appropriate constant and an invocation of the join-point continuation. |
| 1552 IrBuilderVisitor emptyBuilder = new IrBuilderVisitor.delimited(this); | 1600 IrBuilder emptyBuilder = new IrBuilder.delimited(irBuilder); |
| 1553 // Dummy empty targets for right true and right false. They hold | 1601 // Dummy empty targets for right true and right false. They hold |
| 1554 // definitions of the appropriate constant and an invocation of the | 1602 // definitions of the appropriate constant and an invocation of the |
| 1555 // join-point continuation. | 1603 // join-point continuation. |
| 1556 IrBuilderVisitor rightTrueBuilder = new IrBuilderVisitor.delimited(rightBuil der); | 1604 IrBuilder rightTrueBuilder = new IrBuilder.delimited(rightBuilder); |
| 1557 IrBuilderVisitor rightFalseBuilder = new IrBuilderVisitor.delimited(rightBui lder); | 1605 IrBuilder rightFalseBuilder = new IrBuilder.delimited(rightBuilder); |
| 1558 | 1606 |
| 1559 // If we don't evaluate the right subexpression, the value of the whole | 1607 // If we don't evaluate the right subexpression, the value of the whole |
| 1560 // expression is this constant. | 1608 // expression is this constant. |
| 1561 ir.Constant leftBool = emptyBuilder.makePrimConst( | 1609 ir.Constant leftBool = emptyBuilder.makePrimConst( |
| 1562 constantSystem.createBool(op.source == '||')); | 1610 emptyBuilder.state.constantSystem.createBool(op.source == '||')); |
| 1563 // If we do evaluate the right subexpression, the value of the expression | 1611 // If we do evaluate the right subexpression, the value of the expression |
| 1564 // is a true or false constant. | 1612 // is a true or false constant. |
| 1565 ir.Constant rightTrue = rightTrueBuilder.makePrimConst( | 1613 ir.Constant rightTrue = rightTrueBuilder.makePrimConst( |
| 1566 constantSystem.createBool(true)); | 1614 rightTrueBuilder.state.constantSystem.createBool(true)); |
| 1567 ir.Constant rightFalse = rightFalseBuilder.makePrimConst( | 1615 ir.Constant rightFalse = rightFalseBuilder.makePrimConst( |
| 1568 constantSystem.createBool(false)); | 1616 rightFalseBuilder.state.constantSystem.createBool(false)); |
| 1569 emptyBuilder.add(new ir.LetPrim(leftBool)); | 1617 emptyBuilder.add(new ir.LetPrim(leftBool)); |
| 1570 rightTrueBuilder.add(new ir.LetPrim(rightTrue)); | 1618 rightTrueBuilder.add(new ir.LetPrim(rightTrue)); |
| 1571 rightFalseBuilder.add(new ir.LetPrim(rightFalse)); | 1619 rightFalseBuilder.add(new ir.LetPrim(rightFalse)); |
| 1572 | 1620 |
| 1573 // Treat the result values as named values in the environment, so they | 1621 // Treat the result values as named values in the environment, so they |
| 1574 // will be treated as arguments to the join-point continuation. | 1622 // will be treated as arguments to the join-point continuation. |
| 1575 assert(environment.length == emptyBuilder.environment.length); | 1623 assert(irBuilder.environment.length == emptyBuilder.environment.length); |
| 1576 assert(environment.length == rightTrueBuilder.environment.length); | 1624 assert(irBuilder.environment.length == rightTrueBuilder.environment.length); |
| 1577 assert(environment.length == rightFalseBuilder.environment.length); | 1625 assert(irBuilder.environment.length == |
| 1626 rightFalseBuilder.environment.length); | |
| 1578 emptyBuilder.environment.extend(null, leftBool); | 1627 emptyBuilder.environment.extend(null, leftBool); |
| 1579 rightTrueBuilder.environment.extend(null, rightTrue); | 1628 rightTrueBuilder.environment.extend(null, rightTrue); |
| 1580 rightFalseBuilder.environment.extend(null, rightFalse); | 1629 rightFalseBuilder.environment.extend(null, rightFalse); |
| 1581 | 1630 |
| 1582 // Wire up two continuations for the left subexpression, two continuations | 1631 // Wire up two continuations for the left subexpression, two continuations |
| 1583 // for the right subexpression, and a three-way join continuation. | 1632 // for the right subexpression, and a three-way join continuation. |
| 1584 JumpCollector jumps = new JumpCollector(null); | 1633 JumpCollector jumps = new JumpCollector(null); |
| 1585 jumps.addJump(emptyBuilder); | 1634 jumps.addJump(emptyBuilder); |
| 1586 jumps.addJump(rightTrueBuilder); | 1635 jumps.addJump(rightTrueBuilder); |
| 1587 jumps.addJump(rightFalseBuilder); | 1636 jumps.addJump(rightFalseBuilder); |
| 1588 ir.Continuation joinContinuation = | 1637 ir.Continuation joinContinuation = |
| 1589 createJoin(environment.length + 1, jumps); | 1638 createJoin(irBuilder.environment.length + 1, jumps); |
| 1590 ir.Continuation leftTrueContinuation = new ir.Continuation([]); | 1639 ir.Continuation leftTrueContinuation = new ir.Continuation([]); |
| 1591 ir.Continuation leftFalseContinuation = new ir.Continuation([]); | 1640 ir.Continuation leftFalseContinuation = new ir.Continuation([]); |
| 1592 ir.Continuation rightTrueContinuation = new ir.Continuation([]); | 1641 ir.Continuation rightTrueContinuation = new ir.Continuation([]); |
| 1593 ir.Continuation rightFalseContinuation = new ir.Continuation([]); | 1642 ir.Continuation rightFalseContinuation = new ir.Continuation([]); |
| 1594 rightTrueContinuation.body = rightTrueBuilder._root; | 1643 rightTrueContinuation.body = rightTrueBuilder._root; |
| 1595 rightFalseContinuation.body = rightFalseBuilder._root; | 1644 rightFalseContinuation.body = rightFalseBuilder._root; |
| 1596 // The right subexpression has two continuations. | 1645 // The right subexpression has two continuations. |
| 1597 rightBuilder.add( | 1646 rightBuilder.add( |
| 1598 new ir.LetCont(rightTrueContinuation, | 1647 new ir.LetCont(rightTrueContinuation, |
| 1599 new ir.LetCont(rightFalseContinuation, | 1648 new ir.LetCont(rightFalseContinuation, |
| 1600 new ir.Branch(new ir.IsTrue(rightValue), | 1649 new ir.Branch(new ir.IsTrue(rightValue), |
| 1601 rightTrueContinuation, | 1650 rightTrueContinuation, |
| 1602 rightFalseContinuation)))); | 1651 rightFalseContinuation)))); |
| 1603 // Depending on the operator, the left subexpression's continuations are | 1652 // Depending on the operator, the left subexpression's continuations are |
| 1604 // either the right subexpression or an invocation of the join-point | 1653 // either the right subexpression or an invocation of the join-point |
| 1605 // continuation. | 1654 // continuation. |
| 1606 if (op.source == '&&') { | 1655 if (op.source == '&&') { |
| 1607 leftTrueContinuation.body = rightBuilder._root; | 1656 leftTrueContinuation.body = rightBuilder._root; |
| 1608 leftFalseContinuation.body = emptyBuilder._root; | 1657 leftFalseContinuation.body = emptyBuilder._root; |
| 1609 } else { | 1658 } else { |
| 1610 leftTrueContinuation.body = emptyBuilder._root; | 1659 leftTrueContinuation.body = emptyBuilder._root; |
| 1611 leftFalseContinuation.body = rightBuilder._root; | 1660 leftFalseContinuation.body = rightBuilder._root; |
| 1612 } | 1661 } |
| 1613 | 1662 |
| 1614 add(new ir.LetCont(joinContinuation, | 1663 irBuilder.add(new ir.LetCont(joinContinuation, |
| 1615 new ir.LetCont(leftTrueContinuation, | 1664 new ir.LetCont(leftTrueContinuation, |
| 1616 new ir.LetCont(leftFalseContinuation, | 1665 new ir.LetCont(leftFalseContinuation, |
| 1617 new ir.Branch(new ir.IsTrue(leftValue), | 1666 new ir.Branch(new ir.IsTrue(leftValue), |
| 1618 leftTrueContinuation, | 1667 leftTrueContinuation, |
| 1619 leftFalseContinuation))))); | 1668 leftFalseContinuation))))); |
| 1620 // There is always a join parameter for the result value, because it | 1669 // There is always a join parameter for the result value, because it |
| 1621 // is different on at least two paths. | 1670 // is different on at least two paths. |
| 1622 return joinContinuation.parameters.last; | 1671 return joinContinuation.parameters.last; |
| 1623 } | 1672 } |
| 1624 | 1673 |
| 1625 ir.Primitive visitOperatorSend(ast.Send node) { | 1674 ir.Primitive visitOperatorSend(ast.Send node) { |
| 1626 assert(isOpen); | 1675 assert(irBuilder.isOpen); |
| 1627 ast.Operator op = node.selector; | 1676 ast.Operator op = node.selector; |
| 1628 if (isUserDefinableOperator(op.source)) { | 1677 if (isUserDefinableOperator(op.source)) { |
| 1629 return visitDynamicSend(node); | 1678 return visitDynamicSend(node); |
| 1630 } | 1679 } |
| 1631 if (op.source == '&&' || op.source == '||') { | 1680 if (op.source == '&&' || op.source == '||') { |
| 1632 assert(node.receiver != null); | 1681 assert(node.receiver != null); |
| 1633 assert(!node.arguments.isEmpty); | 1682 assert(!node.arguments.isEmpty); |
| 1634 assert(node.arguments.tail.isEmpty); | 1683 assert(node.arguments.tail.isEmpty); |
| 1635 return translateLogicalOperator(op, node.receiver, node.arguments.head); | 1684 return translateLogicalOperator(op, node.receiver, node.arguments.head); |
| 1636 } | 1685 } |
| 1637 if (op.source == "!") { | 1686 if (op.source == "!") { |
| 1638 assert(node.receiver != null); | 1687 assert(node.receiver != null); |
| 1639 assert(node.arguments.isEmpty); | 1688 assert(node.arguments.isEmpty); |
| 1640 return buildNegation(visit(node.receiver)); | 1689 return buildNegation(visit(node.receiver)); |
| 1641 } | 1690 } |
| 1642 if (op.source == "!=") { | 1691 if (op.source == "!=") { |
| 1643 assert(node.receiver != null); | 1692 assert(node.receiver != null); |
| 1644 assert(!node.arguments.isEmpty); | 1693 assert(!node.arguments.isEmpty); |
| 1645 assert(node.arguments.tail.isEmpty); | 1694 assert(node.arguments.tail.isEmpty); |
| 1646 return buildNegation(visitDynamicSend(node)); | 1695 return buildNegation(visitDynamicSend(node)); |
| 1647 } | 1696 } |
| 1648 assert(invariant(node, op.source == "is" || op.source == "as", | 1697 assert(invariant(node, op.source == "is" || op.source == "as", |
| 1649 message: "unexpected operator $op")); | 1698 message: "unexpected operator $op")); |
| 1650 DartType type = elements.getType(node.typeAnnotationFromIsCheckOrCast); | 1699 DartType type = elements.getType(node.typeAnnotationFromIsCheckOrCast); |
| 1651 ir.Primitive receiver = visit(node.receiver); | 1700 ir.Primitive receiver = visit(node.receiver); |
| 1652 ir.Primitive check = continueWithExpression( | 1701 ir.Primitive check = irBuilder.continueWithExpression( |
| 1653 (k) => new ir.TypeOperator(op.source, receiver, type, k)); | 1702 (k) => new ir.TypeOperator(op.source, receiver, type, k)); |
| 1654 return node.isIsNotCheck ? buildNegation(check) : check; | 1703 return node.isIsNotCheck ? buildNegation(check) : check; |
| 1655 } | 1704 } |
| 1656 | 1705 |
| 1657 // Build(StaticSend(f, arguments), C) = C[C'[InvokeStatic(f, xs)]] | 1706 // Build(StaticSend(f, arguments), C) = C[C'[InvokeStatic(f, xs)]] |
| 1658 // where (C', xs) = arguments.fold(Build, C) | 1707 // where (C', xs) = arguments.fold(Build, C) |
| 1659 ir.Primitive visitStaticSend(ast.Send node) { | 1708 ir.Primitive visitStaticSend(ast.Send node) { |
| 1660 assert(isOpen); | 1709 assert(irBuilder.isOpen); |
| 1661 Element element = elements[node]; | 1710 Element element = elements[node]; |
| 1662 assert(!element.isConstructor); | 1711 assert(!element.isConstructor); |
| 1663 // TODO(lry): support foreign functions. | 1712 // TODO(lry): support foreign functions. |
| 1664 if (element.isForeign(compiler.backend)) { | 1713 if (element.isForeign(compiler.backend)) { |
| 1665 return giveup(node, 'StaticSend: foreign'); | 1714 return giveup(node, 'StaticSend: foreign'); |
| 1666 } | 1715 } |
| 1667 | 1716 |
| 1668 Selector selector = elements.getSelector(node); | 1717 Selector selector = elements.getSelector(node); |
| 1669 | 1718 |
| 1670 // TODO(lry): support default arguments, need support for locals. | 1719 // TODO(lry): support default arguments, need support for locals. |
| 1671 List<ir.Definition> arguments = node.arguments.mapToList(visit, | 1720 List<ir.Definition> arguments = node.arguments.mapToList(visit, |
| 1672 growable:false); | 1721 growable:false); |
| 1673 return buildStaticInvocation(element, selector, arguments); | 1722 return irBuilder.buildStaticInvocation(element, selector, arguments); |
| 1674 } | 1723 } |
| 1675 | 1724 |
| 1676 | 1725 |
| 1677 ir.Primitive visitSuperSend(ast.Send node) { | 1726 ir.Primitive visitSuperSend(ast.Send node) { |
| 1678 assert(isOpen); | 1727 assert(irBuilder.isOpen); |
| 1679 if (node.isPropertyAccess) { | 1728 if (node.isPropertyAccess) { |
| 1680 return visitGetterSend(node); | 1729 return visitGetterSend(node); |
| 1681 } else { | 1730 } else { |
| 1682 return visitDynamicSend(node); | 1731 return visitDynamicSend(node); |
| 1683 } | 1732 } |
| 1684 } | 1733 } |
| 1685 | 1734 |
| 1686 visitTypePrefixSend(ast.Send node) { | 1735 visitTypePrefixSend(ast.Send node) { |
| 1687 compiler.internalError(node, "visitTypePrefixSend should not be called."); | 1736 compiler.internalError(node, "visitTypePrefixSend should not be called."); |
| 1688 } | 1737 } |
| 1689 | 1738 |
| 1690 ir.Primitive visitTypeLiteralSend(ast.Send node) { | 1739 ir.Primitive visitTypeLiteralSend(ast.Send node) { |
| 1691 assert(isOpen); | 1740 assert(irBuilder.isOpen); |
| 1692 // If the user is trying to invoke the type literal or variable, | 1741 // If the user is trying to invoke the type literal or variable, |
| 1693 // it must be treated as a function call. | 1742 // it must be treated as a function call. |
| 1694 if (node.argumentsNode != null) { | 1743 if (node.argumentsNode != null) { |
| 1695 // TODO(sigurdm): Handle this to match proposed semantics of issue #19725. | 1744 // TODO(sigurdm): Handle this to match proposed semantics of issue #19725. |
| 1696 return giveup(node, 'Type literal invoked as function'); | 1745 return giveup(node, 'Type literal invoked as function'); |
| 1697 } | 1746 } |
| 1698 | 1747 |
| 1699 DartType type = elements.getTypeLiteralType(node); | 1748 DartType type = elements.getTypeLiteralType(node); |
| 1700 if (type is TypeVariableType) { | 1749 if (type is TypeVariableType) { |
| 1701 ir.Primitive prim = new ir.ReifyTypeVar(type.element); | 1750 ir.Primitive prim = new ir.ReifyTypeVar(type.element); |
| 1702 add(new ir.LetPrim(prim)); | 1751 irBuilder.add(new ir.LetPrim(prim)); |
| 1703 return prim; | 1752 return prim; |
| 1704 } else { | 1753 } else { |
| 1705 return translateConstant(node); | 1754 return translateConstant(node); |
| 1706 } | 1755 } |
| 1707 } | 1756 } |
| 1708 | 1757 |
| 1709 /// True if [element] is a local variable, local function, or parameter that | 1758 /// True if [element] is a local variable, local function, or parameter that |
| 1710 /// is accessed from an inner function. Recursive self-references in a local | 1759 /// is accessed from an inner function. Recursive self-references in a local |
| 1711 /// function count as closure accesses. | 1760 /// function count as closure accesses. |
| 1712 /// | 1761 /// |
| 1713 /// If `true`, [element] is a [LocalElement]. | 1762 /// If `true`, [element] is a [LocalElement]. |
| 1714 bool isClosureVariable(Element element) { | 1763 bool isClosureVariable(Element element) { |
| 1715 return closureLocals.isClosureVariable(element); | 1764 return irBuilder.state.closureLocals.contains(element); |
| 1716 } | 1765 } |
| 1717 | 1766 |
| 1718 void setLocal(Element element, ir.Primitive valueToStore) { | 1767 void setLocal(Element element, ir.Primitive valueToStore) { |
| 1719 if (isClosureVariable(element)) { | 1768 if (isClosureVariable(element)) { |
| 1720 LocalElement local = element; | 1769 LocalElement local = element; |
| 1721 add(new ir.SetClosureVariable(local, valueToStore)); | 1770 irBuilder.add(new ir.SetClosureVariable(local, valueToStore)); |
| 1722 } else { | 1771 } else { |
| 1723 valueToStore.useElementAsHint(element); | 1772 valueToStore.useElementAsHint(element); |
| 1724 environment.update(element, valueToStore); | 1773 irBuilder.environment.update(element, valueToStore); |
| 1725 } | 1774 } |
| 1726 } | 1775 } |
| 1727 | 1776 |
| 1728 void setStatic(Element element, | 1777 void setStatic(Element element, |
| 1729 Selector selector, | 1778 Selector selector, |
| 1730 ir.Primitive valueToStore) { | 1779 ir.Primitive valueToStore) { |
| 1731 assert(element.isErroneous || element.isField || element.isSetter); | 1780 assert(element.isErroneous || element.isField || element.isSetter); |
| 1732 continueWithExpression( | 1781 irBuilder.continueWithExpression( |
| 1733 (k) => new ir.InvokeStatic(element, selector, k, [valueToStore])); | 1782 (k) => new ir.InvokeStatic(element, selector, k, [valueToStore])); |
| 1734 } | 1783 } |
| 1735 | 1784 |
| 1736 void setDynamic(ast.Node node, | 1785 void setDynamic(ast.Node node, |
| 1737 ir.Primitive receiver, Selector selector, | 1786 ir.Primitive receiver, Selector selector, |
| 1738 ir.Primitive valueToStore) { | 1787 ir.Primitive valueToStore) { |
| 1739 List<ir.Definition> arguments = [valueToStore]; | 1788 List<ir.Definition> arguments = [valueToStore]; |
| 1740 continueWithExpression( | 1789 irBuilder.continueWithExpression( |
| 1741 (k) => createDynamicInvoke(node, selector, receiver, k, arguments)); | 1790 (k) => createDynamicInvoke(node, selector, receiver, k, arguments)); |
| 1742 } | 1791 } |
| 1743 | 1792 |
| 1744 void setIndex(ast.Node node, | 1793 void setIndex(ast.Node node, |
| 1745 ir.Primitive receiver, | 1794 ir.Primitive receiver, |
| 1746 Selector selector, | 1795 Selector selector, |
| 1747 ir.Primitive index, | 1796 ir.Primitive index, |
| 1748 ir.Primitive valueToStore) { | 1797 ir.Primitive valueToStore) { |
| 1749 List<ir.Definition> arguments = [index, valueToStore]; | 1798 List<ir.Definition> arguments = [index, valueToStore]; |
| 1750 continueWithExpression( | 1799 irBuilder.continueWithExpression( |
| 1751 (k) => createDynamicInvoke(node, selector, receiver, k, arguments)); | 1800 (k) => createDynamicInvoke(node, selector, receiver, k, arguments)); |
| 1752 } | 1801 } |
| 1753 | 1802 |
| 1754 ir.Primitive visitSendSet(ast.SendSet node) { | 1803 ir.Primitive visitSendSet(ast.SendSet node) { |
| 1755 assert(isOpen); | 1804 assert(irBuilder.isOpen); |
| 1756 Element element = elements[node]; | 1805 Element element = elements[node]; |
| 1757 ast.Operator op = node.assignmentOperator; | 1806 ast.Operator op = node.assignmentOperator; |
| 1758 // For complex operators, this is the result of getting (before assigning) | 1807 // For complex operators, this is the result of getting (before assigning) |
| 1759 ir.Primitive originalValue; | 1808 ir.Primitive originalValue; |
| 1760 // For []+= style operators, this saves the index. | 1809 // For []+= style operators, this saves the index. |
| 1761 ir.Primitive index; | 1810 ir.Primitive index; |
| 1762 ir.Primitive receiver; | 1811 ir.Primitive receiver; |
| 1763 // This is what gets assigned. | 1812 // This is what gets assigned. |
| 1764 ir.Primitive valueToStore; | 1813 ir.Primitive valueToStore; |
| 1765 Selector selector = elements.getSelector(node); | 1814 Selector selector = elements.getSelector(node); |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 1796 assert(ast.Operator.COMPLEX_OPERATORS.contains(op.source)); | 1845 assert(ast.Operator.COMPLEX_OPERATORS.contains(op.source)); |
| 1797 | 1846 |
| 1798 _GetterElements getterResult = translateGetter(node, getterSelector); | 1847 _GetterElements getterResult = translateGetter(node, getterSelector); |
| 1799 index = getterResult.index; | 1848 index = getterResult.index; |
| 1800 receiver = getterResult.receiver; | 1849 receiver = getterResult.receiver; |
| 1801 originalValue = getterResult.result; | 1850 originalValue = getterResult.result; |
| 1802 | 1851 |
| 1803 // Do the modification of the value in getter. | 1852 // Do the modification of the value in getter. |
| 1804 ir.Primitive arg; | 1853 ir.Primitive arg; |
| 1805 if (ast.Operator.INCREMENT_OPERATORS.contains(op.source)) { | 1854 if (ast.Operator.INCREMENT_OPERATORS.contains(op.source)) { |
| 1806 arg = makePrimConst(constantSystem.createInt(1)); | 1855 arg = irBuilder.makePrimConst( |
| 1807 add(new ir.LetPrim(arg)); | 1856 irBuilder.state.constantSystem.createInt(1)); |
| 1857 irBuilder.add(new ir.LetPrim(arg)); | |
| 1808 } else { | 1858 } else { |
| 1809 arg = visit(getAssignArgument()); | 1859 arg = visit(getAssignArgument()); |
| 1810 } | 1860 } |
| 1811 valueToStore = new ir.Parameter(null); | 1861 valueToStore = new ir.Parameter(null); |
| 1812 ir.Continuation k = new ir.Continuation([valueToStore]); | 1862 ir.Continuation k = new ir.Continuation([valueToStore]); |
| 1813 ir.Expression invoke = | 1863 ir.Expression invoke = |
| 1814 new ir.InvokeMethod(originalValue, operatorSelector, k, [arg]); | 1864 new ir.InvokeMethod(originalValue, operatorSelector, k, [arg]); |
| 1815 add(new ir.LetCont(k, invoke)); | 1865 irBuilder.add(new ir.LetCont(k, invoke)); |
| 1816 } | 1866 } |
| 1817 | 1867 |
| 1818 if (Elements.isLocal(element)) { | 1868 if (Elements.isLocal(element)) { |
| 1819 setLocal(element, valueToStore); | 1869 setLocal(element, valueToStore); |
| 1820 } else if ((!node.isSuperCall && Elements.isErroneousElement(element)) || | 1870 } else if ((!node.isSuperCall && Elements.isErroneousElement(element)) || |
| 1821 Elements.isStaticOrTopLevel(element)) { | 1871 Elements.isStaticOrTopLevel(element)) { |
| 1822 setStatic(element, elements.getSelector(node), valueToStore); | 1872 setStatic(element, elements.getSelector(node), valueToStore); |
| 1823 } else { | 1873 } else { |
| 1824 // Setter or index-setter invocation | 1874 // Setter or index-setter invocation |
| 1825 Selector selector = elements.getSelector(node); | 1875 Selector selector = elements.getSelector(node); |
| 1826 assert(selector.kind == SelectorKind.SETTER || | 1876 assert(selector.kind == SelectorKind.SETTER || |
| 1827 selector.kind == SelectorKind.INDEX); | 1877 selector.kind == SelectorKind.INDEX); |
| 1828 if (selector.isIndexSet) { | 1878 if (selector.isIndexSet) { |
| 1829 setIndex(node, receiver, selector, index, valueToStore); | 1879 setIndex(node, receiver, selector, index, valueToStore); |
| 1830 } else { | 1880 } else { |
| 1831 setDynamic(node, receiver, selector, valueToStore); | 1881 setDynamic(node, receiver, selector, valueToStore); |
| 1832 } | 1882 } |
| 1833 } | 1883 } |
| 1834 | 1884 |
| 1835 if (node.isPostfix) { | 1885 if (node.isPostfix) { |
| 1836 assert(originalValue != null); | 1886 assert(originalValue != null); |
| 1837 return originalValue; | 1887 return originalValue; |
| 1838 } else { | 1888 } else { |
| 1839 return valueToStore; | 1889 return valueToStore; |
| 1840 } | 1890 } |
| 1841 } | 1891 } |
| 1842 | 1892 |
| 1843 ir.Primitive visitNewExpression(ast.NewExpression node) { | 1893 ir.Primitive visitNewExpression(ast.NewExpression node) { |
| 1844 assert(isOpen); | 1894 assert(irBuilder.isOpen); |
| 1845 if (node.isConst) { | 1895 if (node.isConst) { |
| 1846 return translateConstant(node); | 1896 return translateConstant(node); |
| 1847 } | 1897 } |
| 1848 FunctionElement element = elements[node.send]; | 1898 FunctionElement element = elements[node.send]; |
| 1849 Selector selector = elements.getSelector(node.send); | 1899 Selector selector = elements.getSelector(node.send); |
| 1850 ast.Node selectorNode = node.send.selector; | 1900 ast.Node selectorNode = node.send.selector; |
| 1851 DartType type = elements.getType(node); | 1901 DartType type = elements.getType(node); |
| 1852 List<ir.Primitive> args = | 1902 List<ir.Primitive> args = |
| 1853 node.send.arguments.mapToList(visit, growable:false); | 1903 node.send.arguments.mapToList(visit, growable:false); |
| 1854 return continueWithExpression( | 1904 return irBuilder.continueWithExpression( |
| 1855 (k) => new ir.InvokeConstructor(type, element,selector, k, args)); | 1905 (k) => new ir.InvokeConstructor(type, element,selector, k, args)); |
| 1856 } | 1906 } |
| 1857 | 1907 |
| 1858 ir.Primitive visitStringJuxtaposition(ast.StringJuxtaposition node) { | 1908 ir.Primitive visitStringJuxtaposition(ast.StringJuxtaposition node) { |
| 1859 assert(isOpen); | 1909 assert(irBuilder.isOpen); |
| 1860 ir.Primitive first = visit(node.first); | 1910 ir.Primitive first = visit(node.first); |
| 1861 ir.Primitive second = visit(node.second); | 1911 ir.Primitive second = visit(node.second); |
| 1862 return continueWithExpression( | 1912 return irBuilder.continueWithExpression( |
| 1863 (k) => new ir.ConcatenateStrings(k, [first, second])); | 1913 (k) => new ir.ConcatenateStrings(k, [first, second])); |
| 1864 } | 1914 } |
| 1865 | 1915 |
| 1866 ir.Primitive visitStringInterpolation(ast.StringInterpolation node) { | 1916 ir.Primitive visitStringInterpolation(ast.StringInterpolation node) { |
| 1867 assert(isOpen); | 1917 assert(irBuilder.isOpen); |
| 1868 List<ir.Primitive> arguments = []; | 1918 List<ir.Primitive> arguments = []; |
| 1869 arguments.add(visitLiteralString(node.string)); | 1919 arguments.add(visitLiteralString(node.string)); |
| 1870 var it = node.parts.iterator; | 1920 var it = node.parts.iterator; |
| 1871 while (it.moveNext()) { | 1921 while (it.moveNext()) { |
| 1872 ast.StringInterpolationPart part = it.current; | 1922 ast.StringInterpolationPart part = it.current; |
| 1873 arguments.add(visit(part.expression)); | 1923 arguments.add(visit(part.expression)); |
| 1874 arguments.add(visitLiteralString(part.string)); | 1924 arguments.add(visitLiteralString(part.string)); |
| 1875 } | 1925 } |
| 1876 return continueWithExpression( | 1926 return irBuilder.continueWithExpression( |
| 1877 (k) => new ir.ConcatenateStrings(k, arguments)); | 1927 (k) => new ir.ConcatenateStrings(k, arguments)); |
| 1878 } | 1928 } |
| 1879 | 1929 |
| 1880 ir.Primitive translateConstant(ast.Node node, [ConstantExpression constant]) { | 1930 ir.Primitive translateConstant(ast.Node node, [ConstantExpression constant]) { |
| 1881 assert(isOpen); | 1931 assert(irBuilder.isOpen); |
| 1882 if (constant == null) { | 1932 if (constant == null) { |
| 1883 constant = getConstantForNode(node); | 1933 constant = getConstantForNode(node); |
| 1884 } | 1934 } |
| 1885 ir.Primitive primitive = makeConst(constant); | 1935 ir.Primitive primitive = irBuilder.makeConst(constant); |
| 1886 add(new ir.LetPrim(primitive)); | 1936 irBuilder.add(new ir.LetPrim(primitive)); |
| 1887 return primitive; | 1937 return primitive; |
| 1888 } | 1938 } |
| 1889 | 1939 |
| 1890 ir.FunctionDefinition makeSubFunction(ast.FunctionExpression node) { | 1940 ir.FunctionDefinition makeSubFunction(ast.FunctionExpression node) { |
| 1941 // TODO(johnniwinther): Share the visitor. | |
| 1891 return new IrBuilderVisitor(elements, compiler, sourceFile) | 1942 return new IrBuilderVisitor(elements, compiler, sourceFile) |
| 1892 .buildFunctionInternal(elements[node]); | 1943 .buildFunctionInternal(elements[node]); |
| 1893 } | 1944 } |
| 1894 | 1945 |
| 1895 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) { | 1946 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) { |
| 1896 FunctionElement element = elements[node]; | 1947 FunctionElement element = elements[node]; |
| 1897 ir.FunctionDefinition inner = makeSubFunction(node); | 1948 ir.FunctionDefinition inner = makeSubFunction(node); |
| 1898 ir.CreateFunction prim = new ir.CreateFunction(inner); | 1949 ir.CreateFunction prim = new ir.CreateFunction(inner); |
| 1899 add(new ir.LetPrim(prim)); | 1950 irBuilder.add(new ir.LetPrim(prim)); |
| 1900 return prim; | 1951 return prim; |
| 1901 } | 1952 } |
| 1902 | 1953 |
| 1903 ir.Primitive visitFunctionDeclaration(ast.FunctionDeclaration node) { | 1954 ir.Primitive visitFunctionDeclaration(ast.FunctionDeclaration node) { |
| 1904 LocalFunctionElement element = elements[node.function]; | 1955 LocalFunctionElement element = elements[node.function]; |
| 1905 ir.FunctionDefinition inner = makeSubFunction(node.function); | 1956 ir.FunctionDefinition inner = makeSubFunction(node.function); |
| 1906 if (isClosureVariable(element)) { | 1957 if (isClosureVariable(element)) { |
| 1907 add(new ir.DeclareFunction(element, inner)); | 1958 irBuilder.add(new ir.DeclareFunction(element, inner)); |
| 1908 } else { | 1959 } else { |
| 1909 ir.CreateFunction prim = new ir.CreateFunction(inner); | 1960 ir.CreateFunction prim = new ir.CreateFunction(inner); |
| 1910 add(new ir.LetPrim(prim)); | 1961 irBuilder.add(new ir.LetPrim(prim)); |
| 1911 environment.extend(element, prim); | 1962 irBuilder.environment.extend(element, prim); |
| 1912 prim.useElementAsHint(element); | 1963 prim.useElementAsHint(element); |
| 1913 } | 1964 } |
| 1914 return null; | 1965 return null; |
| 1915 } | 1966 } |
| 1916 | 1967 |
| 1917 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; | 1968 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; |
| 1918 | 1969 |
| 1919 dynamic giveup(ast.Node node, [String reason]) { | 1970 dynamic giveup(ast.Node node, [String reason]) { |
| 1920 throw ABORT_IRNODE_BUILDER; | 1971 throw ABORT_IRNODE_BUILDER; |
| 1921 } | 1972 } |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1971 } | 2022 } |
| 1972 | 2023 |
| 1973 visitFunctionExpression(ast.FunctionExpression node) { | 2024 visitFunctionExpression(ast.FunctionExpression node) { |
| 1974 FunctionElement oldFunction = currentFunction; | 2025 FunctionElement oldFunction = currentFunction; |
| 1975 currentFunction = elements[node]; | 2026 currentFunction = elements[node]; |
| 1976 visit(node.body); | 2027 visit(node.body); |
| 1977 currentFunction = oldFunction; | 2028 currentFunction = oldFunction; |
| 1978 } | 2029 } |
| 1979 | 2030 |
| 1980 } | 2031 } |
| OLD | NEW |