| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 part of dart2js.js_emitter; | |
| 6 | |
| 7 // TODO(ahe): Share these with js_helper.dart. | |
| 8 const FUNCTION_INDEX = 0; | |
| 9 const NAME_INDEX = 1; | |
| 10 const CALL_NAME_INDEX = 2; | |
| 11 const REQUIRED_PARAMETER_INDEX = 3; | |
| 12 const OPTIONAL_PARAMETER_INDEX = 4; | |
| 13 const DEFAULT_ARGUMENTS_INDEX = 5; | |
| 14 | |
| 15 const bool VALIDATE_DATA = false; | |
| 16 | |
| 17 // TODO(zarah): Rename this when renaming this file. | |
| 18 String get parseReflectionDataName => 'parseReflectionData'; | |
| 19 | |
| 20 jsAst.Statement getReflectionDataParser(OldEmitter oldEmitter, | |
| 21 JavaScriptBackend backend, | |
| 22 bool needsNativeSupport) { | |
| 23 Namer namer = backend.namer; | |
| 24 Compiler compiler = backend.compiler; | |
| 25 CodeEmitterTask emitter = backend.emitter; | |
| 26 | |
| 27 String reflectableField = namer.reflectableField; | |
| 28 String reflectionInfoField = namer.reflectionInfoField; | |
| 29 String reflectionNameField = namer.reflectionNameField; | |
| 30 String metadataIndexField = namer.metadataIndexField; | |
| 31 String defaultValuesField = namer.defaultValuesField; | |
| 32 String methodsWithOptionalArgumentsField = | |
| 33 namer.methodsWithOptionalArgumentsField; | |
| 34 | |
| 35 String unmangledNameIndex = backend.mustRetainMetadata | |
| 36 ? ' 3 * optionalParameterCount + 2 * requiredParameterCount + 3' | |
| 37 : ' 2 * optionalParameterCount + requiredParameterCount + 3'; | |
| 38 | |
| 39 jsAst.Expression typeInformationAccess = | |
| 40 emitter.generateEmbeddedGlobalAccess(embeddedNames.TYPE_INFORMATION); | |
| 41 jsAst.Expression globalFunctionsAccess = | |
| 42 emitter.generateEmbeddedGlobalAccess(embeddedNames.GLOBAL_FUNCTIONS); | |
| 43 jsAst.Expression staticsAccess = | |
| 44 emitter.generateEmbeddedGlobalAccess(embeddedNames.STATICS); | |
| 45 jsAst.Expression interceptedNamesAccess = | |
| 46 emitter.generateEmbeddedGlobalAccess(embeddedNames.INTERCEPTED_NAMES); | |
| 47 jsAst.Expression mangledGlobalNamesAccess = | |
| 48 emitter.generateEmbeddedGlobalAccess(embeddedNames.MANGLED_GLOBAL_NAMES); | |
| 49 jsAst.Expression mangledNamesAccess = | |
| 50 emitter.generateEmbeddedGlobalAccess(embeddedNames.MANGLED_NAMES); | |
| 51 jsAst.Expression librariesAccess = | |
| 52 emitter.generateEmbeddedGlobalAccess(embeddedNames.LIBRARIES); | |
| 53 jsAst.Expression typesAccess = | |
| 54 emitter.generateEmbeddedGlobalAccess(embeddedNames.TYPES); | |
| 55 | |
| 56 | |
| 57 jsAst.Statement processClassData = js.statement('''{ | |
| 58 // For convenience, this method can be called with a prototype as argument | |
| 59 // or, if it was bound to an object, by invoking it as a method. Therefore, | |
| 60 // if prototype is undefined, this is used as prototype. | |
| 61 function finishAddStubsHelper(prototype) { | |
| 62 var prototype = prototype || this; | |
| 63 var object; | |
| 64 while (prototype.#deferredAction != #markerFun) { | |
| 65 if (prototype.hasOwnProperty(#deferredActionString)) { | |
| 66 delete prototype.#deferredAction; // Intended to make it slow, too. | |
| 67 var properties = Object.keys(prototype); | |
| 68 for (var index = 0; index < properties.length; index++) { | |
| 69 var property = properties[index]; | |
| 70 var firstChar = property.charCodeAt(0); | |
| 71 var elem; | |
| 72 // We have to filter out some special properties that are used for | |
| 73 // metadata in descriptors. Currently, we filter everything that | |
| 74 // starts with + or *. This has to stay in sync with the special | |
| 75 // properties that are used by processClassData below. | |
| 76 if (property !== "${namer.classDescriptorProperty}" && | |
| 77 property !== "$reflectableField" && | |
| 78 firstChar !== 43 && // 43 is aka "+". | |
| 79 firstChar !== 42 && // 42 is aka "*" | |
| 80 (elem = prototype[property]) != null && | |
| 81 elem.constructor === Array && | |
| 82 property !== "<>") { | |
| 83 addStubs(prototype, elem, property, false, []); | |
| 84 } | |
| 85 } | |
| 86 convertToFastObject(prototype); | |
| 87 } | |
| 88 prototype = prototype.__proto__; | |
| 89 } | |
| 90 } | |
| 91 | |
| 92 function processClassData(cls, descriptor, processedClasses) { | |
| 93 descriptor = convertToSlowObject(descriptor); // Use a slow object. | |
| 94 var previousProperty; | |
| 95 var properties = Object.keys(descriptor); | |
| 96 var hasDeferredWork = false; | |
| 97 var shouldDeferWork = supportsDirectProtoAccess && cls != #objectClassName; | |
| 98 for (var i = 0; i < properties.length; i++) { | |
| 99 var property = properties[i]; | |
| 100 var firstChar = property.charCodeAt(0); | |
| 101 if (property === "static") { | |
| 102 processStatics(#embeddedStatics[cls] = descriptor.static, | |
| 103 processedClasses); | |
| 104 delete descriptor.static; | |
| 105 } else if (firstChar === 43) { // 43 is "+". | |
| 106 mangledNames[previousProperty] = property.substring(1); | |
| 107 var flag = descriptor[property]; | |
| 108 if (flag > 0) | |
| 109 descriptor[previousProperty].$reflectableField = flag; | |
| 110 } else if (firstChar === 42) { // 42 is "*" | |
| 111 descriptor[previousProperty].$defaultValuesField = descriptor[property]; | |
| 112 var optionalMethods = descriptor.$methodsWithOptionalArgumentsField; | |
| 113 if (!optionalMethods) { | |
| 114 descriptor.$methodsWithOptionalArgumentsField = optionalMethods={} | |
| 115 } | |
| 116 optionalMethods[property] = previousProperty; | |
| 117 } else { | |
| 118 var elem = descriptor[property]; | |
| 119 if (property !== "${namer.classDescriptorProperty}" && | |
| 120 elem != null && | |
| 121 elem.constructor === Array && | |
| 122 property !== "<>") { | |
| 123 if (shouldDeferWork) { | |
| 124 hasDeferredWork = true; | |
| 125 } else { | |
| 126 addStubs(descriptor, elem, property, false, []); | |
| 127 } | |
| 128 } else { | |
| 129 previousProperty = property; | |
| 130 } | |
| 131 } | |
| 132 } | |
| 133 | |
| 134 if (hasDeferredWork) | |
| 135 descriptor.#deferredAction = finishAddStubsHelper; | |
| 136 | |
| 137 /* The 'fields' are either a constructor function or a | |
| 138 * string encoding fields, constructor and superclass. Gets the | |
| 139 * superclass and fields in the format | |
| 140 * 'Super;field1,field2' | |
| 141 * from the CLASS_DESCRIPTOR_PROPERTY property on the descriptor. | |
| 142 */ | |
| 143 var classData = descriptor["${namer.classDescriptorProperty}"], | |
| 144 split, supr, fields = classData; | |
| 145 | |
| 146 if (#hasRetainedMetadata) | |
| 147 if (typeof classData == "object" && | |
| 148 classData instanceof Array) { | |
| 149 classData = fields = classData[0]; | |
| 150 } | |
| 151 // ${ClassBuilder.fieldEncodingDescription}. | |
| 152 var s = fields.split(";"); | |
| 153 fields = s[1] == "" ? [] : s[1].split(","); | |
| 154 supr = s[0]; | |
| 155 // ${ClassBuilder.functionTypeEncodingDescription}. | |
| 156 split = supr.split(":"); | |
| 157 if (split.length == 2) { | |
| 158 supr = split[0]; | |
| 159 var functionSignature = split[1]; | |
| 160 if (functionSignature) | |
| 161 descriptor.${namer.operatorSignature} = function(s) { | |
| 162 return function() { | |
| 163 return #types[s]; | |
| 164 }; | |
| 165 }(functionSignature); | |
| 166 } | |
| 167 | |
| 168 if (supr) processedClasses.pending[cls] = supr; | |
| 169 if (#notInCspMode) { | |
| 170 processedClasses.combinedConstructorFunction += defineClass(cls, fields); | |
| 171 processedClasses.constructorsList.push(cls); | |
| 172 } | |
| 173 processedClasses.collected[cls] = [globalObject, descriptor]; | |
| 174 classes.push(cls); | |
| 175 } | |
| 176 }''', {'deferredAction': namer.deferredAction, | |
| 177 'deferredActionString': js.string(namer.deferredAction), | |
| 178 'embeddedStatics': staticsAccess, | |
| 179 'hasRetainedMetadata': backend.hasRetainedMetadata, | |
| 180 'markerFun': oldEmitter.markerFun, | |
| 181 'types': typesAccess, | |
| 182 'notInCspMode': !compiler.useContentSecurityPolicy, | |
| 183 'objectClassName': | |
| 184 js.string(namer.runtimeTypeName(compiler.objectClass))}); | |
| 185 | |
| 186 // TODO(zarah): Remove empty else branches in output when if(#hole) is false. | |
| 187 jsAst.Statement processStatics = js.statement(''' | |
| 188 function processStatics(descriptor, processedClasses) { | |
| 189 var properties = Object.keys(descriptor); | |
| 190 for (var i = 0; i < properties.length; i++) { | |
| 191 var property = properties[i]; | |
| 192 if (property === "${namer.classDescriptorProperty}") continue; | |
| 193 var element = descriptor[property]; | |
| 194 var firstChar = property.charCodeAt(0); | |
| 195 var previousProperty; | |
| 196 if (firstChar === 43) { // 43 is "+". | |
| 197 mangledGlobalNames[previousProperty] = property.substring(1); | |
| 198 var flag = descriptor[property]; | |
| 199 if (flag > 0) | |
| 200 descriptor[previousProperty].$reflectableField = flag; | |
| 201 if (element && element.length) | |
| 202 #typeInformation[previousProperty] = element; | |
| 203 } else if (firstChar === 42) { // 42 is "*" | |
| 204 globalObject[previousProperty].$defaultValuesField = element; | |
| 205 var optionalMethods = descriptor.$methodsWithOptionalArgumentsField; | |
| 206 if (!optionalMethods) { | |
| 207 descriptor.$methodsWithOptionalArgumentsField = optionalMethods = {} | |
| 208 } | |
| 209 optionalMethods[property] = previousProperty; | |
| 210 } else if (typeof element === "function") { | |
| 211 globalObject[previousProperty = property] = element; | |
| 212 functions.push(property); | |
| 213 #globalFunctions[property] = element; | |
| 214 } else if (element.constructor === Array) { | |
| 215 if (#needsStructuredMemberInfo) { | |
| 216 addStubs(globalObject, element, property, true, functions); | |
| 217 } | |
| 218 } else { | |
| 219 // We will not enter this case if no classes are defined. | |
| 220 if (#hasClasses) { | |
| 221 previousProperty = property; | |
| 222 processClassData(property, element, processedClasses); | |
| 223 } | |
| 224 } | |
| 225 } | |
| 226 } | |
| 227 ''', {'typeInformation': typeInformationAccess, | |
| 228 'globalFunctions': globalFunctionsAccess, | |
| 229 'hasClasses': oldEmitter.needsClassSupport, | |
| 230 'needsStructuredMemberInfo': oldEmitter.needsStructuredMemberInfo}); | |
| 231 | |
| 232 | |
| 233 /** | |
| 234 * See [dart2js.js_emitter.ContainerBuilder.addMemberMethod] for format of | |
| 235 * [array]. | |
| 236 */ | |
| 237 jsAst.Statement addStubs = js.statement(''' | |
| 238 // Processes the stub declaration given by [array] and stores the results | |
| 239 // in the corresponding [prototype]. [name] is the property name in | |
| 240 // [prototype] that the stub declaration belongs to. | |
| 241 // If [isStatic] is true, the property being processed belongs to a static | |
| 242 // function and thus is stored as a global. In that case we also add all | |
| 243 // generated functions to the [functions] array, which is used by the mirrors | |
| 244 // system to enumerate all static functions of a library. For non-static | |
| 245 // functions we might still add some functions to [functions] but the | |
| 246 // information is thrown away at the call site. This is to avoid conditionals.
| |
| 247 function addStubs(prototype, array, name, isStatic, functions) { | |
| 248 var index = $FUNCTION_INDEX, alias = array[index], f; | |
| 249 if (typeof alias == "string") { | |
| 250 f = array[++index]; | |
| 251 } else { | |
| 252 f = alias; | |
| 253 alias = name; | |
| 254 } | |
| 255 var funcs = [prototype[name] = prototype[alias] = f]; | |
| 256 f.\$stubName = name; | |
| 257 functions.push(name); | |
| 258 for (; index < array.length; index += 2) { | |
| 259 f = array[index + 1]; | |
| 260 if (typeof f != "function") break; | |
| 261 f.\$stubName = ${readString("array", "index + 2")}; | |
| 262 funcs.push(f); | |
| 263 if (f.\$stubName) { | |
| 264 prototype[f.\$stubName] = f; | |
| 265 functions.push(f.\$stubName); | |
| 266 } | |
| 267 } | |
| 268 index++; | |
| 269 for (var i = 0; i < funcs.length; index++, i++) { | |
| 270 funcs[i].\$callName = ${readString("array", "index")}; | |
| 271 } | |
| 272 var getterStubName = ${readString("array", "index")}; | |
| 273 array = array.slice(++index); | |
| 274 var requiredParameterInfo = ${readInt("array", "0")}; | |
| 275 var requiredParameterCount = requiredParameterInfo >> 1; | |
| 276 var isAccessor = (requiredParameterInfo & 1) === 1; | |
| 277 var isSetter = requiredParameterInfo === 3; | |
| 278 var isGetter = requiredParameterInfo === 1; | |
| 279 var optionalParameterInfo = ${readInt("array", "1")}; | |
| 280 var optionalParameterCount = optionalParameterInfo >> 1; | |
| 281 var optionalParametersAreNamed = (optionalParameterInfo & 1) === 1; | |
| 282 var isIntercepted = | |
| 283 requiredParameterCount + optionalParameterCount != funcs[0].length; | |
| 284 var functionTypeIndex = ${readFunctionType("array", "2")}; | |
| 285 var unmangledNameIndex = $unmangledNameIndex; | |
| 286 | |
| 287 if (getterStubName) { | |
| 288 f = tearOff(funcs, array, isStatic, name, isIntercepted); | |
| 289 prototype[name].\$getter = f; | |
| 290 f.\$getterStub = true; | |
| 291 // Used to create an isolate using spawnFunction. | |
| 292 if (isStatic) { | |
| 293 #globalFunctions[name] = f; | |
| 294 functions.push(getterStubName); | |
| 295 } | |
| 296 prototype[getterStubName] = f; | |
| 297 funcs.push(f); | |
| 298 f.\$stubName = getterStubName; | |
| 299 f.\$callName = null; | |
| 300 // Update the interceptedNames map (which only exists if `invokeOn` was | |
| 301 // enabled). | |
| 302 if (#enabledInvokeOn) | |
| 303 if (isIntercepted) #interceptedNames[getterStubName] = 1; | |
| 304 } | |
| 305 | |
| 306 if (#usesMangledNames) { | |
| 307 var isReflectable = array.length > unmangledNameIndex; | |
| 308 if (isReflectable) { | |
| 309 for (var i = 0; i < funcs.length; i++) { | |
| 310 funcs[i].$reflectableField = 1; | |
| 311 funcs[i].$reflectionInfoField = array; | |
| 312 } | |
| 313 var mangledNames = isStatic ? #mangledGlobalNames : #mangledNames; | |
| 314 var unmangledName = ${readString("array", "unmangledNameIndex")}; | |
| 315 // The function is either a getter, a setter, or a method. | |
| 316 // If it is a method, it might also have a tear-off closure. | |
| 317 // The unmangledName is the same as the getter-name. | |
| 318 var reflectionName = unmangledName; | |
| 319 if (getterStubName) mangledNames[getterStubName] = reflectionName; | |
| 320 if (isSetter) { | |
| 321 reflectionName += "="; | |
| 322 } else if (!isGetter) { | |
| 323 reflectionName += ":" + requiredParameterCount + | |
| 324 ":" + optionalParameterCount; | |
| 325 } | |
| 326 mangledNames[name] = reflectionName; | |
| 327 funcs[0].$reflectionNameField = reflectionName; | |
| 328 funcs[0].$metadataIndexField = unmangledNameIndex + 1; | |
| 329 if (optionalParameterCount) prototype[unmangledName + "*"] = funcs[0]; | |
| 330 } | |
| 331 } | |
| 332 } | |
| 333 ''', {'globalFunctions': globalFunctionsAccess, | |
| 334 'enabledInvokeOn': compiler.enabledInvokeOn, | |
| 335 'interceptedNames': interceptedNamesAccess, | |
| 336 'usesMangledNames': | |
| 337 compiler.mirrorsLibrary != null || compiler.enabledFunctionApply, | |
| 338 'mangledGlobalNames': mangledGlobalNamesAccess, | |
| 339 'mangledNames': mangledNamesAccess}); | |
| 340 | |
| 341 List<jsAst.Statement> tearOffCode = buildTearOffCode(backend); | |
| 342 | |
| 343 jsAst.ObjectInitializer interceptedNamesSet = | |
| 344 oldEmitter.interceptorEmitter.generateInterceptedNamesSet(); | |
| 345 | |
| 346 jsAst.Statement init = js.statement('''{ | |
| 347 var functionCounter = 0; | |
| 348 if (!#libraries) #libraries = []; | |
| 349 if (!#mangledNames) #mangledNames = map(); | |
| 350 if (!#mangledGlobalNames) #mangledGlobalNames = map(); | |
| 351 if (!#statics) #statics = map(); | |
| 352 if (!#typeInformation) #typeInformation = map(); | |
| 353 if (!#globalFunctions) #globalFunctions = map(); | |
| 354 if (#enabledInvokeOn) | |
| 355 if (!#interceptedNames) #interceptedNames = #interceptedNamesSet; | |
| 356 var libraries = #libraries; | |
| 357 var mangledNames = #mangledNames; | |
| 358 var mangledGlobalNames = #mangledGlobalNames; | |
| 359 var hasOwnProperty = Object.prototype.hasOwnProperty; | |
| 360 var length = reflectionData.length; | |
| 361 var processedClasses = map(); | |
| 362 processedClasses.collected = map(); | |
| 363 processedClasses.pending = map(); | |
| 364 if (#notInCspMode) { | |
| 365 processedClasses.constructorsList = []; | |
| 366 // For every class processed [processedClasses.combinedConstructorFunction] | |
| 367 // will be updated with the corresponding constructor function. | |
| 368 processedClasses.combinedConstructorFunction = | |
| 369 "function \$reflectable(fn){fn.$reflectableField=1;return fn};\\n"+ | |
| 370 "var \$desc;\\n"; | |
| 371 } | |
| 372 for (var i = 0; i < length; i++) { | |
| 373 var data = reflectionData[i]; | |
| 374 | |
| 375 // [data] contains these elements: | |
| 376 // 0. The library name (not unique). | |
| 377 // 1. The library URI (unique). | |
| 378 // 2. A function returning the metadata associated with this library. | |
| 379 // 3. The global object to use for this library. | |
| 380 // 4. An object literal listing the members of the library. | |
| 381 // 5. This element is optional and if present it is true and signals that this | |
| 382 // library is the root library (see dart:mirrors IsolateMirror.rootLibrary). | |
| 383 // | |
| 384 // The entries of [data] are built in [assembleProgram] above. | |
| 385 | |
| 386 var name = data[0]; | |
| 387 var uri = data[1]; | |
| 388 var metadata = data[2]; | |
| 389 var globalObject = data[3]; | |
| 390 var descriptor = data[4]; | |
| 391 var isRoot = !!data[5]; | |
| 392 var fields = descriptor && descriptor["${namer.classDescriptorProperty}"]; | |
| 393 if (fields instanceof Array) fields = fields[0]; | |
| 394 var classes = []; | |
| 395 var functions = []; | |
| 396 processStatics(descriptor, processedClasses); | |
| 397 libraries.push([name, uri, classes, functions, metadata, fields, isRoot, | |
| 398 globalObject]); | |
| 399 } | |
| 400 if (#needsClassSupport) finishClasses(processedClasses); | |
| 401 }''', {'libraries': librariesAccess, | |
| 402 'mangledNames': mangledNamesAccess, | |
| 403 'mangledGlobalNames': mangledGlobalNamesAccess, | |
| 404 'statics': staticsAccess, | |
| 405 'typeInformation': typeInformationAccess, | |
| 406 'globalFunctions': globalFunctionsAccess, | |
| 407 'enabledInvokeOn': compiler.enabledInvokeOn, | |
| 408 'interceptedNames': interceptedNamesAccess, | |
| 409 'interceptedNamesSet': interceptedNamesSet, | |
| 410 'notInCspMode': !compiler.useContentSecurityPolicy, | |
| 411 'needsClassSupport': oldEmitter.needsClassSupport}); | |
| 412 | |
| 413 jsAst.Expression allClassesAccess = | |
| 414 emitter.generateEmbeddedGlobalAccess(embeddedNames.ALL_CLASSES); | |
| 415 | |
| 416 // Class descriptions are collected in a JS object. | |
| 417 // 'finishClasses' takes all collected descriptions and sets up | |
| 418 // the prototype. | |
| 419 // Once set up, the constructors prototype field satisfy: | |
| 420 // - it contains all (local) members. | |
| 421 // - its internal prototype (__proto__) points to the superclass' | |
| 422 // prototype field. | |
| 423 // - the prototype's constructor field points to the JavaScript | |
| 424 // constructor. | |
| 425 // For engines where we have access to the '__proto__' we can manipulate | |
| 426 // the object literal directly. For other engines we have to create a new | |
| 427 // object and copy over the members. | |
| 428 jsAst.Statement finishClasses = js.statement('''{ | |
| 429 function finishClasses(processedClasses) { | |
| 430 if (#debugFastObjects) | |
| 431 print("Number of classes: " + | |
| 432 Object.getOwnPropertyNames(processedClasses.collected).length); | |
| 433 | |
| 434 var allClasses = #allClasses; | |
| 435 | |
| 436 if (#inCspMode) { | |
| 437 var constructors = #precompiled(processedClasses.collected); | |
| 438 } | |
| 439 | |
| 440 if (#notInCspMode) { | |
| 441 processedClasses.combinedConstructorFunction += | |
| 442 "return [\\n" + processedClasses.constructorsList.join(",\\n ") + | |
| 443 "\\n]"; | |
| 444 var constructors = | |
| 445 new Function("\$collectedClasses", | |
| 446 processedClasses.combinedConstructorFunction) | |
| 447 (processedClasses.collected); | |
| 448 processedClasses.combinedConstructorFunction = null; | |
| 449 } | |
| 450 | |
| 451 for (var i = 0; i < constructors.length; i++) { | |
| 452 var constructor = constructors[i]; | |
| 453 var cls = constructor.name; | |
| 454 var desc = processedClasses.collected[cls]; | |
| 455 var globalObject = desc[0]; | |
| 456 desc = desc[1]; | |
| 457 if (#isTreeShakingDisabled) | |
| 458 constructor["${namer.metadataField}"] = desc; | |
| 459 allClasses[cls] = constructor; | |
| 460 globalObject[cls] = constructor; | |
| 461 } | |
| 462 constructors = null; | |
| 463 | |
| 464 #finishClassFunction; | |
| 465 | |
| 466 #trivialNsmHandlers; | |
| 467 | |
| 468 var properties = Object.keys(processedClasses.pending); | |
| 469 for (var i = 0; i < properties.length; i++) finishClass(properties[i]); | |
| 470 } | |
| 471 }''', {'allClasses': allClassesAccess, | |
| 472 'debugFastObjects': DEBUG_FAST_OBJECTS, | |
| 473 'isTreeShakingDisabled': backend.isTreeShakingDisabled, | |
| 474 'finishClassFunction': oldEmitter.buildFinishClass(needsNativeSupport), | |
| 475 'trivialNsmHandlers': oldEmitter.buildTrivialNsmHandlers(), | |
| 476 'inCspMode': compiler.useContentSecurityPolicy, | |
| 477 'notInCspMode': !compiler.useContentSecurityPolicy, | |
| 478 'precompiled': oldEmitter | |
| 479 .generateEmbeddedGlobalAccess(embeddedNames.PRECOMPILED)}); | |
| 480 | |
| 481 List<jsAst.Statement> incrementalSupport = <jsAst.Statement>[]; | |
| 482 if (compiler.hasIncrementalSupport) { | |
| 483 incrementalSupport.add( | |
| 484 js.statement( | |
| 485 '#.addStubs = addStubs;', [namer.accessIncrementalHelper])); | |
| 486 } | |
| 487 | |
| 488 return js.statement(''' | |
| 489 function $parseReflectionDataName(reflectionData) { | |
| 490 "use strict"; | |
| 491 if (#needsClassSupport) { | |
| 492 #defineClass; | |
| 493 #inheritFrom; | |
| 494 #finishClasses; | |
| 495 #processClassData; | |
| 496 } | |
| 497 #processStatics; | |
| 498 if (#needsStructuredMemberInfo) { | |
| 499 #addStubs; | |
| 500 #tearOffCode; | |
| 501 } | |
| 502 #incrementalSupport; | |
| 503 #init; | |
| 504 }''', { | |
| 505 'defineClass': oldEmitter.defineClassFunction, | |
| 506 'inheritFrom': oldEmitter.buildInheritFrom(), | |
| 507 'processClassData': processClassData, | |
| 508 'processStatics': processStatics, | |
| 509 'incrementalSupport': incrementalSupport, | |
| 510 'addStubs': addStubs, | |
| 511 'tearOffCode': tearOffCode, | |
| 512 'init': init, | |
| 513 'finishClasses': finishClasses, | |
| 514 'needsClassSupport': oldEmitter.needsClassSupport, | |
| 515 'needsStructuredMemberInfo': oldEmitter.needsStructuredMemberInfo}); | |
| 516 } | |
| 517 | |
| 518 String readString(String array, String index) { | |
| 519 return readChecked( | |
| 520 array, index, 'result != null && typeof result != "string"', 'string'); | |
| 521 } | |
| 522 | |
| 523 String readInt(String array, String index) { | |
| 524 return readChecked( | |
| 525 array, index, | |
| 526 'result != null && (typeof result != "number" || (result|0) !== result)', | |
| 527 'int'); | |
| 528 } | |
| 529 | |
| 530 String readFunctionType(String array, String index) { | |
| 531 return readChecked( | |
| 532 array, index, | |
| 533 'result != null && ' | |
| 534 '(typeof result != "number" || (result|0) !== result) && ' | |
| 535 'typeof result != "function"', | |
| 536 'function or int'); | |
| 537 } | |
| 538 | |
| 539 String readChecked(String array, String index, String check, String type) { | |
| 540 if (!VALIDATE_DATA) return '$array[$index]'; | |
| 541 return ''' | |
| 542 (function() { | |
| 543 var result = $array[$index]; | |
| 544 if ($check) { | |
| 545 throw new Error( | |
| 546 name + ": expected value of type \'$type\' at index " + ($index) + | |
| 547 " but got " + (typeof result)); | |
| 548 } | |
| 549 return result; | |
| 550 })()'''; | |
| 551 } | |
| OLD | NEW |