Chromium Code Reviews| 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 class NativeEmitter { | 5 class NativeEmitter { |
| 6 | 6 |
| 7 Compiler compiler; | 7 Compiler compiler; |
| 8 bool addedDynamicFunction = false; | 8 StringBuffer buffer; |
| 9 bool addedTypeNameOfFunction = false; | |
| 10 bool addedDefPropFunction = false; | |
| 11 bool addedNativeProperty = false; | |
| 12 | 9 |
| 13 // Classes that participate in dynamic dispatch. These are the | 10 // Classes that participate in dynamic dispatch. These are the |
| 14 // classes that contain used members. | 11 // classes that contain used members. |
| 15 Set<ClassElement> classesWithDynamicDispatch; | 12 Set<ClassElement> classesWithDynamicDispatch; |
| 16 | 13 |
| 17 // Native classes found in the application. | 14 // Native classes found in the application. |
| 18 Set<ClassElement> nativeClasses; | 15 Set<ClassElement> nativeClasses; |
| 19 | 16 |
| 20 // Caches the direct native subtypes of a native class. | 17 // Caches the direct native subtypes of a native class. |
| 21 Map<ClassElement, List<ClassElement>> subtypes; | 18 Map<ClassElement, List<ClassElement>> subtypes; |
| 22 | 19 |
| 23 // Caches the native methods that are overridden by a native class. | 20 // Caches the native methods that are overridden by a native class. |
| 24 // Note that the method that overrides does not have to be native: | 21 // Note that the method that overrides does not have to be native: |
| 25 // it's the overridden method that must make sure it will dispatch | 22 // it's the overridden method that must make sure it will dispatch |
| 26 // to its subclass if it sees an instance whose class is a subclass. | 23 // to its subclass if it sees an instance whose class is a subclass. |
| 27 Set<FunctionElement> overriddenMethods; | 24 Set<FunctionElement> overriddenMethods; |
| 28 | 25 |
| 29 NativeEmitter(this.compiler) | 26 NativeEmitter(this.compiler) |
| 30 : classesWithDynamicDispatch = new Set<ClassElement>(), | 27 : classesWithDynamicDispatch = new Set<ClassElement>(), |
| 31 nativeClasses = new Set<ClassElement>(), | 28 nativeClasses = new Set<ClassElement>(), |
| 32 subtypes = new Map<ClassElement, List<ClassElement>>(), | 29 subtypes = new Map<ClassElement, List<ClassElement>>(), |
| 33 overriddenMethods = new Set<FunctionElement>(); | 30 overriddenMethods = new Set<FunctionElement>(), |
| 31 buffer = new StringBuffer(); | |
| 34 | 32 |
| 35 /** | 33 String get dynamicName() { |
| 36 * Code for finding the type name of a JavaScript object. | 34 Element element = compiler.findHelper( |
| 37 */ | 35 const SourceString('dynamicFunction')); |
| 38 static final String TYPE_NAME_OF_FUNCTION = @""" | 36 return compiler.namer.isolateAccess(element); |
| 39 (function() { | |
| 40 function constructorNameWithFallback(obj) { | |
| 41 var constructor = obj.constructor; | |
| 42 if (typeof(constructor) == 'function') { | |
| 43 // The constructor isn't null or undefined at this point. Try | |
| 44 // to grab hold of its name. | |
| 45 var name = constructor.name; | |
| 46 // If the name is a non-empty string, we use that as the type | |
| 47 // name of this object. On Firefox, we often get 'Object' as | |
| 48 // the constructor name even for more specialized objects so | |
| 49 // we have to fall through to the toString() based implementation | |
| 50 // below in that case. | |
| 51 if (typeof(name) == 'string' && name && name != 'Object') return name; | |
| 52 } | |
| 53 var string = Object.prototype.toString.call(obj); | |
| 54 return string.substring(8, string.length - 1); | |
| 55 } | 37 } |
| 56 | 38 |
| 57 function chrome$typeNameOf(obj) { | 39 String get dynamicSetMetadataName() { |
| 58 var name = obj.constructor.name; | 40 Element element = compiler.findHelper( |
| 59 if (name == 'Window') return 'DOMWindow'; | 41 const SourceString('dynamicSetMetadata')); |
| 60 return name; | 42 return compiler.namer.isolateAccess(element); |
| 61 } | 43 } |
| 62 | 44 |
| 63 function firefox$typeNameOf(obj) { | 45 String get typeNameOfName() { |
| 64 var name = constructorNameWithFallback(obj); | 46 Element element = compiler.findHelper( |
| 65 if (name == 'Window') return 'DOMWindow'; | 47 const SourceString('getTypeNameOf')); |
| 66 if (name == 'Document') return 'HTMLDocument'; | 48 return compiler.namer.isolateAccess(element); |
| 67 if (name == 'XMLDocument') return 'Document'; | |
| 68 return name; | |
| 69 } | 49 } |
| 70 | 50 |
| 71 function ie$typeNameOf(obj) { | 51 String get dynamicIsCheckName() { |
| 72 var name = constructorNameWithFallback(obj); | 52 Element element = compiler.findHelper( |
| 73 if (name == 'Window') return 'DOMWindow'; | 53 const SourceString('dynamicIsCheck')); |
| 74 // IE calls both HTML and XML documents 'Document', so we check for the | 54 return compiler.namer.isolateAccess(element); |
| 75 // xmlVersion property, which is the empty string on HTML documents. | |
| 76 if (name == 'Document' && obj.xmlVersion) return 'Document'; | |
| 77 if (name == 'Document') return 'HTMLDocument'; | |
| 78 return name; | |
| 79 } | 55 } |
| 80 | 56 |
| 81 // If we're not in the browser, we're almost certainly running on v8. | 57 String get isChecksHelperName() { |
| 82 if (typeof(navigator) != 'object') return chrome$typeNameOf; | 58 Element element = compiler.findHelper( |
| 83 | 59 const SourceString('isChecksHelper')); |
| 84 var userAgent = navigator.userAgent; | 60 if (element === null) return null; |
| 85 if (/Chrome|DumpRenderTree/.test(userAgent)) return chrome$typeNameOf; | 61 return compiler.namer.isolateAccess(element); |
| 86 if (/Firefox/.test(userAgent)) return firefox$typeNameOf; | |
| 87 if (/MSIE/.test(userAgent)) return ie$typeNameOf; | |
| 88 return constructorNameWithFallback; | |
| 89 })()"""; | |
| 90 | |
| 91 /** | |
| 92 * Code for defining a property in a JavaScript object that will not | |
| 93 * be visible through for-in (aka enumerable is false). | |
| 94 */ | |
| 95 static final String DEF_PROP_FUNCTION = ''' | |
| 96 function(obj, prop, value) { | |
| 97 Object.defineProperty(obj, prop, | |
| 98 {value: value, enumerable: false, writable: true, configurable: true}); | |
| 99 }'''; | |
| 100 | |
| 101 /** | |
| 102 * Code for doing the dynamic dispatch on JavaScript prototypes that are not | |
| 103 * available at compile-time. Each property of a native Dart class | |
| 104 * is registered through this function, which is called with the | |
| 105 * following pattern: | |
| 106 * | |
| 107 * $dynamic('propertyName').prototypeName = // JS code | |
| 108 * | |
| 109 * What this function does is: | |
| 110 * - Creates a map of { prototypeName: JS code }. | |
| 111 * - Attaches 'propertyName' to the JS Object prototype that will | |
| 112 * intercept at runtime all calls to propertyName. | |
| 113 * - Sets the value of 'propertyName' to a function that queries the | |
| 114 * map with the prototype of 'this', patches the prototype of | |
| 115 * 'this' with the found JS code, and invokes the JS code. | |
| 116 * | |
| 117 */ | |
| 118 String buildDynamicFunctionCode() { | |
| 119 ClassElement noSuchMethodException = | |
| 120 compiler.coreLibrary.find(Compiler.NO_SUCH_METHOD_EXCEPTION); | |
| 121 Element helper = compiler.findHelper(new SourceString('captureStackTrace')); | |
| 122 String capture = compiler.namer.isolateAccess(helper); | |
| 123 String exception = compiler.namer.isolateAccess(noSuchMethodException); | |
| 124 | |
| 125 return ''' | |
| 126 function(name) { | |
| 127 var f = Object.prototype[name]; | |
| 128 if (f && f.methods) return f.methods; | |
| 129 | |
| 130 var methods = {}; | |
| 131 // If there is a method attached to the Dart Object class, use it as | |
| 132 // the method to call in case no method is registered for that type. | |
| 133 var dartMethod = ${compiler.emitter.objectClassName}.prototype[name]; | |
| 134 if (dartMethod) methods.Object = dartMethod; | |
| 135 function dynamicBind() { | |
| 136 // Find the target method | |
| 137 var obj = this; | |
| 138 var tag = $typeNameOfName(obj); | |
| 139 var method = methods[tag]; | |
| 140 if (!method) { | |
| 141 var table = $dynamicMetadataName; | |
| 142 for (var i = 0; i < table.length; i++) { | |
| 143 var entry = table[i]; | |
| 144 if (entry.map.hasOwnProperty(tag)) { | |
| 145 method = methods[entry.tag]; | |
| 146 if (method) break; | |
| 147 } | |
| 148 } | |
| 149 } | |
| 150 method = method || methods.Object; | |
| 151 | |
| 152 if (method == null) { | |
| 153 method = function() { | |
| 154 throw $capture(new $exception(obj, name, arguments)); | |
| 155 }; | |
| 156 } | |
| 157 | |
| 158 var proto = Object.getPrototypeOf(obj); | |
| 159 var nullCheckMethod = function() { | |
| 160 var res = method.apply(this, Array.prototype.slice.call(arguments)); | |
| 161 return res === null ? (void 0) : res; | |
| 162 } | |
| 163 if (!proto.hasOwnProperty(name)) { | |
| 164 $defPropName(proto, name, nullCheckMethod); | |
| 165 } | |
| 166 | |
| 167 return nullCheckMethod.apply(this, Array.prototype.slice.call(arguments)); | |
| 168 }; | |
| 169 dynamicBind.methods = methods; | |
| 170 $defPropName(Object.prototype, name, dynamicBind); | |
| 171 return methods; | |
| 172 }'''; | |
| 173 } | |
| 174 | |
| 175 String buildDynamicMetadataCode() => ''' | |
| 176 if (typeof $dynamicMetadataName == 'undefined') $dynamicMetadataName = [];'''; | |
| 177 | |
| 178 // This method will be called for 'is' checks on native types. | |
| 179 // It takes the object on which the 'is' check is being done, and the | |
| 180 // property name for the type check. The method patches the real | |
| 181 // prototype of the object with the value from the Dart object | |
| 182 // (see [generateNativeClass]). | |
| 183 String buildDynamicIsCheckCode() { | |
| 184 ClassElement objectClass = | |
| 185 compiler.coreLibrary.find(const SourceString('Object')); | |
| 186 return ''' | |
| 187 function(obj, isCheck) { | |
| 188 if (obj.constructor === Array) return false; | |
| 189 var proto = Object.getPrototypeOf(obj); | |
| 190 // Check if the Dart object corresponding to this class has the property. | |
| 191 var res = | |
| 192 !!${compiler.namer.CURRENT_ISOLATE}.native[$typeNameOfName(obj)][isCheck]; | |
| 193 res = res || false; | |
| 194 $defPropName(proto, isCheck, res); | |
| 195 return res; | |
| 196 }'''; | |
| 197 } | 62 } |
| 198 | 63 |
| 199 String buildNativePropertyCode() => ''' | 64 void generateNativeLiteral(ClassElement classElement) { |
| 200 ${compiler.namer.ISOLATE}.prototype.native = {};'''; | |
| 201 | |
| 202 String buildDynamicSetMetadataCode() => """ | |
| 203 function(inputTable) { | |
| 204 // TODO: Deal with light isolates. | |
| 205 var table = []; | |
| 206 for (var i = 0; i < inputTable.length; i++) { | |
| 207 var tag = inputTable[i][0]; | |
| 208 var tags = inputTable[i][1]; | |
| 209 var map = {}; | |
| 210 var tagNames = tags.split('|'); | |
| 211 for (var j = 0; j < tagNames.length; j++) { | |
| 212 map[tagNames[j]] = true; | |
| 213 } | |
| 214 table.push({tag: tag, tags: tags, map: map}); | |
| 215 } | |
| 216 $dynamicMetadataName = table; | |
| 217 }"""; | |
| 218 | |
| 219 | |
| 220 String get dynamicName() => '${compiler.namer.ISOLATE}.\$dynamic'; | |
| 221 String get defPropName() => '${compiler.namer.ISOLATE}.\$defProp'; | |
| 222 String get typeNameOfName() => '${compiler.namer.ISOLATE}.\$typeNameOf'; | |
| 223 String get dynamicMetadataName() => | |
| 224 '${compiler.namer.ISOLATE}.\$dynamicMetatada'; | |
| 225 String get dynamicIsCheckName() => | |
| 226 '${compiler.namer.ISOLATE}.\$dynamicIsCheck'; | |
| 227 String get dynamicSetMetadataName() => | |
| 228 '${compiler.namer.ISOLATE}.\$dynamicSetMetatada'; | |
| 229 | |
| 230 void addDynamicFunctionIfNecessary(StringBuffer buffer) { | |
| 231 if (addedDynamicFunction) return; | |
| 232 addedDynamicFunction = true; | |
| 233 addTypeNameOfFunctionIfNecessary(buffer); | |
| 234 buffer.add('$dynamicName = '); | |
| 235 buffer.add(buildDynamicFunctionCode()); | |
| 236 buffer.add('\n'); | |
| 237 buffer.add(buildDynamicMetadataCode()); | |
| 238 buffer.add('\n'); | |
| 239 } | |
| 240 | |
| 241 void addTypeNameOfFunctionIfNecessary(StringBuffer buffer) { | |
| 242 if (addedTypeNameOfFunction) return; | |
| 243 addedTypeNameOfFunction = true; | |
| 244 addDefPropFunctionIfNecessary(buffer); | |
| 245 buffer.add('$typeNameOfName = '); | |
| 246 buffer.add(TYPE_NAME_OF_FUNCTION); | |
| 247 buffer.add('\n'); | |
| 248 } | |
| 249 | |
| 250 void addDefPropFunctionIfNecessary(StringBuffer buffer) { | |
| 251 if (addedDefPropFunction) return; | |
| 252 addedDefPropFunction = true; | |
| 253 buffer.add('$defPropName = '); | |
| 254 buffer.add(DEF_PROP_FUNCTION); | |
| 255 buffer.add('\n'); | |
| 256 } | |
| 257 | |
| 258 void addNativePropertyIfNecessary(StringBuffer buffer) { | |
| 259 if (addedNativeProperty) return; | |
| 260 addedNativeProperty = true; | |
| 261 buffer.add(buildNativePropertyCode()); | |
| 262 buffer.add('\n'); | |
| 263 } | |
| 264 | |
| 265 void generateNativeLiteral(ClassElement classElement, StringBuffer buffer) { | |
| 266 String quotedNative = classElement.nativeName.slowToString(); | 65 String quotedNative = classElement.nativeName.slowToString(); |
| 267 String nativeCode = quotedNative.substring(2, quotedNative.length - 1); | 66 String nativeCode = quotedNative.substring(2, quotedNative.length - 1); |
| 268 String className = compiler.namer.getName(classElement); | 67 String className = compiler.namer.getName(classElement); |
| 269 buffer.add(className); | 68 buffer.add(className); |
| 270 buffer.add(' = '); | 69 buffer.add(' = '); |
| 271 buffer.add(nativeCode); | 70 buffer.add(nativeCode); |
| 272 buffer.add(';\n'); | 71 buffer.add(';\n'); |
| 273 | 72 |
| 274 String attachTo(name) => "$className.$name"; | 73 String attachTo(name) => "$className.$name"; |
| 275 | 74 |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 292 String toNativeName(ClassElement cls) { | 91 String toNativeName(ClassElement cls) { |
| 293 String quotedName = cls.nativeName.slowToString(); | 92 String quotedName = cls.nativeName.slowToString(); |
| 294 if (isNativeGlobal(quotedName)) { | 93 if (isNativeGlobal(quotedName)) { |
| 295 // Global object, just be like the other types for now. | 94 // Global object, just be like the other types for now. |
| 296 return quotedName.substring(3, quotedName.length - 1); | 95 return quotedName.substring(3, quotedName.length - 1); |
| 297 } else { | 96 } else { |
| 298 return quotedName.substring(2, quotedName.length - 1); | 97 return quotedName.substring(2, quotedName.length - 1); |
| 299 } | 98 } |
| 300 } | 99 } |
| 301 | 100 |
| 302 void generateNativeClass(ClassElement classElement, StringBuffer buffer) { | 101 void generateNativeClass(ClassElement classElement) { |
| 303 nativeClasses.add(classElement); | 102 nativeClasses.add(classElement); |
| 304 | 103 |
| 305 assert(classElement.backendMembers.isEmpty()); | 104 assert(classElement.backendMembers.isEmpty()); |
| 306 String quotedName = classElement.nativeName.slowToString(); | 105 String quotedName = classElement.nativeName.slowToString(); |
| 307 if (isNativeLiteral(quotedName)) { | 106 if (isNativeLiteral(quotedName)) { |
| 308 generateNativeLiteral(classElement, buffer); | 107 generateNativeLiteral(classElement); |
| 309 // The native literal kind needs to be dealt with specially when | 108 // The native literal kind needs to be dealt with specially when |
| 310 // generating code for it. | 109 // generating code for it. |
| 311 return; | 110 return; |
| 312 } | 111 } |
| 313 | 112 |
| 314 String nativeName = toNativeName(classElement); | 113 String nativeName = toNativeName(classElement); |
| 315 bool hasUsedSelectors = false; | 114 bool hasUsedSelectors = false; |
| 316 | 115 |
| 317 String attachTo(String name) { | 116 String attachTo(String name) { |
| 318 hasUsedSelectors = true; | 117 hasUsedSelectors = true; |
| 319 addDynamicFunctionIfNecessary(buffer); | |
| 320 return "$dynamicName('$name').$nativeName"; | 118 return "$dynamicName('$name').$nativeName"; |
| 321 } | 119 } |
| 322 | 120 |
| 323 for (Element member in classElement.members) { | 121 for (Element member in classElement.members) { |
| 324 if (member.isInstanceMember()) { | 122 if (member.isInstanceMember()) { |
| 325 compiler.emitter.addInstanceMember( | 123 compiler.emitter.addInstanceMember( |
| 326 member, attachTo, buffer, isNative: true); | 124 member, attachTo, buffer, isNative: true); |
| 327 } | 125 } |
| 328 } | 126 } |
| 329 | 127 |
| 330 addNativePropertyIfNecessary(buffer); | 128 // Create an object that contains the is checks properties. |
| 331 // Create an object that contains the is checks properties. The | 129 buffer.add('$isChecksHelperName.$nativeName = { '); |
| 332 // object will be used when entering [buildDynamicIsCheckCode]. | |
| 333 buffer.add('${compiler.namer.ISOLATE}.prototype.native.$nativeName = { '); | |
| 334 List<String> tests = <String>[]; | 130 List<String> tests = <String>[]; |
| 335 | 131 |
| 336 ClassElement objectClass = | 132 ClassElement objectClass = |
| 337 compiler.coreLibrary.find(const SourceString('Object')); | 133 compiler.coreLibrary.find(const SourceString('Object')); |
| 338 ClassElement element = classElement; | 134 ClassElement element = classElement; |
| 339 // We need to put the super class is checks too, since a check on | 135 // We need to put the super class is checks too, since a check on |
| 340 // the subclass can happen before a check on the super class | 136 // the subclass can happen before a check on the super class |
| 341 // (which does the patching on the prototype). | 137 // (which does the patching on the prototype). |
| 342 do { | 138 do { |
| 343 compiler.emitter.generateTypeTests(element, (Element other) { | 139 compiler.emitter.generateTypeTests(element, (Element other) { |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 355 List<ClassElement> getDirectSubclasses(ClassElement cls) { | 151 List<ClassElement> getDirectSubclasses(ClassElement cls) { |
| 356 List<ClassElement> result = subtypes[cls]; | 152 List<ClassElement> result = subtypes[cls]; |
| 357 if (result === null) result = const<ClassElement>[]; | 153 if (result === null) result = const<ClassElement>[]; |
| 358 return result; | 154 return result; |
| 359 } | 155 } |
| 360 | 156 |
| 361 void emitParameterStub(Element member, | 157 void emitParameterStub(Element member, |
| 362 String invocationName, | 158 String invocationName, |
| 363 String stubParameters, | 159 String stubParameters, |
| 364 List<String> argumentsBuffer, | 160 List<String> argumentsBuffer, |
| 365 int indexOfLastOptionalArgumentInParameters, | 161 int indexOfLastOptionalArgumentInParameters) { |
| 366 StringBuffer buffer) { | |
| 367 // The target JS function may check arguments.length so we need to | 162 // The target JS function may check arguments.length so we need to |
| 368 // make sure not to pass any unspecified optional arguments to it. | 163 // make sure not to pass any unspecified optional arguments to it. |
| 369 // For example, for the following Dart method: | 164 // For example, for the following Dart method: |
| 370 // foo([x, y, z]); | 165 // foo([x, y, z]); |
| 371 // The call: | 166 // The call: |
| 372 // foo(y: 1) | 167 // foo(y: 1) |
| 373 // must be turned into a JS call to: | 168 // must be turned into a JS call to: |
| 374 // foo(null, y). | 169 // foo(null, y). |
| 375 | 170 |
| 376 List<String> nativeArgumentsBuffer = argumentsBuffer.getRange( | 171 List<String> nativeArgumentsBuffer = argumentsBuffer.getRange( |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 397 buffer.add(' if (Object.getPrototypeOf(this).hasOwnProperty('); | 192 buffer.add(' if (Object.getPrototypeOf(this).hasOwnProperty('); |
| 398 buffer.add("'$invocationName')) {\n"); | 193 buffer.add("'$invocationName')) {\n"); |
| 399 buffer.add(' return this.${member.name.slowToString()}'); | 194 buffer.add(' return this.${member.name.slowToString()}'); |
| 400 buffer.add('($nativeArguments)'); | 195 buffer.add('($nativeArguments)'); |
| 401 buffer.add('\n }\n'); | 196 buffer.add('\n }\n'); |
| 402 buffer.add(' return Object.prototype.$invocationName.call(this'); | 197 buffer.add(' return Object.prototype.$invocationName.call(this'); |
| 403 buffer.add(stubParameters == '' ? '' : ', $stubParameters'); | 198 buffer.add(stubParameters == '' ? '' : ', $stubParameters'); |
| 404 buffer.add(');'); | 199 buffer.add(');'); |
| 405 } | 200 } |
| 406 | 201 |
| 407 void emitDynamicDispatchMetadata(StringBuffer buffer) { | 202 void emitDynamicDispatchMetadata() { |
| 408 // TODO(ngeoffray): emit this conditionally. | |
| 409 addTypeNameOfFunctionIfNecessary(buffer); | |
| 410 buffer.add('$dynamicIsCheckName = '); | |
| 411 buffer.add(buildDynamicIsCheckCode()); | |
| 412 buffer.add('\n'); | |
| 413 | |
| 414 if (classesWithDynamicDispatch.isEmpty()) return; | 203 if (classesWithDynamicDispatch.isEmpty()) return; |
| 415 buffer.add('// ${classesWithDynamicDispatch.length} dynamic classes.\n'); | 204 buffer.add('// ${classesWithDynamicDispatch.length} dynamic classes.\n'); |
| 416 | 205 |
| 417 // Build a pre-order traversal over all the classes and their subclasses. | 206 // Build a pre-order traversal over all the classes and their subclasses. |
| 418 Set<ClassElement> seen = new Set<ClassElement>(); | 207 Set<ClassElement> seen = new Set<ClassElement>(); |
| 419 List<ClassElement> classes = <ClassElement>[]; | 208 List<ClassElement> classes = <ClassElement>[]; |
| 420 void visit(ClassElement cls) { | 209 void visit(ClassElement cls) { |
| 421 if (seen.contains(cls)) return; | 210 if (seen.contains(cls)) return; |
| 422 seen.add(cls); | 211 seen.add(cls); |
| 423 for (final ClassElement subclass in getDirectSubclasses(cls)) { | 212 for (final ClassElement subclass in getDirectSubclasses(cls)) { |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 495 return expression; | 284 return expression; |
| 496 } | 285 } |
| 497 | 286 |
| 498 for (final ClassElement cls in dispatchClasses) { | 287 for (final ClassElement cls in dispatchClasses) { |
| 499 tagDefns[cls] = makeExpression(cls); | 288 tagDefns[cls] = makeExpression(cls); |
| 500 } | 289 } |
| 501 | 290 |
| 502 // Write out a thunk that builds the metadata. | 291 // Write out a thunk that builds the metadata. |
| 503 | 292 |
| 504 if (!tagDefns.isEmpty()) { | 293 if (!tagDefns.isEmpty()) { |
| 505 buffer.add('$dynamicSetMetadataName = '); | |
| 506 buffer.add(buildDynamicSetMetadataCode()); | |
| 507 buffer.add(';\n\n'); | |
| 508 | |
| 509 buffer.add('(function(){\n'); | 294 buffer.add('(function(){\n'); |
| 510 | 295 |
| 511 for (final String varName in varNames) { | 296 for (final String varName in varNames) { |
| 512 buffer.add(' var ${varName} = ${varDefns[varName]};\n'); | 297 buffer.add(' var ${varName} = ${varDefns[varName]};\n'); |
| 513 } | 298 } |
| 514 | 299 |
| 515 buffer.add(' var table = [\n'); | 300 buffer.add(' var table = [\n'); |
| 516 buffer.add( | 301 buffer.add( |
| 517 ' // [dynamic-dispatch-tag, ' | 302 ' // [dynamic-dispatch-tag, ' |
| 518 'tags of classes implementing dynamic-dispatch-tag]'); | 303 'tags of classes implementing dynamic-dispatch-tag]'); |
| 519 bool needsComma = false; | 304 bool needsComma = false; |
| 520 List<String> entries = <String>[]; | 305 List<String> entries = <String>[]; |
| 521 for (final ClassElement cls in dispatchClasses) { | 306 for (final ClassElement cls in dispatchClasses) { |
| 522 String clsName = toNativeName(cls); | 307 String clsName = toNativeName(cls); |
| 523 entries.add("\n ['$clsName', ${tagDefns[cls]}]"); | 308 entries.add("\n ['$clsName', ${tagDefns[cls]}]"); |
| 524 } | 309 } |
| 525 buffer.add(Strings.join(entries, ',')); | 310 buffer.add(Strings.join(entries, ',')); |
| 526 buffer.add('];\n'); | 311 buffer.add('];\n'); |
| 527 buffer.add('$dynamicSetMetadataName(table);\n'); | 312 buffer.add('$dynamicSetMetadataName(table);\n'); |
| 528 | 313 |
| 529 buffer.add('})();\n'); | 314 buffer.add('})();\n'); |
| 530 } | 315 } |
| 531 } | 316 } |
| 317 | |
| 318 void assembleCode(StringBuffer other) { | |
|
floitsch
2012/03/28 23:36:33
s/other/targetBuffer ?
ngeoffray
2012/03/29 11:38:40
Done.
| |
| 319 if (isChecksHelperName === null) return; | |
| 320 other.add('(function() { $isChecksHelperName = {};\n$buffer\n })();\n'); | |
| 321 } | |
| 532 } | 322 } |
| OLD | NEW |