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

Unified Diff: pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart

Issue 1249023002: dart2js: support isolates in the startup-emitter. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Fix typo. Created 5 years, 5 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 side-by-side diff with in-line comments
Download patch
Index: pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
index 58207b3d3209e65b7eb8274f040009a5f4b64a9e..d82122ae14da61339cf16b76fe1904cd67da448d 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
@@ -4,6 +4,27 @@
part of dart2js.js_emitter.startup_emitter.model_emitter;
+/// The name of the property that stores the tear-off getter on a static
+/// function.
+///
+/// This property is only used when isolates are used.
+///
+/// When serializing static functions we transmit the
+/// name of the static function, but not the name of the function's getter. We
+/// store the getter-function on the static function itself, which allows us to
+/// find it easily.
+const String tearOffPropertyName = r'$tearOff';
+
+/// The name of the property that stores the list of fields on a constructor.
+///
+/// This property is only used when isolates are used.
+///
+/// When serializing objects we extract all fields from any given object.
+/// We extract the names of all fields from a fresh empty object. This list
+/// is cached on the constructor in this property to to avoid too many
+/// allocations.
+const String cachedClassFieldNames = r'$cachedFieldNames';
+
/// The fast startup emitter's goal is to minimize the amount of work that the
/// JavaScript engine has to do before it can start running user code.
///
@@ -142,6 +163,8 @@ function installTearOff(container, getterName,
isStatic, isIntercepted, requiredParameterCount,
optionalParameterDefaultValues,
callNames, funsOrNames, funType) {
+ // A function can have several stubs (for example to fill in optional
+ // arguments). We collect these functions in the `funs` array.
var funs = [];
for (var i = 0; i < funsOrNames.length; i++) {
var fun = funsOrNames[i];
@@ -150,8 +173,11 @@ function installTearOff(container, getterName,
funs.push(fun);
}
- funs[0][#argumentCount] = requiredParameterCount;
- funs[0][#defaultArgumentValues] = optionalParameterDefaultValues;
+ // The main function to which all stubs redirect.
+ var fun = funs[0];
+
+ fun[#argumentCount] = requiredParameterCount;
+ fun[#defaultArgumentValues] = optionalParameterDefaultValues;
var reflectionInfo = funType;
if (typeof reflectionInfo == "number") {
// The reflectionInfo can either be a function, or a pointer into the types
@@ -160,8 +186,12 @@ function installTearOff(container, getterName,
reflectionInfo = reflectionInfo + typesOffset;
}
var name = funsOrNames[0];
- container[getterName] =
+ var getterFunction =
tearOff(funs, reflectionInfo, isStatic, name, isIntercepted);
+ container[getterName] = getterFunction;
+ if (isStatic) {
+ fun.$tearOffPropertyName = getterFunction;
+ }
}
// Instead of setting the interceptor tags directly we use this update
@@ -221,6 +251,19 @@ function initializeDeferredHunk(hunk) {
#embeddedGlobalsObject, #holdersList, #staticState);
}
+// Returns the global with the given [name].
+function getGlobalFromName(name) {
+ // TODO(floitsch): we are running through all holders. Since negative
+ // lookups are expensive we might need to improve this.
+ // Relies on the fact that all names are unique across all holders.
+ for (var i = 0; i < holders.length; i++) {
+ // The constant holder reuses the same names. Therefore we must skip it.
+ if (holders[i] == #constantHolderReference) continue;
+ // Relies on the fact that all variables are unique.
+ if (holders[i][name]) return holders[i][name];
+ }
+}
+
// Creates the holders.
#holders;
// TODO(floitsch): if name is not set (for example in IE), run through all
@@ -350,6 +393,7 @@ class FragmentEmitter {
'staticStateDeclaration': new js.VariableDeclaration(
namer.staticStateHolder, allowRename: false),
'staticState': js.js('#', namer.staticStateHolder),
+ 'constantHolderReference': buildConstantHolderReference(program),
'holders': emitHolders(program.holders, fragment),
'callName': js.string(namer.callNameField),
'argumentCount': js.string(namer.requiredParameterField),
@@ -469,6 +513,15 @@ class FragmentEmitter {
return new js.Block(statements);
}
+ /// Returns a reference to the constant holder, or the JS-literal `null`.
+ js.Expression buildConstantHolderReference(Program program) {
+ Holder constantHolder = program.holders
+ .firstWhere((Holder holder) => holder.isConstantsHolder,
+ orElse: () => null);
+ if (constantHolder == null) return new js.LiteralNull();
+ return new js.VariableUse(constantHolder.name);
+ }
+
/// Emits the given [method].
///
/// A Dart method might result in several JavaScript functions, if it
@@ -955,19 +1008,7 @@ class FragmentEmitter {
/// This embedded global provides a way to go from a class name (which is
/// also the constructor's name) to the constructor itself.
js.Property emitGetTypeFromName() {
- // TODO(floitsch): Fix getTypeFromName. It's too inefficient.
- // The current implementation relies on the fact that the names in holders
- // are unique across all holders.
- // TODO(floitsch): constants and other globals may share the same name.
- // If a global happens to have the same (minified) name this code breaks.
- // A follow-up CL has a fix for this.
- js.Expression function =
- js.js( """function(name) {
- for (var i = 0; i < holders.length; i++) {
- // Relies on the fact that all variables are unique.
- if (holders[i][name]) return holders[i][name];
- }
- }""");
+ js.Expression function = js.js("getGlobalFromName");
return new js.Property(js.string(GET_TYPE_FROM_NAME), function);
}
@@ -1014,8 +1055,67 @@ class FragmentEmitter {
// impact on real-world programs, though.
globals.add(
new js.Property(js.string(CREATE_NEW_ISOLATE),
- js.js('function () { return $staticStateName; }')));
- // TODO(floitsch): add remaining isolate functions.
+ js.js('function () { return $staticStateName; }')));
+
+ js.Expression nameToClosureFunction = js.js('''
+ // First fetch the static function. From there we can execute its
+ // getter function which builds a Dart closure.
+ function(name) {
+ var staticFunction = getGlobalFromName(name);
+ var getterFunction = staticFunction.$tearOffPropertyName;
+ return getterFunction();
+ }''');
+ globals.add(new js.Property(js.string(STATIC_FUNCTION_NAME_TO_CLOSURE),
+ nameToClosureFunction));
+
+ globals.add(
+ new js.Property(js.string(CLASS_ID_EXTRACTOR),
+ js.js('function(o) { return o.constructor.name; }')));
+
+ js.Expression extractFieldsFunction = js.js('''
+ function(o) {
+ var constructor = o.constructor;
+ var fieldNames = constructor.$cachedClassFieldNames;
+ if (!fieldNames) {
+ // Extract the fields from an empty unmodified object.
+ var empty = new constructor();
+ // This gives us the keys that the constructor sets.
+ fieldNames = constructor.$cachedClassFieldNames = Object.keys(empty);
+ }
+ var result = new Array(fieldNames.length);
+ for (var i = 0; i < fieldNames.length; i++) {
+ result[i] = o[fieldNames[i]];
+ }
+ return result;
+ }''');
+ globals.add(new js.Property(js.string(CLASS_FIELDS_EXTRACTOR),
+ extractFieldsFunction));
+
+ js.Expression createInstanceFromClassIdFunction = js.js('''
+ function(name) {
+ var constructor = getGlobalFromName(name);
+ return new constructor();
+ }
+ ''');
+ globals.add(new js.Property(js.string(INSTANCE_FROM_CLASS_ID),
+ createInstanceFromClassIdFunction));
+
+ js.Expression initializeEmptyInstanceFunction = js.js('''
+ function(name, o, fields) {
+ var constructor = o.constructor;
+ // By construction the object `o` is an empty object with the same
+ // keys as the one we used in the extract-fields function.
+ var fieldNames = Object.keys(o);
+ if (fieldNames.length != fields.length) {
+ throw new Error("Mismatch during deserialization.");
+ }
+ for (var i = 0; i < fields.length; i++) {
+ o[fieldNames[i]] = fields[i];
+ }
+ return o;
+ }''');
+ globals.add(new js.Property(js.string(INITIALIZE_EMPTY_INSTANCE),
+ initializeEmptyInstanceFunction));
}
globals.add(emitMangledGlobalNames());
@@ -1106,4 +1206,4 @@ class FragmentEmitter {
return new js.Block(statements);
}
-}
+}

Powered by Google App Engine
This is Rietveld 408576698