blob: d90caf63373636f2e0ee95f1f3658d0f6354a149 [file] [log] [blame]
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart2js.js_emitter;
// TODO(ahe): This code should be integrated in CodeEmitterTask.finishClasses.
String getReflectionDataParser(String classesCollector, Namer namer) {
String metadataField = '"${namer.metadataField}"';
String reflectableField = namer.reflectableField;
String defaultValuesField = namer.defaultValuesField;
String methodsWithOptionalArgumentsField =
namer.methodsWithOptionalArgumentsField;
return '''
(function (reflectionData) {
'''
// [map] returns an object literal that V8 shouldn't try to optimize with a
// hidden class. This prevents a potential performance problem where V8 tries
// to build a hidden class for an object used as a hashMap.
'''
function map(x){x={x:x};delete x.x;return x}
if (!init.libraries) init.libraries = [];
if (!init.mangledNames) init.mangledNames = map();
if (!init.mangledGlobalNames) init.mangledGlobalNames = map();
if (!init.statics) init.statics = map();
if (!init.interfaces) init.interfaces = map();
if (!init.globalFunctions) init.globalFunctions = map();
var libraries = init.libraries;
var mangledNames = init.mangledNames;
var mangledGlobalNames = init.mangledGlobalNames;
var hasOwnProperty = Object.prototype.hasOwnProperty;
var length = reflectionData.length;
for (var i = 0; i < length; i++) {
var data = reflectionData[i];
'''
// [data] contains these elements:
// 0. The library name (not unique).
// 1. The library URI (unique).
// 2. A function returning the metadata associated with this library.
// 3. The global object to use for this library.
// 4. An object literal listing the members of the library.
// 5. This element is optional and if present it is true and signals that this
// library is the root library (see dart:mirrors IsolateMirror.rootLibrary).
//
// The entries of [data] are built in [assembleProgram] above.
'''
var name = data[0];
var uri = data[1];
var metadata = data[2];
var globalObject = data[3];
var descriptor = data[4];
var isRoot = !!data[5];
var fields = descriptor && descriptor[""];
var classes = [];
var functions = [];
function processStatics(descriptor) {
for (var property in descriptor) {
if (!hasOwnProperty.call(descriptor, property)) continue;
if (property === "") continue;
var element = descriptor[property];
var firstChar = property.substring(0, 1);
var previousProperty;
if (firstChar === "+") {
mangledGlobalNames[previousProperty] = property.substring(1);
if (descriptor[property] == 1) ''' // Break long line.
'''descriptor[previousProperty].$reflectableField = 1;
if (element && element.length) ''' // Break long line.
'''init.interfaces[previousProperty] = element;
} else if (firstChar === "@") {
property = property.substring(1);
${namer.CURRENT_ISOLATE}[property][$metadataField] = element;
} else if (firstChar === "*") {
globalObject[previousProperty].$defaultValuesField = element;
var optionalMethods = descriptor.$methodsWithOptionalArgumentsField;
if (!optionalMethods) {
descriptor.$methodsWithOptionalArgumentsField = optionalMethods = {}
}
optionalMethods[property] = previousProperty;
} else if (typeof element === "function") {
globalObject[previousProperty = property] = element;
functions.push(property);
init.globalFunctions[property] = element;
} else {
previousProperty = property;
var newDesc = {};
var previousProp;
for (var prop in element) {
if (!hasOwnProperty.call(element, prop)) continue;
firstChar = prop.substring(0, 1);
if (prop === "static") {
processStatics(init.statics[property] = element[prop]);
} else if (firstChar === "+") {
mangledNames[previousProp] = prop.substring(1);
if (element[prop] == 1) ''' // Break long line.
'''element[previousProp].$reflectableField = 1;
} else if (firstChar === "@" && prop !== "@") {
newDesc[prop.substring(1)][$metadataField] = element[prop];
} else if (firstChar === "*") {
newDesc[previousProp].$defaultValuesField = element[prop];
var optionalMethods = newDesc.$methodsWithOptionalArgumentsField;
if (!optionalMethods) {
newDesc.$methodsWithOptionalArgumentsField = optionalMethods={}
}
optionalMethods[prop] = previousProp;
} else {
newDesc[previousProp = prop] = element[prop];
}
}
$classesCollector[property] = [globalObject, newDesc];
classes.push(property);
}
}
}
processStatics(descriptor);
libraries.push([name, uri, classes, functions, metadata, fields, isRoot,
globalObject]);
}
})''';
}