| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 import 'dart:collection'; | 5 import 'dart:collection'; |
| 6 | 6 |
| 7 import 'package:js_runtime/shared/embedded_names.dart'; | 7 import 'package:js_runtime/shared/embedded_names.dart'; |
| 8 | 8 |
| 9 import '../closure.dart'; | 9 import '../closure.dart'; |
| 10 import '../common.dart'; | 10 import '../common.dart'; |
| 11 import '../common/codegen.dart' show | 11 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; |
| 12 CodegenRegistry, | 12 import '../common/names.dart' show Identifiers, Selectors; |
| 13 CodegenWorkItem; | 13 import '../common/tasks.dart' show CompilerTask; |
| 14 import '../common/names.dart' show | 14 import '../compiler.dart' show Compiler; |
| 15 Identifiers, | |
| 16 Selectors; | |
| 17 import '../common/tasks.dart' show | |
| 18 CompilerTask; | |
| 19 import '../compiler.dart' show | |
| 20 Compiler; | |
| 21 import '../constants/constant_system.dart'; | 15 import '../constants/constant_system.dart'; |
| 22 import '../constants/expressions.dart'; | 16 import '../constants/expressions.dart'; |
| 23 import '../constants/values.dart'; | 17 import '../constants/values.dart'; |
| 24 import '../core_types.dart' show | 18 import '../core_types.dart' show CoreClasses; |
| 25 CoreClasses; | |
| 26 import '../dart_types.dart'; | 19 import '../dart_types.dart'; |
| 27 import '../diagnostics/messages.dart' show | 20 import '../diagnostics/messages.dart' show Message, MessageTemplate; |
| 28 Message, | |
| 29 MessageTemplate; | |
| 30 import '../elements/elements.dart'; | 21 import '../elements/elements.dart'; |
| 31 import '../elements/modelx.dart' show | 22 import '../elements/modelx.dart' |
| 32 ConstructorBodyElementX, | 23 show ConstructorBodyElementX, ElementX, VariableElementX; |
| 33 ElementX, | |
| 34 VariableElementX; | |
| 35 import '../io/source_information.dart'; | 24 import '../io/source_information.dart'; |
| 36 import '../js/js.dart' as js; | 25 import '../js/js.dart' as js; |
| 37 import '../js_backend/backend_helpers.dart' show | 26 import '../js_backend/backend_helpers.dart' show BackendHelpers; |
| 38 BackendHelpers; | |
| 39 import '../js_backend/js_backend.dart'; | 27 import '../js_backend/js_backend.dart'; |
| 40 import '../js_emitter/js_emitter.dart' show | 28 import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter; |
| 41 CodeEmitterTask, | |
| 42 NativeEmitter; | |
| 43 import '../native/native.dart' as native; | 29 import '../native/native.dart' as native; |
| 44 import '../resolution/operators.dart'; | 30 import '../resolution/operators.dart'; |
| 45 import '../resolution/semantic_visitor.dart'; | 31 import '../resolution/semantic_visitor.dart'; |
| 46 import '../resolution/tree_elements.dart' show | 32 import '../resolution/tree_elements.dart' show TreeElements; |
| 47 TreeElements; | |
| 48 import '../tree/tree.dart' as ast; | 33 import '../tree/tree.dart' as ast; |
| 49 import '../types/types.dart'; | 34 import '../types/types.dart'; |
| 50 import '../universe/call_structure.dart' show | 35 import '../universe/call_structure.dart' show CallStructure; |
| 51 CallStructure; | 36 import '../universe/selector.dart' show Selector; |
| 52 import '../universe/selector.dart' show | 37 import '../universe/side_effects.dart' show SideEffects; |
| 53 Selector; | 38 import '../universe/use.dart' show DynamicUse, StaticUse, TypeUse; |
| 54 import '../universe/side_effects.dart' show | |
| 55 SideEffects; | |
| 56 import '../universe/use.dart' show | |
| 57 DynamicUse, | |
| 58 StaticUse, | |
| 59 TypeUse; | |
| 60 import '../util/util.dart'; | 39 import '../util/util.dart'; |
| 61 import '../world.dart' show | 40 import '../world.dart' show ClassWorld, World; |
| 62 ClassWorld, | |
| 63 World; | |
| 64 import '../dump_info.dart' show InfoReporter; | 41 import '../dump_info.dart' show InfoReporter; |
| 65 | 42 |
| 66 import 'nodes.dart'; | 43 import 'nodes.dart'; |
| 67 import 'codegen.dart'; | 44 import 'codegen.dart'; |
| 68 import 'optimize.dart'; | 45 import 'optimize.dart'; |
| 69 import 'types.dart'; | 46 import 'types.dart'; |
| 70 | 47 |
| 71 class SsaFunctionCompiler implements FunctionCompiler { | 48 class SsaFunctionCompiler implements FunctionCompiler { |
| 72 final SsaCodeGeneratorTask generator; | 49 final SsaCodeGeneratorTask generator; |
| 73 final SsaBuilderTask builder; | 50 final SsaBuilderTask builder; |
| 74 final SsaOptimizerTask optimizer; | 51 final SsaOptimizerTask optimizer; |
| 75 final JavaScriptBackend backend; | 52 final JavaScriptBackend backend; |
| 76 | 53 |
| 77 SsaFunctionCompiler(JavaScriptBackend backend, | 54 SsaFunctionCompiler(JavaScriptBackend backend, |
| 78 SourceInformationStrategy sourceInformationFactory) | 55 SourceInformationStrategy sourceInformationFactory) |
| 79 : generator = new SsaCodeGeneratorTask(backend, sourceInformationFactory), | 56 : generator = new SsaCodeGeneratorTask(backend, sourceInformationFactory), |
| 80 builder = new SsaBuilderTask(backend, sourceInformationFactory), | 57 builder = new SsaBuilderTask(backend, sourceInformationFactory), |
| 81 optimizer = new SsaOptimizerTask(backend), | 58 optimizer = new SsaOptimizerTask(backend), |
| 82 backend = backend; | 59 backend = backend; |
| 83 | 60 |
| 84 /// Generates JavaScript code for `work.element`. | 61 /// Generates JavaScript code for `work.element`. |
| 85 /// Using the ssa builder, optimizer and codegenerator. | 62 /// Using the ssa builder, optimizer and codegenerator. |
| 86 js.Fun compile(CodegenWorkItem work) { | 63 js.Fun compile(CodegenWorkItem work) { |
| 87 HGraph graph = builder.build(work); | 64 HGraph graph = builder.build(work); |
| 88 optimizer.optimize(work, graph); | 65 optimizer.optimize(work, graph); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 113 } | 90 } |
| 114 | 91 |
| 115 class SsaBuilderTask extends CompilerTask { | 92 class SsaBuilderTask extends CompilerTask { |
| 116 final CodeEmitterTask emitter; | 93 final CodeEmitterTask emitter; |
| 117 final JavaScriptBackend backend; | 94 final JavaScriptBackend backend; |
| 118 final SourceInformationStrategy sourceInformationFactory; | 95 final SourceInformationStrategy sourceInformationFactory; |
| 119 | 96 |
| 120 String get name => 'SSA builder'; | 97 String get name => 'SSA builder'; |
| 121 | 98 |
| 122 SsaBuilderTask(JavaScriptBackend backend, this.sourceInformationFactory) | 99 SsaBuilderTask(JavaScriptBackend backend, this.sourceInformationFactory) |
| 123 : emitter = backend.emitter, | 100 : emitter = backend.emitter, |
| 124 backend = backend, | 101 backend = backend, |
| 125 super(backend.compiler); | 102 super(backend.compiler); |
| 126 | 103 |
| 127 DiagnosticReporter get reporter => compiler.reporter; | 104 DiagnosticReporter get reporter => compiler.reporter; |
| 128 | 105 |
| 129 HGraph build(CodegenWorkItem work) { | 106 HGraph build(CodegenWorkItem work) { |
| 130 return measure(() { | 107 return measure(() { |
| 131 Element element = work.element.implementation; | 108 Element element = work.element.implementation; |
| 132 return reporter.withCurrentElement(element, () { | 109 return reporter.withCurrentElement(element, () { |
| 133 SsaBuilder builder = | 110 SsaBuilder builder = new SsaBuilder( |
| 134 new SsaBuilder(work.element.implementation, | 111 work.element.implementation, |
| 135 work.resolutionTree, work.compilationContext, work.registry, | 112 work.resolutionTree, |
| 136 backend, emitter.nativeEmitter, | 113 work.compilationContext, |
| 137 sourceInformationFactory); | 114 work.registry, |
| 115 backend, |
| 116 emitter.nativeEmitter, |
| 117 sourceInformationFactory); |
| 138 HGraph graph = builder.build(); | 118 HGraph graph = builder.build(); |
| 139 | 119 |
| 140 // Default arguments are handled elsewhere, but we must ensure | 120 // Default arguments are handled elsewhere, but we must ensure |
| 141 // that the default values are computed during codegen. | 121 // that the default values are computed during codegen. |
| 142 if (!identical(element.kind, ElementKind.FIELD)) { | 122 if (!identical(element.kind, ElementKind.FIELD)) { |
| 143 FunctionElement function = element; | 123 FunctionElement function = element; |
| 144 FunctionSignature signature = function.functionSignature; | 124 FunctionSignature signature = function.functionSignature; |
| 145 signature.forEachOptionalParameter((ParameterElement parameter) { | 125 signature.forEachOptionalParameter((ParameterElement parameter) { |
| 146 // This ensures the default value will be computed. | 126 // This ensures the default value will be computed. |
| 147 ConstantValue constant = | 127 ConstantValue constant = |
| 148 backend.constants.getConstantValueForVariable(parameter); | 128 backend.constants.getConstantValueForVariable(parameter); |
| 149 work.registry.registerCompileTimeConstant(constant); | 129 work.registry.registerCompileTimeConstant(constant); |
| 150 }); | 130 }); |
| 151 } | 131 } |
| 152 if (compiler.tracer.isEnabled) { | 132 if (compiler.tracer.isEnabled) { |
| 153 String name; | 133 String name; |
| 154 if (element.isClassMember) { | 134 if (element.isClassMember) { |
| 155 String className = element.enclosingClass.name; | 135 String className = element.enclosingClass.name; |
| 156 String memberName = element.name; | 136 String memberName = element.name; |
| 157 name = "$className.$memberName"; | 137 name = "$className.$memberName"; |
| 158 if (element.isGenerativeConstructorBody) { | 138 if (element.isGenerativeConstructorBody) { |
| 159 name = "$name (body)"; | 139 name = "$name (body)"; |
| 160 } | 140 } |
| 161 } else { | 141 } else { |
| 162 name = "${element.name}"; | 142 name = "${element.name}"; |
| 163 } | 143 } |
| 164 compiler.tracer.traceCompilation( | 144 compiler.tracer.traceCompilation(name, work.compilationContext); |
| 165 name, work.compilationContext); | |
| 166 compiler.tracer.traceGraph('builder', graph); | 145 compiler.tracer.traceGraph('builder', graph); |
| 167 } | 146 } |
| 168 return graph; | 147 return graph; |
| 169 }); | 148 }); |
| 170 }); | 149 }); |
| 171 } | 150 } |
| 172 | |
| 173 } | 151 } |
| 174 | 152 |
| 175 /** | 153 /** |
| 176 * Keeps track of locals (including parameters and phis) when building. The | 154 * Keeps track of locals (including parameters and phis) when building. The |
| 177 * 'this' reference is treated as parameter and hence handled by this class, | 155 * 'this' reference is treated as parameter and hence handled by this class, |
| 178 * too. | 156 * too. |
| 179 */ | 157 */ |
| 180 class LocalsHandler { | 158 class LocalsHandler { |
| 181 /** | 159 /** |
| 182 * The values of locals that can be directly accessed (without redirections | 160 * The values of locals that can be directly accessed (without redirections |
| 183 * to boxes or closure-fields). | 161 * to boxes or closure-fields). |
| 184 * | 162 * |
| 185 * [directLocals] is iterated, so it is "insertion ordered" to make the | 163 * [directLocals] is iterated, so it is "insertion ordered" to make the |
| 186 * iteration order a function only of insertions and not a function of | 164 * iteration order a function only of insertions and not a function of |
| 187 * e.g. Element hash codes. I'd prefer to use a SortedMap but some elements | 165 * e.g. Element hash codes. I'd prefer to use a SortedMap but some elements |
| 188 * don't have source locations for [Elements.compareByPosition]. | 166 * don't have source locations for [Elements.compareByPosition]. |
| 189 */ | 167 */ |
| 190 Map<Local, HInstruction> directLocals = | 168 Map<Local, HInstruction> directLocals = new Map<Local, HInstruction>(); |
| 191 new Map<Local, HInstruction>(); | |
| 192 Map<Local, CapturedVariable> redirectionMapping = | 169 Map<Local, CapturedVariable> redirectionMapping = |
| 193 new Map<Local, CapturedVariable>(); | 170 new Map<Local, CapturedVariable>(); |
| 194 SsaBuilder builder; | 171 SsaBuilder builder; |
| 195 ClosureClassMap closureData; | 172 ClosureClassMap closureData; |
| 196 Map<TypeVariableType, TypeVariableLocal> typeVariableLocals = | 173 Map<TypeVariableType, TypeVariableLocal> typeVariableLocals = |
| 197 new Map<TypeVariableType, TypeVariableLocal>(); | 174 new Map<TypeVariableType, TypeVariableLocal>(); |
| 198 final ExecutableElement executableContext; | 175 final ExecutableElement executableContext; |
| 199 | 176 |
| 200 /// The class that defines the current type environment or null if no type | 177 /// The class that defines the current type environment or null if no type |
| 201 /// variables are in scope. | 178 /// variables are in scope. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 216 /// | 193 /// |
| 217 /// [instanceType] is not used if it contains type variables, since these | 194 /// [instanceType] is not used if it contains type variables, since these |
| 218 /// might not be in scope or from the current instance. | 195 /// might not be in scope or from the current instance. |
| 219 /// | 196 /// |
| 220 final InterfaceType instanceType; | 197 final InterfaceType instanceType; |
| 221 | 198 |
| 222 SourceInformationBuilder get sourceInformationBuilder { | 199 SourceInformationBuilder get sourceInformationBuilder { |
| 223 return builder.sourceInformationBuilder; | 200 return builder.sourceInformationBuilder; |
| 224 } | 201 } |
| 225 | 202 |
| 226 LocalsHandler(this.builder, this.executableContext, | 203 LocalsHandler( |
| 227 InterfaceType instanceType) | 204 this.builder, this.executableContext, InterfaceType instanceType) |
| 228 : this.instanceType = | 205 : this.instanceType = instanceType == null || |
| 229 instanceType == null || instanceType.containsTypeVariables | 206 instanceType.containsTypeVariables ? null : instanceType; |
| 230 ? null : instanceType; | |
| 231 | 207 |
| 232 /// Substituted type variables occurring in [type] into the context of | 208 /// Substituted type variables occurring in [type] into the context of |
| 233 /// [contextClass]. | 209 /// [contextClass]. |
| 234 DartType substInContext(DartType type) { | 210 DartType substInContext(DartType type) { |
| 235 if (contextClass != null) { | 211 if (contextClass != null) { |
| 236 ClassElement typeContext = Types.getClassContext(type); | 212 ClassElement typeContext = Types.getClassContext(type); |
| 237 if (typeContext != null) { | 213 if (typeContext != null) { |
| 238 type = type.substByContext( | 214 type = type.substByContext(contextClass.asInstanceOf(typeContext)); |
| 239 contextClass.asInstanceOf(typeContext)); | |
| 240 } | 215 } |
| 241 } | 216 } |
| 242 if (instanceType != null) { | 217 if (instanceType != null) { |
| 243 type = type.substByContext(instanceType); | 218 type = type.substByContext(instanceType); |
| 244 } | 219 } |
| 245 return type; | 220 return type; |
| 246 } | 221 } |
| 247 | 222 |
| 248 get typesTask => builder.compiler.typesTask; | 223 get typesTask => builder.compiler.typesTask; |
| 249 | 224 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 268 assert(redirectionMapping[from] == null); | 243 assert(redirectionMapping[from] == null); |
| 269 redirectionMapping[from] = to; | 244 redirectionMapping[from] = to; |
| 270 assert(isStoredInClosureField(from) || isBoxed(from)); | 245 assert(isStoredInClosureField(from) || isBoxed(from)); |
| 271 } | 246 } |
| 272 | 247 |
| 273 HInstruction createBox() { | 248 HInstruction createBox() { |
| 274 // TODO(floitsch): Clean up this hack. Should we create a box-object by | 249 // TODO(floitsch): Clean up this hack. Should we create a box-object by |
| 275 // just creating an empty object literal? | 250 // just creating an empty object literal? |
| 276 JavaScriptBackend backend = builder.backend; | 251 JavaScriptBackend backend = builder.backend; |
| 277 HInstruction box = new HForeignCode( | 252 HInstruction box = new HForeignCode( |
| 278 js.js.parseForeignJS('{}'), | 253 js.js.parseForeignJS('{}'), backend.nonNullType, <HInstruction>[], |
| 279 backend.nonNullType, | |
| 280 <HInstruction>[], | |
| 281 nativeBehavior: native.NativeBehavior.PURE_ALLOCATION); | 254 nativeBehavior: native.NativeBehavior.PURE_ALLOCATION); |
| 282 builder.add(box); | 255 builder.add(box); |
| 283 return box; | 256 return box; |
| 284 } | 257 } |
| 285 | 258 |
| 286 /** | 259 /** |
| 287 * If the scope (function or loop) [node] has captured variables then this | 260 * If the scope (function or loop) [node] has captured variables then this |
| 288 * method creates a box and sets up the redirections. | 261 * method creates a box and sets up the redirections. |
| 289 */ | 262 */ |
| 290 void enterScope(ast.Node node, Element element) { | 263 void enterScope(ast.Node node, Element element) { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 324 } else { | 297 } else { |
| 325 redirectElement(from, to); | 298 redirectElement(from, to); |
| 326 } | 299 } |
| 327 }); | 300 }); |
| 328 } | 301 } |
| 329 | 302 |
| 330 /** | 303 /** |
| 331 * Replaces the current box with a new box and copies over the given list | 304 * Replaces the current box with a new box and copies over the given list |
| 332 * of elements from the old box into the new box. | 305 * of elements from the old box into the new box. |
| 333 */ | 306 */ |
| 334 void updateCaptureBox(BoxLocal boxElement, | 307 void updateCaptureBox( |
| 335 List<LocalVariableElement> toBeCopiedElements) { | 308 BoxLocal boxElement, List<LocalVariableElement> toBeCopiedElements) { |
| 336 // Create a new box and copy over the values from the old box into the | 309 // Create a new box and copy over the values from the old box into the |
| 337 // new one. | 310 // new one. |
| 338 HInstruction oldBox = readLocal(boxElement); | 311 HInstruction oldBox = readLocal(boxElement); |
| 339 HInstruction newBox = createBox(); | 312 HInstruction newBox = createBox(); |
| 340 for (LocalVariableElement boxedVariable in toBeCopiedElements) { | 313 for (LocalVariableElement boxedVariable in toBeCopiedElements) { |
| 341 // [readLocal] uses the [boxElement] to find its box. By replacing it | 314 // [readLocal] uses the [boxElement] to find its box. By replacing it |
| 342 // behind its back we can still get to the old values. | 315 // behind its back we can still get to the old values. |
| 343 updateLocal(boxElement, oldBox); | 316 updateLocal(boxElement, oldBox); |
| 344 HInstruction oldValue = readLocal(boxedVariable); | 317 HInstruction oldValue = readLocal(boxedVariable); |
| 345 updateLocal(boxElement, newBox); | 318 updateLocal(boxElement, newBox); |
| 346 updateLocal(boxedVariable, oldValue); | 319 updateLocal(boxedVariable, oldValue); |
| 347 } | 320 } |
| 348 updateLocal(boxElement, newBox); | 321 updateLocal(boxElement, newBox); |
| 349 } | 322 } |
| 350 | 323 |
| 351 /** | 324 /** |
| 352 * Documentation wanted -- johnniwinther | 325 * Documentation wanted -- johnniwinther |
| 353 * | 326 * |
| 354 * Invariant: [function] must be an implementation element. | 327 * Invariant: [function] must be an implementation element. |
| 355 */ | 328 */ |
| 356 void startFunction(Element element, ast.Node node) { | 329 void startFunction(Element element, ast.Node node) { |
| 357 assert(invariant(element, element.isImplementation)); | 330 assert(invariant(element, element.isImplementation)); |
| 358 Compiler compiler = builder.compiler; | 331 Compiler compiler = builder.compiler; |
| 359 closureData = compiler.closureToClassMapper.computeClosureToClassMapping( | 332 closureData = compiler.closureToClassMapper |
| 360 element, node, builder.elements); | 333 .computeClosureToClassMapping(element, node, builder.elements); |
| 361 | 334 |
| 362 if (element is FunctionElement) { | 335 if (element is FunctionElement) { |
| 363 FunctionElement functionElement = element; | 336 FunctionElement functionElement = element; |
| 364 FunctionSignature params = functionElement.functionSignature; | 337 FunctionSignature params = functionElement.functionSignature; |
| 365 ClosureScope scopeData = closureData.capturingScopes[node]; | 338 ClosureScope scopeData = closureData.capturingScopes[node]; |
| 366 params.orderedForEachParameter((ParameterElement parameterElement) { | 339 params.orderedForEachParameter((ParameterElement parameterElement) { |
| 367 if (element.isGenerativeConstructorBody) { | 340 if (element.isGenerativeConstructorBody) { |
| 368 if (scopeData != null && | 341 if (scopeData != null && |
| 369 scopeData.isCapturedVariable(parameterElement)) { | 342 scopeData.isCapturedVariable(parameterElement)) { |
| 370 // The parameter will be a field in the box passed as the | 343 // The parameter will be a field in the box passed as the |
| 371 // last parameter. So no need to have it. | 344 // last parameter. So no need to have it. |
| 372 return; | 345 return; |
| 373 } | 346 } |
| 374 } | 347 } |
| 375 HInstruction parameter = builder.addParameter( | 348 HInstruction parameter = builder.addParameter(parameterElement, |
| 376 parameterElement, | |
| 377 TypeMaskFactory.inferredTypeForElement(parameterElement, compiler)); | 349 TypeMaskFactory.inferredTypeForElement(parameterElement, compiler)); |
| 378 builder.parameters[parameterElement] = parameter; | 350 builder.parameters[parameterElement] = parameter; |
| 379 directLocals[parameterElement] = parameter; | 351 directLocals[parameterElement] = parameter; |
| 380 }); | 352 }); |
| 381 } | 353 } |
| 382 | 354 |
| 383 enterScope(node, element); | 355 enterScope(node, element); |
| 384 | 356 |
| 385 // If the freeVariableMapping is not empty, then this function was a | 357 // If the freeVariableMapping is not empty, then this function was a |
| 386 // nested closure that captures variables. Redirect the captured | 358 // nested closure that captures variables. Redirect the captured |
| 387 // variables to fields in the closure. | 359 // variables to fields in the closure. |
| 388 closureData.forEachFreeVariable((Local from, CapturedVariable to) { | 360 closureData.forEachFreeVariable((Local from, CapturedVariable to) { |
| 389 redirectElement(from, to); | 361 redirectElement(from, to); |
| 390 }); | 362 }); |
| 391 JavaScriptBackend backend = compiler.backend; | 363 JavaScriptBackend backend = compiler.backend; |
| 392 if (closureData.isClosure) { | 364 if (closureData.isClosure) { |
| 393 // Inside closure redirect references to itself to [:this:]. | 365 // Inside closure redirect references to itself to [:this:]. |
| 394 HThis thisInstruction = new HThis(closureData.thisLocal, | 366 HThis thisInstruction = |
| 395 backend.nonNullType); | 367 new HThis(closureData.thisLocal, backend.nonNullType); |
| 396 builder.graph.thisInstruction = thisInstruction; | 368 builder.graph.thisInstruction = thisInstruction; |
| 397 builder.graph.entry.addAtEntry(thisInstruction); | 369 builder.graph.entry.addAtEntry(thisInstruction); |
| 398 updateLocal(closureData.closureElement, thisInstruction); | 370 updateLocal(closureData.closureElement, thisInstruction); |
| 399 } else if (element.isInstanceMember) { | 371 } else if (element.isInstanceMember) { |
| 400 // Once closures have been mapped to classes their instance members might | 372 // Once closures have been mapped to classes their instance members might |
| 401 // not have any thisElement if the closure was created inside a static | 373 // not have any thisElement if the closure was created inside a static |
| 402 // context. | 374 // context. |
| 403 HThis thisInstruction = new HThis( | 375 HThis thisInstruction = |
| 404 closureData.thisLocal, builder.getTypeOfThis()); | 376 new HThis(closureData.thisLocal, builder.getTypeOfThis()); |
| 405 builder.graph.thisInstruction = thisInstruction; | 377 builder.graph.thisInstruction = thisInstruction; |
| 406 builder.graph.entry.addAtEntry(thisInstruction); | 378 builder.graph.entry.addAtEntry(thisInstruction); |
| 407 directLocals[closureData.thisLocal] = thisInstruction; | 379 directLocals[closureData.thisLocal] = thisInstruction; |
| 408 } | 380 } |
| 409 | 381 |
| 410 // If this method is an intercepted method, add the extra | 382 // If this method is an intercepted method, add the extra |
| 411 // parameter to it, that is the actual receiver for intercepted | 383 // parameter to it, that is the actual receiver for intercepted |
| 412 // classes, or the same as [:this:] for non-intercepted classes. | 384 // classes, or the same as [:this:] for non-intercepted classes. |
| 413 ClassElement cls = element.enclosingClass; | 385 ClassElement cls = element.enclosingClass; |
| 414 | 386 |
| 415 // When the class extends a native class, the instance is pre-constructed | 387 // When the class extends a native class, the instance is pre-constructed |
| 416 // and passed to the generative constructor factory function as a parameter. | 388 // and passed to the generative constructor factory function as a parameter. |
| 417 // Instead of allocating and initializing the object, the constructor | 389 // Instead of allocating and initializing the object, the constructor |
| 418 // 'upgrades' the native subclass object by initializing the Dart fields. | 390 // 'upgrades' the native subclass object by initializing the Dart fields. |
| 419 bool isNativeUpgradeFactory = element.isGenerativeConstructor | 391 bool isNativeUpgradeFactory = |
| 420 && backend.isNativeOrExtendsNative(cls); | 392 element.isGenerativeConstructor && backend.isNativeOrExtendsNative(cls); |
| 421 if (backend.isInterceptedMethod(element)) { | 393 if (backend.isInterceptedMethod(element)) { |
| 422 bool isInterceptorClass = backend.isInterceptorClass(cls.declaration); | 394 bool isInterceptorClass = backend.isInterceptorClass(cls.declaration); |
| 423 String name = isInterceptorClass ? 'receiver' : '_'; | 395 String name = isInterceptorClass ? 'receiver' : '_'; |
| 424 SyntheticLocal parameter = new SyntheticLocal(name, executableContext); | 396 SyntheticLocal parameter = new SyntheticLocal(name, executableContext); |
| 425 HParameterValue value = | 397 HParameterValue value = |
| 426 new HParameterValue(parameter, builder.getTypeOfThis()); | 398 new HParameterValue(parameter, builder.getTypeOfThis()); |
| 427 builder.graph.explicitReceiverParameter = value; | 399 builder.graph.explicitReceiverParameter = value; |
| 428 builder.graph.entry.addAfter(directLocals[closureData.thisLocal], value); | 400 builder.graph.entry.addAfter(directLocals[closureData.thisLocal], value); |
| 429 if (builder.lastAddedParameter == null) { | 401 if (builder.lastAddedParameter == null) { |
| 430 // If this is the first parameter inserted, make sure it stays first. | 402 // If this is the first parameter inserted, make sure it stays first. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 446 builder.graph.entry.addAtEntry(value); | 418 builder.graph.entry.addAtEntry(value); |
| 447 } | 419 } |
| 448 } | 420 } |
| 449 | 421 |
| 450 /** | 422 /** |
| 451 * Returns true if the local can be accessed directly. Boxed variables or | 423 * Returns true if the local can be accessed directly. Boxed variables or |
| 452 * captured variables that are stored in the closure-field return [:false:]. | 424 * captured variables that are stored in the closure-field return [:false:]. |
| 453 */ | 425 */ |
| 454 bool isAccessedDirectly(Local local) { | 426 bool isAccessedDirectly(Local local) { |
| 455 assert(local != null); | 427 assert(local != null); |
| 456 return !redirectionMapping.containsKey(local) | 428 return !redirectionMapping.containsKey(local) && |
| 457 && !closureData.variablesUsedInTryOrGenerator.contains(local); | 429 !closureData.variablesUsedInTryOrGenerator.contains(local); |
| 458 } | 430 } |
| 459 | 431 |
| 460 bool isStoredInClosureField(Local local) { | 432 bool isStoredInClosureField(Local local) { |
| 461 assert(local != null); | 433 assert(local != null); |
| 462 if (isAccessedDirectly(local)) return false; | 434 if (isAccessedDirectly(local)) return false; |
| 463 CapturedVariable redirectTarget = redirectionMapping[local]; | 435 CapturedVariable redirectTarget = redirectionMapping[local]; |
| 464 if (redirectTarget == null) return false; | 436 if (redirectTarget == null) return false; |
| 465 return redirectTarget is ClosureFieldElement; | 437 return redirectTarget is ClosureFieldElement; |
| 466 } | 438 } |
| 467 | 439 |
| 468 bool isBoxed(Local local) { | 440 bool isBoxed(Local local) { |
| 469 if (isAccessedDirectly(local)) return false; | 441 if (isAccessedDirectly(local)) return false; |
| 470 if (isStoredInClosureField(local)) return false; | 442 if (isStoredInClosureField(local)) return false; |
| 471 return redirectionMapping.containsKey(local); | 443 return redirectionMapping.containsKey(local); |
| 472 } | 444 } |
| 473 | 445 |
| 474 bool isUsedInTryOrGenerator(Local local) { | 446 bool isUsedInTryOrGenerator(Local local) { |
| 475 return closureData.variablesUsedInTryOrGenerator.contains(local); | 447 return closureData.variablesUsedInTryOrGenerator.contains(local); |
| 476 } | 448 } |
| 477 | 449 |
| 478 /** | 450 /** |
| 479 * Returns an [HInstruction] for the given element. If the element is | 451 * Returns an [HInstruction] for the given element. If the element is |
| 480 * boxed or stored in a closure then the method generates code to retrieve | 452 * boxed or stored in a closure then the method generates code to retrieve |
| 481 * the value. | 453 * the value. |
| 482 */ | 454 */ |
| 483 HInstruction readLocal(Local local, | 455 HInstruction readLocal(Local local, {SourceInformation sourceInformation}) { |
| 484 {SourceInformation sourceInformation}) { | |
| 485 if (isAccessedDirectly(local)) { | 456 if (isAccessedDirectly(local)) { |
| 486 if (directLocals[local] == null) { | 457 if (directLocals[local] == null) { |
| 487 if (local is TypeVariableElement) { | 458 if (local is TypeVariableElement) { |
| 488 builder.reporter.internalError(builder.compiler.currentElement, | 459 builder.reporter.internalError(builder.compiler.currentElement, |
| 489 "Runtime type information not available for $local."); | 460 "Runtime type information not available for $local."); |
| 490 } else { | 461 } else { |
| 491 builder.reporter.internalError(local, | 462 builder.reporter.internalError(local, "Cannot find value $local."); |
| 492 "Cannot find value $local."); | |
| 493 } | 463 } |
| 494 } | 464 } |
| 495 HInstruction value = directLocals[local]; | 465 HInstruction value = directLocals[local]; |
| 496 if (sourceInformation != null) { | 466 if (sourceInformation != null) { |
| 497 value = new HRef(value, sourceInformation); | 467 value = new HRef(value, sourceInformation); |
| 498 builder.add(value); | 468 builder.add(value); |
| 499 } | 469 } |
| 500 return value; | 470 return value; |
| 501 } else if (isStoredInClosureField(local)) { | 471 } else if (isStoredInClosureField(local)) { |
| 502 ClosureFieldElement redirect = redirectionMapping[local]; | 472 ClosureFieldElement redirect = redirectionMapping[local]; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 530 } | 500 } |
| 531 | 501 |
| 532 HInstruction readThis() { | 502 HInstruction readThis() { |
| 533 HInstruction res = readLocal(closureData.thisLocal); | 503 HInstruction res = readLocal(closureData.thisLocal); |
| 534 if (res.instructionType == null) { | 504 if (res.instructionType == null) { |
| 535 res.instructionType = builder.getTypeOfThis(); | 505 res.instructionType = builder.getTypeOfThis(); |
| 536 } | 506 } |
| 537 return res; | 507 return res; |
| 538 } | 508 } |
| 539 | 509 |
| 540 HLocalValue getLocal(Local local, | 510 HLocalValue getLocal(Local local, {SourceInformation sourceInformation}) { |
| 541 {SourceInformation sourceInformation}) { | |
| 542 // If the element is a parameter, we already have a | 511 // If the element is a parameter, we already have a |
| 543 // HParameterValue for it. We cannot create another one because | 512 // HParameterValue for it. We cannot create another one because |
| 544 // it could then have another name than the real parameter. And | 513 // it could then have another name than the real parameter. And |
| 545 // the other one would not know it is just a copy of the real | 514 // the other one would not know it is just a copy of the real |
| 546 // parameter. | 515 // parameter. |
| 547 if (local is ParameterElement) return builder.parameters[local]; | 516 if (local is ParameterElement) return builder.parameters[local]; |
| 548 | 517 |
| 549 return builder.activationVariables.putIfAbsent(local, () { | 518 return builder.activationVariables.putIfAbsent(local, () { |
| 550 JavaScriptBackend backend = builder.backend; | 519 JavaScriptBackend backend = builder.backend; |
| 551 HLocalValue localValue = new HLocalValue(local, backend.nonNullType) | 520 HLocalValue localValue = new HLocalValue(local, backend.nonNullType) |
| 552 ..sourceInformation = sourceInformation; | 521 ..sourceInformation = sourceInformation; |
| 553 builder.graph.entry.addAtExit(localValue); | 522 builder.graph.entry.addAtExit(localValue); |
| 554 return localValue; | 523 return localValue; |
| 555 }); | 524 }); |
| 556 } | 525 } |
| 557 | 526 |
| 558 Local getTypeVariableAsLocal(TypeVariableType type) { | 527 Local getTypeVariableAsLocal(TypeVariableType type) { |
| 559 return typeVariableLocals.putIfAbsent(type, () { | 528 return typeVariableLocals.putIfAbsent(type, () { |
| 560 return new TypeVariableLocal(type, executableContext); | 529 return new TypeVariableLocal(type, executableContext); |
| 561 }); | 530 }); |
| 562 } | 531 } |
| 563 | 532 |
| 564 /** | 533 /** |
| 565 * Sets the [element] to [value]. If the element is boxed or stored in a | 534 * Sets the [element] to [value]. If the element is boxed or stored in a |
| 566 * closure then the method generates code to set the value. | 535 * closure then the method generates code to set the value. |
| 567 */ | 536 */ |
| 568 void updateLocal(Local local, HInstruction value, | 537 void updateLocal(Local local, HInstruction value, |
| 569 {SourceInformation sourceInformation}) { | 538 {SourceInformation sourceInformation}) { |
| 570 if (value is HRef) { | 539 if (value is HRef) { |
| 571 HRef ref = value; | 540 HRef ref = value; |
| 572 value = ref.value; | 541 value = ref.value; |
| 573 } | 542 } |
| 574 assert(!isStoredInClosureField(local)); | 543 assert(!isStoredInClosureField(local)); |
| 575 if (isAccessedDirectly(local)) { | 544 if (isAccessedDirectly(local)) { |
| 576 directLocals[local] = value; | 545 directLocals[local] = value; |
| 577 } else if (isBoxed(local)) { | 546 } else if (isBoxed(local)) { |
| 578 BoxFieldElement redirect = redirectionMapping[local]; | 547 BoxFieldElement redirect = redirectionMapping[local]; |
| 579 // The box itself could be captured, or be local. A local variable that | 548 // The box itself could be captured, or be local. A local variable that |
| 580 // is captured will be boxed, but the box itself will be a local. | 549 // is captured will be boxed, but the box itself will be a local. |
| 581 // Inside the closure the box is stored in a closure-field and cannot | 550 // Inside the closure the box is stored in a closure-field and cannot |
| 582 // be accessed directly. | 551 // be accessed directly. |
| 583 HInstruction box = readLocal(redirect.box); | 552 HInstruction box = readLocal(redirect.box); |
| 584 builder.add(new HFieldSet(redirect, box, value) | 553 builder.add(new HFieldSet(redirect, box, value) |
| 585 ..sourceInformation = sourceInformation); | 554 ..sourceInformation = sourceInformation); |
| 586 } else { | 555 } else { |
| 587 assert(isUsedInTryOrGenerator(local)); | 556 assert(isUsedInTryOrGenerator(local)); |
| 588 HLocalValue localValue = getLocal(local); | 557 HLocalValue localValue = getLocal(local); |
| 589 builder.add(new HLocalSet(local, localValue, value) | 558 builder.add(new HLocalSet(local, localValue, value) |
| 590 ..sourceInformation = sourceInformation); | 559 ..sourceInformation = sourceInformation); |
| 591 } | 560 } |
| 592 } | 561 } |
| 593 | 562 |
| 594 /** | 563 /** |
| 595 * This function, startLoop, must be called before visiting any children of | 564 * This function, startLoop, must be called before visiting any children of |
| 596 * the loop. In particular it needs to be called before executing the | 565 * the loop. In particular it needs to be called before executing the |
| 597 * initializers. | 566 * initializers. |
| 598 * | 567 * |
| 599 * The [LocalsHandler] will make the boxes and updates at the right moment. | 568 * The [LocalsHandler] will make the boxes and updates at the right moment. |
| 600 * The builder just needs to call [enterLoopBody] and [enterLoopUpdates] | 569 * The builder just needs to call [enterLoopBody] and [enterLoopUpdates] |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 653 * Create phis at the loop entry for local variables (ready for the values | 622 * Create phis at the loop entry for local variables (ready for the values |
| 654 * from the back edge). Populate the phis with the current values. | 623 * from the back edge). Populate the phis with the current values. |
| 655 */ | 624 */ |
| 656 void beginLoopHeader(HBasicBlock loopEntry) { | 625 void beginLoopHeader(HBasicBlock loopEntry) { |
| 657 // Create a copy because we modify the map while iterating over it. | 626 // Create a copy because we modify the map while iterating over it. |
| 658 Map<Local, HInstruction> savedDirectLocals = | 627 Map<Local, HInstruction> savedDirectLocals = |
| 659 new Map<Local, HInstruction>.from(directLocals); | 628 new Map<Local, HInstruction>.from(directLocals); |
| 660 | 629 |
| 661 JavaScriptBackend backend = builder.backend; | 630 JavaScriptBackend backend = builder.backend; |
| 662 // Create phis for all elements in the definitions environment. | 631 // Create phis for all elements in the definitions environment. |
| 663 savedDirectLocals.forEach((Local local, | 632 savedDirectLocals.forEach((Local local, HInstruction instruction) { |
| 664 HInstruction instruction) { | |
| 665 if (isAccessedDirectly(local)) { | 633 if (isAccessedDirectly(local)) { |
| 666 // We know 'this' cannot be modified. | 634 // We know 'this' cannot be modified. |
| 667 if (local != closureData.thisLocal) { | 635 if (local != closureData.thisLocal) { |
| 668 HPhi phi = new HPhi.singleInput( | 636 HPhi phi = |
| 669 local, instruction, backend.dynamicType); | 637 new HPhi.singleInput(local, instruction, backend.dynamicType); |
| 670 loopEntry.addPhi(phi); | 638 loopEntry.addPhi(phi); |
| 671 directLocals[local] = phi; | 639 directLocals[local] = phi; |
| 672 } else { | 640 } else { |
| 673 directLocals[local] = instruction; | 641 directLocals[local] = instruction; |
| 674 } | 642 } |
| 675 } | 643 } |
| 676 }); | 644 }); |
| 677 } | 645 } |
| 678 | 646 |
| 679 void enterLoopBody(ast.Node node) { | 647 void enterLoopBody(ast.Node node) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 719 * there is a conflict. | 687 * there is a conflict. |
| 720 * If a phi node is necessary, it will use this handler's instruction as the | 688 * If a phi node is necessary, it will use this handler's instruction as the |
| 721 * first input, and the otherLocals instruction as the second. | 689 * first input, and the otherLocals instruction as the second. |
| 722 */ | 690 */ |
| 723 void mergeWith(LocalsHandler otherLocals, HBasicBlock joinBlock) { | 691 void mergeWith(LocalsHandler otherLocals, HBasicBlock joinBlock) { |
| 724 // If an element is in one map but not the other we can safely | 692 // If an element is in one map but not the other we can safely |
| 725 // ignore it. It means that a variable was declared in the | 693 // ignore it. It means that a variable was declared in the |
| 726 // block. Since variable declarations are scoped the declared | 694 // block. Since variable declarations are scoped the declared |
| 727 // variable cannot be alive outside the block. Note: this is only | 695 // variable cannot be alive outside the block. Note: this is only |
| 728 // true for nodes where we do joins. | 696 // true for nodes where we do joins. |
| 729 Map<Local, HInstruction> joinedLocals = | 697 Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>(); |
| 730 new Map<Local, HInstruction>(); | |
| 731 JavaScriptBackend backend = builder.backend; | 698 JavaScriptBackend backend = builder.backend; |
| 732 otherLocals.directLocals.forEach((Local local, | 699 otherLocals.directLocals.forEach((Local local, HInstruction instruction) { |
| 733 HInstruction instruction) { | |
| 734 // We know 'this' cannot be modified. | 700 // We know 'this' cannot be modified. |
| 735 if (local == closureData.thisLocal) { | 701 if (local == closureData.thisLocal) { |
| 736 assert(directLocals[local] == instruction); | 702 assert(directLocals[local] == instruction); |
| 737 joinedLocals[local] = instruction; | 703 joinedLocals[local] = instruction; |
| 738 } else { | 704 } else { |
| 739 HInstruction mine = directLocals[local]; | 705 HInstruction mine = directLocals[local]; |
| 740 if (mine == null) return; | 706 if (mine == null) return; |
| 741 if (identical(instruction, mine)) { | 707 if (identical(instruction, mine)) { |
| 742 joinedLocals[local] = instruction; | 708 joinedLocals[local] = instruction; |
| 743 } else { | 709 } else { |
| 744 HInstruction phi = new HPhi.manyInputs( | 710 HInstruction phi = new HPhi.manyInputs( |
| 745 local, <HInstruction>[mine, instruction], backend.dynamicType); | 711 local, <HInstruction>[mine, instruction], backend.dynamicType); |
| 746 joinBlock.addPhi(phi); | 712 joinBlock.addPhi(phi); |
| 747 joinedLocals[local] = phi; | 713 joinedLocals[local] = phi; |
| 748 } | 714 } |
| 749 } | 715 } |
| 750 }); | 716 }); |
| 751 directLocals = joinedLocals; | 717 directLocals = joinedLocals; |
| 752 } | 718 } |
| 753 | 719 |
| 754 /** | 720 /** |
| 755 * When control flow merges, this method can be used to merge several | 721 * When control flow merges, this method can be used to merge several |
| 756 * localsHandlers into a new one using phis. The new localsHandler is | 722 * localsHandlers into a new one using phis. The new localsHandler is |
| 757 * returned. Unless it is also in the list, the current localsHandler is not | 723 * returned. Unless it is also in the list, the current localsHandler is not |
| 758 * used for its values, only for its declared variables. This is a way to | 724 * used for its values, only for its declared variables. This is a way to |
| 759 * exclude local values from the result when they are no longer in scope. | 725 * exclude local values from the result when they are no longer in scope. |
| 760 */ | 726 */ |
| 761 LocalsHandler mergeMultiple(List<LocalsHandler> localsHandlers, | 727 LocalsHandler mergeMultiple( |
| 762 HBasicBlock joinBlock) { | 728 List<LocalsHandler> localsHandlers, HBasicBlock joinBlock) { |
| 763 assert(localsHandlers.length > 0); | 729 assert(localsHandlers.length > 0); |
| 764 if (localsHandlers.length == 1) return localsHandlers[0]; | 730 if (localsHandlers.length == 1) return localsHandlers[0]; |
| 765 Map<Local, HInstruction> joinedLocals = | 731 Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>(); |
| 766 new Map<Local, HInstruction>(); | |
| 767 HInstruction thisValue = null; | 732 HInstruction thisValue = null; |
| 768 JavaScriptBackend backend = builder.backend; | 733 JavaScriptBackend backend = builder.backend; |
| 769 directLocals.forEach((Local local, HInstruction instruction) { | 734 directLocals.forEach((Local local, HInstruction instruction) { |
| 770 if (local != closureData.thisLocal) { | 735 if (local != closureData.thisLocal) { |
| 771 HPhi phi = new HPhi.noInputs(local, backend.dynamicType); | 736 HPhi phi = new HPhi.noInputs(local, backend.dynamicType); |
| 772 joinedLocals[local] = phi; | 737 joinedLocals[local] = phi; |
| 773 joinBlock.addPhi(phi); | 738 joinBlock.addPhi(phi); |
| 774 } else { | 739 } else { |
| 775 // We know that "this" never changes, if it's there. | 740 // We know that "this" never changes, if it's there. |
| 776 // Save it for later. While merging, there is no phi for "this", | 741 // Save it for later. While merging, there is no phi for "this", |
| 777 // so we don't have to special case it in the merge loop. | 742 // so we don't have to special case it in the merge loop. |
| 778 thisValue = instruction; | 743 thisValue = instruction; |
| 779 } | 744 } |
| 780 }); | 745 }); |
| 781 for (LocalsHandler handler in localsHandlers) { | 746 for (LocalsHandler handler in localsHandlers) { |
| 782 handler.directLocals.forEach((Local local, | 747 handler.directLocals.forEach((Local local, HInstruction instruction) { |
| 783 HInstruction instruction) { | |
| 784 HPhi phi = joinedLocals[local]; | 748 HPhi phi = joinedLocals[local]; |
| 785 if (phi != null) { | 749 if (phi != null) { |
| 786 phi.addInput(instruction); | 750 phi.addInput(instruction); |
| 787 } | 751 } |
| 788 }); | 752 }); |
| 789 } | 753 } |
| 790 if (thisValue != null) { | 754 if (thisValue != null) { |
| 791 // If there was a "this" for the scope, add it to the new locals. | 755 // If there was a "this" for the scope, add it to the new locals. |
| 792 joinedLocals[closureData.thisLocal] = thisValue; | 756 joinedLocals[closureData.thisLocal] = thisValue; |
| 793 } | 757 } |
| 794 | 758 |
| 795 // Remove locals that are not in all handlers. | 759 // Remove locals that are not in all handlers. |
| 796 directLocals = new Map<Local, HInstruction>(); | 760 directLocals = new Map<Local, HInstruction>(); |
| 797 joinedLocals.forEach((Local local, | 761 joinedLocals.forEach((Local local, HInstruction instruction) { |
| 798 HInstruction instruction) { | 762 if (local != closureData.thisLocal && |
| 799 if (local != closureData.thisLocal | 763 instruction.inputs.length != localsHandlers.length) { |
| 800 && instruction.inputs.length != localsHandlers.length) { | |
| 801 joinBlock.removePhi(instruction); | 764 joinBlock.removePhi(instruction); |
| 802 } else { | 765 } else { |
| 803 directLocals[local] = instruction; | 766 directLocals[local] = instruction; |
| 804 } | 767 } |
| 805 }); | 768 }); |
| 806 return this; | 769 return this; |
| 807 } | 770 } |
| 808 } | 771 } |
| 809 | 772 |
| 810 | |
| 811 // Represents a single break/continue instruction. | 773 // Represents a single break/continue instruction. |
| 812 class JumpHandlerEntry { | 774 class JumpHandlerEntry { |
| 813 final HJump jumpInstruction; | 775 final HJump jumpInstruction; |
| 814 final LocalsHandler locals; | 776 final LocalsHandler locals; |
| 815 bool isBreak() => jumpInstruction is HBreak; | 777 bool isBreak() => jumpInstruction is HBreak; |
| 816 bool isContinue() => jumpInstruction is HContinue; | 778 bool isContinue() => jumpInstruction is HContinue; |
| 817 JumpHandlerEntry(this.jumpInstruction, this.locals); | 779 JumpHandlerEntry(this.jumpInstruction, this.locals); |
| 818 } | 780 } |
| 819 | 781 |
| 820 | |
| 821 abstract class JumpHandler { | 782 abstract class JumpHandler { |
| 822 factory JumpHandler(SsaBuilder builder, JumpTarget target) { | 783 factory JumpHandler(SsaBuilder builder, JumpTarget target) { |
| 823 return new TargetJumpHandler(builder, target); | 784 return new TargetJumpHandler(builder, target); |
| 824 } | 785 } |
| 825 void generateBreak([LabelDefinition label]); | 786 void generateBreak([LabelDefinition label]); |
| 826 void generateContinue([LabelDefinition label]); | 787 void generateContinue([LabelDefinition label]); |
| 827 void forEachBreak(void action(HBreak instruction, LocalsHandler locals)); | 788 void forEachBreak(void action(HBreak instruction, LocalsHandler locals)); |
| 828 void forEachContinue(void action(HContinue instruction, | 789 void forEachContinue( |
| 829 LocalsHandler locals)); | 790 void action(HContinue instruction, LocalsHandler locals)); |
| 830 bool hasAnyContinue(); | 791 bool hasAnyContinue(); |
| 831 bool hasAnyBreak(); | 792 bool hasAnyBreak(); |
| 832 void close(); | 793 void close(); |
| 833 final JumpTarget target; | 794 final JumpTarget target; |
| 834 List<LabelDefinition> labels(); | 795 List<LabelDefinition> labels(); |
| 835 } | 796 } |
| 836 | 797 |
| 837 // Insert break handler used to avoid null checks when a target isn't | 798 // Insert break handler used to avoid null checks when a target isn't |
| 838 // used as the target of a break, and therefore doesn't need a break | 799 // used as the target of a break, and therefore doesn't need a break |
| 839 // handler associated with it. | 800 // handler associated with it. |
| 840 class NullJumpHandler implements JumpHandler { | 801 class NullJumpHandler implements JumpHandler { |
| 841 final DiagnosticReporter reporter; | 802 final DiagnosticReporter reporter; |
| 842 | 803 |
| 843 NullJumpHandler(this.reporter); | 804 NullJumpHandler(this.reporter); |
| 844 | 805 |
| 845 void generateBreak([LabelDefinition label]) { | 806 void generateBreak([LabelDefinition label]) { |
| 846 reporter.internalError(CURRENT_ELEMENT_SPANNABLE, | 807 reporter.internalError(CURRENT_ELEMENT_SPANNABLE, |
| 847 'NullJumpHandler.generateBreak should not be called.'); | 808 'NullJumpHandler.generateBreak should not be called.'); |
| 848 } | 809 } |
| 849 | 810 |
| 850 void generateContinue([LabelDefinition label]) { | 811 void generateContinue([LabelDefinition label]) { |
| 851 reporter.internalError(CURRENT_ELEMENT_SPANNABLE, | 812 reporter.internalError(CURRENT_ELEMENT_SPANNABLE, |
| 852 'NullJumpHandler.generateContinue should not be called.'); | 813 'NullJumpHandler.generateContinue should not be called.'); |
| 853 } | 814 } |
| 854 | 815 |
| 855 void forEachBreak(Function ignored) { } | 816 void forEachBreak(Function ignored) {} |
| 856 void forEachContinue(Function ignored) { } | 817 void forEachContinue(Function ignored) {} |
| 857 void close() { } | 818 void close() {} |
| 858 bool hasAnyContinue() => false; | 819 bool hasAnyContinue() => false; |
| 859 bool hasAnyBreak() => false; | 820 bool hasAnyBreak() => false; |
| 860 | 821 |
| 861 List<LabelDefinition> labels() => const <LabelDefinition>[]; | 822 List<LabelDefinition> labels() => const <LabelDefinition>[]; |
| 862 JumpTarget get target => null; | 823 JumpTarget get target => null; |
| 863 } | 824 } |
| 864 | 825 |
| 865 // Records breaks until a target block is available. | 826 // Records breaks until a target block is available. |
| 866 // Breaks are always forward jumps. | 827 // Breaks are always forward jumps. |
| 867 // Continues in loops are implemented as breaks of the body. | 828 // Continues in loops are implemented as breaks of the body. |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 946 } | 907 } |
| 947 } | 908 } |
| 948 | 909 |
| 949 /// Special [JumpHandler] implementation used to handle continue statements | 910 /// Special [JumpHandler] implementation used to handle continue statements |
| 950 /// targeting switch cases. | 911 /// targeting switch cases. |
| 951 class SwitchCaseJumpHandler extends TargetJumpHandler { | 912 class SwitchCaseJumpHandler extends TargetJumpHandler { |
| 952 /// Map from switch case targets to indices used to encode the flow of the | 913 /// Map from switch case targets to indices used to encode the flow of the |
| 953 /// switch case loop. | 914 /// switch case loop. |
| 954 final Map<JumpTarget, int> targetIndexMap = new Map<JumpTarget, int>(); | 915 final Map<JumpTarget, int> targetIndexMap = new Map<JumpTarget, int>(); |
| 955 | 916 |
| 956 SwitchCaseJumpHandler(SsaBuilder builder, | 917 SwitchCaseJumpHandler( |
| 957 JumpTarget target, | 918 SsaBuilder builder, JumpTarget target, ast.SwitchStatement node) |
| 958 ast.SwitchStatement node) | |
| 959 : super(builder, target) { | 919 : super(builder, target) { |
| 960 // The switch case indices must match those computed in | 920 // The switch case indices must match those computed in |
| 961 // [SsaFromAstMixin.buildSwitchCaseConstants]. | 921 // [SsaFromAstMixin.buildSwitchCaseConstants]. |
| 962 // Switch indices are 1-based so we can bypass the synthetic loop when no | 922 // Switch indices are 1-based so we can bypass the synthetic loop when no |
| 963 // cases match simply by branching on the index (which defaults to null). | 923 // cases match simply by branching on the index (which defaults to null). |
| 964 int switchIndex = 1; | 924 int switchIndex = 1; |
| 965 for (ast.SwitchCase switchCase in node.cases) { | 925 for (ast.SwitchCase switchCase in node.cases) { |
| 966 for (ast.Node labelOrCase in switchCase.labelsAndCases) { | 926 for (ast.Node labelOrCase in switchCase.labelsAndCases) { |
| 967 ast.Node label = labelOrCase.asLabel(); | 927 ast.Node label = labelOrCase.asLabel(); |
| 968 if (label != null) { | 928 if (label != null) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1000 return label != null && targetIndexMap.containsKey(label.target); | 960 return label != null && targetIndexMap.containsKey(label.target); |
| 1001 } | 961 } |
| 1002 | 962 |
| 1003 void generateContinue([LabelDefinition label]) { | 963 void generateContinue([LabelDefinition label]) { |
| 1004 if (isContinueToSwitchCase(label)) { | 964 if (isContinueToSwitchCase(label)) { |
| 1005 // Creates the special instructions 'label = i; continue l;' used in | 965 // Creates the special instructions 'label = i; continue l;' used in |
| 1006 // switch statements with continue statements. See | 966 // switch statements with continue statements. See |
| 1007 // [SsaFromAstMixin.buildComplexSwitchStatement] for detail. | 967 // [SsaFromAstMixin.buildComplexSwitchStatement] for detail. |
| 1008 | 968 |
| 1009 assert(label != null); | 969 assert(label != null); |
| 1010 HInstruction value = builder.graph.addConstantInt( | 970 HInstruction value = builder.graph |
| 1011 targetIndexMap[label.target], | 971 .addConstantInt(targetIndexMap[label.target], builder.compiler); |
| 1012 builder.compiler); | |
| 1013 builder.localsHandler.updateLocal(target, value); | 972 builder.localsHandler.updateLocal(target, value); |
| 1014 | 973 |
| 1015 assert(label.target.labels.contains(label)); | 974 assert(label.target.labels.contains(label)); |
| 1016 HInstruction continueInstruction = new HContinue(target); | 975 HInstruction continueInstruction = new HContinue(target); |
| 1017 LocalsHandler locals = new LocalsHandler.from(builder.localsHandler); | 976 LocalsHandler locals = new LocalsHandler.from(builder.localsHandler); |
| 1018 builder.close(continueInstruction); | 977 builder.close(continueInstruction); |
| 1019 jumps.add(new JumpHandlerEntry(continueInstruction, locals)); | 978 jumps.add(new JumpHandlerEntry(continueInstruction, locals)); |
| 1020 } else { | 979 } else { |
| 1021 super.generateContinue(label); | 980 super.generateContinue(label); |
| 1022 } | 981 } |
| 1023 } | 982 } |
| 1024 | 983 |
| 1025 void close() { | 984 void close() { |
| 1026 // The mapping from TargetElement to JumpHandler is no longer needed. | 985 // The mapping from TargetElement to JumpHandler is no longer needed. |
| 1027 for (JumpTarget target in targetIndexMap.keys) { | 986 for (JumpTarget target in targetIndexMap.keys) { |
| 1028 builder.jumpTargets.remove(target); | 987 builder.jumpTargets.remove(target); |
| 1029 } | 988 } |
| 1030 super.close(); | 989 super.close(); |
| 1031 } | 990 } |
| 1032 } | 991 } |
| 1033 | 992 |
| 1034 /** | 993 /** |
| 1035 * This class builds SSA nodes for functions represented in AST. | 994 * This class builds SSA nodes for functions represented in AST. |
| 1036 */ | 995 */ |
| 1037 class SsaBuilder extends ast.Visitor | 996 class SsaBuilder extends ast.Visitor |
| 1038 with BaseImplementationOfCompoundsMixin, | 997 with |
| 1039 BaseImplementationOfSetIfNullsMixin, | 998 BaseImplementationOfCompoundsMixin, |
| 1040 BaseImplementationOfSuperIndexSetIfNullMixin, | 999 BaseImplementationOfSetIfNullsMixin, |
| 1041 SemanticSendResolvedMixin, | 1000 BaseImplementationOfSuperIndexSetIfNullMixin, |
| 1042 NewBulkMixin, | 1001 SemanticSendResolvedMixin, |
| 1043 ErrorBulkMixin | 1002 NewBulkMixin, |
| 1003 ErrorBulkMixin |
| 1044 implements SemanticSendVisitor { | 1004 implements SemanticSendVisitor { |
| 1045 | |
| 1046 /// The element for which this SSA builder is being used. | 1005 /// The element for which this SSA builder is being used. |
| 1047 final Element target; | 1006 final Element target; |
| 1048 | 1007 |
| 1049 /// Reference to resolved elements in [target]'s AST. | 1008 /// Reference to resolved elements in [target]'s AST. |
| 1050 TreeElements elements; | 1009 TreeElements elements; |
| 1051 | 1010 |
| 1052 /// Used to report information about inlining (which occurs while building the | 1011 /// Used to report information about inlining (which occurs while building the |
| 1053 /// SSA graph), when dump-info is enabled. | 1012 /// SSA graph), when dump-info is enabled. |
| 1054 final InfoReporter infoReporter; | 1013 final InfoReporter infoReporter; |
| 1055 | 1014 |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1139 Map<ParameterElement, HInstruction> parameters = | 1098 Map<ParameterElement, HInstruction> parameters = |
| 1140 <ParameterElement, HInstruction>{}; | 1099 <ParameterElement, HInstruction>{}; |
| 1141 | 1100 |
| 1142 Map<JumpTarget, JumpHandler> jumpTargets = <JumpTarget, JumpHandler>{}; | 1101 Map<JumpTarget, JumpHandler> jumpTargets = <JumpTarget, JumpHandler>{}; |
| 1143 | 1102 |
| 1144 /** | 1103 /** |
| 1145 * Variables stored in the current activation. These variables are | 1104 * Variables stored in the current activation. These variables are |
| 1146 * being updated in try/catch blocks, and should be | 1105 * being updated in try/catch blocks, and should be |
| 1147 * accessed indirectly through [HLocalGet] and [HLocalSet]. | 1106 * accessed indirectly through [HLocalGet] and [HLocalSet]. |
| 1148 */ | 1107 */ |
| 1149 Map<Local, HLocalValue> activationVariables = | 1108 Map<Local, HLocalValue> activationVariables = <Local, HLocalValue>{}; |
| 1150 <Local, HLocalValue>{}; | |
| 1151 | 1109 |
| 1152 // We build the Ssa graph by simulating a stack machine. | 1110 // We build the Ssa graph by simulating a stack machine. |
| 1153 List<HInstruction> stack = <HInstruction>[]; | 1111 List<HInstruction> stack = <HInstruction>[]; |
| 1154 | 1112 |
| 1155 /// Returns `true` if the current element is an `async` function. | 1113 /// Returns `true` if the current element is an `async` function. |
| 1156 bool get isBuildingAsyncFunction { | 1114 bool get isBuildingAsyncFunction { |
| 1157 Element element = sourceElement; | 1115 Element element = sourceElement; |
| 1158 return (element is FunctionElement && | 1116 return (element is FunctionElement && |
| 1159 element.asyncMarker == AsyncMarker.ASYNC); | 1117 element.asyncMarker == AsyncMarker.ASYNC); |
| 1160 } | 1118 } |
| 1161 | 1119 |
| 1162 // TODO(sigmund): make most args optional | 1120 // TODO(sigmund): make most args optional |
| 1163 SsaBuilder(this.target, this.elements, this.context, this.registry, | 1121 SsaBuilder( |
| 1164 JavaScriptBackend backend, this.nativeEmitter, | 1122 this.target, |
| 1123 this.elements, |
| 1124 this.context, |
| 1125 this.registry, |
| 1126 JavaScriptBackend backend, |
| 1127 this.nativeEmitter, |
| 1165 SourceInformationStrategy sourceInformationFactory) | 1128 SourceInformationStrategy sourceInformationFactory) |
| 1166 : this.compiler = backend.compiler, | 1129 : this.compiler = backend.compiler, |
| 1167 this.infoReporter = backend.compiler.dumpInfoTask, | 1130 this.infoReporter = backend.compiler.dumpInfoTask, |
| 1168 this.backend = backend, | 1131 this.backend = backend, |
| 1169 this.constantSystem = backend.constantSystem, | 1132 this.constantSystem = backend.constantSystem, |
| 1170 this.rti = backend.rti { | 1133 this.rti = backend.rti { |
| 1171 assert(target.isImplementation); | 1134 assert(target.isImplementation); |
| 1172 graph.element = target; | 1135 graph.element = target; |
| 1173 localsHandler = new LocalsHandler(this, target, null); | 1136 localsHandler = new LocalsHandler(this, target, null); |
| 1174 sourceElementStack.add(target); | 1137 sourceElementStack.add(target); |
| 1175 sourceInformationBuilder = sourceInformationFactory.createBuilderForContext( | 1138 sourceInformationBuilder = |
| 1176 target); | 1139 sourceInformationFactory.createBuilderForContext(target); |
| 1177 graph.sourceInformation = | 1140 graph.sourceInformation = |
| 1178 sourceInformationBuilder.buildVariableDeclaration(); | 1141 sourceInformationBuilder.buildVariableDeclaration(); |
| 1179 } | 1142 } |
| 1180 | 1143 |
| 1181 BackendHelpers get helpers => backend.helpers; | 1144 BackendHelpers get helpers => backend.helpers; |
| 1182 | 1145 |
| 1183 RuntimeTypesEncoder get rtiEncoder => backend.rtiEncoder; | 1146 RuntimeTypesEncoder get rtiEncoder => backend.rtiEncoder; |
| 1184 | 1147 |
| 1185 DiagnosticReporter get reporter => compiler.reporter; | 1148 DiagnosticReporter get reporter => compiler.reporter; |
| 1186 | 1149 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1199 node.accept(this); | 1162 node.accept(this); |
| 1200 } | 1163 } |
| 1201 | 1164 |
| 1202 /// Returns the current source element. | 1165 /// Returns the current source element. |
| 1203 /// | 1166 /// |
| 1204 /// The returned element is a declaration element. | 1167 /// The returned element is a declaration element. |
| 1205 // TODO(johnniwinther): Check that all usages of sourceElement agree on | 1168 // TODO(johnniwinther): Check that all usages of sourceElement agree on |
| 1206 // implementation/declaration distinction. | 1169 // implementation/declaration distinction. |
| 1207 Element get sourceElement => sourceElementStack.last; | 1170 Element get sourceElement => sourceElementStack.last; |
| 1208 | 1171 |
| 1209 bool get _checkOrTrustTypes => compiler.options.enableTypeAssertions || | 1172 bool get _checkOrTrustTypes => |
| 1173 compiler.options.enableTypeAssertions || |
| 1210 compiler.options.trustTypeAnnotations; | 1174 compiler.options.trustTypeAnnotations; |
| 1211 | 1175 |
| 1212 /// Build the graph for [target]. | 1176 /// Build the graph for [target]. |
| 1213 HGraph build() { | 1177 HGraph build() { |
| 1214 assert(invariant(target, target.isImplementation)); | 1178 assert(invariant(target, target.isImplementation)); |
| 1215 HInstruction.idCounter = 0; | 1179 HInstruction.idCounter = 0; |
| 1216 // TODO(sigmund): remove `result` and return graph directly, need to ensure | 1180 // TODO(sigmund): remove `result` and return graph directly, need to ensure |
| 1217 // that it can never be null (see result in buildFactory for instance). | 1181 // that it can never be null (see result in buildFactory for instance). |
| 1218 var result; | 1182 var result; |
| 1219 if (target.isGenerativeConstructor) { | 1183 if (target.isGenerativeConstructor) { |
| 1220 result = buildFactory(target); | 1184 result = buildFactory(target); |
| 1221 } else if (target.isGenerativeConstructorBody || | 1185 } else if (target.isGenerativeConstructorBody || |
| 1222 target.isFactoryConstructor || | 1186 target.isFactoryConstructor || |
| 1223 target.isFunction || | 1187 target.isFunction || |
| 1224 target.isGetter || | 1188 target.isGetter || |
| 1225 target.isSetter) { | 1189 target.isSetter) { |
| 1226 result = buildMethod(target); | 1190 result = buildMethod(target); |
| 1227 } else if (target.isField) { | 1191 } else if (target.isField) { |
| 1228 if (target.isInstanceMember) { | 1192 if (target.isInstanceMember) { |
| 1229 assert(compiler.options.enableTypeAssertions); | 1193 assert(compiler.options.enableTypeAssertions); |
| 1230 result = buildCheckedSetter(target); | 1194 result = buildCheckedSetter(target); |
| 1231 } else { | 1195 } else { |
| 1232 result = buildLazyInitializer(target); | 1196 result = buildLazyInitializer(target); |
| 1233 } | 1197 } |
| 1234 } else { | 1198 } else { |
| 1235 reporter.internalError(target, 'Unexpected element kind $target.'); | 1199 reporter.internalError(target, 'Unexpected element kind $target.'); |
| 1236 } | 1200 } |
| 1237 assert(result.isValid()); | 1201 assert(result.isValid()); |
| 1238 return result; | 1202 return result; |
| 1239 } | 1203 } |
| 1240 | 1204 |
| 1241 | |
| 1242 HBasicBlock addNewBlock() { | 1205 HBasicBlock addNewBlock() { |
| 1243 HBasicBlock block = graph.addNewBlock(); | 1206 HBasicBlock block = graph.addNewBlock(); |
| 1244 // If adding a new block during building of an expression, it is due to | 1207 // If adding a new block during building of an expression, it is due to |
| 1245 // conditional expressions or short-circuit logical operators. | 1208 // conditional expressions or short-circuit logical operators. |
| 1246 return block; | 1209 return block; |
| 1247 } | 1210 } |
| 1248 | 1211 |
| 1249 void open(HBasicBlock block) { | 1212 void open(HBasicBlock block) { |
| 1250 block.open(); | 1213 block.open(); |
| 1251 current = block; | 1214 current = block; |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1302 FunctionElement function, | 1265 FunctionElement function, |
| 1303 Selector selector, | 1266 Selector selector, |
| 1304 List<HInstruction> providedArguments, | 1267 List<HInstruction> providedArguments, |
| 1305 ast.Node currentNode) { | 1268 ast.Node currentNode) { |
| 1306 assert(invariant(function, function.isImplementation)); | 1269 assert(invariant(function, function.isImplementation)); |
| 1307 assert(providedArguments != null); | 1270 assert(providedArguments != null); |
| 1308 | 1271 |
| 1309 bool isInstanceMember = function.isInstanceMember; | 1272 bool isInstanceMember = function.isInstanceMember; |
| 1310 // For static calls, [providedArguments] is complete, default arguments | 1273 // For static calls, [providedArguments] is complete, default arguments |
| 1311 // have been included if necessary, see [makeStaticArgumentList]. | 1274 // have been included if necessary, see [makeStaticArgumentList]. |
| 1312 if (!isInstanceMember | 1275 if (!isInstanceMember || |
| 1313 || currentNode == null // In erroneous code, currentNode can be null. | 1276 currentNode == null // In erroneous code, currentNode can be null. |
| 1314 || providedArgumentsKnownToBeComplete(currentNode) | 1277 || |
| 1315 || function.isGenerativeConstructorBody | 1278 providedArgumentsKnownToBeComplete(currentNode) || |
| 1316 || selector.isGetter) { | 1279 function.isGenerativeConstructorBody || |
| 1280 selector.isGetter) { |
| 1317 // For these cases, the provided argument list is known to be complete. | 1281 // For these cases, the provided argument list is known to be complete. |
| 1318 return providedArguments; | 1282 return providedArguments; |
| 1319 } else { | 1283 } else { |
| 1320 return completeDynamicSendArgumentsList( | 1284 return completeDynamicSendArgumentsList( |
| 1321 selector, function, providedArguments); | 1285 selector, function, providedArguments); |
| 1322 } | 1286 } |
| 1323 } | 1287 } |
| 1324 | 1288 |
| 1325 /** | 1289 /** |
| 1326 * Returns a complete argument list for a dynamic call of [function]. The | 1290 * Returns a complete argument list for a dynamic call of [function]. The |
| 1327 * initial argument list [providedArguments], created by | 1291 * initial argument list [providedArguments], created by |
| 1328 * [addDynamicSendArgumentsToList], does not include values for default | 1292 * [addDynamicSendArgumentsToList], does not include values for default |
| 1329 * arguments used in the call. The reason is that the target function (which | 1293 * arguments used in the call. The reason is that the target function (which |
| 1330 * defines the defaults) is not known. | 1294 * defines the defaults) is not known. |
| 1331 * | 1295 * |
| 1332 * However, inlining can only be performed when the target function can be | 1296 * However, inlining can only be performed when the target function can be |
| 1333 * resolved statically. The defaults can therefore be included at this point. | 1297 * resolved statically. The defaults can therefore be included at this point. |
| 1334 * | 1298 * |
| 1335 * The [providedArguments] list contains first all positional arguments, then | 1299 * The [providedArguments] list contains first all positional arguments, then |
| 1336 * the provided named arguments (the named arguments that are defined in the | 1300 * the provided named arguments (the named arguments that are defined in the |
| 1337 * [selector]) in a specific order (see [addDynamicSendArgumentsToList]). | 1301 * [selector]) in a specific order (see [addDynamicSendArgumentsToList]). |
| 1338 */ | 1302 */ |
| 1339 List<HInstruction> completeDynamicSendArgumentsList( | 1303 List<HInstruction> completeDynamicSendArgumentsList(Selector selector, |
| 1340 Selector selector, | 1304 FunctionElement function, List<HInstruction> providedArguments) { |
| 1341 FunctionElement function, | |
| 1342 List<HInstruction> providedArguments) { | |
| 1343 assert(selector.applies(function, compiler.world)); | 1305 assert(selector.applies(function, compiler.world)); |
| 1344 FunctionSignature signature = function.functionSignature; | 1306 FunctionSignature signature = function.functionSignature; |
| 1345 List<HInstruction> compiledArguments = new List<HInstruction>( | 1307 List<HInstruction> compiledArguments = new List<HInstruction>( |
| 1346 signature.parameterCount + 1); // Plus one for receiver. | 1308 signature.parameterCount + 1); // Plus one for receiver. |
| 1347 | 1309 |
| 1348 compiledArguments[0] = providedArguments[0]; // Receiver. | 1310 compiledArguments[0] = providedArguments[0]; // Receiver. |
| 1349 int index = 1; | 1311 int index = 1; |
| 1350 for (; index <= signature.requiredParameterCount; index++) { | 1312 for (; index <= signature.requiredParameterCount; index++) { |
| 1351 compiledArguments[index] = providedArguments[index]; | 1313 compiledArguments[index] = providedArguments[index]; |
| 1352 } | 1314 } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1389 index++; | 1351 index++; |
| 1390 }); | 1352 }); |
| 1391 } | 1353 } |
| 1392 return compiledArguments; | 1354 return compiledArguments; |
| 1393 } | 1355 } |
| 1394 | 1356 |
| 1395 /** | 1357 /** |
| 1396 * Try to inline [element] within the currect context of the builder. The | 1358 * Try to inline [element] within the currect context of the builder. The |
| 1397 * insertion point is the state of the builder. | 1359 * insertion point is the state of the builder. |
| 1398 */ | 1360 */ |
| 1399 bool tryInlineMethod(Element element, | 1361 bool tryInlineMethod(Element element, Selector selector, TypeMask mask, |
| 1400 Selector selector, | 1362 List<HInstruction> providedArguments, ast.Node currentNode, |
| 1401 TypeMask mask, | 1363 {InterfaceType instanceType}) { |
| 1402 List<HInstruction> providedArguments, | |
| 1403 ast.Node currentNode, | |
| 1404 {InterfaceType instanceType}) { | |
| 1405 // TODO(johnniwinther): Register this on the [registry]. Currently the | 1364 // TODO(johnniwinther): Register this on the [registry]. Currently the |
| 1406 // [CodegenRegistry] calls the enqueuer, but [element] should _not_ be | 1365 // [CodegenRegistry] calls the enqueuer, but [element] should _not_ be |
| 1407 // enqueued. | 1366 // enqueued. |
| 1408 backend.registerStaticUse(element, compiler.enqueuer.codegen); | 1367 backend.registerStaticUse(element, compiler.enqueuer.codegen); |
| 1409 | 1368 |
| 1410 if (backend.isJsInterop(element) && !element.isFactoryConstructor) { | 1369 if (backend.isJsInterop(element) && !element.isFactoryConstructor) { |
| 1411 // We only inline factory JavaScript interop constructors. | 1370 // We only inline factory JavaScript interop constructors. |
| 1412 return false; | 1371 return false; |
| 1413 } | 1372 } |
| 1414 | 1373 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1425 bool cachedCanBeInlined = | 1384 bool cachedCanBeInlined = |
| 1426 backend.inlineCache.canInline(function, insideLoop: insideLoop); | 1385 backend.inlineCache.canInline(function, insideLoop: insideLoop); |
| 1427 if (cachedCanBeInlined == false) return false; | 1386 if (cachedCanBeInlined == false) return false; |
| 1428 | 1387 |
| 1429 bool meetsHardConstraints() { | 1388 bool meetsHardConstraints() { |
| 1430 if (compiler.options.disableInlining) return false; | 1389 if (compiler.options.disableInlining) return false; |
| 1431 | 1390 |
| 1432 assert(invariant( | 1391 assert(invariant( |
| 1433 currentNode != null ? currentNode : element, | 1392 currentNode != null ? currentNode : element, |
| 1434 selector != null || | 1393 selector != null || |
| 1435 Elements.isStaticOrTopLevel(element) || | 1394 Elements.isStaticOrTopLevel(element) || |
| 1436 element.isGenerativeConstructorBody, | 1395 element.isGenerativeConstructorBody, |
| 1437 message: "Missing selector for inlining of $element.")); | 1396 message: "Missing selector for inlining of $element.")); |
| 1438 if (selector != null) { | 1397 if (selector != null) { |
| 1439 if (!selector.applies(function, compiler.world)) return false; | 1398 if (!selector.applies(function, compiler.world)) return false; |
| 1440 if (mask != null && !mask.canHit(function, selector, compiler.world)) { | 1399 if (mask != null && !mask.canHit(function, selector, compiler.world)) { |
| 1441 return false; | 1400 return false; |
| 1442 } | 1401 } |
| 1443 } | 1402 } |
| 1444 | 1403 |
| 1445 if (backend.isJsInterop(element)) return false; | 1404 if (backend.isJsInterop(element)) return false; |
| 1446 | 1405 |
| 1447 // Don't inline operator== methods if the parameter can be null. | 1406 // Don't inline operator== methods if the parameter can be null. |
| 1448 if (element.name == '==') { | 1407 if (element.name == '==') { |
| 1449 if (element.enclosingClass != coreClasses.objectClass | 1408 if (element.enclosingClass != coreClasses.objectClass && |
| 1450 && providedArguments[1].canBeNull()) { | 1409 providedArguments[1].canBeNull()) { |
| 1451 return false; | 1410 return false; |
| 1452 } | 1411 } |
| 1453 } | 1412 } |
| 1454 | 1413 |
| 1455 // Generative constructors of native classes should not be called directly | 1414 // Generative constructors of native classes should not be called directly |
| 1456 // and have an extra argument that causes problems with inlining. | 1415 // and have an extra argument that causes problems with inlining. |
| 1457 if (element.isGenerativeConstructor | 1416 if (element.isGenerativeConstructor && |
| 1458 && backend.isNativeOrExtendsNative(element.enclosingClass)) { | 1417 backend.isNativeOrExtendsNative(element.enclosingClass)) { |
| 1459 return false; | 1418 return false; |
| 1460 } | 1419 } |
| 1461 | 1420 |
| 1462 // A generative constructor body is not seen by global analysis, | 1421 // A generative constructor body is not seen by global analysis, |
| 1463 // so we should not query for its type. | 1422 // so we should not query for its type. |
| 1464 if (!element.isGenerativeConstructorBody) { | 1423 if (!element.isGenerativeConstructorBody) { |
| 1465 // Don't inline if the return type was inferred to be non-null empty. | 1424 // Don't inline if the return type was inferred to be non-null empty. |
| 1466 // This means that the function always throws an exception. | 1425 // This means that the function always throws an exception. |
| 1467 TypeMask returnType = | 1426 TypeMask returnType = |
| 1468 compiler.typesTask.getGuaranteedReturnTypeOfElement(element); | 1427 compiler.typesTask.getGuaranteedReturnTypeOfElement(element); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1517 | 1476 |
| 1518 // Do not inline code that is rarely executed unless it reduces size. | 1477 // Do not inline code that is rarely executed unless it reduces size. |
| 1519 if (inExpressionOfThrow || inLazyInitializerExpression) { | 1478 if (inExpressionOfThrow || inLazyInitializerExpression) { |
| 1520 return reductiveHeuristic(); | 1479 return reductiveHeuristic(); |
| 1521 } | 1480 } |
| 1522 | 1481 |
| 1523 if (cachedCanBeInlined == true) { | 1482 if (cachedCanBeInlined == true) { |
| 1524 // We may have forced the inlining of some methods. Therefore check | 1483 // We may have forced the inlining of some methods. Therefore check |
| 1525 // if we can inline this method regardless of size. | 1484 // if we can inline this method regardless of size. |
| 1526 assert(InlineWeeder.canBeInlined(function, -1, false, | 1485 assert(InlineWeeder.canBeInlined(function, -1, false, |
| 1527 allowLoops: true, | 1486 allowLoops: true, |
| 1528 enableUserAssertions: compiler.options.enableUserAssertions)); | 1487 enableUserAssertions: compiler.options.enableUserAssertions)); |
| 1529 return true; | 1488 return true; |
| 1530 } | 1489 } |
| 1531 | 1490 |
| 1532 int numParameters = function.functionSignature.parameterCount; | 1491 int numParameters = function.functionSignature.parameterCount; |
| 1533 int maxInliningNodes; | 1492 int maxInliningNodes; |
| 1534 bool useMaxInliningNodes = true; | 1493 bool useMaxInliningNodes = true; |
| 1535 if (insideLoop) { | 1494 if (insideLoop) { |
| 1536 maxInliningNodes = InlineWeeder.INLINING_NODES_INSIDE_LOOP + | 1495 maxInliningNodes = InlineWeeder.INLINING_NODES_INSIDE_LOOP + |
| 1537 InlineWeeder.INLINING_NODES_INSIDE_LOOP_ARG_FACTOR * numParameters; | 1496 InlineWeeder.INLINING_NODES_INSIDE_LOOP_ARG_FACTOR * numParameters; |
| 1538 } else { | 1497 } else { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1560 | 1519 |
| 1561 void doInlining() { | 1520 void doInlining() { |
| 1562 // Add an explicit null check on the receiver before doing the | 1521 // Add an explicit null check on the receiver before doing the |
| 1563 // inlining. We use [element] to get the same name in the | 1522 // inlining. We use [element] to get the same name in the |
| 1564 // NoSuchMethodError message as if we had called it. | 1523 // NoSuchMethodError message as if we had called it. |
| 1565 if (element.isInstanceMember && | 1524 if (element.isInstanceMember && |
| 1566 !element.isGenerativeConstructorBody && | 1525 !element.isGenerativeConstructorBody && |
| 1567 (mask == null || mask.isNullable)) { | 1526 (mask == null || mask.isNullable)) { |
| 1568 addWithPosition( | 1527 addWithPosition( |
| 1569 new HFieldGet(null, providedArguments[0], backend.dynamicType, | 1528 new HFieldGet(null, providedArguments[0], backend.dynamicType, |
| 1570 isAssignable: false), | 1529 isAssignable: false), |
| 1571 currentNode); | 1530 currentNode); |
| 1572 } | 1531 } |
| 1573 List<HInstruction> compiledArguments = completeSendArgumentsList( | 1532 List<HInstruction> compiledArguments = completeSendArgumentsList( |
| 1574 function, selector, providedArguments, currentNode); | 1533 function, selector, providedArguments, currentNode); |
| 1575 enterInlinedMethod( | 1534 enterInlinedMethod(function, currentNode, compiledArguments, |
| 1576 function, currentNode, compiledArguments, instanceType: instanceType); | 1535 instanceType: instanceType); |
| 1577 inlinedFrom(function, () { | 1536 inlinedFrom(function, () { |
| 1578 if (!isReachable) { | 1537 if (!isReachable) { |
| 1579 emitReturn(graph.addConstantNull(compiler), null); | 1538 emitReturn(graph.addConstantNull(compiler), null); |
| 1580 } else { | 1539 } else { |
| 1581 doInline(function); | 1540 doInline(function); |
| 1582 } | 1541 } |
| 1583 }); | 1542 }); |
| 1584 leaveInlinedMethod(); | 1543 leaveInlinedMethod(); |
| 1585 } | 1544 } |
| 1586 | 1545 |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1721 graph.calledInLoop = compiler.world.isCalledInLoop(functionElement); | 1680 graph.calledInLoop = compiler.world.isCalledInLoop(functionElement); |
| 1722 ast.FunctionExpression function = functionElement.node; | 1681 ast.FunctionExpression function = functionElement.node; |
| 1723 assert(function != null); | 1682 assert(function != null); |
| 1724 assert(elements.getFunctionDefinition(function) != null); | 1683 assert(elements.getFunctionDefinition(function) != null); |
| 1725 openFunction(functionElement, function); | 1684 openFunction(functionElement, function); |
| 1726 String name = functionElement.name; | 1685 String name = functionElement.name; |
| 1727 if (backend.isJsInterop(functionElement)) { | 1686 if (backend.isJsInterop(functionElement)) { |
| 1728 push(invokeJsInteropFunction(functionElement, parameters.values.toList(), | 1687 push(invokeJsInteropFunction(functionElement, parameters.values.toList(), |
| 1729 sourceInformationBuilder.buildGeneric(function))); | 1688 sourceInformationBuilder.buildGeneric(function))); |
| 1730 var value = pop(); | 1689 var value = pop(); |
| 1731 closeAndGotoExit(new HReturn(value, | 1690 closeAndGotoExit(new HReturn( |
| 1732 sourceInformationBuilder.buildReturn(functionElement.node))); | 1691 value, sourceInformationBuilder.buildReturn(functionElement.node))); |
| 1733 return closeFunction(); | 1692 return closeFunction(); |
| 1734 } | 1693 } |
| 1735 assert(invariant(functionElement, !function.modifiers.isExternal)); | 1694 assert(invariant(functionElement, !function.modifiers.isExternal)); |
| 1736 | 1695 |
| 1737 // If [functionElement] is `operator==` we explicitely add a null check at | 1696 // If [functionElement] is `operator==` we explicitely add a null check at |
| 1738 // the beginning of the method. This is to avoid having call sites do the | 1697 // the beginning of the method. This is to avoid having call sites do the |
| 1739 // null check. | 1698 // null check. |
| 1740 if (name == '==') { | 1699 if (name == '==') { |
| 1741 if (!backend.operatorEqHandlesNullArgument(functionElement)) { | 1700 if (!backend.operatorEqHandlesNullArgument(functionElement)) { |
| 1742 handleIf( | 1701 handleIf(function, visitCondition: () { |
| 1743 function, | 1702 HParameterValue parameter = parameters.values.first; |
| 1744 visitCondition: () { | 1703 push(new HIdentity(parameter, graph.addConstantNull(compiler), null, |
| 1745 HParameterValue parameter = parameters.values.first; | 1704 backend.boolType)); |
| 1746 push(new HIdentity( | 1705 }, visitThen: () { |
| 1747 parameter, graph.addConstantNull(compiler), null, | 1706 closeAndGotoExit(new HReturn(graph.addConstantBool(false, compiler), |
| 1748 backend.boolType)); | 1707 sourceInformationBuilder.buildImplicitReturn(functionElement))); |
| 1749 }, | 1708 }, |
| 1750 visitThen: () { | |
| 1751 closeAndGotoExit(new HReturn( | |
| 1752 graph.addConstantBool(false, compiler), | |
| 1753 sourceInformationBuilder | |
| 1754 .buildImplicitReturn(functionElement))); | |
| 1755 }, | |
| 1756 visitElse: null, | 1709 visitElse: null, |
| 1757 sourceInformation: sourceInformationBuilder.buildIf(function.body)); | 1710 sourceInformation: sourceInformationBuilder.buildIf(function.body)); |
| 1758 } | 1711 } |
| 1759 } | 1712 } |
| 1760 if (const bool.fromEnvironment('unreachable-throw') == true) { | 1713 if (const bool.fromEnvironment('unreachable-throw') == true) { |
| 1761 var emptyParameters = parameters.values | 1714 var emptyParameters = |
| 1762 .where((p) => p.instructionType.isEmpty); | 1715 parameters.values.where((p) => p.instructionType.isEmpty); |
| 1763 if (emptyParameters.length > 0) { | 1716 if (emptyParameters.length > 0) { |
| 1764 addComment('${emptyParameters} inferred as [empty]'); | 1717 addComment('${emptyParameters} inferred as [empty]'); |
| 1765 pushInvokeStatic(function.body, helpers.assertUnreachableMethod, []); | 1718 pushInvokeStatic(function.body, helpers.assertUnreachableMethod, []); |
| 1766 pop(); | 1719 pop(); |
| 1767 return closeFunction(); | 1720 return closeFunction(); |
| 1768 } | 1721 } |
| 1769 } | 1722 } |
| 1770 function.body.accept(this); | 1723 function.body.accept(this); |
| 1771 return closeFunction(); | 1724 return closeFunction(); |
| 1772 } | 1725 } |
| 1773 | 1726 |
| 1774 /// Adds a JavaScript comment to the output. The comment will be omitted in | 1727 /// Adds a JavaScript comment to the output. The comment will be omitted in |
| 1775 /// minified mode. Each line in [text] is preceded with `//` and indented. | 1728 /// minified mode. Each line in [text] is preceded with `//` and indented. |
| 1776 /// Use sparingly. In order for the comment to be retained it is modeled as | 1729 /// Use sparingly. In order for the comment to be retained it is modeled as |
| 1777 /// having side effects which will inhibit code motion. | 1730 /// having side effects which will inhibit code motion. |
| 1778 // TODO(sra): Figure out how to keep comment anchored without effects. | 1731 // TODO(sra): Figure out how to keep comment anchored without effects. |
| 1779 void addComment(String text) { | 1732 void addComment(String text) { |
| 1780 add(new HForeignCode( | 1733 add(new HForeignCode(js.js.statementTemplateYielding(new js.Comment(text)), |
| 1781 js.js.statementTemplateYielding(new js.Comment(text)), | 1734 backend.dynamicType, <HInstruction>[], |
| 1782 backend.dynamicType, | |
| 1783 <HInstruction>[], | |
| 1784 isStatement: true)); | 1735 isStatement: true)); |
| 1785 } | 1736 } |
| 1786 | 1737 |
| 1787 HGraph buildCheckedSetter(VariableElement field) { | 1738 HGraph buildCheckedSetter(VariableElement field) { |
| 1788 openFunction(field, field.node); | 1739 openFunction(field, field.node); |
| 1789 HInstruction thisInstruction = localsHandler.readThis(); | 1740 HInstruction thisInstruction = localsHandler.readThis(); |
| 1790 // Use dynamic type because the type computed by the inferrer is | 1741 // Use dynamic type because the type computed by the inferrer is |
| 1791 // narrowed to the type annotation. | 1742 // narrowed to the type annotation. |
| 1792 HInstruction parameter = new HParameterValue(field, backend.dynamicType); | 1743 HInstruction parameter = new HParameterValue(field, backend.dynamicType); |
| 1793 // Add the parameter as the last instruction of the entry block. | 1744 // Add the parameter as the last instruction of the entry block. |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1871 | 1822 |
| 1872 /** | 1823 /** |
| 1873 * This method sets up the local state of the builder for inlining [function]. | 1824 * This method sets up the local state of the builder for inlining [function]. |
| 1874 * The arguments of the function are inserted into the [localsHandler]. | 1825 * The arguments of the function are inserted into the [localsHandler]. |
| 1875 * | 1826 * |
| 1876 * When inlining a function, [:return:] statements are not emitted as | 1827 * When inlining a function, [:return:] statements are not emitted as |
| 1877 * [HReturn] instructions. Instead, the value of a synthetic element is | 1828 * [HReturn] instructions. Instead, the value of a synthetic element is |
| 1878 * updated in the [localsHandler]. This function creates such an element and | 1829 * updated in the [localsHandler]. This function creates such an element and |
| 1879 * stores it in the [returnLocal] field. | 1830 * stores it in the [returnLocal] field. |
| 1880 */ | 1831 */ |
| 1881 void setupStateForInlining(FunctionElement function, | 1832 void setupStateForInlining( |
| 1882 List<HInstruction> compiledArguments, | 1833 FunctionElement function, List<HInstruction> compiledArguments, |
| 1883 {InterfaceType instanceType}) { | 1834 {InterfaceType instanceType}) { |
| 1884 localsHandler = new LocalsHandler(this, function, instanceType); | 1835 localsHandler = new LocalsHandler(this, function, instanceType); |
| 1885 localsHandler.closureData = | 1836 localsHandler.closureData = compiler.closureToClassMapper |
| 1886 compiler.closureToClassMapper.computeClosureToClassMapping( | 1837 .computeClosureToClassMapping(function, function.node, elements); |
| 1887 function, function.node, elements); | |
| 1888 returnLocal = new SyntheticLocal("result", function); | 1838 returnLocal = new SyntheticLocal("result", function); |
| 1889 localsHandler.updateLocal(returnLocal, | 1839 localsHandler.updateLocal(returnLocal, graph.addConstantNull(compiler)); |
| 1890 graph.addConstantNull(compiler)); | |
| 1891 | 1840 |
| 1892 inTryStatement = false; // TODO(lry): why? Document. | 1841 inTryStatement = false; // TODO(lry): why? Document. |
| 1893 | 1842 |
| 1894 int argumentIndex = 0; | 1843 int argumentIndex = 0; |
| 1895 if (function.isInstanceMember) { | 1844 if (function.isInstanceMember) { |
| 1896 localsHandler.updateLocal(localsHandler.closureData.thisLocal, | 1845 localsHandler.updateLocal(localsHandler.closureData.thisLocal, |
| 1897 compiledArguments[argumentIndex++]); | 1846 compiledArguments[argumentIndex++]); |
| 1898 } | 1847 } |
| 1899 | 1848 |
| 1900 FunctionSignature signature = function.functionSignature; | 1849 FunctionSignature signature = function.functionSignature; |
| 1901 signature.orderedForEachParameter((ParameterElement parameter) { | 1850 signature.orderedForEachParameter((ParameterElement parameter) { |
| 1902 HInstruction argument = compiledArguments[argumentIndex++]; | 1851 HInstruction argument = compiledArguments[argumentIndex++]; |
| 1903 localsHandler.updateLocal(parameter, argument); | 1852 localsHandler.updateLocal(parameter, argument); |
| 1904 }); | 1853 }); |
| 1905 | 1854 |
| 1906 ClassElement enclosing = function.enclosingClass; | 1855 ClassElement enclosing = function.enclosingClass; |
| 1907 if ((function.isConstructor || function.isGenerativeConstructorBody) | 1856 if ((function.isConstructor || function.isGenerativeConstructorBody) && |
| 1908 && backend.classNeedsRti(enclosing)) { | 1857 backend.classNeedsRti(enclosing)) { |
| 1909 enclosing.typeVariables.forEach((TypeVariableType typeVariable) { | 1858 enclosing.typeVariables.forEach((TypeVariableType typeVariable) { |
| 1910 HInstruction argument = compiledArguments[argumentIndex++]; | 1859 HInstruction argument = compiledArguments[argumentIndex++]; |
| 1911 localsHandler.updateLocal( | 1860 localsHandler.updateLocal( |
| 1912 localsHandler.getTypeVariableAsLocal(typeVariable), argument); | 1861 localsHandler.getTypeVariableAsLocal(typeVariable), argument); |
| 1913 }); | 1862 }); |
| 1914 } | 1863 } |
| 1915 assert(argumentIndex == compiledArguments.length); | 1864 assert(argumentIndex == compiledArguments.length); |
| 1916 | 1865 |
| 1917 elements = function.resolvedAst.elements; | 1866 elements = function.resolvedAst.elements; |
| 1918 assert(elements != null); | 1867 assert(elements != null); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1940 potentiallyCheckInlinedParameterTypes(function); | 1889 potentiallyCheckInlinedParameterTypes(function); |
| 1941 | 1890 |
| 1942 if (function.isGenerativeConstructor) { | 1891 if (function.isGenerativeConstructor) { |
| 1943 buildFactory(function); | 1892 buildFactory(function); |
| 1944 } else { | 1893 } else { |
| 1945 ast.FunctionExpression functionNode = function.node; | 1894 ast.FunctionExpression functionNode = function.node; |
| 1946 functionNode.body.accept(this); | 1895 functionNode.body.accept(this); |
| 1947 } | 1896 } |
| 1948 } | 1897 } |
| 1949 | 1898 |
| 1950 | |
| 1951 addInlinedInstantiation(DartType type) { | 1899 addInlinedInstantiation(DartType type) { |
| 1952 if (type != null) { | 1900 if (type != null) { |
| 1953 currentInlinedInstantiations.add(type); | 1901 currentInlinedInstantiations.add(type); |
| 1954 } | 1902 } |
| 1955 } | 1903 } |
| 1956 | 1904 |
| 1957 removeInlinedInstantiation(DartType type) { | 1905 removeInlinedInstantiation(DartType type) { |
| 1958 if (type != null) { | 1906 if (type != null) { |
| 1959 currentInlinedInstantiations.removeLast(); | 1907 currentInlinedInstantiations.removeLast(); |
| 1960 } | 1908 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1982 HInstruction argument = localsHandler.readLocal(parameter); | 1930 HInstruction argument = localsHandler.readLocal(parameter); |
| 1983 potentiallyCheckOrTrustType(argument, parameter.type); | 1931 potentiallyCheckOrTrustType(argument, parameter.type); |
| 1984 }); | 1932 }); |
| 1985 } | 1933 } |
| 1986 | 1934 |
| 1987 /** | 1935 /** |
| 1988 * Documentation wanted -- johnniwinther | 1936 * Documentation wanted -- johnniwinther |
| 1989 * | 1937 * |
| 1990 * Invariant: [constructors] must contain only implementation elements. | 1938 * Invariant: [constructors] must contain only implementation elements. |
| 1991 */ | 1939 */ |
| 1992 void inlineSuperOrRedirect(ConstructorElement callee, | 1940 void inlineSuperOrRedirect( |
| 1993 List<HInstruction> compiledArguments, | 1941 ConstructorElement callee, |
| 1994 List<FunctionElement> constructors, | 1942 List<HInstruction> compiledArguments, |
| 1995 Map<Element, HInstruction> fieldValues, | 1943 List<FunctionElement> constructors, |
| 1996 FunctionElement caller) { | 1944 Map<Element, HInstruction> fieldValues, |
| 1945 FunctionElement caller) { |
| 1997 callee = callee.implementation; | 1946 callee = callee.implementation; |
| 1998 reporter.withCurrentElement(callee, () { | 1947 reporter.withCurrentElement(callee, () { |
| 1999 constructors.add(callee); | 1948 constructors.add(callee); |
| 2000 ClassElement enclosingClass = callee.enclosingClass; | 1949 ClassElement enclosingClass = callee.enclosingClass; |
| 2001 if (backend.classNeedsRti(enclosingClass)) { | 1950 if (backend.classNeedsRti(enclosingClass)) { |
| 2002 // If [enclosingClass] needs RTI, we have to give a value to its | 1951 // If [enclosingClass] needs RTI, we have to give a value to its |
| 2003 // type parameters. | 1952 // type parameters. |
| 2004 ClassElement currentClass = caller.enclosingClass; | 1953 ClassElement currentClass = caller.enclosingClass; |
| 2005 // For a super constructor call, the type is the supertype of | 1954 // For a super constructor call, the type is the supertype of |
| 2006 // [currentClass]. For a redirecting constructor, the type is | 1955 // [currentClass]. For a redirecting constructor, the type is |
| (...skipping 21 matching lines...) Expand all Loading... |
| 2028 localsHandler.getTypeVariableAsLocal(variable), | 1977 localsHandler.getTypeVariableAsLocal(variable), |
| 2029 graph.addConstantNull(compiler)); | 1978 graph.addConstantNull(compiler)); |
| 2030 } | 1979 } |
| 2031 } | 1980 } |
| 2032 } | 1981 } |
| 2033 | 1982 |
| 2034 // For redirecting constructors, the fields will be initialized later | 1983 // For redirecting constructors, the fields will be initialized later |
| 2035 // by the effective target. | 1984 // by the effective target. |
| 2036 if (!callee.isRedirectingGenerative) { | 1985 if (!callee.isRedirectingGenerative) { |
| 2037 inlinedFrom(callee, () { | 1986 inlinedFrom(callee, () { |
| 2038 buildFieldInitializers(callee.enclosingClass.implementation, | 1987 buildFieldInitializers( |
| 2039 fieldValues); | 1988 callee.enclosingClass.implementation, fieldValues); |
| 2040 }); | 1989 }); |
| 2041 } | 1990 } |
| 2042 | 1991 |
| 2043 int index = 0; | 1992 int index = 0; |
| 2044 FunctionSignature params = callee.functionSignature; | 1993 FunctionSignature params = callee.functionSignature; |
| 2045 params.orderedForEachParameter((ParameterElement parameter) { | 1994 params.orderedForEachParameter((ParameterElement parameter) { |
| 2046 HInstruction argument = compiledArguments[index++]; | 1995 HInstruction argument = compiledArguments[index++]; |
| 2047 // Because we are inlining the initializer, we must update | 1996 // Because we are inlining the initializer, we must update |
| 2048 // what was given as parameter. This will be used in case | 1997 // what was given as parameter. This will be used in case |
| 2049 // there is a parameter check expression in the initializer. | 1998 // there is a parameter check expression in the initializer. |
| 2050 parameters[parameter] = argument; | 1999 parameters[parameter] = argument; |
| 2051 localsHandler.updateLocal(parameter, argument); | 2000 localsHandler.updateLocal(parameter, argument); |
| 2052 // Don't forget to update the field, if the parameter is of the | 2001 // Don't forget to update the field, if the parameter is of the |
| 2053 // form [:this.x:]. | 2002 // form [:this.x:]. |
| 2054 if (parameter.isInitializingFormal) { | 2003 if (parameter.isInitializingFormal) { |
| 2055 InitializingFormalElement fieldParameterElement = parameter; | 2004 InitializingFormalElement fieldParameterElement = parameter; |
| 2056 fieldValues[fieldParameterElement.fieldElement] = argument; | 2005 fieldValues[fieldParameterElement.fieldElement] = argument; |
| 2057 } | 2006 } |
| 2058 }); | 2007 }); |
| 2059 | 2008 |
| 2060 // Build the initializers in the context of the new constructor. | 2009 // Build the initializers in the context of the new constructor. |
| 2061 TreeElements oldElements = elements; | 2010 TreeElements oldElements = elements; |
| 2062 ResolvedAst resolvedAst = callee.resolvedAst; | 2011 ResolvedAst resolvedAst = callee.resolvedAst; |
| 2063 elements = resolvedAst.elements; | 2012 elements = resolvedAst.elements; |
| 2064 ClosureClassMap oldClosureData = localsHandler.closureData; | 2013 ClosureClassMap oldClosureData = localsHandler.closureData; |
| 2065 ast.Node node = resolvedAst.node; | 2014 ast.Node node = resolvedAst.node; |
| 2066 ClosureClassMap newClosureData = | 2015 ClosureClassMap newClosureData = compiler.closureToClassMapper |
| 2067 compiler.closureToClassMapper.computeClosureToClassMapping( | 2016 .computeClosureToClassMapping(callee, node, elements); |
| 2068 callee, node, elements); | |
| 2069 localsHandler.closureData = newClosureData; | 2017 localsHandler.closureData = newClosureData; |
| 2070 localsHandler.enterScope(node, callee); | 2018 localsHandler.enterScope(node, callee); |
| 2071 buildInitializers(callee, constructors, fieldValues); | 2019 buildInitializers(callee, constructors, fieldValues); |
| 2072 localsHandler.closureData = oldClosureData; | 2020 localsHandler.closureData = oldClosureData; |
| 2073 elements = oldElements; | 2021 elements = oldElements; |
| 2074 }); | 2022 }); |
| 2075 } | 2023 } |
| 2076 | 2024 |
| 2077 /** | 2025 /** |
| 2078 * Run through the initializers and inline all field initializers. Recursively | 2026 * Run through the initializers and inline all field initializers. Recursively |
| 2079 * inlines super initializers. | 2027 * inlines super initializers. |
| 2080 * | 2028 * |
| 2081 * The constructors of the inlined initializers is added to [constructors] | 2029 * The constructors of the inlined initializers is added to [constructors] |
| 2082 * with sub constructors having a lower index than super constructors. | 2030 * with sub constructors having a lower index than super constructors. |
| 2083 * | 2031 * |
| 2084 * Invariant: The [constructor] and elements in [constructors] must all be | 2032 * Invariant: The [constructor] and elements in [constructors] must all be |
| 2085 * implementation elements. | 2033 * implementation elements. |
| 2086 */ | 2034 */ |
| 2087 void buildInitializers(ConstructorElement constructor, | 2035 void buildInitializers( |
| 2088 List<FunctionElement> constructors, | 2036 ConstructorElement constructor, |
| 2089 Map<Element, HInstruction> fieldValues) { | 2037 List<FunctionElement> constructors, |
| 2038 Map<Element, HInstruction> fieldValues) { |
| 2090 assert(invariant(constructor, constructor.isImplementation)); | 2039 assert(invariant(constructor, constructor.isImplementation)); |
| 2091 if (constructor.isSynthesized) { | 2040 if (constructor.isSynthesized) { |
| 2092 List<HInstruction> arguments = <HInstruction>[]; | 2041 List<HInstruction> arguments = <HInstruction>[]; |
| 2093 HInstruction compileArgument(ParameterElement parameter) { | 2042 HInstruction compileArgument(ParameterElement parameter) { |
| 2094 return localsHandler.readLocal(parameter); | 2043 return localsHandler.readLocal(parameter); |
| 2095 } | 2044 } |
| 2096 | 2045 |
| 2097 Element target = constructor.definingConstructor.implementation; | 2046 Element target = constructor.definingConstructor.implementation; |
| 2098 bool match = !target.isMalformed && | 2047 bool match = !target.isMalformed && |
| 2099 CallStructure.addForwardingElementArgumentsToList( | 2048 CallStructure.addForwardingElementArgumentsToList( |
| 2100 constructor, | 2049 constructor, |
| 2101 arguments, | 2050 arguments, |
| 2102 target, | 2051 target, |
| 2103 compileArgument, | 2052 compileArgument, |
| 2104 handleConstantForOptionalParameter); | 2053 handleConstantForOptionalParameter); |
| 2105 if (!match) { | 2054 if (!match) { |
| 2106 if (compiler.elementHasCompileTimeError(constructor)) { | 2055 if (compiler.elementHasCompileTimeError(constructor)) { |
| 2107 return; | 2056 return; |
| 2108 } | 2057 } |
| 2109 // If this fails, the selector we constructed for the call to a | 2058 // If this fails, the selector we constructed for the call to a |
| 2110 // forwarding constructor in a mixin application did not match the | 2059 // forwarding constructor in a mixin application did not match the |
| 2111 // constructor (which, for example, may happen when the libraries are | 2060 // constructor (which, for example, may happen when the libraries are |
| 2112 // not compatible for private names, see issue 20394). | 2061 // not compatible for private names, see issue 20394). |
| 2113 reporter.internalError(constructor, | 2062 reporter.internalError( |
| 2114 'forwarding constructor call does not match'); | 2063 constructor, 'forwarding constructor call does not match'); |
| 2115 } | 2064 } |
| 2116 inlineSuperOrRedirect( | 2065 inlineSuperOrRedirect( |
| 2117 target, | 2066 target, arguments, constructors, fieldValues, constructor); |
| 2118 arguments, | |
| 2119 constructors, | |
| 2120 fieldValues, | |
| 2121 constructor); | |
| 2122 return; | 2067 return; |
| 2123 } | 2068 } |
| 2124 ast.FunctionExpression functionNode = constructor.node; | 2069 ast.FunctionExpression functionNode = constructor.node; |
| 2125 | 2070 |
| 2126 bool foundSuperOrRedirect = false; | 2071 bool foundSuperOrRedirect = false; |
| 2127 if (functionNode.initializers != null) { | 2072 if (functionNode.initializers != null) { |
| 2128 Link<ast.Node> initializers = functionNode.initializers.nodes; | 2073 Link<ast.Node> initializers = functionNode.initializers.nodes; |
| 2129 for (Link<ast.Node> link = initializers; !link.isEmpty; link = link.tail)
{ | 2074 for (Link<ast.Node> link = initializers; |
| 2075 !link.isEmpty; |
| 2076 link = link.tail) { |
| 2130 assert(link.head is ast.Send); | 2077 assert(link.head is ast.Send); |
| 2131 if (link.head is !ast.SendSet) { | 2078 if (link.head is! ast.SendSet) { |
| 2132 // A super initializer or constructor redirection. | 2079 // A super initializer or constructor redirection. |
| 2133 foundSuperOrRedirect = true; | 2080 foundSuperOrRedirect = true; |
| 2134 ast.Send call = link.head; | 2081 ast.Send call = link.head; |
| 2135 assert(ast.Initializers.isSuperConstructorCall(call) || | 2082 assert(ast.Initializers.isSuperConstructorCall(call) || |
| 2136 ast.Initializers.isConstructorRedirect(call)); | 2083 ast.Initializers.isConstructorRedirect(call)); |
| 2137 FunctionElement target = elements[call].implementation; | 2084 FunctionElement target = elements[call].implementation; |
| 2138 CallStructure callStructure = | 2085 CallStructure callStructure = |
| 2139 elements.getSelector(call).callStructure; | 2086 elements.getSelector(call).callStructure; |
| 2140 Link<ast.Node> arguments = call.arguments; | 2087 Link<ast.Node> arguments = call.arguments; |
| 2141 List<HInstruction> compiledArguments; | 2088 List<HInstruction> compiledArguments; |
| 2142 inlinedFrom(constructor, () { | 2089 inlinedFrom(constructor, () { |
| 2143 compiledArguments = | 2090 compiledArguments = |
| 2144 makeStaticArgumentList(callStructure, arguments, target); | 2091 makeStaticArgumentList(callStructure, arguments, target); |
| 2145 }); | 2092 }); |
| 2146 inlineSuperOrRedirect(target, | 2093 inlineSuperOrRedirect(target, compiledArguments, constructors, |
| 2147 compiledArguments, | 2094 fieldValues, constructor); |
| 2148 constructors, | |
| 2149 fieldValues, | |
| 2150 constructor); | |
| 2151 } else { | 2095 } else { |
| 2152 // A field initializer. | 2096 // A field initializer. |
| 2153 ast.SendSet init = link.head; | 2097 ast.SendSet init = link.head; |
| 2154 Link<ast.Node> arguments = init.arguments; | 2098 Link<ast.Node> arguments = init.arguments; |
| 2155 assert(!arguments.isEmpty && arguments.tail.isEmpty); | 2099 assert(!arguments.isEmpty && arguments.tail.isEmpty); |
| 2156 inlinedFrom(constructor, () { | 2100 inlinedFrom(constructor, () { |
| 2157 visit(arguments.head); | 2101 visit(arguments.head); |
| 2158 }); | 2102 }); |
| 2159 fieldValues[elements[init]] = pop(); | 2103 fieldValues[elements[init]] = pop(); |
| 2160 } | 2104 } |
| 2161 } | 2105 } |
| 2162 } | 2106 } |
| 2163 | 2107 |
| 2164 if (!foundSuperOrRedirect) { | 2108 if (!foundSuperOrRedirect) { |
| 2165 // No super initializer found. Try to find the default constructor if | 2109 // No super initializer found. Try to find the default constructor if |
| 2166 // the class is not Object. | 2110 // the class is not Object. |
| 2167 ClassElement enclosingClass = constructor.enclosingClass; | 2111 ClassElement enclosingClass = constructor.enclosingClass; |
| 2168 ClassElement superClass = enclosingClass.superclass; | 2112 ClassElement superClass = enclosingClass.superclass; |
| 2169 if (!enclosingClass.isObject) { | 2113 if (!enclosingClass.isObject) { |
| 2170 assert(superClass != null); | 2114 assert(superClass != null); |
| 2171 assert(superClass.isResolved); | 2115 assert(superClass.isResolved); |
| 2172 // TODO(johnniwinther): Should we find injected constructors as well? | 2116 // TODO(johnniwinther): Should we find injected constructors as well? |
| 2173 FunctionElement target = superClass.lookupDefaultConstructor(); | 2117 FunctionElement target = superClass.lookupDefaultConstructor(); |
| 2174 if (target == null) { | 2118 if (target == null) { |
| 2175 reporter.internalError(superClass, | 2119 reporter.internalError( |
| 2176 "No default constructor available."); | 2120 superClass, "No default constructor available."); |
| 2177 } | 2121 } |
| 2178 List<HInstruction> arguments = | 2122 List<HInstruction> arguments = CallStructure.NO_ARGS.makeArgumentsList( |
| 2179 CallStructure.NO_ARGS.makeArgumentsList( | 2123 const Link<ast.Node>(), |
| 2180 const Link<ast.Node>(), | 2124 target.implementation, |
| 2181 target.implementation, | 2125 null, |
| 2182 null, | 2126 handleConstantForOptionalParameter); |
| 2183 handleConstantForOptionalParameter); | 2127 inlineSuperOrRedirect( |
| 2184 inlineSuperOrRedirect(target, | 2128 target, arguments, constructors, fieldValues, constructor); |
| 2185 arguments, | |
| 2186 constructors, | |
| 2187 fieldValues, | |
| 2188 constructor); | |
| 2189 } | 2129 } |
| 2190 } | 2130 } |
| 2191 } | 2131 } |
| 2192 | 2132 |
| 2193 /** | 2133 /** |
| 2194 * Run through the fields of [cls] and add their potential | 2134 * Run through the fields of [cls] and add their potential |
| 2195 * initializers. | 2135 * initializers. |
| 2196 * | 2136 * |
| 2197 * Invariant: [classElement] must be an implementation element. | 2137 * Invariant: [classElement] must be an implementation element. |
| 2198 */ | 2138 */ |
| 2199 void buildFieldInitializers(ClassElement classElement, | 2139 void buildFieldInitializers( |
| 2200 Map<Element, HInstruction> fieldValues) { | 2140 ClassElement classElement, Map<Element, HInstruction> fieldValues) { |
| 2201 assert(invariant(classElement, classElement.isImplementation)); | 2141 assert(invariant(classElement, classElement.isImplementation)); |
| 2202 classElement.forEachInstanceField( | 2142 classElement.forEachInstanceField( |
| 2203 (ClassElement enclosingClass, VariableElement member) { | 2143 (ClassElement enclosingClass, VariableElement member) { |
| 2204 if (compiler.elementHasCompileTimeError(member)) return; | 2144 if (compiler.elementHasCompileTimeError(member)) return; |
| 2205 reporter.withCurrentElement(member, () { | 2145 reporter.withCurrentElement(member, () { |
| 2206 TreeElements definitions = member.treeElements; | 2146 TreeElements definitions = member.treeElements; |
| 2207 ast.Node node = member.node; | 2147 ast.Node node = member.node; |
| 2208 ast.Expression initializer = member.initializer; | 2148 ast.Expression initializer = member.initializer; |
| 2209 if (initializer == null) { | 2149 if (initializer == null) { |
| 2210 // Unassigned fields of native classes are not initialized to | 2150 // Unassigned fields of native classes are not initialized to |
| 2211 // prevent overwriting pre-initialized native properties. | 2151 // prevent overwriting pre-initialized native properties. |
| 2212 if (!backend.isNativeOrExtendsNative(classElement)) { | 2152 if (!backend.isNativeOrExtendsNative(classElement)) { |
| 2213 fieldValues[member] = graph.addConstantNull(compiler); | 2153 fieldValues[member] = graph.addConstantNull(compiler); |
| 2214 } | 2154 } |
| 2215 } else { | 2155 } else { |
| 2216 ast.Node right = initializer; | 2156 ast.Node right = initializer; |
| 2217 TreeElements savedElements = elements; | 2157 TreeElements savedElements = elements; |
| 2218 elements = definitions; | 2158 elements = definitions; |
| 2219 // In case the field initializer uses closures, run the | 2159 // In case the field initializer uses closures, run the |
| 2220 // closure to class mapper. | 2160 // closure to class mapper. |
| 2221 compiler.closureToClassMapper.computeClosureToClassMapping( | 2161 compiler.closureToClassMapper |
| 2222 member, node, elements); | 2162 .computeClosureToClassMapping(member, node, elements); |
| 2223 inlinedFrom(member, () => right.accept(this)); | 2163 inlinedFrom(member, () => right.accept(this)); |
| 2224 elements = savedElements; | 2164 elements = savedElements; |
| 2225 fieldValues[member] = pop(); | 2165 fieldValues[member] = pop(); |
| 2226 } | 2166 } |
| 2227 }); | 2167 }); |
| 2228 }); | 2168 }); |
| 2229 } | 2169 } |
| 2230 | 2170 |
| 2231 /** | 2171 /** |
| 2232 * Build the factory function corresponding to the constructor | 2172 * Build the factory function corresponding to the constructor |
| 2233 * [functionElement]: | 2173 * [functionElement]: |
| 2234 * - Initialize fields with the values of the field initializers of the | 2174 * - Initialize fields with the values of the field initializers of the |
| 2235 * current constructor and super constructors or constructors redirected | 2175 * current constructor and super constructors or constructors redirected |
| 2236 * to, starting from the current constructor. | 2176 * to, starting from the current constructor. |
| 2237 * - Call the constructor bodies, starting from the constructor(s) in the | 2177 * - Call the constructor bodies, starting from the constructor(s) in the |
| 2238 * super class(es). | 2178 * super class(es). |
| 2239 */ | 2179 */ |
| 2240 HGraph buildFactory(ConstructorElement functionElement) { | 2180 HGraph buildFactory(ConstructorElement functionElement) { |
| 2241 functionElement = functionElement.implementation; | 2181 functionElement = functionElement.implementation; |
| 2242 ClassElement classElement = | 2182 ClassElement classElement = functionElement.enclosingClass.implementation; |
| 2243 functionElement.enclosingClass.implementation; | |
| 2244 bool isNativeUpgradeFactory = | 2183 bool isNativeUpgradeFactory = |
| 2245 backend.isNativeOrExtendsNative(classElement) | 2184 backend.isNativeOrExtendsNative(classElement) && |
| 2246 && !backend.isJsInterop(classElement); | 2185 !backend.isJsInterop(classElement); |
| 2247 ast.FunctionExpression function = functionElement.node; | 2186 ast.FunctionExpression function = functionElement.node; |
| 2248 // Note that constructors (like any other static function) do not need | 2187 // Note that constructors (like any other static function) do not need |
| 2249 // to deal with optional arguments. It is the callers job to provide all | 2188 // to deal with optional arguments. It is the callers job to provide all |
| 2250 // arguments as if they were positional. | 2189 // arguments as if they were positional. |
| 2251 | 2190 |
| 2252 if (inliningStack.isEmpty) { | 2191 if (inliningStack.isEmpty) { |
| 2253 // The initializer list could contain closures. | 2192 // The initializer list could contain closures. |
| 2254 openFunction(functionElement, function); | 2193 openFunction(functionElement, function); |
| 2255 } | 2194 } |
| 2256 | 2195 |
| 2257 Map<Element, HInstruction> fieldValues = new Map<Element, HInstruction>(); | 2196 Map<Element, HInstruction> fieldValues = new Map<Element, HInstruction>(); |
| 2258 | 2197 |
| 2259 // Compile the possible initialization code for local fields and | 2198 // Compile the possible initialization code for local fields and |
| 2260 // super fields, unless this is a redirecting constructor, in which case | 2199 // super fields, unless this is a redirecting constructor, in which case |
| 2261 // the effective target will initialize these. | 2200 // the effective target will initialize these. |
| 2262 if (!functionElement.isRedirectingGenerative) { | 2201 if (!functionElement.isRedirectingGenerative) { |
| 2263 buildFieldInitializers(classElement, fieldValues); | 2202 buildFieldInitializers(classElement, fieldValues); |
| 2264 } | 2203 } |
| 2265 | 2204 |
| 2266 // Compile field-parameters such as [:this.x:]. | 2205 // Compile field-parameters such as [:this.x:]. |
| 2267 FunctionSignature params = functionElement.functionSignature; | 2206 FunctionSignature params = functionElement.functionSignature; |
| 2268 params.orderedForEachParameter((ParameterElement parameter) { | 2207 params.orderedForEachParameter((ParameterElement parameter) { |
| 2269 if (parameter.isInitializingFormal) { | 2208 if (parameter.isInitializingFormal) { |
| 2270 // If the [element] is a field-parameter then | 2209 // If the [element] is a field-parameter then |
| 2271 // initialize the field element with its value. | 2210 // initialize the field element with its value. |
| 2272 InitializingFormalElement fieldParameter = parameter; | 2211 InitializingFormalElement fieldParameter = parameter; |
| 2273 HInstruction parameterValue = | 2212 HInstruction parameterValue = localsHandler.readLocal(fieldParameter); |
| 2274 localsHandler.readLocal(fieldParameter); | |
| 2275 fieldValues[fieldParameter.fieldElement] = parameterValue; | 2213 fieldValues[fieldParameter.fieldElement] = parameterValue; |
| 2276 } | 2214 } |
| 2277 }); | 2215 }); |
| 2278 | 2216 |
| 2279 // Analyze the constructor and all referenced constructors and collect | 2217 // Analyze the constructor and all referenced constructors and collect |
| 2280 // initializers and constructor bodies. | 2218 // initializers and constructor bodies. |
| 2281 List<FunctionElement> constructors = <FunctionElement>[functionElement]; | 2219 List<FunctionElement> constructors = <FunctionElement>[functionElement]; |
| 2282 buildInitializers(functionElement, constructors, fieldValues); | 2220 buildInitializers(functionElement, constructors, fieldValues); |
| 2283 | 2221 |
| 2284 // Call the JavaScript constructor with the fields as argument. | 2222 // Call the JavaScript constructor with the fields as argument. |
| 2285 List<HInstruction> constructorArguments = <HInstruction>[]; | 2223 List<HInstruction> constructorArguments = <HInstruction>[]; |
| 2286 List<Element> fields = <Element>[]; | 2224 List<Element> fields = <Element>[]; |
| 2287 | 2225 |
| 2288 classElement.forEachInstanceField( | 2226 classElement.forEachInstanceField( |
| 2289 (ClassElement enclosingClass, VariableElement member) { | 2227 (ClassElement enclosingClass, VariableElement member) { |
| 2290 HInstruction value = fieldValues[member]; | 2228 HInstruction value = fieldValues[member]; |
| 2291 if (value == null) { | 2229 if (value == null) { |
| 2292 // Uninitialized native fields are pre-initialized by the native | 2230 // Uninitialized native fields are pre-initialized by the native |
| 2293 // implementation. | 2231 // implementation. |
| 2294 assert(invariant( | 2232 assert(invariant( |
| 2295 member, isNativeUpgradeFactory || compiler.compilationFailed)); | 2233 member, isNativeUpgradeFactory || compiler.compilationFailed)); |
| 2296 } else { | 2234 } else { |
| 2297 fields.add(member); | 2235 fields.add(member); |
| 2298 DartType type = localsHandler.substInContext(member.type); | 2236 DartType type = localsHandler.substInContext(member.type); |
| 2299 constructorArguments.add(potentiallyCheckOrTrustType(value, type)); | 2237 constructorArguments.add(potentiallyCheckOrTrustType(value, type)); |
| 2300 } | 2238 } |
| 2301 }, | 2239 }, includeSuperAndInjectedMembers: true); |
| 2302 includeSuperAndInjectedMembers: true); | |
| 2303 | 2240 |
| 2304 InterfaceType type = classElement.thisType; | 2241 InterfaceType type = classElement.thisType; |
| 2305 TypeMask ssaType = | 2242 TypeMask ssaType = |
| 2306 new TypeMask.nonNullExact(classElement.declaration, compiler.world); | 2243 new TypeMask.nonNullExact(classElement.declaration, compiler.world); |
| 2307 List<DartType> instantiatedTypes; | 2244 List<DartType> instantiatedTypes; |
| 2308 addInlinedInstantiation(type); | 2245 addInlinedInstantiation(type); |
| 2309 if (!currentInlinedInstantiations.isEmpty) { | 2246 if (!currentInlinedInstantiations.isEmpty) { |
| 2310 instantiatedTypes = new List<DartType>.from(currentInlinedInstantiations); | 2247 instantiatedTypes = new List<DartType>.from(currentInlinedInstantiations); |
| 2311 } | 2248 } |
| 2312 | 2249 |
| 2313 HInstruction newObject; | 2250 HInstruction newObject; |
| 2314 if (!isNativeUpgradeFactory) { | 2251 if (!isNativeUpgradeFactory) { |
| 2315 newObject = new HForeignNew(classElement, | 2252 newObject = new HForeignNew( |
| 2316 ssaType, | 2253 classElement, ssaType, constructorArguments, instantiatedTypes); |
| 2317 constructorArguments, | |
| 2318 instantiatedTypes); | |
| 2319 if (function != null) { | 2254 if (function != null) { |
| 2320 // TODO(johnniwinther): Provide source information for creation | 2255 // TODO(johnniwinther): Provide source information for creation |
| 2321 // through synthetic constructors. | 2256 // through synthetic constructors. |
| 2322 newObject.sourceInformation = | 2257 newObject.sourceInformation = |
| 2323 sourceInformationBuilder.buildCreate(function); | 2258 sourceInformationBuilder.buildCreate(function); |
| 2324 } | 2259 } |
| 2325 add(newObject); | 2260 add(newObject); |
| 2326 } else { | 2261 } else { |
| 2327 // Bulk assign to the initialized fields. | 2262 // Bulk assign to the initialized fields. |
| 2328 newObject = graph.explicitReceiverParameter; | 2263 newObject = graph.explicitReceiverParameter; |
| 2329 // Null guard ensures an error if we are being called from an explicit | 2264 // Null guard ensures an error if we are being called from an explicit |
| 2330 // 'new' of the constructor instead of via an upgrade. It is optimized out | 2265 // 'new' of the constructor instead of via an upgrade. It is optimized out |
| 2331 // if there are field initializers. | 2266 // if there are field initializers. |
| 2332 add(new HFieldGet( | 2267 add(new HFieldGet(null, newObject, backend.dynamicType, |
| 2333 null, newObject, backend.dynamicType, isAssignable: false)); | 2268 isAssignable: false)); |
| 2334 for (int i = 0; i < fields.length; i++) { | 2269 for (int i = 0; i < fields.length; i++) { |
| 2335 add(new HFieldSet(fields[i], newObject, constructorArguments[i])); | 2270 add(new HFieldSet(fields[i], newObject, constructorArguments[i])); |
| 2336 } | 2271 } |
| 2337 } | 2272 } |
| 2338 removeInlinedInstantiation(type); | 2273 removeInlinedInstantiation(type); |
| 2339 // Create the runtime type information, if needed. | 2274 // Create the runtime type information, if needed. |
| 2340 if (backend.classNeedsRti(classElement)) { | 2275 if (backend.classNeedsRti(classElement)) { |
| 2341 // Read the values of the type arguments and create a list to set on the | 2276 // Read the values of the type arguments and create a list to set on the |
| 2342 // newly create object. We can identify the case where the new list | 2277 // newly create object. We can identify the case where the new list |
| 2343 // would be of the form: | 2278 // would be of the form: |
| 2344 // [getTypeArgumentByIndex(this, 0), .., getTypeArgumentByIndex(this, k)] | 2279 // [getTypeArgumentByIndex(this, 0), .., getTypeArgumentByIndex(this, k)] |
| 2345 // and k is the number of type arguments of this. If this is the case, | 2280 // and k is the number of type arguments of this. If this is the case, |
| 2346 // we can simply copy the list from this. | 2281 // we can simply copy the list from this. |
| 2347 | 2282 |
| 2348 // These locals are modified by [isIndexedTypeArgumentGet]. | 2283 // These locals are modified by [isIndexedTypeArgumentGet]. |
| 2349 HThis source; // The source of the type arguments. | 2284 HThis source; // The source of the type arguments. |
| 2350 bool allIndexed = true; | 2285 bool allIndexed = true; |
| 2351 int expectedIndex = 0; | 2286 int expectedIndex = 0; |
| 2352 ClassElement contextClass; // The class of `this`. | 2287 ClassElement contextClass; // The class of `this`. |
| 2353 int remainingTypeVariables; // The number of 'remaining type variables' | 2288 int remainingTypeVariables; // The number of 'remaining type variables' |
| 2354 // of `this`. | 2289 // of `this`. |
| 2355 | 2290 |
| 2356 /// Helper to identify instructions that read a type variable without | 2291 /// Helper to identify instructions that read a type variable without |
| 2357 /// substitution (that is, directly use the index). These instructions | 2292 /// substitution (that is, directly use the index). These instructions |
| 2358 /// are of the form: | 2293 /// are of the form: |
| 2359 /// HInvokeStatic(getTypeArgumentByIndex, this, index) | 2294 /// HInvokeStatic(getTypeArgumentByIndex, this, index) |
| 2360 /// | 2295 /// |
| 2361 /// Return `true` if [instruction] is of that form and the index is the | 2296 /// Return `true` if [instruction] is of that form and the index is the |
| 2362 /// next index in the sequence (held in [expectedIndex]). | 2297 /// next index in the sequence (held in [expectedIndex]). |
| 2363 bool isIndexedTypeArgumentGet(HInstruction instruction) { | 2298 bool isIndexedTypeArgumentGet(HInstruction instruction) { |
| 2364 if (instruction is! HInvokeStatic) return false; | 2299 if (instruction is! HInvokeStatic) return false; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 2386 // a copy. Otherwise remove one argument. | 2321 // a copy. Otherwise remove one argument. |
| 2387 if (remainingTypeVariables == 0) return false; | 2322 if (remainingTypeVariables == 0) return false; |
| 2388 remainingTypeVariables--; | 2323 remainingTypeVariables--; |
| 2389 // Check that the index is the one we expect. | 2324 // Check that the index is the one we expect. |
| 2390 IntConstantValue constant = index.constant; | 2325 IntConstantValue constant = index.constant; |
| 2391 return constant.primitiveValue == expectedIndex++; | 2326 return constant.primitiveValue == expectedIndex++; |
| 2392 } | 2327 } |
| 2393 | 2328 |
| 2394 List<HInstruction> typeArguments = <HInstruction>[]; | 2329 List<HInstruction> typeArguments = <HInstruction>[]; |
| 2395 classElement.typeVariables.forEach((TypeVariableType typeVariable) { | 2330 classElement.typeVariables.forEach((TypeVariableType typeVariable) { |
| 2396 HInstruction argument = localsHandler.readLocal( | 2331 HInstruction argument = localsHandler |
| 2397 localsHandler.getTypeVariableAsLocal(typeVariable)); | 2332 .readLocal(localsHandler.getTypeVariableAsLocal(typeVariable)); |
| 2398 if (allIndexed && !isIndexedTypeArgumentGet(argument)) { | 2333 if (allIndexed && !isIndexedTypeArgumentGet(argument)) { |
| 2399 allIndexed = false; | 2334 allIndexed = false; |
| 2400 } | 2335 } |
| 2401 typeArguments.add(argument); | 2336 typeArguments.add(argument); |
| 2402 }); | 2337 }); |
| 2403 | 2338 |
| 2404 if (source != null && allIndexed && remainingTypeVariables == 0) { | 2339 if (source != null && allIndexed && remainingTypeVariables == 0) { |
| 2405 copyRuntimeTypeInfo(source, newObject); | 2340 copyRuntimeTypeInfo(source, newObject); |
| 2406 } else { | 2341 } else { |
| 2407 newObject = | 2342 newObject = |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2451 } | 2386 } |
| 2452 | 2387 |
| 2453 // Type variables arguments must come after the box (if there is one). | 2388 // Type variables arguments must come after the box (if there is one). |
| 2454 ClassElement currentClass = constructor.enclosingClass; | 2389 ClassElement currentClass = constructor.enclosingClass; |
| 2455 if (backend.classNeedsRti(currentClass)) { | 2390 if (backend.classNeedsRti(currentClass)) { |
| 2456 // If [currentClass] needs RTI, we add the type variables as | 2391 // If [currentClass] needs RTI, we add the type variables as |
| 2457 // parameters of the generative constructor body. | 2392 // parameters of the generative constructor body. |
| 2458 currentClass.typeVariables.forEach((TypeVariableType argument) { | 2393 currentClass.typeVariables.forEach((TypeVariableType argument) { |
| 2459 // TODO(johnniwinther): Substitute [argument] with | 2394 // TODO(johnniwinther): Substitute [argument] with |
| 2460 // `localsHandler.substInContext(argument)`. | 2395 // `localsHandler.substInContext(argument)`. |
| 2461 bodyCallInputs.add(localsHandler.readLocal( | 2396 bodyCallInputs.add(localsHandler |
| 2462 localsHandler.getTypeVariableAsLocal(argument))); | 2397 .readLocal(localsHandler.getTypeVariableAsLocal(argument))); |
| 2463 }); | 2398 }); |
| 2464 } | 2399 } |
| 2465 | 2400 |
| 2466 if (!isNativeUpgradeFactory && // TODO(13836): Fix inlining. | 2401 if (!isNativeUpgradeFactory && // TODO(13836): Fix inlining. |
| 2467 tryInlineMethod(body, null, null, bodyCallInputs, function)) { | 2402 tryInlineMethod(body, null, null, bodyCallInputs, function)) { |
| 2468 pop(); | 2403 pop(); |
| 2469 } else { | 2404 } else { |
| 2470 HInvokeConstructorBody invoke = new HInvokeConstructorBody( | 2405 HInvokeConstructorBody invoke = new HInvokeConstructorBody( |
| 2471 body.declaration, bodyCallInputs, backend.nonNullType); | 2406 body.declaration, bodyCallInputs, backend.nonNullType); |
| 2472 invoke.sideEffects = | 2407 invoke.sideEffects = |
| (...skipping 23 matching lines...) Expand all Loading... |
| 2496 | 2431 |
| 2497 localsHandler.startFunction(element, node); | 2432 localsHandler.startFunction(element, node); |
| 2498 close(new HGoto()).addSuccessor(block); | 2433 close(new HGoto()).addSuccessor(block); |
| 2499 | 2434 |
| 2500 open(block); | 2435 open(block); |
| 2501 | 2436 |
| 2502 // Add the type parameters of the class as parameters of this method. This | 2437 // Add the type parameters of the class as parameters of this method. This |
| 2503 // must be done before adding the normal parameters, because their types | 2438 // must be done before adding the normal parameters, because their types |
| 2504 // may contain references to type variables. | 2439 // may contain references to type variables. |
| 2505 var enclosing = element.enclosingElement; | 2440 var enclosing = element.enclosingElement; |
| 2506 if ((element.isConstructor || element.isGenerativeConstructorBody) | 2441 if ((element.isConstructor || element.isGenerativeConstructorBody) && |
| 2507 && backend.classNeedsRti(enclosing)) { | 2442 backend.classNeedsRti(enclosing)) { |
| 2508 enclosing.typeVariables.forEach((TypeVariableType typeVariable) { | 2443 enclosing.typeVariables.forEach((TypeVariableType typeVariable) { |
| 2509 HParameterValue param = addParameter( | 2444 HParameterValue param = |
| 2510 typeVariable.element, backend.nonNullType); | 2445 addParameter(typeVariable.element, backend.nonNullType); |
| 2511 localsHandler.directLocals[ | 2446 localsHandler.directLocals[ |
| 2512 localsHandler.getTypeVariableAsLocal(typeVariable)] = param; | 2447 localsHandler.getTypeVariableAsLocal(typeVariable)] = param; |
| 2513 }); | 2448 }); |
| 2514 } | 2449 } |
| 2515 | 2450 |
| 2516 if (element is FunctionElement) { | 2451 if (element is FunctionElement) { |
| 2517 FunctionElement functionElement = element; | 2452 FunctionElement functionElement = element; |
| 2518 FunctionSignature signature = functionElement.functionSignature; | 2453 FunctionSignature signature = functionElement.functionSignature; |
| 2519 | 2454 |
| 2520 // Put the type checks in the first successor of the entry, | 2455 // Put the type checks in the first successor of the entry, |
| 2521 // because that is where the type guards will also be inserted. | 2456 // because that is where the type guards will also be inserted. |
| 2522 // This way we ensure that a type guard will dominate the type | 2457 // This way we ensure that a type guard will dominate the type |
| 2523 // check. | 2458 // check. |
| 2524 ClosureScope scopeData = | 2459 ClosureScope scopeData = localsHandler.closureData.capturingScopes[node]; |
| 2525 localsHandler.closureData.capturingScopes[node]; | |
| 2526 signature.orderedForEachParameter((ParameterElement parameterElement) { | 2460 signature.orderedForEachParameter((ParameterElement parameterElement) { |
| 2527 if (element.isGenerativeConstructorBody) { | 2461 if (element.isGenerativeConstructorBody) { |
| 2528 if (scopeData != null && | 2462 if (scopeData != null && |
| 2529 scopeData.isCapturedVariable(parameterElement)) { | 2463 scopeData.isCapturedVariable(parameterElement)) { |
| 2530 // The parameter will be a field in the box passed as the | 2464 // The parameter will be a field in the box passed as the |
| 2531 // last parameter. So no need to have it. | 2465 // last parameter. So no need to have it. |
| 2532 return; | 2466 return; |
| 2533 } | 2467 } |
| 2534 } | 2468 } |
| 2535 HInstruction newParameter = | 2469 HInstruction newParameter = |
| (...skipping 26 matching lines...) Expand all Loading... |
| 2562 | 2496 |
| 2563 insertTraceCall(element); | 2497 insertTraceCall(element); |
| 2564 insertCoverageCall(element); | 2498 insertCoverageCall(element); |
| 2565 } | 2499 } |
| 2566 | 2500 |
| 2567 insertTraceCall(Element element) { | 2501 insertTraceCall(Element element) { |
| 2568 if (JavaScriptBackend.TRACE_METHOD == 'console') { | 2502 if (JavaScriptBackend.TRACE_METHOD == 'console') { |
| 2569 if (element == backend.traceHelper) return; | 2503 if (element == backend.traceHelper) return; |
| 2570 n(e) => e == null ? '' : e.name; | 2504 n(e) => e == null ? '' : e.name; |
| 2571 String name = "${n(element.library)}:${n(element.enclosingClass)}." | 2505 String name = "${n(element.library)}:${n(element.enclosingClass)}." |
| 2572 "${n(element)}"; | 2506 "${n(element)}"; |
| 2573 HConstant nameConstant = addConstantString(name); | 2507 HConstant nameConstant = addConstantString(name); |
| 2574 add(new HInvokeStatic(backend.traceHelper, | 2508 add(new HInvokeStatic(backend.traceHelper, <HInstruction>[nameConstant], |
| 2575 <HInstruction>[nameConstant], | 2509 backend.dynamicType)); |
| 2576 backend.dynamicType)); | |
| 2577 } | 2510 } |
| 2578 } | 2511 } |
| 2579 | 2512 |
| 2580 insertCoverageCall(Element element) { | 2513 insertCoverageCall(Element element) { |
| 2581 if (JavaScriptBackend.TRACE_METHOD == 'post') { | 2514 if (JavaScriptBackend.TRACE_METHOD == 'post') { |
| 2582 if (element == backend.traceHelper) return; | 2515 if (element == backend.traceHelper) return; |
| 2583 // TODO(sigmund): create a better uuid for elements. | 2516 // TODO(sigmund): create a better uuid for elements. |
| 2584 HConstant idConstant = graph.addConstantInt(element.hashCode, compiler); | 2517 HConstant idConstant = graph.addConstantInt(element.hashCode, compiler); |
| 2585 HConstant nameConstant = addConstantString(element.name); | 2518 HConstant nameConstant = addConstantString(element.name); |
| 2586 add(new HInvokeStatic(backend.traceHelper, | 2519 add(new HInvokeStatic(backend.traceHelper, |
| 2587 <HInstruction>[idConstant, nameConstant], | 2520 <HInstruction>[idConstant, nameConstant], backend.dynamicType)); |
| 2588 backend.dynamicType)); | |
| 2589 } | 2521 } |
| 2590 } | 2522 } |
| 2591 | 2523 |
| 2592 /// Check that [type] is valid in the context of `localsHandler.contextClass`. | 2524 /// Check that [type] is valid in the context of `localsHandler.contextClass`. |
| 2593 /// This should only be called in assertions. | 2525 /// This should only be called in assertions. |
| 2594 bool assertTypeInContext(DartType type, [Spannable spannable]) { | 2526 bool assertTypeInContext(DartType type, [Spannable spannable]) { |
| 2595 return invariant(spannable == null ? CURRENT_ELEMENT_SPANNABLE : spannable, | 2527 return invariant(spannable == null ? CURRENT_ELEMENT_SPANNABLE : spannable, |
| 2596 () { | 2528 () { |
| 2597 ClassElement contextClass = Types.getClassContext(type); | 2529 ClassElement contextClass = Types.getClassContext(type); |
| 2598 return contextClass == null || | 2530 return contextClass == null || contextClass == localsHandler.contextClass; |
| 2599 contextClass == localsHandler.contextClass; | 2531 }, |
| 2600 }, | |
| 2601 message: "Type '$type' is not valid context of " | 2532 message: "Type '$type' is not valid context of " |
| 2602 "${localsHandler.contextClass}."); | 2533 "${localsHandler.contextClass}."); |
| 2603 } | 2534 } |
| 2604 | 2535 |
| 2605 /// Build a [HTypeConversion] for convertion [original] to type [type]. | 2536 /// Build a [HTypeConversion] for convertion [original] to type [type]. |
| 2606 /// | 2537 /// |
| 2607 /// Invariant: [type] must be valid in the context. | 2538 /// Invariant: [type] must be valid in the context. |
| 2608 /// See [LocalsHandler.substInContext]. | 2539 /// See [LocalsHandler.substInContext]. |
| 2609 HInstruction buildTypeConversion(HInstruction original, | 2540 HInstruction buildTypeConversion( |
| 2610 DartType type, | 2541 HInstruction original, DartType type, int kind) { |
| 2611 int kind) { | |
| 2612 if (type == null) return original; | 2542 if (type == null) return original; |
| 2613 type = type.unaliased; | 2543 type = type.unaliased; |
| 2614 assert(assertTypeInContext(type, original)); | 2544 assert(assertTypeInContext(type, original)); |
| 2615 if (type.isInterfaceType && !type.treatAsRaw) { | 2545 if (type.isInterfaceType && !type.treatAsRaw) { |
| 2616 TypeMask subtype = new TypeMask.subtype(type.element, compiler.world); | 2546 TypeMask subtype = new TypeMask.subtype(type.element, compiler.world); |
| 2617 HInstruction representations = buildTypeArgumentRepresentations(type); | 2547 HInstruction representations = buildTypeArgumentRepresentations(type); |
| 2618 add(representations); | 2548 add(representations); |
| 2619 return new HTypeConversion.withTypeRepresentation(type, kind, subtype, | 2549 return new HTypeConversion.withTypeRepresentation( |
| 2620 original, representations); | 2550 type, kind, subtype, original, representations); |
| 2621 } else if (type.isTypeVariable) { | 2551 } else if (type.isTypeVariable) { |
| 2622 TypeMask subtype = original.instructionType; | 2552 TypeMask subtype = original.instructionType; |
| 2623 HInstruction typeVariable = addTypeVariableReference(type); | 2553 HInstruction typeVariable = addTypeVariableReference(type); |
| 2624 return new HTypeConversion.withTypeRepresentation(type, kind, subtype, | 2554 return new HTypeConversion.withTypeRepresentation( |
| 2625 original, typeVariable); | 2555 type, kind, subtype, original, typeVariable); |
| 2626 } else if (type.isFunctionType) { | 2556 } else if (type.isFunctionType) { |
| 2627 String name = kind == HTypeConversion.CAST_TYPE_CHECK | 2557 String name = |
| 2628 ? '_asCheck' : '_assertCheck'; | 2558 kind == HTypeConversion.CAST_TYPE_CHECK ? '_asCheck' : '_assertCheck'; |
| 2629 | 2559 |
| 2630 List<HInstruction> arguments = | 2560 List<HInstruction> arguments = <HInstruction>[ |
| 2631 <HInstruction>[buildFunctionType(type), original]; | 2561 buildFunctionType(type), |
| 2562 original |
| 2563 ]; |
| 2632 pushInvokeDynamic( | 2564 pushInvokeDynamic( |
| 2633 null, | 2565 null, |
| 2634 new Selector.call( | 2566 new Selector.call( |
| 2635 new Name(name, helpers.jsHelperLibrary), CallStructure.ONE_ARG), | 2567 new Name(name, helpers.jsHelperLibrary), CallStructure.ONE_ARG), |
| 2636 null, | 2568 null, |
| 2637 arguments); | 2569 arguments); |
| 2638 | 2570 |
| 2639 return new HTypeConversion(type, kind, original.instructionType, pop()); | 2571 return new HTypeConversion(type, kind, original.instructionType, pop()); |
| 2640 } else { | 2572 } else { |
| 2641 return original.convertType(compiler, type, kind); | 2573 return original.convertType(compiler, type, kind); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 2659 HInstruction _checkType(HInstruction original, DartType type, int kind) { | 2591 HInstruction _checkType(HInstruction original, DartType type, int kind) { |
| 2660 assert(compiler.options.enableTypeAssertions); | 2592 assert(compiler.options.enableTypeAssertions); |
| 2661 assert(type != null); | 2593 assert(type != null); |
| 2662 type = localsHandler.substInContext(type); | 2594 type = localsHandler.substInContext(type); |
| 2663 HInstruction other = buildTypeConversion(original, type, kind); | 2595 HInstruction other = buildTypeConversion(original, type, kind); |
| 2664 registry?.registerTypeUse(new TypeUse.isCheck(type)); | 2596 registry?.registerTypeUse(new TypeUse.isCheck(type)); |
| 2665 return other; | 2597 return other; |
| 2666 } | 2598 } |
| 2667 | 2599 |
| 2668 HInstruction potentiallyCheckOrTrustType(HInstruction original, DartType type, | 2600 HInstruction potentiallyCheckOrTrustType(HInstruction original, DartType type, |
| 2669 { int kind: HTypeConversion.CHECKED_MODE_CHECK }) { | 2601 {int kind: HTypeConversion.CHECKED_MODE_CHECK}) { |
| 2670 if (type == null) return original; | 2602 if (type == null) return original; |
| 2671 HInstruction checkedOrTrusted = original; | 2603 HInstruction checkedOrTrusted = original; |
| 2672 if (compiler.options.trustTypeAnnotations) { | 2604 if (compiler.options.trustTypeAnnotations) { |
| 2673 checkedOrTrusted = _trustType(original, type); | 2605 checkedOrTrusted = _trustType(original, type); |
| 2674 } else if (compiler.options.enableTypeAssertions) { | 2606 } else if (compiler.options.enableTypeAssertions) { |
| 2675 checkedOrTrusted = _checkType(original, type, kind); | 2607 checkedOrTrusted = _checkType(original, type, kind); |
| 2676 } | 2608 } |
| 2677 if (checkedOrTrusted == original) return original; | 2609 if (checkedOrTrusted == original) return original; |
| 2678 add(checkedOrTrusted); | 2610 add(checkedOrTrusted); |
| 2679 return checkedOrTrusted; | 2611 return checkedOrTrusted; |
| 2680 } | 2612 } |
| 2681 | 2613 |
| 2682 void assertIsSubtype(ast.Node node, DartType subtype, DartType supertype, | 2614 void assertIsSubtype( |
| 2683 String message) { | 2615 ast.Node node, DartType subtype, DartType supertype, String message) { |
| 2684 HInstruction subtypeInstruction = | 2616 HInstruction subtypeInstruction = |
| 2685 analyzeTypeArgument(localsHandler.substInContext(subtype)); | 2617 analyzeTypeArgument(localsHandler.substInContext(subtype)); |
| 2686 HInstruction supertypeInstruction = | 2618 HInstruction supertypeInstruction = |
| 2687 analyzeTypeArgument(localsHandler.substInContext(supertype)); | 2619 analyzeTypeArgument(localsHandler.substInContext(supertype)); |
| 2688 HInstruction messageInstruction = | 2620 HInstruction messageInstruction = |
| 2689 graph.addConstantString(new ast.DartString.literal(message), compiler); | 2621 graph.addConstantString(new ast.DartString.literal(message), compiler); |
| 2690 Element element = helpers.assertIsSubtype; | 2622 Element element = helpers.assertIsSubtype; |
| 2691 var inputs = <HInstruction>[subtypeInstruction, supertypeInstruction, | 2623 var inputs = <HInstruction>[ |
| 2692 messageInstruction]; | 2624 subtypeInstruction, |
| 2693 HInstruction assertIsSubtype = new HInvokeStatic( | 2625 supertypeInstruction, |
| 2694 element, inputs, subtypeInstruction.instructionType); | 2626 messageInstruction |
| 2627 ]; |
| 2628 HInstruction assertIsSubtype = |
| 2629 new HInvokeStatic(element, inputs, subtypeInstruction.instructionType); |
| 2695 registry?.registerTypeVariableBoundsSubtypeCheck(subtype, supertype); | 2630 registry?.registerTypeVariableBoundsSubtypeCheck(subtype, supertype); |
| 2696 add(assertIsSubtype); | 2631 add(assertIsSubtype); |
| 2697 } | 2632 } |
| 2698 | 2633 |
| 2699 HGraph closeFunction() { | 2634 HGraph closeFunction() { |
| 2700 // TODO(kasperl): Make this goto an implicit return. | 2635 // TODO(kasperl): Make this goto an implicit return. |
| 2701 if (!isAborted()) closeAndGotoExit(new HGoto()); | 2636 if (!isAborted()) closeAndGotoExit(new HGoto()); |
| 2702 graph.finalize(); | 2637 graph.finalize(); |
| 2703 return graph; | 2638 return graph; |
| 2704 } | 2639 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2716 return stack.removeLast(); | 2651 return stack.removeLast(); |
| 2717 } | 2652 } |
| 2718 | 2653 |
| 2719 void dup() { | 2654 void dup() { |
| 2720 stack.add(stack.last); | 2655 stack.add(stack.last); |
| 2721 } | 2656 } |
| 2722 | 2657 |
| 2723 HInstruction popBoolified() { | 2658 HInstruction popBoolified() { |
| 2724 HInstruction value = pop(); | 2659 HInstruction value = pop(); |
| 2725 if (_checkOrTrustTypes) { | 2660 if (_checkOrTrustTypes) { |
| 2726 return potentiallyCheckOrTrustType( | 2661 return potentiallyCheckOrTrustType(value, compiler.coreTypes.boolType, |
| 2727 value, | |
| 2728 compiler.coreTypes.boolType, | |
| 2729 kind: HTypeConversion.BOOLEAN_CONVERSION_CHECK); | 2662 kind: HTypeConversion.BOOLEAN_CONVERSION_CHECK); |
| 2730 } | 2663 } |
| 2731 HInstruction result = new HBoolify(value, backend.boolType); | 2664 HInstruction result = new HBoolify(value, backend.boolType); |
| 2732 add(result); | 2665 add(result); |
| 2733 return result; | 2666 return result; |
| 2734 } | 2667 } |
| 2735 | 2668 |
| 2736 HInstruction attachPosition(HInstruction target, ast.Node node) { | 2669 HInstruction attachPosition(HInstruction target, ast.Node node) { |
| 2737 if (node != null) { | 2670 if (node != null) { |
| 2738 target.sourceInformation = sourceInformationBuilder.buildGeneric(node); | 2671 target.sourceInformation = sourceInformationBuilder.buildGeneric(node); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 2769 // | 2702 // |
| 2770 void buildCondition() { | 2703 void buildCondition() { |
| 2771 visit(node.condition); | 2704 visit(node.condition); |
| 2772 pushInvokeStatic(node, helpers.assertTest, [pop()]); | 2705 pushInvokeStatic(node, helpers.assertTest, [pop()]); |
| 2773 } | 2706 } |
| 2774 void fail() { | 2707 void fail() { |
| 2775 visit(node.message); | 2708 visit(node.message); |
| 2776 pushInvokeStatic(node, helpers.assertThrow, [pop()]); | 2709 pushInvokeStatic(node, helpers.assertThrow, [pop()]); |
| 2777 pop(); | 2710 pop(); |
| 2778 } | 2711 } |
| 2779 handleIf(node, | 2712 handleIf(node, visitCondition: buildCondition, visitThen: fail); |
| 2780 visitCondition: buildCondition, | |
| 2781 visitThen: fail); | |
| 2782 } | 2713 } |
| 2783 | 2714 |
| 2784 visitBlock(ast.Block node) { | 2715 visitBlock(ast.Block node) { |
| 2785 assert(!isAborted()); | 2716 assert(!isAborted()); |
| 2786 if (!isReachable) return; // This can only happen when inlining. | 2717 if (!isReachable) return; // This can only happen when inlining. |
| 2787 for (Link<ast.Node> link = node.statements.nodes; | 2718 for (Link<ast.Node> link = node.statements.nodes; |
| 2788 !link.isEmpty; | 2719 !link.isEmpty; |
| 2789 link = link.tail) { | 2720 link = link.tail) { |
| 2790 visit(link.head); | 2721 visit(link.head); |
| 2791 if (!isReachable) { | 2722 if (!isReachable) { |
| 2792 // The block has been aborted by a return or a throw. | 2723 // The block has been aborted by a return or a throw. |
| 2793 if (!stack.isEmpty) { | 2724 if (!stack.isEmpty) { |
| 2794 reporter.internalError(node, 'Non-empty instruction stack.'); | 2725 reporter.internalError(node, 'Non-empty instruction stack.'); |
| 2795 } | 2726 } |
| 2796 return; | 2727 return; |
| 2797 } | 2728 } |
| 2798 } | 2729 } |
| 2799 assert(!current.isClosed()); | 2730 assert(!current.isClosed()); |
| 2800 if (!stack.isEmpty) { | 2731 if (!stack.isEmpty) { |
| 2801 reporter.internalError(node, 'Non-empty instruction stack.'); | 2732 reporter.internalError(node, 'Non-empty instruction stack.'); |
| 2802 } | 2733 } |
| 2803 } | 2734 } |
| 2804 | 2735 |
| 2805 visitClassNode(ast.ClassNode node) { | 2736 visitClassNode(ast.ClassNode node) { |
| 2806 reporter.internalError(node, | 2737 reporter.internalError( |
| 2807 'SsaBuilder.visitClassNode should not be called.'); | 2738 node, 'SsaBuilder.visitClassNode should not be called.'); |
| 2808 } | 2739 } |
| 2809 | 2740 |
| 2810 visitThrowExpression(ast.Expression expression) { | 2741 visitThrowExpression(ast.Expression expression) { |
| 2811 bool old = inExpressionOfThrow; | 2742 bool old = inExpressionOfThrow; |
| 2812 try { | 2743 try { |
| 2813 inExpressionOfThrow = true; | 2744 inExpressionOfThrow = true; |
| 2814 visit(expression); | 2745 visit(expression); |
| 2815 } finally { | 2746 } finally { |
| 2816 inExpressionOfThrow = old; | 2747 inExpressionOfThrow = old; |
| 2817 } | 2748 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 2834 /** | 2765 /** |
| 2835 * Creates a new loop-header block. The previous [current] block | 2766 * Creates a new loop-header block. The previous [current] block |
| 2836 * is closed with an [HGoto] and replaced by the newly created block. | 2767 * is closed with an [HGoto] and replaced by the newly created block. |
| 2837 * Also notifies the locals handler that we're entering a loop. | 2768 * Also notifies the locals handler that we're entering a loop. |
| 2838 */ | 2769 */ |
| 2839 JumpHandler beginLoopHeader(ast.Node node) { | 2770 JumpHandler beginLoopHeader(ast.Node node) { |
| 2840 assert(!isAborted()); | 2771 assert(!isAborted()); |
| 2841 HBasicBlock previousBlock = close(new HGoto()); | 2772 HBasicBlock previousBlock = close(new HGoto()); |
| 2842 | 2773 |
| 2843 JumpHandler jumpHandler = createJumpHandler(node, isLoopJump: true); | 2774 JumpHandler jumpHandler = createJumpHandler(node, isLoopJump: true); |
| 2844 HBasicBlock loopEntry = graph.addNewLoopHeaderBlock( | 2775 HBasicBlock loopEntry = |
| 2845 jumpHandler.target, | 2776 graph.addNewLoopHeaderBlock(jumpHandler.target, jumpHandler.labels()); |
| 2846 jumpHandler.labels()); | |
| 2847 previousBlock.addSuccessor(loopEntry); | 2777 previousBlock.addSuccessor(loopEntry); |
| 2848 open(loopEntry); | 2778 open(loopEntry); |
| 2849 | 2779 |
| 2850 localsHandler.beginLoopHeader(loopEntry); | 2780 localsHandler.beginLoopHeader(loopEntry); |
| 2851 return jumpHandler; | 2781 return jumpHandler; |
| 2852 } | 2782 } |
| 2853 | 2783 |
| 2854 /** | 2784 /** |
| 2855 * Ends the loop: | 2785 * Ends the loop: |
| 2856 * - creates a new block and adds it as successor to the [branchExitBlock] and | 2786 * - creates a new block and adds it as successor to the [branchExitBlock] and |
| 2857 * any blocks that end in break. | 2787 * any blocks that end in break. |
| 2858 * - opens the new block (setting as [current]). | 2788 * - opens the new block (setting as [current]). |
| 2859 * - notifies the locals handler that we're exiting a loop. | 2789 * - notifies the locals handler that we're exiting a loop. |
| 2860 * [savedLocals] are the locals from the end of the loop condition. | 2790 * [savedLocals] are the locals from the end of the loop condition. |
| 2861 * [branchExitBlock] is the exit (branching) block of the condition. Generally | 2791 * [branchExitBlock] is the exit (branching) block of the condition. Generally |
| 2862 * this is not the top of the loop, since this would lead to critical edges. | 2792 * this is not the top of the loop, since this would lead to critical edges. |
| 2863 * It is null for degenerate do-while loops that have | 2793 * It is null for degenerate do-while loops that have |
| 2864 * no back edge because they abort (throw/return/break in the body and have | 2794 * no back edge because they abort (throw/return/break in the body and have |
| 2865 * no continues). | 2795 * no continues). |
| 2866 */ | 2796 */ |
| 2867 void endLoop(HBasicBlock loopEntry, | 2797 void endLoop(HBasicBlock loopEntry, HBasicBlock branchExitBlock, |
| 2868 HBasicBlock branchExitBlock, | 2798 JumpHandler jumpHandler, LocalsHandler savedLocals) { |
| 2869 JumpHandler jumpHandler, | |
| 2870 LocalsHandler savedLocals) { | |
| 2871 HBasicBlock loopExitBlock = addNewBlock(); | 2799 HBasicBlock loopExitBlock = addNewBlock(); |
| 2872 | 2800 |
| 2873 List<LocalsHandler> breakHandlers = <LocalsHandler>[]; | 2801 List<LocalsHandler> breakHandlers = <LocalsHandler>[]; |
| 2874 // Collect data for the successors and the phis at each break. | 2802 // Collect data for the successors and the phis at each break. |
| 2875 jumpHandler.forEachBreak((HBreak breakInstruction, LocalsHandler locals) { | 2803 jumpHandler.forEachBreak((HBreak breakInstruction, LocalsHandler locals) { |
| 2876 breakInstruction.block.addSuccessor(loopExitBlock); | 2804 breakInstruction.block.addSuccessor(loopExitBlock); |
| 2877 breakHandlers.add(locals); | 2805 breakHandlers.add(locals); |
| 2878 }); | 2806 }); |
| 2879 | 2807 |
| 2880 // The exit block is a successor of the loop condition if it is reached. | 2808 // The exit block is a successor of the loop condition if it is reached. |
| (...skipping 29 matching lines...) Expand all Loading... |
| 2910 } | 2838 } |
| 2911 | 2839 |
| 2912 HSubExpressionBlockInformation wrapExpressionGraph(SubExpression expression) { | 2840 HSubExpressionBlockInformation wrapExpressionGraph(SubExpression expression) { |
| 2913 if (expression == null) return null; | 2841 if (expression == null) return null; |
| 2914 return new HSubExpressionBlockInformation(expression); | 2842 return new HSubExpressionBlockInformation(expression); |
| 2915 } | 2843 } |
| 2916 | 2844 |
| 2917 // For while loops, initializer and update are null. | 2845 // For while loops, initializer and update are null. |
| 2918 // The condition function must return a boolean result. | 2846 // The condition function must return a boolean result. |
| 2919 // None of the functions must leave anything on the stack. | 2847 // None of the functions must leave anything on the stack. |
| 2920 void handleLoop(ast.Node loop, | 2848 void handleLoop(ast.Node loop, void initialize(), HInstruction condition(), |
| 2921 void initialize(), | 2849 void update(), void body()) { |
| 2922 HInstruction condition(), | |
| 2923 void update(), | |
| 2924 void body()) { | |
| 2925 // Generate: | 2850 // Generate: |
| 2926 // <initializer> | 2851 // <initializer> |
| 2927 // loop-entry: | 2852 // loop-entry: |
| 2928 // if (!<condition>) goto loop-exit; | 2853 // if (!<condition>) goto loop-exit; |
| 2929 // <body> | 2854 // <body> |
| 2930 // <updates> | 2855 // <updates> |
| 2931 // goto loop-entry; | 2856 // goto loop-entry; |
| 2932 // loop-exit: | 2857 // loop-exit: |
| 2933 | 2858 |
| 2934 localsHandler.startLoop(loop); | 2859 localsHandler.startLoop(loop); |
| 2935 | 2860 |
| 2936 // The initializer. | 2861 // The initializer. |
| 2937 SubExpression initializerGraph = null; | 2862 SubExpression initializerGraph = null; |
| 2938 HBasicBlock startBlock; | 2863 HBasicBlock startBlock; |
| 2939 if (initialize != null) { | 2864 if (initialize != null) { |
| 2940 HBasicBlock initializerBlock = openNewBlock(); | 2865 HBasicBlock initializerBlock = openNewBlock(); |
| 2941 startBlock = initializerBlock; | 2866 startBlock = initializerBlock; |
| 2942 initialize(); | 2867 initialize(); |
| 2943 assert(!isAborted()); | 2868 assert(!isAborted()); |
| 2944 initializerGraph = | 2869 initializerGraph = new SubExpression(initializerBlock, current); |
| 2945 new SubExpression(initializerBlock, current); | |
| 2946 } | 2870 } |
| 2947 | 2871 |
| 2948 loopNesting++; | 2872 loopNesting++; |
| 2949 JumpHandler jumpHandler = beginLoopHeader(loop); | 2873 JumpHandler jumpHandler = beginLoopHeader(loop); |
| 2950 HLoopInformation loopInfo = current.loopInformation; | 2874 HLoopInformation loopInfo = current.loopInformation; |
| 2951 HBasicBlock conditionBlock = current; | 2875 HBasicBlock conditionBlock = current; |
| 2952 if (startBlock == null) startBlock = conditionBlock; | 2876 if (startBlock == null) startBlock = conditionBlock; |
| 2953 | 2877 |
| 2954 HInstruction conditionInstruction = condition(); | 2878 HInstruction conditionInstruction = condition(); |
| 2955 HBasicBlock conditionEndBlock = | 2879 HBasicBlock conditionEndBlock = |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2978 | 2902 |
| 2979 bool loopIsDegenerate = !jumpHandler.hasAnyContinue() && bodyBlock == null; | 2903 bool loopIsDegenerate = !jumpHandler.hasAnyContinue() && bodyBlock == null; |
| 2980 if (!loopIsDegenerate) { | 2904 if (!loopIsDegenerate) { |
| 2981 // Update. | 2905 // Update. |
| 2982 // We create an update block, even when we are in a while loop. There the | 2906 // We create an update block, even when we are in a while loop. There the |
| 2983 // update block is the jump-target for continue statements. We could avoid | 2907 // update block is the jump-target for continue statements. We could avoid |
| 2984 // the creation if there is no continue, but for now we always create it. | 2908 // the creation if there is no continue, but for now we always create it. |
| 2985 HBasicBlock updateBlock = addNewBlock(); | 2909 HBasicBlock updateBlock = addNewBlock(); |
| 2986 | 2910 |
| 2987 List<LocalsHandler> continueHandlers = <LocalsHandler>[]; | 2911 List<LocalsHandler> continueHandlers = <LocalsHandler>[]; |
| 2988 jumpHandler.forEachContinue((HContinue instruction, | 2912 jumpHandler |
| 2989 LocalsHandler locals) { | 2913 .forEachContinue((HContinue instruction, LocalsHandler locals) { |
| 2990 instruction.block.addSuccessor(updateBlock); | 2914 instruction.block.addSuccessor(updateBlock); |
| 2991 continueHandlers.add(locals); | 2915 continueHandlers.add(locals); |
| 2992 }); | 2916 }); |
| 2993 | 2917 |
| 2994 | |
| 2995 if (bodyBlock != null) { | 2918 if (bodyBlock != null) { |
| 2996 continueHandlers.add(localsHandler); | 2919 continueHandlers.add(localsHandler); |
| 2997 bodyBlock.addSuccessor(updateBlock); | 2920 bodyBlock.addSuccessor(updateBlock); |
| 2998 } | 2921 } |
| 2999 | 2922 |
| 3000 open(updateBlock); | 2923 open(updateBlock); |
| 3001 localsHandler = | 2924 localsHandler = |
| 3002 continueHandlers[0].mergeMultiple(continueHandlers, updateBlock); | 2925 continueHandlers[0].mergeMultiple(continueHandlers, updateBlock); |
| 3003 | 2926 |
| 3004 List<LabelDefinition> labels = jumpHandler.labels(); | 2927 List<LabelDefinition> labels = jumpHandler.labels(); |
| 3005 JumpTarget target = elements.getTargetDefinition(loop); | 2928 JumpTarget target = elements.getTargetDefinition(loop); |
| 3006 if (!labels.isEmpty) { | 2929 if (!labels.isEmpty) { |
| 3007 beginBodyBlock.setBlockFlow( | 2930 beginBodyBlock.setBlockFlow( |
| 3008 new HLabeledBlockInformation( | 2931 new HLabeledBlockInformation( |
| 3009 new HSubGraphBlockInformation(bodyGraph), | 2932 new HSubGraphBlockInformation(bodyGraph), jumpHandler.labels(), |
| 3010 jumpHandler.labels(), | |
| 3011 isContinue: true), | 2933 isContinue: true), |
| 3012 updateBlock); | 2934 updateBlock); |
| 3013 } else if (target != null && target.isContinueTarget) { | 2935 } else if (target != null && target.isContinueTarget) { |
| 3014 beginBodyBlock.setBlockFlow( | 2936 beginBodyBlock.setBlockFlow( |
| 3015 new HLabeledBlockInformation.implicit( | 2937 new HLabeledBlockInformation.implicit( |
| 3016 new HSubGraphBlockInformation(bodyGraph), | 2938 new HSubGraphBlockInformation(bodyGraph), target, |
| 3017 target, | |
| 3018 isContinue: true), | 2939 isContinue: true), |
| 3019 updateBlock); | 2940 updateBlock); |
| 3020 } | 2941 } |
| 3021 | 2942 |
| 3022 localsHandler.enterLoopUpdates(loop); | 2943 localsHandler.enterLoopUpdates(loop); |
| 3023 | 2944 |
| 3024 update(); | 2945 update(); |
| 3025 | 2946 |
| 3026 HBasicBlock updateEndBlock = close(new HGoto()); | 2947 HBasicBlock updateEndBlock = close(new HGoto()); |
| 3027 // The back-edge completing the cycle. | 2948 // The back-edge completing the cycle. |
| 3028 updateEndBlock.addSuccessor(conditionBlock); | 2949 updateEndBlock.addSuccessor(conditionBlock); |
| 3029 updateGraph = new SubExpression(updateBlock, updateEndBlock); | 2950 updateGraph = new SubExpression(updateBlock, updateEndBlock); |
| 3030 | 2951 |
| 3031 // Avoid a critical edge from the condition to the loop-exit body. | 2952 // Avoid a critical edge from the condition to the loop-exit body. |
| 3032 HBasicBlock conditionExitBlock = addNewBlock(); | 2953 HBasicBlock conditionExitBlock = addNewBlock(); |
| 3033 open(conditionExitBlock); | 2954 open(conditionExitBlock); |
| 3034 close(new HGoto()); | 2955 close(new HGoto()); |
| 3035 conditionEndBlock.addSuccessor(conditionExitBlock); | 2956 conditionEndBlock.addSuccessor(conditionExitBlock); |
| 3036 | 2957 |
| 3037 endLoop(conditionBlock, conditionExitBlock, jumpHandler, savedLocals); | 2958 endLoop(conditionBlock, conditionExitBlock, jumpHandler, savedLocals); |
| 3038 | 2959 |
| 3039 conditionBlock.postProcessLoopHeader(); | 2960 conditionBlock.postProcessLoopHeader(); |
| 3040 HLoopBlockInformation info = | 2961 HLoopBlockInformation info = new HLoopBlockInformation( |
| 3041 new HLoopBlockInformation( | 2962 _loopKind(loop), |
| 3042 _loopKind(loop), | 2963 wrapExpressionGraph(initializerGraph), |
| 3043 wrapExpressionGraph(initializerGraph), | 2964 wrapExpressionGraph(conditionExpression), |
| 3044 wrapExpressionGraph(conditionExpression), | 2965 wrapStatementGraph(bodyGraph), |
| 3045 wrapStatementGraph(bodyGraph), | 2966 wrapExpressionGraph(updateGraph), |
| 3046 wrapExpressionGraph(updateGraph), | 2967 conditionBlock.loopInformation.target, |
| 3047 conditionBlock.loopInformation.target, | 2968 conditionBlock.loopInformation.labels, |
| 3048 conditionBlock.loopInformation.labels, | 2969 sourceInformationBuilder.buildLoop(loop)); |
| 3049 sourceInformationBuilder.buildLoop(loop)); | |
| 3050 | 2970 |
| 3051 startBlock.setBlockFlow(info, current); | 2971 startBlock.setBlockFlow(info, current); |
| 3052 loopInfo.loopBlockInformation = info; | 2972 loopInfo.loopBlockInformation = info; |
| 3053 } else { | 2973 } else { |
| 3054 // The body of the for/while loop always aborts, so there is no back edge. | 2974 // The body of the for/while loop always aborts, so there is no back edge. |
| 3055 // We turn the code into: | 2975 // We turn the code into: |
| 3056 // if (condition) { | 2976 // if (condition) { |
| 3057 // body; | 2977 // body; |
| 3058 // } else { | 2978 // } else { |
| 3059 // // We always create an empty else block to avoid critical edges. | 2979 // // We always create an empty else block to avoid critical edges. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 3071 SubGraph elseGraph = new SubGraph(elseBlock, elseBlock); | 2991 SubGraph elseGraph = new SubGraph(elseBlock, elseBlock); |
| 3072 // Remove the loop information attached to the header. | 2992 // Remove the loop information attached to the header. |
| 3073 conditionBlock.loopInformation = null; | 2993 conditionBlock.loopInformation = null; |
| 3074 | 2994 |
| 3075 // Remove the [HLoopBranch] instruction and replace it with | 2995 // Remove the [HLoopBranch] instruction and replace it with |
| 3076 // [HIf]. | 2996 // [HIf]. |
| 3077 HInstruction condition = conditionEndBlock.last.inputs[0]; | 2997 HInstruction condition = conditionEndBlock.last.inputs[0]; |
| 3078 conditionEndBlock.addAtExit(new HIf(condition)); | 2998 conditionEndBlock.addAtExit(new HIf(condition)); |
| 3079 conditionEndBlock.addSuccessor(elseBlock); | 2999 conditionEndBlock.addSuccessor(elseBlock); |
| 3080 conditionEndBlock.remove(conditionEndBlock.last); | 3000 conditionEndBlock.remove(conditionEndBlock.last); |
| 3081 HIfBlockInformation info = | 3001 HIfBlockInformation info = new HIfBlockInformation( |
| 3082 new HIfBlockInformation( | 3002 wrapExpressionGraph(conditionExpression), |
| 3083 wrapExpressionGraph(conditionExpression), | 3003 wrapStatementGraph(bodyGraph), |
| 3084 wrapStatementGraph(bodyGraph), | 3004 wrapStatementGraph(elseGraph)); |
| 3085 wrapStatementGraph(elseGraph)); | |
| 3086 | 3005 |
| 3087 conditionEndBlock.setBlockFlow(info, current); | 3006 conditionEndBlock.setBlockFlow(info, current); |
| 3088 HIf ifBlock = conditionEndBlock.last; | 3007 HIf ifBlock = conditionEndBlock.last; |
| 3089 ifBlock.blockInformation = conditionEndBlock.blockFlow; | 3008 ifBlock.blockInformation = conditionEndBlock.blockFlow; |
| 3090 | 3009 |
| 3091 // If the body has any break, attach a synthesized label to the | 3010 // If the body has any break, attach a synthesized label to the |
| 3092 // if block. | 3011 // if block. |
| 3093 if (jumpHandler.hasAnyBreak()) { | 3012 if (jumpHandler.hasAnyBreak()) { |
| 3094 JumpTarget target = elements.getTargetDefinition(loop); | 3013 JumpTarget target = elements.getTargetDefinition(loop); |
| 3095 LabelDefinition label = target.addLabel(null, 'loop'); | 3014 LabelDefinition label = target.addLabel(null, 'loop'); |
| 3096 label.setBreakTarget(); | 3015 label.setBreakTarget(); |
| 3097 SubGraph labelGraph = new SubGraph(conditionBlock, current); | 3016 SubGraph labelGraph = new SubGraph(conditionBlock, current); |
| 3098 HLabeledBlockInformation labelInfo = new HLabeledBlockInformation( | 3017 HLabeledBlockInformation labelInfo = new HLabeledBlockInformation( |
| 3099 new HSubGraphBlockInformation(labelGraph), | 3018 new HSubGraphBlockInformation(labelGraph), |
| 3100 <LabelDefinition>[label]); | 3019 <LabelDefinition>[label]); |
| 3101 | 3020 |
| 3102 conditionBlock.setBlockFlow(labelInfo, current); | 3021 conditionBlock.setBlockFlow(labelInfo, current); |
| 3103 | 3022 |
| 3104 jumpHandler.forEachBreak((HBreak breakInstruction, _) { | 3023 jumpHandler.forEachBreak((HBreak breakInstruction, _) { |
| 3105 HBasicBlock block = breakInstruction.block; | 3024 HBasicBlock block = breakInstruction.block; |
| 3106 block.addAtExit(new HBreak.toLabel(label)); | 3025 block.addAtExit(new HBreak.toLabel(label)); |
| 3107 block.remove(breakInstruction); | 3026 block.remove(breakInstruction); |
| 3108 }); | 3027 }); |
| 3109 } | 3028 } |
| 3110 } | 3029 } |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3144 } | 3063 } |
| 3145 handleLoop(node, buildInitializer, buildCondition, buildUpdate, buildBody); | 3064 handleLoop(node, buildInitializer, buildCondition, buildUpdate, buildBody); |
| 3146 } | 3065 } |
| 3147 | 3066 |
| 3148 visitWhile(ast.While node) { | 3067 visitWhile(ast.While node) { |
| 3149 assert(isReachable); | 3068 assert(isReachable); |
| 3150 HInstruction buildCondition() { | 3069 HInstruction buildCondition() { |
| 3151 visit(node.condition); | 3070 visit(node.condition); |
| 3152 return popBoolified(); | 3071 return popBoolified(); |
| 3153 } | 3072 } |
| 3154 handleLoop(node, | 3073 handleLoop(node, () {}, buildCondition, () {}, () { |
| 3155 () {}, | 3074 visit(node.body); |
| 3156 buildCondition, | 3075 }); |
| 3157 () {}, | |
| 3158 () { visit(node.body); }); | |
| 3159 } | 3076 } |
| 3160 | 3077 |
| 3161 visitDoWhile(ast.DoWhile node) { | 3078 visitDoWhile(ast.DoWhile node) { |
| 3162 assert(isReachable); | 3079 assert(isReachable); |
| 3163 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); | 3080 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); |
| 3164 localsHandler.startLoop(node); | 3081 localsHandler.startLoop(node); |
| 3165 loopNesting++; | 3082 loopNesting++; |
| 3166 JumpHandler jumpHandler = beginLoopHeader(node); | 3083 JumpHandler jumpHandler = beginLoopHeader(node); |
| 3167 HLoopInformation loopInfo = current.loopInformation; | 3084 HLoopInformation loopInfo = current.loopInformation; |
| 3168 HBasicBlock loopEntryBlock = current; | 3085 HBasicBlock loopEntryBlock = current; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 3192 isAbortingBody = true; | 3109 isAbortingBody = true; |
| 3193 bodyExitBlock = lastOpenedBlock; | 3110 bodyExitBlock = lastOpenedBlock; |
| 3194 } | 3111 } |
| 3195 | 3112 |
| 3196 SubExpression conditionExpression; | 3113 SubExpression conditionExpression; |
| 3197 bool loopIsDegenerate = isAbortingBody && !hasContinues; | 3114 bool loopIsDegenerate = isAbortingBody && !hasContinues; |
| 3198 if (!loopIsDegenerate) { | 3115 if (!loopIsDegenerate) { |
| 3199 HBasicBlock conditionBlock = addNewBlock(); | 3116 HBasicBlock conditionBlock = addNewBlock(); |
| 3200 | 3117 |
| 3201 List<LocalsHandler> continueHandlers = <LocalsHandler>[]; | 3118 List<LocalsHandler> continueHandlers = <LocalsHandler>[]; |
| 3202 jumpHandler.forEachContinue((HContinue instruction, | 3119 jumpHandler |
| 3203 LocalsHandler locals) { | 3120 .forEachContinue((HContinue instruction, LocalsHandler locals) { |
| 3204 instruction.block.addSuccessor(conditionBlock); | 3121 instruction.block.addSuccessor(conditionBlock); |
| 3205 continueHandlers.add(locals); | 3122 continueHandlers.add(locals); |
| 3206 }); | 3123 }); |
| 3207 | 3124 |
| 3208 if (!isAbortingBody) { | 3125 if (!isAbortingBody) { |
| 3209 bodyExitBlock.addSuccessor(conditionBlock); | 3126 bodyExitBlock.addSuccessor(conditionBlock); |
| 3210 } | 3127 } |
| 3211 | 3128 |
| 3212 if (!continueHandlers.isEmpty) { | 3129 if (!continueHandlers.isEmpty) { |
| 3213 if (!isAbortingBody) continueHandlers.add(localsHandler); | 3130 if (!isAbortingBody) continueHandlers.add(localsHandler); |
| 3214 localsHandler = | 3131 localsHandler = |
| 3215 savedLocals.mergeMultiple(continueHandlers, conditionBlock); | 3132 savedLocals.mergeMultiple(continueHandlers, conditionBlock); |
| 3216 SubGraph bodyGraph = new SubGraph(bodyEntryBlock, bodyExitBlock); | 3133 SubGraph bodyGraph = new SubGraph(bodyEntryBlock, bodyExitBlock); |
| 3217 List<LabelDefinition> labels = jumpHandler.labels(); | 3134 List<LabelDefinition> labels = jumpHandler.labels(); |
| 3218 HSubGraphBlockInformation bodyInfo = | 3135 HSubGraphBlockInformation bodyInfo = |
| 3219 new HSubGraphBlockInformation(bodyGraph); | 3136 new HSubGraphBlockInformation(bodyGraph); |
| 3220 HLabeledBlockInformation info; | 3137 HLabeledBlockInformation info; |
| 3221 if (!labels.isEmpty) { | 3138 if (!labels.isEmpty) { |
| 3222 info = new HLabeledBlockInformation(bodyInfo, labels, | 3139 info = |
| 3223 isContinue: true); | 3140 new HLabeledBlockInformation(bodyInfo, labels, isContinue: true); |
| 3224 } else { | 3141 } else { |
| 3225 info = new HLabeledBlockInformation.implicit(bodyInfo, target, | 3142 info = new HLabeledBlockInformation.implicit(bodyInfo, target, |
| 3226 isContinue: true); | 3143 isContinue: true); |
| 3227 } | 3144 } |
| 3228 bodyEntryBlock.setBlockFlow(info, conditionBlock); | 3145 bodyEntryBlock.setBlockFlow(info, conditionBlock); |
| 3229 } | 3146 } |
| 3230 open(conditionBlock); | 3147 open(conditionBlock); |
| 3231 | 3148 |
| 3232 visit(node.condition); | 3149 visit(node.condition); |
| 3233 assert(!isAborted()); | 3150 assert(!isAborted()); |
| 3234 HInstruction conditionInstruction = popBoolified(); | 3151 HInstruction conditionInstruction = popBoolified(); |
| 3235 HBasicBlock conditionEndBlock = close( | 3152 HBasicBlock conditionEndBlock = close( |
| 3236 new HLoopBranch(conditionInstruction, HLoopBranch.DO_WHILE_LOOP)); | 3153 new HLoopBranch(conditionInstruction, HLoopBranch.DO_WHILE_LOOP)); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 3247 // Avoid a critical edge from the condition to the loop-exit body. | 3164 // Avoid a critical edge from the condition to the loop-exit body. |
| 3248 HBasicBlock conditionExitBlock = addNewBlock(); | 3165 HBasicBlock conditionExitBlock = addNewBlock(); |
| 3249 open(conditionExitBlock); | 3166 open(conditionExitBlock); |
| 3250 close(new HGoto()); | 3167 close(new HGoto()); |
| 3251 conditionEndBlock.addSuccessor(conditionExitBlock); | 3168 conditionEndBlock.addSuccessor(conditionExitBlock); |
| 3252 | 3169 |
| 3253 endLoop(loopEntryBlock, conditionExitBlock, jumpHandler, localsHandler); | 3170 endLoop(loopEntryBlock, conditionExitBlock, jumpHandler, localsHandler); |
| 3254 | 3171 |
| 3255 loopEntryBlock.postProcessLoopHeader(); | 3172 loopEntryBlock.postProcessLoopHeader(); |
| 3256 SubGraph bodyGraph = new SubGraph(loopEntryBlock, bodyExitBlock); | 3173 SubGraph bodyGraph = new SubGraph(loopEntryBlock, bodyExitBlock); |
| 3257 HLoopBlockInformation loopBlockInfo = | 3174 HLoopBlockInformation loopBlockInfo = new HLoopBlockInformation( |
| 3258 new HLoopBlockInformation( | 3175 HLoopBlockInformation.DO_WHILE_LOOP, |
| 3259 HLoopBlockInformation.DO_WHILE_LOOP, | 3176 null, |
| 3260 null, | 3177 wrapExpressionGraph(conditionExpression), |
| 3261 wrapExpressionGraph(conditionExpression), | 3178 wrapStatementGraph(bodyGraph), |
| 3262 wrapStatementGraph(bodyGraph), | 3179 null, |
| 3263 null, | 3180 loopEntryBlock.loopInformation.target, |
| 3264 loopEntryBlock.loopInformation.target, | 3181 loopEntryBlock.loopInformation.labels, |
| 3265 loopEntryBlock.loopInformation.labels, | 3182 sourceInformationBuilder.buildLoop(node)); |
| 3266 sourceInformationBuilder.buildLoop(node)); | |
| 3267 loopEntryBlock.setBlockFlow(loopBlockInfo, current); | 3183 loopEntryBlock.setBlockFlow(loopBlockInfo, current); |
| 3268 loopInfo.loopBlockInformation = loopBlockInfo; | 3184 loopInfo.loopBlockInformation = loopBlockInfo; |
| 3269 } else { | 3185 } else { |
| 3270 // Since the loop has no back edge, we remove the loop information on the | 3186 // Since the loop has no back edge, we remove the loop information on the |
| 3271 // header. | 3187 // header. |
| 3272 loopEntryBlock.loopInformation = null; | 3188 loopEntryBlock.loopInformation = null; |
| 3273 | 3189 |
| 3274 if (jumpHandler.hasAnyBreak()) { | 3190 if (jumpHandler.hasAnyBreak()) { |
| 3275 // Null branchBlock because the body of the do-while loop always aborts, | 3191 // Null branchBlock because the body of the do-while loop always aborts, |
| 3276 // so we never get to the condition. | 3192 // so we never get to the condition. |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3313 closureClassElement.closureFields.forEach((ClosureFieldElement field) { | 3229 closureClassElement.closureFields.forEach((ClosureFieldElement field) { |
| 3314 Local capturedLocal = | 3230 Local capturedLocal = |
| 3315 nestedClosureData.getLocalVariableForClosureField(field); | 3231 nestedClosureData.getLocalVariableForClosureField(field); |
| 3316 assert(capturedLocal != null); | 3232 assert(capturedLocal != null); |
| 3317 capturedVariables.add(localsHandler.readLocal(capturedLocal)); | 3233 capturedVariables.add(localsHandler.readLocal(capturedLocal)); |
| 3318 }); | 3234 }); |
| 3319 | 3235 |
| 3320 TypeMask type = | 3236 TypeMask type = |
| 3321 new TypeMask.nonNullExact(closureClassElement, compiler.world); | 3237 new TypeMask.nonNullExact(closureClassElement, compiler.world); |
| 3322 push(new HForeignNew(closureClassElement, type, capturedVariables) | 3238 push(new HForeignNew(closureClassElement, type, capturedVariables) |
| 3323 ..sourceInformation = sourceInformationBuilder.buildCreate(node)); | 3239 ..sourceInformation = sourceInformationBuilder.buildCreate(node)); |
| 3324 | 3240 |
| 3325 Element methodElement = nestedClosureData.closureElement; | 3241 Element methodElement = nestedClosureData.closureElement; |
| 3326 registry?.registerInstantiatedClosure(methodElement); | 3242 registry?.registerInstantiatedClosure(methodElement); |
| 3327 } | 3243 } |
| 3328 | 3244 |
| 3329 visitFunctionDeclaration(ast.FunctionDeclaration node) { | 3245 visitFunctionDeclaration(ast.FunctionDeclaration node) { |
| 3330 assert(isReachable); | 3246 assert(isReachable); |
| 3331 visit(node.function); | 3247 visit(node.function); |
| 3332 LocalFunctionElement localFunction = | 3248 LocalFunctionElement localFunction = |
| 3333 elements.getFunctionDefinition(node.function); | 3249 elements.getFunctionDefinition(node.function); |
| 3334 localsHandler.updateLocal(localFunction, pop()); | 3250 localsHandler.updateLocal(localFunction, pop()); |
| 3335 } | 3251 } |
| 3336 | 3252 |
| 3337 @override | 3253 @override |
| 3338 void visitThisGet(ast.Identifier node, [_]) { | 3254 void visitThisGet(ast.Identifier node, [_]) { |
| 3339 stack.add(localsHandler.readThis()); | 3255 stack.add(localsHandler.readThis()); |
| 3340 } | 3256 } |
| 3341 | 3257 |
| 3342 visitIdentifier(ast.Identifier node) { | 3258 visitIdentifier(ast.Identifier node) { |
| 3343 if (node.isThis()) { | 3259 if (node.isThis()) { |
| 3344 visitThisGet(node); | 3260 visitThisGet(node); |
| 3345 } else { | 3261 } else { |
| 3346 reporter.internalError(node, | 3262 reporter.internalError( |
| 3347 "SsaFromAstMixin.visitIdentifier on non-this."); | 3263 node, "SsaFromAstMixin.visitIdentifier on non-this."); |
| 3348 } | 3264 } |
| 3349 } | 3265 } |
| 3350 | 3266 |
| 3351 visitIf(ast.If node) { | 3267 visitIf(ast.If node) { |
| 3352 assert(isReachable); | 3268 assert(isReachable); |
| 3353 handleIf( | 3269 handleIf(node, |
| 3354 node, | |
| 3355 visitCondition: () => visit(node.condition), | 3270 visitCondition: () => visit(node.condition), |
| 3356 visitThen: () => visit(node.thenPart), | 3271 visitThen: () => visit(node.thenPart), |
| 3357 visitElse: node.elsePart != null ? () => visit(node.elsePart) : null, | 3272 visitElse: node.elsePart != null ? () => visit(node.elsePart) : null, |
| 3358 sourceInformation: sourceInformationBuilder.buildIf(node)); | 3273 sourceInformation: sourceInformationBuilder.buildIf(node)); |
| 3359 } | 3274 } |
| 3360 | 3275 |
| 3361 void handleIf(ast.Node diagnosticNode, | 3276 void handleIf(ast.Node diagnosticNode, |
| 3362 {void visitCondition(), | 3277 {void visitCondition(), |
| 3363 void visitThen(), | 3278 void visitThen(), |
| 3364 void visitElse(), | 3279 void visitElse(), |
| 3365 SourceInformation sourceInformation}) { | 3280 SourceInformation sourceInformation}) { |
| 3366 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, diagnosticNode); | 3281 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, diagnosticNode); |
| 3367 branchBuilder.handleIf( | 3282 branchBuilder.handleIf(visitCondition, visitThen, visitElse, |
| 3368 visitCondition, visitThen, visitElse, | |
| 3369 sourceInformation: sourceInformation); | 3283 sourceInformation: sourceInformation); |
| 3370 } | 3284 } |
| 3371 | 3285 |
| 3372 @override | 3286 @override |
| 3373 void visitIfNull(ast.Send node, ast.Node left, ast.Node right, _) { | 3287 void visitIfNull(ast.Send node, ast.Node left, ast.Node right, _) { |
| 3374 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 3288 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
| 3375 brancher.handleIfNull(() => visit(left), () => visit(right)); | 3289 brancher.handleIfNull(() => visit(left), () => visit(right)); |
| 3376 } | 3290 } |
| 3377 | 3291 |
| 3378 @override | 3292 @override |
| 3379 void visitLogicalAnd(ast.Send node, ast.Node left, ast.Node right, _) { | 3293 void visitLogicalAnd(ast.Send node, ast.Node left, ast.Node right, _) { |
| 3380 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, node); | 3294 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, node); |
| 3381 branchBuilder.handleLogicalAndOrWithLeftNode( | 3295 branchBuilder.handleLogicalAndOrWithLeftNode(left, () { |
| 3382 left, | 3296 visit(right); |
| 3383 () { visit(right); }, | 3297 }, isAnd: true); |
| 3384 isAnd: true); | |
| 3385 } | 3298 } |
| 3386 | 3299 |
| 3387 @override | 3300 @override |
| 3388 void visitLogicalOr(ast.Send node, ast.Node left, ast.Node right, _) { | 3301 void visitLogicalOr(ast.Send node, ast.Node left, ast.Node right, _) { |
| 3389 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, node); | 3302 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, node); |
| 3390 branchBuilder.handleLogicalAndOrWithLeftNode( | 3303 branchBuilder.handleLogicalAndOrWithLeftNode(left, () { |
| 3391 left, | 3304 visit(right); |
| 3392 () { visit(right); }, | 3305 }, isAnd: false); |
| 3393 isAnd: false); | |
| 3394 } | 3306 } |
| 3395 | 3307 |
| 3396 @override | 3308 @override |
| 3397 void visitNot(ast.Send node, ast.Node expression, _) { | 3309 void visitNot(ast.Send node, ast.Node expression, _) { |
| 3398 assert(node.argumentsNode is ast.Prefix); | 3310 assert(node.argumentsNode is ast.Prefix); |
| 3399 visit(expression); | 3311 visit(expression); |
| 3400 SourceInformation sourceInformation = | 3312 SourceInformation sourceInformation = |
| 3401 sourceInformationBuilder.buildGeneric(node); | 3313 sourceInformationBuilder.buildGeneric(node); |
| 3402 push(new HNot(popBoolified(), backend.boolType) | 3314 push(new HNot(popBoolified(), backend.boolType) |
| 3403 ..sourceInformation = sourceInformation); | 3315 ..sourceInformation = sourceInformation); |
| 3404 } | 3316 } |
| 3405 | 3317 |
| 3406 @override | 3318 @override |
| 3407 void visitUnary(ast.Send node, | 3319 void visitUnary( |
| 3408 UnaryOperator operator, | 3320 ast.Send node, UnaryOperator operator, ast.Node expression, _) { |
| 3409 ast.Node expression,_) { | |
| 3410 assert(node.argumentsNode is ast.Prefix); | 3321 assert(node.argumentsNode is ast.Prefix); |
| 3411 HInstruction operand = visitAndPop(expression); | 3322 HInstruction operand = visitAndPop(expression); |
| 3412 | 3323 |
| 3413 // See if we can constant-fold right away. This avoids rewrites later on. | 3324 // See if we can constant-fold right away. This avoids rewrites later on. |
| 3414 if (operand is HConstant) { | 3325 if (operand is HConstant) { |
| 3415 UnaryOperation operation = constantSystem.lookupUnary(operator); | 3326 UnaryOperation operation = constantSystem.lookupUnary(operator); |
| 3416 HConstant constant = operand; | 3327 HConstant constant = operand; |
| 3417 ConstantValue folded = operation.fold(constant.constant); | 3328 ConstantValue folded = operation.fold(constant.constant); |
| 3418 if (folded != null) { | 3329 if (folded != null) { |
| 3419 stack.add(graph.addConstant(folded, compiler)); | 3330 stack.add(graph.addConstant(folded, compiler)); |
| 3420 return; | 3331 return; |
| 3421 } | 3332 } |
| 3422 } | 3333 } |
| 3423 | 3334 |
| 3424 pushInvokeDynamic( | 3335 pushInvokeDynamic( |
| 3425 node, | 3336 node, elements.getSelector(node), elements.getTypeMask(node), [operand], |
| 3426 elements.getSelector(node), | |
| 3427 elements.getTypeMask(node), | |
| 3428 [operand], | |
| 3429 sourceInformation: sourceInformationBuilder.buildGeneric(node)); | 3337 sourceInformation: sourceInformationBuilder.buildGeneric(node)); |
| 3430 } | 3338 } |
| 3431 | 3339 |
| 3432 @override | 3340 @override |
| 3433 void visitBinary(ast.Send node, | 3341 void visitBinary(ast.Send node, ast.Node left, BinaryOperator operator, |
| 3434 ast.Node left, | 3342 ast.Node right, _) { |
| 3435 BinaryOperator operator, | |
| 3436 ast.Node right, _) { | |
| 3437 handleBinary(node, left, right); | 3343 handleBinary(node, left, right); |
| 3438 } | 3344 } |
| 3439 | 3345 |
| 3440 @override | 3346 @override |
| 3441 void visitIndex(ast.Send node, ast.Node receiver, ast.Node index, _) { | 3347 void visitIndex(ast.Send node, ast.Node receiver, ast.Node index, _) { |
| 3442 generateDynamicSend(node); | 3348 generateDynamicSend(node); |
| 3443 } | 3349 } |
| 3444 | 3350 |
| 3445 @override | 3351 @override |
| 3446 void visitEquals(ast.Send node, ast.Node left, ast.Node right, _) { | 3352 void visitEquals(ast.Send node, ast.Node left, ast.Node right, _) { |
| 3447 handleBinary(node, left, right); | 3353 handleBinary(node, left, right); |
| 3448 } | 3354 } |
| 3449 | 3355 |
| 3450 @override | 3356 @override |
| 3451 void visitNotEquals(ast.Send node, ast.Node left, ast.Node right, _) { | 3357 void visitNotEquals(ast.Send node, ast.Node left, ast.Node right, _) { |
| 3452 handleBinary(node, left, right); | 3358 handleBinary(node, left, right); |
| 3453 pushWithPosition(new HNot(popBoolified(), backend.boolType), node.selector); | 3359 pushWithPosition(new HNot(popBoolified(), backend.boolType), node.selector); |
| 3454 } | 3360 } |
| 3455 | 3361 |
| 3456 void handleBinary(ast.Send node, ast.Node left, ast.Node right) { | 3362 void handleBinary(ast.Send node, ast.Node left, ast.Node right) { |
| 3457 visitBinarySend( | 3363 visitBinarySend(visitAndPop(left), visitAndPop(right), |
| 3458 visitAndPop(left), | 3364 elements.getSelector(node), elements.getTypeMask(node), node, |
| 3459 visitAndPop(right), | |
| 3460 elements.getSelector(node), | |
| 3461 elements.getTypeMask(node), | |
| 3462 node, | |
| 3463 sourceInformation: | 3365 sourceInformation: |
| 3464 sourceInformationBuilder.buildGeneric(node.selector)); | 3366 sourceInformationBuilder.buildGeneric(node.selector)); |
| 3465 } | 3367 } |
| 3466 | 3368 |
| 3467 /// TODO(johnniwinther): Merge [visitBinarySend] with [handleBinary] and | 3369 /// TODO(johnniwinther): Merge [visitBinarySend] with [handleBinary] and |
| 3468 /// remove use of [location] for source information. | 3370 /// remove use of [location] for source information. |
| 3469 void visitBinarySend(HInstruction left, | 3371 void visitBinarySend(HInstruction left, HInstruction right, Selector selector, |
| 3470 HInstruction right, | 3372 TypeMask mask, ast.Send send, |
| 3471 Selector selector, | 3373 {SourceInformation sourceInformation}) { |
| 3472 TypeMask mask, | |
| 3473 ast.Send send, | |
| 3474 {SourceInformation sourceInformation}) { | |
| 3475 pushInvokeDynamic(send, selector, mask, [left, right], | 3374 pushInvokeDynamic(send, selector, mask, [left, right], |
| 3476 sourceInformation: sourceInformation); | 3375 sourceInformation: sourceInformation); |
| 3477 } | 3376 } |
| 3478 | 3377 |
| 3479 HInstruction generateInstanceSendReceiver(ast.Send send) { | 3378 HInstruction generateInstanceSendReceiver(ast.Send send) { |
| 3480 assert(Elements.isInstanceSend(send, elements)); | 3379 assert(Elements.isInstanceSend(send, elements)); |
| 3481 if (send.receiver == null) { | 3380 if (send.receiver == null) { |
| 3482 return localsHandler.readThis(); | 3381 return localsHandler.readThis(); |
| 3483 } | 3382 } |
| 3484 visit(send.receiver); | 3383 visit(send.receiver); |
| 3485 return pop(); | 3384 return pop(); |
| 3486 } | 3385 } |
| 3487 | 3386 |
| 3488 String noSuchMethodTargetSymbolString(Element error, [String prefix]) { | 3387 String noSuchMethodTargetSymbolString(Element error, [String prefix]) { |
| 3489 String result = error.name; | 3388 String result = error.name; |
| 3490 if (prefix == "set") return "$result="; | 3389 if (prefix == "set") return "$result="; |
| 3491 return result; | 3390 return result; |
| 3492 } | 3391 } |
| 3493 | 3392 |
| 3494 /** | 3393 /** |
| 3495 * Returns a set of interceptor classes that contain the given | 3394 * Returns a set of interceptor classes that contain the given |
| 3496 * [selector]. | 3395 * [selector]. |
| 3497 */ | 3396 */ |
| 3498 void generateInstanceGetterWithCompiledReceiver( | 3397 void generateInstanceGetterWithCompiledReceiver( |
| 3499 ast.Send send, | 3398 ast.Send send, Selector selector, TypeMask mask, HInstruction receiver) { |
| 3500 Selector selector, | |
| 3501 TypeMask mask, | |
| 3502 HInstruction receiver) { | |
| 3503 assert(Elements.isInstanceSend(send, elements)); | 3399 assert(Elements.isInstanceSend(send, elements)); |
| 3504 assert(selector.isGetter); | 3400 assert(selector.isGetter); |
| 3505 pushInvokeDynamic(send, selector, mask, [receiver], | 3401 pushInvokeDynamic(send, selector, mask, [receiver], |
| 3506 sourceInformation: sourceInformationBuilder.buildGet(send)); | 3402 sourceInformation: sourceInformationBuilder.buildGet(send)); |
| 3507 } | 3403 } |
| 3508 | 3404 |
| 3509 /// Inserts a call to checkDeferredIsLoaded for [prefixElement]. | 3405 /// Inserts a call to checkDeferredIsLoaded for [prefixElement]. |
| 3510 /// If [prefixElement] is [null] ndo nothing. | 3406 /// If [prefixElement] is [null] ndo nothing. |
| 3511 void generateIsDeferredLoadedCheckIfNeeded(PrefixElement prefixElement, | 3407 void generateIsDeferredLoadedCheckIfNeeded( |
| 3512 ast.Node location) { | 3408 PrefixElement prefixElement, ast.Node location) { |
| 3513 if (prefixElement == null) return; | 3409 if (prefixElement == null) return; |
| 3514 String loadId = | 3410 String loadId = |
| 3515 compiler.deferredLoadTask.getImportDeferName(location, prefixElement); | 3411 compiler.deferredLoadTask.getImportDeferName(location, prefixElement); |
| 3516 HInstruction loadIdConstant = addConstantString(loadId); | 3412 HInstruction loadIdConstant = addConstantString(loadId); |
| 3517 String uri = prefixElement.deferredImport.uri.toString(); | 3413 String uri = prefixElement.deferredImport.uri.toString(); |
| 3518 HInstruction uriConstant = addConstantString(uri); | 3414 HInstruction uriConstant = addConstantString(uri); |
| 3519 Element helper = helpers.checkDeferredIsLoaded; | 3415 Element helper = helpers.checkDeferredIsLoaded; |
| 3520 pushInvokeStatic(location, helper, [loadIdConstant, uriConstant]); | 3416 pushInvokeStatic(location, helper, [loadIdConstant, uriConstant]); |
| 3521 pop(); | 3417 pop(); |
| 3522 } | 3418 } |
| 3523 | 3419 |
| 3524 /// Inserts a call to checkDeferredIsLoaded if the send has a prefix that | 3420 /// Inserts a call to checkDeferredIsLoaded if the send has a prefix that |
| 3525 /// resolves to a deferred library. | 3421 /// resolves to a deferred library. |
| 3526 void generateIsDeferredLoadedCheckOfSend(ast.Send node) { | 3422 void generateIsDeferredLoadedCheckOfSend(ast.Send node) { |
| 3527 generateIsDeferredLoadedCheckIfNeeded( | 3423 generateIsDeferredLoadedCheckIfNeeded( |
| 3528 compiler.deferredLoadTask.deferredPrefixElement(node, elements), | 3424 compiler.deferredLoadTask.deferredPrefixElement(node, elements), node); |
| 3529 node); | |
| 3530 } | 3425 } |
| 3531 | 3426 |
| 3532 void handleInvalidStaticGet(ast.Send node, Element element) { | 3427 void handleInvalidStaticGet(ast.Send node, Element element) { |
| 3533 SourceInformation sourceInformation = | 3428 SourceInformation sourceInformation = |
| 3534 sourceInformationBuilder.buildGet(node); | 3429 sourceInformationBuilder.buildGet(node); |
| 3535 generateThrowNoSuchMethod( | 3430 generateThrowNoSuchMethod( |
| 3536 node, | 3431 node, noSuchMethodTargetSymbolString(element, 'get'), |
| 3537 noSuchMethodTargetSymbolString(element, 'get'), | |
| 3538 argumentNodes: const Link<ast.Node>(), | 3432 argumentNodes: const Link<ast.Node>(), |
| 3539 sourceInformation: sourceInformation); | 3433 sourceInformation: sourceInformation); |
| 3540 } | 3434 } |
| 3541 | 3435 |
| 3542 /// Generate read access of an unresolved static or top level entity. | 3436 /// Generate read access of an unresolved static or top level entity. |
| 3543 void generateStaticUnresolvedGet(ast.Send node, Element element) { | 3437 void generateStaticUnresolvedGet(ast.Send node, Element element) { |
| 3544 if (element is ErroneousElement) { | 3438 if (element is ErroneousElement) { |
| 3545 SourceInformation sourceInformation = | 3439 SourceInformation sourceInformation = |
| 3546 sourceInformationBuilder.buildGet(node); | 3440 sourceInformationBuilder.buildGet(node); |
| 3547 // An erroneous element indicates an unresolved static getter. | 3441 // An erroneous element indicates an unresolved static getter. |
| 3548 handleInvalidStaticGet(node, element); | 3442 handleInvalidStaticGet(node, element); |
| 3549 } else { | 3443 } else { |
| 3550 // This happens when [element] has parse errors. | 3444 // This happens when [element] has parse errors. |
| 3551 assert(invariant(node, element == null || element.isMalformed)); | 3445 assert(invariant(node, element == null || element.isMalformed)); |
| 3552 // TODO(ahe): Do something like the above, that is, emit a runtime | 3446 // TODO(ahe): Do something like the above, that is, emit a runtime |
| 3553 // error. | 3447 // error. |
| 3554 stack.add(graph.addConstantNull(compiler)); | 3448 stack.add(graph.addConstantNull(compiler)); |
| 3555 } | 3449 } |
| 3556 } | 3450 } |
| 3557 | 3451 |
| 3558 /// Read a static or top level [field] of constant value. | 3452 /// Read a static or top level [field] of constant value. |
| 3559 void generateStaticConstGet( | 3453 void generateStaticConstGet(ast.Send node, FieldElement field, |
| 3560 ast.Send node, | 3454 ConstantExpression constant, SourceInformation sourceInformation) { |
| 3561 FieldElement field, | |
| 3562 ConstantExpression constant, | |
| 3563 SourceInformation sourceInformation) { | |
| 3564 ConstantValue value = backend.constants.getConstantValue(constant); | 3455 ConstantValue value = backend.constants.getConstantValue(constant); |
| 3565 HConstant instruction; | 3456 HConstant instruction; |
| 3566 // Constants that are referred via a deferred prefix should be referred | 3457 // Constants that are referred via a deferred prefix should be referred |
| 3567 // by reference. | 3458 // by reference. |
| 3568 PrefixElement prefix = compiler.deferredLoadTask | 3459 PrefixElement prefix = |
| 3569 .deferredPrefixElement(node, elements); | 3460 compiler.deferredLoadTask.deferredPrefixElement(node, elements); |
| 3570 if (prefix != null) { | 3461 if (prefix != null) { |
| 3571 instruction = | 3462 instruction = |
| 3572 graph.addDeferredConstant(value, prefix, sourceInformation, compiler); | 3463 graph.addDeferredConstant(value, prefix, sourceInformation, compiler); |
| 3573 } else { | 3464 } else { |
| 3574 instruction = graph.addConstant( | 3465 instruction = graph.addConstant(value, compiler, |
| 3575 value, compiler, sourceInformation: sourceInformation); | 3466 sourceInformation: sourceInformation); |
| 3576 } | 3467 } |
| 3577 stack.add(instruction); | 3468 stack.add(instruction); |
| 3578 // The inferrer may have found a better type than the constant | 3469 // The inferrer may have found a better type than the constant |
| 3579 // handler in the case of lists, because the constant handler | 3470 // handler in the case of lists, because the constant handler |
| 3580 // does not look at elements in the list. | 3471 // does not look at elements in the list. |
| 3581 TypeMask type = | 3472 TypeMask type = TypeMaskFactory.inferredTypeForElement(field, compiler); |
| 3582 TypeMaskFactory.inferredTypeForElement(field, compiler); | 3473 if (!type.containsAll(compiler.world) && !instruction.isConstantNull()) { |
| 3583 if (!type.containsAll(compiler.world) && | |
| 3584 !instruction.isConstantNull()) { | |
| 3585 // TODO(13429): The inferrer should know that an element | 3474 // TODO(13429): The inferrer should know that an element |
| 3586 // cannot be null. | 3475 // cannot be null. |
| 3587 instruction.instructionType = type.nonNullable(); | 3476 instruction.instructionType = type.nonNullable(); |
| 3588 } | 3477 } |
| 3589 } | 3478 } |
| 3590 | 3479 |
| 3591 @override | 3480 @override |
| 3592 void previsitDeferredAccess(ast.Send node, PrefixElement prefix, _) { | 3481 void previsitDeferredAccess(ast.Send node, PrefixElement prefix, _) { |
| 3593 generateIsDeferredLoadedCheckIfNeeded(prefix, node); | 3482 generateIsDeferredLoadedCheckIfNeeded(prefix, node); |
| 3594 } | 3483 } |
| 3595 | 3484 |
| 3596 /// Read a static or top level [field]. | 3485 /// Read a static or top level [field]. |
| 3597 void generateStaticFieldGet(ast.Send node, FieldElement field) { | 3486 void generateStaticFieldGet(ast.Send node, FieldElement field) { |
| 3598 ConstantExpression constant = | 3487 ConstantExpression constant = |
| 3599 backend.constants.getConstantForVariable(field); | 3488 backend.constants.getConstantForVariable(field); |
| 3600 SourceInformation sourceInformation = | 3489 SourceInformation sourceInformation = |
| 3601 sourceInformationBuilder.buildGet(node); | 3490 sourceInformationBuilder.buildGet(node); |
| 3602 if (constant != null) { | 3491 if (constant != null) { |
| 3603 if (!field.isAssignable) { | 3492 if (!field.isAssignable) { |
| 3604 // A static final or const. Get its constant value and inline it if | 3493 // A static final or const. Get its constant value and inline it if |
| 3605 // the value can be compiled eagerly. | 3494 // the value can be compiled eagerly. |
| 3606 generateStaticConstGet(node, field, constant, sourceInformation); | 3495 generateStaticConstGet(node, field, constant, sourceInformation); |
| 3607 } else { | 3496 } else { |
| 3608 // TODO(5346): Try to avoid the need for calling [declaration] before | 3497 // TODO(5346): Try to avoid the need for calling [declaration] before |
| 3609 // creating an [HStatic]. | 3498 // creating an [HStatic]. |
| 3610 HInstruction instruction = new HStatic( | 3499 HInstruction instruction = new HStatic(field.declaration, |
| 3611 field.declaration, | |
| 3612 TypeMaskFactory.inferredTypeForElement(field, compiler)) | 3500 TypeMaskFactory.inferredTypeForElement(field, compiler)) |
| 3613 ..sourceInformation = sourceInformation; | 3501 ..sourceInformation = sourceInformation; |
| 3614 push(instruction); | 3502 push(instruction); |
| 3615 } | 3503 } |
| 3616 } else { | 3504 } else { |
| 3617 HInstruction instruction = new HLazyStatic( | 3505 HInstruction instruction = new HLazyStatic( |
| 3618 field, | 3506 field, TypeMaskFactory.inferredTypeForElement(field, compiler)) |
| 3619 TypeMaskFactory.inferredTypeForElement(field, compiler)) | 3507 ..sourceInformation = sourceInformation; |
| 3620 ..sourceInformation = sourceInformation; | |
| 3621 push(instruction); | 3508 push(instruction); |
| 3622 } | 3509 } |
| 3623 } | 3510 } |
| 3624 | 3511 |
| 3625 /// Generate a getter invocation of the static or top level [getter]. | 3512 /// Generate a getter invocation of the static or top level [getter]. |
| 3626 void generateStaticGetterGet(ast.Send node, MethodElement getter) { | 3513 void generateStaticGetterGet(ast.Send node, MethodElement getter) { |
| 3627 SourceInformation sourceInformation = | 3514 SourceInformation sourceInformation = |
| 3628 sourceInformationBuilder.buildGet(node); | 3515 sourceInformationBuilder.buildGet(node); |
| 3629 if (getter.isDeferredLoaderGetter) { | 3516 if (getter.isDeferredLoaderGetter) { |
| 3630 generateDeferredLoaderGet(node, getter, sourceInformation); | 3517 generateDeferredLoaderGet(node, getter, sourceInformation); |
| 3631 } else { | 3518 } else { |
| 3632 pushInvokeStatic(node, getter, <HInstruction>[], | 3519 pushInvokeStatic(node, getter, <HInstruction>[], |
| 3633 sourceInformation: sourceInformation); | 3520 sourceInformation: sourceInformation); |
| 3634 } | 3521 } |
| 3635 } | 3522 } |
| 3636 | 3523 |
| 3637 /// Generate a dynamic getter invocation. | 3524 /// Generate a dynamic getter invocation. |
| 3638 void generateDynamicGet(ast.Send node) { | 3525 void generateDynamicGet(ast.Send node) { |
| 3639 HInstruction receiver = generateInstanceSendReceiver(node); | 3526 HInstruction receiver = generateInstanceSendReceiver(node); |
| 3640 generateInstanceGetterWithCompiledReceiver( | 3527 generateInstanceGetterWithCompiledReceiver( |
| 3641 node, elements.getSelector(node), elements.getTypeMask(node), receiver); | 3528 node, elements.getSelector(node), elements.getTypeMask(node), receiver); |
| 3642 } | 3529 } |
| 3643 | 3530 |
| 3644 /// Generate a closurization of the static or top level [function]. | 3531 /// Generate a closurization of the static or top level [function]. |
| 3645 void generateStaticFunctionGet(ast.Send node, MethodElement function) { | 3532 void generateStaticFunctionGet(ast.Send node, MethodElement function) { |
| 3646 // TODO(5346): Try to avoid the need for calling [declaration] before | 3533 // TODO(5346): Try to avoid the need for calling [declaration] before |
| 3647 // creating an [HStatic]. | 3534 // creating an [HStatic]. |
| 3648 SourceInformation sourceInformation = | 3535 SourceInformation sourceInformation = |
| 3649 sourceInformationBuilder.buildGet(node); | 3536 sourceInformationBuilder.buildGet(node); |
| 3650 push(new HStatic(function.declaration, backend.nonNullType) | 3537 push(new HStatic(function.declaration, backend.nonNullType) |
| 3651 ..sourceInformation = sourceInformation); | 3538 ..sourceInformation = sourceInformation); |
| 3652 } | 3539 } |
| 3653 | 3540 |
| 3654 /// Read a local variable, function or parameter. | 3541 /// Read a local variable, function or parameter. |
| 3655 void buildLocalGet(LocalElement local, SourceInformation sourceInformation) { | 3542 void buildLocalGet(LocalElement local, SourceInformation sourceInformation) { |
| 3656 stack.add(localsHandler.readLocal( | 3543 stack.add( |
| 3657 local, sourceInformation: sourceInformation)); | 3544 localsHandler.readLocal(local, sourceInformation: sourceInformation)); |
| 3658 } | 3545 } |
| 3659 | 3546 |
| 3660 void handleLocalGet(ast.Send node, LocalElement local) { | 3547 void handleLocalGet(ast.Send node, LocalElement local) { |
| 3661 buildLocalGet(local, sourceInformationBuilder.buildGet(node)); | 3548 buildLocalGet(local, sourceInformationBuilder.buildGet(node)); |
| 3662 } | 3549 } |
| 3663 | 3550 |
| 3664 @override | 3551 @override |
| 3665 void visitDynamicPropertyGet( | 3552 void visitDynamicPropertyGet(ast.Send node, ast.Node receiver, Name name, _) { |
| 3666 ast.Send node, | |
| 3667 ast.Node receiver, | |
| 3668 Name name, | |
| 3669 _) { | |
| 3670 generateDynamicGet(node); | 3553 generateDynamicGet(node); |
| 3671 } | 3554 } |
| 3672 | 3555 |
| 3673 @override | 3556 @override |
| 3674 void visitIfNotNullDynamicPropertyGet( | 3557 void visitIfNotNullDynamicPropertyGet( |
| 3675 ast.Send node, | 3558 ast.Send node, ast.Node receiver, Name name, _) { |
| 3676 ast.Node receiver, | |
| 3677 Name name, | |
| 3678 _) { | |
| 3679 // exp?.x compiled as: | 3559 // exp?.x compiled as: |
| 3680 // t1 = exp; | 3560 // t1 = exp; |
| 3681 // result = t1 == null ? t1 : t1.x; | 3561 // result = t1 == null ? t1 : t1.x; |
| 3682 // This is equivalent to t1 == null ? null : t1.x, but in the current form | 3562 // This is equivalent to t1 == null ? null : t1.x, but in the current form |
| 3683 // we will be able to later compress it as: | 3563 // we will be able to later compress it as: |
| 3684 // t1 || t1.x | 3564 // t1 || t1.x |
| 3685 HInstruction expression; | 3565 HInstruction expression; |
| 3686 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 3566 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
| 3687 brancher.handleConditional( | 3567 brancher.handleConditional( |
| 3688 () { | 3568 () { |
| 3689 expression = visitAndPop(receiver); | 3569 expression = visitAndPop(receiver); |
| 3690 pushCheckNull(expression); | 3570 pushCheckNull(expression); |
| 3691 }, | 3571 }, |
| 3692 () => stack.add(expression), | 3572 () => stack.add(expression), |
| 3693 () { | 3573 () { |
| 3694 generateInstanceGetterWithCompiledReceiver( | 3574 generateInstanceGetterWithCompiledReceiver( |
| 3695 node, | 3575 node, |
| 3696 elements.getSelector(node), | 3576 elements.getSelector(node), |
| 3697 elements.getTypeMask(node), | 3577 elements.getTypeMask(node), |
| 3698 expression); | 3578 expression); |
| 3699 }); | 3579 }); |
| 3700 } | 3580 } |
| 3701 | 3581 |
| 3702 /// Pushes a boolean checking [expression] against null. | 3582 /// Pushes a boolean checking [expression] against null. |
| 3703 pushCheckNull(HInstruction expression) { | 3583 pushCheckNull(HInstruction expression) { |
| 3704 push(new HIdentity(expression, graph.addConstantNull(compiler), | 3584 push(new HIdentity( |
| 3705 null, backend.boolType)); | 3585 expression, graph.addConstantNull(compiler), null, backend.boolType)); |
| 3706 } | 3586 } |
| 3707 | 3587 |
| 3708 @override | 3588 @override |
| 3709 void visitLocalVariableGet(ast.Send node, LocalVariableElement variable, _) { | 3589 void visitLocalVariableGet(ast.Send node, LocalVariableElement variable, _) { |
| 3710 handleLocalGet(node, variable); | 3590 handleLocalGet(node, variable); |
| 3711 } | 3591 } |
| 3712 | 3592 |
| 3713 @override | 3593 @override |
| 3714 void visitParameterGet(ast.Send node, ParameterElement parameter, _) { | 3594 void visitParameterGet(ast.Send node, ParameterElement parameter, _) { |
| 3715 handleLocalGet(node, parameter); | 3595 handleLocalGet(node, parameter); |
| 3716 } | 3596 } |
| 3717 | 3597 |
| 3718 @override | 3598 @override |
| 3719 void visitLocalFunctionGet(ast.Send node, LocalFunctionElement function, _) { | 3599 void visitLocalFunctionGet(ast.Send node, LocalFunctionElement function, _) { |
| 3720 handleLocalGet(node, function); | 3600 handleLocalGet(node, function); |
| 3721 } | 3601 } |
| 3722 | 3602 |
| 3723 @override | 3603 @override |
| 3724 void visitStaticFieldGet( | 3604 void visitStaticFieldGet(ast.Send node, FieldElement field, _) { |
| 3725 ast.Send node, | |
| 3726 FieldElement field, | |
| 3727 _) { | |
| 3728 generateStaticFieldGet(node, field); | 3605 generateStaticFieldGet(node, field); |
| 3729 } | 3606 } |
| 3730 | 3607 |
| 3731 @override | 3608 @override |
| 3732 void visitStaticFunctionGet( | 3609 void visitStaticFunctionGet(ast.Send node, MethodElement function, _) { |
| 3733 ast.Send node, | |
| 3734 MethodElement function, | |
| 3735 _) { | |
| 3736 generateStaticFunctionGet(node, function); | 3610 generateStaticFunctionGet(node, function); |
| 3737 } | 3611 } |
| 3738 | 3612 |
| 3739 @override | 3613 @override |
| 3740 void visitStaticGetterGet( | 3614 void visitStaticGetterGet(ast.Send node, FunctionElement getter, _) { |
| 3741 ast.Send node, | |
| 3742 FunctionElement getter, | |
| 3743 _) { | |
| 3744 generateStaticGetterGet(node, getter); | 3615 generateStaticGetterGet(node, getter); |
| 3745 } | 3616 } |
| 3746 | 3617 |
| 3747 @override | 3618 @override |
| 3748 void visitThisPropertyGet( | 3619 void visitThisPropertyGet(ast.Send node, Name name, _) { |
| 3749 ast.Send node, | |
| 3750 Name name, | |
| 3751 _) { | |
| 3752 generateDynamicGet(node); | 3620 generateDynamicGet(node); |
| 3753 } | 3621 } |
| 3754 | 3622 |
| 3755 @override | 3623 @override |
| 3756 void visitTopLevelFieldGet( | 3624 void visitTopLevelFieldGet(ast.Send node, FieldElement field, _) { |
| 3757 ast.Send node, | |
| 3758 FieldElement field, | |
| 3759 _) { | |
| 3760 generateStaticFieldGet(node, field); | 3625 generateStaticFieldGet(node, field); |
| 3761 } | 3626 } |
| 3762 | 3627 |
| 3763 @override | 3628 @override |
| 3764 void visitTopLevelFunctionGet( | 3629 void visitTopLevelFunctionGet(ast.Send node, MethodElement function, _) { |
| 3765 ast.Send node, | |
| 3766 MethodElement function, | |
| 3767 _) { | |
| 3768 generateStaticFunctionGet(node, function); | 3630 generateStaticFunctionGet(node, function); |
| 3769 } | 3631 } |
| 3770 | 3632 |
| 3771 @override | 3633 @override |
| 3772 void visitTopLevelGetterGet( | 3634 void visitTopLevelGetterGet(ast.Send node, FunctionElement getter, _) { |
| 3773 ast.Send node, | |
| 3774 FunctionElement getter, | |
| 3775 _) { | |
| 3776 generateStaticGetterGet(node, getter); | 3635 generateStaticGetterGet(node, getter); |
| 3777 } | 3636 } |
| 3778 | 3637 |
| 3779 void generateInstanceSetterWithCompiledReceiver(ast.Send send, | 3638 void generateInstanceSetterWithCompiledReceiver( |
| 3780 HInstruction receiver, | 3639 ast.Send send, HInstruction receiver, HInstruction value, |
| 3781 HInstruction value, | 3640 {Selector selector, TypeMask mask, ast.Node location}) { |
| 3782 {Selector selector, | 3641 assert(invariant(send == null ? location : send, |
| 3783 TypeMask mask, | |
| 3784 ast.Node location}) { | |
| 3785 assert(invariant( | |
| 3786 send == null ? location : send, | |
| 3787 send == null || Elements.isInstanceSend(send, elements), | 3642 send == null || Elements.isInstanceSend(send, elements), |
| 3788 message: "Unexpected instance setter" | 3643 message: "Unexpected instance setter" |
| 3789 "${send != null ? " element: ${elements[send]}" : ""}")); | 3644 "${send != null ? " element: ${elements[send]}" : ""}")); |
| 3790 if (selector == null) { | 3645 if (selector == null) { |
| 3791 assert(send != null); | 3646 assert(send != null); |
| 3792 selector = elements.getSelector(send); | 3647 selector = elements.getSelector(send); |
| 3793 if (mask == null) { | 3648 if (mask == null) { |
| 3794 mask = elements.getTypeMask(send); | 3649 mask = elements.getTypeMask(send); |
| 3795 } | 3650 } |
| 3796 } | 3651 } |
| 3797 if (location == null) { | 3652 if (location == null) { |
| 3798 assert(send != null); | 3653 assert(send != null); |
| 3799 location = send; | 3654 location = send; |
| 3800 } | 3655 } |
| 3801 assert(selector.isSetter); | 3656 assert(selector.isSetter); |
| 3802 pushInvokeDynamic(location, selector, mask, [receiver, value], | 3657 pushInvokeDynamic(location, selector, mask, [receiver, value], |
| 3803 sourceInformation: sourceInformationBuilder.buildAssignment(location)); | 3658 sourceInformation: sourceInformationBuilder.buildAssignment(location)); |
| 3804 pop(); | 3659 pop(); |
| 3805 stack.add(value); | 3660 stack.add(value); |
| 3806 } | 3661 } |
| 3807 | 3662 |
| 3808 void generateNoSuchSetter(ast.Node location, | 3663 void generateNoSuchSetter( |
| 3809 Element element, | 3664 ast.Node location, Element element, HInstruction value) { |
| 3810 HInstruction value) { | |
| 3811 List<HInstruction> arguments = | 3665 List<HInstruction> arguments = |
| 3812 value == null ? const <HInstruction>[] : <HInstruction>[value]; | 3666 value == null ? const <HInstruction>[] : <HInstruction>[value]; |
| 3813 // An erroneous element indicates an unresolved static setter. | 3667 // An erroneous element indicates an unresolved static setter. |
| 3814 generateThrowNoSuchMethod( | 3668 generateThrowNoSuchMethod( |
| 3815 location, noSuchMethodTargetSymbolString(element, 'set'), | 3669 location, noSuchMethodTargetSymbolString(element, 'set'), |
| 3816 argumentValues: arguments); | 3670 argumentValues: arguments); |
| 3817 } | 3671 } |
| 3818 | 3672 |
| 3819 void generateNonInstanceSetter(ast.SendSet send, | 3673 void generateNonInstanceSetter( |
| 3820 Element element, | 3674 ast.SendSet send, Element element, HInstruction value, |
| 3821 HInstruction value, | 3675 {ast.Node location}) { |
| 3822 {ast.Node location}) { | |
| 3823 if (location == null) { | 3676 if (location == null) { |
| 3824 assert(send != null); | 3677 assert(send != null); |
| 3825 location = send; | 3678 location = send; |
| 3826 } | 3679 } |
| 3827 assert(invariant(location, | 3680 assert(invariant( |
| 3828 send == null || !Elements.isInstanceSend(send, elements), | 3681 location, send == null || !Elements.isInstanceSend(send, elements), |
| 3829 message: "Unexpected non instance setter: $element.")); | 3682 message: "Unexpected non instance setter: $element.")); |
| 3830 if (Elements.isStaticOrTopLevelField(element)) { | 3683 if (Elements.isStaticOrTopLevelField(element)) { |
| 3831 if (element.isSetter) { | 3684 if (element.isSetter) { |
| 3832 pushInvokeStatic(location, element, <HInstruction>[value]); | 3685 pushInvokeStatic(location, element, <HInstruction>[value]); |
| 3833 pop(); | 3686 pop(); |
| 3834 } else { | 3687 } else { |
| 3835 VariableElement field = element; | 3688 VariableElement field = element; |
| 3836 value = potentiallyCheckOrTrustType(value, field.type); | 3689 value = potentiallyCheckOrTrustType(value, field.type); |
| 3837 addWithPosition(new HStaticStore(element, value), location); | 3690 addWithPosition(new HStaticStore(element, value), location); |
| 3838 } | 3691 } |
| 3839 stack.add(value); | 3692 stack.add(value); |
| 3840 } else if (Elements.isError(element)) { | 3693 } else if (Elements.isError(element)) { |
| 3841 generateNoSuchSetter(location, element, send == null ? null : value); | 3694 generateNoSuchSetter(location, element, send == null ? null : value); |
| 3842 } else if (Elements.isMalformed(element)) { | 3695 } else if (Elements.isMalformed(element)) { |
| 3843 // TODO(ahe): Do something like [generateWrongArgumentCountError]. | 3696 // TODO(ahe): Do something like [generateWrongArgumentCountError]. |
| 3844 stack.add(graph.addConstantNull(compiler)); | 3697 stack.add(graph.addConstantNull(compiler)); |
| 3845 } else { | 3698 } else { |
| 3846 stack.add(value); | 3699 stack.add(value); |
| 3847 LocalElement local = element; | 3700 LocalElement local = element; |
| 3848 // If the value does not already have a name, give it here. | 3701 // If the value does not already have a name, give it here. |
| 3849 if (value.sourceElement == null) { | 3702 if (value.sourceElement == null) { |
| 3850 value.sourceElement = local; | 3703 value.sourceElement = local; |
| 3851 } | 3704 } |
| (...skipping 30 matching lines...) Expand all Loading... |
| 3882 } else { | 3735 } else { |
| 3883 assert(type.element.isClass); | 3736 assert(type.element.isClass); |
| 3884 InterfaceType interface = type; | 3737 InterfaceType interface = type; |
| 3885 List<HInstruction> inputs = <HInstruction>[]; | 3738 List<HInstruction> inputs = <HInstruction>[]; |
| 3886 List<js.Expression> templates = <js.Expression>[]; | 3739 List<js.Expression> templates = <js.Expression>[]; |
| 3887 for (DartType argument in interface.typeArguments) { | 3740 for (DartType argument in interface.typeArguments) { |
| 3888 // As we construct the template in stages, we have to make sure that for | 3741 // As we construct the template in stages, we have to make sure that for |
| 3889 // each part the generated sub-template's holes match the index of the | 3742 // each part the generated sub-template's holes match the index of the |
| 3890 // inputs that are later used to instantiate it. We do this by starting | 3743 // inputs that are later used to instantiate it. We do this by starting |
| 3891 // the indexing with the number of inputs from previous sub-templates. | 3744 // the indexing with the number of inputs from previous sub-templates. |
| 3892 templates.add( | 3745 templates.add(rtiEncoder.getTypeRepresentationWithPlaceholders(argument, |
| 3893 rtiEncoder.getTypeRepresentationWithPlaceholders( | 3746 (variable) { |
| 3894 argument, (variable) { | 3747 HInstruction runtimeType = addTypeVariableReference(variable); |
| 3895 HInstruction runtimeType = addTypeVariableReference(variable); | 3748 inputs.add(runtimeType); |
| 3896 inputs.add(runtimeType); | 3749 }, firstPlaceholderIndex: inputs.length)); |
| 3897 }, firstPlaceholderIndex: inputs.length)); | |
| 3898 } | 3750 } |
| 3899 // TODO(sra): This is a fresh template each time. We can't let the | 3751 // TODO(sra): This is a fresh template each time. We can't let the |
| 3900 // template manager build them. | 3752 // template manager build them. |
| 3901 js.Template code = new js.Template(null, | 3753 js.Template code = |
| 3902 new js.ArrayInitializer(templates)); | 3754 new js.Template(null, new js.ArrayInitializer(templates)); |
| 3903 HInstruction representation = | 3755 HInstruction representation = new HForeignCode( |
| 3904 new HForeignCode(code, backend.readableArrayType, inputs, | 3756 code, backend.readableArrayType, inputs, |
| 3905 nativeBehavior: native.NativeBehavior.PURE_ALLOCATION); | 3757 nativeBehavior: native.NativeBehavior.PURE_ALLOCATION); |
| 3906 return representation; | 3758 return representation; |
| 3907 } | 3759 } |
| 3908 } | 3760 } |
| 3909 | 3761 |
| 3910 @override | 3762 @override |
| 3911 void visitAs(ast.Send node, ast.Node expression, DartType type, _) { | 3763 void visitAs(ast.Send node, ast.Node expression, DartType type, _) { |
| 3912 HInstruction expressionInstruction = visitAndPop(expression); | 3764 HInstruction expressionInstruction = visitAndPop(expression); |
| 3913 if (type.isMalformed) { | 3765 if (type.isMalformed) { |
| 3914 ErroneousElement element = type.element; | 3766 ErroneousElement element = type.element; |
| 3915 generateTypeError(node, element.message); | 3767 generateTypeError(node, element.message); |
| 3916 } else { | 3768 } else { |
| 3917 HInstruction converted = buildTypeConversion( | 3769 HInstruction converted = buildTypeConversion(expressionInstruction, |
| 3918 expressionInstruction, | 3770 localsHandler.substInContext(type), HTypeConversion.CAST_TYPE_CHECK); |
| 3919 localsHandler.substInContext(type), | |
| 3920 HTypeConversion.CAST_TYPE_CHECK); | |
| 3921 if (converted != expressionInstruction) add(converted); | 3771 if (converted != expressionInstruction) add(converted); |
| 3922 stack.add(converted); | 3772 stack.add(converted); |
| 3923 } | 3773 } |
| 3924 } | 3774 } |
| 3925 | 3775 |
| 3926 @override | 3776 @override |
| 3927 void visitIs(ast.Send node, ast.Node expression, DartType type, _) { | 3777 void visitIs(ast.Send node, ast.Node expression, DartType type, _) { |
| 3928 HInstruction expressionInstruction = visitAndPop(expression); | 3778 HInstruction expressionInstruction = visitAndPop(expression); |
| 3929 push(buildIsNode(node, type, expressionInstruction)); | 3779 push(buildIsNode(node, type, expressionInstruction)); |
| 3930 } | 3780 } |
| 3931 | 3781 |
| 3932 @override | 3782 @override |
| 3933 void visitIsNot(ast.Send node, ast.Node expression, DartType type, _) { | 3783 void visitIsNot(ast.Send node, ast.Node expression, DartType type, _) { |
| 3934 HInstruction expressionInstruction = visitAndPop(expression); | 3784 HInstruction expressionInstruction = visitAndPop(expression); |
| 3935 HInstruction instruction = buildIsNode(node, type, expressionInstruction); | 3785 HInstruction instruction = buildIsNode(node, type, expressionInstruction); |
| 3936 add(instruction); | 3786 add(instruction); |
| 3937 push(new HNot(instruction, backend.boolType)); | 3787 push(new HNot(instruction, backend.boolType)); |
| 3938 } | 3788 } |
| 3939 | 3789 |
| 3940 HInstruction buildIsNode(ast.Node node, | 3790 HInstruction buildIsNode( |
| 3941 DartType type, | 3791 ast.Node node, DartType type, HInstruction expression) { |
| 3942 HInstruction expression) { | |
| 3943 type = localsHandler.substInContext(type).unaliased; | 3792 type = localsHandler.substInContext(type).unaliased; |
| 3944 if (type.isFunctionType) { | 3793 if (type.isFunctionType) { |
| 3945 List arguments = [buildFunctionType(type), expression]; | 3794 List arguments = [buildFunctionType(type), expression]; |
| 3946 pushInvokeDynamic( | 3795 pushInvokeDynamic( |
| 3947 node, | 3796 node, |
| 3948 new Selector.call( | 3797 new Selector.call(new PrivateName('_isTest', helpers.jsHelperLibrary), |
| 3949 new PrivateName('_isTest', helpers.jsHelperLibrary), | |
| 3950 CallStructure.ONE_ARG), | 3798 CallStructure.ONE_ARG), |
| 3951 null, | 3799 null, |
| 3952 arguments); | 3800 arguments); |
| 3953 return new HIs.compound(type, expression, pop(), backend.boolType); | 3801 return new HIs.compound(type, expression, pop(), backend.boolType); |
| 3954 } else if (type.isTypeVariable) { | 3802 } else if (type.isTypeVariable) { |
| 3955 HInstruction runtimeType = addTypeVariableReference(type); | 3803 HInstruction runtimeType = addTypeVariableReference(type); |
| 3956 Element helper = helpers.checkSubtypeOfRuntimeType; | 3804 Element helper = helpers.checkSubtypeOfRuntimeType; |
| 3957 List<HInstruction> inputs = <HInstruction>[expression, runtimeType]; | 3805 List<HInstruction> inputs = <HInstruction>[expression, runtimeType]; |
| 3958 pushInvokeStatic(null, helper, inputs, typeMask: backend.boolType); | 3806 pushInvokeStatic(null, helper, inputs, typeMask: backend.boolType); |
| 3959 HInstruction call = pop(); | 3807 HInstruction call = pop(); |
| 3960 return new HIs.variable(type, expression, call, backend.boolType); | 3808 return new HIs.variable(type, expression, call, backend.boolType); |
| 3961 } else if (RuntimeTypes.hasTypeArguments(type)) { | 3809 } else if (RuntimeTypes.hasTypeArguments(type)) { |
| 3962 ClassElement element = type.element; | 3810 ClassElement element = type.element; |
| 3963 Element helper = helpers.checkSubtype; | 3811 Element helper = helpers.checkSubtype; |
| 3964 HInstruction representations = | 3812 HInstruction representations = buildTypeArgumentRepresentations(type); |
| 3965 buildTypeArgumentRepresentations(type); | |
| 3966 add(representations); | 3813 add(representations); |
| 3967 js.Name operator = backend.namer.operatorIs(element); | 3814 js.Name operator = backend.namer.operatorIs(element); |
| 3968 HInstruction isFieldName = addConstantStringFromName(operator); | 3815 HInstruction isFieldName = addConstantStringFromName(operator); |
| 3969 HInstruction asFieldName = compiler.world.hasAnyStrictSubtype(element) | 3816 HInstruction asFieldName = compiler.world.hasAnyStrictSubtype(element) |
| 3970 ? addConstantStringFromName(backend.namer.substitutionName(element)) | 3817 ? addConstantStringFromName(backend.namer.substitutionName(element)) |
| 3971 : graph.addConstantNull(compiler); | 3818 : graph.addConstantNull(compiler); |
| 3972 List<HInstruction> inputs = <HInstruction>[expression, | 3819 List<HInstruction> inputs = <HInstruction>[ |
| 3973 isFieldName, | 3820 expression, |
| 3974 representations, | 3821 isFieldName, |
| 3975 asFieldName]; | 3822 representations, |
| 3823 asFieldName |
| 3824 ]; |
| 3976 pushInvokeStatic(node, helper, inputs, typeMask: backend.boolType); | 3825 pushInvokeStatic(node, helper, inputs, typeMask: backend.boolType); |
| 3977 HInstruction call = pop(); | 3826 HInstruction call = pop(); |
| 3978 return new HIs.compound(type, expression, call, backend.boolType); | 3827 return new HIs.compound(type, expression, call, backend.boolType); |
| 3979 } else if (type.isMalformed) { | 3828 } else if (type.isMalformed) { |
| 3980 ErroneousElement element = type.element; | 3829 ErroneousElement element = type.element; |
| 3981 generateTypeError(node, element.message); | 3830 generateTypeError(node, element.message); |
| 3982 HInstruction call = pop(); | 3831 HInstruction call = pop(); |
| 3983 return new HIs.compound(type, expression, call, backend.boolType); | 3832 return new HIs.compound(type, expression, call, backend.boolType); |
| 3984 } else { | 3833 } else { |
| 3985 if (backend.hasDirectCheckFor(type)) { | 3834 if (backend.hasDirectCheckFor(type)) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 3999 | 3848 |
| 4000 void addDynamicSendArgumentsToList(ast.Send node, List<HInstruction> list) { | 3849 void addDynamicSendArgumentsToList(ast.Send node, List<HInstruction> list) { |
| 4001 CallStructure callStructure = elements.getSelector(node).callStructure; | 3850 CallStructure callStructure = elements.getSelector(node).callStructure; |
| 4002 if (callStructure.namedArgumentCount == 0) { | 3851 if (callStructure.namedArgumentCount == 0) { |
| 4003 addGenericSendArgumentsToList(node.arguments, list); | 3852 addGenericSendArgumentsToList(node.arguments, list); |
| 4004 } else { | 3853 } else { |
| 4005 // Visit positional arguments and add them to the list. | 3854 // Visit positional arguments and add them to the list. |
| 4006 Link<ast.Node> arguments = node.arguments; | 3855 Link<ast.Node> arguments = node.arguments; |
| 4007 int positionalArgumentCount = callStructure.positionalArgumentCount; | 3856 int positionalArgumentCount = callStructure.positionalArgumentCount; |
| 4008 for (int i = 0; | 3857 for (int i = 0; |
| 4009 i < positionalArgumentCount; | 3858 i < positionalArgumentCount; |
| 4010 arguments = arguments.tail, i++) { | 3859 arguments = arguments.tail, i++) { |
| 4011 visit(arguments.head); | 3860 visit(arguments.head); |
| 4012 list.add(pop()); | 3861 list.add(pop()); |
| 4013 } | 3862 } |
| 4014 | 3863 |
| 4015 // Visit named arguments and add them into a temporary map. | 3864 // Visit named arguments and add them into a temporary map. |
| 4016 Map<String, HInstruction> instructions = | 3865 Map<String, HInstruction> instructions = new Map<String, HInstruction>(); |
| 4017 new Map<String, HInstruction>(); | |
| 4018 List<String> namedArguments = callStructure.namedArguments; | 3866 List<String> namedArguments = callStructure.namedArguments; |
| 4019 int nameIndex = 0; | 3867 int nameIndex = 0; |
| 4020 for (; !arguments.isEmpty; arguments = arguments.tail) { | 3868 for (; !arguments.isEmpty; arguments = arguments.tail) { |
| 4021 visit(arguments.head); | 3869 visit(arguments.head); |
| 4022 instructions[namedArguments[nameIndex++]] = pop(); | 3870 instructions[namedArguments[nameIndex++]] = pop(); |
| 4023 } | 3871 } |
| 4024 | 3872 |
| 4025 // Iterate through the named arguments to add them to the list | 3873 // Iterate through the named arguments to add them to the list |
| 4026 // of instructions, in an order that can be shared with | 3874 // of instructions, in an order that can be shared with |
| 4027 // selectors with the same named arguments. | 3875 // selectors with the same named arguments. |
| 4028 List<String> orderedNames = callStructure.getOrderedNamedArguments(); | 3876 List<String> orderedNames = callStructure.getOrderedNamedArguments(); |
| 4029 for (String name in orderedNames) { | 3877 for (String name in orderedNames) { |
| 4030 list.add(instructions[name]); | 3878 list.add(instructions[name]); |
| 4031 } | 3879 } |
| 4032 } | 3880 } |
| 4033 } | 3881 } |
| 4034 | 3882 |
| 4035 /** | 3883 /** |
| 4036 * Returns a list with the evaluated [arguments] in the normalized order. | 3884 * Returns a list with the evaluated [arguments] in the normalized order. |
| 4037 * | 3885 * |
| 4038 * Precondition: `this.applies(element, world)`. | 3886 * Precondition: `this.applies(element, world)`. |
| 4039 * Invariant: [element] must be an implementation element. | 3887 * Invariant: [element] must be an implementation element. |
| 4040 */ | 3888 */ |
| 4041 List<HInstruction> makeStaticArgumentList(CallStructure callStructure, | 3889 List<HInstruction> makeStaticArgumentList(CallStructure callStructure, |
| 4042 Link<ast.Node> arguments, | 3890 Link<ast.Node> arguments, FunctionElement element) { |
| 4043 FunctionElement element) { | |
| 4044 assert(invariant(element, element.isImplementation)); | 3891 assert(invariant(element, element.isImplementation)); |
| 4045 | 3892 |
| 4046 HInstruction compileArgument(ast.Node argument) { | 3893 HInstruction compileArgument(ast.Node argument) { |
| 4047 visit(argument); | 3894 visit(argument); |
| 4048 return pop(); | 3895 return pop(); |
| 4049 } | 3896 } |
| 4050 | 3897 |
| 4051 return callStructure.makeArgumentsList( | 3898 return callStructure.makeArgumentsList( |
| 4052 arguments, | 3899 arguments, |
| 4053 element, | 3900 element, |
| 4054 compileArgument, | 3901 compileArgument, |
| 4055 backend.isJsInterop(element) ? | 3902 backend.isJsInterop(element) |
| 4056 handleConstantForOptionalParameterJsInterop : | 3903 ? handleConstantForOptionalParameterJsInterop |
| 4057 handleConstantForOptionalParameter); | 3904 : handleConstantForOptionalParameter); |
| 4058 } | 3905 } |
| 4059 | 3906 |
| 4060 void addGenericSendArgumentsToList(Link<ast.Node> link, List<HInstruction> lis
t) { | 3907 void addGenericSendArgumentsToList( |
| 3908 Link<ast.Node> link, List<HInstruction> list) { |
| 4061 for (; !link.isEmpty; link = link.tail) { | 3909 for (; !link.isEmpty; link = link.tail) { |
| 4062 visit(link.head); | 3910 visit(link.head); |
| 4063 list.add(pop()); | 3911 list.add(pop()); |
| 4064 } | 3912 } |
| 4065 } | 3913 } |
| 4066 | 3914 |
| 4067 /// Generate a dynamic method, getter or setter invocation. | 3915 /// Generate a dynamic method, getter or setter invocation. |
| 4068 void generateDynamicSend(ast.Send node) { | 3916 void generateDynamicSend(ast.Send node) { |
| 4069 HInstruction receiver = generateInstanceSendReceiver(node); | 3917 HInstruction receiver = generateInstanceSendReceiver(node); |
| 4070 _generateDynamicSend(node, receiver); | 3918 _generateDynamicSend(node, receiver); |
| 4071 } | 3919 } |
| 4072 | 3920 |
| 4073 void _generateDynamicSend(ast.Send node, HInstruction receiver) { | 3921 void _generateDynamicSend(ast.Send node, HInstruction receiver) { |
| 4074 Selector selector = elements.getSelector(node); | 3922 Selector selector = elements.getSelector(node); |
| 4075 TypeMask mask = elements.getTypeMask(node); | 3923 TypeMask mask = elements.getTypeMask(node); |
| 4076 SourceInformation sourceInformation = | 3924 SourceInformation sourceInformation = |
| 4077 sourceInformationBuilder.buildCall(node, node.selector); | 3925 sourceInformationBuilder.buildCall(node, node.selector); |
| 4078 | 3926 |
| 4079 List<HInstruction> inputs = <HInstruction>[]; | 3927 List<HInstruction> inputs = <HInstruction>[]; |
| 4080 inputs.add(receiver); | 3928 inputs.add(receiver); |
| 4081 addDynamicSendArgumentsToList(node, inputs); | 3929 addDynamicSendArgumentsToList(node, inputs); |
| 4082 | 3930 |
| 4083 pushInvokeDynamic(node, selector, mask, inputs, | 3931 pushInvokeDynamic(node, selector, mask, inputs, |
| 4084 sourceInformation: sourceInformation); | 3932 sourceInformation: sourceInformation); |
| 4085 if (selector.isSetter || selector.isIndexSet) { | 3933 if (selector.isSetter || selector.isIndexSet) { |
| 4086 pop(); | 3934 pop(); |
| 4087 stack.add(inputs.last); | 3935 stack.add(inputs.last); |
| 4088 } | 3936 } |
| 4089 } | 3937 } |
| 4090 | 3938 |
| 4091 @override | 3939 @override |
| 4092 visitDynamicPropertyInvoke( | 3940 visitDynamicPropertyInvoke(ast.Send node, ast.Node receiver, |
| 4093 ast.Send node, | 3941 ast.NodeList arguments, Selector selector, _) { |
| 4094 ast.Node receiver, | |
| 4095 ast.NodeList arguments, | |
| 4096 Selector selector, | |
| 4097 _) { | |
| 4098 generateDynamicSend(node); | 3942 generateDynamicSend(node); |
| 4099 } | 3943 } |
| 4100 | 3944 |
| 4101 @override | 3945 @override |
| 4102 visitIfNotNullDynamicPropertyInvoke( | 3946 visitIfNotNullDynamicPropertyInvoke(ast.Send node, ast.Node receiver, |
| 4103 ast.Send node, | 3947 ast.NodeList arguments, Selector selector, _) { |
| 4104 ast.Node receiver, | |
| 4105 ast.NodeList arguments, | |
| 4106 Selector selector, | |
| 4107 _) { | |
| 4108 /// Desugar `exp?.m()` to `(t1 = exp) == null ? t1 : t1.m()` | 3948 /// Desugar `exp?.m()` to `(t1 = exp) == null ? t1 : t1.m()` |
| 4109 HInstruction receiver; | 3949 HInstruction receiver; |
| 4110 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 3950 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
| 4111 brancher.handleConditional( | 3951 brancher.handleConditional(() { |
| 4112 () { | 3952 receiver = generateInstanceSendReceiver(node); |
| 4113 receiver = generateInstanceSendReceiver(node); | 3953 pushCheckNull(receiver); |
| 4114 pushCheckNull(receiver); | 3954 }, () => stack.add(receiver), () => _generateDynamicSend(node, receiver)); |
| 4115 }, | |
| 4116 () => stack.add(receiver), | |
| 4117 () => _generateDynamicSend(node, receiver)); | |
| 4118 } | 3955 } |
| 4119 | 3956 |
| 4120 @override | 3957 @override |
| 4121 visitThisPropertyInvoke( | 3958 visitThisPropertyInvoke( |
| 4122 ast.Send node, | 3959 ast.Send node, ast.NodeList arguments, Selector selector, _) { |
| 4123 ast.NodeList arguments, | |
| 4124 Selector selector, | |
| 4125 _) { | |
| 4126 generateDynamicSend(node); | 3960 generateDynamicSend(node); |
| 4127 } | 3961 } |
| 4128 | 3962 |
| 4129 @override | 3963 @override |
| 4130 visitExpressionInvoke( | 3964 visitExpressionInvoke(ast.Send node, ast.Node expression, |
| 4131 ast.Send node, | 3965 ast.NodeList arguments, CallStructure callStructure, _) { |
| 4132 ast.Node expression, | 3966 generateCallInvoke(node, visitAndPop(expression), |
| 4133 ast.NodeList arguments, | |
| 4134 CallStructure callStructure, | |
| 4135 _) { | |
| 4136 generateCallInvoke( | |
| 4137 node, | |
| 4138 visitAndPop(expression), | |
| 4139 sourceInformationBuilder.buildCall(node, node.argumentsNode)); | 3967 sourceInformationBuilder.buildCall(node, node.argumentsNode)); |
| 4140 } | 3968 } |
| 4141 | 3969 |
| 4142 @override | 3970 @override |
| 4143 visitThisInvoke( | 3971 visitThisInvoke( |
| 4144 ast.Send node, | 3972 ast.Send node, ast.NodeList arguments, CallStructure callStructure, _) { |
| 4145 ast.NodeList arguments, | 3973 generateCallInvoke(node, localsHandler.readThis(), |
| 4146 CallStructure callStructure, | |
| 4147 _) { | |
| 4148 generateCallInvoke( | |
| 4149 node, | |
| 4150 localsHandler.readThis(), | |
| 4151 sourceInformationBuilder.buildCall(node, node.argumentsNode)); | 3974 sourceInformationBuilder.buildCall(node, node.argumentsNode)); |
| 4152 } | 3975 } |
| 4153 | 3976 |
| 4154 @override | 3977 @override |
| 4155 visitParameterInvoke( | 3978 visitParameterInvoke(ast.Send node, ParameterElement parameter, |
| 4156 ast.Send node, | 3979 ast.NodeList arguments, CallStructure callStructure, _) { |
| 4157 ParameterElement parameter, | 3980 generateCallInvoke(node, localsHandler.readLocal(parameter), |
| 4158 ast.NodeList arguments, | |
| 4159 CallStructure callStructure, | |
| 4160 _) { | |
| 4161 generateCallInvoke( | |
| 4162 node, | |
| 4163 localsHandler.readLocal(parameter), | |
| 4164 sourceInformationBuilder.buildCall(node, node.argumentsNode)); | 3981 sourceInformationBuilder.buildCall(node, node.argumentsNode)); |
| 4165 } | 3982 } |
| 4166 | 3983 |
| 4167 @override | 3984 @override |
| 4168 visitLocalVariableInvoke( | 3985 visitLocalVariableInvoke(ast.Send node, LocalVariableElement variable, |
| 4169 ast.Send node, | 3986 ast.NodeList arguments, CallStructure callStructure, _) { |
| 4170 LocalVariableElement variable, | 3987 generateCallInvoke(node, localsHandler.readLocal(variable), |
| 4171 ast.NodeList arguments, | |
| 4172 CallStructure callStructure, | |
| 4173 _) { | |
| 4174 generateCallInvoke( | |
| 4175 node, | |
| 4176 localsHandler.readLocal(variable), | |
| 4177 sourceInformationBuilder.buildCall(node, node.argumentsNode)); | 3988 sourceInformationBuilder.buildCall(node, node.argumentsNode)); |
| 4178 } | 3989 } |
| 4179 | 3990 |
| 4180 @override | 3991 @override |
| 4181 visitLocalFunctionInvoke( | 3992 visitLocalFunctionInvoke(ast.Send node, LocalFunctionElement function, |
| 4182 ast.Send node, | 3993 ast.NodeList arguments, CallStructure callStructure, _) { |
| 4183 LocalFunctionElement function, | 3994 generateCallInvoke(node, localsHandler.readLocal(function), |
| 4184 ast.NodeList arguments, | |
| 4185 CallStructure callStructure, | |
| 4186 _) { | |
| 4187 generateCallInvoke( | |
| 4188 node, | |
| 4189 localsHandler.readLocal(function), | |
| 4190 sourceInformationBuilder.buildCall(node, node.argumentsNode)); | 3995 sourceInformationBuilder.buildCall(node, node.argumentsNode)); |
| 4191 } | 3996 } |
| 4192 | 3997 |
| 4193 @override | 3998 @override |
| 4194 visitLocalFunctionIncompatibleInvoke( | 3999 visitLocalFunctionIncompatibleInvoke( |
| 4195 ast.Send node, | 4000 ast.Send node, |
| 4196 LocalFunctionElement function, | 4001 LocalFunctionElement function, |
| 4197 ast.NodeList arguments, | 4002 ast.NodeList arguments, |
| 4198 CallStructure callStructure, | 4003 CallStructure callStructure, |
| 4199 _) { | 4004 _) { |
| 4200 generateCallInvoke(node, localsHandler.readLocal(function), | 4005 generateCallInvoke(node, localsHandler.readLocal(function), |
| 4201 sourceInformationBuilder.buildCall(node, node.argumentsNode)); | 4006 sourceInformationBuilder.buildCall(node, node.argumentsNode)); |
| 4202 } | 4007 } |
| 4203 | 4008 |
| 4204 void handleForeignJs(ast.Send node) { | 4009 void handleForeignJs(ast.Send node) { |
| 4205 Link<ast.Node> link = node.arguments; | 4010 Link<ast.Node> link = node.arguments; |
| 4206 // Don't visit the first argument, which is the type, and the second | 4011 // Don't visit the first argument, which is the type, and the second |
| 4207 // argument, which is the foreign code. | 4012 // argument, which is the foreign code. |
| 4208 if (link.isEmpty || link.tail.isEmpty) { | 4013 if (link.isEmpty || link.tail.isEmpty) { |
| 4209 // We should not get here because the call should be compiled to NSM. | 4014 // We should not get here because the call should be compiled to NSM. |
| 4210 reporter.internalError(node.argumentsNode, | 4015 reporter.internalError( |
| 4211 'At least two arguments expected.'); | 4016 node.argumentsNode, 'At least two arguments expected.'); |
| 4212 } | 4017 } |
| 4213 native.NativeBehavior nativeBehavior = | 4018 native.NativeBehavior nativeBehavior = |
| 4214 compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node); | 4019 compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node); |
| 4215 | 4020 |
| 4216 List<HInstruction> inputs = <HInstruction>[]; | 4021 List<HInstruction> inputs = <HInstruction>[]; |
| 4217 addGenericSendArgumentsToList(link.tail.tail, inputs); | 4022 addGenericSendArgumentsToList(link.tail.tail, inputs); |
| 4218 | 4023 |
| 4219 if (nativeBehavior.codeTemplate.positionalArgumentCount != inputs.length) { | 4024 if (nativeBehavior.codeTemplate.positionalArgumentCount != inputs.length) { |
| 4220 reporter.reportErrorMessage( | 4025 reporter.reportErrorMessage(node, MessageKind.GENERIC, { |
| 4221 node, MessageKind.GENERIC, | 4026 'text': 'Mismatch between number of placeholders' |
| 4222 {'text': | 4027 ' and number of arguments.' |
| 4223 'Mismatch between number of placeholders' | 4028 }); |
| 4224 ' and number of arguments.'}); | 4029 stack.add(graph.addConstantNull(compiler)); // Result expected on stack. |
| 4225 stack.add(graph.addConstantNull(compiler)); // Result expected on stack. | |
| 4226 return; | 4030 return; |
| 4227 } | 4031 } |
| 4228 | 4032 |
| 4229 if (native.HasCapturedPlaceholders.check(nativeBehavior.codeTemplate.ast)) { | 4033 if (native.HasCapturedPlaceholders.check(nativeBehavior.codeTemplate.ast)) { |
| 4230 reporter.reportErrorMessage(node, MessageKind.JS_PLACEHOLDER_CAPTURE); | 4034 reporter.reportErrorMessage(node, MessageKind.JS_PLACEHOLDER_CAPTURE); |
| 4231 } | 4035 } |
| 4232 | 4036 |
| 4233 TypeMask ssaType = | 4037 TypeMask ssaType = |
| 4234 TypeMaskFactory.fromNativeBehavior(nativeBehavior, compiler); | 4038 TypeMaskFactory.fromNativeBehavior(nativeBehavior, compiler); |
| 4235 | 4039 |
| 4236 SourceInformation sourceInformation = | 4040 SourceInformation sourceInformation = |
| 4237 sourceInformationBuilder.buildCall(node, node.argumentsNode); | 4041 sourceInformationBuilder.buildCall(node, node.argumentsNode); |
| 4238 if (nativeBehavior.codeTemplate.isExpression) { | 4042 if (nativeBehavior.codeTemplate.isExpression) { |
| 4239 push(new HForeignCode( | 4043 push(new HForeignCode(nativeBehavior.codeTemplate, ssaType, inputs, |
| 4240 nativeBehavior.codeTemplate, ssaType, inputs, | 4044 effects: nativeBehavior.sideEffects, nativeBehavior: nativeBehavior) |
| 4241 effects: nativeBehavior.sideEffects, | 4045 ..sourceInformation = sourceInformation); |
| 4242 nativeBehavior: nativeBehavior) | |
| 4243 ..sourceInformation = sourceInformation); | |
| 4244 } else { | 4046 } else { |
| 4245 push(new HForeignCode( | 4047 push(new HForeignCode(nativeBehavior.codeTemplate, ssaType, inputs, |
| 4246 nativeBehavior.codeTemplate, ssaType, inputs, | |
| 4247 isStatement: true, | 4048 isStatement: true, |
| 4248 effects: nativeBehavior.sideEffects, | 4049 effects: nativeBehavior.sideEffects, |
| 4249 nativeBehavior: nativeBehavior) | 4050 nativeBehavior: nativeBehavior) |
| 4250 ..sourceInformation = sourceInformation); | 4051 ..sourceInformation = sourceInformation); |
| 4251 } | 4052 } |
| 4252 } | 4053 } |
| 4253 | 4054 |
| 4254 void handleJsStringConcat(ast.Send node) { | 4055 void handleJsStringConcat(ast.Send node) { |
| 4255 List<HInstruction> inputs = <HInstruction>[]; | 4056 List<HInstruction> inputs = <HInstruction>[]; |
| 4256 addGenericSendArgumentsToList(node.arguments, inputs); | 4057 addGenericSendArgumentsToList(node.arguments, inputs); |
| 4257 if (inputs.length != 2) { | 4058 if (inputs.length != 2) { |
| 4258 reporter.internalError(node.argumentsNode, 'Two arguments expected.'); | 4059 reporter.internalError(node.argumentsNode, 'Two arguments expected.'); |
| 4259 } | 4060 } |
| 4260 push(new HStringConcat(inputs[0], inputs[1], backend.stringType)); | 4061 push(new HStringConcat(inputs[0], inputs[1], backend.stringType)); |
| 4261 } | 4062 } |
| 4262 | 4063 |
| 4263 void handleForeignJsCurrentIsolateContext(ast.Send node) { | 4064 void handleForeignJsCurrentIsolateContext(ast.Send node) { |
| 4264 if (!node.arguments.isEmpty) { | 4065 if (!node.arguments.isEmpty) { |
| 4265 reporter.internalError(node, | 4066 reporter.internalError( |
| 4266 'Too many arguments to JS_CURRENT_ISOLATE_CONTEXT.'); | 4067 node, 'Too many arguments to JS_CURRENT_ISOLATE_CONTEXT.'); |
| 4267 } | 4068 } |
| 4268 | 4069 |
| 4269 if (!compiler.hasIsolateSupport) { | 4070 if (!compiler.hasIsolateSupport) { |
| 4270 // If the isolate library is not used, we just generate code | 4071 // If the isolate library is not used, we just generate code |
| 4271 // to fetch the static state. | 4072 // to fetch the static state. |
| 4272 String name = backend.namer.staticStateHolder; | 4073 String name = backend.namer.staticStateHolder; |
| 4273 push(new HForeignCode( | 4074 push(new HForeignCode( |
| 4274 js.js.parseForeignJS(name), | 4075 js.js.parseForeignJS(name), backend.dynamicType, <HInstruction>[], |
| 4275 backend.dynamicType, | |
| 4276 <HInstruction>[], | |
| 4277 nativeBehavior: native.NativeBehavior.DEPENDS_OTHER)); | 4076 nativeBehavior: native.NativeBehavior.DEPENDS_OTHER)); |
| 4278 } else { | 4077 } else { |
| 4279 // Call a helper method from the isolate library. The isolate | 4078 // Call a helper method from the isolate library. The isolate |
| 4280 // library uses its own isolate structure, that encapsulates | 4079 // library uses its own isolate structure, that encapsulates |
| 4281 // Leg's isolate. | 4080 // Leg's isolate. |
| 4282 Element element = helpers.currentIsolate; | 4081 Element element = helpers.currentIsolate; |
| 4283 if (element == null) { | 4082 if (element == null) { |
| 4284 reporter.internalError(node, | 4083 reporter.internalError(node, 'Isolate library and compiler mismatch.'); |
| 4285 'Isolate library and compiler mismatch.'); | |
| 4286 } | 4084 } |
| 4287 pushInvokeStatic(null, element, [], typeMask: backend.dynamicType); | 4085 pushInvokeStatic(null, element, [], typeMask: backend.dynamicType); |
| 4288 } | 4086 } |
| 4289 } | 4087 } |
| 4290 | 4088 |
| 4291 void handleForeignJsGetFlag(ast.Send node) { | 4089 void handleForeignJsGetFlag(ast.Send node) { |
| 4292 List<ast.Node> arguments = node.arguments.toList(); | 4090 List<ast.Node> arguments = node.arguments.toList(); |
| 4293 ast.Node argument; | 4091 ast.Node argument; |
| 4294 switch (arguments.length) { | 4092 switch (arguments.length) { |
| 4295 case 0: | 4093 case 0: |
| 4296 reporter.reportErrorMessage( | 4094 reporter.reportErrorMessage(node, MessageKind.GENERIC, |
| 4297 node, MessageKind.GENERIC, | 4095 {'text': 'Error: Expected one argument to JS_GET_FLAG.'}); |
| 4298 {'text': 'Error: Expected one argument to JS_GET_FLAG.'}); | 4096 return; |
| 4299 return; | 4097 case 1: |
| 4300 case 1: | 4098 argument = arguments[0]; |
| 4301 argument = arguments[0]; | 4099 break; |
| 4302 break; | 4100 default: |
| 4303 default: | 4101 for (int i = 1; i < arguments.length; i++) { |
| 4304 for (int i = 1; i < arguments.length; i++) { | 4102 reporter.reportErrorMessage(arguments[i], MessageKind.GENERIC, |
| 4305 reporter.reportErrorMessage( | 4103 {'text': 'Error: Extra argument to JS_GET_FLAG.'}); |
| 4306 arguments[i], MessageKind.GENERIC, | 4104 } |
| 4307 {'text': 'Error: Extra argument to JS_GET_FLAG.'}); | 4105 return; |
| 4308 } | 4106 } |
| 4309 return; | 4107 ast.LiteralString string = argument.asLiteralString(); |
| 4310 } | 4108 if (string == null) { |
| 4311 ast.LiteralString string = argument.asLiteralString(); | 4109 reporter.reportErrorMessage(argument, MessageKind.GENERIC, |
| 4312 if (string == null) { | 4110 {'text': 'Error: Expected a literal string.'}); |
| 4313 reporter.reportErrorMessage( | 4111 } |
| 4314 argument, MessageKind.GENERIC, | 4112 String name = string.dartString.slowToString(); |
| 4315 {'text': 'Error: Expected a literal string.'}); | 4113 bool value = false; |
| 4316 } | 4114 switch (name) { |
| 4317 String name = string.dartString.slowToString(); | 4115 case 'MUST_RETAIN_METADATA': |
| 4318 bool value = false; | 4116 value = backend.mustRetainMetadata; |
| 4319 switch (name) { | 4117 break; |
| 4320 case 'MUST_RETAIN_METADATA': | 4118 case 'USE_CONTENT_SECURITY_POLICY': |
| 4321 value = backend.mustRetainMetadata; | 4119 value = compiler.options.useContentSecurityPolicy; |
| 4322 break; | 4120 break; |
| 4323 case 'USE_CONTENT_SECURITY_POLICY': | 4121 default: |
| 4324 value = compiler.options.useContentSecurityPolicy; | 4122 reporter.reportErrorMessage(node, MessageKind.GENERIC, |
| 4325 break; | 4123 {'text': 'Error: Unknown internal flag "$name".'}); |
| 4326 default: | 4124 } |
| 4327 reporter.reportErrorMessage( | 4125 stack.add(graph.addConstantBool(value, compiler)); |
| 4328 node, MessageKind.GENERIC, | |
| 4329 {'text': 'Error: Unknown internal flag "$name".'}); | |
| 4330 } | |
| 4331 stack.add(graph.addConstantBool(value, compiler)); | |
| 4332 } | 4126 } |
| 4333 | 4127 |
| 4334 void handleForeignJsGetName(ast.Send node) { | 4128 void handleForeignJsGetName(ast.Send node) { |
| 4335 List<ast.Node> arguments = node.arguments.toList(); | 4129 List<ast.Node> arguments = node.arguments.toList(); |
| 4336 ast.Node argument; | 4130 ast.Node argument; |
| 4337 switch (arguments.length) { | 4131 switch (arguments.length) { |
| 4338 case 0: | 4132 case 0: |
| 4339 reporter.reportErrorMessage( | 4133 reporter.reportErrorMessage(node, MessageKind.GENERIC, |
| 4340 node, MessageKind.GENERIC, | 4134 {'text': 'Error: Expected one argument to JS_GET_NAME.'}); |
| 4341 {'text': 'Error: Expected one argument to JS_GET_NAME.'}); | 4135 return; |
| 4342 return; | 4136 case 1: |
| 4343 case 1: | 4137 argument = arguments[0]; |
| 4344 argument = arguments[0]; | 4138 break; |
| 4345 break; | 4139 default: |
| 4346 default: | 4140 for (int i = 1; i < arguments.length; i++) { |
| 4347 for (int i = 1; i < arguments.length; i++) { | 4141 reporter.reportErrorMessage(arguments[i], MessageKind.GENERIC, |
| 4348 reporter.reportErrorMessage( | 4142 {'text': 'Error: Extra argument to JS_GET_NAME.'}); |
| 4349 arguments[i], MessageKind.GENERIC, | 4143 } |
| 4350 {'text': 'Error: Extra argument to JS_GET_NAME.'}); | 4144 return; |
| 4351 } | |
| 4352 return; | |
| 4353 } | 4145 } |
| 4354 Element element = elements[argument]; | 4146 Element element = elements[argument]; |
| 4355 if (element == null || | 4147 if (element == null || |
| 4356 element is! FieldElement || | 4148 element is! FieldElement || |
| 4357 element.enclosingClass != helpers.jsGetNameEnum) { | 4149 element.enclosingClass != helpers.jsGetNameEnum) { |
| 4358 reporter.reportErrorMessage( | 4150 reporter.reportErrorMessage(argument, MessageKind.GENERIC, |
| 4359 argument, MessageKind.GENERIC, | |
| 4360 {'text': 'Error: Expected a JsGetName enum value.'}); | 4151 {'text': 'Error: Expected a JsGetName enum value.'}); |
| 4361 } | 4152 } |
| 4362 EnumClassElement enumClass = element.enclosingClass; | 4153 EnumClassElement enumClass = element.enclosingClass; |
| 4363 int index = enumClass.enumValues.indexOf(element); | 4154 int index = enumClass.enumValues.indexOf(element); |
| 4364 stack.add( | 4155 stack.add(addConstantStringFromName( |
| 4365 addConstantStringFromName( | 4156 backend.namer.getNameForJsGetName(argument, JsGetName.values[index]))); |
| 4366 backend.namer.getNameForJsGetName( | |
| 4367 argument, JsGetName.values[index]))); | |
| 4368 } | 4157 } |
| 4369 | 4158 |
| 4370 void handleForeignJsBuiltin(ast.Send node) { | 4159 void handleForeignJsBuiltin(ast.Send node) { |
| 4371 List<ast.Node> arguments = node.arguments.toList(); | 4160 List<ast.Node> arguments = node.arguments.toList(); |
| 4372 ast.Node argument; | 4161 ast.Node argument; |
| 4373 if (arguments.length < 2) { | 4162 if (arguments.length < 2) { |
| 4374 reporter.reportErrorMessage( | 4163 reporter.reportErrorMessage(node, MessageKind.GENERIC, |
| 4375 node, MessageKind.GENERIC, | |
| 4376 {'text': 'Error: Expected at least two arguments to JS_BUILTIN.'}); | 4164 {'text': 'Error: Expected at least two arguments to JS_BUILTIN.'}); |
| 4377 } | 4165 } |
| 4378 | 4166 |
| 4379 Element builtinElement = elements[arguments[1]]; | 4167 Element builtinElement = elements[arguments[1]]; |
| 4380 if (builtinElement == null || | 4168 if (builtinElement == null || |
| 4381 (builtinElement is! FieldElement) || | 4169 (builtinElement is! FieldElement) || |
| 4382 builtinElement.enclosingClass != helpers.jsBuiltinEnum) { | 4170 builtinElement.enclosingClass != helpers.jsBuiltinEnum) { |
| 4383 reporter.reportErrorMessage( | 4171 reporter.reportErrorMessage(argument, MessageKind.GENERIC, |
| 4384 argument, MessageKind.GENERIC, | |
| 4385 {'text': 'Error: Expected a JsBuiltin enum value.'}); | 4172 {'text': 'Error: Expected a JsBuiltin enum value.'}); |
| 4386 } | 4173 } |
| 4387 EnumClassElement enumClass = builtinElement.enclosingClass; | 4174 EnumClassElement enumClass = builtinElement.enclosingClass; |
| 4388 int index = enumClass.enumValues.indexOf(builtinElement); | 4175 int index = enumClass.enumValues.indexOf(builtinElement); |
| 4389 | 4176 |
| 4390 js.Template template = | 4177 js.Template template = |
| 4391 backend.emitter.builtinTemplateFor(JsBuiltin.values[index]); | 4178 backend.emitter.builtinTemplateFor(JsBuiltin.values[index]); |
| 4392 | 4179 |
| 4393 List<HInstruction> compiledArguments = <HInstruction>[]; | 4180 List<HInstruction> compiledArguments = <HInstruction>[]; |
| 4394 for (int i = 2; i < arguments.length; i++) { | 4181 for (int i = 2; i < arguments.length; i++) { |
| 4395 visit(arguments[i]); | 4182 visit(arguments[i]); |
| 4396 compiledArguments.add(pop()); | 4183 compiledArguments.add(pop()); |
| 4397 } | 4184 } |
| 4398 | 4185 |
| 4399 native.NativeBehavior nativeBehavior = | 4186 native.NativeBehavior nativeBehavior = |
| 4400 compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node); | 4187 compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node); |
| 4401 | 4188 |
| 4402 TypeMask ssaType = | 4189 TypeMask ssaType = |
| 4403 TypeMaskFactory.fromNativeBehavior(nativeBehavior, compiler); | 4190 TypeMaskFactory.fromNativeBehavior(nativeBehavior, compiler); |
| 4404 | 4191 |
| 4405 push(new HForeignCode(template, | 4192 push(new HForeignCode(template, ssaType, compiledArguments, |
| 4406 ssaType, | 4193 nativeBehavior: nativeBehavior)); |
| 4407 compiledArguments, | |
| 4408 nativeBehavior: nativeBehavior)); | |
| 4409 } | 4194 } |
| 4410 | 4195 |
| 4411 void handleForeignJsEmbeddedGlobal(ast.Send node) { | 4196 void handleForeignJsEmbeddedGlobal(ast.Send node) { |
| 4412 List<ast.Node> arguments = node.arguments.toList(); | 4197 List<ast.Node> arguments = node.arguments.toList(); |
| 4413 ast.Node globalNameNode; | 4198 ast.Node globalNameNode; |
| 4414 switch (arguments.length) { | 4199 switch (arguments.length) { |
| 4415 case 0: | 4200 case 0: |
| 4416 case 1: | 4201 case 1: |
| 4417 reporter.reportErrorMessage( | 4202 reporter.reportErrorMessage(node, MessageKind.GENERIC, |
| 4418 node, MessageKind.GENERIC, | 4203 {'text': 'Error: Expected two arguments to JS_EMBEDDED_GLOBAL.'}); |
| 4419 {'text': 'Error: Expected two arguments to JS_EMBEDDED_GLOBAL.'}); | 4204 return; |
| 4420 return; | 4205 case 2: |
| 4421 case 2: | 4206 // The type has been extracted earlier. We are only interested in the |
| 4422 // The type has been extracted earlier. We are only interested in the | 4207 // name in this function. |
| 4423 // name in this function. | 4208 globalNameNode = arguments[1]; |
| 4424 globalNameNode = arguments[1]; | 4209 break; |
| 4425 break; | 4210 default: |
| 4426 default: | 4211 for (int i = 2; i < arguments.length; i++) { |
| 4427 for (int i = 2; i < arguments.length; i++) { | 4212 reporter.reportErrorMessage(arguments[i], MessageKind.GENERIC, |
| 4428 reporter.reportErrorMessage( | 4213 {'text': 'Error: Extra argument to JS_EMBEDDED_GLOBAL.'}); |
| 4429 arguments[i], MessageKind.GENERIC, | 4214 } |
| 4430 {'text': 'Error: Extra argument to JS_EMBEDDED_GLOBAL.'}); | 4215 return; |
| 4431 } | |
| 4432 return; | |
| 4433 } | 4216 } |
| 4434 visit(globalNameNode); | 4217 visit(globalNameNode); |
| 4435 HInstruction globalNameHNode = pop(); | 4218 HInstruction globalNameHNode = pop(); |
| 4436 if (!globalNameHNode.isConstantString()) { | 4219 if (!globalNameHNode.isConstantString()) { |
| 4437 reporter.reportErrorMessage( | 4220 reporter.reportErrorMessage(arguments[1], MessageKind.GENERIC, { |
| 4438 arguments[1], MessageKind.GENERIC, | 4221 'text': 'Error: Expected String as second argument ' |
| 4439 {'text': 'Error: Expected String as second argument ' | 4222 'to JS_EMBEDDED_GLOBAL.' |
| 4440 'to JS_EMBEDDED_GLOBAL.'}); | 4223 }); |
| 4441 return; | 4224 return; |
| 4442 } | 4225 } |
| 4443 HConstant hConstant = globalNameHNode; | 4226 HConstant hConstant = globalNameHNode; |
| 4444 StringConstantValue constant = hConstant.constant; | 4227 StringConstantValue constant = hConstant.constant; |
| 4445 String globalName = constant.primitiveValue.slowToString(); | 4228 String globalName = constant.primitiveValue.slowToString(); |
| 4446 js.Template expr = js.js.expressionTemplateYielding( | 4229 js.Template expr = js.js.expressionTemplateYielding( |
| 4447 backend.emitter.generateEmbeddedGlobalAccess(globalName)); | 4230 backend.emitter.generateEmbeddedGlobalAccess(globalName)); |
| 4448 native.NativeBehavior nativeBehavior = | 4231 native.NativeBehavior nativeBehavior = |
| 4449 compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node); | 4232 compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node); |
| 4450 TypeMask ssaType = | 4233 TypeMask ssaType = |
| 4451 TypeMaskFactory.fromNativeBehavior(nativeBehavior, compiler); | 4234 TypeMaskFactory.fromNativeBehavior(nativeBehavior, compiler); |
| 4452 push(new HForeignCode(expr, ssaType, const [], | 4235 push(new HForeignCode(expr, ssaType, const [], |
| 4453 nativeBehavior: nativeBehavior)); | 4236 nativeBehavior: nativeBehavior)); |
| 4454 } | 4237 } |
| 4455 | 4238 |
| 4456 void handleJsInterceptorConstant(ast.Send node) { | 4239 void handleJsInterceptorConstant(ast.Send node) { |
| 4457 // Single argument must be a TypeConstant which is converted into a | 4240 // Single argument must be a TypeConstant which is converted into a |
| 4458 // InterceptorConstant. | 4241 // InterceptorConstant. |
| 4459 if (!node.arguments.isEmpty && node.arguments.tail.isEmpty) { | 4242 if (!node.arguments.isEmpty && node.arguments.tail.isEmpty) { |
| 4460 ast.Node argument = node.arguments.head; | 4243 ast.Node argument = node.arguments.head; |
| 4461 visit(argument); | 4244 visit(argument); |
| 4462 HInstruction argumentInstruction = pop(); | 4245 HInstruction argumentInstruction = pop(); |
| 4463 if (argumentInstruction is HConstant) { | 4246 if (argumentInstruction is HConstant) { |
| 4464 ConstantValue argumentConstant = argumentInstruction.constant; | 4247 ConstantValue argumentConstant = argumentInstruction.constant; |
| 4465 if (argumentConstant is TypeConstantValue) { | 4248 if (argumentConstant is TypeConstantValue) { |
| 4466 ConstantValue constant = | 4249 ConstantValue constant = |
| 4467 new InterceptorConstantValue(argumentConstant.representedType); | 4250 new InterceptorConstantValue(argumentConstant.representedType); |
| 4468 HInstruction instruction = graph.addConstant(constant, compiler); | 4251 HInstruction instruction = graph.addConstant(constant, compiler); |
| 4469 stack.add(instruction); | 4252 stack.add(instruction); |
| 4470 return; | 4253 return; |
| 4471 } | 4254 } |
| 4472 } | 4255 } |
| 4473 } | 4256 } |
| 4474 reporter.reportErrorMessage( | 4257 reporter.reportErrorMessage( |
| 4475 node, | 4258 node, MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT); |
| 4476 MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT); | |
| 4477 stack.add(graph.addConstantNull(compiler)); | 4259 stack.add(graph.addConstantNull(compiler)); |
| 4478 } | 4260 } |
| 4479 | 4261 |
| 4480 void handleForeignJsCallInIsolate(ast.Send node) { | 4262 void handleForeignJsCallInIsolate(ast.Send node) { |
| 4481 Link<ast.Node> link = node.arguments; | 4263 Link<ast.Node> link = node.arguments; |
| 4482 if (!compiler.hasIsolateSupport) { | 4264 if (!compiler.hasIsolateSupport) { |
| 4483 // If the isolate library is not used, we just invoke the | 4265 // If the isolate library is not used, we just invoke the |
| 4484 // closure. | 4266 // closure. |
| 4485 visit(link.tail.head); | 4267 visit(link.tail.head); |
| 4486 push(new HInvokeClosure(new Selector.callClosure(0), | 4268 push(new HInvokeClosure(new Selector.callClosure(0), |
| 4487 <HInstruction>[pop()], | 4269 <HInstruction>[pop()], backend.dynamicType)); |
| 4488 backend.dynamicType)); | |
| 4489 } else { | 4270 } else { |
| 4490 // Call a helper method from the isolate library. | 4271 // Call a helper method from the isolate library. |
| 4491 Element element = helpers.callInIsolate; | 4272 Element element = helpers.callInIsolate; |
| 4492 if (element == null) { | 4273 if (element == null) { |
| 4493 reporter.internalError(node, | 4274 reporter.internalError(node, 'Isolate library and compiler mismatch.'); |
| 4494 'Isolate library and compiler mismatch.'); | |
| 4495 } | 4275 } |
| 4496 List<HInstruction> inputs = <HInstruction>[]; | 4276 List<HInstruction> inputs = <HInstruction>[]; |
| 4497 addGenericSendArgumentsToList(link, inputs); | 4277 addGenericSendArgumentsToList(link, inputs); |
| 4498 pushInvokeStatic(node, element, inputs, typeMask: backend.dynamicType); | 4278 pushInvokeStatic(node, element, inputs, typeMask: backend.dynamicType); |
| 4499 } | 4279 } |
| 4500 } | 4280 } |
| 4501 | 4281 |
| 4502 FunctionSignature handleForeignRawFunctionRef(ast.Send node, String name) { | 4282 FunctionSignature handleForeignRawFunctionRef(ast.Send node, String name) { |
| 4503 if (node.arguments.isEmpty || !node.arguments.tail.isEmpty) { | 4283 if (node.arguments.isEmpty || !node.arguments.tail.isEmpty) { |
| 4504 reporter.internalError(node.argumentsNode, | 4284 reporter.internalError( |
| 4505 '"$name" requires exactly one argument.'); | 4285 node.argumentsNode, '"$name" requires exactly one argument.'); |
| 4506 } | 4286 } |
| 4507 ast.Node closure = node.arguments.head; | 4287 ast.Node closure = node.arguments.head; |
| 4508 Element element = elements[closure]; | 4288 Element element = elements[closure]; |
| 4509 if (!Elements.isStaticOrTopLevelFunction(element)) { | 4289 if (!Elements.isStaticOrTopLevelFunction(element)) { |
| 4510 reporter.internalError(closure, | 4290 reporter.internalError( |
| 4511 '"$name" requires a static or top-level method.'); | 4291 closure, '"$name" requires a static or top-level method.'); |
| 4512 } | 4292 } |
| 4513 FunctionElement function = element; | 4293 FunctionElement function = element; |
| 4514 // TODO(johnniwinther): Try to eliminate the need to distinguish declaration | 4294 // TODO(johnniwinther): Try to eliminate the need to distinguish declaration |
| 4515 // and implementation signatures. Currently it is need because the | 4295 // and implementation signatures. Currently it is need because the |
| 4516 // signatures have different elements for parameters. | 4296 // signatures have different elements for parameters. |
| 4517 FunctionElement implementation = function.implementation; | 4297 FunctionElement implementation = function.implementation; |
| 4518 FunctionSignature params = implementation.functionSignature; | 4298 FunctionSignature params = implementation.functionSignature; |
| 4519 if (params.optionalParameterCount != 0) { | 4299 if (params.optionalParameterCount != 0) { |
| 4520 reporter.internalError(closure, | 4300 reporter.internalError( |
| 4521 '"$name" does not handle closure with optional parameters.'); | 4301 closure, '"$name" does not handle closure with optional parameters.'); |
| 4522 } | 4302 } |
| 4523 | 4303 |
| 4524 registry?.registerStaticUse( | 4304 registry?.registerStaticUse(new StaticUse.foreignUse(function)); |
| 4525 new StaticUse.foreignUse(function)); | |
| 4526 push(new HForeignCode( | 4305 push(new HForeignCode( |
| 4527 js.js.expressionTemplateYielding( | 4306 js.js.expressionTemplateYielding( |
| 4528 backend.emitter.staticFunctionAccess(function)), | 4307 backend.emitter.staticFunctionAccess(function)), |
| 4529 backend.dynamicType, | 4308 backend.dynamicType, |
| 4530 <HInstruction>[], | 4309 <HInstruction>[], |
| 4531 nativeBehavior: native.NativeBehavior.PURE)); | 4310 nativeBehavior: native.NativeBehavior.PURE)); |
| 4532 return params; | 4311 return params; |
| 4533 } | 4312 } |
| 4534 | 4313 |
| 4535 void handleForeignDartClosureToJs(ast.Send node, String name) { | 4314 void handleForeignDartClosureToJs(ast.Send node, String name) { |
| 4536 // TODO(ahe): This implements DART_CLOSURE_TO_JS and should probably take | 4315 // TODO(ahe): This implements DART_CLOSURE_TO_JS and should probably take |
| 4537 // care to wrap the closure in another closure that saves the current | 4316 // care to wrap the closure in another closure that saves the current |
| 4538 // isolate. | 4317 // isolate. |
| 4539 handleForeignRawFunctionRef(node, name); | 4318 handleForeignRawFunctionRef(node, name); |
| 4540 } | 4319 } |
| 4541 | 4320 |
| 4542 void handleForeignJsSetStaticState(ast.Send node) { | 4321 void handleForeignJsSetStaticState(ast.Send node) { |
| 4543 if (node.arguments.isEmpty || !node.arguments.tail.isEmpty) { | 4322 if (node.arguments.isEmpty || !node.arguments.tail.isEmpty) { |
| 4544 reporter.internalError(node.argumentsNode, | 4323 reporter.internalError( |
| 4545 'Exactly one argument required.'); | 4324 node.argumentsNode, 'Exactly one argument required.'); |
| 4546 } | 4325 } |
| 4547 visit(node.arguments.head); | 4326 visit(node.arguments.head); |
| 4548 String isolateName = backend.namer.staticStateHolder; | 4327 String isolateName = backend.namer.staticStateHolder; |
| 4549 SideEffects sideEffects = new SideEffects.empty(); | 4328 SideEffects sideEffects = new SideEffects.empty(); |
| 4550 sideEffects.setAllSideEffects(); | 4329 sideEffects.setAllSideEffects(); |
| 4551 push(new HForeignCode( | 4330 push(new HForeignCode(js.js.parseForeignJS("$isolateName = #"), |
| 4552 js.js.parseForeignJS("$isolateName = #"), | 4331 backend.dynamicType, <HInstruction>[pop()], |
| 4553 backend.dynamicType, | |
| 4554 <HInstruction>[pop()], | |
| 4555 nativeBehavior: native.NativeBehavior.CHANGES_OTHER, | 4332 nativeBehavior: native.NativeBehavior.CHANGES_OTHER, |
| 4556 effects: sideEffects)); | 4333 effects: sideEffects)); |
| 4557 } | 4334 } |
| 4558 | 4335 |
| 4559 void handleForeignJsGetStaticState(ast.Send node) { | 4336 void handleForeignJsGetStaticState(ast.Send node) { |
| 4560 if (!node.arguments.isEmpty) { | 4337 if (!node.arguments.isEmpty) { |
| 4561 reporter.internalError(node.argumentsNode, 'Too many arguments.'); | 4338 reporter.internalError(node.argumentsNode, 'Too many arguments.'); |
| 4562 } | 4339 } |
| 4563 push(new HForeignCode(js.js.parseForeignJS(backend.namer.staticStateHolder), | 4340 push(new HForeignCode(js.js.parseForeignJS(backend.namer.staticStateHolder), |
| 4564 backend.dynamicType, | 4341 backend.dynamicType, <HInstruction>[], |
| 4565 <HInstruction>[], | 4342 nativeBehavior: native.NativeBehavior.DEPENDS_OTHER)); |
| 4566 nativeBehavior: native.NativeBehavior.DEPENDS_OTHER)); | |
| 4567 } | 4343 } |
| 4568 | 4344 |
| 4569 void handleForeignSend(ast.Send node, FunctionElement element) { | 4345 void handleForeignSend(ast.Send node, FunctionElement element) { |
| 4570 String name = element.name; | 4346 String name = element.name; |
| 4571 if (name == 'JS') { | 4347 if (name == 'JS') { |
| 4572 handleForeignJs(node); | 4348 handleForeignJs(node); |
| 4573 } else if (name == 'JS_CURRENT_ISOLATE_CONTEXT') { | 4349 } else if (name == 'JS_CURRENT_ISOLATE_CONTEXT') { |
| 4574 handleForeignJsCurrentIsolateContext(node); | 4350 handleForeignJsCurrentIsolateContext(node); |
| 4575 } else if (name == 'JS_CALL_IN_ISOLATE') { | 4351 } else if (name == 'JS_CALL_IN_ISOLATE') { |
| 4576 handleForeignJsCallInIsolate(node); | 4352 handleForeignJsCallInIsolate(node); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 4594 stack.add(graph.addConstantNull(compiler)); | 4370 stack.add(graph.addConstantNull(compiler)); |
| 4595 } else if (name == 'JS_INTERCEPTOR_CONSTANT') { | 4371 } else if (name == 'JS_INTERCEPTOR_CONSTANT') { |
| 4596 handleJsInterceptorConstant(node); | 4372 handleJsInterceptorConstant(node); |
| 4597 } else if (name == 'JS_STRING_CONCAT') { | 4373 } else if (name == 'JS_STRING_CONCAT') { |
| 4598 handleJsStringConcat(node); | 4374 handleJsStringConcat(node); |
| 4599 } else { | 4375 } else { |
| 4600 reporter.internalError(node, "Unknown foreign: ${element}"); | 4376 reporter.internalError(node, "Unknown foreign: ${element}"); |
| 4601 } | 4377 } |
| 4602 } | 4378 } |
| 4603 | 4379 |
| 4604 generateDeferredLoaderGet(ast.Send node, | 4380 generateDeferredLoaderGet(ast.Send node, FunctionElement deferredLoader, |
| 4605 FunctionElement deferredLoader, | 4381 SourceInformation sourceInformation) { |
| 4606 SourceInformation sourceInformation) { | |
| 4607 // Until now we only handle these as getters. | 4382 // Until now we only handle these as getters. |
| 4608 invariant(node, deferredLoader.isDeferredLoaderGetter); | 4383 invariant(node, deferredLoader.isDeferredLoaderGetter); |
| 4609 Element loadFunction = compiler.loadLibraryFunction; | 4384 Element loadFunction = compiler.loadLibraryFunction; |
| 4610 PrefixElement prefixElement = deferredLoader.enclosingElement; | 4385 PrefixElement prefixElement = deferredLoader.enclosingElement; |
| 4611 String loadId = | 4386 String loadId = |
| 4612 compiler.deferredLoadTask.getImportDeferName(node, prefixElement); | 4387 compiler.deferredLoadTask.getImportDeferName(node, prefixElement); |
| 4613 var inputs = [graph.addConstantString( | 4388 var inputs = [ |
| 4614 new ast.DartString.literal(loadId), compiler)]; | 4389 graph.addConstantString(new ast.DartString.literal(loadId), compiler) |
| 4390 ]; |
| 4615 push(new HInvokeStatic(loadFunction, inputs, backend.nonNullType, | 4391 push(new HInvokeStatic(loadFunction, inputs, backend.nonNullType, |
| 4616 targetCanThrow: false) | 4392 targetCanThrow: false)..sourceInformation = sourceInformation); |
| 4617 ..sourceInformation = sourceInformation); | |
| 4618 } | 4393 } |
| 4619 | 4394 |
| 4620 generateSuperNoSuchMethodSend(ast.Send node, | 4395 generateSuperNoSuchMethodSend( |
| 4621 Selector selector, | 4396 ast.Send node, Selector selector, List<HInstruction> arguments) { |
| 4622 List<HInstruction> arguments) { | |
| 4623 String name = selector.name; | 4397 String name = selector.name; |
| 4624 | 4398 |
| 4625 ClassElement cls = currentNonClosureClass; | 4399 ClassElement cls = currentNonClosureClass; |
| 4626 MethodElement element = cls.lookupSuperMember(Identifiers.noSuchMethod_); | 4400 MethodElement element = cls.lookupSuperMember(Identifiers.noSuchMethod_); |
| 4627 if (!Selectors.noSuchMethod_.signatureApplies(element)) { | 4401 if (!Selectors.noSuchMethod_.signatureApplies(element)) { |
| 4628 element = coreClasses.objectClass.lookupMember(Identifiers.noSuchMethod_); | 4402 element = coreClasses.objectClass.lookupMember(Identifiers.noSuchMethod_); |
| 4629 } | 4403 } |
| 4630 if (compiler.enabledInvokeOn && !element.enclosingClass.isObject) { | 4404 if (compiler.enabledInvokeOn && !element.enclosingClass.isObject) { |
| 4631 // Register the call as dynamic if [noSuchMethod] on the super | 4405 // Register the call as dynamic if [noSuchMethod] on the super |
| 4632 // class is _not_ the default implementation from [Object], in | 4406 // class is _not_ the default implementation from [Object], in |
| 4633 // case the [noSuchMethod] implementation calls | 4407 // case the [noSuchMethod] implementation calls |
| 4634 // [JSInvocationMirror._invokeOn]. | 4408 // [JSInvocationMirror._invokeOn]. |
| 4635 // TODO(johnniwinther): Register this more precisely. | 4409 // TODO(johnniwinther): Register this more precisely. |
| 4636 registry?.registerDynamicUse(new DynamicUse(selector, null)); | 4410 registry?.registerDynamicUse(new DynamicUse(selector, null)); |
| 4637 } | 4411 } |
| 4638 String publicName = name; | 4412 String publicName = name; |
| 4639 if (selector.isSetter) publicName += '='; | 4413 if (selector.isSetter) publicName += '='; |
| 4640 | 4414 |
| 4641 ConstantValue nameConstant = constantSystem.createString( | 4415 ConstantValue nameConstant = |
| 4642 new ast.DartString.literal(publicName)); | 4416 constantSystem.createString(new ast.DartString.literal(publicName)); |
| 4643 | 4417 |
| 4644 js.Name internalName = backend.namer.invocationName(selector); | 4418 js.Name internalName = backend.namer.invocationName(selector); |
| 4645 | 4419 |
| 4646 Element createInvocationMirror = helpers.createInvocationMirror; | 4420 Element createInvocationMirror = helpers.createInvocationMirror; |
| 4647 var argumentsInstruction = buildLiteralList(arguments); | 4421 var argumentsInstruction = buildLiteralList(arguments); |
| 4648 add(argumentsInstruction); | 4422 add(argumentsInstruction); |
| 4649 | 4423 |
| 4650 var argumentNames = new List<HInstruction>(); | 4424 var argumentNames = new List<HInstruction>(); |
| 4651 for (String argumentName in selector.namedArguments) { | 4425 for (String argumentName in selector.namedArguments) { |
| 4652 ConstantValue argumentNameConstant = | 4426 ConstantValue argumentNameConstant = |
| 4653 constantSystem.createString(new ast.DartString.literal(argumentName)); | 4427 constantSystem.createString(new ast.DartString.literal(argumentName)); |
| 4654 argumentNames.add(graph.addConstant(argumentNameConstant, compiler)); | 4428 argumentNames.add(graph.addConstant(argumentNameConstant, compiler)); |
| 4655 } | 4429 } |
| 4656 var argumentNamesInstruction = buildLiteralList(argumentNames); | 4430 var argumentNamesInstruction = buildLiteralList(argumentNames); |
| 4657 add(argumentNamesInstruction); | 4431 add(argumentNamesInstruction); |
| 4658 | 4432 |
| 4659 ConstantValue kindConstant = | 4433 ConstantValue kindConstant = |
| 4660 constantSystem.createInt(selector.invocationMirrorKind); | 4434 constantSystem.createInt(selector.invocationMirrorKind); |
| 4661 | 4435 |
| 4662 pushInvokeStatic(null, | 4436 pushInvokeStatic( |
| 4663 createInvocationMirror, | 4437 null, |
| 4664 [graph.addConstant(nameConstant, compiler), | 4438 createInvocationMirror, |
| 4665 graph.addConstantStringFromName(internalName, compiler), | 4439 [ |
| 4666 graph.addConstant(kindConstant, compiler), | 4440 graph.addConstant(nameConstant, compiler), |
| 4667 argumentsInstruction, | 4441 graph.addConstantStringFromName(internalName, compiler), |
| 4668 argumentNamesInstruction], | 4442 graph.addConstant(kindConstant, compiler), |
| 4669 typeMask: backend.dynamicType); | 4443 argumentsInstruction, |
| 4444 argumentNamesInstruction |
| 4445 ], |
| 4446 typeMask: backend.dynamicType); |
| 4670 | 4447 |
| 4671 var inputs = <HInstruction>[pop()]; | 4448 var inputs = <HInstruction>[pop()]; |
| 4672 push(buildInvokeSuper(Selectors.noSuchMethod_, element, inputs)); | 4449 push(buildInvokeSuper(Selectors.noSuchMethod_, element, inputs)); |
| 4673 } | 4450 } |
| 4674 | 4451 |
| 4675 /// Generate a call to a super method or constructor. | 4452 /// Generate a call to a super method or constructor. |
| 4676 void generateSuperInvoke(ast.Send node, | 4453 void generateSuperInvoke(ast.Send node, FunctionElement function, |
| 4677 FunctionElement function, | 4454 SourceInformation sourceInformation) { |
| 4678 SourceInformation sourceInformation) { | |
| 4679 // TODO(5347): Try to avoid the need for calling [implementation] before | 4455 // TODO(5347): Try to avoid the need for calling [implementation] before |
| 4680 // calling [makeStaticArgumentList]. | 4456 // calling [makeStaticArgumentList]. |
| 4681 Selector selector = elements.getSelector(node); | 4457 Selector selector = elements.getSelector(node); |
| 4682 assert(invariant(node, | 4458 assert(invariant( |
| 4683 selector.applies(function.implementation, compiler.world), | 4459 node, selector.applies(function.implementation, compiler.world), |
| 4684 message: "$selector does not apply to ${function.implementation}")); | 4460 message: "$selector does not apply to ${function.implementation}")); |
| 4685 List<HInstruction> inputs = | 4461 List<HInstruction> inputs = makeStaticArgumentList( |
| 4686 makeStaticArgumentList(selector.callStructure, | 4462 selector.callStructure, node.arguments, function.implementation); |
| 4687 node.arguments, | |
| 4688 function.implementation); | |
| 4689 push(buildInvokeSuper(selector, function, inputs, sourceInformation)); | 4463 push(buildInvokeSuper(selector, function, inputs, sourceInformation)); |
| 4690 } | 4464 } |
| 4691 | 4465 |
| 4692 /// Access the value from the super [element]. | 4466 /// Access the value from the super [element]. |
| 4693 void handleSuperGet(ast.Send node, Element element) { | 4467 void handleSuperGet(ast.Send node, Element element) { |
| 4694 Selector selector = elements.getSelector(node); | 4468 Selector selector = elements.getSelector(node); |
| 4695 SourceInformation sourceInformation = | 4469 SourceInformation sourceInformation = |
| 4696 sourceInformationBuilder.buildGet(node); | 4470 sourceInformationBuilder.buildGet(node); |
| 4697 push(buildInvokeSuper( | 4471 push(buildInvokeSuper( |
| 4698 selector, element, const <HInstruction>[], sourceInformation)); | 4472 selector, element, const <HInstruction>[], sourceInformation)); |
| 4699 } | 4473 } |
| 4700 | 4474 |
| 4701 /// Invoke .call on the value retrieved from the super [element]. | 4475 /// Invoke .call on the value retrieved from the super [element]. |
| 4702 void handleSuperCallInvoke(ast.Send node, Element element) { | 4476 void handleSuperCallInvoke(ast.Send node, Element element) { |
| 4703 Selector selector = elements.getSelector(node); | 4477 Selector selector = elements.getSelector(node); |
| 4704 HInstruction target = buildInvokeSuper( | 4478 HInstruction target = buildInvokeSuper(selector, element, |
| 4705 selector, element, const <HInstruction>[], | 4479 const <HInstruction>[], sourceInformationBuilder.buildGet(node)); |
| 4706 sourceInformationBuilder.buildGet(node)); | |
| 4707 add(target); | 4480 add(target); |
| 4708 generateCallInvoke( | 4481 generateCallInvoke(node, target, |
| 4709 node, | |
| 4710 target, | |
| 4711 sourceInformationBuilder.buildCall(node, node.argumentsNode)); | 4482 sourceInformationBuilder.buildCall(node, node.argumentsNode)); |
| 4712 } | 4483 } |
| 4713 | 4484 |
| 4714 /// Invoke super [method]. | 4485 /// Invoke super [method]. |
| 4715 void handleSuperMethodInvoke( | 4486 void handleSuperMethodInvoke(ast.Send node, MethodElement method) { |
| 4716 ast.Send node, | 4487 generateSuperInvoke( |
| 4717 MethodElement method) { | 4488 node, method, sourceInformationBuilder.buildCall(node, node.selector)); |
| 4718 generateSuperInvoke(node, method, | |
| 4719 sourceInformationBuilder.buildCall(node, node.selector)); | |
| 4720 } | 4489 } |
| 4721 | 4490 |
| 4722 /// Access an unresolved super property. | 4491 /// Access an unresolved super property. |
| 4723 void handleUnresolvedSuperInvoke(ast.Send node) { | 4492 void handleUnresolvedSuperInvoke(ast.Send node) { |
| 4724 Selector selector = elements.getSelector(node); | 4493 Selector selector = elements.getSelector(node); |
| 4725 List<HInstruction> arguments = <HInstruction>[]; | 4494 List<HInstruction> arguments = <HInstruction>[]; |
| 4726 if (!node.isPropertyAccess) { | 4495 if (!node.isPropertyAccess) { |
| 4727 addGenericSendArgumentsToList(node.arguments, arguments); | 4496 addGenericSendArgumentsToList(node.arguments, arguments); |
| 4728 } | 4497 } |
| 4729 generateSuperNoSuchMethodSend(node, selector, arguments); | 4498 generateSuperNoSuchMethodSend(node, selector, arguments); |
| 4730 } | 4499 } |
| 4731 | 4500 |
| 4732 @override | 4501 @override |
| 4733 void visitUnresolvedSuperIndex( | 4502 void visitUnresolvedSuperIndex( |
| 4734 ast.Send node, | 4503 ast.Send node, Element element, ast.Node index, _) { |
| 4735 Element element, | |
| 4736 ast.Node index, | |
| 4737 _) { | |
| 4738 handleUnresolvedSuperInvoke(node); | 4504 handleUnresolvedSuperInvoke(node); |
| 4739 } | 4505 } |
| 4740 | 4506 |
| 4741 @override | 4507 @override |
| 4742 void visitUnresolvedSuperUnary( | 4508 void visitUnresolvedSuperUnary( |
| 4743 ast.Send node, | 4509 ast.Send node, UnaryOperator operator, Element element, _) { |
| 4744 UnaryOperator operator, | |
| 4745 Element element, | |
| 4746 _) { | |
| 4747 handleUnresolvedSuperInvoke(node); | 4510 handleUnresolvedSuperInvoke(node); |
| 4748 } | 4511 } |
| 4749 | 4512 |
| 4750 @override | 4513 @override |
| 4751 void visitUnresolvedSuperBinary( | 4514 void visitUnresolvedSuperBinary(ast.Send node, Element element, |
| 4752 ast.Send node, | 4515 BinaryOperator operator, ast.Node argument, _) { |
| 4753 Element element, | |
| 4754 BinaryOperator operator, | |
| 4755 ast.Node argument, | |
| 4756 _) { | |
| 4757 handleUnresolvedSuperInvoke(node); | 4516 handleUnresolvedSuperInvoke(node); |
| 4758 } | 4517 } |
| 4759 | 4518 |
| 4760 @override | 4519 @override |
| 4761 void visitUnresolvedSuperGet( | 4520 void visitUnresolvedSuperGet(ast.Send node, Element element, _) { |
| 4762 ast.Send node, | |
| 4763 Element element, | |
| 4764 _) { | |
| 4765 handleUnresolvedSuperInvoke(node); | 4521 handleUnresolvedSuperInvoke(node); |
| 4766 } | 4522 } |
| 4767 | 4523 |
| 4768 @override | 4524 @override |
| 4769 void visitUnresolvedSuperSet( | 4525 void visitUnresolvedSuperSet( |
| 4770 ast.Send node, | 4526 ast.Send node, Element element, ast.Node rhs, _) { |
| 4771 Element element, | |
| 4772 ast.Node rhs, | |
| 4773 _) { | |
| 4774 handleSuperSendSet(node); | 4527 handleSuperSendSet(node); |
| 4775 } | 4528 } |
| 4776 | 4529 |
| 4777 @override | 4530 @override |
| 4778 void visitSuperSetterGet( | 4531 void visitSuperSetterGet(ast.Send node, MethodElement setter, _) { |
| 4779 ast.Send node, | |
| 4780 MethodElement setter, | |
| 4781 _) { | |
| 4782 handleUnresolvedSuperInvoke(node); | 4532 handleUnresolvedSuperInvoke(node); |
| 4783 } | 4533 } |
| 4784 | 4534 |
| 4785 @override | 4535 @override |
| 4786 void visitUnresolvedSuperInvoke( | 4536 void visitUnresolvedSuperInvoke( |
| 4787 ast.Send node, | 4537 ast.Send node, Element element, ast.Node argument, Selector selector, _) { |
| 4788 Element element, | |
| 4789 ast.Node argument, | |
| 4790 Selector selector, | |
| 4791 _) { | |
| 4792 handleUnresolvedSuperInvoke(node); | 4538 handleUnresolvedSuperInvoke(node); |
| 4793 } | 4539 } |
| 4794 | 4540 |
| 4795 @override | 4541 @override |
| 4796 void visitSuperFieldGet( | 4542 void visitSuperFieldGet(ast.Send node, FieldElement field, _) { |
| 4797 ast.Send node, | |
| 4798 FieldElement field, | |
| 4799 _) { | |
| 4800 handleSuperGet(node, field); | 4543 handleSuperGet(node, field); |
| 4801 } | 4544 } |
| 4802 | 4545 |
| 4803 @override | 4546 @override |
| 4804 void visitSuperGetterGet( | 4547 void visitSuperGetterGet(ast.Send node, MethodElement method, _) { |
| 4805 ast.Send node, | |
| 4806 MethodElement method, | |
| 4807 _) { | |
| 4808 handleSuperGet(node, method); | 4548 handleSuperGet(node, method); |
| 4809 } | 4549 } |
| 4810 | 4550 |
| 4811 @override | 4551 @override |
| 4812 void visitSuperMethodGet( | 4552 void visitSuperMethodGet(ast.Send node, MethodElement method, _) { |
| 4813 ast.Send node, | |
| 4814 MethodElement method, | |
| 4815 _) { | |
| 4816 handleSuperGet(node, method); | 4553 handleSuperGet(node, method); |
| 4817 } | 4554 } |
| 4818 | 4555 |
| 4819 @override | 4556 @override |
| 4820 void visitSuperFieldInvoke( | 4557 void visitSuperFieldInvoke(ast.Send node, FieldElement field, |
| 4821 ast.Send node, | 4558 ast.NodeList arguments, CallStructure callStructure, _) { |
| 4822 FieldElement field, | |
| 4823 ast.NodeList arguments, | |
| 4824 CallStructure callStructure, | |
| 4825 _) { | |
| 4826 handleSuperCallInvoke(node, field); | 4559 handleSuperCallInvoke(node, field); |
| 4827 } | 4560 } |
| 4828 | 4561 |
| 4829 @override | 4562 @override |
| 4830 void visitSuperGetterInvoke( | 4563 void visitSuperGetterInvoke(ast.Send node, MethodElement getter, |
| 4831 ast.Send node, | 4564 ast.NodeList arguments, CallStructure callStructure, _) { |
| 4832 MethodElement getter, | |
| 4833 ast.NodeList arguments, | |
| 4834 CallStructure callStructure, | |
| 4835 _) { | |
| 4836 handleSuperCallInvoke(node, getter); | 4565 handleSuperCallInvoke(node, getter); |
| 4837 } | 4566 } |
| 4838 | 4567 |
| 4839 @override | 4568 @override |
| 4840 void visitSuperMethodInvoke( | 4569 void visitSuperMethodInvoke(ast.Send node, MethodElement method, |
| 4841 ast.Send node, | 4570 ast.NodeList arguments, CallStructure callStructure, _) { |
| 4842 MethodElement method, | |
| 4843 ast.NodeList arguments, | |
| 4844 CallStructure callStructure, | |
| 4845 _) { | |
| 4846 handleSuperMethodInvoke(node, method); | 4571 handleSuperMethodInvoke(node, method); |
| 4847 } | 4572 } |
| 4848 | 4573 |
| 4849 @override | 4574 @override |
| 4850 void visitSuperIndex( | 4575 void visitSuperIndex(ast.Send node, MethodElement method, ast.Node index, _) { |
| 4851 ast.Send node, | |
| 4852 MethodElement method, | |
| 4853 ast.Node index, | |
| 4854 _) { | |
| 4855 handleSuperMethodInvoke(node, method); | 4576 handleSuperMethodInvoke(node, method); |
| 4856 } | 4577 } |
| 4857 | 4578 |
| 4858 @override | 4579 @override |
| 4859 void visitSuperEquals( | 4580 void visitSuperEquals( |
| 4860 ast.Send node, | 4581 ast.Send node, MethodElement method, ast.Node argument, _) { |
| 4861 MethodElement method, | |
| 4862 ast.Node argument, | |
| 4863 _) { | |
| 4864 handleSuperMethodInvoke(node, method); | 4582 handleSuperMethodInvoke(node, method); |
| 4865 } | 4583 } |
| 4866 | 4584 |
| 4867 @override | 4585 @override |
| 4868 void visitSuperBinary( | 4586 void visitSuperBinary(ast.Send node, MethodElement method, |
| 4869 ast.Send node, | 4587 BinaryOperator operator, ast.Node argument, _) { |
| 4870 MethodElement method, | |
| 4871 BinaryOperator operator, | |
| 4872 ast.Node argument, | |
| 4873 _) { | |
| 4874 handleSuperMethodInvoke(node, method); | 4588 handleSuperMethodInvoke(node, method); |
| 4875 } | 4589 } |
| 4876 | 4590 |
| 4877 @override | 4591 @override |
| 4878 void visitSuperNotEquals( | 4592 void visitSuperNotEquals( |
| 4879 ast.Send node, | 4593 ast.Send node, MethodElement method, ast.Node argument, _) { |
| 4880 MethodElement method, | |
| 4881 ast.Node argument, | |
| 4882 _) { | |
| 4883 handleSuperMethodInvoke(node, method); | 4594 handleSuperMethodInvoke(node, method); |
| 4884 pushWithPosition(new HNot(popBoolified(), backend.boolType), node.selector); | 4595 pushWithPosition(new HNot(popBoolified(), backend.boolType), node.selector); |
| 4885 } | 4596 } |
| 4886 | 4597 |
| 4887 @override | 4598 @override |
| 4888 void visitSuperUnary( | 4599 void visitSuperUnary( |
| 4889 ast.Send node, | 4600 ast.Send node, UnaryOperator operator, MethodElement method, _) { |
| 4890 UnaryOperator operator, | |
| 4891 MethodElement method, | |
| 4892 _) { | |
| 4893 handleSuperMethodInvoke(node, method); | 4601 handleSuperMethodInvoke(node, method); |
| 4894 } | 4602 } |
| 4895 | 4603 |
| 4896 @override | 4604 @override |
| 4897 void visitSuperMethodIncompatibleInvoke( | 4605 void visitSuperMethodIncompatibleInvoke(ast.Send node, MethodElement method, |
| 4898 ast.Send node, | 4606 ast.NodeList arguments, CallStructure callStructure, _) { |
| 4899 MethodElement method, | |
| 4900 ast.NodeList arguments, | |
| 4901 CallStructure callStructure, | |
| 4902 _) { | |
| 4903 handleInvalidSuperInvoke(node, arguments); | 4607 handleInvalidSuperInvoke(node, arguments); |
| 4904 } | 4608 } |
| 4905 | 4609 |
| 4906 @override | 4610 @override |
| 4907 void visitSuperSetterInvoke( | 4611 void visitSuperSetterInvoke(ast.Send node, SetterElement setter, |
| 4908 ast.Send node, | 4612 ast.NodeList arguments, CallStructure callStructure, _) { |
| 4909 SetterElement setter, | |
| 4910 ast.NodeList arguments, | |
| 4911 CallStructure callStructure, | |
| 4912 _) { | |
| 4913 handleInvalidSuperInvoke(node, arguments); | 4613 handleInvalidSuperInvoke(node, arguments); |
| 4914 } | 4614 } |
| 4915 | 4615 |
| 4916 void handleInvalidSuperInvoke(ast.Send node, ast.NodeList arguments) { | 4616 void handleInvalidSuperInvoke(ast.Send node, ast.NodeList arguments) { |
| 4917 Selector selector = elements.getSelector(node); | 4617 Selector selector = elements.getSelector(node); |
| 4918 List<HInstruction> inputs = <HInstruction>[]; | 4618 List<HInstruction> inputs = <HInstruction>[]; |
| 4919 addGenericSendArgumentsToList(arguments.nodes, inputs); | 4619 addGenericSendArgumentsToList(arguments.nodes, inputs); |
| 4920 generateSuperNoSuchMethodSend(node, selector, inputs); | 4620 generateSuperNoSuchMethodSend(node, selector, inputs); |
| 4921 } | 4621 } |
| 4922 | 4622 |
| 4923 bool needsSubstitutionForTypeVariableAccess(ClassElement cls) { | 4623 bool needsSubstitutionForTypeVariableAccess(ClassElement cls) { |
| 4924 ClassWorld classWorld = compiler.world; | 4624 ClassWorld classWorld = compiler.world; |
| 4925 if (classWorld.isUsedAsMixin(cls)) return true; | 4625 if (classWorld.isUsedAsMixin(cls)) return true; |
| 4926 | 4626 |
| 4927 return compiler.world.anyStrictSubclassOf(cls, (ClassElement subclass) { | 4627 return compiler.world.anyStrictSubclassOf(cls, (ClassElement subclass) { |
| 4928 return !rti.isTrivialSubstitution(subclass, cls); | 4628 return !rti.isTrivialSubstitution(subclass, cls); |
| 4929 }); | 4629 }); |
| 4930 } | 4630 } |
| 4931 | 4631 |
| 4932 /** | 4632 /** |
| 4933 * Generate code to extract the type arguments from the object, substitute | 4633 * Generate code to extract the type arguments from the object, substitute |
| 4934 * them as an instance of the type we are testing against (if necessary), and | 4634 * them as an instance of the type we are testing against (if necessary), and |
| 4935 * extract the type argument by the index of the variable in the list of type | 4635 * extract the type argument by the index of the variable in the list of type |
| 4936 * variables for that class. | 4636 * variables for that class. |
| 4937 */ | 4637 */ |
| 4938 HInstruction readTypeVariable( | 4638 HInstruction readTypeVariable(ClassElement cls, TypeVariableElement variable, |
| 4939 ClassElement cls, | |
| 4940 TypeVariableElement variable, | |
| 4941 {SourceInformation sourceInformation}) { | 4639 {SourceInformation sourceInformation}) { |
| 4942 assert(sourceElement.isInstanceMember); | 4640 assert(sourceElement.isInstanceMember); |
| 4943 | 4641 |
| 4944 HInstruction target = localsHandler.readThis(); | 4642 HInstruction target = localsHandler.readThis(); |
| 4945 HConstant index = graph.addConstantInt(variable.index, compiler); | 4643 HConstant index = graph.addConstantInt(variable.index, compiler); |
| 4946 | 4644 |
| 4947 if (needsSubstitutionForTypeVariableAccess(cls)) { | 4645 if (needsSubstitutionForTypeVariableAccess(cls)) { |
| 4948 // TODO(ahe): Creating a string here is unfortunate. It is slow (due to | 4646 // TODO(ahe): Creating a string here is unfortunate. It is slow (due to |
| 4949 // string concatenation in the implementation), and may prevent | 4647 // string concatenation in the implementation), and may prevent |
| 4950 // segmentation of '$'. | 4648 // segmentation of '$'. |
| 4951 js.Name substitutionName = backend.namer.runtimeTypeName(cls); | 4649 js.Name substitutionName = backend.namer.runtimeTypeName(cls); |
| 4952 HInstruction substitutionNameInstr = graph.addConstantStringFromName( | 4650 HInstruction substitutionNameInstr = |
| 4953 substitutionName, compiler); | 4651 graph.addConstantStringFromName(substitutionName, compiler); |
| 4954 pushInvokeStatic(null, | 4652 pushInvokeStatic(null, helpers.getRuntimeTypeArgument, |
| 4955 helpers.getRuntimeTypeArgument, | 4653 [target, substitutionNameInstr, index], |
| 4956 [target, substitutionNameInstr, index], | 4654 typeMask: backend.dynamicType, sourceInformation: sourceInformation); |
| 4957 typeMask: backend.dynamicType, | |
| 4958 sourceInformation: sourceInformation); | |
| 4959 } else { | 4655 } else { |
| 4960 pushInvokeStatic( | 4656 pushInvokeStatic(null, helpers.getTypeArgumentByIndex, [target, index], |
| 4961 null, | 4657 typeMask: backend.dynamicType, sourceInformation: sourceInformation); |
| 4962 helpers.getTypeArgumentByIndex, | |
| 4963 [target, index], | |
| 4964 typeMask: backend.dynamicType, | |
| 4965 sourceInformation: sourceInformation); | |
| 4966 } | 4658 } |
| 4967 return pop(); | 4659 return pop(); |
| 4968 } | 4660 } |
| 4969 | 4661 |
| 4970 // TODO(karlklose): this is needed to avoid a bug where the resolved type is | 4662 // TODO(karlklose): this is needed to avoid a bug where the resolved type is |
| 4971 // not stored on a type annotation in the closure translator. Remove when | 4663 // not stored on a type annotation in the closure translator. Remove when |
| 4972 // fixed. | 4664 // fixed. |
| 4973 bool hasDirectLocal(Local local) { | 4665 bool hasDirectLocal(Local local) { |
| 4974 return !localsHandler.isAccessedDirectly(local) || | 4666 return !localsHandler.isAccessedDirectly(local) || |
| 4975 localsHandler.directLocals[local] != null; | 4667 localsHandler.directLocals[local] != null; |
| 4976 } | 4668 } |
| 4977 | 4669 |
| 4978 /** | 4670 /** |
| 4979 * Helper to create an instruction that gets the value of a type variable. | 4671 * Helper to create an instruction that gets the value of a type variable. |
| 4980 */ | 4672 */ |
| 4981 HInstruction addTypeVariableReference( | 4673 HInstruction addTypeVariableReference(TypeVariableType type, |
| 4982 TypeVariableType type, | |
| 4983 {SourceInformation sourceInformation}) { | 4674 {SourceInformation sourceInformation}) { |
| 4984 | |
| 4985 assert(assertTypeInContext(type)); | 4675 assert(assertTypeInContext(type)); |
| 4986 Element member = sourceElement; | 4676 Element member = sourceElement; |
| 4987 bool isClosure = member.enclosingElement.isClosure; | 4677 bool isClosure = member.enclosingElement.isClosure; |
| 4988 if (isClosure) { | 4678 if (isClosure) { |
| 4989 ClosureClassElement closureClass = member.enclosingElement; | 4679 ClosureClassElement closureClass = member.enclosingElement; |
| 4990 member = closureClass.methodElement; | 4680 member = closureClass.methodElement; |
| 4991 member = member.outermostEnclosingMemberOrTopLevel; | 4681 member = member.outermostEnclosingMemberOrTopLevel; |
| 4992 } | 4682 } |
| 4993 bool isInConstructorContext = member.isConstructor || | 4683 bool isInConstructorContext = |
| 4994 member.isGenerativeConstructorBody; | 4684 member.isConstructor || member.isGenerativeConstructorBody; |
| 4995 Local typeVariableLocal = localsHandler.getTypeVariableAsLocal(type); | 4685 Local typeVariableLocal = localsHandler.getTypeVariableAsLocal(type); |
| 4996 if (isClosure) { | 4686 if (isClosure) { |
| 4997 if (member.isFactoryConstructor || | 4687 if (member.isFactoryConstructor || |
| 4998 (isInConstructorContext && hasDirectLocal(typeVariableLocal))) { | 4688 (isInConstructorContext && hasDirectLocal(typeVariableLocal))) { |
| 4999 // The type variable is used from a closure in a factory constructor. | 4689 // The type variable is used from a closure in a factory constructor. |
| 5000 // The value of the type argument is stored as a local on the closure | 4690 // The value of the type argument is stored as a local on the closure |
| 5001 // itself. | 4691 // itself. |
| 5002 return localsHandler.readLocal( | 4692 return localsHandler.readLocal(typeVariableLocal, |
| 5003 typeVariableLocal, sourceInformation: sourceInformation); | 4693 sourceInformation: sourceInformation); |
| 5004 } else if (member.isFunction || | 4694 } else if (member.isFunction || |
| 5005 member.isGetter || | 4695 member.isGetter || |
| 5006 member.isSetter || | 4696 member.isSetter || |
| 5007 isInConstructorContext) { | 4697 isInConstructorContext) { |
| 5008 // The type variable is stored on the "enclosing object" and needs to be | 4698 // The type variable is stored on the "enclosing object" and needs to be |
| 5009 // accessed using the this-reference in the closure. | 4699 // accessed using the this-reference in the closure. |
| 5010 return readTypeVariable( | 4700 return readTypeVariable(member.enclosingClass, type.element, |
| 5011 member.enclosingClass, | |
| 5012 type.element, | |
| 5013 sourceInformation: sourceInformation); | 4701 sourceInformation: sourceInformation); |
| 5014 } else { | 4702 } else { |
| 5015 assert(member.isField); | 4703 assert(member.isField); |
| 5016 // The type variable is stored in a parameter of the method. | 4704 // The type variable is stored in a parameter of the method. |
| 5017 return localsHandler.readLocal(typeVariableLocal); | 4705 return localsHandler.readLocal(typeVariableLocal); |
| 5018 } | 4706 } |
| 5019 } else if (isInConstructorContext || | 4707 } else if (isInConstructorContext || |
| 5020 // When [member] is a field, we can be either | 4708 // When [member] is a field, we can be either |
| 5021 // generating a checked setter or inlining its | 4709 // generating a checked setter or inlining its |
| 5022 // initializer in a constructor. An initializer is | 4710 // initializer in a constructor. An initializer is |
| 5023 // never built standalone, so in that case [target] is not | 4711 // never built standalone, so in that case [target] is not |
| 5024 // the [member] itself. | 4712 // the [member] itself. |
| 5025 (member.isField && member != target)) { | 4713 (member.isField && member != target)) { |
| 5026 // The type variable is stored in a parameter of the method. | 4714 // The type variable is stored in a parameter of the method. |
| 5027 return localsHandler.readLocal( | 4715 return localsHandler.readLocal(typeVariableLocal, |
| 5028 typeVariableLocal, sourceInformation: sourceInformation); | 4716 sourceInformation: sourceInformation); |
| 5029 } else if (member.isInstanceMember) { | 4717 } else if (member.isInstanceMember) { |
| 5030 // The type variable is stored on the object. | 4718 // The type variable is stored on the object. |
| 5031 return readTypeVariable( | 4719 return readTypeVariable(member.enclosingClass, type.element, |
| 5032 member.enclosingClass, | |
| 5033 type.element, | |
| 5034 sourceInformation: sourceInformation); | 4720 sourceInformation: sourceInformation); |
| 5035 } else { | 4721 } else { |
| 5036 reporter.internalError(type.element, | 4722 reporter.internalError( |
| 5037 'Unexpected type variable in static context.'); | 4723 type.element, 'Unexpected type variable in static context.'); |
| 5038 return null; | 4724 return null; |
| 5039 } | 4725 } |
| 5040 } | 4726 } |
| 5041 | 4727 |
| 5042 HInstruction analyzeTypeArgument( | 4728 HInstruction analyzeTypeArgument(DartType argument, |
| 5043 DartType argument, | |
| 5044 {SourceInformation sourceInformation}) { | 4729 {SourceInformation sourceInformation}) { |
| 5045 | |
| 5046 assert(assertTypeInContext(argument)); | 4730 assert(assertTypeInContext(argument)); |
| 5047 if (argument.treatAsDynamic) { | 4731 if (argument.treatAsDynamic) { |
| 5048 // Represent [dynamic] as [null]. | 4732 // Represent [dynamic] as [null]. |
| 5049 return graph.addConstantNull(compiler); | 4733 return graph.addConstantNull(compiler); |
| 5050 } | 4734 } |
| 5051 | 4735 |
| 5052 if (argument.isTypeVariable) { | 4736 if (argument.isTypeVariable) { |
| 5053 return addTypeVariableReference( | 4737 return addTypeVariableReference(argument, |
| 5054 argument, sourceInformation: sourceInformation); | 4738 sourceInformation: sourceInformation); |
| 5055 } | 4739 } |
| 5056 | 4740 |
| 5057 List<HInstruction> inputs = <HInstruction>[]; | 4741 List<HInstruction> inputs = <HInstruction>[]; |
| 5058 | 4742 |
| 5059 js.Expression template = | 4743 js.Expression template = |
| 5060 rtiEncoder.getTypeRepresentationWithPlaceholders(argument, (variable) { | 4744 rtiEncoder.getTypeRepresentationWithPlaceholders(argument, (variable) { |
| 5061 inputs.add(addTypeVariableReference(variable)); | 4745 inputs.add(addTypeVariableReference(variable)); |
| 5062 }); | 4746 }); |
| 5063 | 4747 |
| 5064 js.Template code = new js.Template(null, template); | 4748 js.Template code = new js.Template(null, template); |
| 5065 HInstruction result = new HForeignCode(code, backend.stringType, inputs, | 4749 HInstruction result = new HForeignCode(code, backend.stringType, inputs, |
| 5066 nativeBehavior: native.NativeBehavior.PURE); | 4750 nativeBehavior: native.NativeBehavior.PURE); |
| 5067 add(result); | 4751 add(result); |
| 5068 return result; | 4752 return result; |
| 5069 } | 4753 } |
| 5070 | 4754 |
| 5071 HInstruction handleListConstructor(InterfaceType type, | 4755 HInstruction handleListConstructor( |
| 5072 ast.Node currentNode, | 4756 InterfaceType type, ast.Node currentNode, HInstruction newObject) { |
| 5073 HInstruction newObject) { | |
| 5074 if (!backend.classNeedsRti(type.element) || type.treatAsRaw) { | 4757 if (!backend.classNeedsRti(type.element) || type.treatAsRaw) { |
| 5075 return newObject; | 4758 return newObject; |
| 5076 } | 4759 } |
| 5077 List<HInstruction> inputs = <HInstruction>[]; | 4760 List<HInstruction> inputs = <HInstruction>[]; |
| 5078 type = localsHandler.substInContext(type); | 4761 type = localsHandler.substInContext(type); |
| 5079 type.typeArguments.forEach((DartType argument) { | 4762 type.typeArguments.forEach((DartType argument) { |
| 5080 inputs.add(analyzeTypeArgument(argument)); | 4763 inputs.add(analyzeTypeArgument(argument)); |
| 5081 }); | 4764 }); |
| 5082 // TODO(15489): Register at codegen. | 4765 // TODO(15489): Register at codegen. |
| 5083 registry?.registerInstantiation(type); | 4766 registry?.registerInstantiation(type); |
| 5084 return callSetRuntimeTypeInfo(type.element, inputs, newObject); | 4767 return callSetRuntimeTypeInfo(type.element, inputs, newObject); |
| 5085 } | 4768 } |
| 5086 | 4769 |
| 5087 void copyRuntimeTypeInfo(HInstruction source, HInstruction target) { | 4770 void copyRuntimeTypeInfo(HInstruction source, HInstruction target) { |
| 5088 Element copyHelper = helpers.copyTypeArguments; | 4771 Element copyHelper = helpers.copyTypeArguments; |
| 5089 pushInvokeStatic(null, copyHelper, [source, target], | 4772 pushInvokeStatic(null, copyHelper, [source, target], |
| 5090 sourceInformation: target.sourceInformation); | 4773 sourceInformation: target.sourceInformation); |
| 5091 pop(); | 4774 pop(); |
| 5092 } | 4775 } |
| 5093 | 4776 |
| 5094 HInstruction callSetRuntimeTypeInfo(ClassElement element, | 4777 HInstruction callSetRuntimeTypeInfo(ClassElement element, |
| 5095 List<HInstruction> rtiInputs, | 4778 List<HInstruction> rtiInputs, HInstruction newObject) { |
| 5096 HInstruction newObject) { | |
| 5097 if (!backend.classNeedsRti(element) || element.typeVariables.isEmpty) { | 4779 if (!backend.classNeedsRti(element) || element.typeVariables.isEmpty) { |
| 5098 return newObject; | 4780 return newObject; |
| 5099 } | 4781 } |
| 5100 | 4782 |
| 5101 HInstruction typeInfo = buildLiteralList(rtiInputs); | 4783 HInstruction typeInfo = buildLiteralList(rtiInputs); |
| 5102 add(typeInfo); | 4784 add(typeInfo); |
| 5103 | 4785 |
| 5104 // Set the runtime type information on the object. | 4786 // Set the runtime type information on the object. |
| 5105 Element typeInfoSetterElement = helpers.setRuntimeTypeInfo; | 4787 Element typeInfoSetterElement = helpers.setRuntimeTypeInfo; |
| 5106 pushInvokeStatic( | 4788 pushInvokeStatic( |
| 5107 null, | 4789 null, typeInfoSetterElement, <HInstruction>[newObject, typeInfo], |
| 5108 typeInfoSetterElement, | |
| 5109 <HInstruction>[newObject, typeInfo], | |
| 5110 typeMask: backend.dynamicType, | 4790 typeMask: backend.dynamicType, |
| 5111 sourceInformation: newObject.sourceInformation); | 4791 sourceInformation: newObject.sourceInformation); |
| 5112 | 4792 |
| 5113 // The new object will now be referenced through the | 4793 // The new object will now be referenced through the |
| 5114 // `setRuntimeTypeInfo` call. We therefore set the type of that | 4794 // `setRuntimeTypeInfo` call. We therefore set the type of that |
| 5115 // instruction to be of the object's type. | 4795 // instruction to be of the object's type. |
| 5116 assert(invariant( | 4796 assert(invariant(CURRENT_ELEMENT_SPANNABLE, |
| 5117 CURRENT_ELEMENT_SPANNABLE, | |
| 5118 stack.last is HInvokeStatic || stack.last == newObject, | 4797 stack.last is HInvokeStatic || stack.last == newObject, |
| 5119 message: | 4798 message: "Unexpected `stack.last`: Found ${stack.last}, " |
| 5120 "Unexpected `stack.last`: Found ${stack.last}, " | 4799 "expected ${newObject} or an HInvokeStatic. " |
| 5121 "expected ${newObject} or an HInvokeStatic. " | 4800 "State: element=$element, rtiInputs=$rtiInputs, stack=$stack.")); |
| 5122 "State: element=$element, rtiInputs=$rtiInputs, stack=$stack.")); | |
| 5123 stack.last.instructionType = newObject.instructionType; | 4801 stack.last.instructionType = newObject.instructionType; |
| 5124 return pop(); | 4802 return pop(); |
| 5125 } | 4803 } |
| 5126 | 4804 |
| 5127 void handleNewSend(ast.NewExpression node) { | 4805 void handleNewSend(ast.NewExpression node) { |
| 5128 ast.Send send = node.send; | 4806 ast.Send send = node.send; |
| 5129 generateIsDeferredLoadedCheckOfSend(send); | 4807 generateIsDeferredLoadedCheckOfSend(send); |
| 5130 | 4808 |
| 5131 bool isFixedList = false; | 4809 bool isFixedList = false; |
| 5132 bool isFixedListConstructorCall = | 4810 bool isFixedListConstructorCall = |
| 5133 Elements.isFixedListConstructorCall(elements[send], send, compiler); | 4811 Elements.isFixedListConstructorCall(elements[send], send, compiler); |
| 5134 bool isGrowableListConstructorCall = | 4812 bool isGrowableListConstructorCall = |
| 5135 Elements.isGrowableListConstructorCall(elements[send], send, compiler); | 4813 Elements.isGrowableListConstructorCall(elements[send], send, compiler); |
| 5136 | 4814 |
| 5137 TypeMask computeType(element) { | 4815 TypeMask computeType(element) { |
| 5138 Element originalElement = elements[send]; | 4816 Element originalElement = elements[send]; |
| 5139 if (isFixedListConstructorCall | 4817 if (isFixedListConstructorCall || |
| 5140 || Elements.isFilledListConstructorCall( | 4818 Elements.isFilledListConstructorCall( |
| 5141 originalElement, send, compiler)) { | 4819 originalElement, send, compiler)) { |
| 5142 isFixedList = true; | 4820 isFixedList = true; |
| 5143 TypeMask inferred = | 4821 TypeMask inferred = |
| 5144 TypeMaskFactory.inferredForNode(sourceElement, send, compiler); | 4822 TypeMaskFactory.inferredForNode(sourceElement, send, compiler); |
| 5145 return inferred.containsAll(compiler.world) | 4823 return inferred.containsAll(compiler.world) |
| 5146 ? backend.fixedArrayType | 4824 ? backend.fixedArrayType |
| 5147 : inferred; | 4825 : inferred; |
| 5148 } else if (isGrowableListConstructorCall) { | 4826 } else if (isGrowableListConstructorCall) { |
| 5149 TypeMask inferred = | 4827 TypeMask inferred = |
| 5150 TypeMaskFactory.inferredForNode(sourceElement, send, compiler); | 4828 TypeMaskFactory.inferredForNode(sourceElement, send, compiler); |
| 5151 return inferred.containsAll(compiler.world) | 4829 return inferred.containsAll(compiler.world) |
| 5152 ? backend.extendableArrayType | 4830 ? backend.extendableArrayType |
| 5153 : inferred; | 4831 : inferred; |
| 5154 } else if (Elements.isConstructorOfTypedArraySubclass( | 4832 } else if (Elements.isConstructorOfTypedArraySubclass( |
| 5155 originalElement, compiler)) { | 4833 originalElement, compiler)) { |
| 5156 isFixedList = true; | 4834 isFixedList = true; |
| 5157 TypeMask inferred = | 4835 TypeMask inferred = |
| 5158 TypeMaskFactory.inferredForNode(sourceElement, send, compiler); | 4836 TypeMaskFactory.inferredForNode(sourceElement, send, compiler); |
| 5159 ClassElement cls = element.enclosingClass; | 4837 ClassElement cls = element.enclosingClass; |
| 5160 assert(backend.isNative(cls.thisType.element)); | 4838 assert(backend.isNative(cls.thisType.element)); |
| 5161 return inferred.containsAll(compiler.world) | 4839 return inferred.containsAll(compiler.world) |
| 5162 ? new TypeMask.nonNullExact(cls.thisType.element, compiler.world) | 4840 ? new TypeMask.nonNullExact(cls.thisType.element, compiler.world) |
| 5163 : inferred; | 4841 : inferred; |
| 5164 } else if (element.isGenerativeConstructor) { | 4842 } else if (element.isGenerativeConstructor) { |
| 5165 ClassElement cls = element.enclosingClass; | 4843 ClassElement cls = element.enclosingClass; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 5183 constructor = constructorImplementation.effectiveTarget; | 4861 constructor = constructorImplementation.effectiveTarget; |
| 5184 | 4862 |
| 5185 final bool isSymbolConstructor = | 4863 final bool isSymbolConstructor = |
| 5186 constructorDeclaration == compiler.symbolConstructor; | 4864 constructorDeclaration == compiler.symbolConstructor; |
| 5187 final bool isJSArrayTypedConstructor = | 4865 final bool isJSArrayTypedConstructor = |
| 5188 constructorDeclaration == helpers.jsArrayTypedConstructor; | 4866 constructorDeclaration == helpers.jsArrayTypedConstructor; |
| 5189 | 4867 |
| 5190 if (isSymbolConstructor) { | 4868 if (isSymbolConstructor) { |
| 5191 constructor = compiler.symbolValidatedConstructor; | 4869 constructor = compiler.symbolValidatedConstructor; |
| 5192 assert(invariant(send, constructor != null, | 4870 assert(invariant(send, constructor != null, |
| 5193 message: 'Constructor Symbol.validated is missing')); | 4871 message: 'Constructor Symbol.validated is missing')); |
| 5194 callStructure = compiler.symbolValidatedConstructorSelector.callStructure; | 4872 callStructure = compiler.symbolValidatedConstructorSelector.callStructure; |
| 5195 assert(invariant(send, callStructure != null, | 4873 assert(invariant(send, callStructure != null, |
| 5196 message: 'Constructor Symbol.validated is missing')); | 4874 message: 'Constructor Symbol.validated is missing')); |
| 5197 } | 4875 } |
| 5198 | 4876 |
| 5199 bool isRedirected = constructorDeclaration.isRedirectingFactory; | 4877 bool isRedirected = constructorDeclaration.isRedirectingFactory; |
| 5200 if (!constructorDeclaration.isCyclicRedirection) { | 4878 if (!constructorDeclaration.isCyclicRedirection) { |
| 5201 // Insert a check for every deferred redirection on the path to the | 4879 // Insert a check for every deferred redirection on the path to the |
| 5202 // final target. | 4880 // final target. |
| 5203 ConstructorElement target = constructorDeclaration; | 4881 ConstructorElement target = constructorDeclaration; |
| 5204 while (target.isRedirectingFactory) { | 4882 while (target.isRedirectingFactory) { |
| 5205 if (constructorDeclaration.redirectionDeferredPrefix != null) { | 4883 if (constructorDeclaration.redirectionDeferredPrefix != null) { |
| 5206 generateIsDeferredLoadedCheckIfNeeded( | 4884 generateIsDeferredLoadedCheckIfNeeded( |
| 5207 target.redirectionDeferredPrefix, | 4885 target.redirectionDeferredPrefix, node); |
| 5208 node); | |
| 5209 } | 4886 } |
| 5210 target = target.immediateRedirectionTarget; | 4887 target = target.immediateRedirectionTarget; |
| 5211 } | 4888 } |
| 5212 } | 4889 } |
| 5213 InterfaceType type = elements.getType(node); | 4890 InterfaceType type = elements.getType(node); |
| 5214 InterfaceType expectedType = | 4891 InterfaceType expectedType = |
| 5215 constructorDeclaration.computeEffectiveTargetType(type); | 4892 constructorDeclaration.computeEffectiveTargetType(type); |
| 5216 expectedType = localsHandler.substInContext(expectedType); | 4893 expectedType = localsHandler.substInContext(expectedType); |
| 5217 | 4894 |
| 5218 if (compiler.elementHasCompileTimeError(constructor)) { | 4895 if (compiler.elementHasCompileTimeError(constructor)) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 5234 pop(); | 4911 pop(); |
| 5235 }); | 4912 }); |
| 5236 generateAbstractClassInstantiationError(send, cls.name); | 4913 generateAbstractClassInstantiationError(send, cls.name); |
| 5237 return; | 4914 return; |
| 5238 } | 4915 } |
| 5239 | 4916 |
| 5240 // TODO(5347): Try to avoid the need for calling [implementation] before | 4917 // TODO(5347): Try to avoid the need for calling [implementation] before |
| 5241 // calling [makeStaticArgumentList]. | 4918 // calling [makeStaticArgumentList]. |
| 5242 constructorImplementation = constructor.implementation; | 4919 constructorImplementation = constructor.implementation; |
| 5243 if (constructorImplementation.isMalformed || | 4920 if (constructorImplementation.isMalformed || |
| 5244 !callStructure.signatureApplies( | 4921 !callStructure |
| 5245 constructorImplementation.functionSignature)) { | 4922 .signatureApplies(constructorImplementation.functionSignature)) { |
| 5246 generateWrongArgumentCountError(send, constructor, send.arguments); | 4923 generateWrongArgumentCountError(send, constructor, send.arguments); |
| 5247 return; | 4924 return; |
| 5248 } | 4925 } |
| 5249 | 4926 |
| 5250 var inputs = <HInstruction>[]; | 4927 var inputs = <HInstruction>[]; |
| 5251 if (constructor.isGenerativeConstructor && | 4928 if (constructor.isGenerativeConstructor && |
| 5252 backend.isNativeOrExtendsNative(constructor.enclosingClass) && | 4929 backend.isNativeOrExtendsNative(constructor.enclosingClass) && |
| 5253 !backend.isJsInterop(constructor)) { | 4930 !backend.isJsInterop(constructor)) { |
| 5254 // Native class generative constructors take a pre-constructed object. | 4931 // Native class generative constructors take a pre-constructed object. |
| 5255 inputs.add(graph.addConstantNull(compiler)); | 4932 inputs.add(graph.addConstantNull(compiler)); |
| 5256 } | 4933 } |
| 5257 inputs.addAll(makeStaticArgumentList(callStructure, | 4934 inputs.addAll(makeStaticArgumentList( |
| 5258 send.arguments, | 4935 callStructure, send.arguments, constructorImplementation)); |
| 5259 constructorImplementation)); | |
| 5260 | 4936 |
| 5261 TypeMask elementType = computeType(constructor); | 4937 TypeMask elementType = computeType(constructor); |
| 5262 if (isFixedListConstructorCall) { | 4938 if (isFixedListConstructorCall) { |
| 5263 if (!inputs[0].isNumber(compiler)) { | 4939 if (!inputs[0].isNumber(compiler)) { |
| 5264 HTypeConversion conversion = new HTypeConversion( | 4940 HTypeConversion conversion = new HTypeConversion( |
| 5265 null, HTypeConversion.ARGUMENT_TYPE_CHECK, backend.numType, | 4941 null, |
| 5266 inputs[0], null); | 4942 HTypeConversion.ARGUMENT_TYPE_CHECK, |
| 4943 backend.numType, |
| 4944 inputs[0], |
| 4945 null); |
| 5267 add(conversion); | 4946 add(conversion); |
| 5268 inputs[0] = conversion; | 4947 inputs[0] = conversion; |
| 5269 } | 4948 } |
| 5270 js.Template code = js.js.parseForeignJS('new Array(#)'); | 4949 js.Template code = js.js.parseForeignJS('new Array(#)'); |
| 5271 var behavior = new native.NativeBehavior(); | 4950 var behavior = new native.NativeBehavior(); |
| 5272 behavior.typesReturned.add(expectedType); | 4951 behavior.typesReturned.add(expectedType); |
| 5273 // The allocation can throw only if the given length is a double or | 4952 // The allocation can throw only if the given length is a double or |
| 5274 // outside the unsigned 32 bit range. | 4953 // outside the unsigned 32 bit range. |
| 5275 // TODO(sra): Array allocation should be an instruction so that canThrow | 4954 // TODO(sra): Array allocation should be an instruction so that canThrow |
| 5276 // can depend on a length type discovered in optimization. | 4955 // can depend on a length type discovered in optimization. |
| 5277 bool canThrow = true; | 4956 bool canThrow = true; |
| 5278 if (inputs[0].isInteger(compiler) && inputs[0] is HConstant) { | 4957 if (inputs[0].isInteger(compiler) && inputs[0] is HConstant) { |
| 5279 var constant = inputs[0]; | 4958 var constant = inputs[0]; |
| 5280 int value = constant.constant.primitiveValue; | 4959 int value = constant.constant.primitiveValue; |
| 5281 if (0 <= value && value < 0x100000000) canThrow = false; | 4960 if (0 <= value && value < 0x100000000) canThrow = false; |
| 5282 } | 4961 } |
| 5283 HForeignCode foreign = new HForeignCode(code, elementType, inputs, | 4962 HForeignCode foreign = new HForeignCode(code, elementType, inputs, |
| 5284 nativeBehavior: behavior, | 4963 nativeBehavior: behavior, |
| 5285 throwBehavior: canThrow | 4964 throwBehavior: canThrow |
| 5286 ? native.NativeThrowBehavior.MAY | 4965 ? native.NativeThrowBehavior.MAY |
| 5287 : native.NativeThrowBehavior.NEVER); | 4966 : native.NativeThrowBehavior.NEVER); |
| 5288 push(foreign); | 4967 push(foreign); |
| 5289 TypesInferrer inferrer = compiler.typesTask.typesInferrer; | 4968 TypesInferrer inferrer = compiler.typesTask.typesInferrer; |
| 5290 if (inferrer.isFixedArrayCheckedForGrowable(send)) { | 4969 if (inferrer.isFixedArrayCheckedForGrowable(send)) { |
| 5291 js.Template code = js.js.parseForeignJS(r'#.fixed$length = Array'); | 4970 js.Template code = js.js.parseForeignJS(r'#.fixed$length = Array'); |
| 5292 // We set the instruction as [canThrow] to avoid it being dead code. | 4971 // We set the instruction as [canThrow] to avoid it being dead code. |
| 5293 // We need a finer grained side effect. | 4972 // We need a finer grained side effect. |
| 5294 add(new HForeignCode(code, backend.nullType, [stack.last], | 4973 add(new HForeignCode(code, backend.nullType, [stack.last], |
| 5295 throwBehavior: native.NativeThrowBehavior.MAY)); | 4974 throwBehavior: native.NativeThrowBehavior.MAY)); |
| 5296 } | 4975 } |
| 5297 } else if (isGrowableListConstructorCall) { | 4976 } else if (isGrowableListConstructorCall) { |
| 5298 push(buildLiteralList(<HInstruction>[])); | 4977 push(buildLiteralList(<HInstruction>[])); |
| 5299 stack.last.instructionType = elementType; | 4978 stack.last.instructionType = elementType; |
| 5300 } else { | 4979 } else { |
| 5301 SourceInformation sourceInformation = | 4980 SourceInformation sourceInformation = |
| 5302 sourceInformationBuilder.buildNew(send); | 4981 sourceInformationBuilder.buildNew(send); |
| 5303 potentiallyAddTypeArguments(inputs, cls, expectedType); | 4982 potentiallyAddTypeArguments(inputs, cls, expectedType); |
| 5304 addInlinedInstantiation(expectedType); | 4983 addInlinedInstantiation(expectedType); |
| 5305 pushInvokeStatic(node, constructor, inputs, | 4984 pushInvokeStatic(node, constructor, inputs, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 5316 if (context != null) { | 4995 if (context != null) { |
| 5317 context.allocatedFixedLists.add(newInstance); | 4996 context.allocatedFixedLists.add(newInstance); |
| 5318 } | 4997 } |
| 5319 } | 4998 } |
| 5320 | 4999 |
| 5321 // The List constructor forwards to a Dart static method that does | 5000 // The List constructor forwards to a Dart static method that does |
| 5322 // not know about the type argument. Therefore we special case | 5001 // not know about the type argument. Therefore we special case |
| 5323 // this constructor to have the setRuntimeTypeInfo called where | 5002 // this constructor to have the setRuntimeTypeInfo called where |
| 5324 // the 'new' is done. | 5003 // the 'new' is done. |
| 5325 if (backend.classNeedsRti(coreClasses.listClass) && | 5004 if (backend.classNeedsRti(coreClasses.listClass) && |
| 5326 (isFixedListConstructorCall || isGrowableListConstructorCall || | 5005 (isFixedListConstructorCall || |
| 5327 isJSArrayTypedConstructor)) { | 5006 isGrowableListConstructorCall || |
| 5007 isJSArrayTypedConstructor)) { |
| 5328 newInstance = handleListConstructor(type, send, pop()); | 5008 newInstance = handleListConstructor(type, send, pop()); |
| 5329 stack.add(newInstance); | 5009 stack.add(newInstance); |
| 5330 } | 5010 } |
| 5331 | 5011 |
| 5332 // Finally, if we called a redirecting factory constructor, check the type. | 5012 // Finally, if we called a redirecting factory constructor, check the type. |
| 5333 if (isRedirected) { | 5013 if (isRedirected) { |
| 5334 HInstruction checked = potentiallyCheckOrTrustType(newInstance, type); | 5014 HInstruction checked = potentiallyCheckOrTrustType(newInstance, type); |
| 5335 if (checked != newInstance) { | 5015 if (checked != newInstance) { |
| 5336 pop(); | 5016 pop(); |
| 5337 stack.add(checked); | 5017 stack.add(checked); |
| 5338 } | 5018 } |
| 5339 } | 5019 } |
| 5340 } | 5020 } |
| 5341 | 5021 |
| 5342 void potentiallyAddTypeArguments(List<HInstruction> inputs, ClassElement cls, | 5022 void potentiallyAddTypeArguments( |
| 5343 InterfaceType expectedType, | 5023 List<HInstruction> inputs, ClassElement cls, InterfaceType expectedType, |
| 5344 {SourceInformation sourceInformation}) { | 5024 {SourceInformation sourceInformation}) { |
| 5345 if (!backend.classNeedsRti(cls)) return; | 5025 if (!backend.classNeedsRti(cls)) return; |
| 5346 assert(expectedType.typeArguments.isEmpty || | 5026 assert(expectedType.typeArguments.isEmpty || |
| 5347 cls.typeVariables.length == expectedType.typeArguments.length); | 5027 cls.typeVariables.length == expectedType.typeArguments.length); |
| 5348 expectedType.typeArguments.forEach((DartType argument) { | 5028 expectedType.typeArguments.forEach((DartType argument) { |
| 5349 inputs.add(analyzeTypeArgument( | 5029 inputs.add( |
| 5350 argument, sourceInformation: sourceInformation)); | 5030 analyzeTypeArgument(argument, sourceInformation: sourceInformation)); |
| 5351 }); | 5031 }); |
| 5352 } | 5032 } |
| 5353 | 5033 |
| 5354 /// In checked mode checks the [type] of [node] to be well-bounded. The method | 5034 /// In checked mode checks the [type] of [node] to be well-bounded. The method |
| 5355 /// returns [:true:] if an error can be statically determined. | 5035 /// returns [:true:] if an error can be statically determined. |
| 5356 bool checkTypeVariableBounds(ast.NewExpression node, InterfaceType type) { | 5036 bool checkTypeVariableBounds(ast.NewExpression node, InterfaceType type) { |
| 5357 if (!compiler.options.enableTypeAssertions) return false; | 5037 if (!compiler.options.enableTypeAssertions) return false; |
| 5358 | 5038 |
| 5359 Map<DartType, Set<DartType>> seenChecksMap = | 5039 Map<DartType, Set<DartType>> seenChecksMap = |
| 5360 new Map<DartType, Set<DartType>>(); | 5040 new Map<DartType, Set<DartType>>(); |
| 5361 bool definitelyFails = false; | 5041 bool definitelyFails = false; |
| 5362 | 5042 |
| 5363 addTypeVariableBoundCheck(GenericType instance, | 5043 addTypeVariableBoundCheck(GenericType instance, DartType typeArgument, |
| 5364 DartType typeArgument, | 5044 TypeVariableType typeVariable, DartType bound) { |
| 5365 TypeVariableType typeVariable, | |
| 5366 DartType bound) { | |
| 5367 if (definitelyFails) return; | 5045 if (definitelyFails) return; |
| 5368 | 5046 |
| 5369 int subtypeRelation = compiler.types.computeSubtypeRelation(typeArgument,
bound); | 5047 int subtypeRelation = |
| 5048 compiler.types.computeSubtypeRelation(typeArgument, bound); |
| 5370 if (subtypeRelation == Types.IS_SUBTYPE) return; | 5049 if (subtypeRelation == Types.IS_SUBTYPE) return; |
| 5371 | 5050 |
| 5372 String message = | 5051 String message = "Can't create an instance of malbounded type '$type': " |
| 5373 "Can't create an instance of malbounded type '$type': " | |
| 5374 "'${typeArgument}' is not a subtype of bound '${bound}' for " | 5052 "'${typeArgument}' is not a subtype of bound '${bound}' for " |
| 5375 "type variable '${typeVariable}' of type " | 5053 "type variable '${typeVariable}' of type " |
| 5376 "${type == instance | 5054 "${type == instance |
| 5377 ? "'${type.element.thisType}'" | 5055 ? "'${type.element.thisType}'" |
| 5378 : "'${instance.element.thisType}' on the supertype " | 5056 : "'${instance.element.thisType}' on the supertype " |
| 5379 "'${instance}' of '${type}'" | 5057 "'${instance}' of '${type}'" |
| 5380 }."; | 5058 }."; |
| 5381 if (subtypeRelation == Types.NOT_SUBTYPE) { | 5059 if (subtypeRelation == Types.NOT_SUBTYPE) { |
| 5382 generateTypeError(node, message); | 5060 generateTypeError(node, message); |
| 5383 definitelyFails = true; | 5061 definitelyFails = true; |
| 5384 return; | 5062 return; |
| 5385 } else if (subtypeRelation == Types.MAYBE_SUBTYPE) { | 5063 } else if (subtypeRelation == Types.MAYBE_SUBTYPE) { |
| 5386 Set<DartType> seenChecks = | 5064 Set<DartType> seenChecks = |
| 5387 seenChecksMap.putIfAbsent(typeArgument, () => new Set<DartType>()); | 5065 seenChecksMap.putIfAbsent(typeArgument, () => new Set<DartType>()); |
| 5388 if (!seenChecks.contains(bound)) { | 5066 if (!seenChecks.contains(bound)) { |
| 5389 seenChecks.add(bound); | 5067 seenChecks.add(bound); |
| 5390 assertIsSubtype(node, typeArgument, bound, message); | 5068 assertIsSubtype(node, typeArgument, bound, message); |
| 5391 } | 5069 } |
| 5392 } | 5070 } |
| 5393 } | 5071 } |
| 5394 | 5072 |
| 5395 compiler.types.checkTypeVariableBounds(type, addTypeVariableBoundCheck); | 5073 compiler.types.checkTypeVariableBounds(type, addTypeVariableBoundCheck); |
| 5396 if (definitelyFails) { | 5074 if (definitelyFails) { |
| 5397 return true; | 5075 return true; |
| 5398 } | 5076 } |
| 5399 for (InterfaceType supertype in type.element.allSupertypes) { | 5077 for (InterfaceType supertype in type.element.allSupertypes) { |
| 5400 DartType instance = type.asInstanceOf(supertype.element); | 5078 DartType instance = type.asInstanceOf(supertype.element); |
| 5401 compiler.types.checkTypeVariableBounds(instance, | 5079 compiler.types |
| 5402 addTypeVariableBoundCheck); | 5080 .checkTypeVariableBounds(instance, addTypeVariableBoundCheck); |
| 5403 if (definitelyFails) { | 5081 if (definitelyFails) { |
| 5404 return true; | 5082 return true; |
| 5405 } | 5083 } |
| 5406 } | 5084 } |
| 5407 return false; | 5085 return false; |
| 5408 } | 5086 } |
| 5409 | 5087 |
| 5410 visitStaticSend(ast.Send node) { | 5088 visitStaticSend(ast.Send node) { |
| 5411 internalError(node, "Unexpected visitStaticSend"); | 5089 internalError(node, "Unexpected visitStaticSend"); |
| 5412 } | 5090 } |
| 5413 | 5091 |
| 5414 /// Generate an invocation to the static or top level [function]. | 5092 /// Generate an invocation to the static or top level [function]. |
| 5415 void generateStaticFunctionInvoke( | 5093 void generateStaticFunctionInvoke( |
| 5416 ast.Send node, | 5094 ast.Send node, FunctionElement function, CallStructure callStructure) { |
| 5417 FunctionElement function, | |
| 5418 CallStructure callStructure) { | |
| 5419 List<HInstruction> inputs = makeStaticArgumentList( | 5095 List<HInstruction> inputs = makeStaticArgumentList( |
| 5420 callStructure, | 5096 callStructure, node.arguments, function.implementation); |
| 5421 node.arguments, | |
| 5422 function.implementation); | |
| 5423 | 5097 |
| 5424 if (function == compiler.identicalFunction) { | 5098 if (function == compiler.identicalFunction) { |
| 5425 pushWithPosition( | 5099 pushWithPosition( |
| 5426 new HIdentity(inputs[0], inputs[1], null, backend.boolType), node); | 5100 new HIdentity(inputs[0], inputs[1], null, backend.boolType), node); |
| 5427 return; | 5101 return; |
| 5428 } else { | 5102 } else { |
| 5429 pushInvokeStatic(node, function, inputs, | 5103 pushInvokeStatic(node, function, inputs, |
| 5430 sourceInformation: sourceInformationBuilder.buildCall( | 5104 sourceInformation: |
| 5431 node, node.selector)); | 5105 sourceInformationBuilder.buildCall(node, node.selector)); |
| 5432 } | 5106 } |
| 5433 } | 5107 } |
| 5434 | 5108 |
| 5435 /// Generate an invocation to a static or top level function with the wrong | 5109 /// Generate an invocation to a static or top level function with the wrong |
| 5436 /// number of arguments. | 5110 /// number of arguments. |
| 5437 void generateStaticFunctionIncompatibleInvoke(ast.Send node, | 5111 void generateStaticFunctionIncompatibleInvoke( |
| 5438 Element element) { | 5112 ast.Send node, Element element) { |
| 5439 generateWrongArgumentCountError(node, element, node.arguments); | 5113 generateWrongArgumentCountError(node, element, node.arguments); |
| 5440 } | 5114 } |
| 5441 | 5115 |
| 5442 @override | 5116 @override |
| 5443 void visitStaticFieldInvoke( | 5117 void visitStaticFieldInvoke(ast.Send node, FieldElement field, |
| 5444 ast.Send node, | 5118 ast.NodeList arguments, CallStructure callStructure, _) { |
| 5445 FieldElement field, | |
| 5446 ast.NodeList arguments, | |
| 5447 CallStructure callStructure, | |
| 5448 _) { | |
| 5449 generateStaticFieldGet(node, field); | 5119 generateStaticFieldGet(node, field); |
| 5450 generateCallInvoke( | 5120 generateCallInvoke(node, pop(), |
| 5451 node, | |
| 5452 pop(), | |
| 5453 sourceInformationBuilder.buildCall(node, node.argumentsNode)); | 5121 sourceInformationBuilder.buildCall(node, node.argumentsNode)); |
| 5454 } | 5122 } |
| 5455 | 5123 |
| 5456 @override | 5124 @override |
| 5457 void visitStaticFunctionInvoke( | 5125 void visitStaticFunctionInvoke(ast.Send node, MethodElement function, |
| 5458 ast.Send node, | 5126 ast.NodeList arguments, CallStructure callStructure, _) { |
| 5459 MethodElement function, | |
| 5460 ast.NodeList arguments, | |
| 5461 CallStructure callStructure, | |
| 5462 _) { | |
| 5463 generateStaticFunctionInvoke(node, function, callStructure); | 5127 generateStaticFunctionInvoke(node, function, callStructure); |
| 5464 } | 5128 } |
| 5465 | 5129 |
| 5466 @override | 5130 @override |
| 5467 void visitStaticFunctionIncompatibleInvoke( | 5131 void visitStaticFunctionIncompatibleInvoke( |
| 5468 ast.Send node, | 5132 ast.Send node, |
| 5469 MethodElement function, | 5133 MethodElement function, |
| 5470 ast.NodeList arguments, | 5134 ast.NodeList arguments, |
| 5471 CallStructure callStructure, | 5135 CallStructure callStructure, |
| 5472 _) { | 5136 _) { |
| 5473 generateStaticFunctionIncompatibleInvoke(node, function); | 5137 generateStaticFunctionIncompatibleInvoke(node, function); |
| 5474 } | 5138 } |
| 5475 | 5139 |
| 5476 @override | 5140 @override |
| 5477 void visitStaticGetterInvoke( | 5141 void visitStaticGetterInvoke(ast.Send node, FunctionElement getter, |
| 5478 ast.Send node, | 5142 ast.NodeList arguments, CallStructure callStructure, _) { |
| 5479 FunctionElement getter, | |
| 5480 ast.NodeList arguments, | |
| 5481 CallStructure callStructure, | |
| 5482 _) { | |
| 5483 generateStaticGetterGet(node, getter); | 5143 generateStaticGetterGet(node, getter); |
| 5484 generateCallInvoke( | 5144 generateCallInvoke(node, pop(), |
| 5485 node, | |
| 5486 pop(), | |
| 5487 sourceInformationBuilder.buildCall(node, node.argumentsNode)); | 5145 sourceInformationBuilder.buildCall(node, node.argumentsNode)); |
| 5488 } | 5146 } |
| 5489 | 5147 |
| 5490 @override | 5148 @override |
| 5491 void visitTopLevelFieldInvoke( | 5149 void visitTopLevelFieldInvoke(ast.Send node, FieldElement field, |
| 5492 ast.Send node, | 5150 ast.NodeList arguments, CallStructure callStructure, _) { |
| 5493 FieldElement field, | |
| 5494 ast.NodeList arguments, | |
| 5495 CallStructure callStructure, | |
| 5496 _) { | |
| 5497 generateStaticFieldGet(node, field); | 5151 generateStaticFieldGet(node, field); |
| 5498 generateCallInvoke( | 5152 generateCallInvoke(node, pop(), |
| 5499 node, | |
| 5500 pop(), | |
| 5501 sourceInformationBuilder.buildCall(node, node.argumentsNode)); | 5153 sourceInformationBuilder.buildCall(node, node.argumentsNode)); |
| 5502 } | 5154 } |
| 5503 | 5155 |
| 5504 @override | 5156 @override |
| 5505 void visitTopLevelFunctionInvoke( | 5157 void visitTopLevelFunctionInvoke(ast.Send node, MethodElement function, |
| 5506 ast.Send node, | 5158 ast.NodeList arguments, CallStructure callStructure, _) { |
| 5507 MethodElement function, | |
| 5508 ast.NodeList arguments, | |
| 5509 CallStructure callStructure, | |
| 5510 _) { | |
| 5511 if (backend.isForeign(function)) { | 5159 if (backend.isForeign(function)) { |
| 5512 handleForeignSend(node, function); | 5160 handleForeignSend(node, function); |
| 5513 } else { | 5161 } else { |
| 5514 generateStaticFunctionInvoke(node, function, callStructure); | 5162 generateStaticFunctionInvoke(node, function, callStructure); |
| 5515 } | 5163 } |
| 5516 } | 5164 } |
| 5517 | 5165 |
| 5518 @override | 5166 @override |
| 5519 void visitTopLevelFunctionIncompatibleInvoke( | 5167 void visitTopLevelFunctionIncompatibleInvoke( |
| 5520 ast.Send node, | 5168 ast.Send node, |
| 5521 MethodElement function, | 5169 MethodElement function, |
| 5522 ast.NodeList arguments, | 5170 ast.NodeList arguments, |
| 5523 CallStructure callStructure, | 5171 CallStructure callStructure, |
| 5524 _) { | 5172 _) { |
| 5525 generateStaticFunctionIncompatibleInvoke(node, function); | 5173 generateStaticFunctionIncompatibleInvoke(node, function); |
| 5526 } | 5174 } |
| 5527 | 5175 |
| 5528 @override | 5176 @override |
| 5529 void visitTopLevelGetterInvoke( | 5177 void visitTopLevelGetterInvoke(ast.Send node, FunctionElement getter, |
| 5530 ast.Send node, | 5178 ast.NodeList arguments, CallStructure callStructure, _) { |
| 5531 FunctionElement getter, | |
| 5532 ast.NodeList arguments, | |
| 5533 CallStructure callStructure, | |
| 5534 _) { | |
| 5535 generateStaticGetterGet(node, getter); | 5179 generateStaticGetterGet(node, getter); |
| 5536 generateCallInvoke( | 5180 generateCallInvoke(node, pop(), |
| 5537 node, | |
| 5538 pop(), | |
| 5539 sourceInformationBuilder.buildCall(node, node.argumentsNode)); | 5181 sourceInformationBuilder.buildCall(node, node.argumentsNode)); |
| 5540 } | 5182 } |
| 5541 | 5183 |
| 5542 @override | 5184 @override |
| 5543 void visitTopLevelSetterGet( | 5185 void visitTopLevelSetterGet(ast.Send node, MethodElement setter, _) { |
| 5544 ast.Send node, | |
| 5545 MethodElement setter, | |
| 5546 _) { | |
| 5547 handleInvalidStaticGet(node, setter); | 5186 handleInvalidStaticGet(node, setter); |
| 5548 } | 5187 } |
| 5549 | 5188 |
| 5550 @override | 5189 @override |
| 5551 void visitStaticSetterGet( | 5190 void visitStaticSetterGet(ast.Send node, MethodElement setter, _) { |
| 5552 ast.Send node, | |
| 5553 MethodElement setter, | |
| 5554 _) { | |
| 5555 handleInvalidStaticGet(node, setter); | 5191 handleInvalidStaticGet(node, setter); |
| 5556 } | 5192 } |
| 5557 | 5193 |
| 5558 @override | 5194 @override |
| 5559 void visitUnresolvedGet( | 5195 void visitUnresolvedGet(ast.Send node, Element element, _) { |
| 5560 ast.Send node, | |
| 5561 Element element, | |
| 5562 _) { | |
| 5563 generateStaticUnresolvedGet(node, element); | 5196 generateStaticUnresolvedGet(node, element); |
| 5564 } | 5197 } |
| 5565 | 5198 |
| 5566 void handleInvalidStaticInvoke(ast.Send node, Element element) { | 5199 void handleInvalidStaticInvoke(ast.Send node, Element element) { |
| 5567 generateThrowNoSuchMethod(node, | 5200 generateThrowNoSuchMethod(node, noSuchMethodTargetSymbolString(element), |
| 5568 noSuchMethodTargetSymbolString(element), | 5201 argumentNodes: node.arguments); |
| 5569 argumentNodes: node.arguments); | |
| 5570 } | 5202 } |
| 5571 | 5203 |
| 5572 @override | 5204 @override |
| 5573 void visitStaticSetterInvoke( | 5205 void visitStaticSetterInvoke(ast.Send node, MethodElement setter, |
| 5574 ast.Send node, | 5206 ast.NodeList arguments, CallStructure callStructure, _) { |
| 5575 MethodElement setter, | |
| 5576 ast.NodeList arguments, | |
| 5577 CallStructure callStructure, | |
| 5578 _) { | |
| 5579 handleInvalidStaticInvoke(node, setter); | 5207 handleInvalidStaticInvoke(node, setter); |
| 5580 } | 5208 } |
| 5581 | 5209 |
| 5582 @override | 5210 @override |
| 5583 void visitTopLevelSetterInvoke( | 5211 void visitTopLevelSetterInvoke(ast.Send node, MethodElement setter, |
| 5584 ast.Send node, | 5212 ast.NodeList arguments, CallStructure callStructure, _) { |
| 5585 MethodElement setter, | |
| 5586 ast.NodeList arguments, | |
| 5587 CallStructure callStructure, | |
| 5588 _) { | |
| 5589 handleInvalidStaticInvoke(node, setter); | 5213 handleInvalidStaticInvoke(node, setter); |
| 5590 } | 5214 } |
| 5591 | 5215 |
| 5592 @override | 5216 @override |
| 5593 void visitUnresolvedInvoke( | 5217 void visitUnresolvedInvoke(ast.Send node, Element element, |
| 5594 ast.Send node, | 5218 ast.NodeList arguments, Selector selector, _) { |
| 5595 Element element, | |
| 5596 ast.NodeList arguments, | |
| 5597 Selector selector, | |
| 5598 _) { | |
| 5599 if (element is ErroneousElement) { | 5219 if (element is ErroneousElement) { |
| 5600 // An erroneous element indicates that the function could not be | 5220 // An erroneous element indicates that the function could not be |
| 5601 // resolved (a warning has been issued). | 5221 // resolved (a warning has been issued). |
| 5602 handleInvalidStaticInvoke(node, element); | 5222 handleInvalidStaticInvoke(node, element); |
| 5603 } else { | 5223 } else { |
| 5604 // TODO(ahe): Do something like [generateWrongArgumentCountError]. | 5224 // TODO(ahe): Do something like [generateWrongArgumentCountError]. |
| 5605 stack.add(graph.addConstantNull(compiler)); | 5225 stack.add(graph.addConstantNull(compiler)); |
| 5606 } | 5226 } |
| 5607 return; | 5227 return; |
| 5608 } | 5228 } |
| 5609 | 5229 |
| 5610 HConstant addConstantString(String string) { | 5230 HConstant addConstantString(String string) { |
| 5611 ast.DartString dartString = new ast.DartString.literal(string); | 5231 ast.DartString dartString = new ast.DartString.literal(string); |
| 5612 return graph.addConstantString(dartString, compiler); | 5232 return graph.addConstantString(dartString, compiler); |
| 5613 } | 5233 } |
| 5614 | 5234 |
| 5615 HConstant addConstantStringFromName(js.Name name) { | 5235 HConstant addConstantStringFromName(js.Name name) { |
| 5616 return graph.addConstantStringFromName(name, compiler); | 5236 return graph.addConstantStringFromName(name, compiler); |
| 5617 } | 5237 } |
| 5618 | 5238 |
| 5619 visitClassTypeLiteralGet( | 5239 visitClassTypeLiteralGet(ast.Send node, ConstantExpression constant, _) { |
| 5620 ast.Send node, | |
| 5621 ConstantExpression constant, | |
| 5622 _) { | |
| 5623 generateConstantTypeLiteral(node); | 5240 generateConstantTypeLiteral(node); |
| 5624 } | 5241 } |
| 5625 | 5242 |
| 5626 visitClassTypeLiteralInvoke( | 5243 visitClassTypeLiteralInvoke(ast.Send node, ConstantExpression constant, |
| 5627 ast.Send node, | 5244 ast.NodeList arguments, CallStructure callStructure, _) { |
| 5628 ConstantExpression constant, | |
| 5629 ast.NodeList arguments, | |
| 5630 CallStructure callStructure, | |
| 5631 _) { | |
| 5632 generateConstantTypeLiteral(node); | 5245 generateConstantTypeLiteral(node); |
| 5633 generateTypeLiteralCall(node); | 5246 generateTypeLiteralCall(node); |
| 5634 } | 5247 } |
| 5635 | 5248 |
| 5636 visitTypedefTypeLiteralGet( | 5249 visitTypedefTypeLiteralGet(ast.Send node, ConstantExpression constant, _) { |
| 5637 ast.Send node, | |
| 5638 ConstantExpression constant, | |
| 5639 _) { | |
| 5640 generateConstantTypeLiteral(node); | 5250 generateConstantTypeLiteral(node); |
| 5641 } | 5251 } |
| 5642 | 5252 |
| 5643 visitTypedefTypeLiteralInvoke( | 5253 visitTypedefTypeLiteralInvoke(ast.Send node, ConstantExpression constant, |
| 5644 ast.Send node, | 5254 ast.NodeList arguments, CallStructure callStructure, _) { |
| 5645 ConstantExpression constant, | |
| 5646 ast.NodeList arguments, | |
| 5647 CallStructure callStructure, | |
| 5648 _) { | |
| 5649 generateConstantTypeLiteral(node); | 5255 generateConstantTypeLiteral(node); |
| 5650 generateTypeLiteralCall(node); | 5256 generateTypeLiteralCall(node); |
| 5651 } | 5257 } |
| 5652 | 5258 |
| 5653 visitTypeVariableTypeLiteralGet( | 5259 visitTypeVariableTypeLiteralGet( |
| 5654 ast.Send node, | 5260 ast.Send node, TypeVariableElement element, _) { |
| 5655 TypeVariableElement element, | |
| 5656 _) { | |
| 5657 generateTypeVariableLiteral(node, element.type); | 5261 generateTypeVariableLiteral(node, element.type); |
| 5658 } | 5262 } |
| 5659 | 5263 |
| 5660 visitTypeVariableTypeLiteralInvoke( | 5264 visitTypeVariableTypeLiteralInvoke(ast.Send node, TypeVariableElement element, |
| 5661 ast.Send node, | 5265 ast.NodeList arguments, CallStructure callStructure, _) { |
| 5662 TypeVariableElement element, | |
| 5663 ast.NodeList arguments, | |
| 5664 CallStructure callStructure, | |
| 5665 _) { | |
| 5666 generateTypeVariableLiteral(node, element.type); | 5266 generateTypeVariableLiteral(node, element.type); |
| 5667 generateTypeLiteralCall(node); | 5267 generateTypeLiteralCall(node); |
| 5668 } | 5268 } |
| 5669 | 5269 |
| 5670 visitDynamicTypeLiteralGet( | 5270 visitDynamicTypeLiteralGet(ast.Send node, ConstantExpression constant, _) { |
| 5671 ast.Send node, | |
| 5672 ConstantExpression constant, | |
| 5673 _) { | |
| 5674 generateConstantTypeLiteral(node); | 5271 generateConstantTypeLiteral(node); |
| 5675 } | 5272 } |
| 5676 | 5273 |
| 5677 visitDynamicTypeLiteralInvoke( | 5274 visitDynamicTypeLiteralInvoke(ast.Send node, ConstantExpression constant, |
| 5678 ast.Send node, | 5275 ast.NodeList arguments, CallStructure callStructure, _) { |
| 5679 ConstantExpression constant, | |
| 5680 ast.NodeList arguments, | |
| 5681 CallStructure callStructure, | |
| 5682 _) { | |
| 5683 generateConstantTypeLiteral(node); | 5276 generateConstantTypeLiteral(node); |
| 5684 generateTypeLiteralCall(node); | 5277 generateTypeLiteralCall(node); |
| 5685 } | 5278 } |
| 5686 | 5279 |
| 5687 /// Generate the constant value for a constant type literal. | 5280 /// Generate the constant value for a constant type literal. |
| 5688 void generateConstantTypeLiteral(ast.Send node) { | 5281 void generateConstantTypeLiteral(ast.Send node) { |
| 5689 // TODO(karlklose): add type representation | 5282 // TODO(karlklose): add type representation |
| 5690 if (node.isCall) { | 5283 if (node.isCall) { |
| 5691 // The node itself is not a constant but we register the selector (the | 5284 // The node itself is not a constant but we register the selector (the |
| 5692 // identifier that refers to the class/typedef) as a constant. | 5285 // identifier that refers to the class/typedef) as a constant. |
| 5693 stack.add(addConstant(node.selector)); | 5286 stack.add(addConstant(node.selector)); |
| 5694 } else { | 5287 } else { |
| 5695 stack.add(addConstant(node)); | 5288 stack.add(addConstant(node)); |
| 5696 } | 5289 } |
| 5697 } | 5290 } |
| 5698 | 5291 |
| 5699 /// Generate the literal for [typeVariable] in the current context. | 5292 /// Generate the literal for [typeVariable] in the current context. |
| 5700 void generateTypeVariableLiteral(ast.Send node, | 5293 void generateTypeVariableLiteral( |
| 5701 TypeVariableType typeVariable) { | 5294 ast.Send node, TypeVariableType typeVariable) { |
| 5702 DartType type = localsHandler.substInContext(typeVariable); | 5295 DartType type = localsHandler.substInContext(typeVariable); |
| 5703 HInstruction value = analyzeTypeArgument(type, | 5296 HInstruction value = analyzeTypeArgument(type, |
| 5704 sourceInformation: sourceInformationBuilder.buildGet(node)); | 5297 sourceInformation: sourceInformationBuilder.buildGet(node)); |
| 5705 pushInvokeStatic(node, | 5298 pushInvokeStatic(node, helpers.runtimeTypeToString, [value], |
| 5706 helpers.runtimeTypeToString, | 5299 typeMask: backend.stringType); |
| 5707 [value], | 5300 pushInvokeStatic(node, helpers.createRuntimeType, [pop()]); |
| 5708 typeMask: backend.stringType); | |
| 5709 pushInvokeStatic(node, | |
| 5710 helpers.createRuntimeType, | |
| 5711 [pop()]); | |
| 5712 } | 5301 } |
| 5713 | 5302 |
| 5714 /// Generate a call to a type literal. | 5303 /// Generate a call to a type literal. |
| 5715 void generateTypeLiteralCall(ast.Send node) { | 5304 void generateTypeLiteralCall(ast.Send node) { |
| 5716 // This send is of the form 'e(...)', where e is resolved to a type | 5305 // This send is of the form 'e(...)', where e is resolved to a type |
| 5717 // reference. We create a regular closure call on the result of the type | 5306 // reference. We create a regular closure call on the result of the type |
| 5718 // reference instead of creating a NoSuchMethodError to avoid pulling it | 5307 // reference instead of creating a NoSuchMethodError to avoid pulling it |
| 5719 // in if it is not used (e.g., in a try/catch). | 5308 // in if it is not used (e.g., in a try/catch). |
| 5720 HInstruction target = pop(); | 5309 HInstruction target = pop(); |
| 5721 generateCallInvoke(node, target, | 5310 generateCallInvoke(node, target, |
| 5722 sourceInformationBuilder.buildCall(node, node.argumentsNode)); | 5311 sourceInformationBuilder.buildCall(node, node.argumentsNode)); |
| 5723 } | 5312 } |
| 5724 | 5313 |
| 5725 /// Generate a '.call' invocation on [target]. | 5314 /// Generate a '.call' invocation on [target]. |
| 5726 void generateCallInvoke(ast.Send node, | 5315 void generateCallInvoke( |
| 5727 HInstruction target, | 5316 ast.Send node, HInstruction target, SourceInformation sourceInformation) { |
| 5728 SourceInformation sourceInformation) { | |
| 5729 Selector selector = elements.getSelector(node); | 5317 Selector selector = elements.getSelector(node); |
| 5730 List<HInstruction> inputs = <HInstruction>[target]; | 5318 List<HInstruction> inputs = <HInstruction>[target]; |
| 5731 addDynamicSendArgumentsToList(node, inputs); | 5319 addDynamicSendArgumentsToList(node, inputs); |
| 5732 push(new HInvokeClosure( | 5320 push(new HInvokeClosure( |
| 5733 new Selector.callClosureFrom(selector), | 5321 new Selector.callClosureFrom(selector), inputs, backend.dynamicType) |
| 5734 inputs, backend.dynamicType) | 5322 ..sourceInformation = sourceInformation); |
| 5735 ..sourceInformation = sourceInformation); | |
| 5736 } | 5323 } |
| 5737 | 5324 |
| 5738 visitGetterSend(ast.Send node) { | 5325 visitGetterSend(ast.Send node) { |
| 5739 internalError(node, "Unexpected visitGetterSend"); | 5326 internalError(node, "Unexpected visitGetterSend"); |
| 5740 } | 5327 } |
| 5741 | 5328 |
| 5742 // TODO(antonm): migrate rest of SsaFromAstMixin to internalError. | 5329 // TODO(antonm): migrate rest of SsaFromAstMixin to internalError. |
| 5743 internalError(Spannable node, String reason) { | 5330 internalError(Spannable node, String reason) { |
| 5744 reporter.internalError(node, reason); | 5331 reporter.internalError(node, reason); |
| 5745 } | 5332 } |
| 5746 | 5333 |
| 5747 void generateError(ast.Node node, String message, Element helper) { | 5334 void generateError(ast.Node node, String message, Element helper) { |
| 5748 HInstruction errorMessage = addConstantString(message); | 5335 HInstruction errorMessage = addConstantString(message); |
| 5749 pushInvokeStatic(node, helper, [errorMessage]); | 5336 pushInvokeStatic(node, helper, [errorMessage]); |
| 5750 } | 5337 } |
| 5751 | 5338 |
| 5752 void generateRuntimeError(ast.Node node, String message) { | 5339 void generateRuntimeError(ast.Node node, String message) { |
| 5753 generateError(node, message, helpers.throwRuntimeError); | 5340 generateError(node, message, helpers.throwRuntimeError); |
| 5754 } | 5341 } |
| 5755 | 5342 |
| 5756 void generateTypeError(ast.Node node, String message) { | 5343 void generateTypeError(ast.Node node, String message) { |
| 5757 generateError(node, message, helpers.throwTypeError); | 5344 generateError(node, message, helpers.throwTypeError); |
| 5758 } | 5345 } |
| 5759 | 5346 |
| 5760 void generateAbstractClassInstantiationError(ast.Node node, String message) { | 5347 void generateAbstractClassInstantiationError(ast.Node node, String message) { |
| 5761 generateError(node, | 5348 generateError(node, message, helpers.throwAbstractClassInstantiationError); |
| 5762 message, | |
| 5763 helpers.throwAbstractClassInstantiationError); | |
| 5764 } | 5349 } |
| 5765 | 5350 |
| 5766 void generateThrowNoSuchMethod(ast.Node diagnosticNode, | 5351 void generateThrowNoSuchMethod(ast.Node diagnosticNode, String methodName, |
| 5767 String methodName, | 5352 {Link<ast.Node> argumentNodes, |
| 5768 {Link<ast.Node> argumentNodes, | 5353 List<HInstruction> argumentValues, |
| 5769 List<HInstruction> argumentValues, | 5354 List<String> existingArguments, |
| 5770 List<String> existingArguments, | 5355 SourceInformation sourceInformation}) { |
| 5771 SourceInformation sourceInformation}) { | |
| 5772 Element helper = helpers.throwNoSuchMethod; | 5356 Element helper = helpers.throwNoSuchMethod; |
| 5773 ConstantValue receiverConstant = | 5357 ConstantValue receiverConstant = |
| 5774 constantSystem.createString(new ast.DartString.empty()); | 5358 constantSystem.createString(new ast.DartString.empty()); |
| 5775 HInstruction receiver = graph.addConstant(receiverConstant, compiler); | 5359 HInstruction receiver = graph.addConstant(receiverConstant, compiler); |
| 5776 ast.DartString dartString = new ast.DartString.literal(methodName); | 5360 ast.DartString dartString = new ast.DartString.literal(methodName); |
| 5777 ConstantValue nameConstant = constantSystem.createString(dartString); | 5361 ConstantValue nameConstant = constantSystem.createString(dartString); |
| 5778 HInstruction name = graph.addConstant(nameConstant, compiler); | 5362 HInstruction name = graph.addConstant(nameConstant, compiler); |
| 5779 if (argumentValues == null) { | 5363 if (argumentValues == null) { |
| 5780 argumentValues = <HInstruction>[]; | 5364 argumentValues = <HInstruction>[]; |
| 5781 argumentNodes.forEach((argumentNode) { | 5365 argumentNodes.forEach((argumentNode) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 5792 for (String name in existingArguments) { | 5376 for (String name in existingArguments) { |
| 5793 HInstruction nameConstant = | 5377 HInstruction nameConstant = |
| 5794 graph.addConstantString(new ast.DartString.literal(name), compiler); | 5378 graph.addConstantString(new ast.DartString.literal(name), compiler); |
| 5795 existingNames.add(nameConstant); | 5379 existingNames.add(nameConstant); |
| 5796 } | 5380 } |
| 5797 existingNamesList = buildLiteralList(existingNames); | 5381 existingNamesList = buildLiteralList(existingNames); |
| 5798 add(existingNamesList); | 5382 add(existingNamesList); |
| 5799 } else { | 5383 } else { |
| 5800 existingNamesList = graph.addConstantNull(compiler); | 5384 existingNamesList = graph.addConstantNull(compiler); |
| 5801 } | 5385 } |
| 5802 pushInvokeStatic(diagnosticNode, | 5386 pushInvokeStatic( |
| 5803 helper, | 5387 diagnosticNode, helper, [receiver, name, arguments, existingNamesList], |
| 5804 [receiver, name, arguments, existingNamesList], | 5388 sourceInformation: sourceInformation); |
| 5805 sourceInformation: sourceInformation); | |
| 5806 } | 5389 } |
| 5807 | 5390 |
| 5808 /** | 5391 /** |
| 5809 * Generate code to throw a [NoSuchMethodError] exception for calling a | 5392 * Generate code to throw a [NoSuchMethodError] exception for calling a |
| 5810 * method with a wrong number of arguments or mismatching named optional | 5393 * method with a wrong number of arguments or mismatching named optional |
| 5811 * arguments. | 5394 * arguments. |
| 5812 */ | 5395 */ |
| 5813 void generateWrongArgumentCountError(ast.Node diagnosticNode, | 5396 void generateWrongArgumentCountError(ast.Node diagnosticNode, |
| 5814 FunctionElement function, | 5397 FunctionElement function, Link<ast.Node> argumentNodes) { |
| 5815 Link<ast.Node> argumentNodes) { | |
| 5816 List<String> existingArguments = <String>[]; | 5398 List<String> existingArguments = <String>[]; |
| 5817 FunctionSignature signature = function.functionSignature; | 5399 FunctionSignature signature = function.functionSignature; |
| 5818 signature.forEachParameter((Element parameter) { | 5400 signature.forEachParameter((Element parameter) { |
| 5819 existingArguments.add(parameter.name); | 5401 existingArguments.add(parameter.name); |
| 5820 }); | 5402 }); |
| 5821 generateThrowNoSuchMethod(diagnosticNode, | 5403 generateThrowNoSuchMethod(diagnosticNode, function.name, |
| 5822 function.name, | 5404 argumentNodes: argumentNodes, existingArguments: existingArguments); |
| 5823 argumentNodes: argumentNodes, | |
| 5824 existingArguments: existingArguments); | |
| 5825 } | 5405 } |
| 5826 | 5406 |
| 5827 @override | 5407 @override |
| 5828 void bulkHandleNode(ast.Node node, String message, _) { | 5408 void bulkHandleNode(ast.Node node, String message, _) { |
| 5829 internalError(node, "Unexpected bulk handled node: $node"); | 5409 internalError(node, "Unexpected bulk handled node: $node"); |
| 5830 } | 5410 } |
| 5831 | 5411 |
| 5832 @override | 5412 @override |
| 5833 void bulkHandleNew(ast.NewExpression node, [_]) { | 5413 void bulkHandleNew(ast.NewExpression node, [_]) { |
| 5834 Element element = elements[node.send]; | 5414 Element element = elements[node.send]; |
| 5835 final bool isSymbolConstructor = element == compiler.symbolConstructor; | 5415 final bool isSymbolConstructor = element == compiler.symbolConstructor; |
| 5836 if (!Elements.isMalformed(element)) { | 5416 if (!Elements.isMalformed(element)) { |
| 5837 ConstructorElement function = element; | 5417 ConstructorElement function = element; |
| 5838 element = function.effectiveTarget; | 5418 element = function.effectiveTarget; |
| 5839 } | 5419 } |
| 5840 if (Elements.isError(element)) { | 5420 if (Elements.isError(element)) { |
| 5841 ErroneousElement error = element; | 5421 ErroneousElement error = element; |
| 5842 if (error.messageKind == MessageKind.CANNOT_FIND_CONSTRUCTOR || | 5422 if (error.messageKind == MessageKind.CANNOT_FIND_CONSTRUCTOR || |
| 5843 error.messageKind == MessageKind.CANNOT_FIND_UNNAMED_CONSTRUCTOR) { | 5423 error.messageKind == MessageKind.CANNOT_FIND_UNNAMED_CONSTRUCTOR) { |
| 5844 generateThrowNoSuchMethod( | 5424 generateThrowNoSuchMethod( |
| 5845 node.send, | 5425 node.send, noSuchMethodTargetSymbolString(error, 'constructor'), |
| 5846 noSuchMethodTargetSymbolString(error, 'constructor'), | |
| 5847 argumentNodes: node.send.arguments); | 5426 argumentNodes: node.send.arguments); |
| 5848 } else { | 5427 } else { |
| 5849 MessageTemplate template = MessageTemplate.TEMPLATES[error.messageKind]; | 5428 MessageTemplate template = MessageTemplate.TEMPLATES[error.messageKind]; |
| 5850 Message message = template.message(error.messageArguments); | 5429 Message message = template.message(error.messageArguments); |
| 5851 generateRuntimeError(node.send, message.toString()); | 5430 generateRuntimeError(node.send, message.toString()); |
| 5852 } | 5431 } |
| 5853 } else if (Elements.isMalformed(element)) { | 5432 } else if (Elements.isMalformed(element)) { |
| 5854 // TODO(ahe): Do something like [generateWrongArgumentCountError]. | 5433 // TODO(ahe): Do something like [generateWrongArgumentCountError]. |
| 5855 stack.add(graph.addConstantNull(compiler)); | 5434 stack.add(graph.addConstantNull(compiler)); |
| 5856 } else if (node.isConst) { | 5435 } else if (node.isConst) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 5870 void errorNonConstantConstructorInvoke( | 5449 void errorNonConstantConstructorInvoke( |
| 5871 ast.NewExpression node, | 5450 ast.NewExpression node, |
| 5872 Element element, | 5451 Element element, |
| 5873 DartType type, | 5452 DartType type, |
| 5874 ast.NodeList arguments, | 5453 ast.NodeList arguments, |
| 5875 CallStructure callStructure, | 5454 CallStructure callStructure, |
| 5876 _) { | 5455 _) { |
| 5877 bulkHandleNew(node); | 5456 bulkHandleNew(node); |
| 5878 } | 5457 } |
| 5879 | 5458 |
| 5880 void pushInvokeDynamic(ast.Node node, | 5459 void pushInvokeDynamic(ast.Node node, Selector selector, TypeMask mask, |
| 5881 Selector selector, | 5460 List<HInstruction> arguments, |
| 5882 TypeMask mask, | 5461 {SourceInformation sourceInformation}) { |
| 5883 List<HInstruction> arguments, | |
| 5884 {SourceInformation sourceInformation}) { | |
| 5885 | |
| 5886 // We prefer to not inline certain operations on indexables, | 5462 // We prefer to not inline certain operations on indexables, |
| 5887 // because the constant folder will handle them better and turn | 5463 // because the constant folder will handle them better and turn |
| 5888 // them into simpler instructions that allow further | 5464 // them into simpler instructions that allow further |
| 5889 // optimizations. | 5465 // optimizations. |
| 5890 bool isOptimizableOperationOnIndexable(Selector selector, Element element) { | 5466 bool isOptimizableOperationOnIndexable(Selector selector, Element element) { |
| 5891 bool isLength = selector.isGetter | 5467 bool isLength = selector.isGetter && selector.name == "length"; |
| 5892 && selector.name == "length"; | |
| 5893 if (isLength || selector.isIndex) { | 5468 if (isLength || selector.isIndex) { |
| 5894 return compiler.world.isSubtypeOf( | 5469 return compiler.world.isSubtypeOf( |
| 5895 element.enclosingClass.declaration, | 5470 element.enclosingClass.declaration, helpers.jsIndexableClass); |
| 5896 helpers.jsIndexableClass); | |
| 5897 } else if (selector.isIndexSet) { | 5471 } else if (selector.isIndexSet) { |
| 5898 return compiler.world.isSubtypeOf( | 5472 return compiler.world.isSubtypeOf(element.enclosingClass.declaration, |
| 5899 element.enclosingClass.declaration, | |
| 5900 helpers.jsMutableIndexableClass); | 5473 helpers.jsMutableIndexableClass); |
| 5901 } else { | 5474 } else { |
| 5902 return false; | 5475 return false; |
| 5903 } | 5476 } |
| 5904 } | 5477 } |
| 5905 | 5478 |
| 5906 bool isOptimizableOperation(Selector selector, Element element) { | 5479 bool isOptimizableOperation(Selector selector, Element element) { |
| 5907 ClassElement cls = element.enclosingClass; | 5480 ClassElement cls = element.enclosingClass; |
| 5908 if (isOptimizableOperationOnIndexable(selector, element)) return true; | 5481 if (isOptimizableOperationOnIndexable(selector, element)) return true; |
| 5909 if (!backend.interceptedClasses.contains(cls)) return false; | 5482 if (!backend.interceptedClasses.contains(cls)) return false; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 5933 HInstruction receiver = arguments[0]; | 5506 HInstruction receiver = arguments[0]; |
| 5934 List<HInstruction> inputs = <HInstruction>[]; | 5507 List<HInstruction> inputs = <HInstruction>[]; |
| 5935 bool isIntercepted = backend.isInterceptedSelector(selector); | 5508 bool isIntercepted = backend.isInterceptedSelector(selector); |
| 5936 if (isIntercepted) { | 5509 if (isIntercepted) { |
| 5937 inputs.add(invokeInterceptor(receiver)); | 5510 inputs.add(invokeInterceptor(receiver)); |
| 5938 } | 5511 } |
| 5939 inputs.addAll(arguments); | 5512 inputs.addAll(arguments); |
| 5940 TypeMask type = | 5513 TypeMask type = |
| 5941 TypeMaskFactory.inferredTypeForSelector(selector, mask, compiler); | 5514 TypeMaskFactory.inferredTypeForSelector(selector, mask, compiler); |
| 5942 if (selector.isGetter) { | 5515 if (selector.isGetter) { |
| 5943 push( | 5516 push(new HInvokeDynamicGetter(selector, mask, null, inputs, type) |
| 5944 new HInvokeDynamicGetter(selector, mask, null, inputs, type) | 5517 ..sourceInformation = sourceInformation); |
| 5945 ..sourceInformation = sourceInformation); | |
| 5946 } else if (selector.isSetter) { | 5518 } else if (selector.isSetter) { |
| 5947 push( | 5519 push(new HInvokeDynamicSetter(selector, mask, null, inputs, type) |
| 5948 new HInvokeDynamicSetter(selector, mask, null, inputs, type) | 5520 ..sourceInformation = sourceInformation); |
| 5949 ..sourceInformation = sourceInformation); | |
| 5950 } else { | 5521 } else { |
| 5951 push( | 5522 push(new HInvokeDynamicMethod(selector, mask, inputs, type, isIntercepted) |
| 5952 new HInvokeDynamicMethod(selector, mask, inputs, type, isIntercepted) | 5523 ..sourceInformation = sourceInformation); |
| 5953 ..sourceInformation = sourceInformation); | |
| 5954 } | 5524 } |
| 5955 } | 5525 } |
| 5956 | 5526 |
| 5957 bool _hasNamedParameters(FunctionElement function) { | 5527 bool _hasNamedParameters(FunctionElement function) { |
| 5958 FunctionSignature params = function.functionSignature; | 5528 FunctionSignature params = function.functionSignature; |
| 5959 return params.optionalParameterCount > 0 | 5529 return params.optionalParameterCount > 0 && |
| 5960 && params.optionalParametersAreNamed; | 5530 params.optionalParametersAreNamed; |
| 5961 } | 5531 } |
| 5962 | 5532 |
| 5963 HForeignCode invokeJsInteropFunction(FunctionElement element, | 5533 HForeignCode invokeJsInteropFunction(FunctionElement element, |
| 5964 List<HInstruction> arguments, | 5534 List<HInstruction> arguments, SourceInformation sourceInformation) { |
| 5965 SourceInformation sourceInformation) { | |
| 5966 assert(backend.isJsInterop(element)); | 5535 assert(backend.isJsInterop(element)); |
| 5967 nativeEmitter.nativeMethods.add(element); | 5536 nativeEmitter.nativeMethods.add(element); |
| 5968 String templateString; | 5537 String templateString; |
| 5969 | 5538 |
| 5970 if (element.isFactoryConstructor && | 5539 if (element.isFactoryConstructor && |
| 5971 backend.jsInteropAnalysis.hasAnonymousAnnotation(element.contextClass))
{ | 5540 backend.jsInteropAnalysis |
| 5541 .hasAnonymousAnnotation(element.contextClass)) { |
| 5972 // Factory constructor that is syntactic sugar for creating a JavaScript | 5542 // Factory constructor that is syntactic sugar for creating a JavaScript |
| 5973 // object literal. | 5543 // object literal. |
| 5974 ConstructorElement constructor = element; | 5544 ConstructorElement constructor = element; |
| 5975 FunctionSignature params = constructor.functionSignature; | 5545 FunctionSignature params = constructor.functionSignature; |
| 5976 int i = 0; | 5546 int i = 0; |
| 5977 int positions = 0; | 5547 int positions = 0; |
| 5978 var filteredArguments = <HInstruction>[]; | 5548 var filteredArguments = <HInstruction>[]; |
| 5979 var parameterNameMap = new Map<String, js.Expression>(); | 5549 var parameterNameMap = new Map<String, js.Expression>(); |
| 5980 params.orderedForEachParameter((ParameterElement parameter) { | 5550 params.orderedForEachParameter((ParameterElement parameter) { |
| 5981 // TODO(jacobr): throw if parameter names do not match names of property | 5551 // TODO(jacobr): throw if parameter names do not match names of property |
| 5982 // names in the class. | 5552 // names in the class. |
| 5983 assert (parameter.isNamed); | 5553 assert(parameter.isNamed); |
| 5984 HInstruction argument = arguments[i]; | 5554 HInstruction argument = arguments[i]; |
| 5985 if (argument != null) { | 5555 if (argument != null) { |
| 5986 filteredArguments.add(argument); | 5556 filteredArguments.add(argument); |
| 5987 parameterNameMap[parameter.name] = | 5557 parameterNameMap[parameter.name] = |
| 5988 new js.InterpolatedExpression(positions++); | 5558 new js.InterpolatedExpression(positions++); |
| 5989 } | 5559 } |
| 5990 i++; | 5560 i++; |
| 5991 }); | 5561 }); |
| 5992 var codeTemplate = new js.Template(null, | 5562 var codeTemplate = |
| 5993 js.objectLiteral(parameterNameMap)); | 5563 new js.Template(null, js.objectLiteral(parameterNameMap)); |
| 5994 | 5564 |
| 5995 var nativeBehavior = new native.NativeBehavior() | 5565 var nativeBehavior = new native.NativeBehavior() |
| 5996 ..codeTemplate = codeTemplate; | 5566 ..codeTemplate = codeTemplate; |
| 5997 if (compiler.options.trustJSInteropTypeAnnotations) { | 5567 if (compiler.options.trustJSInteropTypeAnnotations) { |
| 5998 nativeBehavior.typesReturned.add(constructor.enclosingClass.thisType); | 5568 nativeBehavior.typesReturned.add(constructor.enclosingClass.thisType); |
| 5999 } | 5569 } |
| 6000 return new HForeignCode( | 5570 return new HForeignCode( |
| 6001 codeTemplate, | 5571 codeTemplate, backend.dynamicType, filteredArguments, |
| 6002 backend.dynamicType, filteredArguments, | |
| 6003 nativeBehavior: nativeBehavior) | 5572 nativeBehavior: nativeBehavior) |
| 6004 ..sourceInformation = sourceInformation; | 5573 ..sourceInformation = sourceInformation; |
| 6005 } | 5574 } |
| 6006 var target = new HForeignCode(js.js.parseForeignJS( | 5575 var target = new HForeignCode( |
| 6007 "${backend.namer.fixedBackendPath(element)}." | 5576 js.js.parseForeignJS("${backend.namer.fixedBackendPath(element)}." |
| 6008 "${backend.nativeData.getFixedBackendName(element)}"), | 5577 "${backend.nativeData.getFixedBackendName(element)}"), |
| 6009 backend.dynamicType, | 5578 backend.dynamicType, |
| 6010 <HInstruction>[]); | 5579 <HInstruction>[]); |
| 6011 add(target); | 5580 add(target); |
| 6012 // Strip off trailing arguments that were not specified. | 5581 // Strip off trailing arguments that were not specified. |
| 6013 // we could assert that the trailing arguments are all null. | 5582 // we could assert that the trailing arguments are all null. |
| 6014 // TODO(jacobr): rewrite named arguments to an object literal matching | 5583 // TODO(jacobr): rewrite named arguments to an object literal matching |
| 6015 // the factory constructor case. | 5584 // the factory constructor case. |
| 6016 arguments = arguments.where((arg) => arg != null).toList(); | 5585 arguments = arguments.where((arg) => arg != null).toList(); |
| 6017 var inputs = <HInstruction>[target]..addAll(arguments); | 5586 var inputs = <HInstruction>[target]..addAll(arguments); |
| 6018 | 5587 |
| 6019 var nativeBehavior = new native.NativeBehavior() | 5588 var nativeBehavior = new native.NativeBehavior() |
| 6020 ..sideEffects.setAllSideEffects(); | 5589 ..sideEffects.setAllSideEffects(); |
| 6021 | 5590 |
| 6022 DartType type = element.isConstructor ? | 5591 DartType type = element.isConstructor |
| 6023 element.enclosingClass.thisType : element.type.returnType; | 5592 ? element.enclosingClass.thisType |
| 5593 : element.type.returnType; |
| 6024 // Native behavior effects here are similar to native/behavior.dart. | 5594 // Native behavior effects here are similar to native/behavior.dart. |
| 6025 // The return type is dynamic if we don't trust js-interop type | 5595 // The return type is dynamic if we don't trust js-interop type |
| 6026 // declarations. | 5596 // declarations. |
| 6027 nativeBehavior.typesReturned.add( | 5597 nativeBehavior.typesReturned.add(compiler |
| 6028 compiler.options.trustJSInteropTypeAnnotations | 5598 .options.trustJSInteropTypeAnnotations ? type : const DynamicType()); |
| 6029 ? type : const DynamicType()); | |
| 6030 | 5599 |
| 6031 // The allocation effects include the declared type if it is native (which | 5600 // The allocation effects include the declared type if it is native (which |
| 6032 // includes js interop types). | 5601 // includes js interop types). |
| 6033 if (type.element != null && backend.isNative(type.element)) { | 5602 if (type.element != null && backend.isNative(type.element)) { |
| 6034 nativeBehavior.typesInstantiated.add(type); | 5603 nativeBehavior.typesInstantiated.add(type); |
| 6035 } | 5604 } |
| 6036 | 5605 |
| 6037 // It also includes any other JS interop type if we don't trust the | 5606 // It also includes any other JS interop type if we don't trust the |
| 6038 // annotation or if is declared too broad. | 5607 // annotation or if is declared too broad. |
| 6039 if (!compiler.options.trustJSInteropTypeAnnotations || type.isObject || | 5608 if (!compiler.options.trustJSInteropTypeAnnotations || |
| 5609 type.isObject || |
| 6040 type.isDynamic) { | 5610 type.isDynamic) { |
| 6041 nativeBehavior.typesInstantiated.add( | 5611 nativeBehavior.typesInstantiated |
| 6042 backend.helpers.jsJavaScriptObjectClass.thisType); | 5612 .add(backend.helpers.jsJavaScriptObjectClass.thisType); |
| 6043 } | 5613 } |
| 6044 | 5614 |
| 6045 String code; | 5615 String code; |
| 6046 if (element.isGetter) { | 5616 if (element.isGetter) { |
| 6047 code = "#"; | 5617 code = "#"; |
| 6048 } else if (element.isSetter) { | 5618 } else if (element.isSetter) { |
| 6049 code = "# = #"; | 5619 code = "# = #"; |
| 6050 } else { | 5620 } else { |
| 6051 var args = new List.filled(arguments.length, '#').join(','); | 5621 var args = new List.filled(arguments.length, '#').join(','); |
| 6052 code = element.isConstructor ? "new #($args)" : "#($args)"; | 5622 code = element.isConstructor ? "new #($args)" : "#($args)"; |
| 6053 } | 5623 } |
| 6054 js.Template codeTemplate = js.js.parseForeignJS(code); | 5624 js.Template codeTemplate = js.js.parseForeignJS(code); |
| 6055 nativeBehavior.codeTemplate = codeTemplate; | 5625 nativeBehavior.codeTemplate = codeTemplate; |
| 6056 | 5626 |
| 6057 return new HForeignCode( | 5627 return new HForeignCode(codeTemplate, backend.dynamicType, inputs, |
| 6058 codeTemplate, | 5628 nativeBehavior: nativeBehavior)..sourceInformation = sourceInformation; |
| 6059 backend.dynamicType, inputs, | |
| 6060 nativeBehavior: nativeBehavior) | |
| 6061 ..sourceInformation = sourceInformation; | |
| 6062 } | 5629 } |
| 6063 | 5630 |
| 6064 void pushInvokeStatic(ast.Node location, | 5631 void pushInvokeStatic( |
| 6065 Element element, | 5632 ast.Node location, Element element, List<HInstruction> arguments, |
| 6066 List<HInstruction> arguments, | 5633 {TypeMask typeMask, |
| 6067 {TypeMask typeMask, | 5634 InterfaceType instanceType, |
| 6068 InterfaceType instanceType, | 5635 SourceInformation sourceInformation}) { |
| 6069 SourceInformation sourceInformation}) { | |
| 6070 // TODO(johnniwinther): Use [sourceInformation] instead of [location]. | 5636 // TODO(johnniwinther): Use [sourceInformation] instead of [location]. |
| 6071 if (tryInlineMethod(element, null, null, arguments, location, | 5637 if (tryInlineMethod(element, null, null, arguments, location, |
| 6072 instanceType: instanceType)) { | 5638 instanceType: instanceType)) { |
| 6073 return; | 5639 return; |
| 6074 } | 5640 } |
| 6075 | 5641 |
| 6076 if (typeMask == null) { | 5642 if (typeMask == null) { |
| 6077 typeMask = | 5643 typeMask = |
| 6078 TypeMaskFactory.inferredReturnTypeForElement(element, compiler); | 5644 TypeMaskFactory.inferredReturnTypeForElement(element, compiler); |
| 6079 } | 5645 } |
| 6080 bool targetCanThrow = !compiler.world.getCannotThrow(element); | 5646 bool targetCanThrow = !compiler.world.getCannotThrow(element); |
| 6081 // TODO(5346): Try to avoid the need for calling [declaration] before | 5647 // TODO(5346): Try to avoid the need for calling [declaration] before |
| 6082 var instruction; | 5648 var instruction; |
| 6083 if (backend.isJsInterop(element)) { | 5649 if (backend.isJsInterop(element)) { |
| 6084 instruction = invokeJsInteropFunction(element, arguments, | 5650 instruction = |
| 6085 sourceInformation); | 5651 invokeJsInteropFunction(element, arguments, sourceInformation); |
| 6086 } else { | 5652 } else { |
| 6087 // creating an [HInvokeStatic]. | 5653 // creating an [HInvokeStatic]. |
| 6088 instruction = new HInvokeStatic( | 5654 instruction = new HInvokeStatic(element.declaration, arguments, typeMask, |
| 6089 element.declaration, arguments, typeMask, | |
| 6090 targetCanThrow: targetCanThrow) | 5655 targetCanThrow: targetCanThrow) |
| 6091 ..sourceInformation = sourceInformation; | 5656 ..sourceInformation = sourceInformation; |
| 6092 if (!currentInlinedInstantiations.isEmpty) { | 5657 if (!currentInlinedInstantiations.isEmpty) { |
| 6093 instruction.instantiatedTypes = new List<DartType>.from( | 5658 instruction.instantiatedTypes = |
| 6094 currentInlinedInstantiations); | 5659 new List<DartType>.from(currentInlinedInstantiations); |
| 6095 } | 5660 } |
| 6096 instruction.sideEffects = compiler.world.getSideEffectsOfElement(element); | 5661 instruction.sideEffects = compiler.world.getSideEffectsOfElement(element); |
| 6097 } | 5662 } |
| 6098 if (location == null) { | 5663 if (location == null) { |
| 6099 push(instruction); | 5664 push(instruction); |
| 6100 } else { | 5665 } else { |
| 6101 pushWithPosition(instruction, location); | 5666 pushWithPosition(instruction, location); |
| 6102 } | 5667 } |
| 6103 } | 5668 } |
| 6104 | 5669 |
| 6105 HInstruction buildInvokeSuper(Selector selector, | 5670 HInstruction buildInvokeSuper( |
| 6106 Element element, | 5671 Selector selector, Element element, List<HInstruction> arguments, |
| 6107 List<HInstruction> arguments, | 5672 [SourceInformation sourceInformation]) { |
| 6108 [SourceInformation sourceInformation]) { | |
| 6109 HInstruction receiver = localsHandler.readThis(); | 5673 HInstruction receiver = localsHandler.readThis(); |
| 6110 // TODO(5346): Try to avoid the need for calling [declaration] before | 5674 // TODO(5346): Try to avoid the need for calling [declaration] before |
| 6111 // creating an [HStatic]. | 5675 // creating an [HStatic]. |
| 6112 List<HInstruction> inputs = <HInstruction>[]; | 5676 List<HInstruction> inputs = <HInstruction>[]; |
| 6113 if (backend.isInterceptedSelector(selector) && | 5677 if (backend.isInterceptedSelector(selector) && |
| 6114 // Fields don't need an interceptor; consider generating HFieldGet/Set | 5678 // Fields don't need an interceptor; consider generating HFieldGet/Set |
| 6115 // instead. | 5679 // instead. |
| 6116 element.kind != ElementKind.FIELD) { | 5680 element.kind != ElementKind.FIELD) { |
| 6117 inputs.add(invokeInterceptor(receiver)); | 5681 inputs.add(invokeInterceptor(receiver)); |
| 6118 } | 5682 } |
| 6119 inputs.add(receiver); | 5683 inputs.add(receiver); |
| 6120 inputs.addAll(arguments); | 5684 inputs.addAll(arguments); |
| 6121 TypeMask type; | 5685 TypeMask type; |
| 6122 if (!element.isGetter && selector.isGetter) { | 5686 if (!element.isGetter && selector.isGetter) { |
| 6123 type = TypeMaskFactory.inferredTypeForElement(element, compiler); | 5687 type = TypeMaskFactory.inferredTypeForElement(element, compiler); |
| 6124 } else { | 5688 } else { |
| 6125 type = TypeMaskFactory.inferredReturnTypeForElement(element, compiler); | 5689 type = TypeMaskFactory.inferredReturnTypeForElement(element, compiler); |
| 6126 } | 5690 } |
| 6127 HInstruction instruction = new HInvokeSuper( | 5691 HInstruction instruction = new HInvokeSuper(element, currentNonClosureClass, |
| 6128 element, | 5692 selector, inputs, type, sourceInformation, |
| 6129 currentNonClosureClass, | |
| 6130 selector, | |
| 6131 inputs, | |
| 6132 type, | |
| 6133 sourceInformation, | |
| 6134 isSetter: selector.isSetter || selector.isIndexSet); | 5693 isSetter: selector.isSetter || selector.isIndexSet); |
| 6135 instruction.sideEffects = | 5694 instruction.sideEffects = |
| 6136 compiler.world.getSideEffectsOfSelector(selector, null); | 5695 compiler.world.getSideEffectsOfSelector(selector, null); |
| 6137 return instruction; | 5696 return instruction; |
| 6138 } | 5697 } |
| 6139 | 5698 |
| 6140 void handleComplexOperatorSend(ast.SendSet node, | 5699 void handleComplexOperatorSend( |
| 6141 HInstruction receiver, | 5700 ast.SendSet node, HInstruction receiver, Link<ast.Node> arguments) { |
| 6142 Link<ast.Node> arguments) { | |
| 6143 HInstruction rhs; | 5701 HInstruction rhs; |
| 6144 if (node.isPrefix || node.isPostfix) { | 5702 if (node.isPrefix || node.isPostfix) { |
| 6145 rhs = graph.addConstantInt(1, compiler); | 5703 rhs = graph.addConstantInt(1, compiler); |
| 6146 } else { | 5704 } else { |
| 6147 visit(arguments.head); | 5705 visit(arguments.head); |
| 6148 assert(arguments.tail.isEmpty); | 5706 assert(arguments.tail.isEmpty); |
| 6149 rhs = pop(); | 5707 rhs = pop(); |
| 6150 } | 5708 } |
| 6151 visitBinarySend( | 5709 visitBinarySend( |
| 6152 receiver, | 5710 receiver, |
| 6153 rhs, | 5711 rhs, |
| 6154 elements.getOperatorSelectorInComplexSendSet(node), | 5712 elements.getOperatorSelectorInComplexSendSet(node), |
| 6155 elements.getOperatorTypeMaskInComplexSendSet(node), | 5713 elements.getOperatorTypeMaskInComplexSendSet(node), |
| 6156 node, | 5714 node, |
| 6157 sourceInformation: | 5715 sourceInformation: |
| 6158 sourceInformationBuilder.buildGeneric(node.assignmentOperator)); | 5716 sourceInformationBuilder.buildGeneric(node.assignmentOperator)); |
| 6159 } | 5717 } |
| 6160 | 5718 |
| 6161 void handleSuperSendSet(ast.SendSet node) { | 5719 void handleSuperSendSet(ast.SendSet node) { |
| 6162 Element element = elements[node]; | 5720 Element element = elements[node]; |
| 6163 List<HInstruction> setterInputs = <HInstruction>[]; | 5721 List<HInstruction> setterInputs = <HInstruction>[]; |
| 6164 void generateSuperSendSet() { | 5722 void generateSuperSendSet() { |
| 6165 Selector setterSelector = elements.getSelector(node); | 5723 Selector setterSelector = elements.getSelector(node); |
| 6166 if (Elements.isUnresolved(element) | 5724 if (Elements.isUnresolved(element) || |
| 6167 || !setterSelector.applies(element, compiler.world)) { | 5725 !setterSelector.applies(element, compiler.world)) { |
| 6168 generateSuperNoSuchMethodSend( | 5726 generateSuperNoSuchMethodSend(node, setterSelector, setterInputs); |
| 6169 node, setterSelector, setterInputs); | |
| 6170 pop(); | 5727 pop(); |
| 6171 } else { | 5728 } else { |
| 6172 add(buildInvokeSuper(setterSelector, element, setterInputs)); | 5729 add(buildInvokeSuper(setterSelector, element, setterInputs)); |
| 6173 } | 5730 } |
| 6174 } | 5731 } |
| 6175 if (identical(node.assignmentOperator.source, '=')) { | 5732 if (identical(node.assignmentOperator.source, '=')) { |
| 6176 addDynamicSendArgumentsToList(node, setterInputs); | 5733 addDynamicSendArgumentsToList(node, setterInputs); |
| 6177 generateSuperSendSet(); | 5734 generateSuperSendSet(); |
| 6178 stack.add(setterInputs.last); | 5735 stack.add(setterInputs.last); |
| 6179 } else { | 5736 } else { |
| 6180 Element getter = elements[node.selector]; | 5737 Element getter = elements[node.selector]; |
| 6181 List<HInstruction> getterInputs = <HInstruction>[]; | 5738 List<HInstruction> getterInputs = <HInstruction>[]; |
| 6182 Link<ast.Node> arguments = node.arguments; | 5739 Link<ast.Node> arguments = node.arguments; |
| 6183 if (node.isIndex) { | 5740 if (node.isIndex) { |
| 6184 // If node is of the form [:super.foo[0] += 2:], the send has | 5741 // If node is of the form [:super.foo[0] += 2:], the send has |
| 6185 // two arguments: the index and the left hand side. We get | 5742 // two arguments: the index and the left hand side. We get |
| 6186 // the index and add it as input of the getter and the | 5743 // the index and add it as input of the getter and the |
| 6187 // setter. | 5744 // setter. |
| 6188 visit(arguments.head); | 5745 visit(arguments.head); |
| 6189 arguments = arguments.tail; | 5746 arguments = arguments.tail; |
| 6190 HInstruction index = pop(); | 5747 HInstruction index = pop(); |
| 6191 getterInputs.add(index); | 5748 getterInputs.add(index); |
| 6192 setterInputs.add(index); | 5749 setterInputs.add(index); |
| 6193 } | 5750 } |
| 6194 HInstruction getterInstruction; | 5751 HInstruction getterInstruction; |
| 6195 Selector getterSelector = | 5752 Selector getterSelector = |
| 6196 elements.getGetterSelectorInComplexSendSet(node); | 5753 elements.getGetterSelectorInComplexSendSet(node); |
| 6197 if (Elements.isUnresolved(getter)) { | 5754 if (Elements.isUnresolved(getter)) { |
| 6198 generateSuperNoSuchMethodSend( | 5755 generateSuperNoSuchMethodSend(node, getterSelector, getterInputs); |
| 6199 node, | |
| 6200 getterSelector, | |
| 6201 getterInputs); | |
| 6202 getterInstruction = pop(); | 5756 getterInstruction = pop(); |
| 6203 } else { | 5757 } else { |
| 6204 getterInstruction = buildInvokeSuper( | 5758 getterInstruction = |
| 6205 getterSelector, getter, getterInputs); | 5759 buildInvokeSuper(getterSelector, getter, getterInputs); |
| 6206 add(getterInstruction); | 5760 add(getterInstruction); |
| 6207 } | 5761 } |
| 6208 | 5762 |
| 6209 if (node.isIfNullAssignment) { | 5763 if (node.isIfNullAssignment) { |
| 6210 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 5764 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
| 6211 brancher.handleIfNull(() => stack.add(getterInstruction), | 5765 brancher.handleIfNull(() => stack.add(getterInstruction), () { |
| 6212 () { | 5766 addDynamicSendArgumentsToList(node, setterInputs); |
| 6213 addDynamicSendArgumentsToList(node, setterInputs); | 5767 generateSuperSendSet(); |
| 6214 generateSuperSendSet(); | 5768 stack.add(setterInputs.last); |
| 6215 stack.add(setterInputs.last); | 5769 }); |
| 6216 }); | |
| 6217 } else { | 5770 } else { |
| 6218 handleComplexOperatorSend(node, getterInstruction, arguments); | 5771 handleComplexOperatorSend(node, getterInstruction, arguments); |
| 6219 setterInputs.add(pop()); | 5772 setterInputs.add(pop()); |
| 6220 generateSuperSendSet(); | 5773 generateSuperSendSet(); |
| 6221 stack.add(node.isPostfix ? getterInstruction : setterInputs.last); | 5774 stack.add(node.isPostfix ? getterInstruction : setterInputs.last); |
| 6222 } | 5775 } |
| 6223 } | 5776 } |
| 6224 } | 5777 } |
| 6225 | 5778 |
| 6226 @override | 5779 @override |
| 6227 void handleSuperCompounds( | 5780 void handleSuperCompounds( |
| 6228 ast.SendSet node, | 5781 ast.SendSet node, |
| 6229 Element getter, | 5782 Element getter, |
| 6230 CompoundGetter getterKind, | 5783 CompoundGetter getterKind, |
| 6231 Element setter, | 5784 Element setter, |
| 6232 CompoundSetter setterKind, | 5785 CompoundSetter setterKind, |
| 6233 CompoundRhs rhs, | 5786 CompoundRhs rhs, |
| 6234 _) { | 5787 _) { |
| 6235 handleSuperSendSet(node); | 5788 handleSuperSendSet(node); |
| 6236 } | 5789 } |
| 6237 | 5790 |
| 6238 @override | 5791 @override |
| 6239 void visitFinalSuperFieldSet( | 5792 void visitFinalSuperFieldSet( |
| 6240 ast.SendSet node, | 5793 ast.SendSet node, FieldElement field, ast.Node rhs, _) { |
| 6241 FieldElement field, | |
| 6242 ast.Node rhs, | |
| 6243 _) { | |
| 6244 handleSuperSendSet(node); | 5794 handleSuperSendSet(node); |
| 6245 } | 5795 } |
| 6246 | 5796 |
| 6247 @override | 5797 @override |
| 6248 void visitSuperFieldSet( | 5798 void visitSuperFieldSet( |
| 6249 ast.SendSet node, | 5799 ast.SendSet node, FieldElement field, ast.Node rhs, _) { |
| 6250 FieldElement field, | |
| 6251 ast.Node rhs, | |
| 6252 _) { | |
| 6253 handleSuperSendSet(node); | 5800 handleSuperSendSet(node); |
| 6254 } | 5801 } |
| 6255 | 5802 |
| 6256 @override | 5803 @override |
| 6257 void visitSuperGetterSet( | 5804 void visitSuperGetterSet( |
| 6258 ast.SendSet node, | 5805 ast.SendSet node, FunctionElement getter, ast.Node rhs, _) { |
| 6259 FunctionElement getter, | |
| 6260 ast.Node rhs, | |
| 6261 _) { | |
| 6262 handleSuperSendSet(node); | 5806 handleSuperSendSet(node); |
| 6263 } | 5807 } |
| 6264 | 5808 |
| 6265 @override | 5809 @override |
| 6266 void visitSuperIndexSet( | 5810 void visitSuperIndexSet(ast.SendSet node, FunctionElement function, |
| 6267 ast.SendSet node, | 5811 ast.Node index, ast.Node rhs, _) { |
| 6268 FunctionElement function, | |
| 6269 ast.Node index, | |
| 6270 ast.Node rhs, | |
| 6271 _) { | |
| 6272 handleSuperSendSet(node); | 5812 handleSuperSendSet(node); |
| 6273 } | 5813 } |
| 6274 | 5814 |
| 6275 @override | 5815 @override |
| 6276 void visitSuperMethodSet( | 5816 void visitSuperMethodSet( |
| 6277 ast.Send node, | 5817 ast.Send node, MethodElement method, ast.Node rhs, _) { |
| 6278 MethodElement method, | |
| 6279 ast.Node rhs, | |
| 6280 _) { | |
| 6281 handleSuperSendSet(node); | 5818 handleSuperSendSet(node); |
| 6282 } | 5819 } |
| 6283 | 5820 |
| 6284 @override | 5821 @override |
| 6285 void visitSuperSetterSet( | 5822 void visitSuperSetterSet( |
| 6286 ast.SendSet node, | 5823 ast.SendSet node, FunctionElement setter, ast.Node rhs, _) { |
| 6287 FunctionElement setter, | |
| 6288 ast.Node rhs, | |
| 6289 _) { | |
| 6290 handleSuperSendSet(node); | 5824 handleSuperSendSet(node); |
| 6291 } | 5825 } |
| 6292 | 5826 |
| 6293 @override | 5827 @override |
| 6294 void visitUnresolvedSuperIndexSet( | 5828 void visitUnresolvedSuperIndexSet( |
| 6295 ast.Send node, | 5829 ast.Send node, Element element, ast.Node index, ast.Node rhs, _) { |
| 6296 Element element, | |
| 6297 ast.Node index, | |
| 6298 ast.Node rhs, | |
| 6299 _) { | |
| 6300 handleSuperSendSet(node); | 5830 handleSuperSendSet(node); |
| 6301 } | 5831 } |
| 6302 | 5832 |
| 6303 @override | 5833 @override |
| 6304 void visitSuperIndexPrefix( | 5834 void visitSuperIndexPrefix( |
| 6305 ast.Send node, | 5835 ast.Send node, |
| 6306 MethodElement indexFunction, | 5836 MethodElement indexFunction, |
| 6307 MethodElement indexSetFunction, | 5837 MethodElement indexSetFunction, |
| 6308 ast.Node index, | 5838 ast.Node index, |
| 6309 IncDecOperator operator, | 5839 IncDecOperator operator, |
| 6310 _) { | 5840 _) { |
| 6311 handleSuperSendSet(node); | 5841 handleSuperSendSet(node); |
| 6312 } | 5842 } |
| 6313 | 5843 |
| 6314 @override | 5844 @override |
| 6315 void visitSuperIndexPostfix( | 5845 void visitSuperIndexPostfix( |
| 6316 ast.Send node, | 5846 ast.Send node, |
| 6317 MethodElement indexFunction, | 5847 MethodElement indexFunction, |
| 6318 MethodElement indexSetFunction, | 5848 MethodElement indexSetFunction, |
| 6319 ast.Node index, | 5849 ast.Node index, |
| 6320 IncDecOperator operator, | 5850 IncDecOperator operator, |
| 6321 _) { | 5851 _) { |
| 6322 handleSuperSendSet(node); | 5852 handleSuperSendSet(node); |
| 6323 } | 5853 } |
| 6324 | 5854 |
| 6325 @override | 5855 @override |
| 6326 void visitUnresolvedSuperGetterIndexPrefix( | 5856 void visitUnresolvedSuperGetterIndexPrefix(ast.Send node, Element element, |
| 6327 ast.Send node, | 5857 MethodElement setter, ast.Node index, IncDecOperator operator, _) { |
| 6328 Element element, | |
| 6329 MethodElement setter, | |
| 6330 ast.Node index, | |
| 6331 IncDecOperator operator, | |
| 6332 _) { | |
| 6333 handleSuperSendSet(node); | 5858 handleSuperSendSet(node); |
| 6334 } | 5859 } |
| 6335 | 5860 |
| 6336 @override | 5861 @override |
| 6337 void visitUnresolvedSuperGetterIndexPostfix( | 5862 void visitUnresolvedSuperGetterIndexPostfix(ast.Send node, Element element, |
| 6338 ast.Send node, | 5863 MethodElement setter, ast.Node index, IncDecOperator operator, _) { |
| 6339 Element element, | |
| 6340 MethodElement setter, | |
| 6341 ast.Node index, | |
| 6342 IncDecOperator operator, | |
| 6343 _) { | |
| 6344 handleSuperSendSet(node); | 5864 handleSuperSendSet(node); |
| 6345 } | 5865 } |
| 6346 | 5866 |
| 6347 @override | 5867 @override |
| 6348 void visitUnresolvedSuperSetterIndexPrefix( | 5868 void visitUnresolvedSuperSetterIndexPrefix( |
| 6349 ast.Send node, | 5869 ast.Send node, |
| 6350 MethodElement indexFunction, | 5870 MethodElement indexFunction, |
| 6351 Element element, | 5871 Element element, |
| 6352 ast.Node index, | 5872 ast.Node index, |
| 6353 IncDecOperator operator, | 5873 IncDecOperator operator, |
| 6354 _) { | 5874 _) { |
| 6355 handleSuperSendSet(node); | 5875 handleSuperSendSet(node); |
| 6356 } | 5876 } |
| 6357 | 5877 |
| 6358 @override | 5878 @override |
| 6359 void visitUnresolvedSuperSetterIndexPostfix( | 5879 void visitUnresolvedSuperSetterIndexPostfix( |
| 6360 ast.Send node, | 5880 ast.Send node, |
| 6361 MethodElement indexFunction, | 5881 MethodElement indexFunction, |
| 6362 Element element, | 5882 Element element, |
| 6363 ast.Node index, | 5883 ast.Node index, |
| 6364 IncDecOperator operator, | 5884 IncDecOperator operator, |
| 6365 _) { | 5885 _) { |
| 6366 handleSuperSendSet(node); | 5886 handleSuperSendSet(node); |
| 6367 } | 5887 } |
| 6368 | 5888 |
| 6369 @override | 5889 @override |
| 6370 void visitUnresolvedSuperIndexPrefix( | 5890 void visitUnresolvedSuperIndexPrefix(ast.Send node, Element element, |
| 6371 ast.Send node, | 5891 ast.Node index, IncDecOperator operator, _) { |
| 6372 Element element, | |
| 6373 ast.Node index, | |
| 6374 IncDecOperator operator, | |
| 6375 _) { | |
| 6376 handleSuperSendSet(node); | 5892 handleSuperSendSet(node); |
| 6377 } | 5893 } |
| 6378 | 5894 |
| 6379 @override | 5895 @override |
| 6380 void visitUnresolvedSuperIndexPostfix( | 5896 void visitUnresolvedSuperIndexPostfix(ast.Send node, Element element, |
| 6381 ast.Send node, | 5897 ast.Node index, IncDecOperator operator, _) { |
| 6382 Element element, | |
| 6383 ast.Node index, | |
| 6384 IncDecOperator operator, | |
| 6385 _) { | |
| 6386 handleSuperSendSet(node); | 5898 handleSuperSendSet(node); |
| 6387 } | 5899 } |
| 6388 | 5900 |
| 6389 @override | 5901 @override |
| 6390 void visitSuperCompoundIndexSet( | 5902 void visitSuperCompoundIndexSet( |
| 6391 ast.SendSet node, | 5903 ast.SendSet node, |
| 6392 MethodElement getter, | 5904 MethodElement getter, |
| 6393 MethodElement setter, | 5905 MethodElement setter, |
| 6394 ast.Node index, | 5906 ast.Node index, |
| 6395 AssignmentOperator operator, | 5907 AssignmentOperator operator, |
| (...skipping 20 matching lines...) Expand all Loading... |
| 6416 MethodElement getter, | 5928 MethodElement getter, |
| 6417 Element element, | 5929 Element element, |
| 6418 ast.Node index, | 5930 ast.Node index, |
| 6419 AssignmentOperator operator, | 5931 AssignmentOperator operator, |
| 6420 ast.Node rhs, | 5932 ast.Node rhs, |
| 6421 _) { | 5933 _) { |
| 6422 handleSuperSendSet(node); | 5934 handleSuperSendSet(node); |
| 6423 } | 5935 } |
| 6424 | 5936 |
| 6425 @override | 5937 @override |
| 6426 void visitUnresolvedSuperCompoundIndexSet( | 5938 void visitUnresolvedSuperCompoundIndexSet(ast.Send node, Element element, |
| 6427 ast.Send node, | 5939 ast.Node index, AssignmentOperator operator, ast.Node rhs, _) { |
| 6428 Element element, | |
| 6429 ast.Node index, | |
| 6430 AssignmentOperator operator, | |
| 6431 ast.Node rhs, | |
| 6432 _) { | |
| 6433 handleSuperSendSet(node); | 5940 handleSuperSendSet(node); |
| 6434 } | 5941 } |
| 6435 | 5942 |
| 6436 @override | 5943 @override |
| 6437 void visitSuperFieldCompound( | 5944 void visitSuperFieldCompound(ast.Send node, FieldElement field, |
| 6438 ast.Send node, | 5945 AssignmentOperator operator, ast.Node rhs, _) { |
| 6439 FieldElement field, | |
| 6440 AssignmentOperator operator, | |
| 6441 ast.Node rhs, | |
| 6442 _) { | |
| 6443 handleSuperSendSet(node); | 5946 handleSuperSendSet(node); |
| 6444 } | 5947 } |
| 6445 | 5948 |
| 6446 @override | 5949 @override |
| 6447 void visitFinalSuperFieldCompound( | 5950 void visitFinalSuperFieldCompound(ast.Send node, FieldElement field, |
| 6448 ast.Send node, | 5951 AssignmentOperator operator, ast.Node rhs, _) { |
| 6449 FieldElement field, | |
| 6450 AssignmentOperator operator, | |
| 6451 ast.Node rhs, | |
| 6452 _) { | |
| 6453 handleSuperSendSet(node); | 5952 handleSuperSendSet(node); |
| 6454 } | 5953 } |
| 6455 | 5954 |
| 6456 @override | 5955 @override |
| 6457 void visitFinalSuperFieldPrefix( | 5956 void visitFinalSuperFieldPrefix( |
| 6458 ast.Send node, | 5957 ast.Send node, FieldElement field, IncDecOperator operator, _) { |
| 6459 FieldElement field, | |
| 6460 IncDecOperator operator, | |
| 6461 _) { | |
| 6462 handleSuperSendSet(node); | 5958 handleSuperSendSet(node); |
| 6463 } | 5959 } |
| 6464 | 5960 |
| 6465 @override | 5961 @override |
| 6466 void visitUnresolvedSuperPrefix( | 5962 void visitUnresolvedSuperPrefix( |
| 6467 ast.Send node, | 5963 ast.Send node, Element element, IncDecOperator operator, _) { |
| 6468 Element element, | |
| 6469 IncDecOperator operator, | |
| 6470 _) { | |
| 6471 handleSuperSendSet(node); | 5964 handleSuperSendSet(node); |
| 6472 } | 5965 } |
| 6473 | 5966 |
| 6474 @override | 5967 @override |
| 6475 void visitUnresolvedSuperPostfix( | 5968 void visitUnresolvedSuperPostfix( |
| 6476 ast.Send node, | 5969 ast.Send node, Element element, IncDecOperator operator, _) { |
| 6477 Element element, | |
| 6478 IncDecOperator operator, | |
| 6479 _) { | |
| 6480 handleSuperSendSet(node); | 5970 handleSuperSendSet(node); |
| 6481 } | 5971 } |
| 6482 | 5972 |
| 6483 @override | 5973 @override |
| 6484 void visitUnresolvedSuperCompound( | 5974 void visitUnresolvedSuperCompound(ast.Send node, Element element, |
| 6485 ast.Send node, | 5975 AssignmentOperator operator, ast.Node rhs, _) { |
| 6486 Element element, | |
| 6487 AssignmentOperator operator, | |
| 6488 ast.Node rhs, | |
| 6489 _) { | |
| 6490 handleSuperSendSet(node); | 5976 handleSuperSendSet(node); |
| 6491 } | 5977 } |
| 6492 | 5978 |
| 6493 @override | 5979 @override |
| 6494 void visitFinalSuperFieldPostfix( | 5980 void visitFinalSuperFieldPostfix( |
| 6495 ast.Send node, | 5981 ast.Send node, FieldElement field, IncDecOperator operator, _) { |
| 6496 FieldElement field, | |
| 6497 IncDecOperator operator, | |
| 6498 _) { | |
| 6499 handleSuperSendSet(node); | 5982 handleSuperSendSet(node); |
| 6500 } | 5983 } |
| 6501 | 5984 |
| 6502 @override | 5985 @override |
| 6503 void visitSuperFieldFieldCompound( | 5986 void visitSuperFieldFieldCompound(ast.Send node, FieldElement readField, |
| 6504 ast.Send node, | 5987 FieldElement writtenField, AssignmentOperator operator, ast.Node rhs, _) { |
| 6505 FieldElement readField, | |
| 6506 FieldElement writtenField, | |
| 6507 AssignmentOperator operator, | |
| 6508 ast.Node rhs, | |
| 6509 _) { | |
| 6510 handleSuperSendSet(node); | 5988 handleSuperSendSet(node); |
| 6511 } | 5989 } |
| 6512 | 5990 |
| 6513 @override | 5991 @override |
| 6514 void visitSuperGetterSetterCompound( | 5992 void visitSuperGetterSetterCompound(ast.Send node, FunctionElement getter, |
| 6515 ast.Send node, | 5993 FunctionElement setter, AssignmentOperator operator, ast.Node rhs, _) { |
| 6516 FunctionElement getter, | |
| 6517 FunctionElement setter, | |
| 6518 AssignmentOperator operator, | |
| 6519 ast.Node rhs, | |
| 6520 _) { | |
| 6521 handleSuperSendSet(node); | 5994 handleSuperSendSet(node); |
| 6522 } | 5995 } |
| 6523 | 5996 |
| 6524 @override | 5997 @override |
| 6525 void visitSuperMethodSetterCompound( | 5998 void visitSuperMethodSetterCompound(ast.Send node, FunctionElement method, |
| 6526 ast.Send node, | 5999 FunctionElement setter, AssignmentOperator operator, ast.Node rhs, _) { |
| 6527 FunctionElement method, | |
| 6528 FunctionElement setter, | |
| 6529 AssignmentOperator operator, | |
| 6530 ast.Node rhs, | |
| 6531 _) { | |
| 6532 handleSuperSendSet(node); | 6000 handleSuperSendSet(node); |
| 6533 } | 6001 } |
| 6534 | 6002 |
| 6535 @override | 6003 @override |
| 6536 void visitSuperMethodCompound( | 6004 void visitSuperMethodCompound(ast.Send node, FunctionElement method, |
| 6537 ast.Send node, | 6005 AssignmentOperator operator, ast.Node rhs, _) { |
| 6538 FunctionElement method, | |
| 6539 AssignmentOperator operator, | |
| 6540 ast.Node rhs, | |
| 6541 _) { | |
| 6542 handleSuperSendSet(node); | 6006 handleSuperSendSet(node); |
| 6543 } | 6007 } |
| 6544 | 6008 |
| 6545 @override | 6009 @override |
| 6546 void visitUnresolvedSuperGetterCompound( | 6010 void visitUnresolvedSuperGetterCompound(ast.Send node, Element element, |
| 6547 ast.Send node, | 6011 MethodElement setter, AssignmentOperator operator, ast.Node rhs, _) { |
| 6548 Element element, | |
| 6549 MethodElement setter, | |
| 6550 AssignmentOperator operator, | |
| 6551 ast.Node rhs, | |
| 6552 _) { | |
| 6553 handleSuperSendSet(node); | 6012 handleSuperSendSet(node); |
| 6554 } | 6013 } |
| 6555 | 6014 |
| 6556 @override | 6015 @override |
| 6557 void visitUnresolvedSuperSetterCompound( | 6016 void visitUnresolvedSuperSetterCompound(ast.Send node, MethodElement getter, |
| 6558 ast.Send node, | 6017 Element element, AssignmentOperator operator, ast.Node rhs, _) { |
| 6559 MethodElement getter, | |
| 6560 Element element, | |
| 6561 AssignmentOperator operator, | |
| 6562 ast.Node rhs, | |
| 6563 _) { | |
| 6564 handleSuperSendSet(node); | 6018 handleSuperSendSet(node); |
| 6565 } | 6019 } |
| 6566 | 6020 |
| 6567 @override | 6021 @override |
| 6568 void visitSuperFieldSetterCompound( | 6022 void visitSuperFieldSetterCompound(ast.Send node, FieldElement field, |
| 6569 ast.Send node, | 6023 FunctionElement setter, AssignmentOperator operator, ast.Node rhs, _) { |
| 6570 FieldElement field, | |
| 6571 FunctionElement setter, | |
| 6572 AssignmentOperator operator, | |
| 6573 ast.Node rhs, | |
| 6574 _) { | |
| 6575 handleSuperSendSet(node); | 6024 handleSuperSendSet(node); |
| 6576 } | 6025 } |
| 6577 | 6026 |
| 6578 @override | 6027 @override |
| 6579 void visitSuperGetterFieldCompound( | 6028 void visitSuperGetterFieldCompound(ast.Send node, FunctionElement getter, |
| 6580 ast.Send node, | 6029 FieldElement field, AssignmentOperator operator, ast.Node rhs, _) { |
| 6581 FunctionElement getter, | |
| 6582 FieldElement field, | |
| 6583 AssignmentOperator operator, | |
| 6584 ast.Node rhs, | |
| 6585 _) { | |
| 6586 handleSuperSendSet(node); | 6030 handleSuperSendSet(node); |
| 6587 } | 6031 } |
| 6588 | 6032 |
| 6589 @override | 6033 @override |
| 6590 void visitIndexSet( | 6034 void visitIndexSet( |
| 6591 ast.SendSet node, | 6035 ast.SendSet node, ast.Node receiver, ast.Node index, ast.Node rhs, _) { |
| 6592 ast.Node receiver, | |
| 6593 ast.Node index, | |
| 6594 ast.Node rhs, | |
| 6595 _) { | |
| 6596 generateDynamicSend(node); | 6036 generateDynamicSend(node); |
| 6597 } | 6037 } |
| 6598 | 6038 |
| 6599 @override | 6039 @override |
| 6600 void visitCompoundIndexSet( | 6040 void visitCompoundIndexSet(ast.SendSet node, ast.Node receiver, |
| 6601 ast.SendSet node, | 6041 ast.Node index, AssignmentOperator operator, ast.Node rhs, _) { |
| 6602 ast.Node receiver, | |
| 6603 ast.Node index, | |
| 6604 AssignmentOperator operator, | |
| 6605 ast.Node rhs, | |
| 6606 _) { | |
| 6607 generateIsDeferredLoadedCheckOfSend(node); | 6042 generateIsDeferredLoadedCheckOfSend(node); |
| 6608 handleIndexSendSet(node); | 6043 handleIndexSendSet(node); |
| 6609 } | 6044 } |
| 6610 | 6045 |
| 6611 @override | 6046 @override |
| 6612 void visitIndexPrefix( | 6047 void visitIndexPrefix(ast.Send node, ast.Node receiver, ast.Node index, |
| 6613 ast.Send node, | 6048 IncDecOperator operator, _) { |
| 6614 ast.Node receiver, | |
| 6615 ast.Node index, | |
| 6616 IncDecOperator operator, | |
| 6617 _) { | |
| 6618 generateIsDeferredLoadedCheckOfSend(node); | 6049 generateIsDeferredLoadedCheckOfSend(node); |
| 6619 handleIndexSendSet(node); | 6050 handleIndexSendSet(node); |
| 6620 } | 6051 } |
| 6621 | 6052 |
| 6622 @override | 6053 @override |
| 6623 void visitIndexPostfix( | 6054 void visitIndexPostfix(ast.Send node, ast.Node receiver, ast.Node index, |
| 6624 ast.Send node, | 6055 IncDecOperator operator, _) { |
| 6625 ast.Node receiver, | |
| 6626 ast.Node index, | |
| 6627 IncDecOperator operator, | |
| 6628 _) { | |
| 6629 generateIsDeferredLoadedCheckOfSend(node); | 6056 generateIsDeferredLoadedCheckOfSend(node); |
| 6630 handleIndexSendSet(node); | 6057 handleIndexSendSet(node); |
| 6631 } | 6058 } |
| 6632 | 6059 |
| 6633 void handleIndexSendSet(ast.SendSet node) { | 6060 void handleIndexSendSet(ast.SendSet node) { |
| 6634 ast.Operator op = node.assignmentOperator; | 6061 ast.Operator op = node.assignmentOperator; |
| 6635 if ("=" == op.source) { | 6062 if ("=" == op.source) { |
| 6636 internalError(node, "Unexpected index set."); | 6063 internalError(node, "Unexpected index set."); |
| 6637 } else { | 6064 } else { |
| 6638 visit(node.receiver); | 6065 visit(node.receiver); |
| 6639 HInstruction receiver = pop(); | 6066 HInstruction receiver = pop(); |
| 6640 Link<ast.Node> arguments = node.arguments; | 6067 Link<ast.Node> arguments = node.arguments; |
| 6641 HInstruction index; | 6068 HInstruction index; |
| 6642 if (node.isIndex) { | 6069 if (node.isIndex) { |
| 6643 visit(arguments.head); | 6070 visit(arguments.head); |
| 6644 arguments = arguments.tail; | 6071 arguments = arguments.tail; |
| 6645 index = pop(); | 6072 index = pop(); |
| 6646 } | 6073 } |
| 6647 | 6074 |
| 6648 pushInvokeDynamic( | 6075 pushInvokeDynamic(node, elements.getGetterSelectorInComplexSendSet(node), |
| 6649 node, | 6076 elements.getGetterTypeMaskInComplexSendSet(node), [receiver, index]); |
| 6650 elements.getGetterSelectorInComplexSendSet(node), | |
| 6651 elements.getGetterTypeMaskInComplexSendSet(node), | |
| 6652 [receiver, index]); | |
| 6653 HInstruction getterInstruction = pop(); | 6077 HInstruction getterInstruction = pop(); |
| 6654 if (node.isIfNullAssignment) { | 6078 if (node.isIfNullAssignment) { |
| 6655 // Compile x[i] ??= e as: | 6079 // Compile x[i] ??= e as: |
| 6656 // t1 = x[i] | 6080 // t1 = x[i] |
| 6657 // if (t1 == null) | 6081 // if (t1 == null) |
| 6658 // t1 = x[i] = e; | 6082 // t1 = x[i] = e; |
| 6659 // result = t1 | 6083 // result = t1 |
| 6660 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 6084 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
| 6661 brancher.handleIfNull(() => stack.add(getterInstruction), | 6085 brancher.handleIfNull(() => stack.add(getterInstruction), () { |
| 6662 () { | 6086 visit(arguments.head); |
| 6663 visit(arguments.head); | 6087 HInstruction value = pop(); |
| 6664 HInstruction value = pop(); | 6088 pushInvokeDynamic(node, elements.getSelector(node), |
| 6665 pushInvokeDynamic( | 6089 elements.getTypeMask(node), [receiver, index, value]); |
| 6666 node, | 6090 pop(); |
| 6667 elements.getSelector(node), | 6091 stack.add(value); |
| 6668 elements.getTypeMask(node), | 6092 }); |
| 6669 [receiver, index, value]); | |
| 6670 pop(); | |
| 6671 stack.add(value); | |
| 6672 }); | |
| 6673 } else { | 6093 } else { |
| 6674 handleComplexOperatorSend(node, getterInstruction, arguments); | 6094 handleComplexOperatorSend(node, getterInstruction, arguments); |
| 6675 HInstruction value = pop(); | 6095 HInstruction value = pop(); |
| 6676 pushInvokeDynamic( | 6096 pushInvokeDynamic(node, elements.getSelector(node), |
| 6677 node, | 6097 elements.getTypeMask(node), [receiver, index, value]); |
| 6678 elements.getSelector(node), | |
| 6679 elements.getTypeMask(node), | |
| 6680 [receiver, index, value]); | |
| 6681 pop(); | 6098 pop(); |
| 6682 if (node.isPostfix) { | 6099 if (node.isPostfix) { |
| 6683 stack.add(getterInstruction); | 6100 stack.add(getterInstruction); |
| 6684 } else { | 6101 } else { |
| 6685 stack.add(value); | 6102 stack.add(value); |
| 6686 } | 6103 } |
| 6687 } | 6104 } |
| 6688 } | 6105 } |
| 6689 } | 6106 } |
| 6690 | 6107 |
| 6691 @override | 6108 @override |
| 6692 void visitThisPropertySet( | 6109 void visitThisPropertySet(ast.SendSet node, Name name, ast.Node rhs, _) { |
| 6693 ast.SendSet node, | |
| 6694 Name name, | |
| 6695 ast.Node rhs, | |
| 6696 _) { | |
| 6697 generateInstanceSetterWithCompiledReceiver( | 6110 generateInstanceSetterWithCompiledReceiver( |
| 6698 node, | 6111 node, localsHandler.readThis(), visitAndPop(rhs)); |
| 6699 localsHandler.readThis(), | |
| 6700 visitAndPop(rhs)); | |
| 6701 } | 6112 } |
| 6702 | 6113 |
| 6703 @override | 6114 @override |
| 6704 void visitDynamicPropertySet( | 6115 void visitDynamicPropertySet( |
| 6705 ast.SendSet node, | 6116 ast.SendSet node, ast.Node receiver, Name name, ast.Node rhs, _) { |
| 6706 ast.Node receiver, | |
| 6707 Name name, | |
| 6708 ast.Node rhs, | |
| 6709 _) { | |
| 6710 generateInstanceSetterWithCompiledReceiver( | 6117 generateInstanceSetterWithCompiledReceiver( |
| 6711 node, | 6118 node, generateInstanceSendReceiver(node), visitAndPop(rhs)); |
| 6712 generateInstanceSendReceiver(node), | |
| 6713 visitAndPop(rhs)); | |
| 6714 } | 6119 } |
| 6715 | 6120 |
| 6716 @override | 6121 @override |
| 6717 void visitIfNotNullDynamicPropertySet( | 6122 void visitIfNotNullDynamicPropertySet( |
| 6718 ast.SendSet node, | 6123 ast.SendSet node, ast.Node receiver, Name name, ast.Node rhs, _) { |
| 6719 ast.Node receiver, | |
| 6720 Name name, | |
| 6721 ast.Node rhs, | |
| 6722 _) { | |
| 6723 // compile e?.x = e2 to: | 6124 // compile e?.x = e2 to: |
| 6724 // | 6125 // |
| 6725 // t1 = e | 6126 // t1 = e |
| 6726 // if (t1 == null) | 6127 // if (t1 == null) |
| 6727 // result = t1 // same as result = null | 6128 // result = t1 // same as result = null |
| 6728 // else | 6129 // else |
| 6729 // result = e.x = e2 | 6130 // result = e.x = e2 |
| 6730 HInstruction receiverInstruction; | 6131 HInstruction receiverInstruction; |
| 6731 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 6132 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
| 6732 brancher.handleConditional( | 6133 brancher.handleConditional( |
| 6733 () { | 6134 () { |
| 6734 receiverInstruction = generateInstanceSendReceiver(node); | 6135 receiverInstruction = generateInstanceSendReceiver(node); |
| 6735 pushCheckNull(receiverInstruction); | 6136 pushCheckNull(receiverInstruction); |
| 6736 }, | 6137 }, |
| 6737 () => stack.add(receiverInstruction), | 6138 () => stack.add(receiverInstruction), |
| 6738 () { | 6139 () { |
| 6739 generateInstanceSetterWithCompiledReceiver( | 6140 generateInstanceSetterWithCompiledReceiver( |
| 6740 node, | 6141 node, receiverInstruction, visitAndPop(rhs)); |
| 6741 receiverInstruction, | |
| 6742 visitAndPop(rhs)); | |
| 6743 }); | 6142 }); |
| 6744 } | 6143 } |
| 6745 | 6144 |
| 6746 @override | 6145 @override |
| 6747 void visitParameterSet( | 6146 void visitParameterSet( |
| 6748 ast.SendSet node, | 6147 ast.SendSet node, ParameterElement parameter, ast.Node rhs, _) { |
| 6749 ParameterElement parameter, | |
| 6750 ast.Node rhs, | |
| 6751 _) { | |
| 6752 generateNonInstanceSetter(node, parameter, visitAndPop(rhs)); | 6148 generateNonInstanceSetter(node, parameter, visitAndPop(rhs)); |
| 6753 } | 6149 } |
| 6754 | 6150 |
| 6755 @override | 6151 @override |
| 6756 void visitFinalParameterSet( | 6152 void visitFinalParameterSet( |
| 6757 ast.SendSet node, | 6153 ast.SendSet node, ParameterElement parameter, ast.Node rhs, _) { |
| 6758 ParameterElement parameter, | |
| 6759 ast.Node rhs, | |
| 6760 _) { | |
| 6761 generateNoSuchSetter(node, parameter, visitAndPop(rhs)); | 6154 generateNoSuchSetter(node, parameter, visitAndPop(rhs)); |
| 6762 } | 6155 } |
| 6763 | 6156 |
| 6764 @override | 6157 @override |
| 6765 void visitLocalVariableSet( | 6158 void visitLocalVariableSet( |
| 6766 ast.SendSet node, | 6159 ast.SendSet node, LocalVariableElement variable, ast.Node rhs, _) { |
| 6767 LocalVariableElement variable, | |
| 6768 ast.Node rhs, | |
| 6769 _) { | |
| 6770 generateNonInstanceSetter(node, variable, visitAndPop(rhs)); | 6160 generateNonInstanceSetter(node, variable, visitAndPop(rhs)); |
| 6771 } | 6161 } |
| 6772 | 6162 |
| 6773 @override | 6163 @override |
| 6774 void visitFinalLocalVariableSet( | 6164 void visitFinalLocalVariableSet( |
| 6775 ast.SendSet node, | 6165 ast.SendSet node, LocalVariableElement variable, ast.Node rhs, _) { |
| 6776 LocalVariableElement variable, | |
| 6777 ast.Node rhs, | |
| 6778 _) { | |
| 6779 generateNoSuchSetter(node, variable, visitAndPop(rhs)); | 6166 generateNoSuchSetter(node, variable, visitAndPop(rhs)); |
| 6780 } | 6167 } |
| 6781 | 6168 |
| 6782 @override | 6169 @override |
| 6783 void visitLocalFunctionSet( | 6170 void visitLocalFunctionSet( |
| 6784 ast.SendSet node, | 6171 ast.SendSet node, LocalFunctionElement function, ast.Node rhs, _) { |
| 6785 LocalFunctionElement function, | |
| 6786 ast.Node rhs, | |
| 6787 _) { | |
| 6788 generateNoSuchSetter(node, function, visitAndPop(rhs)); | 6172 generateNoSuchSetter(node, function, visitAndPop(rhs)); |
| 6789 } | 6173 } |
| 6790 | 6174 |
| 6791 @override | 6175 @override |
| 6792 void visitTopLevelFieldSet( | 6176 void visitTopLevelFieldSet( |
| 6793 ast.SendSet node, | 6177 ast.SendSet node, FieldElement field, ast.Node rhs, _) { |
| 6794 FieldElement field, | |
| 6795 ast.Node rhs, | |
| 6796 _) { | |
| 6797 generateIsDeferredLoadedCheckOfSend(node); | 6178 generateIsDeferredLoadedCheckOfSend(node); |
| 6798 generateNonInstanceSetter(node, field, visitAndPop(rhs)); | 6179 generateNonInstanceSetter(node, field, visitAndPop(rhs)); |
| 6799 } | 6180 } |
| 6800 | 6181 |
| 6801 @override | 6182 @override |
| 6802 void visitFinalTopLevelFieldSet( | 6183 void visitFinalTopLevelFieldSet( |
| 6803 ast.SendSet node, | 6184 ast.SendSet node, FieldElement field, ast.Node rhs, _) { |
| 6804 FieldElement field, | |
| 6805 ast.Node rhs, | |
| 6806 _) { | |
| 6807 generateIsDeferredLoadedCheckOfSend(node); | 6185 generateIsDeferredLoadedCheckOfSend(node); |
| 6808 generateNoSuchSetter(node, field, visitAndPop(rhs)); | 6186 generateNoSuchSetter(node, field, visitAndPop(rhs)); |
| 6809 } | 6187 } |
| 6810 | 6188 |
| 6811 @override | 6189 @override |
| 6812 void visitTopLevelGetterSet( | 6190 void visitTopLevelGetterSet( |
| 6813 ast.SendSet node, | 6191 ast.SendSet node, GetterElement getter, ast.Node rhs, _) { |
| 6814 GetterElement getter, | |
| 6815 ast.Node rhs, | |
| 6816 _) { | |
| 6817 generateIsDeferredLoadedCheckOfSend(node); | 6192 generateIsDeferredLoadedCheckOfSend(node); |
| 6818 generateNoSuchSetter(node, getter, visitAndPop(rhs)); | 6193 generateNoSuchSetter(node, getter, visitAndPop(rhs)); |
| 6819 } | 6194 } |
| 6820 | 6195 |
| 6821 @override | 6196 @override |
| 6822 void visitTopLevelSetterSet( | 6197 void visitTopLevelSetterSet( |
| 6823 ast.SendSet node, | 6198 ast.SendSet node, SetterElement setter, ast.Node rhs, _) { |
| 6824 SetterElement setter, | |
| 6825 ast.Node rhs, | |
| 6826 _) { | |
| 6827 generateIsDeferredLoadedCheckOfSend(node); | 6199 generateIsDeferredLoadedCheckOfSend(node); |
| 6828 generateNonInstanceSetter(node, setter, visitAndPop(rhs)); | 6200 generateNonInstanceSetter(node, setter, visitAndPop(rhs)); |
| 6829 } | 6201 } |
| 6830 | 6202 |
| 6831 @override | 6203 @override |
| 6832 void visitTopLevelFunctionSet( | 6204 void visitTopLevelFunctionSet( |
| 6833 ast.SendSet node, | 6205 ast.SendSet node, MethodElement function, ast.Node rhs, _) { |
| 6834 MethodElement function, | |
| 6835 ast.Node rhs, | |
| 6836 _) { | |
| 6837 generateIsDeferredLoadedCheckOfSend(node); | 6206 generateIsDeferredLoadedCheckOfSend(node); |
| 6838 generateNoSuchSetter(node, function, visitAndPop(rhs)); | 6207 generateNoSuchSetter(node, function, visitAndPop(rhs)); |
| 6839 } | 6208 } |
| 6840 | 6209 |
| 6841 @override | 6210 @override |
| 6842 void visitStaticFieldSet( | 6211 void visitStaticFieldSet( |
| 6843 ast.SendSet node, | 6212 ast.SendSet node, FieldElement field, ast.Node rhs, _) { |
| 6844 FieldElement field, | |
| 6845 ast.Node rhs, | |
| 6846 _) { | |
| 6847 generateIsDeferredLoadedCheckOfSend(node); | 6213 generateIsDeferredLoadedCheckOfSend(node); |
| 6848 generateNonInstanceSetter(node, field, visitAndPop(rhs)); | 6214 generateNonInstanceSetter(node, field, visitAndPop(rhs)); |
| 6849 } | 6215 } |
| 6850 | 6216 |
| 6851 @override | 6217 @override |
| 6852 void visitFinalStaticFieldSet( | 6218 void visitFinalStaticFieldSet( |
| 6853 ast.SendSet node, | 6219 ast.SendSet node, FieldElement field, ast.Node rhs, _) { |
| 6854 FieldElement field, | |
| 6855 ast.Node rhs, | |
| 6856 _) { | |
| 6857 generateIsDeferredLoadedCheckOfSend(node); | 6220 generateIsDeferredLoadedCheckOfSend(node); |
| 6858 generateNoSuchSetter(node, field, visitAndPop(rhs)); | 6221 generateNoSuchSetter(node, field, visitAndPop(rhs)); |
| 6859 } | 6222 } |
| 6860 | 6223 |
| 6861 @override | 6224 @override |
| 6862 void visitStaticGetterSet( | 6225 void visitStaticGetterSet( |
| 6863 ast.SendSet node, | 6226 ast.SendSet node, GetterElement getter, ast.Node rhs, _) { |
| 6864 GetterElement getter, | |
| 6865 ast.Node rhs, | |
| 6866 _) { | |
| 6867 generateIsDeferredLoadedCheckOfSend(node); | 6227 generateIsDeferredLoadedCheckOfSend(node); |
| 6868 generateNoSuchSetter(node, getter, visitAndPop(rhs)); | 6228 generateNoSuchSetter(node, getter, visitAndPop(rhs)); |
| 6869 } | 6229 } |
| 6870 | 6230 |
| 6871 @override | 6231 @override |
| 6872 void visitStaticSetterSet( | 6232 void visitStaticSetterSet( |
| 6873 ast.SendSet node, | 6233 ast.SendSet node, SetterElement setter, ast.Node rhs, _) { |
| 6874 SetterElement setter, | |
| 6875 ast.Node rhs, | |
| 6876 _) { | |
| 6877 generateIsDeferredLoadedCheckOfSend(node); | 6234 generateIsDeferredLoadedCheckOfSend(node); |
| 6878 generateNonInstanceSetter(node, setter, visitAndPop(rhs)); | 6235 generateNonInstanceSetter(node, setter, visitAndPop(rhs)); |
| 6879 } | 6236 } |
| 6880 | 6237 |
| 6881 @override | 6238 @override |
| 6882 void visitStaticFunctionSet( | 6239 void visitStaticFunctionSet( |
| 6883 ast.SendSet node, | 6240 ast.SendSet node, MethodElement function, ast.Node rhs, _) { |
| 6884 MethodElement function, | |
| 6885 ast.Node rhs, | |
| 6886 _) { | |
| 6887 generateIsDeferredLoadedCheckOfSend(node); | 6241 generateIsDeferredLoadedCheckOfSend(node); |
| 6888 generateNoSuchSetter(node, function, visitAndPop(rhs)); | 6242 generateNoSuchSetter(node, function, visitAndPop(rhs)); |
| 6889 } | 6243 } |
| 6890 | 6244 |
| 6891 @override | 6245 @override |
| 6892 void visitUnresolvedSet( | 6246 void visitUnresolvedSet(ast.SendSet node, Element element, ast.Node rhs, _) { |
| 6893 ast.SendSet node, | |
| 6894 Element element, | |
| 6895 ast.Node rhs, | |
| 6896 _) { | |
| 6897 generateIsDeferredLoadedCheckOfSend(node); | 6247 generateIsDeferredLoadedCheckOfSend(node); |
| 6898 generateNonInstanceSetter(node, element, visitAndPop(rhs)); | 6248 generateNonInstanceSetter(node, element, visitAndPop(rhs)); |
| 6899 } | 6249 } |
| 6900 | 6250 |
| 6901 @override | 6251 @override |
| 6902 void visitClassTypeLiteralSet( | 6252 void visitClassTypeLiteralSet( |
| 6903 ast.SendSet node, | 6253 ast.SendSet node, TypeConstantExpression constant, ast.Node rhs, _) { |
| 6904 TypeConstantExpression constant, | |
| 6905 ast.Node rhs, | |
| 6906 _) { | |
| 6907 generateThrowNoSuchMethod(node, constant.type.name, | 6254 generateThrowNoSuchMethod(node, constant.type.name, |
| 6908 argumentNodes: node.arguments); | 6255 argumentNodes: node.arguments); |
| 6909 } | 6256 } |
| 6910 | 6257 |
| 6911 @override | 6258 @override |
| 6912 void visitTypedefTypeLiteralSet( | 6259 void visitTypedefTypeLiteralSet( |
| 6913 ast.SendSet node, | 6260 ast.SendSet node, TypeConstantExpression constant, ast.Node rhs, _) { |
| 6914 TypeConstantExpression constant, | |
| 6915 ast.Node rhs, | |
| 6916 _) { | |
| 6917 generateThrowNoSuchMethod(node, constant.type.name, | 6261 generateThrowNoSuchMethod(node, constant.type.name, |
| 6918 argumentNodes: node.arguments); | 6262 argumentNodes: node.arguments); |
| 6919 } | 6263 } |
| 6920 | 6264 |
| 6921 @override | 6265 @override |
| 6922 void visitDynamicTypeLiteralSet( | 6266 void visitDynamicTypeLiteralSet( |
| 6923 ast.SendSet node, | 6267 ast.SendSet node, TypeConstantExpression constant, ast.Node rhs, _) { |
| 6924 TypeConstantExpression constant, | |
| 6925 ast.Node rhs, | |
| 6926 _) { | |
| 6927 generateThrowNoSuchMethod(node, constant.type.name, | 6268 generateThrowNoSuchMethod(node, constant.type.name, |
| 6928 argumentNodes: node.arguments); | 6269 argumentNodes: node.arguments); |
| 6929 } | 6270 } |
| 6930 | 6271 |
| 6931 @override | 6272 @override |
| 6932 void visitTypeVariableTypeLiteralSet( | 6273 void visitTypeVariableTypeLiteralSet( |
| 6933 ast.SendSet node, | 6274 ast.SendSet node, TypeVariableElement element, ast.Node rhs, _) { |
| 6934 TypeVariableElement element, | |
| 6935 ast.Node rhs, | |
| 6936 _) { | |
| 6937 generateThrowNoSuchMethod(node, element.name, | 6275 generateThrowNoSuchMethod(node, element.name, |
| 6938 argumentNodes: node.arguments); | 6276 argumentNodes: node.arguments); |
| 6939 } | 6277 } |
| 6940 | 6278 |
| 6941 void handleCompoundSendSet(ast.SendSet node) { | 6279 void handleCompoundSendSet(ast.SendSet node) { |
| 6942 Element element = elements[node]; | 6280 Element element = elements[node]; |
| 6943 Element getter = elements[node.selector]; | 6281 Element getter = elements[node.selector]; |
| 6944 | 6282 |
| 6945 if (!Elements.isUnresolved(getter) && getter.impliesType) { | 6283 if (!Elements.isUnresolved(getter) && getter.impliesType) { |
| 6946 if (node.isIfNullAssignment) { | 6284 if (node.isIfNullAssignment) { |
| 6947 // C ??= x is compiled just as C. | 6285 // C ??= x is compiled just as C. |
| 6948 stack.add(addConstant(node.selector)); | 6286 stack.add(addConstant(node.selector)); |
| 6949 } else { | 6287 } else { |
| 6950 ast.Identifier selector = node.selector; | 6288 ast.Identifier selector = node.selector; |
| 6951 generateThrowNoSuchMethod(node, selector.source, | 6289 generateThrowNoSuchMethod(node, selector.source, |
| 6952 argumentNodes: node.arguments); | 6290 argumentNodes: node.arguments); |
| 6953 } | 6291 } |
| 6954 return; | 6292 return; |
| 6955 } | 6293 } |
| 6956 | 6294 |
| 6957 if (Elements.isInstanceSend(node, elements)) { | 6295 if (Elements.isInstanceSend(node, elements)) { |
| 6958 void generateAssignment(HInstruction receiver) { | 6296 void generateAssignment(HInstruction receiver) { |
| 6959 // desugars `e.x op= e2` to `e.x = e.x op e2` | 6297 // desugars `e.x op= e2` to `e.x = e.x op e2` |
| 6960 generateInstanceGetterWithCompiledReceiver( | 6298 generateInstanceGetterWithCompiledReceiver( |
| 6961 node, | 6299 node, |
| 6962 elements.getGetterSelectorInComplexSendSet(node), | 6300 elements.getGetterSelectorInComplexSendSet(node), |
| 6963 elements.getGetterTypeMaskInComplexSendSet(node), | 6301 elements.getGetterTypeMaskInComplexSendSet(node), |
| 6964 receiver); | 6302 receiver); |
| 6965 HInstruction getterInstruction = pop(); | 6303 HInstruction getterInstruction = pop(); |
| 6966 if (node.isIfNullAssignment) { | 6304 if (node.isIfNullAssignment) { |
| 6967 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 6305 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
| 6968 brancher.handleIfNull(() => stack.add(getterInstruction), | 6306 brancher.handleIfNull(() => stack.add(getterInstruction), () { |
| 6969 () { | 6307 visit(node.arguments.head); |
| 6970 visit(node.arguments.head); | 6308 generateInstanceSetterWithCompiledReceiver(node, receiver, pop()); |
| 6971 generateInstanceSetterWithCompiledReceiver( | 6309 }); |
| 6972 node, receiver, pop()); | |
| 6973 }); | |
| 6974 } else { | 6310 } else { |
| 6975 handleComplexOperatorSend(node, getterInstruction, node.arguments); | 6311 handleComplexOperatorSend(node, getterInstruction, node.arguments); |
| 6976 HInstruction value = pop(); | 6312 HInstruction value = pop(); |
| 6977 generateInstanceSetterWithCompiledReceiver(node, receiver, value); | 6313 generateInstanceSetterWithCompiledReceiver(node, receiver, value); |
| 6978 } | 6314 } |
| 6979 if (node.isPostfix) { | 6315 if (node.isPostfix) { |
| 6980 pop(); | 6316 pop(); |
| 6981 stack.add(getterInstruction); | 6317 stack.add(getterInstruction); |
| 6982 } | 6318 } |
| 6983 } | 6319 } |
| 6984 if (node.isConditional) { | 6320 if (node.isConditional) { |
| 6985 // generate `e?.x op= e2` as: | 6321 // generate `e?.x op= e2` as: |
| 6986 // t1 = e | 6322 // t1 = e |
| 6987 // t1 == null ? t1 : (t1.x = t1.x op e2); | 6323 // t1 == null ? t1 : (t1.x = t1.x op e2); |
| 6988 HInstruction receiver; | 6324 HInstruction receiver; |
| 6989 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 6325 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
| 6990 brancher.handleConditional( | 6326 brancher.handleConditional(() { |
| 6991 () { | 6327 receiver = generateInstanceSendReceiver(node); |
| 6992 receiver = generateInstanceSendReceiver(node); | 6328 pushCheckNull(receiver); |
| 6993 pushCheckNull(receiver); | 6329 }, () => stack.add(receiver), () => generateAssignment(receiver)); |
| 6994 }, | |
| 6995 () => stack.add(receiver), | |
| 6996 () => generateAssignment(receiver)); | |
| 6997 } else { | 6330 } else { |
| 6998 generateAssignment(generateInstanceSendReceiver(node)); | 6331 generateAssignment(generateInstanceSendReceiver(node)); |
| 6999 } | 6332 } |
| 7000 return; | 6333 return; |
| 7001 } | 6334 } |
| 7002 | 6335 |
| 7003 if (getter.isMalformed) { | 6336 if (getter.isMalformed) { |
| 7004 generateStaticUnresolvedGet(node, getter); | 6337 generateStaticUnresolvedGet(node, getter); |
| 7005 } else if (getter.isField) { | 6338 } else if (getter.isField) { |
| 7006 generateStaticFieldGet(node, getter); | 6339 generateStaticFieldGet(node, getter); |
| 7007 } else if (getter.isGetter) { | 6340 } else if (getter.isGetter) { |
| 7008 generateStaticGetterGet(node, getter); | 6341 generateStaticGetterGet(node, getter); |
| 7009 } else if (getter.isFunction) { | 6342 } else if (getter.isFunction) { |
| 7010 generateStaticFunctionGet(node, getter); | 6343 generateStaticFunctionGet(node, getter); |
| 7011 } else if (getter.isLocal) { | 6344 } else if (getter.isLocal) { |
| 7012 handleLocalGet(node, getter); | 6345 handleLocalGet(node, getter); |
| 7013 } else { | 6346 } else { |
| 7014 internalError(node, "Unexpected getter: $getter"); | 6347 internalError(node, "Unexpected getter: $getter"); |
| 7015 } | 6348 } |
| 7016 HInstruction getterInstruction = pop(); | 6349 HInstruction getterInstruction = pop(); |
| 7017 if (node.isIfNullAssignment) { | 6350 if (node.isIfNullAssignment) { |
| 7018 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 6351 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
| 7019 brancher.handleIfNull(() => stack.add(getterInstruction), | 6352 brancher.handleIfNull(() => stack.add(getterInstruction), () { |
| 7020 () { | 6353 visit(node.arguments.head); |
| 7021 visit(node.arguments.head); | 6354 generateNonInstanceSetter(node, element, pop()); |
| 7022 generateNonInstanceSetter(node, element, pop()); | 6355 }); |
| 7023 }); | |
| 7024 } else { | 6356 } else { |
| 7025 handleComplexOperatorSend(node, getterInstruction, node.arguments); | 6357 handleComplexOperatorSend(node, getterInstruction, node.arguments); |
| 7026 HInstruction value = pop(); | 6358 HInstruction value = pop(); |
| 7027 generateNonInstanceSetter(node, element, value); | 6359 generateNonInstanceSetter(node, element, value); |
| 7028 } | 6360 } |
| 7029 if (node.isPostfix) { | 6361 if (node.isPostfix) { |
| 7030 pop(); | 6362 pop(); |
| 7031 stack.add(getterInstruction); | 6363 stack.add(getterInstruction); |
| 7032 } | 6364 } |
| 7033 } | 6365 } |
| 7034 | 6366 |
| 7035 @override | 6367 @override |
| 7036 void handleDynamicCompounds( | 6368 void handleDynamicCompounds( |
| 7037 ast.Send node, | 6369 ast.Send node, ast.Node receiver, Name name, CompoundRhs rhs, _) { |
| 7038 ast.Node receiver, | |
| 7039 Name name, | |
| 7040 CompoundRhs rhs, | |
| 7041 _) { | |
| 7042 handleCompoundSendSet(node); | 6370 handleCompoundSendSet(node); |
| 7043 } | 6371 } |
| 7044 | 6372 |
| 7045 @override | 6373 @override |
| 7046 void handleLocalCompounds( | 6374 void handleLocalCompounds( |
| 7047 ast.SendSet node, | 6375 ast.SendSet node, LocalElement local, CompoundRhs rhs, _, |
| 7048 LocalElement local, | |
| 7049 CompoundRhs rhs, | |
| 7050 _, | |
| 7051 {bool isSetterValid}) { | 6376 {bool isSetterValid}) { |
| 7052 handleCompoundSendSet(node); | 6377 handleCompoundSendSet(node); |
| 7053 } | 6378 } |
| 7054 | 6379 |
| 7055 @override | 6380 @override |
| 7056 void handleStaticCompounds( | 6381 void handleStaticCompounds( |
| 7057 ast.SendSet node, | 6382 ast.SendSet node, |
| 7058 Element getter, | 6383 Element getter, |
| 7059 CompoundGetter getterKind, | 6384 CompoundGetter getterKind, |
| 7060 Element setter, | 6385 Element setter, |
| 7061 CompoundSetter setterKind, | 6386 CompoundSetter setterKind, |
| 7062 CompoundRhs rhs, | 6387 CompoundRhs rhs, |
| 7063 _) { | 6388 _) { |
| 7064 handleCompoundSendSet(node); | 6389 handleCompoundSendSet(node); |
| 7065 } | 6390 } |
| 7066 | 6391 |
| 7067 @override | 6392 @override |
| 7068 handleDynamicSetIfNulls( | 6393 handleDynamicSetIfNulls( |
| 7069 ast.Send node, | 6394 ast.Send node, ast.Node receiver, Name name, ast.Node rhs, arg) { |
| 7070 ast.Node receiver, | |
| 7071 Name name, | |
| 7072 ast.Node rhs, | |
| 7073 arg) { | |
| 7074 handleCompoundSendSet(node); | 6395 handleCompoundSendSet(node); |
| 7075 } | 6396 } |
| 7076 | 6397 |
| 7077 @override | 6398 @override |
| 7078 handleLocalSetIfNulls( | 6399 handleLocalSetIfNulls(ast.SendSet node, LocalElement local, ast.Node rhs, arg, |
| 7079 ast.SendSet node, | |
| 7080 LocalElement local, | |
| 7081 ast.Node rhs, | |
| 7082 arg, | |
| 7083 {bool isSetterValid}) { | 6400 {bool isSetterValid}) { |
| 7084 handleCompoundSendSet(node); | 6401 handleCompoundSendSet(node); |
| 7085 } | 6402 } |
| 7086 | 6403 |
| 7087 @override | 6404 @override |
| 7088 handleStaticSetIfNulls( | 6405 handleStaticSetIfNulls( |
| 7089 ast.SendSet node, | 6406 ast.SendSet node, |
| 7090 Element getter, | 6407 Element getter, |
| 7091 CompoundGetter getterKind, | 6408 CompoundGetter getterKind, |
| 7092 Element setter, | 6409 Element setter, |
| 7093 CompoundSetter setterKind, | 6410 CompoundSetter setterKind, |
| 7094 ast.Node rhs, | 6411 ast.Node rhs, |
| 7095 arg) { | 6412 arg) { |
| 7096 handleCompoundSendSet(node); | 6413 handleCompoundSendSet(node); |
| 7097 } | 6414 } |
| 7098 | 6415 |
| 7099 @override | 6416 @override |
| 7100 handleSuperSetIfNulls( | 6417 handleSuperSetIfNulls( |
| 7101 ast.SendSet node, | 6418 ast.SendSet node, |
| 7102 Element getter, | 6419 Element getter, |
| 7103 CompoundGetter getterKind, | 6420 CompoundGetter getterKind, |
| 7104 Element setter, | 6421 Element setter, |
| 7105 CompoundSetter setterKind, | 6422 CompoundSetter setterKind, |
| 7106 ast.Node rhs, | 6423 ast.Node rhs, |
| 7107 arg) { | 6424 arg) { |
| 7108 handleSuperSendSet(node); | 6425 handleSuperSendSet(node); |
| 7109 } | 6426 } |
| 7110 | 6427 |
| 7111 @override | 6428 @override |
| 7112 handleSuperIndexSetIfNull( | 6429 handleSuperIndexSetIfNull(ast.SendSet node, Element indexFunction, |
| 7113 ast.SendSet node, | 6430 Element indexSetFunction, ast.Node index, ast.Node rhs, arg, |
| 7114 Element indexFunction, | 6431 {bool isGetterValid, bool isSetterValid}) { |
| 7115 Element indexSetFunction, | |
| 7116 ast.Node index, | |
| 7117 ast.Node rhs, | |
| 7118 arg, | |
| 7119 {bool isGetterValid, | |
| 7120 bool isSetterValid}) { | |
| 7121 handleCompoundSendSet(node); | 6432 handleCompoundSendSet(node); |
| 7122 } | 6433 } |
| 7123 | 6434 |
| 7124 @override | 6435 @override |
| 7125 visitIndexSetIfNull( | 6436 visitIndexSetIfNull( |
| 7126 ast.SendSet node, | 6437 ast.SendSet node, ast.Node receiver, ast.Node index, ast.Node rhs, arg, |
| 7127 ast.Node receiver, | 6438 {bool isGetterValid, bool isSetterValid}) { |
| 7128 ast.Node index, | |
| 7129 ast.Node rhs, | |
| 7130 arg, | |
| 7131 {bool isGetterValid, | |
| 7132 bool isSetterValid}) { | |
| 7133 generateIsDeferredLoadedCheckOfSend(node); | 6439 generateIsDeferredLoadedCheckOfSend(node); |
| 7134 handleIndexSendSet(node); | 6440 handleIndexSendSet(node); |
| 7135 } | 6441 } |
| 7136 | 6442 |
| 7137 @override | 6443 @override |
| 7138 handleTypeLiteralConstantSetIfNulls( | 6444 handleTypeLiteralConstantSetIfNulls( |
| 7139 ast.SendSet node, | 6445 ast.SendSet node, ConstantExpression constant, ast.Node rhs, arg) { |
| 7140 ConstantExpression constant, | |
| 7141 ast.Node rhs, | |
| 7142 arg) { | |
| 7143 // The type variable is never `null`. | 6446 // The type variable is never `null`. |
| 7144 generateConstantTypeLiteral(node); | 6447 generateConstantTypeLiteral(node); |
| 7145 } | 6448 } |
| 7146 | 6449 |
| 7147 @override | 6450 @override |
| 7148 visitTypeVariableTypeLiteralSetIfNull( | 6451 visitTypeVariableTypeLiteralSetIfNull( |
| 7149 ast.Send node, | 6452 ast.Send node, TypeVariableElement element, ast.Node rhs, arg) { |
| 7150 TypeVariableElement element, | |
| 7151 ast.Node rhs, | |
| 7152 arg) { | |
| 7153 // The type variable is never `null`. | 6453 // The type variable is never `null`. |
| 7154 generateTypeVariableLiteral(node, element.type); | 6454 generateTypeVariableLiteral(node, element.type); |
| 7155 } | 6455 } |
| 7156 | 6456 |
| 7157 void visitLiteralInt(ast.LiteralInt node) { | 6457 void visitLiteralInt(ast.LiteralInt node) { |
| 7158 stack.add(graph.addConstantInt(node.value, compiler)); | 6458 stack.add(graph.addConstantInt(node.value, compiler)); |
| 7159 } | 6459 } |
| 7160 | 6460 |
| 7161 void visitLiteralDouble(ast.LiteralDouble node) { | 6461 void visitLiteralDouble(ast.LiteralDouble node) { |
| 7162 stack.add(graph.addConstantDouble(node.value, compiler)); | 6462 stack.add(graph.addConstantDouble(node.value, compiler)); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 7187 } | 6487 } |
| 7188 | 6488 |
| 7189 void visitLiteralNull(ast.LiteralNull node) { | 6489 void visitLiteralNull(ast.LiteralNull node) { |
| 7190 stack.add(graph.addConstantNull(compiler)); | 6490 stack.add(graph.addConstantNull(compiler)); |
| 7191 } | 6491 } |
| 7192 | 6492 |
| 7193 visitNodeList(ast.NodeList node) { | 6493 visitNodeList(ast.NodeList node) { |
| 7194 for (Link<ast.Node> link = node.nodes; !link.isEmpty; link = link.tail) { | 6494 for (Link<ast.Node> link = node.nodes; !link.isEmpty; link = link.tail) { |
| 7195 if (isAborted()) { | 6495 if (isAborted()) { |
| 7196 reporter.reportHintMessage( | 6496 reporter.reportHintMessage( |
| 7197 link.head, | 6497 link.head, MessageKind.GENERIC, {'text': 'dead code'}); |
| 7198 MessageKind.GENERIC, | |
| 7199 {'text': 'dead code'}); | |
| 7200 } else { | 6498 } else { |
| 7201 visit(link.head); | 6499 visit(link.head); |
| 7202 } | 6500 } |
| 7203 } | 6501 } |
| 7204 } | 6502 } |
| 7205 | 6503 |
| 7206 void visitParenthesizedExpression(ast.ParenthesizedExpression node) { | 6504 void visitParenthesizedExpression(ast.ParenthesizedExpression node) { |
| 7207 visit(node.expression); | 6505 visit(node.expression); |
| 7208 } | 6506 } |
| 7209 | 6507 |
| 7210 visitOperator(ast.Operator node) { | 6508 visitOperator(ast.Operator node) { |
| 7211 // Operators are intercepted in their surrounding Send nodes. | 6509 // Operators are intercepted in their surrounding Send nodes. |
| 7212 reporter.internalError(node, | 6510 reporter.internalError( |
| 7213 'SsaBuilder.visitOperator should not be called.'); | 6511 node, 'SsaBuilder.visitOperator should not be called.'); |
| 7214 } | 6512 } |
| 7215 | 6513 |
| 7216 visitCascade(ast.Cascade node) { | 6514 visitCascade(ast.Cascade node) { |
| 7217 visit(node.expression); | 6515 visit(node.expression); |
| 7218 // Remove the result and reveal the duplicated receiver on the stack. | 6516 // Remove the result and reveal the duplicated receiver on the stack. |
| 7219 pop(); | 6517 pop(); |
| 7220 } | 6518 } |
| 7221 | 6519 |
| 7222 visitCascadeReceiver(ast.CascadeReceiver node) { | 6520 visitCascadeReceiver(ast.CascadeReceiver node) { |
| 7223 visit(node.expression); | 6521 visit(node.expression); |
| 7224 dup(); | 6522 dup(); |
| 7225 } | 6523 } |
| 7226 | 6524 |
| 7227 void handleInTryStatement() { | 6525 void handleInTryStatement() { |
| 7228 if (!inTryStatement) return; | 6526 if (!inTryStatement) return; |
| 7229 HBasicBlock block = close(new HExitTry()); | 6527 HBasicBlock block = close(new HExitTry()); |
| 7230 HBasicBlock newBlock = graph.addNewBlock(); | 6528 HBasicBlock newBlock = graph.addNewBlock(); |
| 7231 block.addSuccessor(newBlock); | 6529 block.addSuccessor(newBlock); |
| 7232 open(newBlock); | 6530 open(newBlock); |
| 7233 } | 6531 } |
| 7234 | 6532 |
| 7235 visitRethrow(ast.Rethrow node) { | 6533 visitRethrow(ast.Rethrow node) { |
| 7236 HInstruction exception = rethrowableException; | 6534 HInstruction exception = rethrowableException; |
| 7237 if (exception == null) { | 6535 if (exception == null) { |
| 7238 exception = graph.addConstantNull(compiler); | 6536 exception = graph.addConstantNull(compiler); |
| 7239 reporter.internalError(node, | 6537 reporter.internalError(node, 'rethrowableException should not be null.'); |
| 7240 'rethrowableException should not be null.'); | |
| 7241 } | 6538 } |
| 7242 handleInTryStatement(); | 6539 handleInTryStatement(); |
| 7243 closeAndGotoExit( | 6540 closeAndGotoExit(new HThrow( |
| 7244 new HThrow(exception, | 6541 exception, sourceInformationBuilder.buildThrow(node), |
| 7245 sourceInformationBuilder.buildThrow(node), | 6542 isRethrow: true)); |
| 7246 isRethrow: true)); | |
| 7247 } | 6543 } |
| 7248 | 6544 |
| 7249 visitRedirectingFactoryBody(ast.RedirectingFactoryBody node) { | 6545 visitRedirectingFactoryBody(ast.RedirectingFactoryBody node) { |
| 7250 ConstructorElement targetConstructor = | 6546 ConstructorElement targetConstructor = |
| 7251 elements.getRedirectingTargetConstructor(node).implementation; | 6547 elements.getRedirectingTargetConstructor(node).implementation; |
| 7252 ConstructorElement redirectingConstructor = sourceElement.implementation; | 6548 ConstructorElement redirectingConstructor = sourceElement.implementation; |
| 7253 List<HInstruction> inputs = <HInstruction>[]; | 6549 List<HInstruction> inputs = <HInstruction>[]; |
| 7254 FunctionSignature targetSignature = targetConstructor.functionSignature; | 6550 FunctionSignature targetSignature = targetConstructor.functionSignature; |
| 7255 FunctionSignature redirectingSignature = | 6551 FunctionSignature redirectingSignature = |
| 7256 redirectingConstructor.functionSignature; | 6552 redirectingConstructor.functionSignature; |
| 7257 | 6553 |
| 7258 List<Element> targetRequireds = targetSignature.requiredParameters; | 6554 List<Element> targetRequireds = targetSignature.requiredParameters; |
| 7259 List<Element> redirectingRequireds | 6555 List<Element> redirectingRequireds = |
| 7260 = redirectingSignature.requiredParameters; | 6556 redirectingSignature.requiredParameters; |
| 7261 | 6557 |
| 7262 List<Element> targetOptionals = | 6558 List<Element> targetOptionals = targetSignature.orderedOptionalParameters; |
| 7263 targetSignature.orderedOptionalParameters; | |
| 7264 List<Element> redirectingOptionals = | 6559 List<Element> redirectingOptionals = |
| 7265 redirectingSignature.orderedOptionalParameters; | 6560 redirectingSignature.orderedOptionalParameters; |
| 7266 | 6561 |
| 7267 // TODO(25579): This code can do the wrong thing redirecting constructor and | 6562 // TODO(25579): This code can do the wrong thing redirecting constructor and |
| 7268 // the target do not correspond. It is correct if there is no | 6563 // the target do not correspond. It is correct if there is no |
| 7269 // warning. Ideally the redirecting constructor and the target would be the | 6564 // warning. Ideally the redirecting constructor and the target would be the |
| 7270 // same function. | 6565 // same function. |
| 7271 | 6566 |
| 7272 void loadLocal(ParameterElement parameter) { | 6567 void loadLocal(ParameterElement parameter) { |
| 7273 inputs.add(localsHandler.readLocal(parameter)); | 6568 inputs.add(localsHandler.readLocal(parameter)); |
| 7274 } | 6569 } |
| 7275 void loadPosition(int position, ParameterElement optionalParameter) { | 6570 void loadPosition(int position, ParameterElement optionalParameter) { |
| 7276 if (position < redirectingRequireds.length) { | 6571 if (position < redirectingRequireds.length) { |
| 7277 loadLocal(redirectingRequireds[position]); | 6572 loadLocal(redirectingRequireds[position]); |
| 7278 } else if (position < redirectingSignature.parameterCount && | 6573 } else if (position < redirectingSignature.parameterCount && |
| 7279 !redirectingSignature.optionalParametersAreNamed) { | 6574 !redirectingSignature.optionalParametersAreNamed) { |
| 7280 loadLocal(redirectingOptionals[position - redirectingRequireds.length]); | 6575 loadLocal(redirectingOptionals[position - redirectingRequireds.length]); |
| 7281 } else if (optionalParameter != null) { | 6576 } else if (optionalParameter != null) { |
| 7282 inputs.add(handleConstantForOptionalParameter(optionalParameter)); | 6577 inputs.add(handleConstantForOptionalParameter(optionalParameter)); |
| 7283 } else { | 6578 } else { |
| 7284 // Wrong. | 6579 // Wrong. |
| 7285 inputs.add(graph.addConstantNull(compiler)); | 6580 inputs.add(graph.addConstantNull(compiler)); |
| 7286 } | 6581 } |
| 7287 } | 6582 } |
| 7288 | 6583 |
| 7289 int position = 0; | 6584 int position = 0; |
| 7290 | 6585 |
| 7291 for (ParameterElement targetParameter in targetRequireds) { | 6586 for (ParameterElement targetParameter in targetRequireds) { |
| 7292 loadPosition(position++, null); | 6587 loadPosition(position++, null); |
| 7293 } | 6588 } |
| 7294 | 6589 |
| 7295 if (targetOptionals.isNotEmpty) { | 6590 if (targetOptionals.isNotEmpty) { |
| 7296 if (targetSignature.optionalParametersAreNamed) { | 6591 if (targetSignature.optionalParametersAreNamed) { |
| 7297 for (ParameterElement parameter in targetOptionals) { | 6592 for (ParameterElement parameter in targetOptionals) { |
| 7298 ParameterElement redirectingParameter = | 6593 ParameterElement redirectingParameter = redirectingOptionals |
| 7299 redirectingOptionals.firstWhere( | 6594 .firstWhere((p) => p.name == parameter.name, orElse: () => null); |
| 7300 (p) => p.name == parameter.name, | |
| 7301 orElse: () => null); | |
| 7302 if (redirectingParameter == null) { | 6595 if (redirectingParameter == null) { |
| 7303 inputs.add(handleConstantForOptionalParameter(parameter)); | 6596 inputs.add(handleConstantForOptionalParameter(parameter)); |
| 7304 } else { | 6597 } else { |
| 7305 inputs.add(localsHandler.readLocal(redirectingParameter)); | 6598 inputs.add(localsHandler.readLocal(redirectingParameter)); |
| 7306 } | 6599 } |
| 7307 } | 6600 } |
| 7308 } else { | 6601 } else { |
| 7309 for (ParameterElement parameter in targetOptionals) { | 6602 for (ParameterElement parameter in targetOptionals) { |
| 7310 loadPosition(position++, parameter); | 6603 loadPosition(position++, parameter); |
| 7311 } | 6604 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 7328 } | 6621 } |
| 7329 | 6622 |
| 7330 /// Returns true if the [type] is a valid return type for an asynchronous | 6623 /// Returns true if the [type] is a valid return type for an asynchronous |
| 7331 /// function. | 6624 /// function. |
| 7332 /// | 6625 /// |
| 7333 /// Asynchronous functions return a `Future`, and a valid return is thus | 6626 /// Asynchronous functions return a `Future`, and a valid return is thus |
| 7334 /// either dynamic, Object, or Future. | 6627 /// either dynamic, Object, or Future. |
| 7335 /// | 6628 /// |
| 7336 /// We do not accept the internal Future implementation class. | 6629 /// We do not accept the internal Future implementation class. |
| 7337 bool isValidAsyncReturnType(DartType type) { | 6630 bool isValidAsyncReturnType(DartType type) { |
| 7338 assert (isBuildingAsyncFunction); | 6631 assert(isBuildingAsyncFunction); |
| 7339 // TODO(sigurdm): In an internal library a function could be declared: | 6632 // TODO(sigurdm): In an internal library a function could be declared: |
| 7340 // | 6633 // |
| 7341 // _FutureImpl foo async => 1; | 6634 // _FutureImpl foo async => 1; |
| 7342 // | 6635 // |
| 7343 // This should be valid (because the actual value returned from an async | 6636 // This should be valid (because the actual value returned from an async |
| 7344 // function is a `_FutureImpl`), but currently false is returned in this | 6637 // function is a `_FutureImpl`), but currently false is returned in this |
| 7345 // case. | 6638 // case. |
| 7346 return type.isDynamic || | 6639 return type.isDynamic || |
| 7347 type.isObject || | 6640 type.isObject || |
| 7348 (type is InterfaceType && | 6641 (type is InterfaceType && type.element == coreClasses.futureClass); |
| 7349 type.element == coreClasses.futureClass); | |
| 7350 } | 6642 } |
| 7351 | 6643 |
| 7352 visitReturn(ast.Return node) { | 6644 visitReturn(ast.Return node) { |
| 7353 if (identical(node.beginToken.stringValue, 'native')) { | 6645 if (identical(node.beginToken.stringValue, 'native')) { |
| 7354 native.handleSsaNative(this, node.expression); | 6646 native.handleSsaNative(this, node.expression); |
| 7355 return; | 6647 return; |
| 7356 } | 6648 } |
| 7357 HInstruction value; | 6649 HInstruction value; |
| 7358 if (node.expression == null) { | 6650 if (node.expression == null) { |
| 7359 value = graph.addConstantNull(compiler); | 6651 value = graph.addConstantNull(compiler); |
| 7360 } else { | 6652 } else { |
| 7361 visit(node.expression); | 6653 visit(node.expression); |
| 7362 value = pop(); | 6654 value = pop(); |
| 7363 if (isBuildingAsyncFunction) { | 6655 if (isBuildingAsyncFunction) { |
| 7364 if (compiler.options.enableTypeAssertions && | 6656 if (compiler.options.enableTypeAssertions && |
| 7365 !isValidAsyncReturnType(returnType)) { | 6657 !isValidAsyncReturnType(returnType)) { |
| 7366 String message = | 6658 String message = "Async function returned a Future, " |
| 7367 "Async function returned a Future, " | 6659 "was declared to return a $returnType."; |
| 7368 "was declared to return a $returnType."; | |
| 7369 generateTypeError(node, message); | 6660 generateTypeError(node, message); |
| 7370 pop(); | 6661 pop(); |
| 7371 return; | 6662 return; |
| 7372 } | 6663 } |
| 7373 } else { | 6664 } else { |
| 7374 value = potentiallyCheckOrTrustType(value, returnType); | 6665 value = potentiallyCheckOrTrustType(value, returnType); |
| 7375 } | 6666 } |
| 7376 } | 6667 } |
| 7377 | 6668 |
| 7378 handleInTryStatement(); | 6669 handleInTryStatement(); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 7392 visitYield(ast.Yield node) { | 6683 visitYield(ast.Yield node) { |
| 7393 visit(node.expression); | 6684 visit(node.expression); |
| 7394 HInstruction yielded = pop(); | 6685 HInstruction yielded = pop(); |
| 7395 add(new HYield(yielded, node.hasStar)); | 6686 add(new HYield(yielded, node.hasStar)); |
| 7396 } | 6687 } |
| 7397 | 6688 |
| 7398 visitAwait(ast.Await node) { | 6689 visitAwait(ast.Await node) { |
| 7399 visit(node.expression); | 6690 visit(node.expression); |
| 7400 HInstruction awaited = pop(); | 6691 HInstruction awaited = pop(); |
| 7401 // TODO(herhut): Improve this type. | 6692 // TODO(herhut): Improve this type. |
| 7402 push(new HAwait(awaited, new TypeMask.subclass( | 6693 push(new HAwait(awaited, |
| 7403 coreClasses.objectClass, compiler.world))); | 6694 new TypeMask.subclass(coreClasses.objectClass, compiler.world))); |
| 7404 } | 6695 } |
| 7405 | 6696 |
| 7406 visitTypeAnnotation(ast.TypeAnnotation node) { | 6697 visitTypeAnnotation(ast.TypeAnnotation node) { |
| 7407 reporter.internalError(node, | 6698 reporter.internalError(node, 'Visiting type annotation in SSA builder.'); |
| 7408 'Visiting type annotation in SSA builder.'); | |
| 7409 } | 6699 } |
| 7410 | 6700 |
| 7411 visitVariableDefinitions(ast.VariableDefinitions node) { | 6701 visitVariableDefinitions(ast.VariableDefinitions node) { |
| 7412 assert(isReachable); | 6702 assert(isReachable); |
| 7413 for (Link<ast.Node> link = node.definitions.nodes; | 6703 for (Link<ast.Node> link = node.definitions.nodes; |
| 7414 !link.isEmpty; | 6704 !link.isEmpty; |
| 7415 link = link.tail) { | 6705 link = link.tail) { |
| 7416 ast.Node definition = link.head; | 6706 ast.Node definition = link.head; |
| 7417 LocalElement local = elements[definition]; | 6707 LocalElement local = elements[definition]; |
| 7418 if (definition is ast.Identifier) { | 6708 if (definition is ast.Identifier) { |
| 7419 HInstruction initialValue = graph.addConstantNull(compiler); | 6709 HInstruction initialValue = graph.addConstantNull(compiler); |
| 7420 localsHandler.updateLocal(local, initialValue); | 6710 localsHandler.updateLocal(local, initialValue); |
| 7421 } else { | 6711 } else { |
| 7422 ast.SendSet node = definition; | 6712 ast.SendSet node = definition; |
| 7423 generateNonInstanceSetter( | 6713 generateNonInstanceSetter( |
| 7424 node, local, visitAndPop(node.arguments.first)); | 6714 node, local, visitAndPop(node.arguments.first)); |
| 7425 pop(); // Discard value. | 6715 pop(); // Discard value. |
| 7426 } | 6716 } |
| 7427 } | 6717 } |
| 7428 } | 6718 } |
| 7429 | 6719 |
| 7430 HInstruction setRtiIfNeeded(HInstruction object, ast.Node node) { | 6720 HInstruction setRtiIfNeeded(HInstruction object, ast.Node node) { |
| 7431 InterfaceType type = localsHandler.substInContext(elements.getType(node)); | 6721 InterfaceType type = localsHandler.substInContext(elements.getType(node)); |
| 7432 if (!backend.classNeedsRti(type.element) || type.treatAsRaw) { | 6722 if (!backend.classNeedsRti(type.element) || type.treatAsRaw) { |
| 7433 return object; | 6723 return object; |
| 7434 } | 6724 } |
| 7435 List<HInstruction> arguments = <HInstruction>[]; | 6725 List<HInstruction> arguments = <HInstruction>[]; |
| 7436 for (DartType argument in type.typeArguments) { | 6726 for (DartType argument in type.typeArguments) { |
| 7437 arguments.add(analyzeTypeArgument(argument)); | 6727 arguments.add(analyzeTypeArgument(argument)); |
| 7438 } | 6728 } |
| 7439 // TODO(15489): Register at codegen. | 6729 // TODO(15489): Register at codegen. |
| 7440 registry?.registerInstantiation(type); | 6730 registry?.registerInstantiation(type); |
| 7441 return callSetRuntimeTypeInfo(type.element, arguments, object); | 6731 return callSetRuntimeTypeInfo(type.element, arguments, object); |
| 7442 } | 6732 } |
| 7443 | 6733 |
| 7444 visitLiteralList(ast.LiteralList node) { | 6734 visitLiteralList(ast.LiteralList node) { |
| 7445 HInstruction instruction; | 6735 HInstruction instruction; |
| 7446 | 6736 |
| 7447 if (node.isConst) { | 6737 if (node.isConst) { |
| 7448 instruction = addConstant(node); | 6738 instruction = addConstant(node); |
| 7449 } else { | 6739 } else { |
| 7450 List<HInstruction> inputs = <HInstruction>[]; | 6740 List<HInstruction> inputs = <HInstruction>[]; |
| 7451 for (Link<ast.Node> link = node.elements.nodes; | 6741 for (Link<ast.Node> link = node.elements.nodes; |
| 7452 !link.isEmpty; | 6742 !link.isEmpty; |
| 7453 link = link.tail) { | 6743 link = link.tail) { |
| 7454 visit(link.head); | 6744 visit(link.head); |
| 7455 inputs.add(pop()); | 6745 inputs.add(pop()); |
| 7456 } | 6746 } |
| 7457 instruction = buildLiteralList(inputs); | 6747 instruction = buildLiteralList(inputs); |
| 7458 add(instruction); | 6748 add(instruction); |
| 7459 instruction = setRtiIfNeeded(instruction, node); | 6749 instruction = setRtiIfNeeded(instruction, node); |
| 7460 } | 6750 } |
| 7461 | 6751 |
| 7462 TypeMask type = | 6752 TypeMask type = |
| 7463 TypeMaskFactory.inferredForNode(sourceElement, node, compiler); | 6753 TypeMaskFactory.inferredForNode(sourceElement, node, compiler); |
| 7464 if (!type.containsAll(compiler.world)) instruction.instructionType = type; | 6754 if (!type.containsAll(compiler.world)) instruction.instructionType = type; |
| 7465 stack.add(instruction); | 6755 stack.add(instruction); |
| 7466 } | 6756 } |
| 7467 | 6757 |
| 7468 visitConditional(ast.Conditional node) { | 6758 visitConditional(ast.Conditional node) { |
| 7469 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 6759 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
| 7470 brancher.handleConditional(() => visit(node.condition), | 6760 brancher.handleConditional(() => visit(node.condition), |
| 7471 () => visit(node.thenExpression), | 6761 () => visit(node.thenExpression), () => visit(node.elseExpression)); |
| 7472 () => visit(node.elseExpression)); | |
| 7473 } | 6762 } |
| 7474 | 6763 |
| 7475 visitStringInterpolation(ast.StringInterpolation node) { | 6764 visitStringInterpolation(ast.StringInterpolation node) { |
| 7476 StringBuilderVisitor stringBuilder = new StringBuilderVisitor(this, node); | 6765 StringBuilderVisitor stringBuilder = new StringBuilderVisitor(this, node); |
| 7477 stringBuilder.visit(node); | 6766 stringBuilder.visit(node); |
| 7478 stack.add(stringBuilder.result); | 6767 stack.add(stringBuilder.result); |
| 7479 } | 6768 } |
| 7480 | 6769 |
| 7481 visitStringInterpolationPart(ast.StringInterpolationPart node) { | 6770 visitStringInterpolationPart(ast.StringInterpolationPart node) { |
| 7482 // The parts are iterated in visitStringInterpolation. | 6771 // The parts are iterated in visitStringInterpolation. |
| 7483 reporter.internalError(node, | 6772 reporter.internalError( |
| 7484 'SsaBuilder.visitStringInterpolation should not be called.'); | 6773 node, 'SsaBuilder.visitStringInterpolation should not be called.'); |
| 7485 } | 6774 } |
| 7486 | 6775 |
| 7487 visitEmptyStatement(ast.EmptyStatement node) { | 6776 visitEmptyStatement(ast.EmptyStatement node) { |
| 7488 // Do nothing, empty statement. | 6777 // Do nothing, empty statement. |
| 7489 } | 6778 } |
| 7490 | 6779 |
| 7491 visitModifiers(ast.Modifiers node) { | 6780 visitModifiers(ast.Modifiers node) { |
| 7492 compiler.unimplemented(node, 'SsaFromAstMixin.visitModifiers.'); | 6781 compiler.unimplemented(node, 'SsaFromAstMixin.visitModifiers.'); |
| 7493 } | 6782 } |
| 7494 | 6783 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7544 } | 6833 } |
| 7545 return new JumpHandler(this, element); | 6834 return new JumpHandler(this, element); |
| 7546 } | 6835 } |
| 7547 | 6836 |
| 7548 visitAsyncForIn(ast.AsyncForIn node) { | 6837 visitAsyncForIn(ast.AsyncForIn node) { |
| 7549 // The async-for is implemented with a StreamIterator. | 6838 // The async-for is implemented with a StreamIterator. |
| 7550 HInstruction streamIterator; | 6839 HInstruction streamIterator; |
| 7551 | 6840 |
| 7552 visit(node.expression); | 6841 visit(node.expression); |
| 7553 HInstruction expression = pop(); | 6842 HInstruction expression = pop(); |
| 7554 pushInvokeStatic(node, | 6843 pushInvokeStatic(node, helpers.streamIteratorConstructor, |
| 7555 helpers.streamIteratorConstructor, | 6844 [expression, graph.addConstantNull(compiler)]); |
| 7556 [expression, graph.addConstantNull(compiler)]); | |
| 7557 streamIterator = pop(); | 6845 streamIterator = pop(); |
| 7558 | 6846 |
| 7559 void buildInitializer() {} | 6847 void buildInitializer() {} |
| 7560 | 6848 |
| 7561 HInstruction buildCondition() { | 6849 HInstruction buildCondition() { |
| 7562 Selector selector = Selectors.moveNext; | 6850 Selector selector = Selectors.moveNext; |
| 7563 TypeMask mask = elements.getMoveNextTypeMask(node); | 6851 TypeMask mask = elements.getMoveNextTypeMask(node); |
| 7564 pushInvokeDynamic(node, selector, mask, [streamIterator]); | 6852 pushInvokeDynamic(node, selector, mask, [streamIterator]); |
| 7565 HInstruction future = pop(); | 6853 HInstruction future = pop(); |
| 7566 push(new HAwait(future, | 6854 push(new HAwait(future, |
| 7567 new TypeMask.subclass(coreClasses.objectClass, compiler.world))); | 6855 new TypeMask.subclass(coreClasses.objectClass, compiler.world))); |
| 7568 return popBoolified(); | 6856 return popBoolified(); |
| 7569 } | 6857 } |
| 7570 void buildBody() { | 6858 void buildBody() { |
| 7571 Selector call = Selectors.current; | 6859 Selector call = Selectors.current; |
| 7572 TypeMask callMask = elements.getCurrentTypeMask(node); | 6860 TypeMask callMask = elements.getCurrentTypeMask(node); |
| 7573 pushInvokeDynamic(node, call, callMask, [streamIterator]); | 6861 pushInvokeDynamic(node, call, callMask, [streamIterator]); |
| 7574 | 6862 |
| 7575 ast.Node identifier = node.declaredIdentifier; | 6863 ast.Node identifier = node.declaredIdentifier; |
| 7576 Element variable = elements.getForInVariable(node); | 6864 Element variable = elements.getForInVariable(node); |
| 7577 Selector selector = elements.getSelector(identifier); | 6865 Selector selector = elements.getSelector(identifier); |
| 7578 TypeMask mask = elements.getTypeMask(identifier); | 6866 TypeMask mask = elements.getTypeMask(identifier); |
| 7579 | 6867 |
| 7580 HInstruction value = pop(); | 6868 HInstruction value = pop(); |
| 7581 if (identifier.asSend() != null | 6869 if (identifier.asSend() != null && |
| 7582 && Elements.isInstanceSend(identifier, elements)) { | 6870 Elements.isInstanceSend(identifier, elements)) { |
| 7583 HInstruction receiver = generateInstanceSendReceiver(identifier); | 6871 HInstruction receiver = generateInstanceSendReceiver(identifier); |
| 7584 assert(receiver != null); | 6872 assert(receiver != null); |
| 7585 generateInstanceSetterWithCompiledReceiver( | 6873 generateInstanceSetterWithCompiledReceiver(null, receiver, value, |
| 7586 null, | 6874 selector: selector, mask: mask, location: identifier); |
| 7587 receiver, | |
| 7588 value, | |
| 7589 selector: selector, | |
| 7590 mask: mask, | |
| 7591 location: identifier); | |
| 7592 } else { | 6875 } else { |
| 7593 generateNonInstanceSetter( | 6876 generateNonInstanceSetter(null, variable, value, location: identifier); |
| 7594 null, variable, value, location: identifier); | |
| 7595 } | 6877 } |
| 7596 pop(); // Pop the value pushed by the setter call. | 6878 pop(); // Pop the value pushed by the setter call. |
| 7597 | 6879 |
| 7598 visit(node.body); | 6880 visit(node.body); |
| 7599 } | 6881 } |
| 7600 | 6882 |
| 7601 void buildUpdate() {}; | 6883 void buildUpdate() {} |
| 6884 ; |
| 7602 | 6885 |
| 7603 buildProtectedByFinally(() { | 6886 buildProtectedByFinally(() { |
| 7604 handleLoop(node, | 6887 handleLoop( |
| 7605 buildInitializer, | 6888 node, buildInitializer, buildCondition, buildUpdate, buildBody); |
| 7606 buildCondition, | |
| 7607 buildUpdate, | |
| 7608 buildBody); | |
| 7609 }, () { | 6889 }, () { |
| 7610 pushInvokeDynamic(node, | 6890 pushInvokeDynamic(node, Selectors.cancel, null, [streamIterator]); |
| 7611 Selectors.cancel, | 6891 push(new HAwait(pop(), |
| 7612 null, | 6892 new TypeMask.subclass(coreClasses.objectClass, compiler.world))); |
| 7613 [streamIterator]); | |
| 7614 push(new HAwait(pop(), new TypeMask.subclass( | |
| 7615 coreClasses.objectClass, compiler.world))); | |
| 7616 pop(); | 6893 pop(); |
| 7617 }); | 6894 }); |
| 7618 } | 6895 } |
| 7619 | 6896 |
| 7620 visitSyncForIn(ast.SyncForIn node) { | 6897 visitSyncForIn(ast.SyncForIn node) { |
| 7621 // The 'get iterator' selector for this node has the inferred receiver type. | 6898 // The 'get iterator' selector for this node has the inferred receiver type. |
| 7622 // If the receiver supports JavaScript indexing we generate an indexing loop | 6899 // If the receiver supports JavaScript indexing we generate an indexing loop |
| 7623 // instead of allocating an iterator object. | 6900 // instead of allocating an iterator object. |
| 7624 | 6901 |
| 7625 // This scheme recognizes for-in on direct lists. It does not recognize all | 6902 // This scheme recognizes for-in on direct lists. It does not recognize all |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7682 buildAssignLoopVariable(ast.ForIn node, HInstruction value) { | 6959 buildAssignLoopVariable(ast.ForIn node, HInstruction value) { |
| 7683 ast.Node identifier = node.declaredIdentifier; | 6960 ast.Node identifier = node.declaredIdentifier; |
| 7684 Element variable = elements.getForInVariable(node); | 6961 Element variable = elements.getForInVariable(node); |
| 7685 Selector selector = elements.getSelector(identifier); | 6962 Selector selector = elements.getSelector(identifier); |
| 7686 TypeMask mask = elements.getTypeMask(identifier); | 6963 TypeMask mask = elements.getTypeMask(identifier); |
| 7687 | 6964 |
| 7688 if (identifier.asSend() != null && | 6965 if (identifier.asSend() != null && |
| 7689 Elements.isInstanceSend(identifier, elements)) { | 6966 Elements.isInstanceSend(identifier, elements)) { |
| 7690 HInstruction receiver = generateInstanceSendReceiver(identifier); | 6967 HInstruction receiver = generateInstanceSendReceiver(identifier); |
| 7691 assert(receiver != null); | 6968 assert(receiver != null); |
| 7692 generateInstanceSetterWithCompiledReceiver( | 6969 generateInstanceSetterWithCompiledReceiver(null, receiver, value, |
| 7693 null, | 6970 selector: selector, mask: mask, location: identifier); |
| 7694 receiver, | |
| 7695 value, | |
| 7696 selector: selector, | |
| 7697 mask: mask, | |
| 7698 location: identifier); | |
| 7699 } else { | 6971 } else { |
| 7700 generateNonInstanceSetter(null, variable, value, location: identifier); | 6972 generateNonInstanceSetter(null, variable, value, location: identifier); |
| 7701 } | 6973 } |
| 7702 pop(); // Discard the value pushed by the setter call. | 6974 pop(); // Discard the value pushed by the setter call. |
| 7703 } | 6975 } |
| 7704 | 6976 |
| 7705 buildSyncForInIndexable(ast.ForIn node, TypeMask arrayType) { | 6977 buildSyncForInIndexable(ast.ForIn node, TypeMask arrayType) { |
| 7706 // Generate a structure equivalent to: | 6978 // Generate a structure equivalent to: |
| 7707 // | 6979 // |
| 7708 // int end = a.length; | 6980 // int end = a.length; |
| 7709 // for (int i = 0; | 6981 // for (int i = 0; |
| 7710 // i < a.length; | 6982 // i < a.length; |
| 7711 // checkConcurrentModificationError(a.length == end, a), ++i) { | 6983 // checkConcurrentModificationError(a.length == end, a), ++i) { |
| 7712 // <declaredIdentifier> = a[i]; | 6984 // <declaredIdentifier> = a[i]; |
| 7713 // <body> | 6985 // <body> |
| 7714 // } | 6986 // } |
| 7715 Element loopVariable = elements.getForInVariable(node); | 6987 Element loopVariable = elements.getForInVariable(node); |
| 7716 SyntheticLocal indexVariable = new SyntheticLocal('_i', loopVariable); | 6988 SyntheticLocal indexVariable = new SyntheticLocal('_i', loopVariable); |
| 7717 TypeMask boolType = backend.boolType; | 6989 TypeMask boolType = backend.boolType; |
| 7718 | 6990 |
| 7719 // These variables are shared by initializer, condition, body and update. | 6991 // These variables are shared by initializer, condition, body and update. |
| 7720 HInstruction array; // Set in buildInitializer. | 6992 HInstruction array; // Set in buildInitializer. |
| 7721 bool isFixed; // Set in buildInitializer. | 6993 bool isFixed; // Set in buildInitializer. |
| 7722 HInstruction originalLength = null; // Set for growable lists. | 6994 HInstruction originalLength = null; // Set for growable lists. |
| 7723 | 6995 |
| 7724 HInstruction buildGetLength() { | 6996 HInstruction buildGetLength() { |
| 7725 Element lengthElement = helpers.jsIndexableLength; | 6997 Element lengthElement = helpers.jsIndexableLength; |
| 7726 HFieldGet result = new HFieldGet( | 6998 HFieldGet result = new HFieldGet( |
| 7727 lengthElement, array, backend.positiveIntType, | 6999 lengthElement, array, backend.positiveIntType, |
| 7728 isAssignable: !isFixed); | 7000 isAssignable: !isFixed); |
| 7729 add(result); | 7001 add(result); |
| 7730 return result; | 7002 return result; |
| 7731 } | 7003 } |
| 7732 | 7004 |
| 7733 void buildConcurrentModificationErrorCheck() { | 7005 void buildConcurrentModificationErrorCheck() { |
| 7734 if (originalLength == null) return; | 7006 if (originalLength == null) return; |
| 7735 // The static call checkConcurrentModificationError() is expanded in | 7007 // The static call checkConcurrentModificationError() is expanded in |
| 7736 // codegen to: | 7008 // codegen to: |
| 7737 // | 7009 // |
| 7738 // array.length == _end || throwConcurrentModificationError(array) | 7010 // array.length == _end || throwConcurrentModificationError(array) |
| 7739 // | 7011 // |
| 7740 HInstruction length = buildGetLength(); | 7012 HInstruction length = buildGetLength(); |
| 7741 push(new HIdentity(length, originalLength, null, boolType)); | 7013 push(new HIdentity(length, originalLength, null, boolType)); |
| 7742 pushInvokeStatic(node, | 7014 pushInvokeStatic( |
| 7743 helpers.checkConcurrentModificationError, | 7015 node, helpers.checkConcurrentModificationError, [pop(), array]); |
| 7744 [pop(), array]); | |
| 7745 pop(); | 7016 pop(); |
| 7746 } | 7017 } |
| 7747 | 7018 |
| 7748 void buildInitializer() { | 7019 void buildInitializer() { |
| 7749 visit(node.expression); | 7020 visit(node.expression); |
| 7750 array = pop(); | 7021 array = pop(); |
| 7751 isFixed = isFixedLength(array.instructionType, compiler); | 7022 isFixed = isFixedLength(array.instructionType, compiler); |
| 7752 localsHandler.updateLocal(indexVariable, | 7023 localsHandler.updateLocal( |
| 7753 graph.addConstantInt(0, compiler)); | 7024 indexVariable, graph.addConstantInt(0, compiler)); |
| 7754 originalLength = buildGetLength(); | 7025 originalLength = buildGetLength(); |
| 7755 } | 7026 } |
| 7756 | 7027 |
| 7757 HInstruction buildCondition() { | 7028 HInstruction buildCondition() { |
| 7758 HInstruction index = localsHandler.readLocal(indexVariable); | 7029 HInstruction index = localsHandler.readLocal(indexVariable); |
| 7759 HInstruction length = buildGetLength(); | 7030 HInstruction length = buildGetLength(); |
| 7760 HInstruction compare = new HLess(index, length, null, boolType); | 7031 HInstruction compare = new HLess(index, length, null, boolType); |
| 7761 add(compare); | 7032 add(compare); |
| 7762 return compare; | 7033 return compare; |
| 7763 } | 7034 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7803 | 7074 |
| 7804 handleLoop(node, buildInitializer, buildCondition, buildUpdate, buildBody); | 7075 handleLoop(node, buildInitializer, buildCondition, buildUpdate, buildBody); |
| 7805 } | 7076 } |
| 7806 | 7077 |
| 7807 visitLabel(ast.Label node) { | 7078 visitLabel(ast.Label node) { |
| 7808 reporter.internalError(node, 'SsaFromAstMixin.visitLabel.'); | 7079 reporter.internalError(node, 'SsaFromAstMixin.visitLabel.'); |
| 7809 } | 7080 } |
| 7810 | 7081 |
| 7811 visitLabeledStatement(ast.LabeledStatement node) { | 7082 visitLabeledStatement(ast.LabeledStatement node) { |
| 7812 ast.Statement body = node.statement; | 7083 ast.Statement body = node.statement; |
| 7813 if (body is ast.Loop | 7084 if (body is ast.Loop || |
| 7814 || body is ast.SwitchStatement | 7085 body is ast.SwitchStatement || |
| 7815 || Elements.isUnusedLabel(node, elements)) { | 7086 Elements.isUnusedLabel(node, elements)) { |
| 7816 // Loops and switches handle their own labels. | 7087 // Loops and switches handle their own labels. |
| 7817 visit(body); | 7088 visit(body); |
| 7818 return; | 7089 return; |
| 7819 } | 7090 } |
| 7820 JumpTarget targetElement = elements.getTargetDefinition(body); | 7091 JumpTarget targetElement = elements.getTargetDefinition(body); |
| 7821 LocalsHandler beforeLocals = new LocalsHandler.from(localsHandler); | 7092 LocalsHandler beforeLocals = new LocalsHandler.from(localsHandler); |
| 7822 assert(targetElement.isBreakTarget); | 7093 assert(targetElement.isBreakTarget); |
| 7823 JumpHandler handler = new JumpHandler(this, targetElement); | 7094 JumpHandler handler = new JumpHandler(this, targetElement); |
| 7824 // Introduce a new basic block. | 7095 // Introduce a new basic block. |
| 7825 HBasicBlock entryBlock = openNewBlock(); | 7096 HBasicBlock entryBlock = openNewBlock(); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 7836 if (!isAborted()) { | 7107 if (!isAborted()) { |
| 7837 goto(current, joinBlock); | 7108 goto(current, joinBlock); |
| 7838 breakHandlers.add(localsHandler); | 7109 breakHandlers.add(localsHandler); |
| 7839 } | 7110 } |
| 7840 open(joinBlock); | 7111 open(joinBlock); |
| 7841 localsHandler = beforeLocals.mergeMultiple(breakHandlers, joinBlock); | 7112 localsHandler = beforeLocals.mergeMultiple(breakHandlers, joinBlock); |
| 7842 | 7113 |
| 7843 if (hasBreak) { | 7114 if (hasBreak) { |
| 7844 // There was at least one reachable break, so the label is needed. | 7115 // There was at least one reachable break, so the label is needed. |
| 7845 entryBlock.setBlockFlow( | 7116 entryBlock.setBlockFlow( |
| 7846 new HLabeledBlockInformation(new HSubGraphBlockInformation(bodyGraph), | 7117 new HLabeledBlockInformation( |
| 7847 handler.labels()), | 7118 new HSubGraphBlockInformation(bodyGraph), handler.labels()), |
| 7848 joinBlock); | 7119 joinBlock); |
| 7849 } | 7120 } |
| 7850 handler.close(); | 7121 handler.close(); |
| 7851 } | 7122 } |
| 7852 | 7123 |
| 7853 visitLiteralMap(ast.LiteralMap node) { | 7124 visitLiteralMap(ast.LiteralMap node) { |
| 7854 if (node.isConst) { | 7125 if (node.isConst) { |
| 7855 stack.add(addConstant(node)); | 7126 stack.add(addConstant(node)); |
| 7856 return; | 7127 return; |
| 7857 } | 7128 } |
| 7858 List<HInstruction> listInputs = <HInstruction>[]; | 7129 List<HInstruction> listInputs = <HInstruction>[]; |
| 7859 for (Link<ast.Node> link = node.entries.nodes; | 7130 for (Link<ast.Node> link = node.entries.nodes; |
| 7860 !link.isEmpty; | 7131 !link.isEmpty; |
| 7861 link = link.tail) { | 7132 link = link.tail) { |
| 7862 visit(link.head); | 7133 visit(link.head); |
| 7863 listInputs.add(pop()); | 7134 listInputs.add(pop()); |
| 7864 listInputs.add(pop()); | 7135 listInputs.add(pop()); |
| 7865 } | 7136 } |
| 7866 | 7137 |
| 7867 Element constructor; | 7138 Element constructor; |
| 7868 List<HInstruction> inputs = <HInstruction>[]; | 7139 List<HInstruction> inputs = <HInstruction>[]; |
| 7869 | 7140 |
| 7870 if (listInputs.isEmpty) { | 7141 if (listInputs.isEmpty) { |
| 7871 constructor = helpers.mapLiteralConstructorEmpty; | 7142 constructor = helpers.mapLiteralConstructorEmpty; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7910 // If rti is needed and the map literal has no type parameters, | 7181 // If rti is needed and the map literal has no type parameters, |
| 7911 // 'constructor' is a static function that forwards the call to the factory | 7182 // 'constructor' is a static function that forwards the call to the factory |
| 7912 // constructor without type parameters. | 7183 // constructor without type parameters. |
| 7913 assert(constructor is ConstructorElement || constructor is FunctionElement); | 7184 assert(constructor is ConstructorElement || constructor is FunctionElement); |
| 7914 | 7185 |
| 7915 // The instruction type will always be a subtype of the mapLiteralClass, but | 7186 // The instruction type will always be a subtype of the mapLiteralClass, but |
| 7916 // type inference might discover a more specific type, or find nothing (in | 7187 // type inference might discover a more specific type, or find nothing (in |
| 7917 // dart2js unit tests). | 7188 // dart2js unit tests). |
| 7918 TypeMask mapType = | 7189 TypeMask mapType = |
| 7919 new TypeMask.nonNullSubtype(helpers.mapLiteralClass, compiler.world); | 7190 new TypeMask.nonNullSubtype(helpers.mapLiteralClass, compiler.world); |
| 7920 TypeMask returnTypeMask = TypeMaskFactory.inferredReturnTypeForElement( | 7191 TypeMask returnTypeMask = |
| 7921 constructor, compiler); | 7192 TypeMaskFactory.inferredReturnTypeForElement(constructor, compiler); |
| 7922 TypeMask instructionType = | 7193 TypeMask instructionType = |
| 7923 mapType.intersection(returnTypeMask, compiler.world); | 7194 mapType.intersection(returnTypeMask, compiler.world); |
| 7924 | 7195 |
| 7925 addInlinedInstantiation(expectedType); | 7196 addInlinedInstantiation(expectedType); |
| 7926 pushInvokeStatic(node, constructor, inputs, | 7197 pushInvokeStatic(node, constructor, inputs, |
| 7927 typeMask: instructionType, instanceType: expectedType); | 7198 typeMask: instructionType, instanceType: expectedType); |
| 7928 removeInlinedInstantiation(expectedType); | 7199 removeInlinedInstantiation(expectedType); |
| 7929 } | 7200 } |
| 7930 | 7201 |
| 7931 visitLiteralMapEntry(ast.LiteralMapEntry node) { | 7202 visitLiteralMapEntry(ast.LiteralMapEntry node) { |
| 7932 visit(node.value); | 7203 visit(node.value); |
| 7933 visit(node.key); | 7204 visit(node.key); |
| 7934 } | 7205 } |
| 7935 | 7206 |
| 7936 visitNamedArgument(ast.NamedArgument node) { | 7207 visitNamedArgument(ast.NamedArgument node) { |
| 7937 visit(node.expression); | 7208 visit(node.expression); |
| 7938 } | 7209 } |
| 7939 | 7210 |
| 7940 Map<ast.CaseMatch, ConstantValue> buildSwitchCaseConstants( | 7211 Map<ast.CaseMatch, ConstantValue> buildSwitchCaseConstants( |
| 7941 ast.SwitchStatement node) { | 7212 ast.SwitchStatement node) { |
| 7942 | |
| 7943 Map<ast.CaseMatch, ConstantValue> constants = | 7213 Map<ast.CaseMatch, ConstantValue> constants = |
| 7944 new Map<ast.CaseMatch, ConstantValue>(); | 7214 new Map<ast.CaseMatch, ConstantValue>(); |
| 7945 for (ast.SwitchCase switchCase in node.cases) { | 7215 for (ast.SwitchCase switchCase in node.cases) { |
| 7946 for (ast.Node labelOrCase in switchCase.labelsAndCases) { | 7216 for (ast.Node labelOrCase in switchCase.labelsAndCases) { |
| 7947 if (labelOrCase is ast.CaseMatch) { | 7217 if (labelOrCase is ast.CaseMatch) { |
| 7948 ast.CaseMatch match = labelOrCase; | 7218 ast.CaseMatch match = labelOrCase; |
| 7949 ConstantValue constant = getConstantForNode(match.expression); | 7219 ConstantValue constant = getConstantForNode(match.expression); |
| 7950 constants[labelOrCase] = constant; | 7220 constants[labelOrCase] = constant; |
| 7951 } | 7221 } |
| 7952 } | 7222 } |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7986 buildSimpleSwitchStatement(node, constants); | 7256 buildSimpleSwitchStatement(node, constants); |
| 7987 } else { | 7257 } else { |
| 7988 buildComplexSwitchStatement(node, constants, caseIndex, hasDefault); | 7258 buildComplexSwitchStatement(node, constants, caseIndex, hasDefault); |
| 7989 } | 7259 } |
| 7990 } | 7260 } |
| 7991 | 7261 |
| 7992 /** | 7262 /** |
| 7993 * Builds a simple switch statement which does not handle uses of continue | 7263 * Builds a simple switch statement which does not handle uses of continue |
| 7994 * statements to labeled switch cases. | 7264 * statements to labeled switch cases. |
| 7995 */ | 7265 */ |
| 7996 void buildSimpleSwitchStatement(ast.SwitchStatement node, | 7266 void buildSimpleSwitchStatement( |
| 7997 Map<ast.CaseMatch, ConstantValue> constants) { | 7267 ast.SwitchStatement node, Map<ast.CaseMatch, ConstantValue> constants) { |
| 7998 JumpHandler jumpHandler = createJumpHandler(node, isLoopJump: false); | 7268 JumpHandler jumpHandler = createJumpHandler(node, isLoopJump: false); |
| 7999 HInstruction buildExpression() { | 7269 HInstruction buildExpression() { |
| 8000 visit(node.expression); | 7270 visit(node.expression); |
| 8001 return pop(); | 7271 return pop(); |
| 8002 } | 7272 } |
| 8003 Iterable<ConstantValue> getConstants(ast.SwitchCase switchCase) { | 7273 Iterable<ConstantValue> getConstants(ast.SwitchCase switchCase) { |
| 8004 List<ConstantValue> constantList = <ConstantValue>[]; | 7274 List<ConstantValue> constantList = <ConstantValue>[]; |
| 8005 for (ast.Node labelOrCase in switchCase.labelsAndCases) { | 7275 for (ast.Node labelOrCase in switchCase.labelsAndCases) { |
| 8006 if (labelOrCase is ast.CaseMatch) { | 7276 if (labelOrCase is ast.CaseMatch) { |
| 8007 constantList.add(constants[labelOrCase]); | 7277 constantList.add(constants[labelOrCase]); |
| 8008 } | 7278 } |
| 8009 } | 7279 } |
| 8010 return constantList; | 7280 return constantList; |
| 8011 } | 7281 } |
| 8012 bool isDefaultCase(ast.SwitchCase switchCase) { | 7282 bool isDefaultCase(ast.SwitchCase switchCase) { |
| 8013 return switchCase.isDefaultCase; | 7283 return switchCase.isDefaultCase; |
| 8014 } | 7284 } |
| 8015 void buildSwitchCase(ast.SwitchCase node) { | 7285 void buildSwitchCase(ast.SwitchCase node) { |
| 8016 visit(node.statements); | 7286 visit(node.statements); |
| 8017 } | 7287 } |
| 8018 handleSwitch(node, | 7288 handleSwitch(node, jumpHandler, buildExpression, node.cases, getConstants, |
| 8019 jumpHandler, | 7289 isDefaultCase, buildSwitchCase); |
| 8020 buildExpression, | |
| 8021 node.cases, | |
| 8022 getConstants, | |
| 8023 isDefaultCase, | |
| 8024 buildSwitchCase); | |
| 8025 jumpHandler.close(); | 7290 jumpHandler.close(); |
| 8026 } | 7291 } |
| 8027 | 7292 |
| 8028 /** | 7293 /** |
| 8029 * Builds a switch statement that can handle arbitrary uses of continue | 7294 * Builds a switch statement that can handle arbitrary uses of continue |
| 8030 * statements to labeled switch cases. | 7295 * statements to labeled switch cases. |
| 8031 */ | 7296 */ |
| 8032 void buildComplexSwitchStatement(ast.SwitchStatement node, | 7297 void buildComplexSwitchStatement( |
| 8033 Map<ast.CaseMatch, ConstantValue> constants, | 7298 ast.SwitchStatement node, |
| 8034 Map<ast.SwitchCase, int> caseIndex, | 7299 Map<ast.CaseMatch, ConstantValue> constants, |
| 8035 bool hasDefault) { | 7300 Map<ast.SwitchCase, int> caseIndex, |
| 7301 bool hasDefault) { |
| 8036 // If the switch statement has switch cases targeted by continue | 7302 // If the switch statement has switch cases targeted by continue |
| 8037 // statements we create the following encoding: | 7303 // statements we create the following encoding: |
| 8038 // | 7304 // |
| 8039 // switch (e) { | 7305 // switch (e) { |
| 8040 // l_1: case e0: s_1; break; | 7306 // l_1: case e0: s_1; break; |
| 8041 // l_2: case e1: s_2; continue l_i; | 7307 // l_2: case e1: s_2; continue l_i; |
| 8042 // ... | 7308 // ... |
| 8043 // l_n: default: s_n; continue l_j; | 7309 // l_n: default: s_n; continue l_j; |
| 8044 // } | 7310 // } |
| 8045 // | 7311 // |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8097 int index = caseIndex[switchCase]; | 7363 int index = caseIndex[switchCase]; |
| 8098 HInstruction value = graph.addConstantInt(index, compiler); | 7364 HInstruction value = graph.addConstantInt(index, compiler); |
| 8099 localsHandler.updateLocal(switchTarget, value); | 7365 localsHandler.updateLocal(switchTarget, value); |
| 8100 } else { | 7366 } else { |
| 8101 // Generate synthetic default case 'target = null; break;'. | 7367 // Generate synthetic default case 'target = null; break;'. |
| 8102 HInstruction value = graph.addConstantNull(compiler); | 7368 HInstruction value = graph.addConstantNull(compiler); |
| 8103 localsHandler.updateLocal(switchTarget, value); | 7369 localsHandler.updateLocal(switchTarget, value); |
| 8104 } | 7370 } |
| 8105 jumpTargets[switchTarget].generateBreak(); | 7371 jumpTargets[switchTarget].generateBreak(); |
| 8106 } | 7372 } |
| 8107 handleSwitch(node, | 7373 handleSwitch(node, jumpHandler, buildExpression, switchCases, getConstants, |
| 8108 jumpHandler, | 7374 isDefaultCase, buildSwitchCase); |
| 8109 buildExpression, | |
| 8110 switchCases, | |
| 8111 getConstants, | |
| 8112 isDefaultCase, | |
| 8113 buildSwitchCase); | |
| 8114 jumpHandler.close(); | 7375 jumpHandler.close(); |
| 8115 | 7376 |
| 8116 HInstruction buildCondition() => | 7377 HInstruction buildCondition() => graph.addConstantBool(true, compiler); |
| 8117 graph.addConstantBool(true, compiler); | |
| 8118 | 7378 |
| 8119 void buildSwitch() { | 7379 void buildSwitch() { |
| 8120 HInstruction buildExpression() { | 7380 HInstruction buildExpression() { |
| 8121 return localsHandler.readLocal(switchTarget); | 7381 return localsHandler.readLocal(switchTarget); |
| 8122 } | 7382 } |
| 8123 Iterable<ConstantValue> getConstants(ast.SwitchCase switchCase) { | 7383 Iterable<ConstantValue> getConstants(ast.SwitchCase switchCase) { |
| 8124 return <ConstantValue>[constantSystem.createInt(caseIndex[switchCase])]; | 7384 return <ConstantValue>[constantSystem.createInt(caseIndex[switchCase])]; |
| 8125 } | 7385 } |
| 8126 void buildSwitchCase(ast.SwitchCase switchCase) { | 7386 void buildSwitchCase(ast.SwitchCase switchCase) { |
| 8127 visit(switchCase.statements); | 7387 visit(switchCase.statements); |
| 8128 if (!isAborted()) { | 7388 if (!isAborted()) { |
| 8129 // Ensure that we break the loop if the case falls through. (This | 7389 // Ensure that we break the loop if the case falls through. (This |
| 8130 // is only possible for the last case.) | 7390 // is only possible for the last case.) |
| 8131 jumpTargets[switchTarget].generateBreak(); | 7391 jumpTargets[switchTarget].generateBreak(); |
| 8132 } | 7392 } |
| 8133 } | 7393 } |
| 8134 // Pass a [NullJumpHandler] because the target for the contained break | 7394 // Pass a [NullJumpHandler] because the target for the contained break |
| 8135 // is not the generated switch statement but instead the loop generated | 7395 // is not the generated switch statement but instead the loop generated |
| 8136 // in the call to [handleLoop] below. | 7396 // in the call to [handleLoop] below. |
| 8137 handleSwitch(node, | 7397 handleSwitch( |
| 8138 new NullJumpHandler(reporter), | 7398 node, |
| 8139 buildExpression, node.cases, getConstants, | 7399 new NullJumpHandler(reporter), |
| 8140 (_) => false, // No case is default. | 7400 buildExpression, |
| 8141 buildSwitchCase); | 7401 node.cases, |
| 7402 getConstants, |
| 7403 (_) => false, // No case is default. |
| 7404 buildSwitchCase); |
| 8142 } | 7405 } |
| 8143 | 7406 |
| 8144 void buildLoop() { | 7407 void buildLoop() { |
| 8145 handleLoop(node, | 7408 handleLoop(node, () {}, buildCondition, () {}, buildSwitch); |
| 8146 () {}, | |
| 8147 buildCondition, | |
| 8148 () {}, | |
| 8149 buildSwitch); | |
| 8150 } | 7409 } |
| 8151 | 7410 |
| 8152 if (hasDefault) { | 7411 if (hasDefault) { |
| 8153 buildLoop(); | 7412 buildLoop(); |
| 8154 } else { | 7413 } else { |
| 8155 // If the switch statement has no default case, surround the loop with | 7414 // If the switch statement has no default case, surround the loop with |
| 8156 // a test of the target. | 7415 // a test of the target. |
| 8157 void buildCondition() { | 7416 void buildCondition() { |
| 8158 js.Template code = js.js.parseForeignJS('#'); | 7417 js.Template code = js.js.parseForeignJS('#'); |
| 8159 push(new HForeignCode( | 7418 push(new HForeignCode( |
| 8160 code, | 7419 code, backend.boolType, [localsHandler.readLocal(switchTarget)], |
| 8161 backend.boolType, | |
| 8162 [localsHandler.readLocal(switchTarget)], | |
| 8163 nativeBehavior: native.NativeBehavior.PURE)); | 7420 nativeBehavior: native.NativeBehavior.PURE)); |
| 8164 } | 7421 } |
| 8165 handleIf(node, | 7422 handleIf(node, |
| 8166 visitCondition: buildCondition, | 7423 visitCondition: buildCondition, |
| 8167 visitThen: buildLoop, | 7424 visitThen: buildLoop, |
| 8168 visitElse: () => {}); | 7425 visitElse: () => {}); |
| 8169 } | 7426 } |
| 8170 } | 7427 } |
| 8171 | 7428 |
| 8172 /** | 7429 /** |
| 8173 * Creates a switch statement. | 7430 * Creates a switch statement. |
| 8174 * | 7431 * |
| 8175 * [jumpHandler] is the [JumpHandler] for the created switch statement. | 7432 * [jumpHandler] is the [JumpHandler] for the created switch statement. |
| 8176 * [buildExpression] creates the switch expression. | 7433 * [buildExpression] creates the switch expression. |
| 8177 * [switchCases] must be either an [Iterable] of [ast.SwitchCase] nodes or | 7434 * [switchCases] must be either an [Iterable] of [ast.SwitchCase] nodes or |
| 8178 * a [Link] or a [ast.NodeList] of [ast.SwitchCase] nodes. | 7435 * a [Link] or a [ast.NodeList] of [ast.SwitchCase] nodes. |
| 8179 * [getConstants] returns the set of constants for a switch case. | 7436 * [getConstants] returns the set of constants for a switch case. |
| 8180 * [isDefaultCase] returns [:true:] if the provided switch case should be | 7437 * [isDefaultCase] returns [:true:] if the provided switch case should be |
| 8181 * considered default for the created switch statement. | 7438 * considered default for the created switch statement. |
| 8182 * [buildSwitchCase] creates the statements for the switch case. | 7439 * [buildSwitchCase] creates the statements for the switch case. |
| 8183 */ | 7440 */ |
| 8184 void handleSwitch( | 7441 void handleSwitch( |
| 8185 ast.Node errorNode, | 7442 ast.Node errorNode, |
| 8186 JumpHandler jumpHandler, | 7443 JumpHandler jumpHandler, |
| 8187 HInstruction buildExpression(), | 7444 HInstruction buildExpression(), |
| 8188 var switchCases, | 7445 var switchCases, |
| 8189 Iterable<ConstantValue> getConstants(ast.SwitchCase switchCase), | 7446 Iterable<ConstantValue> getConstants(ast.SwitchCase switchCase), |
| 8190 bool isDefaultCase(ast.SwitchCase switchCase), | 7447 bool isDefaultCase(ast.SwitchCase switchCase), |
| 8191 void buildSwitchCase(ast.SwitchCase switchCase)) { | 7448 void buildSwitchCase(ast.SwitchCase switchCase)) { |
| 8192 | |
| 8193 HBasicBlock expressionStart = openNewBlock(); | 7449 HBasicBlock expressionStart = openNewBlock(); |
| 8194 HInstruction expression = buildExpression(); | 7450 HInstruction expression = buildExpression(); |
| 8195 if (switchCases.isEmpty) { | 7451 if (switchCases.isEmpty) { |
| 8196 return; | 7452 return; |
| 8197 } | 7453 } |
| 8198 | 7454 |
| 8199 HSwitch switchInstruction = new HSwitch(<HInstruction>[expression]); | 7455 HSwitch switchInstruction = new HSwitch(<HInstruction>[expression]); |
| 8200 HBasicBlock expressionEnd = close(switchInstruction); | 7456 HBasicBlock expressionEnd = close(switchInstruction); |
| 8201 LocalsHandler savedLocals = localsHandler; | 7457 LocalsHandler savedLocals = localsHandler; |
| 8202 | 7458 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8248 // If we never jump to the join block, [caseHandlers] will stay empty, and | 7504 // If we never jump to the join block, [caseHandlers] will stay empty, and |
| 8249 // the join block is never added to the graph. | 7505 // the join block is never added to the graph. |
| 8250 HBasicBlock joinBlock = new HBasicBlock(); | 7506 HBasicBlock joinBlock = new HBasicBlock(); |
| 8251 List<LocalsHandler> caseHandlers = <LocalsHandler>[]; | 7507 List<LocalsHandler> caseHandlers = <LocalsHandler>[]; |
| 8252 jumpHandler.forEachBreak((HBreak instruction, LocalsHandler locals) { | 7508 jumpHandler.forEachBreak((HBreak instruction, LocalsHandler locals) { |
| 8253 instruction.block.addSuccessor(joinBlock); | 7509 instruction.block.addSuccessor(joinBlock); |
| 8254 caseHandlers.add(locals); | 7510 caseHandlers.add(locals); |
| 8255 }); | 7511 }); |
| 8256 jumpHandler.forEachContinue((HContinue instruction, LocalsHandler locals) { | 7512 jumpHandler.forEachContinue((HContinue instruction, LocalsHandler locals) { |
| 8257 assert(invariant(errorNode, false, | 7513 assert(invariant(errorNode, false, |
| 8258 message: 'Continue cannot target a switch.')); | 7514 message: 'Continue cannot target a switch.')); |
| 8259 }); | 7515 }); |
| 8260 if (!isAborted()) { | 7516 if (!isAborted()) { |
| 8261 current.close(new HGoto()); | 7517 current.close(new HGoto()); |
| 8262 lastOpenedBlock.addSuccessor(joinBlock); | 7518 lastOpenedBlock.addSuccessor(joinBlock); |
| 8263 caseHandlers.add(localsHandler); | 7519 caseHandlers.add(localsHandler); |
| 8264 } | 7520 } |
| 8265 if (!hasDefault) { | 7521 if (!hasDefault) { |
| 8266 // Always create a default case, to avoid a critical edge in the | 7522 // Always create a default case, to avoid a critical edge in the |
| 8267 // graph. | 7523 // graph. |
| 8268 HBasicBlock defaultCase = addNewBlock(); | 7524 HBasicBlock defaultCase = addNewBlock(); |
| 8269 expressionEnd.addSuccessor(defaultCase); | 7525 expressionEnd.addSuccessor(defaultCase); |
| 8270 open(defaultCase); | 7526 open(defaultCase); |
| 8271 close(new HGoto()); | 7527 close(new HGoto()); |
| 8272 defaultCase.addSuccessor(joinBlock); | 7528 defaultCase.addSuccessor(joinBlock); |
| 8273 caseHandlers.add(savedLocals); | 7529 caseHandlers.add(savedLocals); |
| 8274 statements.add(new HSubGraphBlockInformation(new SubGraph( | 7530 statements.add(new HSubGraphBlockInformation( |
| 8275 defaultCase, defaultCase))); | 7531 new SubGraph(defaultCase, defaultCase))); |
| 8276 } | 7532 } |
| 8277 assert(caseHandlers.length == joinBlock.predecessors.length); | 7533 assert(caseHandlers.length == joinBlock.predecessors.length); |
| 8278 if (caseHandlers.length != 0) { | 7534 if (caseHandlers.length != 0) { |
| 8279 graph.addBlock(joinBlock); | 7535 graph.addBlock(joinBlock); |
| 8280 open(joinBlock); | 7536 open(joinBlock); |
| 8281 if (caseHandlers.length == 1) { | 7537 if (caseHandlers.length == 1) { |
| 8282 localsHandler = caseHandlers[0]; | 7538 localsHandler = caseHandlers[0]; |
| 8283 } else { | 7539 } else { |
| 8284 localsHandler = savedLocals.mergeMultiple(caseHandlers, joinBlock); | 7540 localsHandler = savedLocals.mergeMultiple(caseHandlers, joinBlock); |
| 8285 } | 7541 } |
| 8286 } else { | 7542 } else { |
| 8287 // The joinblock is not used. | 7543 // The joinblock is not used. |
| 8288 joinBlock = null; | 7544 joinBlock = null; |
| 8289 } | 7545 } |
| 8290 | 7546 |
| 8291 HSubExpressionBlockInformation expressionInfo = | 7547 HSubExpressionBlockInformation expressionInfo = |
| 8292 new HSubExpressionBlockInformation(new SubExpression(expressionStart, | 7548 new HSubExpressionBlockInformation( |
| 8293 expressionEnd)); | 7549 new SubExpression(expressionStart, expressionEnd)); |
| 8294 expressionStart.setBlockFlow( | 7550 expressionStart.setBlockFlow( |
| 8295 new HSwitchBlockInformation(expressionInfo, | 7551 new HSwitchBlockInformation(expressionInfo, statements, |
| 8296 statements, | 7552 jumpHandler.target, jumpHandler.labels()), |
| 8297 jumpHandler.target, | |
| 8298 jumpHandler.labels()), | |
| 8299 joinBlock); | 7553 joinBlock); |
| 8300 | 7554 |
| 8301 jumpHandler.close(); | 7555 jumpHandler.close(); |
| 8302 } | 7556 } |
| 8303 | 7557 |
| 8304 visitSwitchCase(ast.SwitchCase node) { | 7558 visitSwitchCase(ast.SwitchCase node) { |
| 8305 reporter.internalError(node, 'SsaFromAstMixin.visitSwitchCase.'); | 7559 reporter.internalError(node, 'SsaFromAstMixin.visitSwitchCase.'); |
| 8306 } | 7560 } |
| 8307 | 7561 |
| 8308 visitCaseMatch(ast.CaseMatch node) { | 7562 visitCaseMatch(ast.CaseMatch node) { |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8389 addExitTrySuccessor(startFinallyBlock); | 7643 addExitTrySuccessor(startFinallyBlock); |
| 8390 | 7644 |
| 8391 // Use the locals handler not altered by the catch and finally | 7645 // Use the locals handler not altered by the catch and finally |
| 8392 // blocks. | 7646 // blocks. |
| 8393 // TODO(sigurdm): We can probably do this, because try-variables are boxed. | 7647 // TODO(sigurdm): We can probably do this, because try-variables are boxed. |
| 8394 // Need to verify. | 7648 // Need to verify. |
| 8395 localsHandler = savedLocals; | 7649 localsHandler = savedLocals; |
| 8396 open(exitBlock); | 7650 open(exitBlock); |
| 8397 enterBlock.setBlockFlow( | 7651 enterBlock.setBlockFlow( |
| 8398 new HTryBlockInformation( | 7652 new HTryBlockInformation( |
| 8399 wrapStatementGraph(bodyGraph), | 7653 wrapStatementGraph(bodyGraph), |
| 8400 null, // No catch-variable. | 7654 null, // No catch-variable. |
| 8401 null, // No catchGraph. | 7655 null, // No catchGraph. |
| 8402 wrapStatementGraph(finallyGraph)), | 7656 wrapStatementGraph(finallyGraph)), |
| 8403 exitBlock); | 7657 exitBlock); |
| 8404 inTryStatement = oldInTryStatement; | 7658 inTryStatement = oldInTryStatement; |
| 8405 } | 7659 } |
| 8406 | 7660 |
| 8407 visitTryStatement(ast.TryStatement node) { | 7661 visitTryStatement(ast.TryStatement node) { |
| 8408 // Save the current locals. The catch block and the finally block | 7662 // Save the current locals. The catch block and the finally block |
| 8409 // must not reuse the existing locals handler. None of the variables | 7663 // must not reuse the existing locals handler. None of the variables |
| 8410 // that have been defined in the body-block will be used, but for | 7664 // that have been defined in the body-block will be used, but for |
| 8411 // loops we will add (unnecessary) phis that will reference the body | 7665 // loops we will add (unnecessary) phis that will reference the body |
| 8412 // variables. This makes it look as if the variables were used | 7666 // variables. This makes it look as if the variables were used |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8482 } | 7736 } |
| 8483 } | 7737 } |
| 8484 } | 7738 } |
| 8485 | 7739 |
| 8486 void visitThen() { | 7740 void visitThen() { |
| 8487 ast.CatchBlock catchBlock = link.head; | 7741 ast.CatchBlock catchBlock = link.head; |
| 8488 link = link.tail; | 7742 link = link.tail; |
| 8489 if (catchBlock.exception != null) { | 7743 if (catchBlock.exception != null) { |
| 8490 LocalVariableElement exceptionVariable = | 7744 LocalVariableElement exceptionVariable = |
| 8491 elements[catchBlock.exception]; | 7745 elements[catchBlock.exception]; |
| 8492 localsHandler.updateLocal(exceptionVariable, | 7746 localsHandler.updateLocal(exceptionVariable, unwrappedException); |
| 8493 unwrappedException); | |
| 8494 } | 7747 } |
| 8495 ast.Node trace = catchBlock.trace; | 7748 ast.Node trace = catchBlock.trace; |
| 8496 if (trace != null) { | 7749 if (trace != null) { |
| 8497 pushInvokeStatic(trace, helpers.traceFromException, [exception]); | 7750 pushInvokeStatic(trace, helpers.traceFromException, [exception]); |
| 8498 HInstruction traceInstruction = pop(); | 7751 HInstruction traceInstruction = pop(); |
| 8499 LocalVariableElement traceVariable = elements[trace]; | 7752 LocalVariableElement traceVariable = elements[trace]; |
| 8500 localsHandler.updateLocal(traceVariable, traceInstruction); | 7753 localsHandler.updateLocal(traceVariable, traceInstruction); |
| 8501 } | 7754 } |
| 8502 visit(catchBlock); | 7755 visit(catchBlock); |
| 8503 } | 7756 } |
| 8504 | 7757 |
| 8505 void visitElse() { | 7758 void visitElse() { |
| 8506 if (link.isEmpty) { | 7759 if (link.isEmpty) { |
| 8507 closeAndGotoExit( | 7760 closeAndGotoExit(new HThrow(exception, exception.sourceInformation, |
| 8508 new HThrow(exception, | 7761 isRethrow: true)); |
| 8509 exception.sourceInformation, | |
| 8510 isRethrow: true)); | |
| 8511 } else { | 7762 } else { |
| 8512 ast.CatchBlock newBlock = link.head; | 7763 ast.CatchBlock newBlock = link.head; |
| 8513 handleIf(node, | 7764 handleIf(node, visitCondition: () { |
| 8514 visitCondition: () { pushCondition(newBlock); }, | 7765 pushCondition(newBlock); |
| 8515 visitThen: visitThen, | 7766 }, visitThen: visitThen, visitElse: visitElse); |
| 8516 visitElse: visitElse); | |
| 8517 } | 7767 } |
| 8518 } | 7768 } |
| 8519 | 7769 |
| 8520 ast.CatchBlock firstBlock = link.head; | 7770 ast.CatchBlock firstBlock = link.head; |
| 8521 handleIf(node, | 7771 handleIf(node, visitCondition: () { |
| 8522 visitCondition: () { pushCondition(firstBlock); }, | 7772 pushCondition(firstBlock); |
| 8523 visitThen: visitThen, | 7773 }, visitThen: visitThen, visitElse: visitElse); |
| 8524 visitElse: visitElse); | |
| 8525 if (!isAborted()) endCatchBlock = close(new HGoto()); | 7774 if (!isAborted()) endCatchBlock = close(new HGoto()); |
| 8526 | 7775 |
| 8527 rethrowableException = oldRethrowableException; | 7776 rethrowableException = oldRethrowableException; |
| 8528 tryInstruction.catchBlock = startCatchBlock; | 7777 tryInstruction.catchBlock = startCatchBlock; |
| 8529 catchGraph = new SubGraph(startCatchBlock, lastOpenedBlock); | 7778 catchGraph = new SubGraph(startCatchBlock, lastOpenedBlock); |
| 8530 } | 7779 } |
| 8531 | 7780 |
| 8532 SubGraph finallyGraph = null; | 7781 SubGraph finallyGraph = null; |
| 8533 if (node.finallyBlock != null) { | 7782 if (node.finallyBlock != null) { |
| 8534 localsHandler = new LocalsHandler.from(savedLocals); | 7783 localsHandler = new LocalsHandler.from(savedLocals); |
| 8535 startFinallyBlock = graph.addNewBlock(); | 7784 startFinallyBlock = graph.addNewBlock(); |
| 8536 open(startFinallyBlock); | 7785 open(startFinallyBlock); |
| 8537 visit(node.finallyBlock); | 7786 visit(node.finallyBlock); |
| 8538 if (!isAborted()) endFinallyBlock = close(new HGoto()); | 7787 if (!isAborted()) endFinallyBlock = close(new HGoto()); |
| 8539 tryInstruction.finallyBlock = startFinallyBlock; | 7788 tryInstruction.finallyBlock = startFinallyBlock; |
| 8540 finallyGraph = new SubGraph(startFinallyBlock, lastOpenedBlock); | 7789 finallyGraph = new SubGraph(startFinallyBlock, lastOpenedBlock); |
| 8541 } | 7790 } |
| 8542 | 7791 |
| 8543 HBasicBlock exitBlock = graph.addNewBlock(); | 7792 HBasicBlock exitBlock = graph.addNewBlock(); |
| 8544 | 7793 |
| 8545 addOptionalSuccessor(b1, b2) { if (b2 != null) b1.addSuccessor(b2); } | 7794 addOptionalSuccessor(b1, b2) { |
| 7795 if (b2 != null) b1.addSuccessor(b2); |
| 7796 } |
| 8546 addExitTrySuccessor(successor) { | 7797 addExitTrySuccessor(successor) { |
| 8547 if (successor == null) return; | 7798 if (successor == null) return; |
| 8548 // Iterate over all blocks created inside this try/catch, and | 7799 // Iterate over all blocks created inside this try/catch, and |
| 8549 // attach successor information to blocks that end with | 7800 // attach successor information to blocks that end with |
| 8550 // [HExitTry]. | 7801 // [HExitTry]. |
| 8551 for (int i = startTryBlock.id; i < successor.id; i++) { | 7802 for (int i = startTryBlock.id; i < successor.id; i++) { |
| 8552 HBasicBlock block = graph.blocks[i]; | 7803 HBasicBlock block = graph.blocks[i]; |
| 8553 var last = block.last; | 7804 var last = block.last; |
| 8554 if (last is HExitTry) { | 7805 if (last is HExitTry) { |
| 8555 block.addSuccessor(successor); | 7806 block.addSuccessor(successor); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8589 // we explicitely mark this block a predecessor of the catch | 7840 // we explicitely mark this block a predecessor of the catch |
| 8590 // block and the finally block. | 7841 // block and the finally block. |
| 8591 addExitTrySuccessor(startCatchBlock); | 7842 addExitTrySuccessor(startCatchBlock); |
| 8592 addExitTrySuccessor(startFinallyBlock); | 7843 addExitTrySuccessor(startFinallyBlock); |
| 8593 | 7844 |
| 8594 // Use the locals handler not altered by the catch and finally | 7845 // Use the locals handler not altered by the catch and finally |
| 8595 // blocks. | 7846 // blocks. |
| 8596 localsHandler = savedLocals; | 7847 localsHandler = savedLocals; |
| 8597 open(exitBlock); | 7848 open(exitBlock); |
| 8598 enterBlock.setBlockFlow( | 7849 enterBlock.setBlockFlow( |
| 8599 new HTryBlockInformation( | 7850 new HTryBlockInformation(wrapStatementGraph(bodyGraph), exception, |
| 8600 wrapStatementGraph(bodyGraph), | 7851 wrapStatementGraph(catchGraph), wrapStatementGraph(finallyGraph)), |
| 8601 exception, | |
| 8602 wrapStatementGraph(catchGraph), | |
| 8603 wrapStatementGraph(finallyGraph)), | |
| 8604 exitBlock); | 7852 exitBlock); |
| 8605 inTryStatement = oldInTryStatement; | 7853 inTryStatement = oldInTryStatement; |
| 8606 } | 7854 } |
| 8607 | 7855 |
| 8608 visitCatchBlock(ast.CatchBlock node) { | 7856 visitCatchBlock(ast.CatchBlock node) { |
| 8609 visit(node.block); | 7857 visit(node.block); |
| 8610 } | 7858 } |
| 8611 | 7859 |
| 8612 visitTypedef(ast.Typedef node) { | 7860 visitTypedef(ast.Typedef node) { |
| 8613 compiler.unimplemented(node, 'SsaFromAstMixin.visitTypedef.'); | 7861 compiler.unimplemented(node, 'SsaFromAstMixin.visitTypedef.'); |
| 8614 } | 7862 } |
| 8615 | 7863 |
| 8616 visitTypeVariable(ast.TypeVariable node) { | 7864 visitTypeVariable(ast.TypeVariable node) { |
| 8617 reporter.internalError(node, 'SsaFromAstMixin.visitTypeVariable.'); | 7865 reporter.internalError(node, 'SsaFromAstMixin.visitTypeVariable.'); |
| 8618 } | 7866 } |
| 8619 | 7867 |
| 8620 /** | 7868 /** |
| 8621 * This method is invoked before inlining the body of [function] into this | 7869 * This method is invoked before inlining the body of [function] into this |
| 8622 * [SsaBuilder]. | 7870 * [SsaBuilder]. |
| 8623 */ | 7871 */ |
| 8624 void enterInlinedMethod(FunctionElement function, | 7872 void enterInlinedMethod(FunctionElement function, ast.Node _, |
| 8625 ast.Node _, | 7873 List<HInstruction> compiledArguments, |
| 8626 List<HInstruction> compiledArguments, | 7874 {InterfaceType instanceType}) { |
| 8627 {InterfaceType instanceType}) { | |
| 8628 AstInliningState state = new AstInliningState( | 7875 AstInliningState state = new AstInliningState( |
| 8629 function, returnLocal, returnType, elements, stack, localsHandler, | 7876 function, |
| 7877 returnLocal, |
| 7878 returnType, |
| 7879 elements, |
| 7880 stack, |
| 7881 localsHandler, |
| 8630 inTryStatement, | 7882 inTryStatement, |
| 8631 allInlinedFunctionsCalledOnce && isFunctionCalledOnce(function)); | 7883 allInlinedFunctionsCalledOnce && isFunctionCalledOnce(function)); |
| 8632 inliningStack.add(state); | 7884 inliningStack.add(state); |
| 8633 | 7885 |
| 8634 // Setting up the state of the (AST) builder is performed even when the | 7886 // Setting up the state of the (AST) builder is performed even when the |
| 8635 // inlined function is in IR, because the irInliner uses the [returnElement] | 7887 // inlined function is in IR, because the irInliner uses the [returnElement] |
| 8636 // of the AST builder. | 7888 // of the AST builder. |
| 8637 setupStateForInlining( | 7889 setupStateForInlining(function, compiledArguments, |
| 8638 function, compiledArguments, instanceType: instanceType); | 7890 instanceType: instanceType); |
| 8639 } | 7891 } |
| 8640 | 7892 |
| 8641 void leaveInlinedMethod() { | 7893 void leaveInlinedMethod() { |
| 8642 HInstruction result = localsHandler.readLocal(returnLocal); | 7894 HInstruction result = localsHandler.readLocal(returnLocal); |
| 8643 AstInliningState state = inliningStack.removeLast(); | 7895 AstInliningState state = inliningStack.removeLast(); |
| 8644 restoreState(state); | 7896 restoreState(state); |
| 8645 stack.add(result); | 7897 stack.add(result); |
| 8646 } | 7898 } |
| 8647 | 7899 |
| 8648 void doInline(FunctionElement function) { | 7900 void doInline(FunctionElement function) { |
| 8649 visitInlinedFunction(function); | 7901 visitInlinedFunction(function); |
| 8650 } | 7902 } |
| 8651 | 7903 |
| 8652 void emitReturn(HInstruction value, ast.Node node) { | 7904 void emitReturn(HInstruction value, ast.Node node) { |
| 8653 if (inliningStack.isEmpty) { | 7905 if (inliningStack.isEmpty) { |
| 8654 closeAndGotoExit(new HReturn(value, | 7906 closeAndGotoExit( |
| 8655 sourceInformationBuilder.buildReturn(node))); | 7907 new HReturn(value, sourceInformationBuilder.buildReturn(node))); |
| 8656 } else { | 7908 } else { |
| 8657 localsHandler.updateLocal(returnLocal, value); | 7909 localsHandler.updateLocal(returnLocal, value); |
| 8658 } | 7910 } |
| 8659 } | 7911 } |
| 8660 | 7912 |
| 8661 @override | 7913 @override |
| 8662 void handleTypeLiteralConstantCompounds( | 7914 void handleTypeLiteralConstantCompounds( |
| 8663 ast.SendSet node, | 7915 ast.SendSet node, ConstantExpression constant, CompoundRhs rhs, _) { |
| 8664 ConstantExpression constant, | |
| 8665 CompoundRhs rhs, | |
| 8666 _) { | |
| 8667 handleTypeLiteralCompound(node); | 7916 handleTypeLiteralCompound(node); |
| 8668 } | 7917 } |
| 8669 | 7918 |
| 8670 @override | 7919 @override |
| 8671 void handleTypeVariableTypeLiteralCompounds( | 7920 void handleTypeVariableTypeLiteralCompounds( |
| 8672 ast.SendSet node, | 7921 ast.SendSet node, TypeVariableElement typeVariable, CompoundRhs rhs, _) { |
| 8673 TypeVariableElement typeVariable, | |
| 8674 CompoundRhs rhs, | |
| 8675 _) { | |
| 8676 handleTypeLiteralCompound(node); | 7922 handleTypeLiteralCompound(node); |
| 8677 } | 7923 } |
| 8678 | 7924 |
| 8679 void handleTypeLiteralCompound(ast.SendSet node) { | 7925 void handleTypeLiteralCompound(ast.SendSet node) { |
| 8680 generateIsDeferredLoadedCheckOfSend(node); | 7926 generateIsDeferredLoadedCheckOfSend(node); |
| 8681 ast.Identifier selector = node.selector; | 7927 ast.Identifier selector = node.selector; |
| 8682 generateThrowNoSuchMethod(node, selector.source, | 7928 generateThrowNoSuchMethod(node, selector.source, |
| 8683 argumentNodes: node.arguments); | 7929 argumentNodes: node.arguments); |
| 8684 } | 7930 } |
| 8685 | 7931 |
| 8686 @override | 7932 @override |
| 8687 void visitConstantGet( | 7933 void visitConstantGet(ast.Send node, ConstantExpression constant, _) { |
| 8688 ast.Send node, | |
| 8689 ConstantExpression constant, | |
| 8690 _) { | |
| 8691 visitNode(node); | 7934 visitNode(node); |
| 8692 } | 7935 } |
| 8693 | 7936 |
| 8694 @override | 7937 @override |
| 8695 void visitConstantInvoke( | 7938 void visitConstantInvoke(ast.Send node, ConstantExpression constant, |
| 8696 ast.Send node, | 7939 ast.NodeList arguments, CallStructure callStreucture, _) { |
| 8697 ConstantExpression constant, | |
| 8698 ast.NodeList arguments, | |
| 8699 CallStructure callStreucture, | |
| 8700 _) { | |
| 8701 visitNode(node); | 7940 visitNode(node); |
| 8702 } | 7941 } |
| 8703 | 7942 |
| 8704 @override | 7943 @override |
| 8705 void errorUndefinedBinaryExpression( | 7944 void errorUndefinedBinaryExpression( |
| 8706 ast.Send node, | 7945 ast.Send node, ast.Node left, ast.Operator operator, ast.Node right, _) { |
| 8707 ast.Node left, | |
| 8708 ast.Operator operator, | |
| 8709 ast.Node right, | |
| 8710 _) { | |
| 8711 visitNode(node); | 7946 visitNode(node); |
| 8712 } | 7947 } |
| 8713 | 7948 |
| 8714 @override | 7949 @override |
| 8715 void errorUndefinedUnaryExpression( | 7950 void errorUndefinedUnaryExpression( |
| 8716 ast.Send node, | 7951 ast.Send node, ast.Operator operator, ast.Node expression, _) { |
| 8717 ast.Operator operator, | |
| 8718 ast.Node expression, | |
| 8719 _) { | |
| 8720 visitNode(node); | 7952 visitNode(node); |
| 8721 } | 7953 } |
| 8722 | 7954 |
| 8723 @override | 7955 @override |
| 8724 void bulkHandleError(ast.Node node, ErroneousElement error, _) { | 7956 void bulkHandleError(ast.Node node, ErroneousElement error, _) { |
| 8725 // TODO(johnniwinther): Use an uncatchable error when supported. | 7957 // TODO(johnniwinther): Use an uncatchable error when supported. |
| 8726 generateRuntimeError(node, error.message); | 7958 generateRuntimeError(node, error.message); |
| 8727 } | 7959 } |
| 8728 } | 7960 } |
| 8729 | 7961 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8767 append(stringify(node, expression)); | 7999 append(stringify(node, expression)); |
| 8768 return; | 8000 return; |
| 8769 } | 8001 } |
| 8770 | 8002 |
| 8771 // If the `toString` method is guaranteed to return a string we can call it | 8003 // If the `toString` method is guaranteed to return a string we can call it |
| 8772 // directly. | 8004 // directly. |
| 8773 Selector selector = Selectors.toString_; | 8005 Selector selector = Selectors.toString_; |
| 8774 TypeMask type = TypeMaskFactory.inferredTypeForSelector( | 8006 TypeMask type = TypeMaskFactory.inferredTypeForSelector( |
| 8775 selector, expression.instructionType, compiler); | 8007 selector, expression.instructionType, compiler); |
| 8776 if (type.containsOnlyString(compiler.world)) { | 8008 if (type.containsOnlyString(compiler.world)) { |
| 8777 builder.pushInvokeDynamic( | 8009 builder.pushInvokeDynamic(node, selector, expression.instructionType, |
| 8778 node, selector, | 8010 <HInstruction>[expression]); |
| 8779 expression.instructionType, <HInstruction>[expression]); | |
| 8780 append(builder.pop()); | 8011 append(builder.pop()); |
| 8781 return; | 8012 return; |
| 8782 } | 8013 } |
| 8783 | 8014 |
| 8784 append(stringify(node, expression)); | 8015 append(stringify(node, expression)); |
| 8785 } | 8016 } |
| 8786 | 8017 |
| 8787 void visitStringInterpolation(ast.StringInterpolation node) { | 8018 void visitStringInterpolation(ast.StringInterpolation node) { |
| 8788 node.visitChildren(this); | 8019 node.visitChildren(this); |
| 8789 } | 8020 } |
| 8790 | 8021 |
| 8791 void visitStringInterpolationPart(ast.StringInterpolationPart node) { | 8022 void visitStringInterpolationPart(ast.StringInterpolationPart node) { |
| 8792 visit(node.expression); | 8023 visit(node.expression); |
| 8793 visit(node.string); | 8024 visit(node.string); |
| 8794 } | 8025 } |
| 8795 | 8026 |
| 8796 void visitStringJuxtaposition(ast.StringJuxtaposition node) { | 8027 void visitStringJuxtaposition(ast.StringJuxtaposition node) { |
| 8797 node.visitChildren(this); | 8028 node.visitChildren(this); |
| 8798 } | 8029 } |
| 8799 | 8030 |
| 8800 void visitNodeList(ast.NodeList node) { | 8031 void visitNodeList(ast.NodeList node) { |
| 8801 node.visitChildren(this); | 8032 node.visitChildren(this); |
| 8802 } | 8033 } |
| 8803 | 8034 |
| 8804 void append(HInstruction expression) { | 8035 void append(HInstruction expression) { |
| 8805 result = (result == null) ? expression : concat(result, expression); | 8036 result = (result == null) ? expression : concat(result, expression); |
| 8806 } | 8037 } |
| 8807 | 8038 |
| 8808 HInstruction concat(HInstruction left, HInstruction right) { | 8039 HInstruction concat(HInstruction left, HInstruction right) { |
| 8809 HInstruction instruction = new HStringConcat( | 8040 HInstruction instruction = |
| 8810 left, right, builder.backend.stringType); | 8041 new HStringConcat(left, right, builder.backend.stringType); |
| 8811 builder.add(instruction); | 8042 builder.add(instruction); |
| 8812 return instruction; | 8043 return instruction; |
| 8813 } | 8044 } |
| 8814 | 8045 |
| 8815 HInstruction stringify(ast.Node node, HInstruction expression) { | 8046 HInstruction stringify(ast.Node node, HInstruction expression) { |
| 8816 HInstruction instruction = | 8047 HInstruction instruction = |
| 8817 new HStringify(expression, builder.backend.stringType); | 8048 new HStringify(expression, builder.backend.stringType); |
| 8818 builder.add(instruction); | 8049 builder.add(instruction); |
| 8819 return instruction; | 8050 return instruction; |
| 8820 } | 8051 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 8835 static const INLINING_NODES_INSIDE_LOOP_ARG_FACTOR = 4; | 8066 static const INLINING_NODES_INSIDE_LOOP_ARG_FACTOR = 4; |
| 8836 | 8067 |
| 8837 bool seenReturn = false; | 8068 bool seenReturn = false; |
| 8838 bool tooDifficult = false; | 8069 bool tooDifficult = false; |
| 8839 int nodeCount = 0; | 8070 int nodeCount = 0; |
| 8840 final int maxInliningNodes; | 8071 final int maxInliningNodes; |
| 8841 final bool useMaxInliningNodes; | 8072 final bool useMaxInliningNodes; |
| 8842 final bool allowLoops; | 8073 final bool allowLoops; |
| 8843 final bool enableUserAssertions; | 8074 final bool enableUserAssertions; |
| 8844 | 8075 |
| 8845 InlineWeeder(this.maxInliningNodes, | 8076 InlineWeeder(this.maxInliningNodes, this.useMaxInliningNodes, this.allowLoops, |
| 8846 this.useMaxInliningNodes, | 8077 this.enableUserAssertions); |
| 8847 this.allowLoops, | |
| 8848 this.enableUserAssertions); | |
| 8849 | 8078 |
| 8850 static bool canBeInlined(FunctionElement function, | 8079 static bool canBeInlined( |
| 8851 int maxInliningNodes, | 8080 FunctionElement function, int maxInliningNodes, bool useMaxInliningNodes, |
| 8852 bool useMaxInliningNodes, | 8081 {bool allowLoops: false, bool enableUserAssertions: null}) { |
| 8853 {bool allowLoops: false, | |
| 8854 bool enableUserAssertions: null}) { | |
| 8855 assert(enableUserAssertions is bool); // Ensure we passed it. | 8082 assert(enableUserAssertions is bool); // Ensure we passed it. |
| 8856 if (function.resolvedAst.elements.containsTryStatement) return false; | 8083 if (function.resolvedAst.elements.containsTryStatement) return false; |
| 8857 | 8084 |
| 8858 InlineWeeder weeder = | 8085 InlineWeeder weeder = new InlineWeeder(maxInliningNodes, |
| 8859 new InlineWeeder(maxInliningNodes, useMaxInliningNodes, allowLoops, | 8086 useMaxInliningNodes, allowLoops, enableUserAssertions); |
| 8860 enableUserAssertions); | |
| 8861 ast.FunctionExpression functionExpression = function.node; | 8087 ast.FunctionExpression functionExpression = function.node; |
| 8862 weeder.visit(functionExpression.initializers); | 8088 weeder.visit(functionExpression.initializers); |
| 8863 weeder.visit(functionExpression.body); | 8089 weeder.visit(functionExpression.body); |
| 8864 weeder.visit(functionExpression.asyncModifier); | 8090 weeder.visit(functionExpression.asyncModifier); |
| 8865 return !weeder.tooDifficult; | 8091 return !weeder.tooDifficult; |
| 8866 } | 8092 } |
| 8867 | 8093 |
| 8868 bool registerNode() { | 8094 bool registerNode() { |
| 8869 if (!useMaxInliningNodes) return true; | 8095 if (!useMaxInliningNodes) return true; |
| 8870 if (nodeCount++ > maxInliningNodes) { | 8096 if (nodeCount++ > maxInliningNodes) { |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8929 tooDifficult = true; | 8155 tooDifficult = true; |
| 8930 } | 8156 } |
| 8931 | 8157 |
| 8932 void visitRethrow(ast.Rethrow node) { | 8158 void visitRethrow(ast.Rethrow node) { |
| 8933 if (!registerNode()) return; | 8159 if (!registerNode()) return; |
| 8934 tooDifficult = true; | 8160 tooDifficult = true; |
| 8935 } | 8161 } |
| 8936 | 8162 |
| 8937 void visitReturn(ast.Return node) { | 8163 void visitReturn(ast.Return node) { |
| 8938 if (!registerNode()) return; | 8164 if (!registerNode()) return; |
| 8939 if (seenReturn | 8165 if (seenReturn || identical(node.beginToken.stringValue, 'native')) { |
| 8940 || identical(node.beginToken.stringValue, 'native')) { | |
| 8941 tooDifficult = true; | 8166 tooDifficult = true; |
| 8942 return; | 8167 return; |
| 8943 } | 8168 } |
| 8944 node.visitChildren(this); | 8169 node.visitChildren(this); |
| 8945 seenReturn = true; | 8170 seenReturn = true; |
| 8946 } | 8171 } |
| 8947 | 8172 |
| 8948 void visitThrow(ast.Throw node) { | 8173 void visitThrow(ast.Throw node) { |
| 8949 if (!registerNode()) return; | 8174 if (!registerNode()) return; |
| 8950 // For now, we don't want to handle throw after a return even if | 8175 // For now, we don't want to handle throw after a return even if |
| (...skipping 19 matching lines...) Expand all Loading... |
| 8970 | 8195 |
| 8971 class AstInliningState extends InliningState { | 8196 class AstInliningState extends InliningState { |
| 8972 final Local oldReturnLocal; | 8197 final Local oldReturnLocal; |
| 8973 final DartType oldReturnType; | 8198 final DartType oldReturnType; |
| 8974 final TreeElements oldElements; | 8199 final TreeElements oldElements; |
| 8975 final List<HInstruction> oldStack; | 8200 final List<HInstruction> oldStack; |
| 8976 final LocalsHandler oldLocalsHandler; | 8201 final LocalsHandler oldLocalsHandler; |
| 8977 final bool inTryStatement; | 8202 final bool inTryStatement; |
| 8978 final bool allFunctionsCalledOnce; | 8203 final bool allFunctionsCalledOnce; |
| 8979 | 8204 |
| 8980 AstInliningState(FunctionElement function, | 8205 AstInliningState( |
| 8981 this.oldReturnLocal, | 8206 FunctionElement function, |
| 8982 this.oldReturnType, | 8207 this.oldReturnLocal, |
| 8983 this.oldElements, | 8208 this.oldReturnType, |
| 8984 this.oldStack, | 8209 this.oldElements, |
| 8985 this.oldLocalsHandler, | 8210 this.oldStack, |
| 8986 this.inTryStatement, | 8211 this.oldLocalsHandler, |
| 8987 this.allFunctionsCalledOnce) | 8212 this.inTryStatement, |
| 8213 this.allFunctionsCalledOnce) |
| 8988 : super(function); | 8214 : super(function); |
| 8989 } | 8215 } |
| 8990 | 8216 |
| 8991 class SsaBranch { | 8217 class SsaBranch { |
| 8992 final SsaBranchBuilder branchBuilder; | 8218 final SsaBranchBuilder branchBuilder; |
| 8993 final HBasicBlock block; | 8219 final HBasicBlock block; |
| 8994 LocalsHandler startLocals; | 8220 LocalsHandler startLocals; |
| 8995 LocalsHandler exitLocals; | 8221 LocalsHandler exitLocals; |
| 8996 SubGraph graph; | 8222 SubGraph graph; |
| 8997 | 8223 |
| 8998 SsaBranch(this.branchBuilder) : block = new HBasicBlock(); | 8224 SsaBranch(this.branchBuilder) : block = new HBasicBlock(); |
| 8999 } | 8225 } |
| 9000 | 8226 |
| 9001 class SsaBranchBuilder { | 8227 class SsaBranchBuilder { |
| 9002 final SsaBuilder builder; | 8228 final SsaBuilder builder; |
| 9003 final ast.Node diagnosticNode; | 8229 final ast.Node diagnosticNode; |
| 9004 | 8230 |
| 9005 SsaBranchBuilder(this.builder, [this.diagnosticNode]); | 8231 SsaBranchBuilder(this.builder, [this.diagnosticNode]); |
| 9006 | 8232 |
| 9007 Compiler get compiler => builder.compiler; | 8233 Compiler get compiler => builder.compiler; |
| 9008 | 8234 |
| 9009 void checkNotAborted() { | 8235 void checkNotAborted() { |
| 9010 if (builder.isAborted()) { | 8236 if (builder.isAborted()) { |
| 9011 compiler.unimplemented(diagnosticNode, "aborted control flow"); | 8237 compiler.unimplemented(diagnosticNode, "aborted control flow"); |
| 9012 } | 8238 } |
| 9013 } | 8239 } |
| 9014 | 8240 |
| 9015 void buildCondition(void visitCondition(), | 8241 void buildCondition( |
| 9016 SsaBranch conditionBranch, | 8242 void visitCondition(), |
| 9017 SsaBranch thenBranch, | 8243 SsaBranch conditionBranch, |
| 9018 SsaBranch elseBranch, | 8244 SsaBranch thenBranch, |
| 9019 SourceInformation sourceInformation) { | 8245 SsaBranch elseBranch, |
| 8246 SourceInformation sourceInformation) { |
| 9020 startBranch(conditionBranch); | 8247 startBranch(conditionBranch); |
| 9021 visitCondition(); | 8248 visitCondition(); |
| 9022 checkNotAborted(); | 8249 checkNotAborted(); |
| 9023 assert(identical(builder.current, builder.lastOpenedBlock)); | 8250 assert(identical(builder.current, builder.lastOpenedBlock)); |
| 9024 HInstruction conditionValue = builder.popBoolified(); | 8251 HInstruction conditionValue = builder.popBoolified(); |
| 9025 HIf branch = new HIf(conditionValue)..sourceInformation = sourceInformation; | 8252 HIf branch = new HIf(conditionValue)..sourceInformation = sourceInformation; |
| 9026 HBasicBlock conditionExitBlock = builder.current; | 8253 HBasicBlock conditionExitBlock = builder.current; |
| 9027 builder.close(branch); | 8254 builder.close(branch); |
| 9028 conditionBranch.exitLocals = builder.localsHandler; | 8255 conditionBranch.exitLocals = builder.localsHandler; |
| 9029 conditionExitBlock.addSuccessor(thenBranch.block); | 8256 conditionExitBlock.addSuccessor(thenBranch.block); |
| 9030 conditionExitBlock.addSuccessor(elseBranch.block); | 8257 conditionExitBlock.addSuccessor(elseBranch.block); |
| 9031 bool conditionBranchLocalsCanBeReused = | 8258 bool conditionBranchLocalsCanBeReused = |
| 9032 mergeLocals(conditionBranch, thenBranch, mayReuseFromLocals: true); | 8259 mergeLocals(conditionBranch, thenBranch, mayReuseFromLocals: true); |
| 9033 mergeLocals(conditionBranch, elseBranch, | 8260 mergeLocals(conditionBranch, elseBranch, |
| 9034 mayReuseFromLocals: conditionBranchLocalsCanBeReused); | 8261 mayReuseFromLocals: conditionBranchLocalsCanBeReused); |
| 9035 | 8262 |
| 9036 conditionBranch.graph = | 8263 conditionBranch.graph = |
| 9037 new SubExpression(conditionBranch.block, conditionExitBlock); | 8264 new SubExpression(conditionBranch.block, conditionExitBlock); |
| 9038 } | 8265 } |
| 9039 | 8266 |
| 9040 /** | 8267 /** |
| 9041 * Returns true if the locals of the [fromBranch] may be reused. A [:true:] | 8268 * Returns true if the locals of the [fromBranch] may be reused. A [:true:] |
| 9042 * return value implies that [mayReuseFromLocals] was set to [:true:]. | 8269 * return value implies that [mayReuseFromLocals] was set to [:true:]. |
| 9043 */ | 8270 */ |
| 9044 bool mergeLocals(SsaBranch fromBranch, SsaBranch toBranch, | 8271 bool mergeLocals(SsaBranch fromBranch, SsaBranch toBranch, |
| 9045 {bool mayReuseFromLocals}) { | 8272 {bool mayReuseFromLocals}) { |
| 9046 LocalsHandler fromLocals = fromBranch.exitLocals; | 8273 LocalsHandler fromLocals = fromBranch.exitLocals; |
| 9047 if (toBranch.startLocals == null) { | 8274 if (toBranch.startLocals == null) { |
| 9048 if (mayReuseFromLocals) { | 8275 if (mayReuseFromLocals) { |
| 9049 toBranch.startLocals = fromLocals; | 8276 toBranch.startLocals = fromLocals; |
| 9050 return false; | 8277 return false; |
| 9051 } else { | 8278 } else { |
| 9052 toBranch.startLocals = new LocalsHandler.from(fromLocals); | 8279 toBranch.startLocals = new LocalsHandler.from(fromLocals); |
| 9053 return true; | 8280 return true; |
| 9054 } | 8281 } |
| 9055 } else { | 8282 } else { |
| 9056 toBranch.startLocals.mergeWith(fromLocals, toBranch.block); | 8283 toBranch.startLocals.mergeWith(fromLocals, toBranch.block); |
| 9057 return true; | 8284 return true; |
| 9058 } | 8285 } |
| 9059 } | 8286 } |
| 9060 | 8287 |
| 9061 void startBranch(SsaBranch branch) { | 8288 void startBranch(SsaBranch branch) { |
| 9062 builder.graph.addBlock(branch.block); | 8289 builder.graph.addBlock(branch.block); |
| 9063 builder.localsHandler = branch.startLocals; | 8290 builder.localsHandler = branch.startLocals; |
| 9064 builder.open(branch.block); | 8291 builder.open(branch.block); |
| 9065 } | 8292 } |
| 9066 | 8293 |
| 9067 HInstruction buildBranch(SsaBranch branch, | 8294 HInstruction buildBranch(SsaBranch branch, void visitBranch(), |
| 9068 void visitBranch(), | 8295 SsaBranch joinBranch, bool isExpression) { |
| 9069 SsaBranch joinBranch, | |
| 9070 bool isExpression) { | |
| 9071 startBranch(branch); | 8296 startBranch(branch); |
| 9072 visitBranch(); | 8297 visitBranch(); |
| 9073 branch.graph = new SubGraph(branch.block, builder.lastOpenedBlock); | 8298 branch.graph = new SubGraph(branch.block, builder.lastOpenedBlock); |
| 9074 branch.exitLocals = builder.localsHandler; | 8299 branch.exitLocals = builder.localsHandler; |
| 9075 if (!builder.isAborted()) { | 8300 if (!builder.isAborted()) { |
| 9076 builder.goto(builder.current, joinBranch.block); | 8301 builder.goto(builder.current, joinBranch.block); |
| 9077 mergeLocals(branch, joinBranch, mayReuseFromLocals: true); | 8302 mergeLocals(branch, joinBranch, mayReuseFromLocals: true); |
| 9078 } | 8303 } |
| 9079 if (isExpression) { | 8304 if (isExpression) { |
| 9080 checkNotAborted(); | 8305 checkNotAborted(); |
| 9081 return builder.pop(); | 8306 return builder.pop(); |
| 9082 } | 8307 } |
| 9083 return null; | 8308 return null; |
| 9084 } | 8309 } |
| 9085 | 8310 |
| 9086 handleIf(void visitCondition(), | 8311 handleIf(void visitCondition(), void visitThen(), void visitElse(), |
| 9087 void visitThen(), | 8312 {SourceInformation sourceInformation}) { |
| 9088 void visitElse(), | |
| 9089 {SourceInformation sourceInformation}) { | |
| 9090 if (visitElse == null) { | 8313 if (visitElse == null) { |
| 9091 // Make sure to have an else part to avoid a critical edge. A | 8314 // Make sure to have an else part to avoid a critical edge. A |
| 9092 // critical edge is an edge that connects a block with multiple | 8315 // critical edge is an edge that connects a block with multiple |
| 9093 // successors to a block with multiple predecessors. We avoid | 8316 // successors to a block with multiple predecessors. We avoid |
| 9094 // such edges because they prevent inserting copies during code | 8317 // such edges because they prevent inserting copies during code |
| 9095 // generation of phi instructions. | 8318 // generation of phi instructions. |
| 9096 visitElse = () {}; | 8319 visitElse = () {}; |
| 9097 } | 8320 } |
| 9098 | 8321 |
| 9099 _handleDiamondBranch( | 8322 _handleDiamondBranch(visitCondition, visitThen, visitElse, |
| 9100 visitCondition, visitThen, visitElse, isExpression: false, | 8323 isExpression: false, sourceInformation: sourceInformation); |
| 9101 sourceInformation: sourceInformation); | |
| 9102 } | 8324 } |
| 9103 | 8325 |
| 9104 handleConditional(void visitCondition(), | 8326 handleConditional(void visitCondition(), void visitThen(), void visitElse()) { |
| 9105 void visitThen(), | |
| 9106 void visitElse()) { | |
| 9107 assert(visitElse != null); | 8327 assert(visitElse != null); |
| 9108 _handleDiamondBranch( | 8328 _handleDiamondBranch(visitCondition, visitThen, visitElse, |
| 9109 visitCondition, visitThen, visitElse, isExpression: true); | 8329 isExpression: true); |
| 9110 } | 8330 } |
| 9111 | 8331 |
| 9112 handleIfNull(void left(), void right()) { | 8332 handleIfNull(void left(), void right()) { |
| 9113 // x ?? y is transformed into: x == null ? y : x | 8333 // x ?? y is transformed into: x == null ? y : x |
| 9114 HInstruction leftExpression; | 8334 HInstruction leftExpression; |
| 9115 handleConditional( | 8335 handleConditional(() { |
| 9116 () { | 8336 left(); |
| 9117 left(); | 8337 leftExpression = builder.pop(); |
| 9118 leftExpression = builder.pop(); | 8338 builder.pushCheckNull(leftExpression); |
| 9119 builder.pushCheckNull(leftExpression); | 8339 }, right, () => builder.stack.add(leftExpression)); |
| 9120 }, | |
| 9121 right, | |
| 9122 () => builder.stack.add(leftExpression)); | |
| 9123 } | 8340 } |
| 9124 | 8341 |
| 9125 void handleLogicalAndOr(void left(), void right(), {bool isAnd}) { | 8342 void handleLogicalAndOr(void left(), void right(), {bool isAnd}) { |
| 9126 // x && y is transformed into: | 8343 // x && y is transformed into: |
| 9127 // t0 = boolify(x); | 8344 // t0 = boolify(x); |
| 9128 // if (t0) { | 8345 // if (t0) { |
| 9129 // t1 = boolify(y); | 8346 // t1 = boolify(y); |
| 9130 // } | 8347 // } |
| 9131 // result = phi(t1, false); | 8348 // result = phi(t1, false); |
| 9132 // | 8349 // |
| (...skipping 17 matching lines...) Expand all Loading... |
| 9150 | 8367 |
| 9151 void visitThen() { | 8368 void visitThen() { |
| 9152 right(); | 8369 right(); |
| 9153 boolifiedRight = builder.popBoolified(); | 8370 boolifiedRight = builder.popBoolified(); |
| 9154 } | 8371 } |
| 9155 | 8372 |
| 9156 handleIf(visitCondition, visitThen, null); | 8373 handleIf(visitCondition, visitThen, null); |
| 9157 HConstant notIsAnd = | 8374 HConstant notIsAnd = |
| 9158 builder.graph.addConstantBool(!isAnd, builder.compiler); | 8375 builder.graph.addConstantBool(!isAnd, builder.compiler); |
| 9159 JavaScriptBackend backend = builder.backend; | 8376 JavaScriptBackend backend = builder.backend; |
| 9160 HPhi result = new HPhi.manyInputs(null, | 8377 HPhi result = new HPhi.manyInputs( |
| 9161 <HInstruction>[boolifiedRight, notIsAnd], | 8378 null, <HInstruction>[boolifiedRight, notIsAnd], backend.dynamicType); |
| 9162 backend.dynamicType); | |
| 9163 builder.current.addPhi(result); | 8379 builder.current.addPhi(result); |
| 9164 builder.stack.add(result); | 8380 builder.stack.add(result); |
| 9165 } | 8381 } |
| 9166 | 8382 |
| 9167 void handleLogicalAndOrWithLeftNode(ast.Node left, | 8383 void handleLogicalAndOrWithLeftNode(ast.Node left, void visitRight(), |
| 9168 void visitRight(), | 8384 {bool isAnd}) { |
| 9169 {bool isAnd}) { | |
| 9170 // This method is similar to [handleLogicalAndOr] but optimizes the case | 8385 // This method is similar to [handleLogicalAndOr] but optimizes the case |
| 9171 // where left is a logical "and" or logical "or". | 8386 // where left is a logical "and" or logical "or". |
| 9172 // | 8387 // |
| 9173 // For example (x && y) && z is transformed into x && (y && z): | 8388 // For example (x && y) && z is transformed into x && (y && z): |
| 9174 // t0 = boolify(x); | 8389 // t0 = boolify(x); |
| 9175 // if (t0) { | 8390 // if (t0) { |
| 9176 // t1 = boolify(y); | 8391 // t1 = boolify(y); |
| 9177 // if (t1) { | 8392 // if (t1) { |
| 9178 // t2 = boolify(z); | 8393 // t2 = boolify(z); |
| 9179 // } | 8394 // } |
| 9180 // t3 = phi(t2, false); | 8395 // t3 = phi(t2, false); |
| 9181 // } | 8396 // } |
| 9182 // result = phi(t3, false); | 8397 // result = phi(t3, false); |
| 9183 | 8398 |
| 9184 ast.Send send = left.asSend(); | 8399 ast.Send send = left.asSend(); |
| 9185 if (send != null && | 8400 if (send != null && (isAnd ? send.isLogicalAnd : send.isLogicalOr)) { |
| 9186 (isAnd ? send.isLogicalAnd : send.isLogicalOr)) { | |
| 9187 ast.Node newLeft = send.receiver; | 8401 ast.Node newLeft = send.receiver; |
| 9188 Link<ast.Node> link = send.argumentsNode.nodes; | 8402 Link<ast.Node> link = send.argumentsNode.nodes; |
| 9189 assert(link.tail.isEmpty); | 8403 assert(link.tail.isEmpty); |
| 9190 ast.Node middle = link.head; | 8404 ast.Node middle = link.head; |
| 9191 handleLogicalAndOrWithLeftNode( | 8405 handleLogicalAndOrWithLeftNode( |
| 9192 newLeft, | 8406 newLeft, |
| 9193 () => handleLogicalAndOrWithLeftNode(middle, visitRight, | 8407 () => |
| 9194 isAnd: isAnd), | 8408 handleLogicalAndOrWithLeftNode(middle, visitRight, isAnd: isAnd), |
| 9195 isAnd: isAnd); | 8409 isAnd: isAnd); |
| 9196 } else { | 8410 } else { |
| 9197 handleLogicalAndOr(() => builder.visit(left), visitRight, isAnd: isAnd); | 8411 handleLogicalAndOr(() => builder.visit(left), visitRight, isAnd: isAnd); |
| 9198 } | 8412 } |
| 9199 } | 8413 } |
| 9200 | 8414 |
| 9201 void _handleDiamondBranch(void visitCondition(), | 8415 void _handleDiamondBranch( |
| 9202 void visitThen(), | 8416 void visitCondition(), void visitThen(), void visitElse(), |
| 9203 void visitElse(), | 8417 {bool isExpression, SourceInformation sourceInformation}) { |
| 9204 {bool isExpression, | |
| 9205 SourceInformation sourceInformation}) { | |
| 9206 SsaBranch conditionBranch = new SsaBranch(this); | 8418 SsaBranch conditionBranch = new SsaBranch(this); |
| 9207 SsaBranch thenBranch = new SsaBranch(this); | 8419 SsaBranch thenBranch = new SsaBranch(this); |
| 9208 SsaBranch elseBranch = new SsaBranch(this); | 8420 SsaBranch elseBranch = new SsaBranch(this); |
| 9209 SsaBranch joinBranch = new SsaBranch(this); | 8421 SsaBranch joinBranch = new SsaBranch(this); |
| 9210 | 8422 |
| 9211 conditionBranch.startLocals = builder.localsHandler; | 8423 conditionBranch.startLocals = builder.localsHandler; |
| 9212 builder.goto(builder.current, conditionBranch.block); | 8424 builder.goto(builder.current, conditionBranch.block); |
| 9213 | 8425 |
| 9214 buildCondition(visitCondition, conditionBranch, thenBranch, elseBranch, | 8426 buildCondition(visitCondition, conditionBranch, thenBranch, elseBranch, |
| 9215 sourceInformation); | 8427 sourceInformation); |
| 9216 HInstruction thenValue = | 8428 HInstruction thenValue = |
| 9217 buildBranch(thenBranch, visitThen, joinBranch, isExpression); | 8429 buildBranch(thenBranch, visitThen, joinBranch, isExpression); |
| 9218 HInstruction elseValue = | 8430 HInstruction elseValue = |
| 9219 buildBranch(elseBranch, visitElse, joinBranch, isExpression); | 8431 buildBranch(elseBranch, visitElse, joinBranch, isExpression); |
| 9220 | 8432 |
| 9221 if (isExpression) { | 8433 if (isExpression) { |
| 9222 assert(thenValue != null && elseValue != null); | 8434 assert(thenValue != null && elseValue != null); |
| 9223 JavaScriptBackend backend = builder.backend; | 8435 JavaScriptBackend backend = builder.backend; |
| 9224 HPhi phi = new HPhi.manyInputs( | 8436 HPhi phi = new HPhi.manyInputs( |
| 9225 null, <HInstruction>[thenValue, elseValue], backend.dynamicType); | 8437 null, <HInstruction>[thenValue, elseValue], backend.dynamicType); |
| 9226 joinBranch.block.addPhi(phi); | 8438 joinBranch.block.addPhi(phi); |
| 9227 builder.stack.add(phi); | 8439 builder.stack.add(phi); |
| 9228 } | 8440 } |
| 9229 | 8441 |
| 9230 HBasicBlock joinBlock; | 8442 HBasicBlock joinBlock; |
| 9231 // If at least one branch did not abort, open the joinBranch. | 8443 // If at least one branch did not abort, open the joinBranch. |
| 9232 if (!joinBranch.block.predecessors.isEmpty) { | 8444 if (!joinBranch.block.predecessors.isEmpty) { |
| 9233 startBranch(joinBranch); | 8445 startBranch(joinBranch); |
| 9234 joinBlock = joinBranch.block; | 8446 joinBlock = joinBranch.block; |
| 9235 } | 8447 } |
| 9236 | 8448 |
| 9237 HIfBlockInformation info = | 8449 HIfBlockInformation info = new HIfBlockInformation( |
| 9238 new HIfBlockInformation( | 8450 new HSubExpressionBlockInformation(conditionBranch.graph), |
| 9239 new HSubExpressionBlockInformation(conditionBranch.graph), | 8451 new HSubGraphBlockInformation(thenBranch.graph), |
| 9240 new HSubGraphBlockInformation(thenBranch.graph), | 8452 new HSubGraphBlockInformation(elseBranch.graph)); |
| 9241 new HSubGraphBlockInformation(elseBranch.graph)); | |
| 9242 | 8453 |
| 9243 HBasicBlock conditionStartBlock = conditionBranch.block; | 8454 HBasicBlock conditionStartBlock = conditionBranch.block; |
| 9244 conditionStartBlock.setBlockFlow(info, joinBlock); | 8455 conditionStartBlock.setBlockFlow(info, joinBlock); |
| 9245 SubGraph conditionGraph = conditionBranch.graph; | 8456 SubGraph conditionGraph = conditionBranch.graph; |
| 9246 HIf branch = conditionGraph.end.last; | 8457 HIf branch = conditionGraph.end.last; |
| 9247 assert(branch is HIf); | 8458 assert(branch is HIf); |
| 9248 branch.blockInformation = conditionStartBlock.blockFlow; | 8459 branch.blockInformation = conditionStartBlock.blockFlow; |
| 9249 } | 8460 } |
| 9250 } | 8461 } |
| 9251 | 8462 |
| 9252 class TypeBuilder implements DartTypeVisitor<dynamic, SsaBuilder> { | 8463 class TypeBuilder implements DartTypeVisitor<dynamic, SsaBuilder> { |
| 9253 final ClassWorld classWorld; | 8464 final ClassWorld classWorld; |
| 9254 | 8465 |
| 9255 TypeBuilder(this.classWorld); | 8466 TypeBuilder(this.classWorld); |
| 9256 | 8467 |
| 9257 void visit(DartType type, SsaBuilder builder) => type.accept(this, builder); | 8468 void visit(DartType type, SsaBuilder builder) => type.accept(this, builder); |
| 9258 | 8469 |
| 9259 void visitVoidType(VoidType type, SsaBuilder builder) { | 8470 void visitVoidType(VoidType type, SsaBuilder builder) { |
| 9260 ClassElement cls = builder.backend.helpers.VoidRuntimeType; | 8471 ClassElement cls = builder.backend.helpers.VoidRuntimeType; |
| 9261 builder.push(new HVoidType(type, new TypeMask.exact(cls, classWorld))); | 8472 builder.push(new HVoidType(type, new TypeMask.exact(cls, classWorld))); |
| 9262 } | 8473 } |
| 9263 | 8474 |
| 9264 void visitTypeVariableType(TypeVariableType type, | 8475 void visitTypeVariableType(TypeVariableType type, SsaBuilder builder) { |
| 9265 SsaBuilder builder) { | |
| 9266 ClassElement cls = builder.backend.helpers.RuntimeType; | 8476 ClassElement cls = builder.backend.helpers.RuntimeType; |
| 9267 TypeMask instructionType = new TypeMask.subclass(cls, classWorld); | 8477 TypeMask instructionType = new TypeMask.subclass(cls, classWorld); |
| 9268 if (!builder.sourceElement.enclosingElement.isClosure && | 8478 if (!builder.sourceElement.enclosingElement.isClosure && |
| 9269 builder.sourceElement.isInstanceMember) { | 8479 builder.sourceElement.isInstanceMember) { |
| 9270 HInstruction receiver = builder.localsHandler.readThis(); | 8480 HInstruction receiver = builder.localsHandler.readThis(); |
| 9271 builder.push(new HReadTypeVariable(type, receiver, instructionType)); | 8481 builder.push(new HReadTypeVariable(type, receiver, instructionType)); |
| 9272 } else { | 8482 } else { |
| 9273 builder.push( | 8483 builder.push(new HReadTypeVariable.noReceiver( |
| 9274 new HReadTypeVariable.noReceiver( | 8484 type, builder.addTypeVariableReference(type), instructionType)); |
| 9275 type, builder.addTypeVariableReference(type), instructionType)); | |
| 9276 } | 8485 } |
| 9277 } | 8486 } |
| 9278 | 8487 |
| 9279 void visitFunctionType(FunctionType type, SsaBuilder builder) { | 8488 void visitFunctionType(FunctionType type, SsaBuilder builder) { |
| 9280 type.returnType.accept(this, builder); | 8489 type.returnType.accept(this, builder); |
| 9281 HInstruction returnType = builder.pop(); | 8490 HInstruction returnType = builder.pop(); |
| 9282 List<HInstruction> inputs = <HInstruction>[returnType]; | 8491 List<HInstruction> inputs = <HInstruction>[returnType]; |
| 9283 | 8492 |
| 9284 for (DartType parameter in type.parameterTypes) { | 8493 for (DartType parameter in type.parameterTypes) { |
| 9285 parameter.accept(this, builder); | 8494 parameter.accept(this, builder); |
| 9286 inputs.add(builder.pop()); | 8495 inputs.add(builder.pop()); |
| 9287 } | 8496 } |
| 9288 | 8497 |
| 9289 for (DartType parameter in type.optionalParameterTypes) { | 8498 for (DartType parameter in type.optionalParameterTypes) { |
| 9290 parameter.accept(this, builder); | 8499 parameter.accept(this, builder); |
| 9291 inputs.add(builder.pop()); | 8500 inputs.add(builder.pop()); |
| 9292 } | 8501 } |
| 9293 | 8502 |
| 9294 List<DartType> namedParameterTypes = type.namedParameterTypes; | 8503 List<DartType> namedParameterTypes = type.namedParameterTypes; |
| 9295 List<String> names = type.namedParameters; | 8504 List<String> names = type.namedParameters; |
| 9296 for (int index = 0; index < names.length; index++) { | 8505 for (int index = 0; index < names.length; index++) { |
| 9297 ast.DartString dartString = new ast.DartString.literal(names[index]); | 8506 ast.DartString dartString = new ast.DartString.literal(names[index]); |
| 9298 inputs.add( | 8507 inputs.add(builder.graph.addConstantString(dartString, builder.compiler)); |
| 9299 builder.graph.addConstantString(dartString, builder.compiler)); | |
| 9300 namedParameterTypes[index].accept(this, builder); | 8508 namedParameterTypes[index].accept(this, builder); |
| 9301 inputs.add(builder.pop()); | 8509 inputs.add(builder.pop()); |
| 9302 } | 8510 } |
| 9303 | 8511 |
| 9304 ClassElement cls = builder.backend.helpers.RuntimeFunctionType; | 8512 ClassElement cls = builder.backend.helpers.RuntimeFunctionType; |
| 9305 builder.push(new HFunctionType(inputs, type, | 8513 builder.push( |
| 9306 new TypeMask.exact(cls, classWorld))); | 8514 new HFunctionType(inputs, type, new TypeMask.exact(cls, classWorld))); |
| 9307 } | 8515 } |
| 9308 | 8516 |
| 9309 void visitMalformedType(MalformedType type, SsaBuilder builder) { | 8517 void visitMalformedType(MalformedType type, SsaBuilder builder) { |
| 9310 visitDynamicType(const DynamicType(), builder); | 8518 visitDynamicType(const DynamicType(), builder); |
| 9311 } | 8519 } |
| 9312 | 8520 |
| 9313 void visitStatementType(StatementType type, SsaBuilder builder) { | 8521 void visitStatementType(StatementType type, SsaBuilder builder) { |
| 9314 throw 'not implemented visitStatementType($type)'; | 8522 throw 'not implemented visitStatementType($type)'; |
| 9315 } | 8523 } |
| 9316 | 8524 |
| 9317 void visitInterfaceType(InterfaceType type, SsaBuilder builder) { | 8525 void visitInterfaceType(InterfaceType type, SsaBuilder builder) { |
| 9318 List<HInstruction> inputs = <HInstruction>[]; | 8526 List<HInstruction> inputs = <HInstruction>[]; |
| 9319 for (DartType typeArgument in type.typeArguments) { | 8527 for (DartType typeArgument in type.typeArguments) { |
| 9320 typeArgument.accept(this, builder); | 8528 typeArgument.accept(this, builder); |
| 9321 inputs.add(builder.pop()); | 8529 inputs.add(builder.pop()); |
| 9322 } | 8530 } |
| 9323 ClassElement cls; | 8531 ClassElement cls; |
| 9324 if (type.typeArguments.isEmpty) { | 8532 if (type.typeArguments.isEmpty) { |
| 9325 cls = builder.backend.helpers.RuntimeTypePlain; | 8533 cls = builder.backend.helpers.RuntimeTypePlain; |
| 9326 } else { | 8534 } else { |
| 9327 cls = builder.backend.helpers.RuntimeTypeGeneric; | 8535 cls = builder.backend.helpers.RuntimeTypeGeneric; |
| 9328 } | 8536 } |
| 9329 builder.push(new HInterfaceType(inputs, type, | 8537 builder.push( |
| 9330 new TypeMask.exact(cls, classWorld))); | 8538 new HInterfaceType(inputs, type, new TypeMask.exact(cls, classWorld))); |
| 9331 } | 8539 } |
| 9332 | 8540 |
| 9333 void visitTypedefType(TypedefType type, SsaBuilder builder) { | 8541 void visitTypedefType(TypedefType type, SsaBuilder builder) { |
| 9334 DartType unaliased = type.unaliased; | 8542 DartType unaliased = type.unaliased; |
| 9335 if (unaliased is TypedefType) throw 'unable to unalias $type'; | 8543 if (unaliased is TypedefType) throw 'unable to unalias $type'; |
| 9336 unaliased.accept(this, builder); | 8544 unaliased.accept(this, builder); |
| 9337 } | 8545 } |
| 9338 | 8546 |
| 9339 void visitDynamicType(DynamicType type, SsaBuilder builder) { | 8547 void visitDynamicType(DynamicType type, SsaBuilder builder) { |
| 9340 JavaScriptBackend backend = builder.compiler.backend; | 8548 JavaScriptBackend backend = builder.compiler.backend; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 9351 const _LoopTypeVisitor(); | 8559 const _LoopTypeVisitor(); |
| 9352 int visitNode(ast.Node node) => HLoopBlockInformation.NOT_A_LOOP; | 8560 int visitNode(ast.Node node) => HLoopBlockInformation.NOT_A_LOOP; |
| 9353 int visitWhile(ast.While node) => HLoopBlockInformation.WHILE_LOOP; | 8561 int visitWhile(ast.While node) => HLoopBlockInformation.WHILE_LOOP; |
| 9354 int visitFor(ast.For node) => HLoopBlockInformation.FOR_LOOP; | 8562 int visitFor(ast.For node) => HLoopBlockInformation.FOR_LOOP; |
| 9355 int visitDoWhile(ast.DoWhile node) => HLoopBlockInformation.DO_WHILE_LOOP; | 8563 int visitDoWhile(ast.DoWhile node) => HLoopBlockInformation.DO_WHILE_LOOP; |
| 9356 int visitAsyncForIn(ast.AsyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; | 8564 int visitAsyncForIn(ast.AsyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; |
| 9357 int visitSyncForIn(ast.SyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; | 8565 int visitSyncForIn(ast.SyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; |
| 9358 int visitSwitchStatement(ast.SwitchStatement node) => | 8566 int visitSwitchStatement(ast.SwitchStatement node) => |
| 9359 HLoopBlockInformation.SWITCH_CONTINUE_LOOP; | 8567 HLoopBlockInformation.SWITCH_CONTINUE_LOOP; |
| 9360 } | 8568 } |
| OLD | NEW |