Skip to content

Commit 36518b8

Browse files
author
John Messerly
committed
fixes #146, JS globals were not understood by the renamer
there are two basic strategies to fix: we either provide globals to the renamer, or it determines them based on use. I went with the second approach, as it fits more naturally with the current code generator. [email protected] Review URL: https://codereview.chromium.org/1099813006
1 parent 0efa91a commit 36518b8

File tree

4 files changed

+128
-64
lines changed

4 files changed

+128
-64
lines changed

pkg/dev_compiler/lib/runtime/dart/collection.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2859,7 +2859,7 @@ var collection;
28592859
let _TypeTest = _TypeTest$();
28602860
let _comparator = Symbol('_comparator');
28612861
let _validKey = Symbol('_validKey');
2862-
let _internal = Symbol('_internal');
2862+
let _internal$ = Symbol('_internal');
28632863
let SplayTreeMap$ = dart.generic(function(K, V) {
28642864
class SplayTreeMap extends _SplayTree$(K) {
28652865
SplayTreeMap(compare, isValidKey) {
@@ -2903,7 +2903,7 @@ var collection;
29032903
[_compare](key1, key2) {
29042904
return this[_comparator](key1, key2);
29052905
}
2906-
[_internal]() {
2906+
[_internal$]() {
29072907
this[_comparator] = null;
29082908
this[_validKey] = null;
29092909
super._SplayTree();
@@ -3064,7 +3064,7 @@ var collection;
30643064
dart.defineNamedConstructor(SplayTreeMap, 'from');
30653065
dart.defineNamedConstructor(SplayTreeMap, 'fromIterable');
30663066
dart.defineNamedConstructor(SplayTreeMap, 'fromIterables');
3067-
dart.defineNamedConstructor(SplayTreeMap, _internal);
3067+
dart.defineNamedConstructor(SplayTreeMap, _internal$);
30683068
return SplayTreeMap;
30693069
});
30703070
let SplayTreeMap = SplayTreeMap$();

pkg/dev_compiler/lib/runtime/dart/core.js

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ var core;
100100
return Comparable;
101101
});
102102
let Comparable = Comparable$();
103-
let _internal = dart.JsSymbol('_internal');
103+
let _internal$ = dart.JsSymbol('_internal');
104104
let _now = dart.JsSymbol('_now');
105105
let _brokenDownDateToMillisecondsSinceEpoch = dart.JsSymbol('_brokenDownDateToMillisecondsSinceEpoch');
106106
let _MAX_MILLISECONDS_SINCE_EPOCH = dart.JsSymbol('_MAX_MILLISECONDS_SINCE_EPOCH');
@@ -122,7 +122,7 @@ var core;
122122
second = 0;
123123
if (millisecond === void 0)
124124
millisecond = 0;
125-
this[_internal](year, month, day, hour, minute, second, millisecond, false);
125+
this[_internal$](year, month, day, hour, minute, second, millisecond, false);
126126
}
127127
utc(year, month, day, hour, minute, second, millisecond) {
128128
if (month === void 0)
@@ -137,7 +137,7 @@ var core;
137137
second = 0;
138138
if (millisecond === void 0)
139139
millisecond = 0;
140-
this[_internal](year, month, day, hour, minute, second, millisecond, true);
140+
this[_internal$](year, month, day, hour, minute, second, millisecond, true);
141141
}
142142
now() {
143143
this[_now]();
@@ -306,7 +306,7 @@ var core;
306306
let otherMs = other.millisecondsSinceEpoch;
307307
return new Duration({milliseconds: dart.notNull(ms) - dart.notNull(otherMs)});
308308
}
309-
[_internal](year, month, day, hour, minute, second, millisecond, isUtc) {
309+
[_internal$](year, month, day, hour, minute, second, millisecond, isUtc) {
310310
this.isUtc = typeof isUtc == 'boolean' ? isUtc : dart.throw_(new ArgumentError(isUtc));
311311
this.millisecondsSinceEpoch = dart.as(_js_helper.checkInt(_js_helper.Primitives.valueFromDecomposedDate(year, month, day, hour, minute, second, millisecond, isUtc)), int);
312312
}
@@ -356,7 +356,7 @@ var core;
356356
dart.defineNamedConstructor(DateTime, 'utc');
357357
dart.defineNamedConstructor(DateTime, 'now');
358358
dart.defineNamedConstructor(DateTime, 'fromMillisecondsSinceEpoch');
359-
dart.defineNamedConstructor(DateTime, _internal);
359+
dart.defineNamedConstructor(DateTime, _internal$);
360360
dart.defineNamedConstructor(DateTime, _now);
361361
DateTime.MONDAY = 1;
362362
DateTime.TUESDAY = 2;
@@ -1965,12 +1965,12 @@ var core;
19651965
} else if (char == Uri[_NUMBER_SIGN]) {
19661966
fragment = Uri[_makeFragment](uri, dart.notNull(index) + 1, uri.length);
19671967
}
1968-
return new Uri[_internal](scheme, userinfo, host, port, path, query, fragment);
1968+
return new Uri[_internal$](scheme, userinfo, host, port, path, query, fragment);
19691969
}
19701970
static [_fail](uri, index, message) {
19711971
throw new FormatException(message, uri, index);
19721972
}
1973-
[_internal](scheme, userInfo, host, port, path, query, fragment) {
1973+
[_internal$](scheme, userInfo, host, port, path, query, fragment) {
19741974
this.scheme = scheme;
19751975
this[_userInfo] = userInfo;
19761976
this[_host] = host;
@@ -2005,7 +2005,7 @@ var core;
20052005
}
20062006
let ensureLeadingSlash = host != null;
20072007
path = Uri[_makePath](path, 0, Uri[_stringOrNullLength](path), pathSegments, ensureLeadingSlash, isFile);
2008-
return new Uri[_internal](scheme, userInfo, host, port, path, query, fragment);
2008+
return new Uri[_internal$](scheme, userInfo, host, port, path, query, fragment);
20092009
}
20102010
http(authority, unencodedPath, queryParameters) {
20112011
if (queryParameters === void 0)
@@ -2215,7 +2215,7 @@ var core;
22152215
} else if (this.hasFragment) {
22162216
fragment = this.fragment;
22172217
}
2218-
return new Uri[_internal](scheme, userInfo, host, port, path, query, fragment);
2218+
return new Uri[_internal$](scheme, userInfo, host, port, path, query, fragment);
22192219
}
22202220
get pathSegments() {
22212221
if (this[_pathSegments] == null) {
@@ -2649,7 +2649,7 @@ var core;
26492649
}
26502650
}
26512651
let fragment = reference.hasFragment ? reference.fragment : null;
2652-
return new Uri[_internal](targetScheme, targetUserInfo, targetHost, targetPort, targetPath, targetQuery, fragment);
2652+
return new Uri[_internal$](targetScheme, targetUserInfo, targetHost, targetPort, targetPath, targetQuery, fragment);
26532653
}
26542654
get hasAuthority() {
26552655
return this[_host] != null;
@@ -3009,7 +3009,7 @@ var core;
30093009
return dart.notNull(codeUnit) >= dart.notNull(Uri[_LOWER_CASE_A]) && dart.notNull(codeUnit) <= dart.notNull(Uri[_LOWER_CASE_Z]) || dart.notNull(codeUnit) >= dart.notNull(Uri[_UPPER_CASE_A]) && dart.notNull(codeUnit) <= dart.notNull(Uri[_UPPER_CASE_Z]);
30103010
}
30113011
}
3012-
dart.defineNamedConstructor(Uri, _internal);
3012+
dart.defineNamedConstructor(Uri, _internal$);
30133013
dart.defineNamedConstructor(Uri, 'http');
30143014
dart.defineNamedConstructor(Uri, 'https');
30153015
dart.defineNamedConstructor(Uri, 'file');

pkg/dev_compiler/lib/src/codegen/js_names.dart

Lines changed: 77 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class JSNamer extends LocalNamer {
3434
JSNamer(Node node) : renames = new _RenameVisitor.build(node).renames;
3535

3636
String getName(Identifier node) {
37-
var rename = renames[renameKey(node)];
37+
var rename = renames[identifierKey(node)];
3838
if (rename != null) return rename;
3939

4040
assert(!needsRename(node));
@@ -45,81 +45,108 @@ class JSNamer extends LocalNamer {
4545
void leaveScope() {}
4646
}
4747

48+
/// Represents a complete function scope in JS.
49+
///
50+
/// We don't currently track ES6 block scopes, because we don't represent them
51+
/// in js_ast yet.
4852
class _FunctionScope {
53+
/// The parent scope.
4954
final _FunctionScope parent;
50-
final names = new HashSet<String>();
55+
56+
/// All names declared in this scope.
57+
final declared = new HashSet<Object>();
58+
59+
/// All names [declared] in this scope or its [parent]s, that is used in this
60+
/// scope and/or children. This is exactly the set of variable names we must
61+
/// not collide with inside this scope.
62+
final used = new HashSet<String>();
63+
64+
/// Nested functions, these are visited after everything else so the names
65+
/// they might need are in scope.
66+
final functions = new List<FunctionExpression>();
67+
5168
_FunctionScope(this.parent);
5269
}
5370

5471
/// Collects all names used in the visited tree.
55-
class _RenameVisitor extends BaseVisitor {
72+
class _RenameVisitor extends VariableDeclarationVisitor {
5673
final pendingRenames = new Map<Object, Set<_FunctionScope>>();
5774
final renames = new HashMap<Object, String>();
5875

59-
_FunctionScope scope = new _FunctionScope(null);
76+
final _FunctionScope rootScope = new _FunctionScope(null);
77+
_FunctionScope scope;
6078

6179
_RenameVisitor.build(Node root) {
80+
scope = rootScope;
6281
root.accept(this);
82+
_finishFunctions();
6383
_finishNames();
6484
}
6585

86+
declare(Identifier node) {
87+
var id = identifierKey(node);
88+
scope.declared.add(id);
89+
_markUsed(node, id, scope);
90+
}
91+
6692
visitIdentifier(Identifier node) {
93+
var id = identifierKey(node);
94+
95+
// Find where the node was declared.
96+
var declScope = scope;
97+
while (declScope != null && !declScope.declared.contains(id)) {
98+
declScope = declScope.parent;
99+
}
100+
if (declScope == null) {
101+
// Assume it comes from the global scope.
102+
declScope = rootScope;
103+
declScope.declared.add(id);
104+
}
105+
_markUsed(node, id, declScope);
106+
}
107+
108+
_markUsed(Identifier node, Object id, _FunctionScope declScope) {
109+
// If it needs rename, we can't add it to the used name set yet, instead we
110+
// will record all scopes it is visible in.
111+
Set<_FunctionScope> usedIn = null;
67112
if (needsRename(node)) {
68-
// We can't assign the name yet, but we can add it to the list of things
69-
// that need a name.
70-
var id = renameKey(node);
71-
pendingRenames.putIfAbsent(id, () => new HashSet()).add(scope);
72-
} else {
73-
scope.names.add(node.name);
113+
usedIn = pendingRenames.putIfAbsent(id, () => new HashSet());
114+
}
115+
116+
for (var s = scope, end = declScope.parent; s != end; s = s.parent) {
117+
if (usedIn != null) {
118+
usedIn.add(s);
119+
} else {
120+
s.used.add(node.name);
121+
}
74122
}
75123
}
76124

77125
visitFunctionExpression(FunctionExpression node) {
78-
scope = new _FunctionScope(scope);
79-
super.visitFunctionExpression(node);
80-
scope = scope.parent;
126+
// Visit nested functions after all identifiers are declared.
127+
scope.functions.add(node);
128+
}
129+
130+
void _finishFunctions() {
131+
for (var f in scope.functions) {
132+
scope = new _FunctionScope(scope);
133+
super.visitFunctionExpression(f);
134+
_finishFunctions();
135+
scope = scope.parent;
136+
}
81137
}
82138

83139
void _finishNames() {
140+
var allNames = new Set<String>();
84141
pendingRenames.forEach((id, scopes) {
85-
var name = _findName(id, _allNamesInScope(scopes));
86-
renames[id] = name;
87-
for (var s in scopes) s.names.add(name);
88-
});
89-
}
142+
allNames.clear();
143+
for (var s in scopes) allNames.addAll(s.used);
90144

91-
// Given a set of scopes, populates [allNames] to include all names in those
92-
// scopes as well as intermediate scopes. Returns the common parent of
93-
// all scopes. For example:
94-
//
95-
// function outer(t) {
96-
// function middle(x) {
97-
// function inner() { return t; }
98-
// foo(x);
99-
// }
100-
// }
101-
//
102-
// Here `t` is used in `inner` and `outer` but we need to include `middle`
103-
// as well, so we know the rename of `t` to `x` is not valid.
104-
static Set<String> _allNamesInScope(Set<_FunctionScope> scopes) {
105-
// As we iterate, we'll add more scopes. We don't need to consider these
106-
// as intermediate scopes can't introduce new intermediates.
107-
var candidates = [];
108-
var allScopes = scopes.toSet();
109-
for (var scope in scopes) {
110-
for (var p = scope.parent; p != null; p = p.parent) {
111-
if (allScopes.contains(p)) {
112-
allScopes.addAll(candidates);
113-
break;
114-
}
115-
candidates.add(p);
116-
}
117-
// Discard these, we already added them or we didn't find a parent scope.
118-
candidates.clear();
119-
}
145+
var name = _findName(id, allNames);
146+
renames[id] = name;
120147

121-
// Now collect all names found.
122-
return allScopes.expand((s) => s.names).toSet();
148+
for (var s in scopes) s.used.add(name);
149+
});
123150
}
124151

125152
static String _findName(Object id, Set<String> usedNames) {
@@ -154,7 +181,7 @@ class _RenameVisitor extends BaseVisitor {
154181
bool needsRename(Identifier node) =>
155182
node is JSTemporary || node.allowRename && invalidJSVariableName(node.name);
156183

157-
Object /*String|JSTemporary*/ renameKey(Identifier node) =>
184+
Object /*String|JSTemporary*/ identifierKey(Identifier node) =>
158185
node is JSTemporary ? node : node.name;
159186

160187
/// Returns true for invalid JS variable names, such as keywords.

pkg/dev_compiler/lib/src/js/printer.dart

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,3 +1385,40 @@ class MinifyRenamer implements LocalNamer {
13851385
return newName;
13861386
}
13871387
}
1388+
1389+
/// Like [BaseVisitor], but calls [declare] for [Identifier] declarations, and
1390+
/// [visitIdentifier] otherwise.
1391+
abstract class VariableDeclarationVisitor<T> extends BaseVisitor<T> {
1392+
declare(Identifier node);
1393+
1394+
visitFunctionExpression(FunctionExpression node) {
1395+
for (Identifier param in node.params) declare(param);
1396+
node.body.accept(this);
1397+
}
1398+
1399+
visitVariableInitialization(VariableInitialization node) {
1400+
declare(node.declaration);
1401+
if (node.value != null) node.value.accept(this);
1402+
}
1403+
1404+
visitCatch(Catch node) {
1405+
declare(node.declaration);
1406+
node.body.accept(this);
1407+
}
1408+
1409+
visitFunctionDeclaration(FunctionDeclaration node) {
1410+
declare(node.name);
1411+
node.function.accept(this);
1412+
}
1413+
1414+
visitNamedFunction(NamedFunction node) {
1415+
declare(node.name);
1416+
node.function.accept(this);
1417+
}
1418+
1419+
visitClassExpression(ClassExpression node) {
1420+
declare(node.name);
1421+
if (node.heritage != null) node.heritage.accept(this);
1422+
for (Method element in node.methods) element.accept(this);
1423+
}
1424+
}

0 commit comments

Comments
 (0)