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

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

Issue 693183006: Revert "Move dart2js from sdk/lib/_internal/compiler to pkg/compiler" (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month 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(ahe): This code should be integrated in CodeEmitterTask.finishClasses.
18 jsAst.Expression getReflectionDataParser(String classesCollector,
19 JavaScriptBackend backend) {
20 Namer namer = backend.namer;
21 Compiler compiler = backend.compiler;
22 CodeEmitterTask emitter = backend.emitter;
23
24 String metadataField = '"${namer.metadataField}"';
25 String reflectableField = namer.reflectableField;
26
27 // TODO(ahe): Move this string constants to namer.
28 String reflectionInfoField = r'$reflectionInfo';
29 String reflectionNameField = r'$reflectionName';
30 String metadataIndexField = r'$metadataIndex';
31
32 String defaultValuesField = namer.defaultValuesField;
33 String methodsWithOptionalArgumentsField =
34 namer.methodsWithOptionalArgumentsField;
35
36 String unmangledNameIndex = backend.mustRetainMetadata
37 ? ' 3 * optionalParameterCount + 2 * requiredParameterCount + 3'
38 : ' 2 * optionalParameterCount + requiredParameterCount + 3';
39
40 jsAst.Expression typeInformationAccess =
41 emitter.generateEmbeddedGlobalAccess(embeddedNames.TYPE_INFORMATION);
42 jsAst.Expression globalFunctionsAccess =
43 emitter.generateEmbeddedGlobalAccess(embeddedNames.GLOBAL_FUNCTIONS);
44 jsAst.Expression staticsAccess =
45 emitter.generateEmbeddedGlobalAccess(embeddedNames.STATICS);
46 jsAst.Expression interceptedNamesAccess =
47 emitter.generateEmbeddedGlobalAccess(embeddedNames.INTERCEPTED_NAMES);
48 jsAst.Expression mangledGlobalNamesAccess =
49 emitter.generateEmbeddedGlobalAccess(embeddedNames.MANGLED_GLOBAL_NAMES);
50 jsAst.Expression mangledNamesAccess =
51 emitter.generateEmbeddedGlobalAccess(embeddedNames.MANGLED_NAMES);
52 jsAst.Expression librariesAccess =
53 emitter.generateEmbeddedGlobalAccess(embeddedNames.LIBRARIES);
54
55 jsAst.Statement header = js.statement('''
56 // [map] returns an object literal that V8 shouldn not try to optimize with a
57 // hidden class. This prevents a potential performance problem where V8 tries
58 // to build a hidden class for an object used as a hashMap.
59 // It requires fewer characters to declare a variable as a parameter than
60 // with `var`.
61 function map(x){x=Object.create(null);x.x=0;delete x.x;return x}
62 ''');
63
64 jsAst.Statement processStatics = js.statement('''
65 function processStatics(descriptor) {
66 for (var property in descriptor) {
67 if (!hasOwnProperty.call(descriptor, property)) continue;
68 if (property === "${namer.classDescriptorProperty}") continue;
69 var element = descriptor[property];
70 var firstChar = property.substring(0, 1);
71 var previousProperty;
72 if (firstChar === "+") {
73 mangledGlobalNames[previousProperty] = property.substring(1);
74 var flag = descriptor[property];
75 if (flag > 0)
76 descriptor[previousProperty].$reflectableField = flag;
77 if (element && element.length)
78 #[previousProperty] = element; // embedded typeInformation.
79 } else if (firstChar === "@") {
80 property = property.substring(1);
81 ${namer.currentIsolate}[property][$metadataField] = element;
82 } else if (firstChar === "*") {
83 globalObject[previousProperty].$defaultValuesField = element;
84 var optionalMethods = descriptor.$methodsWithOptionalArgumentsField;
85 if (!optionalMethods) {
86 descriptor.$methodsWithOptionalArgumentsField = optionalMethods = {}
87 }
88 optionalMethods[property] = previousProperty;
89 } else if (typeof element === "function") {
90 globalObject[previousProperty = property] = element;
91 functions.push(property);
92 #[property] = element; // embedded globalFunctions.
93 } else if (element.constructor === Array) {
94 addStubs(globalObject, element, property,
95 true, descriptor, functions);
96 } else {
97 previousProperty = property;
98 var newDesc = {};
99 var previousProp;
100 for (var prop in element) {
101 if (!hasOwnProperty.call(element, prop)) continue;
102 firstChar = prop.substring(0, 1);
103 if (prop === "static") {
104 processStatics(#[property] = element[prop]); // embedded statics.
105 } else if (firstChar === "+") {
106 mangledNames[previousProp] = prop.substring(1);
107 var flag = element[prop];
108 if (flag > 0)
109 element[previousProp].$reflectableField = flag;
110 } else if (firstChar === "@" && prop !== "@") {
111 newDesc[prop.substring(1)][$metadataField] = element[prop];
112 } else if (firstChar === "*") {
113 newDesc[previousProp].$defaultValuesField = element[prop];
114 var optionalMethods = newDesc.$methodsWithOptionalArgumentsField;
115 if (!optionalMethods) {
116 newDesc.$methodsWithOptionalArgumentsField = optionalMethods={}
117 }
118 optionalMethods[prop] = previousProp;
119 } else {
120 var elem = element[prop];
121 if (prop !== "${namer.classDescriptorProperty}" &&
122 elem != null &&
123 elem.constructor === Array &&
124 prop !== "<>") {
125 addStubs(newDesc, elem, prop, false, element, []);
126 } else {
127 newDesc[previousProp = prop] = elem;
128 }
129 }
130 }
131 $classesCollector[property] = [globalObject, newDesc];
132 classes.push(property);
133 }
134 }
135 }
136 ''', [typeInformationAccess, globalFunctionsAccess, staticsAccess]);
137
138
139 /**
140 * See [dart2js.js_emitter.ContainerBuilder.addMemberMethod] for format of
141 * [array].
142 */
143 jsAst.Statement addStubs = js.statement('''
144 function addStubs(descriptor, array, name, isStatic,
145 originalDescriptor, functions) {
146 var f, funcs =
147 [originalDescriptor[name] =
148 descriptor[name] = f = ${readFunction("array", "$FUNCTION_INDEX")}];
149 f.\$stubName = name;
150 functions.push(name);
151 for (var index = $FUNCTION_INDEX; index < array.length; index += 2) {
152 f = array[index + 1];
153 if (typeof f != "function") break;
154 f.\$stubName = ${readString("array", "index + 2")};
155 funcs.push(f);
156 if (f.\$stubName) {
157 originalDescriptor[f.\$stubName] = descriptor[f.\$stubName] = f;
158 functions.push(f.\$stubName);
159 }
160 }
161 for (var i = 0; i < funcs.length; index++, i++) {
162 funcs[i].\$callName = ${readString("array", "index + 1")};
163 }
164 var getterStubName = ${readString("array", "++index")};
165 array = array.slice(++index);
166 var requiredParameterInfo = ${readInt("array", "0")};
167 var requiredParameterCount = requiredParameterInfo >> 1;
168 var isAccessor = (requiredParameterInfo & 1) === 1;
169 var isSetter = requiredParameterInfo === 3;
170 var isGetter = requiredParameterInfo === 1;
171 var optionalParameterInfo = ${readInt("array", "1")};
172 var optionalParameterCount = optionalParameterInfo >> 1;
173 var optionalParametersAreNamed = (optionalParameterInfo & 1) === 1;
174 var isIntercepted =
175 requiredParameterCount + optionalParameterCount != funcs[0].length;
176 var functionTypeIndex = ${readFunctionType("array", "2")};
177 var unmangledNameIndex = $unmangledNameIndex;
178 var isReflectable = array.length > unmangledNameIndex;
179
180 if (getterStubName) {
181 f = tearOff(funcs, array, isStatic, name, isIntercepted);
182 descriptor[name].\$getter = f;
183 f.\$getterStub = true;
184 // Used to create an isolate using spawnFunction.
185 if (isStatic) #[name] = f; // embedded globalFunctions.
186 originalDescriptor[getterStubName] = descriptor[getterStubName] = f;
187 funcs.push(f);
188 if (getterStubName) functions.push(getterStubName);
189 f.\$stubName = getterStubName;
190 f.\$callName = null;
191 if (isIntercepted) #[getterStubName] = true; // embedded interceptedNames.
192 }
193 if (isReflectable) {
194 for (var i = 0; i < funcs.length; i++) {
195 funcs[i].$reflectableField = 1;
196 funcs[i].$reflectionInfoField = array;
197 }
198 var mangledNames = isStatic ? # : #; // embedded mangledGlobalNames, mang ledNames
199 var unmangledName = ${readString("array", "unmangledNameIndex")};
200 // The function is either a getter, a setter, or a method.
201 // If it is a method, it might also have a tear-off closure.
202 // The unmangledName is the same as the getter-name.
203 var reflectionName = unmangledName;
204 if (getterStubName) mangledNames[getterStubName] = reflectionName;
205 if (isSetter) {
206 reflectionName += "=";
207 } else if (!isGetter) {
208 reflectionName += ":" + requiredParameterCount +
209 ":" + optionalParameterCount;
210 }
211 mangledNames[name] = reflectionName;
212 funcs[0].$reflectionNameField = reflectionName;
213 funcs[0].$metadataIndexField = unmangledNameIndex + 1;
214 if (optionalParameterCount) descriptor[unmangledName + "*"] = funcs[0];
215 }
216 }
217 ''', [globalFunctionsAccess, interceptedNamesAccess,
218 mangledGlobalNamesAccess, mangledNamesAccess]);
219
220 List<jsAst.Statement> tearOffCode = buildTearOffCode(backend);
221
222 jsAst.Statement init = js.statement('''{
223 var functionCounter = 0;
224 var tearOffGetter = (typeof dart_precompiled == "function")
225 ? tearOffGetterCsp : tearOffGetterNoCsp;
226 if (!#) # = []; // embedded libraries.
227 if (!#) # = map(); // embedded mangledNames.
228 if (!#) # = map(); // embedded mangledGlobalNames.
229 if (!#) # = map(); // embedded statics.
230 if (!#) # = map(); // embedded typeInformation.
231 if (!#) # = map(); // embedded globalFunctions.
232 if (!#) # = map(); // embedded interceptedNames.
233 var libraries = #; // embeded libraries.
234 var mangledNames = #; // embedded mangledNames.
235 var mangledGlobalNames = #; // embedded mangledGlobalNames.
236 var hasOwnProperty = Object.prototype.hasOwnProperty;
237 var length = reflectionData.length;
238 for (var i = 0; i < length; i++) {
239 var data = reflectionData[i];
240
241 // [data] contains these elements:
242 // 0. The library name (not unique).
243 // 1. The library URI (unique).
244 // 2. A function returning the metadata associated with this library.
245 // 3. The global object to use for this library.
246 // 4. An object literal listing the members of the library.
247 // 5. This element is optional and if present it is true and signals that this
248 // library is the root library (see dart:mirrors IsolateMirror.rootLibrary).
249 //
250 // The entries of [data] are built in [assembleProgram] above.
251
252 var name = data[0];
253 var uri = data[1];
254 var metadata = data[2];
255 var globalObject = data[3];
256 var descriptor = data[4];
257 var isRoot = !!data[5];
258 var fields = descriptor && descriptor["${namer.classDescriptorProperty}"];
259 if (fields instanceof Array) fields = fields[0];
260 var classes = [];
261 var functions = [];
262 processStatics(descriptor);
263 libraries.push([name, uri, classes, functions, metadata, fields, isRoot,
264 globalObject]);
265 }
266 }''', [librariesAccess, librariesAccess,
267 mangledNamesAccess, mangledNamesAccess,
268 mangledGlobalNamesAccess, mangledGlobalNamesAccess,
269 staticsAccess, staticsAccess,
270 typeInformationAccess, typeInformationAccess,
271 globalFunctionsAccess, globalFunctionsAccess,
272 interceptedNamesAccess, interceptedNamesAccess,
273 librariesAccess,
274 mangledNamesAccess,
275 mangledGlobalNamesAccess]);
276
277 return js('''
278 (function (reflectionData) {
279 "use strict";
280 #; // header
281 #; // processStatics
282 #; // addStubs
283 #; // tearOffCode
284 #; // init
285 })''', [header, processStatics, addStubs, tearOffCode, init]);
286 }
287
288
289 List<jsAst.Statement> buildTearOffCode(JavaScriptBackend backend) {
290 Namer namer = backend.namer;
291 Compiler compiler = backend.compiler;
292
293 Element closureFromTearOff = backend.findHelper('closureFromTearOff');
294 String tearOffAccessText;
295 jsAst.Expression tearOffAccessExpression;
296 String tearOffGlobalObjectName;
297 String tearOffGlobalObject;
298 if (closureFromTearOff != null) {
299 // We need both the AST that references [closureFromTearOff] and a string
300 // for the NoCsp version that constructs a function.
301 tearOffAccessExpression = namer.elementAccess(closureFromTearOff);
302 tearOffAccessText =
303 jsAst.prettyPrint(tearOffAccessExpression, compiler).getText();
304 tearOffGlobalObjectName = tearOffGlobalObject =
305 namer.globalObjectFor(closureFromTearOff);
306 } else {
307 // Default values for mocked-up test libraries.
308 tearOffAccessText =
309 r'''function() { throw 'Helper \'closureFromTearOff\' missing.' }''';
310 tearOffAccessExpression = js(tearOffAccessText);
311 tearOffGlobalObjectName = 'MissingHelperFunction';
312 tearOffGlobalObject = '($tearOffAccessText())';
313 }
314
315 // This template is uncached because it is constructed from code fragments
316 // that can change from compilation to compilation. Some of these could be
317 // avoided, except for the string literals that contain the compiled access
318 // path to 'closureFromTearOff'.
319 jsAst.Statement tearOffGetterNoCsp = js.uncachedStatementTemplate('''
320 function tearOffGetterNoCsp(funcs, reflectionInfo, name, isIntercepted) {
321 return isIntercepted
322 ? new Function("funcs", "reflectionInfo", "name",
323 "$tearOffGlobalObjectName", "c",
324 "return function tearOff_" + name + (functionCounter++)+ "(x) {" +
325 "if (c === null) c = $tearOffAccessText(" +
326 "this, funcs, reflectionInfo, false, [x], name);" +
327 "return new c(this, funcs[0], x, name);" +
328 "}")(funcs, reflectionInfo, name, $tearOffGlobalObject, null)
329 : new Function("funcs", "reflectionInfo", "name",
330 "$tearOffGlobalObjectName", "c",
331 "return function tearOff_" + name + (functionCounter++)+ "() {" +
332 "if (c === null) c = $tearOffAccessText(" +
333 "this, funcs, reflectionInfo, false, [], name);" +
334 "return new c(this, funcs[0], null, name);" +
335 "}")(funcs, reflectionInfo, name, $tearOffGlobalObject, null);
336 }''').instantiate([]);
337
338 jsAst.Statement tearOffGetterCsp = js.statement('''
339 function tearOffGetterCsp(funcs, reflectionInfo, name, isIntercepted) {
340 var cache = null;
341 return isIntercepted
342 ? function(x) {
343 if (cache === null) cache = #(
344 this, funcs, reflectionInfo, false, [x], name);
345 return new cache(this, funcs[0], x, name);
346 }
347 : function() {
348 if (cache === null) cache = #(
349 this, funcs, reflectionInfo, false, [], name);
350 return new cache(this, funcs[0], null, name);
351 };
352 }''', [tearOffAccessExpression, tearOffAccessExpression]);
353
354 jsAst.Statement tearOff = js.statement('''
355 function tearOff(funcs, reflectionInfo, isStatic, name, isIntercepted) {
356 var cache;
357 return isStatic
358 ? function() {
359 if (cache === void 0) cache = #(
360 this, funcs, reflectionInfo, true, [], name).prototype;
361 return cache;
362 }
363 : tearOffGetter(funcs, reflectionInfo, name, isIntercepted);
364 }''', tearOffAccessExpression);
365
366 return <jsAst.Statement>[tearOffGetterNoCsp, tearOffGetterCsp, tearOff];
367 }
368
369
370 String readString(String array, String index) {
371 return readChecked(
372 array, index, 'result != null && typeof result != "string"', 'string');
373 }
374
375 String readInt(String array, String index) {
376 return readChecked(
377 array, index,
378 'result != null && (typeof result != "number" || (result|0) !== result)',
379 'int');
380 }
381
382 String readFunction(String array, String index) {
383 return readChecked(
384 array, index, 'result != null && typeof result != "function"',
385 'function');
386 }
387
388 String readFunctionType(String array, String index) {
389 return readChecked(
390 array, index,
391 'result != null && '
392 '(typeof result != "number" || (result|0) !== result) && '
393 'typeof result != "function"',
394 'function or int');
395 }
396
397 String readChecked(String array, String index, String check, String type) {
398 if (!VALIDATE_DATA) return '$array[$index]';
399 return '''
400 (function() {
401 var result = $array[$index];
402 if ($check) {
403 throw new Error(
404 name + ": expected value of type \'$type\' at index " + ($index) +
405 " but got " + (typeof result));
406 }
407 return result;
408 })()''';
409 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698