From 028b1d45b73d099219ab2a272cf75ed8cf704909 Mon Sep 17 00:00:00 2001 From: "floitsch@google.com" Date: Mon, 9 Mar 2015 16:37:01 +0000 Subject: [PATCH] dart2js: create constants lazily in the new emitter. R=zarah@google.com Review URL: https://codereview.chromium.org//952973004 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@44326 260f80e4-7a28-3924-810f-c04153c831b5 --- .../js_emitter/new_emitter/model_emitter.dart | 80 ++++++++++++++----- 1 file changed, 60 insertions(+), 20 deletions(-) diff --git a/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart index 4ab05982d90..32c5a63c9cf 100644 --- a/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart +++ b/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart @@ -118,8 +118,8 @@ class ModelEmitter { if (isConstantInlinedOrAlreadyEmitted(value)) { return constantEmitter.generate(value); } - return js.js('#.#', [namer.globalObjectForConstant(value), - namer.constantName(value)]); + return js.js('#.#()', [namer.globalObjectForConstant(value), + namer.constantName(value)]); } int emitProgram(Program program) { @@ -154,6 +154,11 @@ class ModelEmitter { js.LiteralString unparse(Compiler compiler, js.Node value) { String text = js.prettyPrint(value, compiler).getText(); if (value is js.Fun) text = '($text)'; + if (value is js.LiteralExpression && + (value.template.startsWith("function ") || + value.template.startsWith("{"))) { + text = '($text)'; + } return js.js.escapedString(text); } @@ -168,6 +173,8 @@ class ModelEmitter { List elements = fragment.libraries.map(emitLibrary).toList(); elements.add( emitLazilyInitializedStatics(fragment.staticLazilyInitializedFields)); + elements.add(emitConstants(fragment.constants)); + js.Expression code = new js.ArrayInitializer(elements); @@ -185,7 +192,6 @@ class ModelEmitter { backend.emitter.staticFunctionAccess(backend.getCyclicThrowHelper()), 'outputContainsConstantList': program.outputContainsConstantList, 'embeddedGlobals': emitEmbeddedGlobals(program), - 'constants': emitConstants(fragment.constants), 'staticNonFinals': emitStaticNonFinalFields(fragment.staticNonFinalFields), 'operatorIsPrefix': js.string(namer.operatorIsPrefix), @@ -431,16 +437,14 @@ class ModelEmitter { deferredCode.add( emitLazilyInitializedStatics(fragment.staticLazilyInitializedFields)); + deferredCode.add(emitConstants(fragment.constants)); + js.ArrayInitializer deferredArray = new js.ArrayInitializer(deferredCode); // This is the code that must be evaluated after all deferred classes have // been setup. - js.Statement immediateCode = js.js.statement('''{ - #constants; - #eagerClasses; - }''', - {'constants': emitConstants(fragment.constants), - 'eagerClasses': emitEagerClassInitializations(fragment.libraries)}); + js.Statement immediateCode = + emitEagerClassInitializations(fragment.libraries); js.LiteralString immediateString = unparse(compiler, immediateCode); js.ArrayInitializer hunk = @@ -449,13 +453,25 @@ class ModelEmitter { return js.js("$deferredInitializersGlobal[$hash] = #", hunk); } - js.Block emitConstants(List constants) { - Iterable statements = constants.map((Constant constant) { - js.Expression code = constantEmitter.generate(constant.value); - return js.js.statement("#.# = #;", - [constant.holder.name, constant.name, code]); - }); - return new js.Block(statements.toList()); + // This string should be referenced wherever JavaScript code makes assumptions + // on the constants format. + static final String constantsDescription = + "The constants are encoded as a follows:" + " [constantsHolderIndex, name, code, name2, code2, ...]." + "The array is completely empty if there is no constant at all."; + + js.ArrayInitializer emitConstants(List constants) { + List data = []; + if (constants.isNotEmpty) { + int holderIndex = constants.first.holder.index; + data.add(js.number(holderIndex)); + data.addAll(constants.expand((Constant constant) { + assert(constant.holder.index == holderIndex); + js.Expression code = constantEmitter.generate(constant.value); + return [js.string(constant.name), unparse(compiler, code)]; + })); + } + return new js.ArrayInitializer(data); } js.Block emitStaticNonFinalFields(List fields) { @@ -824,10 +840,11 @@ function parseFunctionDescriptor(proto, name, descriptor) { var functionCounter = 0; function $setupProgramName(program) { - for (var i = 0; i < program.length - 1; i++) { + for (var i = 0; i < program.length - 2; i++) { setupLibrary(program[i]); } setupLazyStatics(program[i]); + setupConstants(program[i + 1]); } function setupLibrary(library) { @@ -873,6 +890,18 @@ function parseFunctionDescriptor(proto, name, descriptor) { } } + function setupConstants(constants) { + // $constantsDescription. + if (constants.length == 0) return; + // We assume that all constants are in the same holder. + var holder = holders[constants[0]]; + for (var i = 1; i < constants.length; i += 2) { + var name = constants[i]; + var initializer = constants[i + 1]; + setupConstant(name, holder, initializer); + } + } + function setupStatic(name, holder, descriptor) { if (typeof descriptor == 'string') { holder[name] = function() { @@ -957,12 +986,26 @@ function parseFunctionDescriptor(proto, name, descriptor) { // initialization failed. holder[name] = null; } + // TODO(floitsch): the function should probably be unique for each + // static. holder[getterName] = function() { return this[name]; }; } return result; }; } + function setupConstant(name, holder, descriptor) { + var c; + holder[name] = function() { + if (descriptor !== null) { + c = compile(name, descriptor); + name = null; + descriptor = null; + } + return c; + }; + } + function setupClass(name, holder, descriptor) { var patch = function() { if (patch.ensureResolved == patch) { @@ -1085,9 +1128,6 @@ function parseFunctionDescriptor(proto, name, descriptor) { $setupProgramName(program); - // Initialize constants. - #constants; - // Initialize globals. #embeddedGlobals;