Index: lib/compiler/implementation/emitter.dart |
diff --git a/lib/compiler/implementation/emitter.dart b/lib/compiler/implementation/emitter.dart |
index 4fafc8382e2482e7409c417a20dd68482343419d..61efdc0936603fe2684d30e0a7b8152654877182 100644 |
--- a/lib/compiler/implementation/emitter.dart |
+++ b/lib/compiler/implementation/emitter.dart |
@@ -26,8 +26,8 @@ class CodeEmitterTask extends CompilerTask { |
bool needsClosureClass = false; |
final Namer namer; |
NativeEmitter nativeEmitter; |
- StringBuffer boundClosureBuffer; |
- StringBuffer mainBuffer; |
+ CodeBuffer boundClosureBuffer; |
+ CodeBuffer mainBuffer; |
/** Shorter access to [isolatePropertiesName]. Both here in the code, as |
well as in the generated code. */ |
String isolateProperties; |
@@ -39,8 +39,8 @@ class CodeEmitterTask extends CompilerTask { |
CodeEmitterTask(Compiler compiler, [bool generateSourceMap = false]) |
: namer = compiler.namer, |
- boundClosureBuffer = new StringBuffer(), |
- mainBuffer = new StringBuffer(), |
+ boundClosureBuffer = new CodeBuffer(), |
+ mainBuffer = new CodeBuffer(), |
boundClosureCache = new Map<int, String>(), |
generateSourceMap = generateSourceMap, |
sourceMapBuilder = new SourceMapBuilder(), |
@@ -233,7 +233,7 @@ function(collectedClasses) { |
}"""; |
} |
- void addDefineClassAndFinishClassFunctionsIfNecessary(StringBuffer buffer) { |
+ void addDefineClassAndFinishClassFunctionsIfNecessary(CodeBuffer buffer) { |
if (needsDefineClass) { |
String isolate = namer.ISOLATE; |
buffer.add("$defineClassName = $defineClassFunction;\n"); |
@@ -242,13 +242,13 @@ function(collectedClasses) { |
} |
} |
- void emitFinishIsolateConstructor(StringBuffer buffer) { |
+ void emitFinishIsolateConstructor(CodeBuffer buffer) { |
String name = finishIsolateConstructorName; |
String value = finishIsolateConstructorFunction; |
buffer.add("$name = $value;\n"); |
} |
- void emitFinishIsolateConstructorInvocation(StringBuffer buffer) { |
+ void emitFinishIsolateConstructorInvocation(CodeBuffer buffer) { |
String isolate = namer.ISOLATE; |
buffer.add("$isolate = $finishIsolateConstructorName($isolate);\n"); |
} |
@@ -268,7 +268,7 @@ function(collectedClasses) { |
String invocationName = |
namer.instanceMethodInvocationName(member.getLibrary(), member.name, |
selector); |
- StringBuffer buffer = new StringBuffer(); |
+ CodeBuffer buffer = new CodeBuffer(); |
buffer.add('function('); |
// The parameters that this stub takes. |
@@ -335,7 +335,7 @@ function(collectedClasses) { |
// down to the native method. |
indexOfLastOptionalArgumentInParameters = count; |
} |
- StringBuffer argumentBuffer = new StringBuffer(); |
+ CodeBuffer argumentBuffer = new CodeBuffer(); |
handler.writeConstant(argumentBuffer, value); |
argumentsBuffer[count] = argumentBuffer.toString(); |
} |
@@ -355,7 +355,7 @@ function(collectedClasses) { |
buffer.add(' return this.${namer.getName(member)}($arguments)'); |
} |
buffer.add('\n}'); |
- defineInstanceMember(invocationName, buffer.toString()); |
+ defineInstanceMember(invocationName, buffer); |
} |
void addParameterStubs(FunctionElement member, |
@@ -396,16 +396,12 @@ function(collectedClasses) { |
|| member.kind === ElementKind.GETTER |
|| member.kind === ElementKind.SETTER) { |
if (member.modifiers !== null && member.modifiers.isAbstract()) return; |
- CodeBlock codeBlock = compiler.codegenWorld.generatedCode[member]; |
- if (codeBlock == null) return; |
- defineInstanceMember(namer.getName(member), |
- codeBlock.code, |
- codeBlock.sourceMappings); |
- codeBlock = compiler.codegenWorld.generatedBailoutCode[member]; |
- if (codeBlock !== null) { |
- defineInstanceMember(compiler.namer.getBailoutName(member), |
- codeBlock.code, |
- codeBlock.sourceMappings); |
+ CodeBuffer codeBuffer = compiler.codegenWorld.generatedCode[member]; |
+ if (codeBuffer == null) return; |
+ defineInstanceMember(namer.getName(member), codeBuffer); |
+ codeBuffer = compiler.codegenWorld.generatedBailoutCode[member]; |
+ if (codeBuffer !== null) { |
+ defineInstanceMember(compiler.namer.getBailoutName(member), codeBuffer); |
} |
FunctionElement function = member; |
FunctionSignature parameters = function.computeSignature(compiler); |
@@ -417,10 +413,14 @@ function(collectedClasses) { |
ClassElement cls = member.getEnclosingClass(); |
if (cls.lookupSuperMember(name) !== null) { |
String fieldName = namer.instanceFieldName(cls, name); |
+ CodeBuffer getterBuffer = new CodeBuffer(); |
+ getterBuffer.add('function() {\n return this.$fieldName;\n }'); |
defineInstanceMember(namer.getterName(cls.getLibrary(), name), |
- 'function() {\n return this.$fieldName;\n }'); |
+ getterBuffer); |
+ CodeBuffer setterBuffer = new CodeBuffer(); |
+ setterBuffer.add('function(x) {\n this.$fieldName = x;\n }'); |
defineInstanceMember(namer.setterName(cls.getLibrary(), name), |
- 'function(x) {\n this.$fieldName = x;\n }'); |
+ setterBuffer); |
} |
} else { |
compiler.internalError('unexpected kind: "${member.kind}"', |
@@ -429,7 +429,7 @@ function(collectedClasses) { |
emitExtraAccessors(member, defineInstanceMember); |
} |
- Set<Element> emitClassFields(ClassElement classElement, StringBuffer buffer) { |
+ Set<Element> emitClassFields(ClassElement classElement, CodeBuffer buffer) { |
// If the class is never instantiated we still need to set it up for |
// inheritance purposes, but we can simplify its JavaScript constructor. |
bool isInstantiated = |
@@ -486,18 +486,16 @@ function(collectedClasses) { |
} |
void emitInstanceMembers(ClassElement classElement, |
- StringBuffer buffer, |
+ CodeBuffer buffer, |
bool needsLeadingComma) { |
bool needsComma = needsLeadingComma; |
- void defineInstanceMember(String name, |
- String value, |
- [List<SourceMappingEntry> sourceMappings]) { |
+ void defineInstanceMember(String name, CodeBuffer memberBuffer) { |
if (needsComma) buffer.add(','); |
needsComma = true; |
buffer.add('\n'); |
buffer.add(' $name: '); |
- sourceMapBuilder.addCodeBlock(sourceMappings, buffer.length); |
- buffer.add('$value'); |
+ addMappings(memberBuffer, buffer.length); |
+ buffer.add(memberBuffer); |
} |
classElement.forEachMember(includeBackendMembers: true, |
@@ -508,12 +506,15 @@ function(collectedClasses) { |
}); |
generateTypeTests(classElement, (Element other) { |
+ String code; |
if (nativeEmitter.requiresNativeIsCheck(other)) { |
- defineInstanceMember(namer.operatorIs(other), |
- 'function() { return true; }'); |
+ code = 'function() { return true; }'; |
} else { |
- defineInstanceMember(namer.operatorIs(other), 'true'); |
+ code = 'true'; |
} |
+ CodeBuffer buffer = new CodeBuffer(); |
+ buffer.add(code); |
+ defineInstanceMember(namer.operatorIs(other), buffer); |
}); |
if (classElement === compiler.objectClass && compiler.enabledNoSuchMethod) { |
@@ -525,7 +526,7 @@ function(collectedClasses) { |
} |
} |
- void generateClass(ClassElement classElement, StringBuffer buffer) { |
+ void generateClass(ClassElement classElement, CodeBuffer buffer) { |
if (classElement.isNative()) { |
nativeEmitter.generateNativeClass(classElement); |
return; |
@@ -579,7 +580,7 @@ function(collectedClasses) { |
} |
} |
- void emitClasses(StringBuffer buffer) { |
+ void emitClasses(CodeBuffer buffer) { |
Set<ClassElement> instantiatedClasses = |
compiler.codegenWorld.instantiatedClasses; |
Set<ClassElement> neededClasses = |
@@ -612,7 +613,7 @@ function(collectedClasses) { |
} |
} |
- void emitFinishClassesInvocationIfNecessary(StringBuffer buffer) { |
+ void emitFinishClassesInvocationIfNecessary(CodeBuffer buffer) { |
if (needsDefineClass) { |
buffer.add("$finishClassesName($classesCollector);\n"); |
// Reset the map. |
@@ -620,20 +621,21 @@ function(collectedClasses) { |
} |
} |
- void emitStaticFunctionsWithNamer(StringBuffer buffer, |
- Map<Element, CodeBlock> generatedCode, |
+ void emitStaticFunctionsWithNamer(CodeBuffer buffer, |
+ Map<Element, CodeBuffer> generatedCode, |
String functionNamer(Element element)) { |
- generatedCode.forEach((Element element, CodeBlock codeBlock) { |
+ generatedCode.forEach((Element element, CodeBuffer functionBuffer) { |
if (!element.isInstanceMember()) { |
String functionName = functionNamer(element); |
buffer.add('$isolateProperties.$functionName = '); |
- sourceMapBuilder.addCodeBlock(codeBlock.sourceMappings, buffer.length); |
- buffer.add('${codeBlock.code};\n\n'); |
+ addMappings(functionBuffer, buffer.length); |
+ buffer.add(functionBuffer); |
+ buffer.add(';\n\n'); |
} |
}); |
} |
- void emitStaticFunctions(StringBuffer buffer) { |
+ void emitStaticFunctions(CodeBuffer buffer) { |
emitStaticFunctionsWithNamer(buffer, |
compiler.codegenWorld.generatedCode, |
namer.getName); |
@@ -642,7 +644,7 @@ function(collectedClasses) { |
namer.getBailoutName); |
} |
- void emitStaticFunctionGetters(StringBuffer buffer) { |
+ void emitStaticFunctionGetters(CodeBuffer buffer) { |
Set<FunctionElement> functionsNeedingGetter = |
compiler.codegenWorld.staticFunctionsNeedingGetter; |
for (FunctionElement element in functionsNeedingGetter) { |
@@ -659,9 +661,7 @@ function(collectedClasses) { |
parameterCount); |
String fieldAccess = '$isolateProperties.$staticName'; |
buffer.add("$fieldAccess.$invocationName = $fieldAccess;\n"); |
- addParameterStubs(callElement, ( |
- String name, String value, |
- [List<SourceMappingEntry> sourceMappings]) { |
+ addParameterStubs(callElement, (String name, CodeBuffer value) { |
buffer.add('$fieldAccess.$name = $value;\n'); |
}); |
// If a static function is used as a closure we need to add its name |
@@ -733,9 +733,7 @@ function(collectedClasses) { |
"$invocationName: function($joinedArgs) {"); |
boundClosureBuffer.add(" return this.self[this.target]($joinedArgs);"); |
boundClosureBuffer.add(" }"); |
- addParameterStubs(callElement, ( |
- String stubName, String memberValue, |
- [List<SourceMappingEntry> sourceMappings]) { |
+ addParameterStubs(callElement, (String stubName, CodeBuffer memberValue) { |
boundClosureBuffer.add(',\n $stubName: $memberValue'); |
}); |
boundClosureBuffer.add("\n});\n"); |
@@ -752,9 +750,10 @@ function(collectedClasses) { |
String getterName = namer.getterName(member.getLibrary(), member.name); |
String targetName = namer.instanceMethodName(member.getLibrary(), |
member.name, parameterCount); |
- defineInstanceMember( |
- getterName, |
+ CodeBuffer getterBuffer = new CodeBuffer(); |
+ getterBuffer.add( |
"function() { return new $closureClass(this, '$targetName'); }"); |
+ defineInstanceMember(getterName, getterBuffer); |
} |
void emitCallStubForGetter(Element member, |
@@ -782,14 +781,15 @@ function(collectedClasses) { |
arguments.add("arg$i"); |
} |
String joined = Strings.join(arguments, ", "); |
- defineInstanceMember( |
- invocationName, |
+ CodeBuffer getterBuffer = new CodeBuffer(); |
+ getterBuffer.add( |
"function($joined) { return $getter.$closureCallName($joined); }"); |
+ defineInstanceMember(invocationName, getterBuffer); |
} |
} |
} |
- void emitStaticNonFinalFieldInitializations(StringBuffer buffer) { |
+ void emitStaticNonFinalFieldInitializations(CodeBuffer buffer) { |
ConstantHandler handler = compiler.constantHandler; |
List<VariableElement> staticNonFinalFields = |
handler.getStaticNonFinalFieldsForEmission(); |
@@ -802,7 +802,7 @@ function(collectedClasses) { |
} |
} |
- void emitCompileTimeConstants(StringBuffer buffer) { |
+ void emitCompileTimeConstants(CodeBuffer buffer) { |
ConstantHandler handler = compiler.constantHandler; |
List<Constant> constants = handler.getConstantsForEmission(); |
bool addedMakeConstantList = false; |
@@ -822,7 +822,7 @@ function(collectedClasses) { |
} |
} |
- void emitMakeConstantList(StringBuffer buffer) { |
+ void emitMakeConstantList(CodeBuffer buffer) { |
buffer.add(namer.ISOLATE); |
buffer.add(@'''.makeConstantList = function(list) { |
list.immutable$list = true; |
@@ -858,10 +858,10 @@ function(collectedClasses) { |
namer.instanceMethodName(null, Compiler.NO_SUCH_METHOD, 2); |
Collection<LibraryElement> libraries = compiler.libraries.getValues(); |
- String generateMethod(String methodName, Selector selector) { |
- StringBuffer buffer = new StringBuffer(); |
+ CodeBuffer generateMethod(String methodName, Selector selector) { |
+ CodeBuffer buffer = new CodeBuffer(); |
buffer.add('function'); |
- StringBuffer args = new StringBuffer(); |
+ CodeBuffer args = new CodeBuffer(); |
for (int i = 0; i < selector.argumentCount; i++) { |
if (i != 0) args.add(', '); |
args.add('arg$i'); |
@@ -876,7 +876,7 @@ function(collectedClasses) { |
buffer.add(" : $runtimeObjectPrototype.$noSuchMethodName.call("); |
buffer.add("this, '$methodName', [$args])\n"); |
buffer.add('}'); |
- return buffer.toString(); |
+ return buffer; |
} |
compiler.codegenWorld.invokedNames.forEach((SourceString methodName, |
@@ -888,14 +888,15 @@ function(collectedClasses) { |
for (LibraryElement lib in libraries) { |
String jsName = |
namer.instanceMethodInvocationName(lib, methodName, selector); |
- String method = |
+ CodeBuffer method = |
generateMethod(methodName.slowToString(), selector); |
defineInstanceMember(jsName, method); |
} |
} else { |
String jsName = |
namer.instanceMethodInvocationName(null, methodName, selector); |
- String method = generateMethod(methodName.slowToString(), selector); |
+ CodeBuffer method = generateMethod(methodName.slowToString(), |
+ selector); |
defineInstanceMember(jsName, method); |
} |
} |
@@ -907,14 +908,14 @@ function(collectedClasses) { |
if (getterName.isPrivate()) { |
for (LibraryElement lib in libraries) { |
String jsName = namer.getterName(lib, getterName); |
- String method = generateMethod('get ${getterName.slowToString()}', |
- Selector.GETTER); |
+ CodeBuffer method = generateMethod('get ${getterName.slowToString()}', |
+ Selector.GETTER); |
defineInstanceMember(jsName, method); |
} |
} else { |
String jsName = namer.getterName(null, getterName); |
- String method = generateMethod('get ${getterName.slowToString()}', |
- Selector.GETTER); |
+ CodeBuffer method = generateMethod('get ${getterName.slowToString()}', |
+ Selector.GETTER); |
defineInstanceMember(jsName, method); |
} |
}); |
@@ -924,20 +925,20 @@ function(collectedClasses) { |
if (setterName.isPrivate()) { |
for (LibraryElement lib in libraries) { |
String jsName = namer.setterName(lib, setterName); |
- String method = generateMethod('set ${setterName.slowToString()}', |
- Selector.SETTER); |
+ CodeBuffer method = generateMethod('set ${setterName.slowToString()}', |
+ Selector.SETTER); |
defineInstanceMember(jsName, method); |
} |
} else { |
String jsName = namer.setterName(null, setterName); |
- String method = generateMethod('set ${setterName.slowToString()}', |
- Selector.SETTER); |
+ CodeBuffer method = generateMethod('set ${setterName.slowToString()}', |
+ Selector.SETTER); |
defineInstanceMember(jsName, method); |
} |
}); |
} |
- String buildIsolateSetup(StringBuffer buffer, |
+ String buildIsolateSetup(CodeBuffer buffer, |
Element appMain, |
Element isolateMain) { |
String mainAccess = "${namer.isolateAccess(appMain)}"; |
@@ -975,7 +976,7 @@ $mainEnsureGetter |
return "${namer.isolateAccess(isolateMain)}($mainAccess)"; |
} |
- emitMain(StringBuffer buffer) { |
+ emitMain(CodeBuffer buffer) { |
if (compiler.isMockCompilation) return; |
Element main = compiler.mainApp.find(Compiler.MAIN); |
String mainCall = null; |
@@ -1057,8 +1058,19 @@ if (typeof window != 'undefined' && typeof document != 'undefined' && |
}); |
return compiler.assembledCode; |
} |
+ |
+ void addMappings(CodeBuffer buffer, int bufferOffset) { |
+ buffer.forEachSourceLocation((Element element, Token token, int offset) { |
+ SourceFile sourceFile = element.getCompilationUnit().script.file; |
+ String sourceName = null; |
+ if (token.kind === IDENTIFIER_TOKEN) { |
+ sourceName = token.slowToString(); |
+ } |
+ int totalOffset = bufferOffset + offset; |
+ sourceMapBuilder.addMapping( |
+ sourceFile, token.charOffset, sourceName, totalOffset); |
+ }); |
+ } |
} |
-typedef void DefineMemberFunction(String invocationName, |
- String definition, |
- [List<SourceMappingEntry> sourceMappings]); |
+typedef void DefineMemberFunction(String invocationName, CodeBuffer definition); |