Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(600)

Side by Side Diff: pkg/compiler/lib/src/js_emitter/old_emitter/reflection_data_parser.dart

Issue 1024523003: dart2js: rename and refactor reflection_data_parser. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698