| 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_task; | 5 library dart2js.ir_builder_task; |
| 6 | 6 |
| 7 import '../closure.dart' as closurelib; | 7 import '../closure.dart' as closure; |
| 8 import '../closure.dart' hide ClosureScope; | |
| 9 import '../common.dart'; | 8 import '../common.dart'; |
| 10 import '../common/names.dart' show | 9 import '../common/names.dart' show |
| 11 Names, | 10 Names, |
| 12 Selectors; | 11 Selectors; |
| 13 import '../common/tasks.dart' show | 12 import '../common/tasks.dart' show |
| 14 CompilerTask; | 13 CompilerTask; |
| 15 import '../compiler.dart' show | 14 import '../compiler.dart' show |
| 16 Compiler; | 15 Compiler; |
| 17 import '../constants/expressions.dart'; | 16 import '../constants/expressions.dart'; |
| 18 import '../dart_types.dart'; | 17 import '../dart_types.dart'; |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 84 return measure(() { | 83 return measure(() { |
| 85 bailoutMessage = null; | 84 bailoutMessage = null; |
| 86 | 85 |
| 87 TreeElements elementsMapping = element.resolvedAst.elements; | 86 TreeElements elementsMapping = element.resolvedAst.elements; |
| 88 element = element.implementation; | 87 element = element.implementation; |
| 89 return reporter.withCurrentElement(element, () { | 88 return reporter.withCurrentElement(element, () { |
| 90 SourceInformationBuilder sourceInformationBuilder = | 89 SourceInformationBuilder sourceInformationBuilder = |
| 91 sourceInformationStrategy.createBuilderForContext(element); | 90 sourceInformationStrategy.createBuilderForContext(element); |
| 92 | 91 |
| 93 IrBuilderVisitor builder = | 92 IrBuilderVisitor builder = |
| 94 new JsIrBuilderVisitor( | 93 new IrBuilderVisitor( |
| 95 elementsMapping, compiler, sourceInformationBuilder, | 94 elementsMapping, compiler, sourceInformationBuilder, |
| 96 typeMaskSystem); | 95 typeMaskSystem); |
| 97 ir.FunctionDefinition irNode = builder.buildExecutable(element); | 96 ir.FunctionDefinition irNode = builder.buildExecutable(element); |
| 98 if (irNode == null) { | 97 if (irNode == null) { |
| 99 bailoutMessage = builder.bailoutMessage; | 98 bailoutMessage = builder.bailoutMessage; |
| 100 } else if (builderCallback != null) { | 99 } else if (builderCallback != null) { |
| 101 builderCallback(element, irNode); | 100 builderCallback(element, irNode); |
| 102 } | 101 } |
| 103 return irNode; | 102 return irNode; |
| 104 }); | 103 }); |
| 105 }); | 104 }); |
| 106 } | 105 } |
| 107 } | 106 } |
| 108 | 107 |
| 109 /// Translates the frontend AST of a method to its CPS IR. | 108 /// Translates the frontend AST of a method to its CPS IR. |
| 110 /// | 109 /// |
| 111 /// The visitor has an [IrBuilder] which contains an IR fragment to build upon | 110 /// The visitor has an [IrBuilder] which contains an IR fragment to build upon |
| 112 /// and the current reaching definition of local variables. | 111 /// and the current reaching definition of local variables. |
| 113 /// | 112 /// |
| 114 /// Visiting a statement or expression extends the IR builder's fragment. | 113 /// Visiting a statement or expression extends the IR builder's fragment. |
| 115 /// For expressions, the primitive holding the resulting value is returned. | 114 /// For expressions, the primitive holding the resulting value is returned. |
| 116 /// For statements, `null` is returned. | 115 /// For statements, `null` is returned. |
| 117 // TODO(johnniwinther): Implement [SemanticDeclVisitor]. | 116 // TODO(johnniwinther): Implement [SemanticDeclVisitor]. |
| 118 abstract class IrBuilderVisitor extends ast.Visitor<ir.Primitive> | 117 class IrBuilderVisitor extends ast.Visitor<ir.Primitive> |
| 119 with IrBuilderMixin<ast.Node>, | 118 with IrBuilderMixin<ast.Node>, |
| 120 SemanticSendResolvedMixin<ir.Primitive, dynamic>, | 119 SemanticSendResolvedMixin<ir.Primitive, dynamic>, |
| 121 ErrorBulkMixin<ir.Primitive, dynamic>, | 120 ErrorBulkMixin<ir.Primitive, dynamic>, |
| 122 BaseImplementationOfStaticsMixin<ir.Primitive, dynamic>, | 121 BaseImplementationOfStaticsMixin<ir.Primitive, dynamic>, |
| 123 BaseImplementationOfLocalsMixin<ir.Primitive, dynamic>, | 122 BaseImplementationOfLocalsMixin<ir.Primitive, dynamic>, |
| 124 BaseImplementationOfDynamicsMixin<ir.Primitive, dynamic>, | 123 BaseImplementationOfDynamicsMixin<ir.Primitive, dynamic>, |
| 125 BaseImplementationOfConstantsMixin<ir.Primitive, dynamic>, | 124 BaseImplementationOfConstantsMixin<ir.Primitive, dynamic>, |
| 126 BaseImplementationOfNewMixin<ir.Primitive, dynamic>, | 125 BaseImplementationOfNewMixin<ir.Primitive, dynamic>, |
| 127 BaseImplementationOfCompoundsMixin<ir.Primitive, dynamic>, | 126 BaseImplementationOfCompoundsMixin<ir.Primitive, dynamic>, |
| 128 BaseImplementationOfSetIfNullsMixin<ir.Primitive, dynamic>, | 127 BaseImplementationOfSetIfNullsMixin<ir.Primitive, dynamic>, |
| (...skipping 29 matching lines...) Expand all Loading... |
| 158 // that is, the definition in effect at the hole in 'current'. These are | 157 // that is, the definition in effect at the hole in 'current'. These are |
| 159 // used to determine if a join-point continuation needs to be passed | 158 // used to determine if a join-point continuation needs to be passed |
| 160 // arguments, and what the arguments are. | 159 // arguments, and what the arguments are. |
| 161 | 160 |
| 162 /// Construct a top-level visitor. | 161 /// Construct a top-level visitor. |
| 163 IrBuilderVisitor(this.elements, | 162 IrBuilderVisitor(this.elements, |
| 164 this.compiler, | 163 this.compiler, |
| 165 this.sourceInformationBuilder, | 164 this.sourceInformationBuilder, |
| 166 this.typeMaskSystem); | 165 this.typeMaskSystem); |
| 167 | 166 |
| 167 JavaScriptBackend get backend => compiler.backend; |
| 168 BackendHelpers get helpers => backend.helpers; |
| 168 DiagnosticReporter get reporter => compiler.reporter; | 169 DiagnosticReporter get reporter => compiler.reporter; |
| 169 | 170 |
| 170 String bailoutMessage = null; | 171 String bailoutMessage = null; |
| 171 | 172 |
| 173 ir.Primitive visit(ast.Node node) => node.accept(this); |
| 174 |
| 172 @override | 175 @override |
| 173 ir.Primitive apply(ast.Node node, _) => node.accept(this); | 176 ir.Primitive apply(ast.Node node, _) => node.accept(this); |
| 174 | 177 |
| 175 @override | |
| 176 SemanticSendVisitor get sendVisitor => this; | 178 SemanticSendVisitor get sendVisitor => this; |
| 177 | 179 |
| 178 /** | 180 /// Result of closure conversion for the current body of code. |
| 179 * Builds the [ir.FunctionDefinition] for an executable element. In case the | 181 /// |
| 180 * function uses features that cannot be expressed in the IR, this element | 182 /// Will be initialized upon entering the body of a function. |
| 181 * returns `null`. | 183 /// It is computed by the [ClosureTranslator]. |
| 182 */ | 184 closure.ClosureClassMap closureClassMap; |
| 183 ir.FunctionDefinition buildExecutable(ExecutableElement element); | 185 |
| 184 | 186 /// If [node] has declarations for variables that should be boxed, |
| 185 ClosureClassMap get closureClassMap; | 187 /// returns a [ClosureScope] naming a box to create, and enumerating the |
| 186 ClosureScope getClosureScopeForNode(ast.Node node); | 188 /// variables that should be stored in the box. |
| 187 ClosureEnvironment getClosureEnvironment(); | 189 /// |
| 190 /// Also see [ClosureScope]. |
| 191 ClosureScope getClosureScopeForNode(ast.Node node) { |
| 192 // We translate a ClosureScope from closure.dart into IR builder's variant |
| 193 // because the IR builder should not depend on the synthetic elements |
| 194 // created in closure.dart. |
| 195 return new ClosureScope(closureClassMap.capturingScopes[node]); |
| 196 } |
| 197 |
| 198 /// Returns the [ClosureScope] for any function, possibly different from the |
| 199 /// one currently being built. |
| 200 ClosureScope getClosureScopeForFunction(FunctionElement function) { |
| 201 closure.ClosureClassMap map = |
| 202 compiler.closureToClassMapper.computeClosureToClassMapping( |
| 203 function, |
| 204 function.node, |
| 205 elements); |
| 206 return new ClosureScope(map.capturingScopes[function.node]); |
| 207 } |
| 208 |
| 209 /// If the current function is a nested function with free variables (or a |
| 210 /// captured reference to `this`), returns a [ClosureEnvironment] |
| 211 /// indicating how to access these. |
| 212 ClosureEnvironment getClosureEnvironment() { |
| 213 return new ClosureEnvironment(closureClassMap); |
| 214 } |
| 215 |
| 216 IrBuilder getBuilderFor(Element element) { |
| 217 return new IrBuilder( |
| 218 new GlobalProgramInformation(compiler), |
| 219 backend.constants, |
| 220 element); |
| 221 } |
| 222 |
| 223 /// Builds the [ir.FunctionDefinition] for an executable element. In case the |
| 224 /// function uses features that cannot be expressed in the IR, this element |
| 225 /// returns `null`. |
| 226 ir.FunctionDefinition buildExecutable(ExecutableElement element) { |
| 227 return nullIfGiveup(() { |
| 228 ir.FunctionDefinition root; |
| 229 switch (element.kind) { |
| 230 case ElementKind.GENERATIVE_CONSTRUCTOR: |
| 231 root = buildConstructor(element); |
| 232 break; |
| 233 |
| 234 case ElementKind.GENERATIVE_CONSTRUCTOR_BODY: |
| 235 root = buildConstructorBody(element); |
| 236 break; |
| 237 |
| 238 case ElementKind.FACTORY_CONSTRUCTOR: |
| 239 case ElementKind.FUNCTION: |
| 240 case ElementKind.GETTER: |
| 241 case ElementKind.SETTER: |
| 242 root = buildFunction(element); |
| 243 break; |
| 244 |
| 245 case ElementKind.FIELD: |
| 246 if (Elements.isStaticOrTopLevel(element)) { |
| 247 root = buildStaticFieldInitializer(element); |
| 248 } else { |
| 249 // Instance field initializers are inlined in the constructor, |
| 250 // so we shouldn't need to build anything here. |
| 251 // TODO(asgerf): But what should we return? |
| 252 return null; |
| 253 } |
| 254 break; |
| 255 |
| 256 default: |
| 257 reporter.internalError(element, "Unexpected element type $element"); |
| 258 } |
| 259 return root; |
| 260 }); |
| 261 } |
| 262 |
| 263 /// Loads the type variables for all super classes of [superClass] into the |
| 264 /// IR builder's environment with their corresponding values. |
| 265 /// |
| 266 /// The type variables for [currentClass] must already be in the IR builder's |
| 267 /// environment. |
| 268 /// |
| 269 /// Type variables are stored as [TypeVariableLocal] in the environment. |
| 270 /// |
| 271 /// This ensures that access to type variables mentioned inside the |
| 272 /// constructors and initializers will happen through the local environment |
| 273 /// instead of using 'this'. |
| 274 void loadTypeVariablesForSuperClasses(ClassElement currentClass) { |
| 275 if (currentClass.isObject) return; |
| 276 loadTypeVariablesForType(currentClass.supertype); |
| 277 if (currentClass is MixinApplicationElement) { |
| 278 loadTypeVariablesForType(currentClass.mixinType); |
| 279 } |
| 280 } |
| 281 |
| 282 /// Loads all type variables for [type] and all of its super classes into |
| 283 /// the environment. All type variables mentioned in [type] must already |
| 284 /// be in the environment. |
| 285 void loadTypeVariablesForType(InterfaceType type) { |
| 286 ClassElement clazz = type.element; |
| 287 assert(clazz.typeVariables.length == type.typeArguments.length); |
| 288 for (int i = 0; i < clazz.typeVariables.length; ++i) { |
| 289 irBuilder.declareTypeVariable(clazz.typeVariables[i], |
| 290 type.typeArguments[i]); |
| 291 } |
| 292 loadTypeVariablesForSuperClasses(clazz); |
| 293 } |
| 294 |
| 295 /// Returns the constructor body associated with the given constructor or |
| 296 /// creates a new constructor body, if none can be found. |
| 297 /// |
| 298 /// Returns `null` if the constructor does not have a body. |
| 299 ConstructorBodyElement getConstructorBody(FunctionElement constructor) { |
| 300 // TODO(asgerf): This is largely inherited from the SSA builder. |
| 301 // The ConstructorBodyElement has an invalid function signature, but we |
| 302 // cannot add a BoxLocal as parameter, because BoxLocal is not an element. |
| 303 // Instead of forging ParameterElements to forge a FunctionSignature, we |
| 304 // need a way to create backend methods without creating more fake elements. |
| 305 assert(constructor.isGenerativeConstructor); |
| 306 assert(constructor.isImplementation); |
| 307 if (constructor.isSynthesized) return null; |
| 308 ast.FunctionExpression node = constructor.node; |
| 309 // If we know the body doesn't have any code, we don't generate it. |
| 310 if (!node.hasBody()) return null; |
| 311 if (node.hasEmptyBody()) return null; |
| 312 ClassElement classElement = constructor.enclosingClass; |
| 313 ConstructorBodyElement bodyElement; |
| 314 classElement.forEachBackendMember((Element backendMember) { |
| 315 if (backendMember.isGenerativeConstructorBody) { |
| 316 ConstructorBodyElement body = backendMember; |
| 317 if (body.constructor == constructor) { |
| 318 bodyElement = backendMember; |
| 319 } |
| 320 } |
| 321 }); |
| 322 if (bodyElement == null) { |
| 323 bodyElement = new ConstructorBodyElementX(constructor); |
| 324 classElement.addBackendMember(bodyElement); |
| 325 |
| 326 if (constructor.isPatch) { |
| 327 // Create origin body element for patched constructors. |
| 328 ConstructorBodyElementX patch = bodyElement; |
| 329 ConstructorBodyElementX origin = |
| 330 new ConstructorBodyElementX(constructor.origin); |
| 331 origin.applyPatch(patch); |
| 332 classElement.origin.addBackendMember(bodyElement.origin); |
| 333 } |
| 334 } |
| 335 assert(bodyElement.isGenerativeConstructorBody); |
| 336 return bodyElement; |
| 337 } |
| 338 |
| 339 /// The list of parameters to send from the generative constructor |
| 340 /// to the generative constructor body. |
| 341 /// |
| 342 /// Boxed parameters are not in the list, instead, a [BoxLocal] is passed |
| 343 /// containing the boxed parameters. |
| 344 /// |
| 345 /// For example, given the following constructor, |
| 346 /// |
| 347 /// Foo(x, y) : field = (() => ++x) { print(x + y) } |
| 348 /// |
| 349 /// the argument `x` would be replaced by a [BoxLocal]: |
| 350 /// |
| 351 /// Foo_body(box0, y) { print(box0.x + y) } |
| 352 /// |
| 353 List<Local> getConstructorBodyParameters(ConstructorBodyElement body) { |
| 354 List<Local> parameters = <Local>[]; |
| 355 ClosureScope scope = getClosureScopeForFunction(body.constructor); |
| 356 if (scope != null) { |
| 357 parameters.add(scope.box); |
| 358 } |
| 359 body.functionSignature.orderedForEachParameter((ParameterElement param) { |
| 360 if (scope != null && scope.capturedVariables.containsKey(param)) { |
| 361 // Do not pass this parameter; the box will carry its value. |
| 362 } else { |
| 363 parameters.add(param); |
| 364 } |
| 365 }); |
| 366 return parameters; |
| 367 } |
| 368 |
| 369 /// Builds the IR for a given constructor. |
| 370 /// |
| 371 /// 1. Computes the type held in all own or "inherited" type variables. |
| 372 /// 2. Evaluates all own or inherited field initializers. |
| 373 /// 3. Creates the object and assigns its fields and runtime type. |
| 374 /// 4. Calls constructor body and super constructor bodies. |
| 375 /// 5. Returns the created object. |
| 376 ir.FunctionDefinition buildConstructor(ConstructorElement constructor) { |
| 377 // TODO(asgerf): Optimization: If constructor is redirecting, then just |
| 378 // evaluate arguments and call the target constructor. |
| 379 constructor = constructor.implementation; |
| 380 ClassElement classElement = constructor.enclosingClass.implementation; |
| 381 |
| 382 IrBuilder builder = getBuilderFor(constructor); |
| 383 |
| 384 final bool requiresTypeInformation = |
| 385 builder.program.requiresRuntimeTypesFor(classElement); |
| 386 |
| 387 return withBuilder(builder, () { |
| 388 // Setup parameters and create a box if anything is captured. |
| 389 List<Local> parameters = <Local>[]; |
| 390 constructor.functionSignature.orderedForEachParameter( |
| 391 (ParameterElement p) => parameters.add(p)); |
| 392 |
| 393 int firstTypeArgumentParameterIndex; |
| 394 |
| 395 // If instances of the class may need runtime type information, we add a |
| 396 // synthetic parameter for each type parameter. |
| 397 if (requiresTypeInformation) { |
| 398 firstTypeArgumentParameterIndex = parameters.length; |
| 399 classElement.typeVariables.forEach((TypeVariableType variable) { |
| 400 parameters.add(new closure.TypeVariableLocal(variable, constructor)); |
| 401 }); |
| 402 } else { |
| 403 classElement.typeVariables.forEach((TypeVariableType variable) { |
| 404 irBuilder.declareTypeVariable(variable, const DynamicType()); |
| 405 }); |
| 406 } |
| 407 |
| 408 // Create IR parameters and setup the environment. |
| 409 List<ir.Parameter> irParameters = builder.buildFunctionHeader(parameters, |
| 410 closureScope: getClosureScopeForFunction(constructor)); |
| 411 |
| 412 // Create a list of the values of all type argument parameters, if any. |
| 413 List<ir.Primitive> typeInformation; |
| 414 if (requiresTypeInformation) { |
| 415 typeInformation = irParameters.sublist(firstTypeArgumentParameterIndex); |
| 416 } else { |
| 417 typeInformation = const <ir.Primitive>[]; |
| 418 } |
| 419 |
| 420 // -- Load values for type variables declared on super classes -- |
| 421 // Field initializers for super classes can reference these, so they |
| 422 // must be available before evaluating field initializers. |
| 423 // This could be interleaved with field initialization, but we choose do |
| 424 // get it out of the way here to avoid complications with mixins. |
| 425 loadTypeVariablesForSuperClasses(classElement); |
| 426 |
| 427 /// Maps each field from this class or a superclass to its initial value. |
| 428 Map<FieldElement, ir.Primitive> fieldValues = |
| 429 <FieldElement, ir.Primitive>{}; |
| 430 |
| 431 // -- Evaluate field initializers --- |
| 432 // Evaluate field initializers in constructor and super constructors. |
| 433 List<ConstructorElement> constructorList = <ConstructorElement>[]; |
| 434 evaluateConstructorFieldInitializers( |
| 435 constructor, constructorList, fieldValues); |
| 436 |
| 437 // All parameters in all constructors are now bound in the environment. |
| 438 // BoxLocals for captured parameters are also in the environment. |
| 439 // The initial value of all fields are now bound in [fieldValues]. |
| 440 |
| 441 // --- Create the object --- |
| 442 // Get the initial field values in the canonical order. |
| 443 List<ir.Primitive> instanceArguments = <ir.Primitive>[]; |
| 444 classElement.forEachInstanceField((ClassElement c, FieldElement field) { |
| 445 ir.Primitive value = fieldValues[field]; |
| 446 if (value != null) { |
| 447 instanceArguments.add(value); |
| 448 } else { |
| 449 assert(backend.isNativeOrExtendsNative(c)); |
| 450 // Native fields are initialized elsewhere. |
| 451 } |
| 452 }, includeSuperAndInjectedMembers: true); |
| 453 |
| 454 ir.Primitive instance = new ir.CreateInstance( |
| 455 classElement, |
| 456 instanceArguments, |
| 457 typeInformation, |
| 458 constructor.hasNode |
| 459 ? sourceInformationBuilder.buildCreate(constructor.node) |
| 460 // TODO(johnniwinther): Provide source information for creation |
| 461 // through synthetic constructors. |
| 462 : null); |
| 463 irBuilder.add(new ir.LetPrim(instance)); |
| 464 |
| 465 // --- Call constructor bodies --- |
| 466 for (ConstructorElement target in constructorList) { |
| 467 ConstructorBodyElement bodyElement = getConstructorBody(target); |
| 468 if (bodyElement == null) continue; // Skip if constructor has no body. |
| 469 List<ir.Primitive> bodyArguments = <ir.Primitive>[]; |
| 470 for (Local param in getConstructorBodyParameters(bodyElement)) { |
| 471 bodyArguments.add(irBuilder.environment.lookup(param)); |
| 472 } |
| 473 irBuilder.buildInvokeDirectly(bodyElement, instance, bodyArguments); |
| 474 } |
| 475 |
| 476 // --- step 4: return the created object ---- |
| 477 irBuilder.buildReturn( |
| 478 value: instance, |
| 479 sourceInformation: |
| 480 sourceInformationBuilder.buildImplicitReturn(constructor)); |
| 481 |
| 482 return irBuilder.makeFunctionDefinition(); |
| 483 }); |
| 484 } |
| 485 |
| 486 /// Make a visitor suitable for translating ASTs taken from [context]. |
| 487 /// |
| 488 /// Every visitor can only be applied to nodes in one context, because |
| 489 /// the [elements] field is specific to that context. |
| 490 IrBuilderVisitor makeVisitorForContext(AstElement context) { |
| 491 return new IrBuilderVisitor( |
| 492 context.resolvedAst.elements, |
| 493 compiler, |
| 494 sourceInformationBuilder.forContext(context), |
| 495 typeMaskSystem); |
| 496 } |
| 497 |
| 498 /// Builds the IR for an [expression] taken from a different [context]. |
| 499 /// |
| 500 /// Such expressions need to be compiled with a different [sourceFile] and |
| 501 /// [elements] mapping. |
| 502 ir.Primitive inlineExpression(AstElement context, ast.Expression expression) { |
| 503 IrBuilderVisitor visitor = makeVisitorForContext(context); |
| 504 return visitor.withBuilder(irBuilder, () => visitor.visit(expression)); |
| 505 } |
| 506 |
| 507 /// Evaluate the implicit super call in the given mixin constructor. |
| 508 void forwardSynthesizedMixinConstructor( |
| 509 ConstructorElement constructor, |
| 510 List<ConstructorElement> supers, |
| 511 Map<FieldElement, ir.Primitive> fieldValues) { |
| 512 assert(constructor.enclosingClass.implementation.isMixinApplication); |
| 513 assert(constructor.isSynthesized); |
| 514 ConstructorElement target = |
| 515 constructor.definingConstructor.implementation; |
| 516 // The resolver gives us the exact same FunctionSignature for the two |
| 517 // constructors. The parameters for the synthesized constructor |
| 518 // are already in the environment, so the target constructor's parameters |
| 519 // are also in the environment since their elements are the same. |
| 520 assert(constructor.functionSignature == target.functionSignature); |
| 521 IrBuilderVisitor visitor = makeVisitorForContext(target); |
| 522 visitor.withBuilder(irBuilder, () { |
| 523 visitor.evaluateConstructorFieldInitializers(target, supers, fieldValues); |
| 524 }); |
| 525 } |
| 526 |
| 527 /// In preparation of inlining (part of) [target], the [arguments] are moved |
| 528 /// into the environment bindings for the corresponding parameters. |
| 529 /// |
| 530 /// Defaults for optional arguments are evaluated in order to ensure |
| 531 /// all parameters are available in the environment. |
| 532 void loadArguments(ConstructorElement target, |
| 533 CallStructure call, |
| 534 List<ir.Primitive> arguments) { |
| 535 assert(target.isImplementation); |
| 536 assert(target == elements.analyzedElement); |
| 537 FunctionSignature signature = target.functionSignature; |
| 538 |
| 539 // Establish a scope in case parameters are captured. |
| 540 ClosureScope scope = getClosureScopeForFunction(target); |
| 541 irBuilder.enterScope(scope); |
| 542 |
| 543 // Load required parameters |
| 544 int index = 0; |
| 545 signature.forEachRequiredParameter((ParameterElement param) { |
| 546 irBuilder.declareLocalVariable(param, initialValue: arguments[index]); |
| 547 index++; |
| 548 }); |
| 549 |
| 550 // Load optional parameters, evaluating default values for omitted ones. |
| 551 signature.forEachOptionalParameter((ParameterElement param) { |
| 552 ir.Primitive value; |
| 553 // Load argument if provided. |
| 554 if (signature.optionalParametersAreNamed) { |
| 555 int nameIndex = call.namedArguments.indexOf(param.name); |
| 556 if (nameIndex != -1) { |
| 557 int translatedIndex = call.positionalArgumentCount + nameIndex; |
| 558 value = arguments[translatedIndex]; |
| 559 } |
| 560 } else if (index < arguments.length) { |
| 561 value = arguments[index]; |
| 562 } |
| 563 // Load default if argument was not provided. |
| 564 if (value == null) { |
| 565 if (param.initializer != null) { |
| 566 value = visit(param.initializer); |
| 567 } else { |
| 568 value = irBuilder.buildNullConstant(); |
| 569 } |
| 570 } |
| 571 irBuilder.declareLocalVariable(param, initialValue: value); |
| 572 index++; |
| 573 }); |
| 574 } |
| 575 |
| 576 /// Evaluates a call to the given constructor from an initializer list. |
| 577 /// |
| 578 /// Calls [loadArguments] and [evaluateConstructorFieldInitializers] in a |
| 579 /// visitor that has the proper [TreeElements] mapping. |
| 580 void evaluateConstructorCallFromInitializer( |
| 581 ConstructorElement target, |
| 582 CallStructure call, |
| 583 List<ir.Primitive> arguments, |
| 584 List<ConstructorElement> supers, |
| 585 Map<FieldElement, ir.Primitive> fieldValues) { |
| 586 IrBuilderVisitor visitor = makeVisitorForContext(target); |
| 587 visitor.withBuilder(irBuilder, () { |
| 588 visitor.loadArguments(target, call, arguments); |
| 589 visitor.evaluateConstructorFieldInitializers(target, supers, fieldValues); |
| 590 }); |
| 591 } |
| 592 |
| 593 /// Evaluates all field initializers on [constructor] and all constructors |
| 594 /// invoked through `this()` or `super()` ("superconstructors"). |
| 595 /// |
| 596 /// The resulting field values will be available in [fieldValues]. The values |
| 597 /// are not stored in any fields. |
| 598 /// |
| 599 /// This procedure assumes that the parameters to [constructor] are available |
| 600 /// in the IR builder's environment. |
| 601 /// |
| 602 /// The parameters to superconstructors are, however, assumed *not* to be in |
| 603 /// the environment, but will be put there by this procedure. |
| 604 /// |
| 605 /// All constructors will be added to [supers], with superconstructors first. |
| 606 void evaluateConstructorFieldInitializers( |
| 607 ConstructorElement constructor, |
| 608 List<ConstructorElement> supers, |
| 609 Map<FieldElement, ir.Primitive> fieldValues) { |
| 610 assert(constructor.isImplementation); |
| 611 assert(constructor == elements.analyzedElement); |
| 612 ClassElement enclosingClass = constructor.enclosingClass.implementation; |
| 613 // Evaluate declaration-site field initializers, unless this constructor |
| 614 // redirects to another using a `this()` initializer. In that case, these |
| 615 // will be initialized by the effective target constructor. |
| 616 if (!constructor.isRedirectingGenerative) { |
| 617 enclosingClass.forEachInstanceField((ClassElement c, FieldElement field) { |
| 618 if (field.initializer != null) { |
| 619 fieldValues[field] = inlineExpression(field, field.initializer); |
| 620 } else { |
| 621 if (backend.isNativeOrExtendsNative(c)) { |
| 622 // Native field is initialized elsewhere. |
| 623 } else { |
| 624 // Fields without an initializer default to null. |
| 625 // This value will be overwritten below if an initializer is found. |
| 626 fieldValues[field] = irBuilder.buildNullConstant(); |
| 627 } |
| 628 } |
| 629 }); |
| 630 } |
| 631 // If this is a mixin constructor, it does not have its own parameter list |
| 632 // or initializer list. Directly forward to the super constructor. |
| 633 // Note that the declaration-site initializers originating from the |
| 634 // mixed-in class were handled above. |
| 635 if (enclosingClass.isMixinApplication) { |
| 636 forwardSynthesizedMixinConstructor(constructor, supers, fieldValues); |
| 637 return; |
| 638 } |
| 639 // Evaluate initializing parameters, e.g. `Foo(this.x)`. |
| 640 constructor.functionSignature.orderedForEachParameter( |
| 641 (ParameterElement parameter) { |
| 642 if (parameter.isInitializingFormal) { |
| 643 InitializingFormalElement fieldParameter = parameter; |
| 644 fieldValues[fieldParameter.fieldElement] = |
| 645 irBuilder.buildLocalVariableGet(parameter); |
| 646 } |
| 647 }); |
| 648 // Evaluate constructor initializers, e.g. `Foo() : x = 50`. |
| 649 ast.FunctionExpression node = constructor.node; |
| 650 bool hasConstructorCall = false; // Has this() or super() initializer? |
| 651 if (node != null && node.initializers != null) { |
| 652 for(ast.Node initializer in node.initializers) { |
| 653 if (initializer is ast.SendSet) { |
| 654 // Field initializer. |
| 655 FieldElement field = elements[initializer]; |
| 656 fieldValues[field] = visit(initializer.arguments.head); |
| 657 } else if (initializer is ast.Send) { |
| 658 // Super or this initializer. |
| 659 ConstructorElement target = elements[initializer].implementation; |
| 660 Selector selector = elements.getSelector(initializer); |
| 661 List<ir.Primitive> arguments = initializer.arguments.mapToList(visit); |
| 662 evaluateConstructorCallFromInitializer( |
| 663 target, |
| 664 selector.callStructure, |
| 665 arguments, |
| 666 supers, |
| 667 fieldValues); |
| 668 hasConstructorCall = true; |
| 669 } else { |
| 670 reporter.internalError(initializer, |
| 671 "Unexpected initializer type $initializer"); |
| 672 } |
| 673 } |
| 674 } |
| 675 // If no super() or this() was found, also call default superconstructor. |
| 676 if (!hasConstructorCall && !enclosingClass.isObject) { |
| 677 ClassElement superClass = enclosingClass.superclass; |
| 678 FunctionElement target = superClass.lookupDefaultConstructor(); |
| 679 if (target == null) { |
| 680 reporter.internalError(superClass, "No default constructor available."); |
| 681 } |
| 682 target = target.implementation; |
| 683 evaluateConstructorCallFromInitializer( |
| 684 target, |
| 685 CallStructure.NO_ARGS, |
| 686 const [], |
| 687 supers, |
| 688 fieldValues); |
| 689 } |
| 690 // Add this constructor after the superconstructors. |
| 691 supers.add(constructor); |
| 692 } |
| 693 |
| 694 TryBoxedVariables _analyzeTryBoxedVariables(ast.Node node) { |
| 695 TryBoxedVariables variables = new TryBoxedVariables(elements); |
| 696 try { |
| 697 variables.analyze(node); |
| 698 } catch (e) { |
| 699 bailoutMessage = variables.bailoutMessage; |
| 700 rethrow; |
| 701 } |
| 702 return variables; |
| 703 } |
| 704 |
| 705 /// Builds the IR for the body of a constructor. |
| 706 /// |
| 707 /// This function is invoked from one or more "factory" constructors built by |
| 708 /// [buildConstructor]. |
| 709 ir.FunctionDefinition buildConstructorBody(ConstructorBodyElement body) { |
| 710 ConstructorElement constructor = body.constructor; |
| 711 ast.FunctionExpression node = constructor.node; |
| 712 closureClassMap = |
| 713 compiler.closureToClassMapper.computeClosureToClassMapping( |
| 714 constructor, |
| 715 node, |
| 716 elements); |
| 717 |
| 718 // We compute variables boxed in mutable variables on entry to each try |
| 719 // block, not including variables captured by a closure (which are boxed |
| 720 // in the heap). This duplicates some of the work of closure conversion |
| 721 // without directly using the results. This duplication is wasteful and |
| 722 // error-prone. |
| 723 // TODO(kmillikin): We should combine closure conversion and try/catch |
| 724 // variable analysis in some way. |
| 725 TryBoxedVariables variables = _analyzeTryBoxedVariables(node); |
| 726 tryStatements = variables.tryStatements; |
| 727 IrBuilder builder = getBuilderFor(body); |
| 728 |
| 729 return withBuilder(builder, () { |
| 730 irBuilder.buildConstructorBodyHeader(getConstructorBodyParameters(body), |
| 731 getClosureScopeForNode(node)); |
| 732 visit(node.body); |
| 733 return irBuilder.makeFunctionDefinition(); |
| 734 }); |
| 735 } |
| 736 |
| 737 ir.FunctionDefinition buildFunction(FunctionElement element) { |
| 738 assert(invariant(element, element.isImplementation)); |
| 739 ast.FunctionExpression node = element.node; |
| 740 |
| 741 assert(!element.isSynthesized); |
| 742 assert(node != null); |
| 743 assert(elements[node] != null); |
| 744 |
| 745 closureClassMap = |
| 746 compiler.closureToClassMapper.computeClosureToClassMapping( |
| 747 element, |
| 748 node, |
| 749 elements); |
| 750 TryBoxedVariables variables = _analyzeTryBoxedVariables(node); |
| 751 tryStatements = variables.tryStatements; |
| 752 IrBuilder builder = getBuilderFor(element); |
| 753 return withBuilder(builder, () => _makeFunctionBody(element, node)); |
| 754 } |
| 755 |
| 756 ir.FunctionDefinition buildStaticFieldInitializer(FieldElement element) { |
| 757 if (!backend.constants.lazyStatics.contains(element)) { |
| 758 return null; // Nothing to do. |
| 759 } |
| 760 closureClassMap = |
| 761 compiler.closureToClassMapper.computeClosureToClassMapping( |
| 762 element, |
| 763 element.node, |
| 764 elements); |
| 765 IrBuilder builder = getBuilderFor(element); |
| 766 return withBuilder(builder, () { |
| 767 irBuilder.buildFunctionHeader(<Local>[]); |
| 768 ir.Primitive initialValue = visit(element.initializer); |
| 769 ast.VariableDefinitions node = element.node; |
| 770 ast.SendSet sendSet = node.definitions.nodes.head; |
| 771 irBuilder.buildReturn( |
| 772 value: initialValue, |
| 773 sourceInformation: |
| 774 sourceInformationBuilder.buildReturn(sendSet.assignmentOperator)); |
| 775 return irBuilder.makeFunctionDefinition(); |
| 776 }); |
| 777 } |
| 778 |
| 779 /// Builds the IR for a constant taken from a different [context]. |
| 780 /// |
| 781 /// Such constants need to be compiled with a different [sourceFile] and |
| 782 /// [elements] mapping. |
| 783 ir.Primitive inlineConstant(AstElement context, ast.Expression exp) { |
| 784 IrBuilderVisitor visitor = makeVisitorForContext(context); |
| 785 return visitor.withBuilder(irBuilder, () => visitor.translateConstant(exp)); |
| 786 } |
| 787 |
| 788 /// Creates a primitive for the default value of [parameter]. |
| 789 ir.Primitive translateDefaultValue(ParameterElement parameter) { |
| 790 if (parameter.initializer == null) { |
| 791 return irBuilder.buildNullConstant(); |
| 792 } else { |
| 793 return inlineConstant(parameter.executableContext, parameter.initializer); |
| 794 } |
| 795 } |
| 188 | 796 |
| 189 /// Normalizes the argument list of a static invocation. | 797 /// Normalizes the argument list of a static invocation. |
| 190 /// | 798 /// |
| 191 /// A static invocation is one where the target is known. The argument list | 799 /// A static invocation is one where the target is known. The argument list |
| 192 /// [arguments] is normalized by adding default values for optional arguments | 800 /// [arguments] is normalized by adding default values for optional arguments |
| 193 /// that are not passed, and by sorting it in place so that named arguments | 801 /// that are not passed, and by sorting it in place so that named arguments |
| 194 /// appear in a canonical order. A [CallStructure] reflecting this order | 802 /// appear in a canonical order. A [CallStructure] reflecting this order |
| 195 /// is returned. | 803 /// is returned. |
| 196 CallStructure normalizeStaticArguments( | 804 CallStructure normalizeStaticArguments(CallStructure callStructure, |
| 197 CallStructure callStructure, | |
| 198 FunctionElement target, | 805 FunctionElement target, |
| 199 List<ir.Primitive> arguments); | 806 List<ir.Primitive> arguments) { |
| 807 target = target.implementation; |
| 808 FunctionSignature signature = target.functionSignature; |
| 809 if (!signature.optionalParametersAreNamed && |
| 810 signature.parameterCount == arguments.length) { |
| 811 return callStructure; |
| 812 } |
| 813 |
| 814 if (!signature.optionalParametersAreNamed) { |
| 815 int i = signature.requiredParameterCount; |
| 816 signature.forEachOptionalParameter((ParameterElement element) { |
| 817 if (i < callStructure.positionalArgumentCount) { |
| 818 ++i; |
| 819 } else { |
| 820 arguments.add(translateDefaultValue(element)); |
| 821 } |
| 822 }); |
| 823 return new CallStructure(signature.parameterCount); |
| 824 } |
| 825 |
| 826 int offset = signature.requiredParameterCount; |
| 827 List<ir.Primitive> namedArguments = arguments.sublist(offset); |
| 828 arguments.length = offset; |
| 829 List<String> normalizedNames = <String>[]; |
| 830 // Iterate over the optional parameters of the signature, and try to |
| 831 // find them in the callStructure's named arguments. If found, we use the |
| 832 // value in the temporary list, otherwise the default value. |
| 833 signature.orderedOptionalParameters.forEach((ParameterElement element) { |
| 834 int nameIndex = callStructure.namedArguments.indexOf(element.name); |
| 835 arguments.add(nameIndex == -1 ? translateDefaultValue(element) |
| 836 : namedArguments[nameIndex]); |
| 837 normalizedNames.add(element.name); |
| 838 }); |
| 839 return new CallStructure(signature.parameterCount, normalizedNames); |
| 840 } |
| 200 | 841 |
| 201 /// Normalizes the argument list of a dynamic invocation. | 842 /// Normalizes the argument list of a dynamic invocation. |
| 202 /// | 843 /// |
| 203 /// A dynamic invocation is one where the target is not known. The argument | 844 /// A dynamic invocation is one where the target is not known. The argument |
| 204 /// list [arguments] is normalized by sorting it in place so that the named | 845 /// list [arguments] is normalized by sorting it in place so that the named |
| 205 /// arguments appear in a canonical order. A [CallStructure] reflecting this | 846 /// arguments appear in a canonical order. A [CallStructure] reflecting this |
| 206 /// order is returned. | 847 /// order is returned. |
| 207 CallStructure normalizeDynamicArguments( | 848 CallStructure normalizeDynamicArguments(CallStructure callStructure, |
| 208 CallStructure callStructure, | 849 List<ir.Primitive> arguments) { |
| 209 List<ir.Primitive> arguments); | 850 assert(arguments.length == callStructure.argumentCount); |
| 851 if (callStructure.namedArguments.isEmpty) return callStructure; |
| 852 int destinationIndex = callStructure.positionalArgumentCount; |
| 853 List<ir.Primitive> namedArguments = arguments.sublist(destinationIndex); |
| 854 for (String argName in callStructure.getOrderedNamedArguments()) { |
| 855 int sourceIndex = callStructure.namedArguments.indexOf(argName); |
| 856 arguments[destinationIndex++] = namedArguments[sourceIndex]; |
| 857 } |
| 858 return new CallStructure(callStructure.argumentCount, |
| 859 callStructure.getOrderedNamedArguments()); |
| 860 } |
| 210 | 861 |
| 211 /// Read the value of [field]. | 862 /// Read the value of [field]. |
| 212 ir.Primitive buildStaticFieldGet(FieldElement field, SourceInformation src); | 863 ir.Primitive buildStaticFieldGet(FieldElement field, SourceInformation src) { |
| 864 ConstantValue constant = getConstantForVariable(field); |
| 865 if (constant != null && !field.isAssignable) { |
| 866 typeMaskSystem.associateConstantValueWithElement(constant, field); |
| 867 return irBuilder.buildConstant(constant, sourceInformation: src); |
| 868 } else if (backend.constants.lazyStatics.contains(field)) { |
| 869 return irBuilder.buildStaticFieldLazyGet(field, src); |
| 870 } else { |
| 871 return irBuilder.buildStaticFieldGet(field, src); |
| 872 } |
| 873 } |
| 213 | 874 |
| 214 ir.FunctionDefinition _makeFunctionBody(FunctionElement element, | 875 ir.FunctionDefinition _makeFunctionBody(FunctionElement element, |
| 215 ast.FunctionExpression node) { | 876 ast.FunctionExpression node) { |
| 216 FunctionSignature signature = element.functionSignature; | 877 FunctionSignature signature = element.functionSignature; |
| 217 List<Local> parameters = <Local>[]; | 878 List<Local> parameters = <Local>[]; |
| 218 signature.orderedForEachParameter( | 879 signature.orderedForEachParameter( |
| 219 (LocalParameterElement e) => parameters.add(e)); | 880 (LocalParameterElement e) => parameters.add(e)); |
| 220 | 881 |
| 221 if (element.isFactoryConstructor) { | 882 if (element.isFactoryConstructor) { |
| 222 // Type arguments are passed in as extra parameters. | 883 // Type arguments are passed in as extra parameters. |
| 223 for (DartType typeVariable in element.enclosingClass.typeVariables) { | 884 for (DartType typeVariable in element.enclosingClass.typeVariables) { |
| 224 parameters.add(new TypeVariableLocal(typeVariable, element)); | 885 parameters.add(new closure.TypeVariableLocal(typeVariable, element)); |
| 225 } | 886 } |
| 226 } | 887 } |
| 227 | 888 |
| 228 irBuilder.buildFunctionHeader(parameters, | 889 irBuilder.buildFunctionHeader(parameters, |
| 229 closureScope: getClosureScopeForNode(node), | 890 closureScope: getClosureScopeForNode(node), |
| 230 env: getClosureEnvironment()); | 891 env: getClosureEnvironment()); |
| 231 | 892 |
| 232 visit(node.body); | 893 visit(node.body); |
| 233 return irBuilder.makeFunctionDefinition(); | 894 return irBuilder.makeFunctionDefinition(); |
| 234 } | 895 } |
| 235 | 896 |
| 236 /// Returns the allocation site-specific type for a given allocation. | 897 /// Builds the IR for creating an instance of the closure class corresponding |
| 237 /// | 898 /// to the given nested function. |
| 238 /// Currently, it is an error to call this with anything that is not the | 899 closure.ClosureClassElement makeSubFunction(ast.FunctionExpression node) { |
| 239 /// allocation site for a List object (a literal list or a call to one | 900 closure.ClosureClassMap innerMap = |
| 240 /// of the List constructors). | 901 compiler.closureToClassMapper.getMappingForNestedFunction(node); |
| 241 TypeMask getAllocationSiteType(ast.Node node) { | 902 closure.ClosureClassElement closureClass = innerMap.closureClassElement; |
| 242 return compiler.typesTask.getGuaranteedTypeOfNode( | 903 return closureClass; |
| 243 elements.analyzedElement, node); | 904 } |
| 244 } | 905 |
| 245 | 906 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) { |
| 246 ir.Primitive visit(ast.Node node) => node.accept(this); | 907 return irBuilder.buildFunctionExpression(makeSubFunction(node), |
| 908 sourceInformationBuilder.buildCreate(node)); |
| 909 } |
| 910 |
| 911 visitFunctionDeclaration(ast.FunctionDeclaration node) { |
| 912 LocalFunctionElement element = elements[node.function]; |
| 913 Object inner = makeSubFunction(node.function); |
| 914 irBuilder.declareLocalFunction(element, inner, |
| 915 sourceInformationBuilder.buildCreate(node.function)); |
| 916 } |
| 247 | 917 |
| 248 // ## Statements ## | 918 // ## Statements ## |
| 249 visitBlock(ast.Block node) { | 919 visitBlock(ast.Block node) { |
| 250 irBuilder.buildBlock(node.statements.nodes, build); | 920 irBuilder.buildBlock(node.statements.nodes, build); |
| 251 } | 921 } |
| 252 | 922 |
| 253 ir.Primitive visitBreakStatement(ast.BreakStatement node) { | 923 ir.Primitive visitBreakStatement(ast.BreakStatement node) { |
| 254 if (!irBuilder.buildBreak(elements.getTargetOf(node))) { | 924 if (!irBuilder.buildBreak(elements.getTargetOf(node))) { |
| 255 reporter.internalError(node, "'break' target not found"); | 925 reporter.internalError(node, "'break' target not found"); |
| 256 } | 926 } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 288 ir.Primitive visitRethrow(ast.Rethrow node) { | 958 ir.Primitive visitRethrow(ast.Rethrow node) { |
| 289 assert(irBuilder.isOpen); | 959 assert(irBuilder.isOpen); |
| 290 irBuilder.buildRethrow(); | 960 irBuilder.buildRethrow(); |
| 291 return null; | 961 return null; |
| 292 } | 962 } |
| 293 | 963 |
| 294 /// Construct a method that executes the forwarding call to the target | 964 /// Construct a method that executes the forwarding call to the target |
| 295 /// constructor. This is only required, if the forwarding factory | 965 /// constructor. This is only required, if the forwarding factory |
| 296 /// constructor can potentially be the target of a reflective call, because | 966 /// constructor can potentially be the target of a reflective call, because |
| 297 /// the builder shortcuts calls to redirecting factories at the call site | 967 /// the builder shortcuts calls to redirecting factories at the call site |
| 298 /// (see [JsIrBuilderVisitor.handleConstructorInvoke]). | 968 /// (see [handleConstructorInvoke]). |
| 299 visitRedirectingFactoryBody(ast.RedirectingFactoryBody node) { | 969 visitRedirectingFactoryBody(ast.RedirectingFactoryBody node) { |
| 300 ConstructorElement targetConstructor = | 970 ConstructorElement targetConstructor = |
| 301 elements.getRedirectingTargetConstructor(node).implementation; | 971 elements.getRedirectingTargetConstructor(node).implementation; |
| 302 ConstructorElement redirectingConstructor = | 972 ConstructorElement redirectingConstructor = |
| 303 irBuilder.state.currentElement.implementation; | 973 irBuilder.state.currentElement.implementation; |
| 304 List<ir.Primitive> arguments = <ir.Primitive>[]; | 974 List<ir.Primitive> arguments = <ir.Primitive>[]; |
| 305 FunctionSignature redirectingSignature = | 975 FunctionSignature redirectingSignature = |
| 306 redirectingConstructor.functionSignature; | 976 redirectingConstructor.functionSignature; |
| 307 List<String> namedParameters = <String>[]; | 977 List<String> namedParameters = <String>[]; |
| 308 redirectingSignature.forEachParameter((ParameterElement parameter) { | 978 redirectingSignature.forEachParameter((ParameterElement parameter) { |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 465 | 1135 |
| 466 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] | 1136 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] |
| 467 // where (C', x) = Build(e, C) | 1137 // where (C', x) = Build(e, C) |
| 468 // | 1138 // |
| 469 // Return without a subexpression is translated as if it were return null. | 1139 // Return without a subexpression is translated as if it were return null. |
| 470 visitReturn(ast.Return node) { | 1140 visitReturn(ast.Return node) { |
| 471 assert(irBuilder.isOpen); | 1141 assert(irBuilder.isOpen); |
| 472 SourceInformation source = sourceInformationBuilder.buildReturn(node); | 1142 SourceInformation source = sourceInformationBuilder.buildReturn(node); |
| 473 if (node.beginToken.value == 'native') { | 1143 if (node.beginToken.value == 'native') { |
| 474 FunctionElement function = irBuilder.state.currentElement; | 1144 FunctionElement function = irBuilder.state.currentElement; |
| 475 assert(compiler.backend.isNative(function)); | 1145 assert(backend.isNative(function)); |
| 476 ast.Node nativeBody = node.expression; | 1146 ast.Node nativeBody = node.expression; |
| 477 if (nativeBody != null) { | 1147 if (nativeBody != null) { |
| 478 ast.LiteralString jsCode = nativeBody.asLiteralString(); | 1148 ast.LiteralString jsCode = nativeBody.asLiteralString(); |
| 479 String javaScriptCode = jsCode.dartString.slowToString(); | 1149 String javaScriptCode = jsCode.dartString.slowToString(); |
| 480 assert(invariant(nativeBody, | 1150 assert(invariant(nativeBody, |
| 481 !nativeRedirectionRegExp.hasMatch(javaScriptCode), | 1151 !nativeRedirectionRegExp.hasMatch(javaScriptCode), |
| 482 message: "Deprecated syntax, use @JSName('name') instead.")); | 1152 message: "Deprecated syntax, use @JSName('name') instead.")); |
| 483 assert(invariant(nativeBody, | 1153 assert(invariant(nativeBody, |
| 484 function.functionSignature.parameterCount == 0, | 1154 function.functionSignature.parameterCount == 0, |
| 485 message: 'native "..." syntax is restricted to ' | 1155 message: 'native "..." syntax is restricted to ' |
| 486 'functions with zero parameters.')); | 1156 'functions with zero parameters.')); |
| 487 irBuilder.buildNativeFunctionBody(function, javaScriptCode); | 1157 irBuilder.buildNativeFunctionBody(function, javaScriptCode); |
| 488 } else { | 1158 } else { |
| 489 JavaScriptBackend backend = compiler.backend; | |
| 490 String name = backend.getFixedBackendName(function); | 1159 String name = backend.getFixedBackendName(function); |
| 491 irBuilder.buildRedirectingNativeFunctionBody(function, name, source); | 1160 irBuilder.buildRedirectingNativeFunctionBody(function, name, source); |
| 492 } | 1161 } |
| 493 } else { | 1162 } else { |
| 494 irBuilder.buildReturn( | 1163 irBuilder.buildReturn( |
| 495 value: build(node.expression), | 1164 value: build(node.expression), |
| 496 sourceInformation: source); | 1165 sourceInformation: source); |
| 497 } | 1166 } |
| 498 } | 1167 } |
| 499 | 1168 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 526 for (ast.Node labelOrCase in switchCase.labelsAndCases) { | 1195 for (ast.Node labelOrCase in switchCase.labelsAndCases) { |
| 527 if (labelOrCase is ast.CaseMatch) { | 1196 if (labelOrCase is ast.CaseMatch) { |
| 528 ir.Primitive constant = translateConstant(labelOrCase.expression); | 1197 ir.Primitive constant = translateConstant(labelOrCase.expression); |
| 529 caseInfo.addConstant(constant); | 1198 caseInfo.addConstant(constant); |
| 530 } | 1199 } |
| 531 } | 1200 } |
| 532 } | 1201 } |
| 533 } | 1202 } |
| 534 ir.Primitive value = visit(node.expression); | 1203 ir.Primitive value = visit(node.expression); |
| 535 JumpTarget target = elements.getTargetDefinition(node); | 1204 JumpTarget target = elements.getTargetDefinition(node); |
| 536 Element error = | 1205 Element error = helpers.fallThroughError; |
| 537 (compiler.backend as JavaScriptBackend).helpers.fallThroughError; | |
| 538 irBuilder.buildSimpleSwitch(target, value, cases, defaultCase, error, | 1206 irBuilder.buildSimpleSwitch(target, value, cases, defaultCase, error, |
| 539 sourceInformationBuilder.buildGeneric(node)); | 1207 sourceInformationBuilder.buildGeneric(node)); |
| 540 } | 1208 } |
| 541 | 1209 |
| 542 visitTryStatement(ast.TryStatement node) { | 1210 visitTryStatement(ast.TryStatement node) { |
| 543 List<CatchClauseInfo> catchClauseInfos = <CatchClauseInfo>[]; | 1211 List<CatchClauseInfo> catchClauseInfos = <CatchClauseInfo>[]; |
| 544 for (ast.CatchBlock catchClause in node.catchBlocks.nodes) { | 1212 for (ast.CatchBlock catchClause in node.catchBlocks.nodes) { |
| 545 LocalVariableElement exceptionVariable; | 1213 LocalVariableElement exceptionVariable; |
| 546 if (catchClause.exception != null) { | 1214 if (catchClause.exception != null) { |
| 547 exceptionVariable = elements[catchClause.exception]; | 1215 exceptionVariable = elements[catchClause.exception]; |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 629 return irBuilder.state.constants.getConstantValueForVariable(element); | 1297 return irBuilder.state.constants.getConstantValueForVariable(element); |
| 630 } | 1298 } |
| 631 | 1299 |
| 632 ir.Primitive buildConstantExpression(ConstantExpression expression, | 1300 ir.Primitive buildConstantExpression(ConstantExpression expression, |
| 633 SourceInformation sourceInformation) { | 1301 SourceInformation sourceInformation) { |
| 634 return irBuilder.buildConstant( | 1302 return irBuilder.buildConstant( |
| 635 irBuilder.state.constants.getConstantValue(expression), | 1303 irBuilder.state.constants.getConstantValue(expression), |
| 636 sourceInformation: sourceInformation); | 1304 sourceInformation: sourceInformation); |
| 637 } | 1305 } |
| 638 | 1306 |
| 1307 /// Returns the allocation site-specific type for a given allocation. |
| 1308 /// |
| 1309 /// Currently, it is an error to call this with anything that is not the |
| 1310 /// allocation site for a List object (a literal list or a call to one |
| 1311 /// of the List constructors). |
| 1312 TypeMask getAllocationSiteType(ast.Node node) { |
| 1313 return compiler.typesTask.getGuaranteedTypeOfNode( |
| 1314 elements.analyzedElement, node); |
| 1315 } |
| 1316 |
| 639 ir.Primitive visitLiteralList(ast.LiteralList node) { | 1317 ir.Primitive visitLiteralList(ast.LiteralList node) { |
| 640 if (node.isConst) { | 1318 if (node.isConst) { |
| 641 return translateConstant(node); | 1319 return translateConstant(node); |
| 642 } | 1320 } |
| 643 List<ir.Primitive> values = node.elements.nodes.mapToList(visit); | 1321 List<ir.Primitive> values = node.elements.nodes.mapToList(visit); |
| 644 InterfaceType type = elements.getType(node); | 1322 InterfaceType type = elements.getType(node); |
| 645 return irBuilder.buildListLiteral(type, values, | 1323 return irBuilder.buildListLiteral(type, values, |
| 646 allocationSiteType: getAllocationSiteType(node)); | 1324 allocationSiteType: getAllocationSiteType(node)); |
| 647 } | 1325 } |
| 648 | 1326 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 706 // ## Sends ## | 1384 // ## Sends ## |
| 707 @override | 1385 @override |
| 708 void previsitDeferredAccess(ast.Send node, PrefixElement prefix, _) { | 1386 void previsitDeferredAccess(ast.Send node, PrefixElement prefix, _) { |
| 709 if (prefix != null) buildCheckDeferredIsLoaded(prefix, node); | 1387 if (prefix != null) buildCheckDeferredIsLoaded(prefix, node); |
| 710 } | 1388 } |
| 711 | 1389 |
| 712 /// Create a call to check that a deferred import has already been loaded. | 1390 /// Create a call to check that a deferred import has already been loaded. |
| 713 ir.Primitive buildCheckDeferredIsLoaded(PrefixElement prefix, ast.Send node) { | 1391 ir.Primitive buildCheckDeferredIsLoaded(PrefixElement prefix, ast.Send node) { |
| 714 SourceInformation sourceInformation = | 1392 SourceInformation sourceInformation = |
| 715 sourceInformationBuilder.buildCall(node, node.selector); | 1393 sourceInformationBuilder.buildCall(node, node.selector); |
| 716 JavaScriptBackend backend = compiler.backend; | |
| 717 return irBuilder.buildStaticFunctionInvocation( | 1394 return irBuilder.buildStaticFunctionInvocation( |
| 718 backend.helpers.checkDeferredIsLoaded, | 1395 helpers.checkDeferredIsLoaded, |
| 719 CallStructure.TWO_ARGS, <ir.Primitive>[ | 1396 CallStructure.TWO_ARGS, <ir.Primitive>[ |
| 720 irBuilder.buildStringConstant( | 1397 irBuilder.buildStringConstant( |
| 721 compiler.deferredLoadTask.getImportDeferName(node, prefix)), | 1398 compiler.deferredLoadTask.getImportDeferName(node, prefix)), |
| 722 irBuilder.buildStringConstant('${prefix.deferredImport.uri}'), | 1399 irBuilder.buildStringConstant('${prefix.deferredImport.uri}'), |
| 723 ], sourceInformation: sourceInformation); | 1400 ], sourceInformation: sourceInformation); |
| 724 } | 1401 } |
| 725 | 1402 |
| 726 ir.Primitive visitNamedArgument(ast.NamedArgument node) { | 1403 ir.Primitive visitNamedArgument(ast.NamedArgument node) { |
| 727 assert(irBuilder.isOpen); | 1404 assert(irBuilder.isOpen); |
| 728 return visit(node.expression); | 1405 return visit(node.expression); |
| (...skipping 427 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1156 ast.NodeList arguments, | 1833 ast.NodeList arguments, |
| 1157 CallStructure callStructure, | 1834 CallStructure callStructure, |
| 1158 _) { | 1835 _) { |
| 1159 ir.Primitive target = buildConstantExpression(constant, | 1836 ir.Primitive target = buildConstantExpression(constant, |
| 1160 sourceInformationBuilder.buildGet(node)); | 1837 sourceInformationBuilder.buildGet(node)); |
| 1161 return translateCallInvoke(target, arguments, callStructure, | 1838 return translateCallInvoke(target, arguments, callStructure, |
| 1162 sourceInformationBuilder.buildCall(node, arguments)); | 1839 sourceInformationBuilder.buildCall(node, arguments)); |
| 1163 } | 1840 } |
| 1164 | 1841 |
| 1165 @override | 1842 @override |
| 1843 ir.Primitive handleConstructorInvoke( |
| 1844 ast.NewExpression node, |
| 1845 ConstructorElement constructor, |
| 1846 DartType type, |
| 1847 ast.NodeList argumentsNode, |
| 1848 CallStructure callStructure, |
| 1849 _) { |
| 1850 |
| 1851 // TODO(sigmund): move these checks down after visiting arguments |
| 1852 // (see issue #25355) |
| 1853 ast.Send send = node.send; |
| 1854 // If an allocation refers to a type using a deferred import prefix (e.g. |
| 1855 // `new lib.A()`), we must ensure that the deferred import has already been |
| 1856 // loaded. |
| 1857 var prefix = compiler.deferredLoadTask.deferredPrefixElement( |
| 1858 send, elements); |
| 1859 if (prefix != null) buildCheckDeferredIsLoaded(prefix, send); |
| 1860 |
| 1861 // We also emit deferred import checks when using redirecting factories that |
| 1862 // refer to deferred prefixes. |
| 1863 if (constructor.isRedirectingFactory && !constructor.isCyclicRedirection) { |
| 1864 ConstructorElement current = constructor; |
| 1865 while (current.isRedirectingFactory) { |
| 1866 var prefix = current.redirectionDeferredPrefix; |
| 1867 if (prefix != null) buildCheckDeferredIsLoaded(prefix, send); |
| 1868 current = current.immediateRedirectionTarget; |
| 1869 } |
| 1870 } |
| 1871 |
| 1872 List<ir.Primitive> arguments = argumentsNode.nodes.mapToList(visit); |
| 1873 // Use default values from the effective target, not the immediate target. |
| 1874 ConstructorElement target = constructor.effectiveTarget; |
| 1875 |
| 1876 callStructure = normalizeStaticArguments(callStructure, target, arguments); |
| 1877 TypeMask allocationSiteType; |
| 1878 |
| 1879 if (Elements.isFixedListConstructorCall(constructor, send, compiler) || |
| 1880 Elements.isGrowableListConstructorCall(constructor, send, compiler) || |
| 1881 Elements.isFilledListConstructorCall(constructor, send, compiler) || |
| 1882 Elements.isConstructorOfTypedArraySubclass(constructor, compiler)) { |
| 1883 allocationSiteType = getAllocationSiteType(send); |
| 1884 } |
| 1885 return irBuilder.buildConstructorInvocation( |
| 1886 target, |
| 1887 callStructure, |
| 1888 constructor.computeEffectiveTargetType(type), |
| 1889 arguments, |
| 1890 sourceInformationBuilder.buildNew(node), |
| 1891 allocationSiteType: allocationSiteType); |
| 1892 } |
| 1893 |
| 1894 @override |
| 1166 ir.Primitive handleDynamicInvoke( | 1895 ir.Primitive handleDynamicInvoke( |
| 1167 ast.Send node, | 1896 ast.Send node, |
| 1168 ast.Node receiver, | 1897 ast.Node receiver, |
| 1169 ast.NodeList argumentsNode, | 1898 ast.NodeList argumentsNode, |
| 1170 Selector selector, | 1899 Selector selector, |
| 1171 _) { | 1900 _) { |
| 1172 ir.Primitive target = translateReceiver(receiver); | 1901 ir.Primitive target = translateReceiver(receiver); |
| 1173 List<ir.Primitive> arguments = <ir.Primitive>[]; | 1902 List<ir.Primitive> arguments = <ir.Primitive>[]; |
| 1174 CallStructure callStructure = translateDynamicArguments( | 1903 CallStructure callStructure = translateDynamicArguments( |
| 1175 argumentsNode, selector.callStructure, arguments); | 1904 argumentsNode, selector.callStructure, arguments); |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1257 translateDynamicArguments(argumentsNode, callStructure, arguments); | 1986 translateDynamicArguments(argumentsNode, callStructure, arguments); |
| 1258 return irBuilder.buildCallInvocation( | 1987 return irBuilder.buildCallInvocation( |
| 1259 target, | 1988 target, |
| 1260 callStructure, | 1989 callStructure, |
| 1261 arguments, | 1990 arguments, |
| 1262 sourceInformation: | 1991 sourceInformation: |
| 1263 sourceInformationBuilder.buildCall(node, argumentsNode)); | 1992 sourceInformationBuilder.buildCall(node, argumentsNode)); |
| 1264 } | 1993 } |
| 1265 | 1994 |
| 1266 @override | 1995 @override |
| 1267 ir.Primitive handleStaticFunctionInvoke( | 1996 ir.Primitive handleStaticFunctionInvoke(ast.Send node, |
| 1268 ast.Send node, | |
| 1269 MethodElement function, | 1997 MethodElement function, |
| 1270 ast.NodeList arguments, | 1998 ast.NodeList argumentsNode, |
| 1271 CallStructure callStructure, | 1999 CallStructure callStructure, |
| 1272 _); | 2000 _) { |
| 2001 if (compiler.backend.isForeign(function)) { |
| 2002 return handleForeignCode(node, function, argumentsNode, callStructure); |
| 2003 } else { |
| 2004 List<ir.Primitive> arguments = <ir.Primitive>[]; |
| 2005 callStructure = translateStaticArguments(argumentsNode, function, |
| 2006 callStructure, arguments); |
| 2007 return irBuilder.buildStaticFunctionInvocation(function, |
| 2008 callStructure, |
| 2009 arguments, |
| 2010 sourceInformation: |
| 2011 sourceInformationBuilder.buildCall(node, node.selector)); |
| 2012 } |
| 2013 } |
| 1273 | 2014 |
| 1274 @override | 2015 @override |
| 1275 ir.Primitive handleStaticFunctionIncompatibleInvoke( | 2016 ir.Primitive handleStaticFunctionIncompatibleInvoke( |
| 1276 ast.Send node, | 2017 ast.Send node, |
| 1277 MethodElement function, | 2018 MethodElement function, |
| 1278 ast.NodeList arguments, | 2019 ast.NodeList arguments, |
| 1279 CallStructure callStructure, _) { | 2020 CallStructure callStructure, _) { |
| 1280 return irBuilder.buildStaticNoSuchMethod( | 2021 return irBuilder.buildStaticNoSuchMethod( |
| 1281 elements.getSelector(node), | 2022 elements.getSelector(node), |
| 1282 arguments.nodes.mapToList(visit)); | 2023 arguments.nodes.mapToList(visit)); |
| (...skipping 720 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2003 irBuilder.buildSuperIndexSet(indexSetFunction, indexValue, result); | 2744 irBuilder.buildSuperIndexSet(indexSetFunction, indexValue, result); |
| 2004 } else { | 2745 } else { |
| 2005 buildInstanceNoSuchMethod( | 2746 buildInstanceNoSuchMethod( |
| 2006 new Selector.indexSet(), | 2747 new Selector.indexSet(), |
| 2007 elements.getTypeMask(node), | 2748 elements.getTypeMask(node), |
| 2008 <ir.Primitive>[indexValue, result]); | 2749 <ir.Primitive>[indexValue, result]); |
| 2009 } | 2750 } |
| 2010 }); | 2751 }); |
| 2011 } | 2752 } |
| 2012 | 2753 |
| 2754 /// Build code to handle foreign code, that is, native JavaScript code, or |
| 2755 /// builtin values and operations of the backend. |
| 2756 ir.Primitive handleForeignCode(ast.Send node, |
| 2757 MethodElement function, |
| 2758 ast.NodeList argumentList, |
| 2759 CallStructure callStructure) { |
| 2760 |
| 2761 void validateArgumentCount({int minimum, int exactly}) { |
| 2762 assert((minimum == null) != (exactly == null)); |
| 2763 int count = 0; |
| 2764 int maximum; |
| 2765 if (exactly != null) { |
| 2766 minimum = exactly; |
| 2767 maximum = exactly; |
| 2768 } |
| 2769 for (ast.Node argument in argumentList) { |
| 2770 count++; |
| 2771 if (maximum != null && count > maximum) { |
| 2772 internalError(argument, 'Additional argument.'); |
| 2773 } |
| 2774 } |
| 2775 if (count < minimum) { |
| 2776 internalError(node, 'Expected at least $minimum arguments.'); |
| 2777 } |
| 2778 } |
| 2779 |
| 2780 /// Call a helper method from the isolate library. The isolate library uses |
| 2781 /// its own isolate structure, that encapsulates dart2js's isolate. |
| 2782 ir.Primitive buildIsolateHelperInvocation(Element element, |
| 2783 CallStructure callStructure) { |
| 2784 if (element == null) { |
| 2785 reporter.internalError(node, |
| 2786 'Isolate library and compiler mismatch.'); |
| 2787 } |
| 2788 List<ir.Primitive> arguments = <ir.Primitive>[]; |
| 2789 callStructure = translateStaticArguments(argumentList, element, |
| 2790 callStructure, arguments); |
| 2791 return irBuilder.buildStaticFunctionInvocation( |
| 2792 element, |
| 2793 callStructure, |
| 2794 arguments, |
| 2795 sourceInformation: |
| 2796 sourceInformationBuilder.buildCall(node, node.selector)); |
| 2797 } |
| 2798 |
| 2799 /// Lookup the value of the enum described by [node]. |
| 2800 getEnumValue(ast.Node node, EnumClassElement enumClass, List values) { |
| 2801 Element element = elements[node]; |
| 2802 if (element is! FieldElement || element.enclosingClass != enumClass) { |
| 2803 internalError(node, 'expected a JsBuiltin enum value'); |
| 2804 } |
| 2805 |
| 2806 int index = enumClass.enumValues.indexOf(element); |
| 2807 return values[index]; |
| 2808 } |
| 2809 |
| 2810 /// Returns the String the node evaluates to, or throws an error if the |
| 2811 /// result is not a string constant. |
| 2812 String expectStringConstant(ast.Node node) { |
| 2813 ir.Primitive nameValue = visit(node); |
| 2814 if (nameValue is ir.Constant && nameValue.value.isString) { |
| 2815 StringConstantValue constantValue = nameValue.value; |
| 2816 return constantValue.primitiveValue.slowToString(); |
| 2817 } else { |
| 2818 return internalError(node, 'expected a literal string'); |
| 2819 } |
| 2820 } |
| 2821 |
| 2822 Link<ast.Node> argumentNodes = argumentList.nodes; |
| 2823 NativeBehavior behavior = |
| 2824 compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node); |
| 2825 switch (function.name) { |
| 2826 case 'JS': |
| 2827 validateArgumentCount(minimum: 2); |
| 2828 // The first two arguments are the type and the foreign code template, |
| 2829 // which already have been analyzed by the resolver and can be retrieved |
| 2830 // using [NativeBehavior]. We can ignore these arguments in the backend. |
| 2831 List<ir.Primitive> arguments = |
| 2832 argumentNodes.skip(2).mapToList(visit, growable: false); |
| 2833 if (behavior.codeTemplate.positionalArgumentCount != arguments.length) { |
| 2834 reporter.reportErrorMessage( |
| 2835 node, MessageKind.GENERIC, |
| 2836 {'text': |
| 2837 'Mismatch between number of placeholders' |
| 2838 ' and number of arguments.'}); |
| 2839 return irBuilder.buildNullConstant(); |
| 2840 } |
| 2841 |
| 2842 if (HasCapturedPlaceholders.check(behavior.codeTemplate.ast)) { |
| 2843 reporter.reportErrorMessage(node, MessageKind.JS_PLACEHOLDER_CAPTURE); |
| 2844 return irBuilder.buildNullConstant(); |
| 2845 } |
| 2846 |
| 2847 return irBuilder.buildForeignCode(behavior.codeTemplate, arguments, |
| 2848 behavior); |
| 2849 |
| 2850 case 'DART_CLOSURE_TO_JS': |
| 2851 // TODO(ahe): This should probably take care to wrap the closure in |
| 2852 // another closure that saves the current isolate. |
| 2853 case 'RAW_DART_FUNCTION_REF': |
| 2854 validateArgumentCount(exactly: 1); |
| 2855 |
| 2856 ast.Node argument = node.arguments.single; |
| 2857 FunctionElement closure = elements[argument].implementation; |
| 2858 if (!Elements.isStaticOrTopLevelFunction(closure)) { |
| 2859 internalError(argument, |
| 2860 'only static or toplevel function supported'); |
| 2861 } |
| 2862 if (closure.functionSignature.hasOptionalParameters) { |
| 2863 internalError(argument, |
| 2864 'closures with optional parameters not supported'); |
| 2865 } |
| 2866 return irBuilder.buildForeignCode( |
| 2867 js.js.expressionTemplateYielding( |
| 2868 backend.emitter.staticFunctionAccess(closure)), |
| 2869 <ir.Primitive>[], |
| 2870 NativeBehavior.PURE, |
| 2871 dependency: closure); |
| 2872 |
| 2873 case 'JS_BUILTIN': |
| 2874 // The first argument is a description of the type and effect of the |
| 2875 // builtin, which has already been analyzed in the frontend. The second |
| 2876 // argument must be a [JsBuiltin] value. All other arguments are |
| 2877 // values used by the JavaScript template that is associated with the |
| 2878 // builtin. |
| 2879 validateArgumentCount(minimum: 2); |
| 2880 |
| 2881 ast.Node builtin = argumentNodes.tail.head; |
| 2882 JsBuiltin value = getEnumValue(builtin, helpers.jsBuiltinEnum, |
| 2883 JsBuiltin.values); |
| 2884 js.Template template = backend.emitter.builtinTemplateFor(value); |
| 2885 List<ir.Primitive> arguments = |
| 2886 argumentNodes.skip(2).mapToList(visit, growable: false); |
| 2887 return irBuilder.buildForeignCode(template, arguments, behavior); |
| 2888 |
| 2889 case 'JS_EMBEDDED_GLOBAL': |
| 2890 validateArgumentCount(exactly: 2); |
| 2891 |
| 2892 String name = expectStringConstant(argumentNodes.tail.head); |
| 2893 js.Expression access = |
| 2894 backend.emitter.generateEmbeddedGlobalAccess(name); |
| 2895 js.Template template = js.js.expressionTemplateYielding(access); |
| 2896 return irBuilder.buildForeignCode(template, <ir.Primitive>[], behavior); |
| 2897 |
| 2898 case 'JS_INTERCEPTOR_CONSTANT': |
| 2899 validateArgumentCount(exactly: 1); |
| 2900 |
| 2901 ast.Node argument = argumentNodes.head; |
| 2902 ir.Primitive argumentValue = visit(argument); |
| 2903 if (argumentValue is ir.Constant && argumentValue.value.isType) { |
| 2904 TypeConstantValue constant = argumentValue.value; |
| 2905 ConstantValue interceptorValue = |
| 2906 new InterceptorConstantValue(constant.representedType); |
| 2907 return irBuilder.buildConstant(interceptorValue); |
| 2908 } |
| 2909 return internalError(argument, 'expected Type as argument'); |
| 2910 |
| 2911 case 'JS_EFFECT': |
| 2912 return irBuilder.buildNullConstant(); |
| 2913 |
| 2914 case 'JS_GET_NAME': |
| 2915 validateArgumentCount(exactly: 1); |
| 2916 |
| 2917 ast.Node argument = argumentNodes.head; |
| 2918 JsGetName id = getEnumValue(argument, helpers.jsGetNameEnum, |
| 2919 JsGetName.values); |
| 2920 js.Name name = backend.namer.getNameForJsGetName(argument, id); |
| 2921 ConstantValue nameConstant = |
| 2922 new SyntheticConstantValue(SyntheticConstantKind.NAME, |
| 2923 js.js.quoteName(name)); |
| 2924 |
| 2925 return irBuilder.buildConstant(nameConstant); |
| 2926 |
| 2927 case 'JS_GET_FLAG': |
| 2928 validateArgumentCount(exactly: 1); |
| 2929 |
| 2930 String name = expectStringConstant(argumentNodes.first); |
| 2931 bool value = false; |
| 2932 switch (name) { |
| 2933 case 'MUST_RETAIN_METADATA': |
| 2934 value = backend.mustRetainMetadata; |
| 2935 break; |
| 2936 case 'USE_CONTENT_SECURITY_POLICY': |
| 2937 value = compiler.useContentSecurityPolicy; |
| 2938 break; |
| 2939 default: |
| 2940 internalError(node, 'Unknown internal flag "$name".'); |
| 2941 } |
| 2942 return irBuilder.buildBooleanConstant(value); |
| 2943 |
| 2944 case 'JS_STRING_CONCAT': |
| 2945 validateArgumentCount(exactly: 2); |
| 2946 List<ir.Primitive> arguments = argumentNodes.mapToList(visit); |
| 2947 return irBuilder.buildStringConcatenation(arguments); |
| 2948 |
| 2949 case 'JS_CURRENT_ISOLATE_CONTEXT': |
| 2950 validateArgumentCount(exactly: 0); |
| 2951 |
| 2952 if (!compiler.hasIsolateSupport) { |
| 2953 // If the isolate library is not used, we just generate code |
| 2954 // to fetch the current isolate. |
| 2955 continue getStaticState; |
| 2956 } |
| 2957 return buildIsolateHelperInvocation(helpers.currentIsolate, |
| 2958 CallStructure.NO_ARGS); |
| 2959 |
| 2960 getStaticState: case 'JS_GET_STATIC_STATE': |
| 2961 validateArgumentCount(exactly: 0); |
| 2962 |
| 2963 return irBuilder.buildForeignCode( |
| 2964 js.js.parseForeignJS(backend.namer.staticStateHolder), |
| 2965 const <ir.Primitive>[], |
| 2966 NativeBehavior.PURE); |
| 2967 |
| 2968 case 'JS_SET_STATIC_STATE': |
| 2969 validateArgumentCount(exactly: 1); |
| 2970 |
| 2971 ir.Primitive value = visit(argumentNodes.single); |
| 2972 String isolateName = backend.namer.staticStateHolder; |
| 2973 return irBuilder.buildForeignCode( |
| 2974 js.js.parseForeignJS("$isolateName = #"), |
| 2975 <ir.Primitive>[value], |
| 2976 NativeBehavior.PURE); |
| 2977 |
| 2978 case 'JS_CALL_IN_ISOLATE': |
| 2979 validateArgumentCount(exactly: 2); |
| 2980 |
| 2981 if (!compiler.hasIsolateSupport) { |
| 2982 ir.Primitive closure = visit(argumentNodes.tail.head); |
| 2983 return irBuilder.buildCallInvocation(closure, CallStructure.NO_ARGS, |
| 2984 const <ir.Primitive>[]); |
| 2985 } |
| 2986 return buildIsolateHelperInvocation(helpers.callInIsolate, |
| 2987 CallStructure.TWO_ARGS); |
| 2988 |
| 2989 default: |
| 2990 return giveup(node, 'unplemented native construct: ${function.name}'); |
| 2991 } |
| 2992 } |
| 2993 |
| 2013 /// Evaluates a string interpolation and appends each part to [accumulator] | 2994 /// Evaluates a string interpolation and appends each part to [accumulator] |
| 2014 /// (after stringify conversion). | 2995 /// (after stringify conversion). |
| 2015 void buildStringParts(ast.Node node, List<ir.Primitive> accumulator) { | 2996 void buildStringParts(ast.Node node, List<ir.Primitive> accumulator) { |
| 2016 if (node is ast.StringJuxtaposition) { | 2997 if (node is ast.StringJuxtaposition) { |
| 2017 buildStringParts(node.first, accumulator); | 2998 buildStringParts(node.first, accumulator); |
| 2018 buildStringParts(node.second, accumulator); | 2999 buildStringParts(node.second, accumulator); |
| 2019 } else if (node is ast.StringInterpolation) { | 3000 } else if (node is ast.StringInterpolation) { |
| 2020 buildStringParts(node.string, accumulator); | 3001 buildStringParts(node.string, accumulator); |
| 2021 for (ast.StringInterpolationPart part in node.parts) { | 3002 for (ast.StringInterpolationPart part in node.parts) { |
| 2022 buildStringParts(part.expression, accumulator); | 3003 buildStringParts(part.expression, accumulator); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2057 sourceInformation: sourceInformationBuilder.buildGet(node)); | 3038 sourceInformation: sourceInformationBuilder.buildGet(node)); |
| 2058 } | 3039 } |
| 2059 | 3040 |
| 2060 ir.Primitive visitThrow(ast.Throw node) { | 3041 ir.Primitive visitThrow(ast.Throw node) { |
| 2061 assert(irBuilder.isOpen); | 3042 assert(irBuilder.isOpen); |
| 2062 // This function is not called for throw expressions occurring as | 3043 // This function is not called for throw expressions occurring as |
| 2063 // statements. | 3044 // statements. |
| 2064 return irBuilder.buildNonTailThrow(visit(node.expression)); | 3045 return irBuilder.buildNonTailThrow(visit(node.expression)); |
| 2065 } | 3046 } |
| 2066 | 3047 |
| 2067 ir.Primitive buildInstanceNoSuchMethod( | 3048 ir.Primitive buildInstanceNoSuchMethod(Selector selector, |
| 2068 Selector selector, | |
| 2069 TypeMask mask, | 3049 TypeMask mask, |
| 2070 List<ir.Primitive> arguments); | 3050 List<ir.Primitive> arguments) { |
| 2071 | 3051 return irBuilder.buildDynamicInvocation( |
| 2072 ir.Primitive buildRuntimeError(String message); | 3052 irBuilder.buildThis(), |
| 2073 | 3053 Selectors.noSuchMethod_, |
| 2074 ir.Primitive buildAbstractClassInstantiationError(ClassElement element); | 3054 mask, |
| 3055 [irBuilder.buildInvocationMirror(selector, arguments)]); |
| 3056 } |
| 3057 |
| 3058 ir.Primitive buildRuntimeError(String message) { |
| 3059 return irBuilder.buildStaticFunctionInvocation( |
| 3060 helpers.throwRuntimeError, |
| 3061 new CallStructure.unnamed(1), |
| 3062 [irBuilder.buildStringConstant(message)]); |
| 3063 } |
| 3064 |
| 3065 ir.Primitive buildAbstractClassInstantiationError(ClassElement element) { |
| 3066 return irBuilder.buildStaticFunctionInvocation( |
| 3067 helpers.throwAbstractClassInstantiationError, |
| 3068 new CallStructure.unnamed(1), |
| 3069 [irBuilder.buildStringConstant(element.name)]); |
| 3070 } |
| 2075 | 3071 |
| 2076 @override | 3072 @override |
| 2077 ir.Primitive visitUnresolvedCompound( | 3073 ir.Primitive visitUnresolvedCompound( |
| 2078 ast.Send node, | 3074 ast.Send node, |
| 2079 Element element, | 3075 Element element, |
| 2080 op.AssignmentOperator operator, | 3076 op.AssignmentOperator operator, |
| 2081 ast.Node rhs, _) { | 3077 ast.Node rhs, _) { |
| 2082 // TODO(asgerf): What is unresolved? The getter and/or the setter? | 3078 // TODO(asgerf): What is unresolved? The getter and/or the setter? |
| 2083 // If it was the setter, we must evaluate the right-hand side. | 3079 // If it was the setter, we must evaluate the right-hand side. |
| 2084 return irBuilder.buildStaticNoSuchMethod(elements.getSelector(node), []); | 3080 return irBuilder.buildStaticNoSuchMethod(elements.getSelector(node), []); |
| (...skipping 539 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2624 } | 3620 } |
| 2625 | 3621 |
| 2626 Element get closureConverter { | 3622 Element get closureConverter { |
| 2627 return _backend.helpers.closureConverter; | 3623 return _backend.helpers.closureConverter; |
| 2628 } | 3624 } |
| 2629 | 3625 |
| 2630 void addNativeMethod(FunctionElement function) { | 3626 void addNativeMethod(FunctionElement function) { |
| 2631 _backend.emitter.nativeEmitter.nativeMethods.add(function); | 3627 _backend.emitter.nativeEmitter.nativeMethods.add(function); |
| 2632 } | 3628 } |
| 2633 } | 3629 } |
| 2634 | |
| 2635 /// IR builder specific to the JavaScript backend, coupled to the [JsIrBuilder]. | |
| 2636 class JsIrBuilderVisitor extends IrBuilderVisitor { | |
| 2637 JavaScriptBackend get backend => compiler.backend; | |
| 2638 | |
| 2639 /// Result of closure conversion for the current body of code. | |
| 2640 /// | |
| 2641 /// Will be initialized upon entering the body of a function. | |
| 2642 /// It is computed by the [ClosureTranslator]. | |
| 2643 ClosureClassMap closureClassMap; | |
| 2644 | |
| 2645 JsIrBuilderVisitor(TreeElements elements, | |
| 2646 Compiler compiler, | |
| 2647 SourceInformationBuilder sourceInformationBuilder, | |
| 2648 TypeMaskSystem typeMaskSystem) | |
| 2649 : super(elements, compiler, sourceInformationBuilder, typeMaskSystem); | |
| 2650 | |
| 2651 BackendHelpers get helpers => backend.helpers; | |
| 2652 | |
| 2653 /// Builds the IR for creating an instance of the closure class corresponding | |
| 2654 /// to the given nested function. | |
| 2655 ClosureClassElement makeSubFunction(ast.FunctionExpression node) { | |
| 2656 ClosureClassMap innerMap = | |
| 2657 compiler.closureToClassMapper.getMappingForNestedFunction(node); | |
| 2658 ClosureClassElement closureClass = innerMap.closureClassElement; | |
| 2659 return closureClass; | |
| 2660 } | |
| 2661 | |
| 2662 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) { | |
| 2663 return irBuilder.buildFunctionExpression(makeSubFunction(node), | |
| 2664 sourceInformationBuilder.buildCreate(node)); | |
| 2665 } | |
| 2666 | |
| 2667 visitFunctionDeclaration(ast.FunctionDeclaration node) { | |
| 2668 LocalFunctionElement element = elements[node.function]; | |
| 2669 Object inner = makeSubFunction(node.function); | |
| 2670 irBuilder.declareLocalFunction(element, inner, | |
| 2671 sourceInformationBuilder.buildCreate(node.function)); | |
| 2672 } | |
| 2673 | |
| 2674 Map mapValues(Map map, dynamic fn(dynamic)) { | |
| 2675 Map result = {}; | |
| 2676 map.forEach((key, value) { | |
| 2677 result[key] = fn(value); | |
| 2678 }); | |
| 2679 return result; | |
| 2680 } | |
| 2681 | |
| 2682 /// Converts closure.dart's CapturedVariable into a ClosureLocation. | |
| 2683 /// There is a 1:1 corresponce between these; we do this because the | |
| 2684 /// IR builder should not depend on synthetic elements. | |
| 2685 ClosureLocation getLocation(CapturedVariable v) { | |
| 2686 if (v is BoxFieldElement) { | |
| 2687 return new ClosureLocation(v.box, v); | |
| 2688 } else { | |
| 2689 ClosureFieldElement field = v; | |
| 2690 return new ClosureLocation(null, field); | |
| 2691 } | |
| 2692 } | |
| 2693 | |
| 2694 /// If the current function is a nested function with free variables (or a | |
| 2695 /// captured reference to `this`), returns a [ClosureEnvironment] | |
| 2696 /// indicating how to access these. | |
| 2697 ClosureEnvironment getClosureEnvironment() { | |
| 2698 if (closureClassMap.closureElement == null) return null; | |
| 2699 return new ClosureEnvironment( | |
| 2700 closureClassMap.closureElement, | |
| 2701 closureClassMap.thisLocal, | |
| 2702 mapValues(closureClassMap.freeVariableMap, getLocation)); | |
| 2703 } | |
| 2704 | |
| 2705 /// If [node] has declarations for variables that should be boxed, | |
| 2706 /// returns a [ClosureScope] naming a box to create, and enumerating the | |
| 2707 /// variables that should be stored in the box. | |
| 2708 /// | |
| 2709 /// Also see [ClosureScope]. | |
| 2710 ClosureScope getClosureScopeForNode(ast.Node node) { | |
| 2711 closurelib.ClosureScope scope = closureClassMap.capturingScopes[node]; | |
| 2712 if (scope == null) return null; | |
| 2713 // We translate a ClosureScope from closure.dart into IR builder's variant | |
| 2714 // because the IR builder should not depend on the synthetic elements | |
| 2715 // created in closure.dart. | |
| 2716 return new ClosureScope(scope.boxElement, | |
| 2717 mapValues(scope.capturedVariables, getLocation), | |
| 2718 scope.boxedLoopVariables); | |
| 2719 } | |
| 2720 | |
| 2721 /// Returns the [ClosureScope] for any function, possibly different from the | |
| 2722 /// one currently being built. | |
| 2723 ClosureScope getClosureScopeForFunction(FunctionElement function) { | |
| 2724 ClosureClassMap map = | |
| 2725 compiler.closureToClassMapper.computeClosureToClassMapping( | |
| 2726 function, | |
| 2727 function.node, | |
| 2728 elements); | |
| 2729 closurelib.ClosureScope scope = map.capturingScopes[function.node]; | |
| 2730 if (scope == null) return null; | |
| 2731 return new ClosureScope(scope.boxElement, | |
| 2732 mapValues(scope.capturedVariables, getLocation), | |
| 2733 scope.boxedLoopVariables); | |
| 2734 } | |
| 2735 | |
| 2736 ir.FunctionDefinition buildExecutable(ExecutableElement element) { | |
| 2737 return nullIfGiveup(() { | |
| 2738 ir.FunctionDefinition root; | |
| 2739 switch (element.kind) { | |
| 2740 case ElementKind.GENERATIVE_CONSTRUCTOR: | |
| 2741 root = buildConstructor(element); | |
| 2742 break; | |
| 2743 | |
| 2744 case ElementKind.GENERATIVE_CONSTRUCTOR_BODY: | |
| 2745 root = buildConstructorBody(element); | |
| 2746 break; | |
| 2747 | |
| 2748 case ElementKind.FACTORY_CONSTRUCTOR: | |
| 2749 case ElementKind.FUNCTION: | |
| 2750 case ElementKind.GETTER: | |
| 2751 case ElementKind.SETTER: | |
| 2752 root = buildFunction(element); | |
| 2753 break; | |
| 2754 | |
| 2755 case ElementKind.FIELD: | |
| 2756 if (Elements.isStaticOrTopLevel(element)) { | |
| 2757 root = buildStaticFieldInitializer(element); | |
| 2758 } else { | |
| 2759 // Instance field initializers are inlined in the constructor, | |
| 2760 // so we shouldn't need to build anything here. | |
| 2761 // TODO(asgerf): But what should we return? | |
| 2762 return null; | |
| 2763 } | |
| 2764 break; | |
| 2765 | |
| 2766 default: | |
| 2767 reporter.internalError(element, "Unexpected element type $element"); | |
| 2768 } | |
| 2769 return root; | |
| 2770 }); | |
| 2771 } | |
| 2772 | |
| 2773 ir.FunctionDefinition buildStaticFieldInitializer(FieldElement element) { | |
| 2774 if (!backend.constants.lazyStatics.contains(element)) { | |
| 2775 return null; // Nothing to do. | |
| 2776 } | |
| 2777 closureClassMap = | |
| 2778 compiler.closureToClassMapper.computeClosureToClassMapping( | |
| 2779 element, | |
| 2780 element.node, | |
| 2781 elements); | |
| 2782 IrBuilder builder = getBuilderFor(element); | |
| 2783 return withBuilder(builder, () { | |
| 2784 irBuilder.buildFunctionHeader(<Local>[]); | |
| 2785 ir.Primitive initialValue = visit(element.initializer); | |
| 2786 ast.VariableDefinitions node = element.node; | |
| 2787 ast.SendSet sendSet = node.definitions.nodes.head; | |
| 2788 irBuilder.buildReturn( | |
| 2789 value: initialValue, | |
| 2790 sourceInformation: | |
| 2791 sourceInformationBuilder.buildReturn(sendSet.assignmentOperator)); | |
| 2792 return irBuilder.makeFunctionDefinition(); | |
| 2793 }); | |
| 2794 } | |
| 2795 | |
| 2796 /// Make a visitor suitable for translating ASTs taken from [context]. | |
| 2797 /// | |
| 2798 /// Every visitor can only be applied to nodes in one context, because | |
| 2799 /// the [elements] field is specific to that context. | |
| 2800 JsIrBuilderVisitor makeVisitorForContext(AstElement context) { | |
| 2801 return new JsIrBuilderVisitor( | |
| 2802 context.resolvedAst.elements, | |
| 2803 compiler, | |
| 2804 sourceInformationBuilder.forContext(context), | |
| 2805 typeMaskSystem); | |
| 2806 } | |
| 2807 | |
| 2808 /// Builds the IR for an [expression] taken from a different [context]. | |
| 2809 /// | |
| 2810 /// Such expressions need to be compiled with a different [sourceFile] and | |
| 2811 /// [elements] mapping. | |
| 2812 ir.Primitive inlineExpression(AstElement context, ast.Expression expression) { | |
| 2813 JsIrBuilderVisitor visitor = makeVisitorForContext(context); | |
| 2814 return visitor.withBuilder(irBuilder, () => visitor.visit(expression)); | |
| 2815 } | |
| 2816 | |
| 2817 /// Builds the IR for a constant taken from a different [context]. | |
| 2818 /// | |
| 2819 /// Such constants need to be compiled with a different [sourceFile] and | |
| 2820 /// [elements] mapping. | |
| 2821 ir.Primitive inlineConstant(AstElement context, ast.Expression exp) { | |
| 2822 JsIrBuilderVisitor visitor = makeVisitorForContext(context); | |
| 2823 return visitor.withBuilder(irBuilder, () => visitor.translateConstant(exp)); | |
| 2824 } | |
| 2825 | |
| 2826 IrBuilder getBuilderFor(Element element) { | |
| 2827 return new IrBuilder( | |
| 2828 new GlobalProgramInformation(compiler), | |
| 2829 compiler.backend.constants, | |
| 2830 element); | |
| 2831 } | |
| 2832 | |
| 2833 /// Builds the IR for a given constructor. | |
| 2834 /// | |
| 2835 /// 1. Computes the type held in all own or "inherited" type variables. | |
| 2836 /// 2. Evaluates all own or inherited field initializers. | |
| 2837 /// 3. Creates the object and assigns its fields and runtime type. | |
| 2838 /// 4. Calls constructor body and super constructor bodies. | |
| 2839 /// 5. Returns the created object. | |
| 2840 ir.FunctionDefinition buildConstructor(ConstructorElement constructor) { | |
| 2841 // TODO(asgerf): Optimization: If constructor is redirecting, then just | |
| 2842 // evaluate arguments and call the target constructor. | |
| 2843 constructor = constructor.implementation; | |
| 2844 ClassElement classElement = constructor.enclosingClass.implementation; | |
| 2845 | |
| 2846 IrBuilder builder = getBuilderFor(constructor); | |
| 2847 | |
| 2848 final bool requiresTypeInformation = | |
| 2849 builder.program.requiresRuntimeTypesFor(classElement); | |
| 2850 | |
| 2851 return withBuilder(builder, () { | |
| 2852 // Setup parameters and create a box if anything is captured. | |
| 2853 List<Local> parameters = <Local>[]; | |
| 2854 constructor.functionSignature.orderedForEachParameter( | |
| 2855 (ParameterElement p) => parameters.add(p)); | |
| 2856 | |
| 2857 int firstTypeArgumentParameterIndex; | |
| 2858 | |
| 2859 // If instances of the class may need runtime type information, we add a | |
| 2860 // synthetic parameter for each type parameter. | |
| 2861 if (requiresTypeInformation) { | |
| 2862 firstTypeArgumentParameterIndex = parameters.length; | |
| 2863 classElement.typeVariables.forEach((TypeVariableType variable) { | |
| 2864 parameters.add(new TypeVariableLocal(variable, constructor)); | |
| 2865 }); | |
| 2866 } else { | |
| 2867 classElement.typeVariables.forEach((TypeVariableType variable) { | |
| 2868 irBuilder.declareTypeVariable(variable, const DynamicType()); | |
| 2869 }); | |
| 2870 } | |
| 2871 | |
| 2872 // Create IR parameters and setup the environment. | |
| 2873 List<ir.Parameter> irParameters = builder.buildFunctionHeader(parameters, | |
| 2874 closureScope: getClosureScopeForFunction(constructor)); | |
| 2875 | |
| 2876 // Create a list of the values of all type argument parameters, if any. | |
| 2877 List<ir.Primitive> typeInformation; | |
| 2878 if (requiresTypeInformation) { | |
| 2879 typeInformation = irParameters.sublist(firstTypeArgumentParameterIndex); | |
| 2880 } else { | |
| 2881 typeInformation = const <ir.Primitive>[]; | |
| 2882 } | |
| 2883 | |
| 2884 // -- Load values for type variables declared on super classes -- | |
| 2885 // Field initializers for super classes can reference these, so they | |
| 2886 // must be available before evaluating field initializers. | |
| 2887 // This could be interleaved with field initialization, but we choose do | |
| 2888 // get it out of the way here to avoid complications with mixins. | |
| 2889 loadTypeVariablesForSuperClasses(classElement); | |
| 2890 | |
| 2891 /// Maps each field from this class or a superclass to its initial value. | |
| 2892 Map<FieldElement, ir.Primitive> fieldValues = | |
| 2893 <FieldElement, ir.Primitive>{}; | |
| 2894 | |
| 2895 // -- Evaluate field initializers --- | |
| 2896 // Evaluate field initializers in constructor and super constructors. | |
| 2897 List<ConstructorElement> constructorList = <ConstructorElement>[]; | |
| 2898 evaluateConstructorFieldInitializers( | |
| 2899 constructor, constructorList, fieldValues); | |
| 2900 | |
| 2901 // All parameters in all constructors are now bound in the environment. | |
| 2902 // BoxLocals for captured parameters are also in the environment. | |
| 2903 // The initial value of all fields are now bound in [fieldValues]. | |
| 2904 | |
| 2905 // --- Create the object --- | |
| 2906 // Get the initial field values in the canonical order. | |
| 2907 List<ir.Primitive> instanceArguments = <ir.Primitive>[]; | |
| 2908 classElement.forEachInstanceField((ClassElement c, FieldElement field) { | |
| 2909 ir.Primitive value = fieldValues[field]; | |
| 2910 if (value != null) { | |
| 2911 instanceArguments.add(value); | |
| 2912 } else { | |
| 2913 assert(backend.isNativeOrExtendsNative(c)); | |
| 2914 // Native fields are initialized elsewhere. | |
| 2915 } | |
| 2916 }, includeSuperAndInjectedMembers: true); | |
| 2917 | |
| 2918 ir.Primitive instance = new ir.CreateInstance( | |
| 2919 classElement, | |
| 2920 instanceArguments, | |
| 2921 typeInformation, | |
| 2922 constructor.hasNode | |
| 2923 ? sourceInformationBuilder.buildCreate(constructor.node) | |
| 2924 // TODO(johnniwinther): Provide source information for creation | |
| 2925 // through synthetic constructors. | |
| 2926 : null); | |
| 2927 irBuilder.add(new ir.LetPrim(instance)); | |
| 2928 | |
| 2929 // --- Call constructor bodies --- | |
| 2930 for (ConstructorElement target in constructorList) { | |
| 2931 ConstructorBodyElement bodyElement = getConstructorBody(target); | |
| 2932 if (bodyElement == null) continue; // Skip if constructor has no body. | |
| 2933 List<ir.Primitive> bodyArguments = <ir.Primitive>[]; | |
| 2934 for (Local param in getConstructorBodyParameters(bodyElement)) { | |
| 2935 bodyArguments.add(irBuilder.environment.lookup(param)); | |
| 2936 } | |
| 2937 irBuilder.buildInvokeDirectly(bodyElement, instance, bodyArguments); | |
| 2938 } | |
| 2939 | |
| 2940 // --- step 4: return the created object ---- | |
| 2941 irBuilder.buildReturn( | |
| 2942 value: instance, | |
| 2943 sourceInformation: | |
| 2944 sourceInformationBuilder.buildImplicitReturn(constructor)); | |
| 2945 | |
| 2946 return irBuilder.makeFunctionDefinition(); | |
| 2947 }); | |
| 2948 } | |
| 2949 | |
| 2950 /// Evaluates all field initializers on [constructor] and all constructors | |
| 2951 /// invoked through `this()` or `super()` ("superconstructors"). | |
| 2952 /// | |
| 2953 /// The resulting field values will be available in [fieldValues]. The values | |
| 2954 /// are not stored in any fields. | |
| 2955 /// | |
| 2956 /// This procedure assumes that the parameters to [constructor] are available | |
| 2957 /// in the IR builder's environment. | |
| 2958 /// | |
| 2959 /// The parameters to superconstructors are, however, assumed *not* to be in | |
| 2960 /// the environment, but will be put there by this procedure. | |
| 2961 /// | |
| 2962 /// All constructors will be added to [supers], with superconstructors first. | |
| 2963 void evaluateConstructorFieldInitializers( | |
| 2964 ConstructorElement constructor, | |
| 2965 List<ConstructorElement> supers, | |
| 2966 Map<FieldElement, ir.Primitive> fieldValues) { | |
| 2967 assert(constructor.isImplementation); | |
| 2968 assert(constructor == elements.analyzedElement); | |
| 2969 ClassElement enclosingClass = constructor.enclosingClass.implementation; | |
| 2970 // Evaluate declaration-site field initializers, unless this constructor | |
| 2971 // redirects to another using a `this()` initializer. In that case, these | |
| 2972 // will be initialized by the effective target constructor. | |
| 2973 if (!constructor.isRedirectingGenerative) { | |
| 2974 enclosingClass.forEachInstanceField((ClassElement c, FieldElement field) { | |
| 2975 if (field.initializer != null) { | |
| 2976 fieldValues[field] = inlineExpression(field, field.initializer); | |
| 2977 } else { | |
| 2978 if (backend.isNativeOrExtendsNative(c)) { | |
| 2979 // Native field is initialized elsewhere. | |
| 2980 } else { | |
| 2981 // Fields without an initializer default to null. | |
| 2982 // This value will be overwritten below if an initializer is found. | |
| 2983 fieldValues[field] = irBuilder.buildNullConstant(); | |
| 2984 } | |
| 2985 } | |
| 2986 }); | |
| 2987 } | |
| 2988 // If this is a mixin constructor, it does not have its own parameter list | |
| 2989 // or initializer list. Directly forward to the super constructor. | |
| 2990 // Note that the declaration-site initializers originating from the | |
| 2991 // mixed-in class were handled above. | |
| 2992 if (enclosingClass.isMixinApplication) { | |
| 2993 forwardSynthesizedMixinConstructor(constructor, supers, fieldValues); | |
| 2994 return; | |
| 2995 } | |
| 2996 // Evaluate initializing parameters, e.g. `Foo(this.x)`. | |
| 2997 constructor.functionSignature.orderedForEachParameter( | |
| 2998 (ParameterElement parameter) { | |
| 2999 if (parameter.isInitializingFormal) { | |
| 3000 InitializingFormalElement fieldParameter = parameter; | |
| 3001 fieldValues[fieldParameter.fieldElement] = | |
| 3002 irBuilder.buildLocalVariableGet(parameter); | |
| 3003 } | |
| 3004 }); | |
| 3005 // Evaluate constructor initializers, e.g. `Foo() : x = 50`. | |
| 3006 ast.FunctionExpression node = constructor.node; | |
| 3007 bool hasConstructorCall = false; // Has this() or super() initializer? | |
| 3008 if (node != null && node.initializers != null) { | |
| 3009 for(ast.Node initializer in node.initializers) { | |
| 3010 if (initializer is ast.SendSet) { | |
| 3011 // Field initializer. | |
| 3012 FieldElement field = elements[initializer]; | |
| 3013 fieldValues[field] = visit(initializer.arguments.head); | |
| 3014 } else if (initializer is ast.Send) { | |
| 3015 // Super or this initializer. | |
| 3016 ConstructorElement target = elements[initializer].implementation; | |
| 3017 Selector selector = elements.getSelector(initializer); | |
| 3018 List<ir.Primitive> arguments = initializer.arguments.mapToList(visit); | |
| 3019 evaluateConstructorCallFromInitializer( | |
| 3020 target, | |
| 3021 selector.callStructure, | |
| 3022 arguments, | |
| 3023 supers, | |
| 3024 fieldValues); | |
| 3025 hasConstructorCall = true; | |
| 3026 } else { | |
| 3027 reporter.internalError(initializer, | |
| 3028 "Unexpected initializer type $initializer"); | |
| 3029 } | |
| 3030 } | |
| 3031 } | |
| 3032 // If no super() or this() was found, also call default superconstructor. | |
| 3033 if (!hasConstructorCall && !enclosingClass.isObject) { | |
| 3034 ClassElement superClass = enclosingClass.superclass; | |
| 3035 FunctionElement target = superClass.lookupDefaultConstructor(); | |
| 3036 if (target == null) { | |
| 3037 reporter.internalError(superClass, "No default constructor available."); | |
| 3038 } | |
| 3039 target = target.implementation; | |
| 3040 evaluateConstructorCallFromInitializer( | |
| 3041 target, | |
| 3042 CallStructure.NO_ARGS, | |
| 3043 const [], | |
| 3044 supers, | |
| 3045 fieldValues); | |
| 3046 } | |
| 3047 // Add this constructor after the superconstructors. | |
| 3048 supers.add(constructor); | |
| 3049 } | |
| 3050 | |
| 3051 /// Evaluates a call to the given constructor from an initializer list. | |
| 3052 /// | |
| 3053 /// Calls [loadArguments] and [evaluateConstructorFieldInitializers] in a | |
| 3054 /// visitor that has the proper [TreeElements] mapping. | |
| 3055 void evaluateConstructorCallFromInitializer( | |
| 3056 ConstructorElement target, | |
| 3057 CallStructure call, | |
| 3058 List<ir.Primitive> arguments, | |
| 3059 List<ConstructorElement> supers, | |
| 3060 Map<FieldElement, ir.Primitive> fieldValues) { | |
| 3061 JsIrBuilderVisitor visitor = makeVisitorForContext(target); | |
| 3062 visitor.withBuilder(irBuilder, () { | |
| 3063 visitor.loadArguments(target, call, arguments); | |
| 3064 visitor.evaluateConstructorFieldInitializers(target, supers, fieldValues); | |
| 3065 }); | |
| 3066 } | |
| 3067 | |
| 3068 /// Evaluate the implicit super call in the given mixin constructor. | |
| 3069 void forwardSynthesizedMixinConstructor( | |
| 3070 ConstructorElement constructor, | |
| 3071 List<ConstructorElement> supers, | |
| 3072 Map<FieldElement, ir.Primitive> fieldValues) { | |
| 3073 assert(constructor.enclosingClass.implementation.isMixinApplication); | |
| 3074 assert(constructor.isSynthesized); | |
| 3075 ConstructorElement target = | |
| 3076 constructor.definingConstructor.implementation; | |
| 3077 // The resolver gives us the exact same FunctionSignature for the two | |
| 3078 // constructors. The parameters for the synthesized constructor | |
| 3079 // are already in the environment, so the target constructor's parameters | |
| 3080 // are also in the environment since their elements are the same. | |
| 3081 assert(constructor.functionSignature == target.functionSignature); | |
| 3082 JsIrBuilderVisitor visitor = makeVisitorForContext(target); | |
| 3083 visitor.withBuilder(irBuilder, () { | |
| 3084 visitor.evaluateConstructorFieldInitializers(target, supers, fieldValues); | |
| 3085 }); | |
| 3086 } | |
| 3087 | |
| 3088 /// Loads the type variables for all super classes of [superClass] into the | |
| 3089 /// IR builder's environment with their corresponding values. | |
| 3090 /// | |
| 3091 /// The type variables for [currentClass] must already be in the IR builder's | |
| 3092 /// environment. | |
| 3093 /// | |
| 3094 /// Type variables are stored as [TypeVariableLocal] in the environment. | |
| 3095 /// | |
| 3096 /// This ensures that access to type variables mentioned inside the | |
| 3097 /// constructors and initializers will happen through the local environment | |
| 3098 /// instead of using 'this'. | |
| 3099 void loadTypeVariablesForSuperClasses(ClassElement currentClass) { | |
| 3100 if (currentClass.isObject) return; | |
| 3101 loadTypeVariablesForType(currentClass.supertype); | |
| 3102 if (currentClass is MixinApplicationElement) { | |
| 3103 loadTypeVariablesForType(currentClass.mixinType); | |
| 3104 } | |
| 3105 } | |
| 3106 | |
| 3107 /// Loads all type variables for [type] and all of its super classes into | |
| 3108 /// the environment. All type variables mentioned in [type] must already | |
| 3109 /// be in the environment. | |
| 3110 void loadTypeVariablesForType(InterfaceType type) { | |
| 3111 ClassElement clazz = type.element; | |
| 3112 assert(clazz.typeVariables.length == type.typeArguments.length); | |
| 3113 for (int i = 0; i < clazz.typeVariables.length; ++i) { | |
| 3114 irBuilder.declareTypeVariable(clazz.typeVariables[i], | |
| 3115 type.typeArguments[i]); | |
| 3116 } | |
| 3117 loadTypeVariablesForSuperClasses(clazz); | |
| 3118 } | |
| 3119 | |
| 3120 /// In preparation of inlining (part of) [target], the [arguments] are moved | |
| 3121 /// into the environment bindings for the corresponding parameters. | |
| 3122 /// | |
| 3123 /// Defaults for optional arguments are evaluated in order to ensure | |
| 3124 /// all parameters are available in the environment. | |
| 3125 void loadArguments(ConstructorElement target, | |
| 3126 CallStructure call, | |
| 3127 List<ir.Primitive> arguments) { | |
| 3128 assert(target.isImplementation); | |
| 3129 assert(target == elements.analyzedElement); | |
| 3130 FunctionSignature signature = target.functionSignature; | |
| 3131 | |
| 3132 // Establish a scope in case parameters are captured. | |
| 3133 ClosureScope scope = getClosureScopeForFunction(target); | |
| 3134 irBuilder.enterScope(scope); | |
| 3135 | |
| 3136 // Load required parameters | |
| 3137 int index = 0; | |
| 3138 signature.forEachRequiredParameter((ParameterElement param) { | |
| 3139 irBuilder.declareLocalVariable(param, initialValue: arguments[index]); | |
| 3140 index++; | |
| 3141 }); | |
| 3142 | |
| 3143 // Load optional parameters, evaluating default values for omitted ones. | |
| 3144 signature.forEachOptionalParameter((ParameterElement param) { | |
| 3145 ir.Primitive value; | |
| 3146 // Load argument if provided. | |
| 3147 if (signature.optionalParametersAreNamed) { | |
| 3148 int nameIndex = call.namedArguments.indexOf(param.name); | |
| 3149 if (nameIndex != -1) { | |
| 3150 int translatedIndex = call.positionalArgumentCount + nameIndex; | |
| 3151 value = arguments[translatedIndex]; | |
| 3152 } | |
| 3153 } else if (index < arguments.length) { | |
| 3154 value = arguments[index]; | |
| 3155 } | |
| 3156 // Load default if argument was not provided. | |
| 3157 if (value == null) { | |
| 3158 if (param.initializer != null) { | |
| 3159 value = visit(param.initializer); | |
| 3160 } else { | |
| 3161 value = irBuilder.buildNullConstant(); | |
| 3162 } | |
| 3163 } | |
| 3164 irBuilder.declareLocalVariable(param, initialValue: value); | |
| 3165 index++; | |
| 3166 }); | |
| 3167 } | |
| 3168 | |
| 3169 /** | |
| 3170 * Returns the constructor body associated with the given constructor or | |
| 3171 * creates a new constructor body, if none can be found. | |
| 3172 * | |
| 3173 * Returns `null` if the constructor does not have a body. | |
| 3174 */ | |
| 3175 ConstructorBodyElement getConstructorBody(FunctionElement constructor) { | |
| 3176 // TODO(asgerf): This is largely inherited from the SSA builder. | |
| 3177 // The ConstructorBodyElement has an invalid function signature, but we | |
| 3178 // cannot add a BoxLocal as parameter, because BoxLocal is not an element. | |
| 3179 // Instead of forging ParameterElements to forge a FunctionSignature, we | |
| 3180 // need a way to create backend methods without creating more fake elements. | |
| 3181 assert(constructor.isGenerativeConstructor); | |
| 3182 assert(constructor.isImplementation); | |
| 3183 if (constructor.isSynthesized) return null; | |
| 3184 ast.FunctionExpression node = constructor.node; | |
| 3185 // If we know the body doesn't have any code, we don't generate it. | |
| 3186 if (!node.hasBody()) return null; | |
| 3187 if (node.hasEmptyBody()) return null; | |
| 3188 ClassElement classElement = constructor.enclosingClass; | |
| 3189 ConstructorBodyElement bodyElement; | |
| 3190 classElement.forEachBackendMember((Element backendMember) { | |
| 3191 if (backendMember.isGenerativeConstructorBody) { | |
| 3192 ConstructorBodyElement body = backendMember; | |
| 3193 if (body.constructor == constructor) { | |
| 3194 bodyElement = backendMember; | |
| 3195 } | |
| 3196 } | |
| 3197 }); | |
| 3198 if (bodyElement == null) { | |
| 3199 bodyElement = new ConstructorBodyElementX(constructor); | |
| 3200 classElement.addBackendMember(bodyElement); | |
| 3201 | |
| 3202 if (constructor.isPatch) { | |
| 3203 // Create origin body element for patched constructors. | |
| 3204 ConstructorBodyElementX patch = bodyElement; | |
| 3205 ConstructorBodyElementX origin = | |
| 3206 new ConstructorBodyElementX(constructor.origin); | |
| 3207 origin.applyPatch(patch); | |
| 3208 classElement.origin.addBackendMember(bodyElement.origin); | |
| 3209 } | |
| 3210 } | |
| 3211 assert(bodyElement.isGenerativeConstructorBody); | |
| 3212 return bodyElement; | |
| 3213 } | |
| 3214 | |
| 3215 /// The list of parameters to send from the generative constructor | |
| 3216 /// to the generative constructor body. | |
| 3217 /// | |
| 3218 /// Boxed parameters are not in the list, instead, a [BoxLocal] is passed | |
| 3219 /// containing the boxed parameters. | |
| 3220 /// | |
| 3221 /// For example, given the following constructor, | |
| 3222 /// | |
| 3223 /// Foo(x, y) : field = (() => ++x) { print(x + y) } | |
| 3224 /// | |
| 3225 /// the argument `x` would be replaced by a [BoxLocal]: | |
| 3226 /// | |
| 3227 /// Foo_body(box0, y) { print(box0.x + y) } | |
| 3228 /// | |
| 3229 List<Local> getConstructorBodyParameters(ConstructorBodyElement body) { | |
| 3230 List<Local> parameters = <Local>[]; | |
| 3231 ClosureScope scope = getClosureScopeForFunction(body.constructor); | |
| 3232 if (scope != null) { | |
| 3233 parameters.add(scope.box); | |
| 3234 } | |
| 3235 body.functionSignature.orderedForEachParameter((ParameterElement param) { | |
| 3236 if (scope != null && scope.capturedVariables.containsKey(param)) { | |
| 3237 // Do not pass this parameter; the box will carry its value. | |
| 3238 } else { | |
| 3239 parameters.add(param); | |
| 3240 } | |
| 3241 }); | |
| 3242 return parameters; | |
| 3243 } | |
| 3244 | |
| 3245 TryBoxedVariables _analyzeTryBoxedVariables(ast.Node node) { | |
| 3246 TryBoxedVariables variables = new TryBoxedVariables(elements); | |
| 3247 try { | |
| 3248 variables.analyze(node); | |
| 3249 } catch (e) { | |
| 3250 bailoutMessage = variables.bailoutMessage; | |
| 3251 rethrow; | |
| 3252 } | |
| 3253 return variables; | |
| 3254 } | |
| 3255 | |
| 3256 /// Builds the IR for the body of a constructor. | |
| 3257 /// | |
| 3258 /// This function is invoked from one or more "factory" constructors built by | |
| 3259 /// [buildConstructor]. | |
| 3260 ir.FunctionDefinition buildConstructorBody(ConstructorBodyElement body) { | |
| 3261 ConstructorElement constructor = body.constructor; | |
| 3262 ast.FunctionExpression node = constructor.node; | |
| 3263 closureClassMap = | |
| 3264 compiler.closureToClassMapper.computeClosureToClassMapping( | |
| 3265 constructor, | |
| 3266 node, | |
| 3267 elements); | |
| 3268 | |
| 3269 // We compute variables boxed in mutable variables on entry to each try | |
| 3270 // block, not including variables captured by a closure (which are boxed | |
| 3271 // in the heap). This duplicates some of the work of closure conversion | |
| 3272 // without directly using the results. This duplication is wasteful and | |
| 3273 // error-prone. | |
| 3274 // TODO(kmillikin): We should combine closure conversion and try/catch | |
| 3275 // variable analysis in some way. | |
| 3276 TryBoxedVariables variables = _analyzeTryBoxedVariables(node); | |
| 3277 tryStatements = variables.tryStatements; | |
| 3278 IrBuilder builder = getBuilderFor(body); | |
| 3279 | |
| 3280 return withBuilder(builder, () { | |
| 3281 irBuilder.buildConstructorBodyHeader(getConstructorBodyParameters(body), | |
| 3282 getClosureScopeForNode(node)); | |
| 3283 visit(node.body); | |
| 3284 return irBuilder.makeFunctionDefinition(); | |
| 3285 }); | |
| 3286 } | |
| 3287 | |
| 3288 ir.FunctionDefinition buildFunction(FunctionElement element) { | |
| 3289 assert(invariant(element, element.isImplementation)); | |
| 3290 ast.FunctionExpression node = element.node; | |
| 3291 | |
| 3292 assert(!element.isSynthesized); | |
| 3293 assert(node != null); | |
| 3294 assert(elements[node] != null); | |
| 3295 | |
| 3296 closureClassMap = | |
| 3297 compiler.closureToClassMapper.computeClosureToClassMapping( | |
| 3298 element, | |
| 3299 node, | |
| 3300 elements); | |
| 3301 TryBoxedVariables variables = _analyzeTryBoxedVariables(node); | |
| 3302 tryStatements = variables.tryStatements; | |
| 3303 IrBuilder builder = getBuilderFor(element); | |
| 3304 return withBuilder(builder, () => _makeFunctionBody(element, node)); | |
| 3305 } | |
| 3306 | |
| 3307 /// Creates a primitive for the default value of [parameter]. | |
| 3308 ir.Primitive translateDefaultValue(ParameterElement parameter) { | |
| 3309 if (parameter.initializer == null) { | |
| 3310 return irBuilder.buildNullConstant(); | |
| 3311 } else { | |
| 3312 return inlineConstant(parameter.executableContext, parameter.initializer); | |
| 3313 } | |
| 3314 } | |
| 3315 | |
| 3316 CallStructure normalizeStaticArguments(CallStructure callStructure, | |
| 3317 FunctionElement target, | |
| 3318 List<ir.Primitive> arguments) { | |
| 3319 target = target.implementation; | |
| 3320 FunctionSignature signature = target.functionSignature; | |
| 3321 if (!signature.optionalParametersAreNamed && | |
| 3322 signature.parameterCount == arguments.length) { | |
| 3323 return callStructure; | |
| 3324 } | |
| 3325 | |
| 3326 if (!signature.optionalParametersAreNamed) { | |
| 3327 int i = signature.requiredParameterCount; | |
| 3328 signature.forEachOptionalParameter((ParameterElement element) { | |
| 3329 if (i < callStructure.positionalArgumentCount) { | |
| 3330 ++i; | |
| 3331 } else { | |
| 3332 arguments.add(translateDefaultValue(element)); | |
| 3333 } | |
| 3334 }); | |
| 3335 return new CallStructure(signature.parameterCount); | |
| 3336 } | |
| 3337 | |
| 3338 int offset = signature.requiredParameterCount; | |
| 3339 List<ir.Primitive> namedArguments = arguments.sublist(offset); | |
| 3340 arguments.length = offset; | |
| 3341 List<String> normalizedNames = <String>[]; | |
| 3342 // Iterate over the optional parameters of the signature, and try to | |
| 3343 // find them in the callStructure's named arguments. If found, we use the | |
| 3344 // value in the temporary list, otherwise the default value. | |
| 3345 signature.orderedOptionalParameters.forEach((ParameterElement element) { | |
| 3346 int nameIndex = callStructure.namedArguments.indexOf(element.name); | |
| 3347 arguments.add(nameIndex == -1 ? translateDefaultValue(element) | |
| 3348 : namedArguments[nameIndex]); | |
| 3349 normalizedNames.add(element.name); | |
| 3350 }); | |
| 3351 return new CallStructure(signature.parameterCount, normalizedNames); | |
| 3352 } | |
| 3353 | |
| 3354 CallStructure normalizeDynamicArguments(CallStructure callStructure, | |
| 3355 List<ir.Primitive> arguments) { | |
| 3356 assert(arguments.length == callStructure.argumentCount); | |
| 3357 if (callStructure.namedArguments.isEmpty) return callStructure; | |
| 3358 int destinationIndex = callStructure.positionalArgumentCount; | |
| 3359 List<ir.Primitive> namedArguments = arguments.sublist(destinationIndex); | |
| 3360 for (String argName in callStructure.getOrderedNamedArguments()) { | |
| 3361 int sourceIndex = callStructure.namedArguments.indexOf(argName); | |
| 3362 arguments[destinationIndex++] = namedArguments[sourceIndex]; | |
| 3363 } | |
| 3364 return new CallStructure(callStructure.argumentCount, | |
| 3365 callStructure.getOrderedNamedArguments()); | |
| 3366 } | |
| 3367 | |
| 3368 @override | |
| 3369 ir.Primitive handleConstructorInvoke( | |
| 3370 ast.NewExpression node, | |
| 3371 ConstructorElement constructor, | |
| 3372 DartType type, | |
| 3373 ast.NodeList argumentsNode, | |
| 3374 CallStructure callStructure, | |
| 3375 _) { | |
| 3376 | |
| 3377 // TODO(sigmund): move these checks down after visiting arguments | |
| 3378 // (see issue #25355) | |
| 3379 ast.Send send = node.send; | |
| 3380 // If an allocation refers to a type using a deferred import prefix (e.g. | |
| 3381 // `new lib.A()`), we must ensure that the deferred import has already been | |
| 3382 // loaded. | |
| 3383 var prefix = compiler.deferredLoadTask.deferredPrefixElement( | |
| 3384 send, elements); | |
| 3385 if (prefix != null) buildCheckDeferredIsLoaded(prefix, send); | |
| 3386 | |
| 3387 // We also emit deferred import checks when using redirecting factories that | |
| 3388 // refer to deferred prefixes. | |
| 3389 if (constructor.isRedirectingFactory && !constructor.isCyclicRedirection) { | |
| 3390 ConstructorElement current = constructor; | |
| 3391 while (current.isRedirectingFactory) { | |
| 3392 var prefix = current.redirectionDeferredPrefix; | |
| 3393 if (prefix != null) buildCheckDeferredIsLoaded(prefix, send); | |
| 3394 current = current.immediateRedirectionTarget; | |
| 3395 } | |
| 3396 } | |
| 3397 | |
| 3398 List<ir.Primitive> arguments = argumentsNode.nodes.mapToList(visit); | |
| 3399 // Use default values from the effective target, not the immediate target. | |
| 3400 ConstructorElement target = constructor.effectiveTarget; | |
| 3401 | |
| 3402 callStructure = normalizeStaticArguments(callStructure, target, arguments); | |
| 3403 TypeMask allocationSiteType; | |
| 3404 | |
| 3405 if (Elements.isFixedListConstructorCall(constructor, send, compiler) || | |
| 3406 Elements.isGrowableListConstructorCall(constructor, send, compiler) || | |
| 3407 Elements.isFilledListConstructorCall(constructor, send, compiler) || | |
| 3408 Elements.isConstructorOfTypedArraySubclass(constructor, compiler)) { | |
| 3409 allocationSiteType = getAllocationSiteType(send); | |
| 3410 } | |
| 3411 return irBuilder.buildConstructorInvocation( | |
| 3412 target, | |
| 3413 callStructure, | |
| 3414 constructor.computeEffectiveTargetType(type), | |
| 3415 arguments, | |
| 3416 sourceInformationBuilder.buildNew(node), | |
| 3417 allocationSiteType: allocationSiteType); | |
| 3418 } | |
| 3419 | |
| 3420 @override | |
| 3421 ir.Primitive buildInstanceNoSuchMethod(Selector selector, | |
| 3422 TypeMask mask, | |
| 3423 List<ir.Primitive> arguments) { | |
| 3424 return irBuilder.buildDynamicInvocation( | |
| 3425 irBuilder.buildThis(), | |
| 3426 Selectors.noSuchMethod_, | |
| 3427 mask, | |
| 3428 [irBuilder.buildInvocationMirror(selector, arguments)]); | |
| 3429 } | |
| 3430 | |
| 3431 @override | |
| 3432 ir.Primitive buildRuntimeError(String message) { | |
| 3433 return irBuilder.buildStaticFunctionInvocation( | |
| 3434 backend.helpers.throwRuntimeError, | |
| 3435 new CallStructure.unnamed(1), | |
| 3436 [irBuilder.buildStringConstant(message)]); | |
| 3437 } | |
| 3438 | |
| 3439 @override | |
| 3440 ir.Primitive buildAbstractClassInstantiationError(ClassElement element) { | |
| 3441 return irBuilder.buildStaticFunctionInvocation( | |
| 3442 backend.helpers.throwAbstractClassInstantiationError, | |
| 3443 new CallStructure.unnamed(1), | |
| 3444 [irBuilder.buildStringConstant(element.name)]); | |
| 3445 } | |
| 3446 | |
| 3447 @override | |
| 3448 ir.Primitive handleStaticFieldGet(ast.Send node, FieldElement field, _) { | |
| 3449 SourceInformation src = sourceInformationBuilder.buildGet(node); | |
| 3450 return buildStaticFieldGet(field, src); | |
| 3451 } | |
| 3452 | |
| 3453 ir.Primitive buildStaticFieldGet(FieldElement field, SourceInformation src) { | |
| 3454 ConstantValue constant = getConstantForVariable(field); | |
| 3455 if (constant != null && !field.isAssignable) { | |
| 3456 typeMaskSystem.associateConstantValueWithElement(constant, field); | |
| 3457 return irBuilder.buildConstant(constant, sourceInformation: src); | |
| 3458 } else if (backend.constants.lazyStatics.contains(field)) { | |
| 3459 return irBuilder.buildStaticFieldLazyGet(field, src); | |
| 3460 } else { | |
| 3461 return irBuilder.buildStaticFieldGet(field, src); | |
| 3462 } | |
| 3463 } | |
| 3464 | |
| 3465 /// Build code to handle foreign code, that is, native JavaScript code, or | |
| 3466 /// builtin values and operations of the backend. | |
| 3467 ir.Primitive handleForeignCode(ast.Send node, | |
| 3468 MethodElement function, | |
| 3469 ast.NodeList argumentList, | |
| 3470 CallStructure callStructure) { | |
| 3471 | |
| 3472 void validateArgumentCount({int minimum, int exactly}) { | |
| 3473 assert((minimum == null) != (exactly == null)); | |
| 3474 int count = 0; | |
| 3475 int maximum; | |
| 3476 if (exactly != null) { | |
| 3477 minimum = exactly; | |
| 3478 maximum = exactly; | |
| 3479 } | |
| 3480 for (ast.Node argument in argumentList) { | |
| 3481 count++; | |
| 3482 if (maximum != null && count > maximum) { | |
| 3483 internalError(argument, 'Additional argument.'); | |
| 3484 } | |
| 3485 } | |
| 3486 if (count < minimum) { | |
| 3487 internalError(node, 'Expected at least $minimum arguments.'); | |
| 3488 } | |
| 3489 } | |
| 3490 | |
| 3491 /// Call a helper method from the isolate library. The isolate library uses | |
| 3492 /// its own isolate structure, that encapsulates dart2js's isolate. | |
| 3493 ir.Primitive buildIsolateHelperInvocation(Element element, | |
| 3494 CallStructure callStructure) { | |
| 3495 if (element == null) { | |
| 3496 reporter.internalError(node, | |
| 3497 'Isolate library and compiler mismatch.'); | |
| 3498 } | |
| 3499 List<ir.Primitive> arguments = <ir.Primitive>[]; | |
| 3500 callStructure = translateStaticArguments(argumentList, element, | |
| 3501 callStructure, arguments); | |
| 3502 return irBuilder.buildStaticFunctionInvocation( | |
| 3503 element, | |
| 3504 callStructure, | |
| 3505 arguments, | |
| 3506 sourceInformation: | |
| 3507 sourceInformationBuilder.buildCall(node, node.selector)); | |
| 3508 } | |
| 3509 | |
| 3510 /// Lookup the value of the enum described by [node]. | |
| 3511 getEnumValue(ast.Node node, EnumClassElement enumClass, List values) { | |
| 3512 Element element = elements[node]; | |
| 3513 if (element is! FieldElement || element.enclosingClass != enumClass) { | |
| 3514 internalError(node, 'expected a JsBuiltin enum value'); | |
| 3515 } | |
| 3516 | |
| 3517 int index = enumClass.enumValues.indexOf(element); | |
| 3518 return values[index]; | |
| 3519 } | |
| 3520 | |
| 3521 /// Returns the String the node evaluates to, or throws an error if the | |
| 3522 /// result is not a string constant. | |
| 3523 String expectStringConstant(ast.Node node) { | |
| 3524 ir.Primitive nameValue = visit(node); | |
| 3525 if (nameValue is ir.Constant && nameValue.value.isString) { | |
| 3526 StringConstantValue constantValue = nameValue.value; | |
| 3527 return constantValue.primitiveValue.slowToString(); | |
| 3528 } else { | |
| 3529 return internalError(node, 'expected a literal string'); | |
| 3530 } | |
| 3531 } | |
| 3532 | |
| 3533 Link<ast.Node> argumentNodes = argumentList.nodes; | |
| 3534 NativeBehavior behavior = | |
| 3535 compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node); | |
| 3536 switch (function.name) { | |
| 3537 case 'JS': | |
| 3538 validateArgumentCount(minimum: 2); | |
| 3539 // The first two arguments are the type and the foreign code template, | |
| 3540 // which already have been analyzed by the resolver and can be retrieved | |
| 3541 // using [NativeBehavior]. We can ignore these arguments in the backend. | |
| 3542 List<ir.Primitive> arguments = | |
| 3543 argumentNodes.skip(2).mapToList(visit, growable: false); | |
| 3544 if (behavior.codeTemplate.positionalArgumentCount != arguments.length) { | |
| 3545 reporter.reportErrorMessage( | |
| 3546 node, MessageKind.GENERIC, | |
| 3547 {'text': | |
| 3548 'Mismatch between number of placeholders' | |
| 3549 ' and number of arguments.'}); | |
| 3550 return irBuilder.buildNullConstant(); | |
| 3551 } | |
| 3552 | |
| 3553 if (HasCapturedPlaceholders.check(behavior.codeTemplate.ast)) { | |
| 3554 reporter.reportErrorMessage(node, MessageKind.JS_PLACEHOLDER_CAPTURE); | |
| 3555 return irBuilder.buildNullConstant(); | |
| 3556 } | |
| 3557 | |
| 3558 return irBuilder.buildForeignCode(behavior.codeTemplate, arguments, | |
| 3559 behavior); | |
| 3560 | |
| 3561 case 'DART_CLOSURE_TO_JS': | |
| 3562 // TODO(ahe): This should probably take care to wrap the closure in | |
| 3563 // another closure that saves the current isolate. | |
| 3564 case 'RAW_DART_FUNCTION_REF': | |
| 3565 validateArgumentCount(exactly: 1); | |
| 3566 | |
| 3567 ast.Node argument = node.arguments.single; | |
| 3568 FunctionElement closure = elements[argument].implementation; | |
| 3569 if (!Elements.isStaticOrTopLevelFunction(closure)) { | |
| 3570 internalError(argument, | |
| 3571 'only static or toplevel function supported'); | |
| 3572 } | |
| 3573 if (closure.functionSignature.hasOptionalParameters) { | |
| 3574 internalError(argument, | |
| 3575 'closures with optional parameters not supported'); | |
| 3576 } | |
| 3577 return irBuilder.buildForeignCode( | |
| 3578 js.js.expressionTemplateYielding( | |
| 3579 backend.emitter.staticFunctionAccess(closure)), | |
| 3580 <ir.Primitive>[], | |
| 3581 NativeBehavior.PURE, | |
| 3582 dependency: closure); | |
| 3583 | |
| 3584 case 'JS_BUILTIN': | |
| 3585 // The first argument is a description of the type and effect of the | |
| 3586 // builtin, which has already been analyzed in the frontend. The second | |
| 3587 // argument must be a [JsBuiltin] value. All other arguments are | |
| 3588 // values used by the JavaScript template that is associated with the | |
| 3589 // builtin. | |
| 3590 validateArgumentCount(minimum: 2); | |
| 3591 | |
| 3592 ast.Node builtin = argumentNodes.tail.head; | |
| 3593 JsBuiltin value = getEnumValue(builtin, helpers.jsBuiltinEnum, | |
| 3594 JsBuiltin.values); | |
| 3595 js.Template template = backend.emitter.builtinTemplateFor(value); | |
| 3596 List<ir.Primitive> arguments = | |
| 3597 argumentNodes.skip(2).mapToList(visit, growable: false); | |
| 3598 return irBuilder.buildForeignCode(template, arguments, behavior); | |
| 3599 | |
| 3600 case 'JS_EMBEDDED_GLOBAL': | |
| 3601 validateArgumentCount(exactly: 2); | |
| 3602 | |
| 3603 String name = expectStringConstant(argumentNodes.tail.head); | |
| 3604 js.Expression access = | |
| 3605 backend.emitter.generateEmbeddedGlobalAccess(name); | |
| 3606 js.Template template = js.js.expressionTemplateYielding(access); | |
| 3607 return irBuilder.buildForeignCode(template, <ir.Primitive>[], behavior); | |
| 3608 | |
| 3609 case 'JS_INTERCEPTOR_CONSTANT': | |
| 3610 validateArgumentCount(exactly: 1); | |
| 3611 | |
| 3612 ast.Node argument = argumentNodes.head; | |
| 3613 ir.Primitive argumentValue = visit(argument); | |
| 3614 if (argumentValue is ir.Constant && argumentValue.value.isType) { | |
| 3615 TypeConstantValue constant = argumentValue.value; | |
| 3616 ConstantValue interceptorValue = | |
| 3617 new InterceptorConstantValue(constant.representedType); | |
| 3618 return irBuilder.buildConstant(interceptorValue); | |
| 3619 } | |
| 3620 return internalError(argument, 'expected Type as argument'); | |
| 3621 | |
| 3622 case 'JS_EFFECT': | |
| 3623 return irBuilder.buildNullConstant(); | |
| 3624 | |
| 3625 case 'JS_GET_NAME': | |
| 3626 validateArgumentCount(exactly: 1); | |
| 3627 | |
| 3628 ast.Node argument = argumentNodes.head; | |
| 3629 JsGetName id = getEnumValue(argument, helpers.jsGetNameEnum, | |
| 3630 JsGetName.values); | |
| 3631 js.Name name = backend.namer.getNameForJsGetName(argument, id); | |
| 3632 ConstantValue nameConstant = | |
| 3633 new SyntheticConstantValue(SyntheticConstantKind.NAME, | |
| 3634 js.js.quoteName(name)); | |
| 3635 | |
| 3636 return irBuilder.buildConstant(nameConstant); | |
| 3637 | |
| 3638 case 'JS_GET_FLAG': | |
| 3639 validateArgumentCount(exactly: 1); | |
| 3640 | |
| 3641 String name = expectStringConstant(argumentNodes.first); | |
| 3642 bool value = false; | |
| 3643 switch (name) { | |
| 3644 case 'MUST_RETAIN_METADATA': | |
| 3645 value = backend.mustRetainMetadata; | |
| 3646 break; | |
| 3647 case 'USE_CONTENT_SECURITY_POLICY': | |
| 3648 value = compiler.useContentSecurityPolicy; | |
| 3649 break; | |
| 3650 default: | |
| 3651 internalError(node, 'Unknown internal flag "$name".'); | |
| 3652 } | |
| 3653 return irBuilder.buildBooleanConstant(value); | |
| 3654 | |
| 3655 case 'JS_STRING_CONCAT': | |
| 3656 validateArgumentCount(exactly: 2); | |
| 3657 List<ir.Primitive> arguments = argumentNodes.mapToList(visit); | |
| 3658 return irBuilder.buildStringConcatenation(arguments); | |
| 3659 | |
| 3660 case 'JS_CURRENT_ISOLATE_CONTEXT': | |
| 3661 validateArgumentCount(exactly: 0); | |
| 3662 | |
| 3663 if (!compiler.hasIsolateSupport) { | |
| 3664 // If the isolate library is not used, we just generate code | |
| 3665 // to fetch the current isolate. | |
| 3666 continue getStaticState; | |
| 3667 } | |
| 3668 return buildIsolateHelperInvocation(backend.helpers.currentIsolate, | |
| 3669 CallStructure.NO_ARGS); | |
| 3670 | |
| 3671 getStaticState: case 'JS_GET_STATIC_STATE': | |
| 3672 validateArgumentCount(exactly: 0); | |
| 3673 | |
| 3674 return irBuilder.buildForeignCode( | |
| 3675 js.js.parseForeignJS(backend.namer.staticStateHolder), | |
| 3676 const <ir.Primitive>[], | |
| 3677 NativeBehavior.PURE); | |
| 3678 | |
| 3679 case 'JS_SET_STATIC_STATE': | |
| 3680 validateArgumentCount(exactly: 1); | |
| 3681 | |
| 3682 ir.Primitive value = visit(argumentNodes.single); | |
| 3683 String isolateName = backend.namer.staticStateHolder; | |
| 3684 return irBuilder.buildForeignCode( | |
| 3685 js.js.parseForeignJS("$isolateName = #"), | |
| 3686 <ir.Primitive>[value], | |
| 3687 NativeBehavior.PURE); | |
| 3688 | |
| 3689 case 'JS_CALL_IN_ISOLATE': | |
| 3690 validateArgumentCount(exactly: 2); | |
| 3691 | |
| 3692 if (!compiler.hasIsolateSupport) { | |
| 3693 ir.Primitive closure = visit(argumentNodes.tail.head); | |
| 3694 return irBuilder.buildCallInvocation(closure, CallStructure.NO_ARGS, | |
| 3695 const <ir.Primitive>[]); | |
| 3696 } | |
| 3697 return buildIsolateHelperInvocation(backend.helpers.callInIsolate, | |
| 3698 CallStructure.TWO_ARGS); | |
| 3699 | |
| 3700 default: | |
| 3701 return giveup(node, 'unplemented native construct: ${function.name}'); | |
| 3702 } | |
| 3703 } | |
| 3704 | |
| 3705 @override | |
| 3706 ir.Primitive handleStaticFunctionInvoke(ast.Send node, | |
| 3707 MethodElement function, | |
| 3708 ast.NodeList argumentsNode, | |
| 3709 CallStructure callStructure, | |
| 3710 _) { | |
| 3711 if (compiler.backend.isForeign(function)) { | |
| 3712 return handleForeignCode(node, function, argumentsNode, callStructure); | |
| 3713 } else { | |
| 3714 List<ir.Primitive> arguments = <ir.Primitive>[]; | |
| 3715 callStructure = translateStaticArguments(argumentsNode, function, | |
| 3716 callStructure, arguments); | |
| 3717 return irBuilder.buildStaticFunctionInvocation(function, | |
| 3718 callStructure, | |
| 3719 arguments, | |
| 3720 sourceInformation: | |
| 3721 sourceInformationBuilder.buildCall(node, node.selector)); | |
| 3722 } | |
| 3723 } | |
| 3724 } | |
| OLD | NEW |