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

Unified Diff: frog/gen.dart

Issue 9270048: Lots of frog cleanup (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 11 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
« no previous file with comments | « frog/element.dart ('k') | frog/lang.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: frog/gen.dart
diff --git a/frog/gen.dart b/frog/gen.dart
index 029c1a600d342812e4c0c82147c8fda705bb46e3..85d2311bd9c0dfcef34b7c694c21ba5332c0c6a1 100644
--- a/frog/gen.dart
+++ b/frog/gen.dart
@@ -19,6 +19,8 @@ class WorldGenerator {
CodeWriter writer;
CodeWriter _mixins;
+ CallingContext mainContext;
+
/**
* Whether the app has any static fields used. Note this could still be true
* and [globals] be empty if no static field has a default initialization.
@@ -35,10 +37,31 @@ class WorldGenerator {
WorldGenerator(this.main, this.writer)
: globals = {}, corejs = new CoreJs();
+ analyze() {
+ // Walk all code and find all NewExpressions - to determine possible types
+ int nlibs=0, ntypes=0, nmems=0, nnews=0;
+ //Set<Type> newedTypes = new Set<Type>();
+ for (var lib in world.libraries.getValues()) {
+ nlibs += 1;
+ for (var type in lib.types.getValues()) {
+ ntypes += 1;
+ var allMembers = [];
+ allMembers.addAll(type.constructors.getValues());
+ allMembers.addAll(type.members.getValues());
+ type.factories.forEach((f) => allMembers.add(f));
+ for (var m in allMembers) {
+ if (m.isAbstract || !m.isMethod) continue;
+
+ m.methodData.analyze();
+ }
+ }
+ }
+ }
+
run() {
- var metaGen = new MethodGenerator(main, null);
+ mainContext = new MethodGenerator(main, null);
var mainTarget = new TypeValue(main.declaringType, main.span);
- var mainCall = main.invoke(metaGen, null, mainTarget, Arguments.EMPTY);
+ var mainCall = main.invoke(mainContext, null, mainTarget, Arguments.EMPTY);
main.declaringType.markUsed();
if (options.compileAll) {
@@ -64,8 +87,8 @@ class WorldGenerator {
MethodMember isolateMain =
world.coreimpl.lookup('startRootIsolate', main.span);
var isolateMainTarget = new TypeValue(world.coreimpl.topType, main.span);
- mainCall = isolateMain.invoke(metaGen, null, isolateMainTarget,
- new Arguments(null, [main._get(metaGen, main.definition, null)]));
+ mainCall = isolateMain.invoke(mainContext, null, isolateMainTarget,
+ new Arguments(null, [main._get(mainContext, main.definition, null)]));
}
writeTypes(world.coreimpl);
@@ -208,10 +231,11 @@ class WorldGenerator {
for (var type in orderedTypes) {
if (type.isUsed && type.isClass) {
writeType(type);
-
- if (type.isGeneric) {
+ // TODO(jimhug): Performance is terrible if we use current
+ // reified generics approach for reified generic Arrays.
+ if (type.isGeneric && type !== world.listFactoryType) {
for (var ct in _orderValues(type._concreteTypes)) {
- writeType(ct);
+ if (ct.isUsed) writeType(ct);
}
}
} else if (type.isFunction && type.varStubs.length > 0) {
@@ -226,10 +250,8 @@ class WorldGenerator {
}
}
- genMethod(Member meth, [MethodGenerator enclosingMethod=null]) {
- if (!meth.isGenerated && !meth.isAbstract && meth.definition != null) {
- new MethodGenerator(meth, enclosingMethod).run();
- }
+ genMethod(MethodMember meth) {
+ meth.methodData.run(meth);
}
String _prototypeOf(Type type, String name) {
@@ -313,17 +335,9 @@ class WorldGenerator {
writeType(type.parent);
}
- // TODO(jimhug): Workaround for problems with reified generic Array.
- if (type.name != null && type is ConcreteType &&
- type.library == world.coreimpl &&
- type.name.startsWith('ListFactory')) {
- writer.writeln('${type.jsname} = ${type.genericType.jsname};');
- return;
- }
-
var typeName = type.jsname != null ? type.jsname : 'top level';
writer.comment('// ********** Code for ${typeName} **************');
- if (type.isNative && !type.isTop) {
+ if (type.isNative && !type.isTop && !type.isConcreteGeneric) {
var nativeName = type.definition.nativeType.name;
if (nativeName == '') {
writer.writeln('function ${type.jsname}() {}');
@@ -339,10 +353,17 @@ class WorldGenerator {
}
}
+ // TODO(jimhug): This comment below seems out-of-order now?
// We need the $inherits function to be declared before factory constructors
// so that inheritance ($inherits) will work correctly in IE.
if (!type.isTop) {
- if (type is ConcreteType) {
+ if (type.genericType !== type) {
+ corejs.ensureInheritsHelper();
+ writer.writeln('\$inherits(${type.jsname}, ${type.genericType.jsname});');
+ }
+
+ // TODO(jimhug): Do we still need this code below?
+ /*if (type is ConcreteType) {
ConcreteType c = type;
corejs.ensureInheritsHelper();
writer.writeln('\$inherits(${c.jsname}, ${c.genericType.jsname});');
@@ -356,7 +377,8 @@ class WorldGenerator {
_ensureInheritMembersHelper();
_mixins.writeln('\$inheritsMembers(${c.jsname}, ${p.jsname});');
}
- } else if (!type.isNative) {
+ } else*/
+ else if (!type.isNative) {
if (type.parent != null && !type.parent.isObject) {
corejs.ensureInheritsHelper();
writer.writeln('\$inherits(${type.jsname}, ${type.parent.jsname});');
@@ -367,31 +389,26 @@ class WorldGenerator {
if (type.isTop) {
// no preludes for top type
} else if (type.constructors.length == 0) {
- if (!type.isNative) {
+ if (!type.isNative || type.isConcreteGeneric) {
// TODO(jimhug): More guards to guarantee staticness
writer.writeln('function ${type.jsname}() {}');
}
} else {
- Member standardConstructor = type.constructors[''];
- if (standardConstructor == null ||
- standardConstructor.generator == null) {
- if (!type.isNative) {
- writer.writeln('function ${type.jsname}() {}');
+ bool wroteStandard = false;
+ for (var c in type.constructors.getValues()) {
+ if (c.methodData.writeDefinition(c, writer)) {
+ if (c.isConstructor && c.constructorName == '') wroteStandard = true;
}
- } else {
- standardConstructor.generator.writeDefinition(writer, null);
}
- for (var c in type.constructors.getValues()) {
- if (c.generator != null && c != standardConstructor) {
- c.generator.writeDefinition(writer, null);
- }
+ if (!wroteStandard && (!type.isNative || type.genericType !== type)) {
+ writer.writeln('function ${type.jsname}() {}');
}
}
// Concrete types (like List<String>) will have this already defined on
// their prototype from the generic type (like List)
- if (type is! ConcreteType) {
+ if (!type.isConcreteGeneric) {
_maybeIsTest(type, type);
}
if (type.genericType._concreteTypes != null) {
@@ -459,16 +476,7 @@ class WorldGenerator {
* This predicate determines when we need to define lib_Float32Array.
*/
_typeNeedsHolderForStaticMethods(Type type) {
- for (var member in type.members.getValues()) {
- if (member.isMethod) {
- if (member.isConstructor || member.isStatic) {
- if (member.isGenerated) {
- return true;
- }
- }
- }
- }
- return false;
+ return type.isUsed;
sra1 2012/01/23 20:40:30 This new code causes 500 useless dummy declaration
}
/**
@@ -520,7 +528,8 @@ function $inheritsMembers(child, parent) {
}
// generate code for instance fields
- if (field._providePropertySyntax) {
+ if (field._providePropertySyntax &&
+ !field.declaringType.isConcreteGeneric) {
_writePrototypePatch(field.declaringType, 'get\$${field.jsname}',
'function() { return this.${field.jsname}; }', writer);
if (!field.isFinal) {
@@ -539,7 +548,7 @@ function $inheritsMembers(child, parent) {
if (property.setter != null) _writeMethod(property.setter);
// TODO(jmesserly): make sure we don't do this on hidden native types!
- if (property._provideFieldSyntax) {
+ if (property.needsFieldSyntax) {
writer.enterBlock('Object.defineProperty(' +
'${property.declaringType.jsname}.prototype, "${property.jsname}", {');
if (property.getter != null) {
@@ -557,11 +566,10 @@ function $inheritsMembers(child, parent) {
}
}
- _writeMethod(Member m) {
- if (m.generator != null) {
- m.generator.writeDefinition(writer, null);
- } else if (m is MethodMember && m.isNative
- && m._providePropertySyntax && !m._provideFieldSyntax) {
+ _writeMethod(MethodMember m) {
+ m.methodData.writeDefinition(m, writer);
+
+ if (m.isNative && m._providePropertySyntax) {
MethodGenerator._maybeGenerateBoundGetter(m, writer);
}
}
@@ -747,7 +755,7 @@ function $inheritsMembers(child, parent) {
/**
* A naive code generator for Dart.
*/
-class MethodGenerator implements TreeVisitor {
+class MethodGenerator implements TreeVisitor, CallingContext {
Member method;
CodeWriter writer;
BlockScope _scope;
@@ -791,6 +799,9 @@ class MethodGenerator implements TreeVisitor {
return library._findMembers(name);
}
+ bool get needsCode() => true;
+ bool get showWarnings() => false;
+
bool get isClosure() => (enclosingMethod != null);
bool get isStatic() => method.isStatic;
@@ -834,12 +845,6 @@ class MethodGenerator implements TreeVisitor {
}
run() {
- if (method.isGenerated) return;
-
- // This avoids any attempts to infer across recursion.
- method.isGenerated = true;
- method.generator = this;
-
// Create most generic possible call for this method.
var thisObject;
if (method.isConstructor) {
@@ -855,17 +860,6 @@ class MethodGenerator implements TreeVisitor {
var args = new Arguments(null, values);
evalBody(thisObject, args);
-
- if (method.definition.nativeBody != null) {
- // Throw away the code--it was just used for tree shaking purposes.
- writer = new CodeWriter();
- if (method.definition.nativeBody == '') {
- method.generator = null;
- } else {
- _paramCode = map(method.parameters, (p) => p.name);
- writer.write(method.definition.nativeBody);
- }
- }
}
@@ -956,11 +950,6 @@ class MethodGenerator implements TreeVisitor {
// TODO(jimhug): Bind not available in older Safari, need fallback?
defWriter.writeln('return this.${m.jsname}.bind(this);');
defWriter.exitBlock(suffix);
-
- if (m._provideFieldSyntax) {
- world.internalError('bound "${m.name}" accessed with field syntax',
- m.definition.span);
- }
}
}
@@ -975,7 +964,7 @@ class MethodGenerator implements TreeVisitor {
if (meth._provideOptionalParamInfo) {
var optNames = [];
var optValues = [];
- meth.genParameterValues();
+ meth.genParameterValues(this);
for (var param in meth.parameters) {
if (param.isOptional) {
optNames.add(param.name);
@@ -1033,7 +1022,7 @@ class MethodGenerator implements TreeVisitor {
currentArg = args.getValue(p.name);
if (currentArg === null) {
// Ensure default value for param has been generated
- p.genValue(method, method.generator);
+ p.genValue(method, this);
currentArg = p.value;
}
}
@@ -1052,7 +1041,7 @@ class MethodGenerator implements TreeVisitor {
}
var initializerCall = null;
- final declaredInitializers = method.definition.initializers;
+ final declaredInitializers = method.definition.dynamic.initializers;
if (declaredInitializers != null) {
for (var init in declaredInitializers) {
if (init is CallExpression) {
@@ -1120,7 +1109,7 @@ class MethodGenerator implements TreeVisitor {
}
}
- var body = method.definition.body;
+ var body = method.definition.dynamic.body;
if (body === null) {
// TODO(jimhug): Move check into resolve on method.
@@ -1316,6 +1305,7 @@ class MethodGenerator implements TreeVisitor {
var meth = new MethodMember(name, method.declaringType, func);
meth.isLambda = true;
meth.enclosingElement = method;
+ meth._methodData = new MethodData(meth, this);
meth.resolve();
return meth;
}
@@ -1376,7 +1366,7 @@ class MethodGenerator implements TreeVisitor {
isFinal = true;
}
writer.write('var ');
- var type = method.resolveType(node.type, false);
+ var type = method.resolveType(node.type, false, true);
for (int i=0; i < node.names.length; i++) {
if (i > 0) {
writer.write(', ');
@@ -1413,8 +1403,7 @@ class MethodGenerator implements TreeVisitor {
var funcValue = _scope.create(meth.name, meth.functionType,
method.definition.span, isFinal:true);
- world.gen.genMethod(meth, this);
- meth.generator.writeDefinition(writer, null);
+ meth.methodData.createFunction(writer);
return false;
}
@@ -1574,13 +1563,15 @@ class MethodGenerator implements TreeVisitor {
bool _isFinal(typeRef) {
if (typeRef is GenericTypeReference) {
typeRef = typeRef.baseType;
+ } else if (typeRef is SimpleTypeReference) {
+ return false;
}
return typeRef != null && typeRef.isFinal;
}
bool visitForInStatement(ForInStatement node) {
// TODO(jimhug): visitValue and other cleanups here.
- var itemType = method.resolveType(node.item.type, false);
+ var itemType = method.resolveType(node.item.type, false, true);
var list = node.list.visit(this);
_visitLoop(node, () {
_visitForInBody(node, itemType, list);
@@ -1599,8 +1590,8 @@ class MethodGenerator implements TreeVisitor {
list = listVar;
}
- // Special path for list for readability and perf optimization.
- if (list.type.isList) {
+ // Special path for concrete Arrays for readability and perf optimization.
+ if (list.type.genericType == world.listFactoryType) {
var tmpi = _scope.create('\$i', world.numType, null);
var listLength = list.get_(this, 'length', node.list);
writer.enterBlock('for (var ${tmpi.code} = 0;' +
@@ -1645,7 +1636,7 @@ class MethodGenerator implements TreeVisitor {
// multiple catch, such as no extra temp or if-else-if chain.
var catch_ = node.catches[0];
_pushBlock(catch_);
- var exType = method.resolveType(catch_.exception.type, false);
+ var exType = method.resolveType(catch_.exception.type, false, true);
var ex = _scope.declare(catch_.exception);
_scope.rethrow = ex.code;
writer.nextBlock('} catch (${ex.code}) {');
@@ -1682,7 +1673,7 @@ class MethodGenerator implements TreeVisitor {
var catch_ = node.catches[i];
_pushBlock(catch_);
- var tmpType = method.resolveType(catch_.exception.type, false);
+ var tmpType = method.resolveType(catch_.exception.type, false, true);
var tmp = _scope.declare(catch_.exception);
if (!tmpType.isVarOrObject) {
var test = ex.instanceOf(this, tmpType, catch_.exception.span,
@@ -1887,21 +1878,7 @@ class MethodGenerator implements TreeVisitor {
var name = (node.func.name != null) ? node.func.name.name : '';
MethodMember meth = _makeLambdaMethod(name, node.func);
- final lambdaGen = new MethodGenerator(meth, this);
- if (name != '') {
- // Note: we don't want to put this in our enclosing scope because the
- // name shouldn't be visible except inside the lambda. We also don't want
- // to put the name directly in the lambda's scope because parameters are
- // allowed to shadow it. So we create an extra scope for it to go into.
- lambdaGen._scope.create(name, meth.functionType, meth.definition.span,
- isFinal:true);
- lambdaGen._pushBlock(node);
- }
- lambdaGen.run();
-
- var w = new CodeWriter();
- meth.generator.writeDefinition(w, node);
- return new Value(meth.functionType, w.text, node.span);
+ return meth.methodData.createLambda(node, this);
}
visitCallExpression(CallExpression node) {
@@ -2067,13 +2044,12 @@ class MethodGenerator implements TreeVisitor {
switch (node.op.kind) {
case TokenKind.INCR:
case TokenKind.DECR:
- // TODO(jimhug): Requires non-null num to be correct.
- if (value.type.isNum) {
+ // TODO(jimhug): Hackish optimization not always correct
+ if (value.type.isNum && !value.isFinal && node.self is VarExpression) {
return new Value(value.type, '${node.op}${value.code}', node.span);
} else {
// ++x becomes x += 1
// --x becomes x -= 1
- // TODO(jimhug): Confirm that --x becomes x -= 1 as it is in VM.
var kind = (TokenKind.INCR == node.op.kind ?
TokenKind.ADD : TokenKind.SUB);
// TODO(jimhug): Shouldn't need a full-expression here.
@@ -2100,9 +2076,10 @@ class MethodGenerator implements TreeVisitor {
}
visitPostfixExpression(PostfixExpression node, [bool isVoid = false]) {
+ // TODO(jimhug): Hackish optimization here to revisit in many ways...
var value = visitValue(node.body);
- // TODO(jimhug): Move and validate this code with nullable ints.
- if (value.type.isNum && !value.isFinal) {
+ if (value.type.isNum && !value.isFinal && node.body is VarExpression) {
+ // Would like to also do on "pure" fields - check to see if possible...
return new Value(value.type, '${value.code}${node.op}', node.span);
}
@@ -2129,7 +2106,7 @@ class MethodGenerator implements TreeVisitor {
// Named constructors and library prefixes, oh my!
// At last, we can collapse the ambiguous wave function...
- if (constructorName == '' && typeRef is !GenericTypeReference &&
+ if (constructorName == '' && typeRef is NameTypeReference &&
typeRef.names != null) {
// Pull off the last name from the type, guess it's the constructor name.
@@ -2141,7 +2118,7 @@ class MethodGenerator implements TreeVisitor {
typeRef.isFinal, typeRef.name, names, typeRef.span);
}
- var type = method.resolveType(typeRef, true);
+ var type = method.resolveType(typeRef, true, true);
if (type.isTop) {
type = type.library.findTypeByName(constructorName);
constructorName = '';
@@ -2186,7 +2163,7 @@ class MethodGenerator implements TreeVisitor {
var listType = world.listType;
var type = world.varType;
if (node.itemType != null) {
- type = method.resolveType(node.itemType, true);
+ type = method.resolveType(node.itemType, true, !node.isConst);
if (node.isConst && (type is ParameterType || type.hasTypeParams)) {
world.error('type parameter cannot be used in const list literals');
}
@@ -2220,7 +2197,7 @@ class MethodGenerator implements TreeVisitor {
var mapType = world.mapType; // TODO(jimhug): immutable type?
if (node.valueType !== null) {
if (node.keyType !== null) {
- keyType = method.resolveType(node.keyType, true);
+ keyType = method.resolveType(node.keyType, true, !node.isConst);
// TODO(jimhug): Would be nice to allow arbitrary keys here (this is
// currently not allowed by the spec).
if (!keyType.isString) {
@@ -2233,7 +2210,7 @@ class MethodGenerator implements TreeVisitor {
}
}
- valueType = method.resolveType(node.valueType, true);
+ valueType = method.resolveType(node.valueType, true, !node.isConst);
if (node.isConst &&
(valueType is ParameterType || valueType.hasTypeParams)) {
world.error('type parameter cannot be used in const map literals');
@@ -2274,7 +2251,11 @@ class MethodGenerator implements TreeVisitor {
visitIsExpression(IsExpression node) {
var value = visitValue(node.x);
- var type = method.resolveType(node.type, false);
+ var type = method.resolveType(node.type, true, true);
+ if (type.isVar) {
+ return Value.comma(value, Value.fromBool(true, node.span));
+ }
+
return value.instanceOf(this, type, node.span, node.isTrue);
}
@@ -2472,6 +2453,18 @@ class Arguments {
}
return new Arguments(nodes, result);
}
+
+ bool matches(Arguments other) {
+ if (length != other.length) return false;
+ if (bareCount != other.bareCount) return false;
+
+ for (int i = 0; i < bareCount; i++) {
+ if (values[i].type != other.values[i].type) return false;
+ }
+ // TODO(jimhug): Needs to check that named args also match!
+ return true;
+ }
+
}
class ReturnKind {
« no previous file with comments | « frog/element.dart ('k') | frog/lang.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698