| 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 part of js_backend; | 5 part of js_backend; |
| 6 | 6 |
| 7 typedef void Recompile(Element element); | |
| 8 | |
| 9 class ReturnInfo { | |
| 10 HType returnType; | |
| 11 List<Element> compiledFunctions; | |
| 12 | |
| 13 ReturnInfo(HType this.returnType) | |
| 14 : compiledFunctions = new List<Element>(); | |
| 15 | |
| 16 ReturnInfo.unknownType() : this(null); | |
| 17 | |
| 18 void update(HType type, Recompile recompile, Compiler compiler) { | |
| 19 HType newType = | |
| 20 returnType != null ? returnType.union(type, compiler) : type; | |
| 21 if (newType != returnType) { | |
| 22 if (returnType == null && identical(newType, HType.UNKNOWN)) { | |
| 23 // If the first actual piece of information is not providing any type | |
| 24 // information there is no need to recompile callers. | |
| 25 compiledFunctions.clear(); | |
| 26 } | |
| 27 returnType = newType; | |
| 28 if (recompile != null) { | |
| 29 compiledFunctions.forEach(recompile); | |
| 30 } | |
| 31 compiledFunctions.clear(); | |
| 32 } | |
| 33 } | |
| 34 | |
| 35 // Note that lazy initializers are treated like functions (but are not | |
| 36 // of type [FunctionElement]. | |
| 37 addCompiledFunction(Element function) => compiledFunctions.add(function); | |
| 38 } | |
| 39 | |
| 40 class OptionalParameterTypes { | |
| 41 final List<SourceString> names; | |
| 42 final List<HType> types; | |
| 43 | |
| 44 OptionalParameterTypes(int optionalArgumentsCount) | |
| 45 : names = new List<SourceString>(optionalArgumentsCount), | |
| 46 types = new List<HType>(optionalArgumentsCount); | |
| 47 | |
| 48 int get length => names.length; | |
| 49 SourceString name(int index) => names[index]; | |
| 50 HType type(int index) => types[index]; | |
| 51 int indexOf(SourceString name) => names.indexOf(name); | |
| 52 | |
| 53 HType typeFor(SourceString name) { | |
| 54 int index = indexOf(name); | |
| 55 if (index == -1) return null; | |
| 56 return type(index); | |
| 57 } | |
| 58 | |
| 59 void update(int index, SourceString name, HType type) { | |
| 60 names[index] = name; | |
| 61 types[index] = type; | |
| 62 } | |
| 63 | |
| 64 String toString() => "OptionalParameterTypes($names, $types)"; | |
| 65 } | |
| 66 | |
| 67 class HTypeList { | |
| 68 final List<HType> types; | |
| 69 final List<SourceString> namedArguments; | |
| 70 | |
| 71 HTypeList(int length) | |
| 72 : types = new List<HType>(length), | |
| 73 namedArguments = null; | |
| 74 HTypeList.withNamedArguments(int length, this.namedArguments) | |
| 75 : types = new List<HType>(length); | |
| 76 const HTypeList.withAllUnknown() | |
| 77 : types = null, | |
| 78 namedArguments = null; | |
| 79 | |
| 80 factory HTypeList.fromStaticInvocation(HInvokeStatic node) { | |
| 81 bool allUnknown = true; | |
| 82 for (int i = 0; i < node.inputs.length; i++) { | |
| 83 if (node.inputs[i].instructionType != HType.UNKNOWN) { | |
| 84 allUnknown = false; | |
| 85 break; | |
| 86 } | |
| 87 } | |
| 88 if (allUnknown) return HTypeList.ALL_UNKNOWN; | |
| 89 | |
| 90 HTypeList result = new HTypeList(node.inputs.length); | |
| 91 for (int i = 0; i < result.types.length; i++) { | |
| 92 result.types[i] = node.inputs[i].instructionType; | |
| 93 } | |
| 94 return result; | |
| 95 } | |
| 96 | |
| 97 factory HTypeList.fromDynamicInvocation(HInvoke node, | |
| 98 Selector selector) { | |
| 99 HTypeList result; | |
| 100 int argumentsCount = node.inputs.length - 1; | |
| 101 int startInvokeIndex = HInvoke.ARGUMENTS_OFFSET; | |
| 102 | |
| 103 if (node.isInterceptedCall) { | |
| 104 argumentsCount--; | |
| 105 startInvokeIndex++; | |
| 106 } | |
| 107 | |
| 108 if (selector.namedArgumentCount > 0) { | |
| 109 result = | |
| 110 new HTypeList.withNamedArguments( | |
| 111 argumentsCount, selector.namedArguments); | |
| 112 } else { | |
| 113 result = new HTypeList(argumentsCount); | |
| 114 } | |
| 115 | |
| 116 for (int i = 0; i < result.types.length; i++) { | |
| 117 result.types[i] = node.inputs[i + startInvokeIndex].instructionType; | |
| 118 } | |
| 119 return result; | |
| 120 } | |
| 121 | |
| 122 static const HTypeList ALL_UNKNOWN = const HTypeList.withAllUnknown(); | |
| 123 | |
| 124 bool get allUnknown => types == null; | |
| 125 bool get hasNamedArguments => namedArguments != null; | |
| 126 int get length => types.length; | |
| 127 HType operator[](int index) => types[index]; | |
| 128 void operator[]=(int index, HType type) { types[index] = type; } | |
| 129 | |
| 130 HTypeList union(HTypeList other, Compiler compiler) { | |
| 131 if (allUnknown) return this; | |
| 132 if (other.allUnknown) return other; | |
| 133 if (length != other.length) return HTypeList.ALL_UNKNOWN; | |
| 134 bool onlyUnknown = true; | |
| 135 HTypeList result = this; | |
| 136 for (int i = 0; i < length; i++) { | |
| 137 HType newType = this[i].union(other[i], compiler); | |
| 138 if (result == this && newType != this[i]) { | |
| 139 // Create a new argument types object with the matching types copied. | |
| 140 result = new HTypeList(length); | |
| 141 result.types.setRange(0, i, this.types); | |
| 142 } | |
| 143 if (result != this) { | |
| 144 result.types[i] = newType; | |
| 145 } | |
| 146 if (result[i] != HType.UNKNOWN) onlyUnknown = false; | |
| 147 } | |
| 148 return onlyUnknown ? HTypeList.ALL_UNKNOWN : result; | |
| 149 } | |
| 150 | |
| 151 HTypeList unionWithOptionalParameters( | |
| 152 Selector selector, | |
| 153 FunctionSignature signature, | |
| 154 OptionalParameterTypes defaultValueTypes) { | |
| 155 assert(allUnknown || selector.argumentCount == this.length); | |
| 156 // Create a new HTypeList for holding types for all parameters. | |
| 157 HTypeList result = new HTypeList(signature.parameterCount); | |
| 158 | |
| 159 // First fill in the type of the positional arguments. | |
| 160 int nextTypeIndex = -1; | |
| 161 if (allUnknown) { | |
| 162 for (int i = 0; i < selector.positionalArgumentCount; i++) { | |
| 163 result.types[i] = HType.UNKNOWN; | |
| 164 } | |
| 165 } else { | |
| 166 result.types.setRange(0, selector.positionalArgumentCount, this.types); | |
| 167 nextTypeIndex = selector.positionalArgumentCount; | |
| 168 } | |
| 169 | |
| 170 // Next fill the type of the optional arguments. | |
| 171 // As the selector can pass optional arguments positionally some of the | |
| 172 // optional arguments might already have a type set. We only need to look | |
| 173 // at the optional arguments not passed positionally. | |
| 174 // The variable 'index' is counting the signatures optional arguments, the | |
| 175 // variable 'next' is set to the next optional arguments to look at and | |
| 176 // is used to skip some optional arguments. | |
| 177 int next = selector.positionalArgumentCount; | |
| 178 int index = signature.requiredParameterCount; | |
| 179 signature.forEachOptionalParameter((Element element) { | |
| 180 // If some optional parameters were passed positionally these have | |
| 181 // already been filled. | |
| 182 if (index == next) { | |
| 183 assert(result.types[index] == null); | |
| 184 HType type = null; | |
| 185 if (hasNamedArguments && | |
| 186 selector.namedArguments.indexOf(element.name) >= 0) { | |
| 187 type = types[nextTypeIndex++]; | |
| 188 } else { | |
| 189 type = defaultValueTypes.typeFor(element.name); | |
| 190 } | |
| 191 result.types[index] = type; | |
| 192 next++; | |
| 193 } | |
| 194 index++; | |
| 195 }); | |
| 196 return result; | |
| 197 } | |
| 198 | |
| 199 String toString() => | |
| 200 allUnknown ? "HTypeList.ALL_UNKNOWN" : "HTypeList $types"; | |
| 201 } | |
| 202 | |
| 203 class FieldTypesRegistry { | |
| 204 final JavaScriptBackend backend; | |
| 205 | |
| 206 /** | |
| 207 * For each class, [constructors] holds the set of constructors. If there is | |
| 208 * more than one constructor for a class it is currently not possible to | |
| 209 * infer the field types from construction, as the information collected does | |
| 210 * not correlate the generative constructors and generative constructor | |
| 211 * body/bodies. | |
| 212 */ | |
| 213 final Map<ClassElement, Set<Element>> constructors; | |
| 214 | |
| 215 /** | |
| 216 * The collected type information is stored in three maps. One for types | |
| 217 * assigned in the initializer list(s) [fieldInitializerTypeMap], one for | |
| 218 * types assigned in the constructor(s) [fieldConstructorTypeMap], and one | |
| 219 * for types assigned in the rest of the code, where the field can be | |
| 220 * resolved [fieldTypeMap]. | |
| 221 * | |
| 222 * If a field has a type both from constructors and from the initializer | |
| 223 * list(s), then the type from the constructor(s) will owerride the one from | |
| 224 * the initializer list(s). | |
| 225 * | |
| 226 * Because the order in which generative constructors, generative constructor | |
| 227 * bodies and normal method/function bodies are compiled is undefined, and | |
| 228 * because they can all be recompiled, it is not possible to combine this | |
| 229 * information into one map at the moment. | |
| 230 */ | |
| 231 final Map<Element, HType> fieldInitializerTypeMap; | |
| 232 final Map<Element, HType> fieldConstructorTypeMap; | |
| 233 final Map<Element, HType> fieldTypeMap; | |
| 234 | |
| 235 /** | |
| 236 * The set of current names setter selectors used. If a named selector is | |
| 237 * used it is currently not possible to infer the type of the field. | |
| 238 */ | |
| 239 final Set<SourceString> setterSelectorsUsed; | |
| 240 | |
| 241 final Map<Element, Set<Element>> optimizedStaticFunctions; | |
| 242 final Map<Element, FunctionSet> optimizedFunctions; | |
| 243 | |
| 244 FieldTypesRegistry(JavaScriptBackend backend) | |
| 245 : constructors = new Map<ClassElement, Set<Element>>(), | |
| 246 fieldInitializerTypeMap = new Map<Element, HType>(), | |
| 247 fieldConstructorTypeMap = new Map<Element, HType>(), | |
| 248 fieldTypeMap = new Map<Element, HType>(), | |
| 249 setterSelectorsUsed = new Set<SourceString>(), | |
| 250 optimizedStaticFunctions = new Map<Element, Set<Element>>(), | |
| 251 optimizedFunctions = new Map<Element, FunctionSet>(), | |
| 252 this.backend = backend; | |
| 253 | |
| 254 Compiler get compiler => backend.compiler; | |
| 255 | |
| 256 void scheduleRecompilation(Element field) { | |
| 257 Set optimizedStatics = optimizedStaticFunctions[field]; | |
| 258 if (optimizedStatics != null) { | |
| 259 optimizedStatics.forEach(backend.scheduleForRecompilation); | |
| 260 optimizedStaticFunctions.remove(field); | |
| 261 } | |
| 262 FunctionSet optimized = optimizedFunctions[field]; | |
| 263 if (optimized != null) { | |
| 264 optimized.forEach(backend.scheduleForRecompilation); | |
| 265 optimizedFunctions.remove(field); | |
| 266 } | |
| 267 } | |
| 268 | |
| 269 int constructorCount(Element element) { | |
| 270 assert(element.isClass()); | |
| 271 Set<Element> ctors = constructors[element]; | |
| 272 return ctors == null ? 0 : ctors.length; | |
| 273 } | |
| 274 | |
| 275 void registerFieldType(Map<Element, HType> typeMap, | |
| 276 Element field, | |
| 277 HType type) { | |
| 278 assert(field.isField()); | |
| 279 HType before = optimisticFieldType(field); | |
| 280 | |
| 281 HType oldType = typeMap[field]; | |
| 282 HType newType; | |
| 283 | |
| 284 if (oldType != null) { | |
| 285 newType = oldType.union(type, compiler); | |
| 286 } else { | |
| 287 newType = type; | |
| 288 } | |
| 289 typeMap[field] = newType; | |
| 290 if (oldType != newType) { | |
| 291 scheduleRecompilation(field); | |
| 292 } | |
| 293 } | |
| 294 | |
| 295 void registerConstructor(Element element) { | |
| 296 assert(element.isGenerativeConstructor()); | |
| 297 Element cls = element.getEnclosingClass(); | |
| 298 constructors.putIfAbsent(cls, () => new Set<Element>()); | |
| 299 Set<Element> ctors = constructors[cls]; | |
| 300 if (ctors.contains(element)) return; | |
| 301 ctors.add(element); | |
| 302 // We cannot infer field types for classes with more than one constructor. | |
| 303 // When the second constructor is seen, recompile all functions relying on | |
| 304 // optimistic field types for that class. | |
| 305 // TODO(sgjesse): Handle field types for classes with more than one | |
| 306 // constructor. | |
| 307 if (ctors.length == 2) { | |
| 308 optimizedFunctions.keys.toList().forEach((Element field) { | |
| 309 if (identical(field.enclosingElement, cls)) { | |
| 310 scheduleRecompilation(field); | |
| 311 } | |
| 312 }); | |
| 313 } | |
| 314 } | |
| 315 | |
| 316 void registerFieldInitializer(Element field, HType type) { | |
| 317 registerFieldType(fieldInitializerTypeMap, field, type); | |
| 318 } | |
| 319 | |
| 320 void registerFieldConstructor(Element field, HType type) { | |
| 321 registerFieldType(fieldConstructorTypeMap, field, type); | |
| 322 } | |
| 323 | |
| 324 void registerFieldSetter(Element element, Element field, HType type) { | |
| 325 HType initializerType = fieldInitializerTypeMap[field]; | |
| 326 HType constructorType = fieldConstructorTypeMap[field]; | |
| 327 HType setterType = fieldTypeMap[field]; | |
| 328 if (type == HType.UNKNOWN | |
| 329 && initializerType == null | |
| 330 && constructorType == null | |
| 331 && setterType == null) { | |
| 332 // Don't register UNKNOWN if there is currently no type information | |
| 333 // present for the field. Instead register the function holding the | |
| 334 // setter for recompilation if better type information for the field | |
| 335 // becomes available. | |
| 336 registerOptimizedFunction(element, field, type); | |
| 337 return; | |
| 338 } | |
| 339 registerFieldType(fieldTypeMap, field, type); | |
| 340 } | |
| 341 | |
| 342 void addedDynamicSetter(Selector setter, HType type) { | |
| 343 // Field type optimizations are disabled for all fields matching a | |
| 344 // setter selector. | |
| 345 assert(setter.isSetter()); | |
| 346 // TODO(sgjesse): Take the type of the setter into account. | |
| 347 if (setterSelectorsUsed.contains(setter.name)) return; | |
| 348 setterSelectorsUsed.add(setter.name); | |
| 349 optimizedStaticFunctions.keys.toList().forEach((Element field) { | |
| 350 if (field.name == setter.name) { | |
| 351 scheduleRecompilation(field); | |
| 352 } | |
| 353 }); | |
| 354 optimizedFunctions.keys.toList().forEach((Element field) { | |
| 355 if (field.name == setter.name) { | |
| 356 scheduleRecompilation(field); | |
| 357 } | |
| 358 }); | |
| 359 } | |
| 360 | |
| 361 HType optimisticFieldType(Element field) { | |
| 362 assert(field.isField()); | |
| 363 if (constructorCount(field.getEnclosingClass()) > 1) { | |
| 364 return HType.UNKNOWN; | |
| 365 } | |
| 366 if (setterSelectorsUsed.contains(field.name)) { | |
| 367 return HType.UNKNOWN; | |
| 368 } | |
| 369 HType initializerType = fieldInitializerTypeMap[field]; | |
| 370 HType constructorType = fieldConstructorTypeMap[field]; | |
| 371 if (initializerType == null && constructorType == null) { | |
| 372 // If there are no constructor type information return UNKNOWN. This | |
| 373 // ensures that the function will be recompiled if useful constructor | |
| 374 // type information becomes available. | |
| 375 return HType.UNKNOWN; | |
| 376 } | |
| 377 // A type set through the constructor overrides the type from the | |
| 378 // initializer list. | |
| 379 HType result = constructorType != null ? constructorType : initializerType; | |
| 380 HType type = fieldTypeMap[field]; | |
| 381 if (type != null) result = result.union(type, compiler); | |
| 382 return result; | |
| 383 } | |
| 384 | |
| 385 void registerOptimizedFunction(Element element, | |
| 386 Element field, | |
| 387 HType type) { | |
| 388 assert(field.isField()); | |
| 389 if (Elements.isStaticOrTopLevel(element)) { | |
| 390 optimizedStaticFunctions.putIfAbsent( | |
| 391 field, () => new Set<Element>()); | |
| 392 optimizedStaticFunctions[field].add(element); | |
| 393 } else { | |
| 394 optimizedFunctions.putIfAbsent( | |
| 395 field, () => new FunctionSet(backend.compiler)); | |
| 396 optimizedFunctions[field].add(element); | |
| 397 } | |
| 398 } | |
| 399 | |
| 400 void dump() { | |
| 401 Set<Element> allFields = new Set<Element>(); | |
| 402 fieldInitializerTypeMap.keys.forEach(allFields.add); | |
| 403 fieldConstructorTypeMap.keys.forEach(allFields.add); | |
| 404 fieldTypeMap.keys.forEach(allFields.add); | |
| 405 allFields.forEach((Element field) { | |
| 406 print("Inferred $field has type ${optimisticFieldType(field)}"); | |
| 407 }); | |
| 408 } | |
| 409 } | |
| 410 | |
| 411 class ArgumentTypesRegistry { | |
| 412 final JavaScriptBackend backend; | |
| 413 | |
| 414 /** | |
| 415 * Documentation wanted -- johnniwinther | |
| 416 * | |
| 417 * Invariant: Keys must be declaration elements. | |
| 418 */ | |
| 419 final Map<Element, HTypeList> staticTypeMap; | |
| 420 | |
| 421 /** | |
| 422 * Documentation wanted -- johnniwinther | |
| 423 * | |
| 424 * Invariant: Elements must be declaration elements. | |
| 425 */ | |
| 426 final Set<Element> optimizedStaticFunctions; | |
| 427 final SelectorMap<HTypeList> selectorTypeMap; | |
| 428 final FunctionSet optimizedFunctions; | |
| 429 | |
| 430 /** | |
| 431 * Documentation wanted -- johnniwinther | |
| 432 * | |
| 433 * Invariant: Keys must be declaration elements. | |
| 434 */ | |
| 435 final Map<Element, HTypeList> optimizedTypes; | |
| 436 final Map<Element, OptionalParameterTypes> optimizedDefaultValueTypes; | |
| 437 | |
| 438 ArgumentTypesRegistry(JavaScriptBackend backend) | |
| 439 : staticTypeMap = new Map<Element, HTypeList>(), | |
| 440 optimizedStaticFunctions = new Set<Element>(), | |
| 441 selectorTypeMap = new SelectorMap<HTypeList>(backend.compiler), | |
| 442 optimizedFunctions = new FunctionSet(backend.compiler), | |
| 443 optimizedTypes = new Map<Element, HTypeList>(), | |
| 444 optimizedDefaultValueTypes = | |
| 445 new Map<Element, OptionalParameterTypes>(), | |
| 446 this.backend = backend; | |
| 447 | |
| 448 Compiler get compiler => backend.compiler; | |
| 449 | |
| 450 bool updateTypes(HTypeList oldTypes, HTypeList newTypes, var key, var map) { | |
| 451 if (oldTypes.allUnknown) return false; | |
| 452 newTypes = oldTypes.union(newTypes, backend.compiler); | |
| 453 if (identical(newTypes, oldTypes)) return false; | |
| 454 map[key] = newTypes; | |
| 455 return true; | |
| 456 } | |
| 457 | |
| 458 void registerStaticInvocation(HInvokeStatic node) { | |
| 459 Element element = node.element; | |
| 460 assert(invariant(node, element.isDeclaration)); | |
| 461 HTypeList oldTypes = staticTypeMap[element]; | |
| 462 HTypeList newTypes = new HTypeList.fromStaticInvocation(node); | |
| 463 if (oldTypes == null) { | |
| 464 staticTypeMap[element] = newTypes; | |
| 465 } else if (updateTypes(oldTypes, newTypes, element, staticTypeMap)) { | |
| 466 if (optimizedStaticFunctions.contains(element)) { | |
| 467 backend.scheduleForRecompilation(element); | |
| 468 } | |
| 469 } | |
| 470 } | |
| 471 | |
| 472 void registerNonCallStaticUse(HStatic node) { | |
| 473 // When a static is used for anything else than a call target we cannot | |
| 474 // infer anything about its parameter types. | |
| 475 Element element = node.element; | |
| 476 assert(invariant(node, element.isDeclaration)); | |
| 477 if (optimizedStaticFunctions.contains(element)) { | |
| 478 backend.scheduleForRecompilation(element); | |
| 479 } | |
| 480 staticTypeMap[element] = HTypeList.ALL_UNKNOWN; | |
| 481 } | |
| 482 | |
| 483 void registerDynamicInvocation(HTypeList providedTypes, Selector selector) { | |
| 484 if (selector.isClosureCall()) { | |
| 485 // We cannot use the current framework to do optimizations based | |
| 486 // on the 'call' selector because we are also generating closure | |
| 487 // calls during the emitter phase, which at this point, does not | |
| 488 // track parameter types, nor invalidates optimized methods. | |
| 489 return; | |
| 490 } | |
| 491 if (!selectorTypeMap.containsKey(selector)) { | |
| 492 selectorTypeMap[selector] = providedTypes; | |
| 493 } else { | |
| 494 HTypeList oldTypes = selectorTypeMap[selector]; | |
| 495 updateTypes(oldTypes, providedTypes, selector, selectorTypeMap); | |
| 496 } | |
| 497 | |
| 498 // If we're not compiling, we don't have to do anything. | |
| 499 if (compiler.phase != Compiler.PHASE_COMPILING) return; | |
| 500 | |
| 501 // Run through all optimized functions and figure out if they need | |
| 502 // to be recompiled because of this new invocation. | |
| 503 for (Element element in optimizedFunctions.filter(selector)) { | |
| 504 // TODO(kasperl): Maybe check if the element is already marked for | |
| 505 // recompilation? Could be pretty cheap compared to computing | |
| 506 // union types. | |
| 507 HTypeList newTypes = | |
| 508 parameterTypes(element, optimizedDefaultValueTypes[element]); | |
| 509 bool recompile = false; | |
| 510 if (newTypes.allUnknown) { | |
| 511 recompile = true; | |
| 512 } else { | |
| 513 HTypeList oldTypes = optimizedTypes[element]; | |
| 514 assert(newTypes.length == oldTypes.length); | |
| 515 for (int i = 0; i < oldTypes.length; i++) { | |
| 516 if (newTypes[i] != oldTypes[i]) { | |
| 517 recompile = true; | |
| 518 break; | |
| 519 } | |
| 520 } | |
| 521 } | |
| 522 if (recompile) backend.scheduleForRecompilation(element); | |
| 523 } | |
| 524 } | |
| 525 | |
| 526 HTypeList parameterTypes(FunctionElement element, | |
| 527 OptionalParameterTypes defaultValueTypes) { | |
| 528 assert(invariant(element, element.isDeclaration)); | |
| 529 // Handle static functions separately. | |
| 530 if (Elements.isStaticOrTopLevelFunction(element) || | |
| 531 element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) { | |
| 532 HTypeList types = staticTypeMap[element]; | |
| 533 if (types != null) { | |
| 534 if (!optimizedStaticFunctions.contains(element)) { | |
| 535 optimizedStaticFunctions.add(element); | |
| 536 } | |
| 537 return types; | |
| 538 } else { | |
| 539 return HTypeList.ALL_UNKNOWN; | |
| 540 } | |
| 541 } | |
| 542 | |
| 543 // Getters have no parameters. | |
| 544 if (element.isGetter()) return HTypeList.ALL_UNKNOWN; | |
| 545 | |
| 546 // TODO(kasperl): What kind of non-members do we get here? | |
| 547 if (!element.isMember()) return HTypeList.ALL_UNKNOWN; | |
| 548 | |
| 549 // If there are any getters for this method we cannot know anything about | |
| 550 // the types of the provided parameters. Use resolverWorld for now as that | |
| 551 // information does not change during compilation. | |
| 552 // TODO(ngeoffray): These checks should use the codegenWorld and keep track | |
| 553 // of changes to this information. | |
| 554 if (compiler.resolverWorld.hasInvokedGetter(element, compiler)) { | |
| 555 return HTypeList.ALL_UNKNOWN; | |
| 556 } | |
| 557 | |
| 558 FunctionSignature signature = element.computeSignature(compiler); | |
| 559 HTypeList found = null; | |
| 560 selectorTypeMap.visitMatching(element, | |
| 561 (Selector selector, HTypeList types) { | |
| 562 if (selector.argumentCount != signature.parameterCount || | |
| 563 selector.namedArgumentCount > 0) { | |
| 564 types = types.unionWithOptionalParameters(selector, | |
| 565 signature, | |
| 566 defaultValueTypes); | |
| 567 } | |
| 568 assert(types.allUnknown || types.length == signature.parameterCount); | |
| 569 found = (found == null) ? types : found.union(types, compiler); | |
| 570 return !found.allUnknown; | |
| 571 }); | |
| 572 return found != null ? found : HTypeList.ALL_UNKNOWN; | |
| 573 } | |
| 574 | |
| 575 void registerOptimizedFunction(Element element, | |
| 576 HTypeList parameterTypes, | |
| 577 OptionalParameterTypes defaultValueTypes) { | |
| 578 if (Elements.isStaticOrTopLevelFunction(element)) { | |
| 579 if (parameterTypes.allUnknown) { | |
| 580 optimizedStaticFunctions.remove(element); | |
| 581 } else { | |
| 582 optimizedStaticFunctions.add(element); | |
| 583 } | |
| 584 } | |
| 585 | |
| 586 // TODO(kasperl): What kind of non-members do we get here? | |
| 587 if (!element.isInstanceMember()) return; | |
| 588 | |
| 589 if (parameterTypes.allUnknown) { | |
| 590 optimizedFunctions.remove(element); | |
| 591 optimizedTypes.remove(element); | |
| 592 optimizedDefaultValueTypes.remove(element); | |
| 593 } else { | |
| 594 optimizedFunctions.add(element); | |
| 595 optimizedTypes[element] = parameterTypes; | |
| 596 optimizedDefaultValueTypes[element] = defaultValueTypes; | |
| 597 } | |
| 598 } | |
| 599 | |
| 600 void dump() { | |
| 601 optimizedFunctions.forEach((Element element) { | |
| 602 HTypeList types = optimizedTypes[element]; | |
| 603 print("Inferred $element has argument types ${types.types}"); | |
| 604 }); | |
| 605 } | |
| 606 } | |
| 607 | |
| 608 class JavaScriptItemCompilationContext extends ItemCompilationContext { | 7 class JavaScriptItemCompilationContext extends ItemCompilationContext { |
| 609 final Set<HInstruction> boundsChecked; | 8 final Set<HInstruction> boundsChecked; |
| 610 | 9 |
| 611 JavaScriptItemCompilationContext() | 10 JavaScriptItemCompilationContext() |
| 612 : boundsChecked = new Set<HInstruction>(); | 11 : boundsChecked = new Set<HInstruction>(); |
| 613 } | 12 } |
| 614 | 13 |
| 615 class JavaScriptBackend extends Backend { | 14 class JavaScriptBackend extends Backend { |
| 616 SsaBuilderTask builder; | 15 SsaBuilderTask builder; |
| 617 SsaOptimizerTask optimizer; | 16 SsaOptimizerTask optimizer; |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 684 | 83 |
| 685 final Namer namer; | 84 final Namer namer; |
| 686 | 85 |
| 687 /** | 86 /** |
| 688 * Interface used to determine if an object has the JavaScript | 87 * Interface used to determine if an object has the JavaScript |
| 689 * indexing behavior. The interface is only visible to specific | 88 * indexing behavior. The interface is only visible to specific |
| 690 * libraries. | 89 * libraries. |
| 691 */ | 90 */ |
| 692 ClassElement jsIndexingBehaviorInterface; | 91 ClassElement jsIndexingBehaviorInterface; |
| 693 | 92 |
| 694 final Map<Element, ReturnInfo> returnInfo; | |
| 695 | |
| 696 /** | |
| 697 * Documentation wanted -- johnniwinther | |
| 698 * | |
| 699 * Invariant: Elements must be declaration elements. | |
| 700 */ | |
| 701 final List<Element> invalidateAfterCodegen; | |
| 702 ArgumentTypesRegistry argumentTypes; | |
| 703 FieldTypesRegistry fieldTypes; | |
| 704 | |
| 705 /** | 93 /** |
| 706 * A collection of selectors of intercepted method calls. The | 94 * A collection of selectors of intercepted method calls. The |
| 707 * emitter uses this set to generate the [:ObjectInterceptor:] class | 95 * emitter uses this set to generate the [:ObjectInterceptor:] class |
| 708 * whose members just forward the call to the intercepted receiver. | 96 * whose members just forward the call to the intercepted receiver. |
| 709 */ | 97 */ |
| 710 final Set<Selector> usedInterceptors; | 98 final Set<Selector> usedInterceptors; |
| 711 | 99 |
| 712 /** | 100 /** |
| 713 * A collection of selectors that must have a one shot interceptor | 101 * A collection of selectors that must have a one shot interceptor |
| 714 * generated. | 102 * generated. |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 755 final Set<ClassElement> specialOperatorEqClasses = new Set<ClassElement>(); | 143 final Set<ClassElement> specialOperatorEqClasses = new Set<ClassElement>(); |
| 756 | 144 |
| 757 List<CompilerTask> get tasks { | 145 List<CompilerTask> get tasks { |
| 758 return <CompilerTask>[builder, optimizer, generator, emitter]; | 146 return <CompilerTask>[builder, optimizer, generator, emitter]; |
| 759 } | 147 } |
| 760 | 148 |
| 761 final RuntimeTypes rti; | 149 final RuntimeTypes rti; |
| 762 | 150 |
| 763 JavaScriptBackend(Compiler compiler, bool generateSourceMap, bool disableEval) | 151 JavaScriptBackend(Compiler compiler, bool generateSourceMap, bool disableEval) |
| 764 : namer = determineNamer(compiler), | 152 : namer = determineNamer(compiler), |
| 765 returnInfo = new Map<Element, ReturnInfo>(), | |
| 766 invalidateAfterCodegen = new List<Element>(), | |
| 767 usedInterceptors = new Set<Selector>(), | 153 usedInterceptors = new Set<Selector>(), |
| 768 oneShotInterceptors = new Map<String, Selector>(), | 154 oneShotInterceptors = new Map<String, Selector>(), |
| 769 interceptedElements = new Map<SourceString, Set<Element>>(), | 155 interceptedElements = new Map<SourceString, Set<Element>>(), |
| 770 rti = new RuntimeTypes(compiler), | 156 rti = new RuntimeTypes(compiler), |
| 771 specializedGetInterceptors = new Map<String, Set<ClassElement>>(), | 157 specializedGetInterceptors = new Map<String, Set<ClassElement>>(), |
| 772 super(compiler, JAVA_SCRIPT_CONSTANT_SYSTEM) { | 158 super(compiler, JAVA_SCRIPT_CONSTANT_SYSTEM) { |
| 773 emitter = disableEval | 159 emitter = disableEval |
| 774 ? new CodeEmitterNoEvalTask(compiler, namer, generateSourceMap) | 160 ? new CodeEmitterNoEvalTask(compiler, namer, generateSourceMap) |
| 775 : new CodeEmitterTask(compiler, namer, generateSourceMap); | 161 : new CodeEmitterTask(compiler, namer, generateSourceMap); |
| 776 builder = new SsaBuilderTask(this); | 162 builder = new SsaBuilderTask(this); |
| 777 optimizer = new SsaOptimizerTask(this); | 163 optimizer = new SsaOptimizerTask(this); |
| 778 generator = new SsaCodeGeneratorTask(this); | 164 generator = new SsaCodeGeneratorTask(this); |
| 779 argumentTypes = new ArgumentTypesRegistry(this); | |
| 780 fieldTypes = new FieldTypesRegistry(this); | |
| 781 } | 165 } |
| 782 | 166 |
| 783 static Namer determineNamer(Compiler compiler) { | 167 static Namer determineNamer(Compiler compiler) { |
| 784 return compiler.enableMinification ? | 168 return compiler.enableMinification ? |
| 785 new MinifyNamer(compiler) : | 169 new MinifyNamer(compiler) : |
| 786 new Namer(compiler); | 170 new Namer(compiler); |
| 787 } | 171 } |
| 788 | 172 |
| 789 bool isInterceptorClass(ClassElement element) { | 173 bool isInterceptorClass(ClassElement element) { |
| 790 if (element == null) return false; | 174 if (element == null) return false; |
| (...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1045 String name = namer.getInterceptorName(getInterceptorMethod, classes); | 429 String name = namer.getInterceptorName(getInterceptorMethod, classes); |
| 1046 if (classes.contains(jsInterceptorClass)) { | 430 if (classes.contains(jsInterceptorClass)) { |
| 1047 // We can't use a specialized [getInterceptorMethod], so we make | 431 // We can't use a specialized [getInterceptorMethod], so we make |
| 1048 // sure we emit the one with all checks. | 432 // sure we emit the one with all checks. |
| 1049 specializedGetInterceptors[name] = interceptedClasses; | 433 specializedGetInterceptors[name] = interceptedClasses; |
| 1050 } else { | 434 } else { |
| 1051 specializedGetInterceptors[name] = classes; | 435 specializedGetInterceptors[name] = classes; |
| 1052 } | 436 } |
| 1053 } | 437 } |
| 1054 | 438 |
| 1055 void initializeNoSuchMethod() { | |
| 1056 // In case the emitter generates noSuchMethod calls, we need to | |
| 1057 // make sure all [noSuchMethod] methods know they might take a | |
| 1058 // [JsInvocationMirror] as parameter. | |
| 1059 HTypeList types = new HTypeList(1); | |
| 1060 types[0] = new HType.nonNullExact( | |
| 1061 compiler.jsInvocationMirrorClass.computeType(compiler), | |
| 1062 compiler); | |
| 1063 argumentTypes.registerDynamicInvocation( | |
| 1064 types, compiler.noSuchMethodSelector); | |
| 1065 } | |
| 1066 | |
| 1067 void registerInstantiatedClass(ClassElement cls, | 439 void registerInstantiatedClass(ClassElement cls, |
| 1068 Enqueuer enqueuer, | 440 Enqueuer enqueuer, |
| 1069 TreeElements elements) { | 441 TreeElements elements) { |
| 1070 if (!seenAnyClass) { | 442 if (!seenAnyClass) { |
| 1071 initializeNoSuchMethod(); | |
| 1072 seenAnyClass = true; | 443 seenAnyClass = true; |
| 1073 if (enqueuer.isResolutionQueue) { | 444 if (enqueuer.isResolutionQueue) { |
| 1074 // TODO(9577): Make it so that these are not needed when there are no | 445 // TODO(9577): Make it so that these are not needed when there are no |
| 1075 // native classes. | 446 // native classes. |
| 1076 enqueuer.registerStaticUse(getNativeInterceptorMethod); | 447 enqueuer.registerStaticUse(getNativeInterceptorMethod); |
| 1077 enqueuer.registerStaticUse(defineNativeMethodsFinishMethod); | 448 enqueuer.registerStaticUse(defineNativeMethodsFinishMethod); |
| 1078 enqueuer.registerStaticUse(initializeDispatchPropertyMethod); | 449 enqueuer.registerStaticUse(initializeDispatchPropertyMethod); |
| 1079 enqueuer.registerInstantiatedClass(jsInterceptorClass, | 450 enqueuer.registerInstantiatedClass(jsInterceptorClass, |
| 1080 compiler.globalDependencies); | 451 compiler.globalDependencies); |
| 1081 } | 452 } |
| (...skipping 322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1404 optimizer.optimize(work, graph, false); | 775 optimizer.optimize(work, graph, false); |
| 1405 if (work.allowSpeculativeOptimization | 776 if (work.allowSpeculativeOptimization |
| 1406 && optimizer.trySpeculativeOptimizations(work, graph)) { | 777 && optimizer.trySpeculativeOptimizations(work, graph)) { |
| 1407 jsAst.Expression code = generator.generateBailoutMethod(work, graph); | 778 jsAst.Expression code = generator.generateBailoutMethod(work, graph); |
| 1408 generatedBailoutCode[element] = code; | 779 generatedBailoutCode[element] = code; |
| 1409 optimizer.prepareForSpeculativeOptimizations(work, graph); | 780 optimizer.prepareForSpeculativeOptimizations(work, graph); |
| 1410 optimizer.optimize(work, graph, true); | 781 optimizer.optimize(work, graph, true); |
| 1411 } | 782 } |
| 1412 jsAst.Expression code = generator.generateCode(work, graph); | 783 jsAst.Expression code = generator.generateCode(work, graph); |
| 1413 generatedCode[element] = code; | 784 generatedCode[element] = code; |
| 1414 invalidateAfterCodegen.forEach(eagerRecompile); | |
| 1415 invalidateAfterCodegen.clear(); | |
| 1416 } | 785 } |
| 1417 | 786 |
| 1418 native.NativeEnqueuer nativeResolutionEnqueuer(Enqueuer world) { | 787 native.NativeEnqueuer nativeResolutionEnqueuer(Enqueuer world) { |
| 1419 return new native.NativeResolutionEnqueuer(world, compiler); | 788 return new native.NativeResolutionEnqueuer(world, compiler); |
| 1420 } | 789 } |
| 1421 | 790 |
| 1422 native.NativeEnqueuer nativeCodegenEnqueuer(Enqueuer world) { | 791 native.NativeEnqueuer nativeCodegenEnqueuer(Enqueuer world) { |
| 1423 return new native.NativeCodegenEnqueuer(world, compiler, emitter); | 792 return new native.NativeCodegenEnqueuer(world, compiler, emitter); |
| 1424 } | 793 } |
| 1425 | 794 |
| 1426 ClassElement defaultSuperclass(ClassElement element) { | 795 ClassElement defaultSuperclass(ClassElement element) { |
| 1427 // Native classes inherit from Interceptor. | 796 // Native classes inherit from Interceptor. |
| 1428 return element.isNative() ? jsInterceptorClass : compiler.objectClass; | 797 return element.isNative() ? jsInterceptorClass : compiler.objectClass; |
| 1429 } | 798 } |
| 1430 | 799 |
| 1431 /** | 800 /** |
| 1432 * Unit test hook that returns code of an element as a String. | 801 * Unit test hook that returns code of an element as a String. |
| 1433 * | 802 * |
| 1434 * Invariant: [element] must be a declaration element. | 803 * Invariant: [element] must be a declaration element. |
| 1435 */ | 804 */ |
| 1436 String assembleCode(Element element) { | 805 String assembleCode(Element element) { |
| 1437 assert(invariant(element, element.isDeclaration)); | 806 assert(invariant(element, element.isDeclaration)); |
| 1438 return jsAst.prettyPrint(generatedCode[element], compiler).getText(); | 807 return jsAst.prettyPrint(generatedCode[element], compiler).getText(); |
| 1439 } | 808 } |
| 1440 | 809 |
| 1441 void assembleProgram() { | 810 void assembleProgram() { |
| 1442 emitter.assembleProgram(); | 811 emitter.assembleProgram(); |
| 1443 } | 812 } |
| 1444 | 813 |
| 1445 /** | |
| 1446 * Documentation wanted -- johnniwinther | |
| 1447 * | |
| 1448 * Invariant: [element] must be a declaration element. | |
| 1449 */ | |
| 1450 void scheduleForRecompilation(Element element) { | |
| 1451 assert(invariant(element, element.isDeclaration)); | |
| 1452 if (compiler.phase == Compiler.PHASE_COMPILING) { | |
| 1453 invalidateAfterCodegen.add(element); | |
| 1454 } | |
| 1455 } | |
| 1456 | |
| 1457 /** | |
| 1458 * Register a dynamic invocation and collect the provided types for the | |
| 1459 * named selector. | |
| 1460 */ | |
| 1461 void registerDynamicInvocation(HInvoke node, Selector selector) { | |
| 1462 HTypeList providedTypes = | |
| 1463 new HTypeList.fromDynamicInvocation(node, selector); | |
| 1464 argumentTypes.registerDynamicInvocation(providedTypes, selector); | |
| 1465 } | |
| 1466 | |
| 1467 /** | |
| 1468 * Register a static invocation and collect the provided types for the | |
| 1469 * named selector. | |
| 1470 */ | |
| 1471 void registerStaticInvocation(HInvokeStatic node) { | |
| 1472 argumentTypes.registerStaticInvocation(node); | |
| 1473 } | |
| 1474 | |
| 1475 /** | |
| 1476 * Register that a static is used for something else than a direct call | |
| 1477 * target. | |
| 1478 */ | |
| 1479 void registerNonCallStaticUse(HStatic node) { | |
| 1480 argumentTypes.registerNonCallStaticUse(node); | |
| 1481 } | |
| 1482 | |
| 1483 /** | |
| 1484 * Retrieve the types of the parameters used for calling the [element] | |
| 1485 * function. The types are optimistic in the sense as they are based on the | |
| 1486 * possible invocations of the function seen so far. | |
| 1487 * | |
| 1488 * Invariant: [element] must be a declaration element. | |
| 1489 */ | |
| 1490 HTypeList optimisticParameterTypes( | |
| 1491 FunctionElement element, | |
| 1492 OptionalParameterTypes defaultValueTypes) { | |
| 1493 assert(invariant(element, element.isDeclaration)); | |
| 1494 if (element.parameterCount(compiler) == 0) return HTypeList.ALL_UNKNOWN; | |
| 1495 return argumentTypes.parameterTypes(element, defaultValueTypes); | |
| 1496 } | |
| 1497 | |
| 1498 /** | |
| 1499 * Register that the function [element] has been optimized under the | |
| 1500 * assumptions that the types [parameterType] will be used for calling it. | |
| 1501 * The passed [defaultValueTypes] holds the types of default values for | |
| 1502 * the optional parameters. If this assumption fail the function will be | |
| 1503 * scheduled for recompilation. | |
| 1504 * | |
| 1505 * Invariant: [element] must be a declaration element. | |
| 1506 */ | |
| 1507 registerParameterTypesOptimization( | |
| 1508 FunctionElement element, | |
| 1509 HTypeList parameterTypes, | |
| 1510 OptionalParameterTypes defaultValueTypes) { | |
| 1511 assert(invariant(element, element.isDeclaration)); | |
| 1512 if (element.parameterCount(compiler) == 0) return; | |
| 1513 argumentTypes.registerOptimizedFunction( | |
| 1514 element, parameterTypes, defaultValueTypes); | |
| 1515 } | |
| 1516 | |
| 1517 registerFieldTypesOptimization(Element element, | |
| 1518 Element field, | |
| 1519 HType type) { | |
| 1520 fieldTypes.registerOptimizedFunction(element, field, type); | |
| 1521 } | |
| 1522 | |
| 1523 /** | |
| 1524 * Documentation wanted -- johnniwinther | |
| 1525 * | |
| 1526 * Invariant: [element] must be a declaration element. | |
| 1527 */ | |
| 1528 void registerReturnType(FunctionElement element, HType returnType) { | |
| 1529 assert(invariant(element, element.isDeclaration)); | |
| 1530 ReturnInfo info = returnInfo[element]; | |
| 1531 if (info != null) { | |
| 1532 info.update(returnType, scheduleForRecompilation, compiler); | |
| 1533 } else { | |
| 1534 returnInfo[element] = new ReturnInfo(returnType); | |
| 1535 } | |
| 1536 } | |
| 1537 | |
| 1538 /** | |
| 1539 * Retrieve the return type of the function [callee]. The type is optimistic | |
| 1540 * in the sense that is is based on the compilation of [callee]. If [callee] | |
| 1541 * is recompiled the return type might change to someting broader. For that | |
| 1542 * reason [caller] is registered for recompilation if this happens. If the | |
| 1543 * function [callee] has not yet been compiled the returned type is [null]. | |
| 1544 * | |
| 1545 * Invariant: Both [caller] and [callee] must be declaration elements. | |
| 1546 */ | |
| 1547 HType optimisticReturnTypesWithRecompilationOnTypeChange( | |
| 1548 Element caller, FunctionElement callee) { | |
| 1549 assert(invariant(callee, callee.isDeclaration)); | |
| 1550 returnInfo.putIfAbsent(callee, () => new ReturnInfo.unknownType()); | |
| 1551 ReturnInfo info = returnInfo[callee]; | |
| 1552 HType returnType = info.returnType; | |
| 1553 if (returnType != HType.UNKNOWN && returnType != null && caller != null) { | |
| 1554 assert(invariant(caller, caller.isDeclaration)); | |
| 1555 info.addCompiledFunction(caller); | |
| 1556 } | |
| 1557 return info.returnType; | |
| 1558 } | |
| 1559 | |
| 1560 void dumpReturnTypes() { | |
| 1561 returnInfo.forEach((Element element, ReturnInfo info) { | |
| 1562 if (info.returnType != HType.UNKNOWN) { | |
| 1563 print("Inferred $element has return type ${info.returnType}"); | |
| 1564 } | |
| 1565 }); | |
| 1566 } | |
| 1567 | |
| 1568 void registerConstructor(Element element) { | |
| 1569 fieldTypes.registerConstructor(element); | |
| 1570 } | |
| 1571 | |
| 1572 void registerFieldInitializer(Element field, HType type) { | |
| 1573 fieldTypes.registerFieldInitializer(field, type); | |
| 1574 } | |
| 1575 | |
| 1576 void registerFieldConstructor(Element field, HType type) { | |
| 1577 fieldTypes.registerFieldConstructor(field, type); | |
| 1578 } | |
| 1579 | |
| 1580 void registerFieldSetter(Element element, Element field, HType type) { | |
| 1581 fieldTypes.registerFieldSetter(element, field, type); | |
| 1582 } | |
| 1583 | |
| 1584 void addedDynamicSetter(Selector setter, HType type) { | |
| 1585 fieldTypes.addedDynamicSetter(setter, type); | |
| 1586 } | |
| 1587 | |
| 1588 HType optimisticFieldType(Element element) { | |
| 1589 return fieldTypes.optimisticFieldType(element); | |
| 1590 } | |
| 1591 | |
| 1592 Element getImplementationClass(Element element) { | 814 Element getImplementationClass(Element element) { |
| 1593 if (element == compiler.intClass) { | 815 if (element == compiler.intClass) { |
| 1594 return jsIntClass; | 816 return jsIntClass; |
| 1595 } else if (element == compiler.boolClass) { | 817 } else if (element == compiler.boolClass) { |
| 1596 return jsBoolClass; | 818 return jsBoolClass; |
| 1597 } else if (element == compiler.numClass) { | 819 } else if (element == compiler.numClass) { |
| 1598 return jsNumberClass; | 820 return jsNumberClass; |
| 1599 } else if (element == compiler.doubleClass) { | 821 } else if (element == compiler.doubleClass) { |
| 1600 return jsDoubleClass; | 822 return jsDoubleClass; |
| 1601 } else if (element == compiler.stringClass) { | 823 } else if (element == compiler.stringClass) { |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1733 } else { | 955 } else { |
| 1734 return typeCast | 956 return typeCast |
| 1735 ? const SourceString('propertyTypeCast') | 957 ? const SourceString('propertyTypeCast') |
| 1736 : const SourceString('propertyTypeCheck'); | 958 : const SourceString('propertyTypeCheck'); |
| 1737 } | 959 } |
| 1738 } | 960 } |
| 1739 } | 961 } |
| 1740 } | 962 } |
| 1741 } | 963 } |
| 1742 | 964 |
| 1743 void dumpInferredTypes() { | |
| 1744 print("Inferred argument types:"); | |
| 1745 print("------------------------"); | |
| 1746 argumentTypes.dump(); | |
| 1747 print(""); | |
| 1748 print("Inferred return types:"); | |
| 1749 print("----------------------"); | |
| 1750 dumpReturnTypes(); | |
| 1751 print(""); | |
| 1752 print("Inferred field types:"); | |
| 1753 print("------------------------"); | |
| 1754 fieldTypes.dump(); | |
| 1755 print(""); | |
| 1756 } | |
| 1757 | |
| 1758 Element getExceptionUnwrapper() { | 965 Element getExceptionUnwrapper() { |
| 1759 return compiler.findHelper(const SourceString('unwrapException')); | 966 return compiler.findHelper(const SourceString('unwrapException')); |
| 1760 } | 967 } |
| 1761 | 968 |
| 1762 Element getThrowRuntimeError() { | 969 Element getThrowRuntimeError() { |
| 1763 return compiler.findHelper(const SourceString('throwRuntimeError')); | 970 return compiler.findHelper(const SourceString('throwRuntimeError')); |
| 1764 } | 971 } |
| 1765 | 972 |
| 1766 Element getThrowMalformedSubtypeError() { | 973 Element getThrowMalformedSubtypeError() { |
| 1767 return compiler.findHelper( | 974 return compiler.findHelper( |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1874 ClassElement get listImplementation => jsArrayClass; | 1081 ClassElement get listImplementation => jsArrayClass; |
| 1875 ClassElement get constListImplementation => jsArrayClass; | 1082 ClassElement get constListImplementation => jsArrayClass; |
| 1876 ClassElement get fixedListImplementation => jsFixedArrayClass; | 1083 ClassElement get fixedListImplementation => jsFixedArrayClass; |
| 1877 ClassElement get growableListImplementation => jsExtendableArrayClass; | 1084 ClassElement get growableListImplementation => jsExtendableArrayClass; |
| 1878 ClassElement get mapImplementation => mapLiteralClass; | 1085 ClassElement get mapImplementation => mapLiteralClass; |
| 1879 ClassElement get constMapImplementation => constMapLiteralClass; | 1086 ClassElement get constMapImplementation => constMapLiteralClass; |
| 1880 ClassElement get typeImplementation => typeLiteralClass; | 1087 ClassElement get typeImplementation => typeLiteralClass; |
| 1881 ClassElement get boolImplementation => jsBoolClass; | 1088 ClassElement get boolImplementation => jsBoolClass; |
| 1882 ClassElement get nullImplementation => jsNullClass; | 1089 ClassElement get nullImplementation => jsNullClass; |
| 1883 } | 1090 } |
| OLD | NEW |