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

Unified Diff: dart/sdk/lib/_internal/compiler/implementation/js_emitter/reflection_data_parser.dart

Issue 27524003: Generate tear-off closures dynamically. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge
Patch Set: Fixed unit tests. Created 7 years 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 side-by-side diff with in-line comments
Download patch
Index: dart/sdk/lib/_internal/compiler/implementation/js_emitter/reflection_data_parser.dart
diff --git a/dart/sdk/lib/_internal/compiler/implementation/js_emitter/reflection_data_parser.dart b/dart/sdk/lib/_internal/compiler/implementation/js_emitter/reflection_data_parser.dart
index 864f130d9538c355200697d8855360af580ec988..2e218f5accfd48bb3aba605b632e8c5631f49e55 100644
--- a/dart/sdk/lib/_internal/compiler/implementation/js_emitter/reflection_data_parser.dart
+++ b/dart/sdk/lib/_internal/compiler/implementation/js_emitter/reflection_data_parser.dart
@@ -4,21 +4,183 @@
part of dart2js.js_emitter;
+// TODO(ahe): Share these with js_helper.dart.
+const FUNCTION_INDEX = 0;
+const NAME_INDEX = 1;
+const CALL_NAME_INDEX = 2;
+const REQUIRED_PARAMETER_INDEX = 3;
+const OPTIONAL_PARAMETER_INDEX = 4;
+const DEFAULT_ARGUMENTS_INDEX = 5;
+
// TODO(ahe): This code should be integrated in CodeEmitterTask.finishClasses.
-String getReflectionDataParser(String classesCollector, Namer namer) {
+String getReflectionDataParser(String classesCollector,
+ JavaScriptBackend backend) {
+ Namer namer = backend.namer;
+ Compiler compiler = backend.compiler;
+ Element closureFromTearOff = compiler.findHelper('closureFromTearOff');
+ String tearOff =
+ // Default value for mocked-up test libraries.
+ 'function () { throw "Helper \'closureFromTearOff\' missing." }';
+ if (closureFromTearOff != null) {
+ tearOff = namer.isolateAccess(closureFromTearOff);
+ }
String metadataField = '"${namer.metadataField}"';
String reflectableField = namer.reflectableField;
+ String reflectionInfoField = r'$reflectionInfo'; // MOVE TO NAMER
Johnni Winther 2013/12/05 11:49:56 Add TODO for the comments.
ahe 2013/12/06 15:57:54 Done.
+ String reflectionNameField = r'$reflectionName'; // DITTO
+ String metadataIndexField = r'$metadataIndex'; // DITTO
String defaultValuesField = namer.defaultValuesField;
String methodsWithOptionalArgumentsField =
namer.methodsWithOptionalArgumentsField;
return '''
(function (reflectionData) {
+ "use strict";
'''
// [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}
+ 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 === "+") {
Johnni Winther 2013/12/05 11:49:56 It would be nice to have a comment that gives an e
ahe 2013/12/06 15:57:54 https://code.google.com/p/dart/issues/detail?id=15
+ mangledGlobalNames[previousProperty] = property.substring(1);
+ if (descriptor[property] == 1) ''' // Break long line.
+'''descriptor[previousProperty].$reflectableField = 1;
Johnni Winther 2013/12/05 11:49:56 Indent so `descriptor[previousProperty]` is below
ahe 2013/12/06 15:57:54 Done.
+ if (element && element.length) ''' // Break long line.
+'''init.typeInformation[previousProperty] = element;
Johnni Winther 2013/12/05 11:49:56 Ditto.
ahe 2013/12/06 15:57:54 Done.
+ } else if (firstChar === "@") {
+ property = property.substring(1);
+ ${namer.currentIsolate}[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 if (element.constructor === Array) {
+ addStubs(globalObject, element, property, true, descriptor, functions);
+ } 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;
Johnni Winther 2013/12/05 11:49:56 Ditto.
ahe 2013/12/06 15:57:54 Done.
+ } 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 {
+ var elem = element[prop];
+ if (prop && elem != null && elem.constructor === Array && prop !== "<>") {
Johnni Winther 2013/12/05 11:49:56 Long line.
ahe 2013/12/06 15:57:54 Done.
+ addStubs(newDesc, elem, prop, false, element, []);
+ } else {
+ newDesc[previousProp = prop] = elem;
+ }
+ }
+ }
+ $classesCollector[property] = [globalObject, newDesc];
+ classes.push(property);
+ }
+ }
+ }${
+ /**
+ * See [dart2js.js_emitter.ContainerBuilder.addMemberMethod] for format of
+ * [array].
+ */ ""}
+ function addStubs(descriptor, array, name, isStatic, originalDescriptor, functions) {
Johnni Winther 2013/12/05 11:49:56 Long line.
ahe 2013/12/06 15:57:54 Done.
+ var f, funcs = [originalDescriptor[name] = descriptor[name] = f = ${readFunction("array", "$FUNCTION_INDEX")}];
Johnni Winther 2013/12/05 11:49:56 Ditto.
ahe 2013/12/06 15:57:54 Done.
+ f.\$stubName = name;
+ functions.push(name);
+ for (var index = $FUNCTION_INDEX; index < array.length; index += 2) {
+ f = array[index + 1];
+ if (typeof f != "function") break;
+ f.\$stubName = ${readString("array", "index + 2")};
+ funcs.push(f);
+ // print("Stub for " + name + ": " + f.\$stubName);
Johnni Winther 2013/12/05 11:49:56 Remove debug code.
ahe 2013/12/06 15:57:54 Done.
+ if (f.\$stubName) {
+ originalDescriptor[f.\$stubName] = descriptor[f.\$stubName] = f;
+ functions.push(f.\$stubName);
+ }
+ }
+ for (var i = 0; i < funcs.length; index++, i++) {
+ funcs[i].\$callName = ${readString("array", "index + 1")};
+ }
+ var getterStubName = ${readString("array", "++index")};
+ array = array.slice(++index);
+ var requiredParameterInfo = ${readInt("array", "0")};
+ var requiredParameterCount = requiredParameterInfo >> 1;
+ var isAccessor = (requiredParameterInfo & 1) === 1;
+ var isSetter = requiredParameterInfo === 3;
+ var isGetter = requiredParameterInfo === 1;
+ var optionalParameterInfo = ${readInt("array", "1")};
+ var optionalParameterCount = optionalParameterInfo >> 1;
+ var optionalParametersAreNamed = (optionalParameterInfo & 1) === 1;
+ var functionTypeIndex = ${readFunctionType("array", "2")};
+ var isReflectable = array.length > optionalParameterCount + 3;
+ if (getterStubName) {
+ f = tearOff(funcs, array, isStatic, name);${
Johnni Winther 2013/12/05 11:49:56 Replace ${ /* ... */ ""} by ''' // ... '''.
ahe 2013/12/06 15:57:54 OK, but I don't think the code is more readable (o
+ /* Used to create an isolate using spawnFunction.*/ ""}
+ if (isStatic) init.globalFunctions[name] = f;
+ originalDescriptor[getterStubName] = descriptor[getterStubName] = f;
+ funcs.push(f);
+ if (getterStubName) functions.push(getterStubName);
+ f.\$stubName = getterStubName;
+ f.\$callName = null;
+ }
+ if (isReflectable) {
+ for (var i = 0; i < funcs.length; i++) {
+ funcs[i].$reflectableField = 1;
+ funcs[i].$reflectionInfoField = array;
+ }
+ }
+ if (isReflectable) {
+ var unmangledNameIndex = optionalParameterCount * 2 + requiredParameterCount + 3;
Johnni Winther 2013/12/05 11:49:56 Long line.
ahe 2013/12/06 15:57:54 Done.
+ var unmangledName = ${readString("array", "unmangledNameIndex")};
+ var reflectionName = unmangledName + ":" + requiredParameterCount + ":" + optionalParameterCount;
Johnni Winther 2013/12/05 11:49:56 Long line.
ahe 2013/12/06 15:57:54 Done.
+ if (isGetter) {
+ reflectionName = unmangledName;
+ } else if (isSetter) {
+ reflectionName = unmangledName + "=";
+ }
+ if (isStatic) {
+ init.mangledGlobalNames[name] = reflectionName;
+ } else {
+ init.mangledNames[name] = reflectionName;
+ }
+ // print(name + " is reflectable with reflection name \'" + reflectionName + "\' " + isStatic);
Johnni Winther 2013/12/05 11:49:56 Long line.
ahe 2013/12/06 15:57:54 Done.
+ funcs[0].$reflectionNameField = reflectionName;
+ funcs[0].$metadataIndexField = unmangledNameIndex + 1;
+ if (optionalParameterCount) descriptor[unmangledName + "*"] = funcs[0];
+ }
+ }
+ function tearOff(funcs, reflectionInfo, isStatic, name) {
+ return function() {
+ return $tearOff(this, funcs, reflectionInfo, isStatic, arguments, name);
+ }
+ }
if (!init.libraries) init.libraries = [];
if (!init.mangledNames) init.mangledNames = map();
if (!init.mangledGlobalNames) init.mangledGlobalNames = map();
@@ -53,67 +215,45 @@ String getReflectionDataParser(String classesCollector, Namer namer) {
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.typeInformation[previousProperty] = element;
- } else if (firstChar === "@") {
- property = property.substring(1);
- ${namer.currentIsolate}[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]);
}
})''';
}
+
+String readString(String array, String index) {
+ return readChecked(
+ array, index, 'result != null && typeof result != "string"', 'string');
+}
+
+String readInt(String array, String index) {
+ return readChecked(
+ array, index, 'result != null && (typeof result != "number" || (result|0) !== result)',
Johnni Winther 2013/12/05 11:49:56 Long line.
ahe 2013/12/06 15:57:54 Done.
+ 'int');
+}
+
+String readFunction(String array, String index) {
+ return readChecked(
+ array, index, 'result != null && typeof result != "function"',
+ 'function');
+}
+
+String readFunctionType(String array, String index) {
+ return readChecked(
+ array, index, 'result != null && (typeof result != "number" || (result|0) !== result) && typeof result != "function"',
Johnni Winther 2013/12/05 11:49:56 Ditto.
ahe 2013/12/06 15:57:54 Done.
+ 'function or int');
+}
+
+String readChecked(String array, String index, String check, String type) {
+ return '''
+(function() {
Johnni Winther 2013/12/05 11:49:56 Only return an applied function in checked mode?
ahe 2013/12/06 15:57:54 Done.
+ var result = $array[$index];
+ if ($check) {
+ throw new Error(
+ name + ": expected value of type \'$type\' at index " + ($index) +
+ " but got " + (typeof result));
+ }
+ return result;
+})()''';
+}

Powered by Google App Engine
This is Rietveld 408576698