fix #27644, allow "dart" and "dartx" to be renamed if needed

R=vsm@google.com

Review URL: https://codereview.chromium.org/2435223002 .
This commit is contained in:
Jennifer Messerly 2016-10-21 11:48:19 -07:00
parent 982f9f46ed
commit ce76fc1fe5
3 changed files with 213 additions and 134 deletions

View file

@ -74,7 +74,7 @@ class CodeGenerator extends GeneralizingAstVisitor
final _moduleItems = <JS.ModuleItem>[];
/// Table of named and possibly hoisted types.
final _typeTable = new TypeTable();
TypeTable _typeTable;
/// The global extension type table.
final ExtensionTypeSet _extensionTypes;
@ -97,8 +97,8 @@ class CodeGenerator extends GeneralizingAstVisitor
final _initializingFormalTemps =
new HashMap<ParameterElement, JS.TemporaryId>();
final _dartxVar = new JS.Identifier('dartx');
final _runtimeLibVar = new JS.Identifier('dart');
JS.Identifier _extensionSymbolsModule;
JS.Identifier _runtimeModule;
final namedArgumentTemp = new JS.TemporaryId('opts');
final _hasDeferredSupertype = new HashSet<ClassElement>();
@ -231,6 +231,18 @@ class CodeGenerator extends GeneralizingAstVisitor
// Transform the AST to make coercions explicit.
compilationUnits = CoercionReifier.reify(compilationUnits);
if (compilationUnits.any((u) => _isDartRuntime(u.element.library))) {
// Don't allow these to be renamed when we're building the SDK.
// There is JS code in dart:* that depends on their names.
_runtimeModule = new JS.Identifier('dart');
_extensionSymbolsModule = new JS.Identifier('dartx');
} else {
// Otherwise allow these to be renamed so users can write them.
_runtimeModule = new JS.TemporaryId('dart');
_extensionSymbolsModule = new JS.TemporaryId('dartx');
}
_typeTable = new TypeTable(_runtimeModule);
// Initialize our library variables.
var items = <JS.ModuleItem>[];
for (var unit in compilationUnits) {
@ -238,7 +250,7 @@ class CodeGenerator extends GeneralizingAstVisitor
if (unit.element != library.definingCompilationUnit) continue;
var libraryTemp = _isDartRuntime(library)
? _runtimeLibVar
? _runtimeModule
: new JS.TemporaryId(jsLibraryName(_libraryRoot, library));
_libraries[library] = libraryTemp;
items.add(new JS.ExportDeclaration(
@ -247,8 +259,8 @@ class CodeGenerator extends GeneralizingAstVisitor
// dart:_runtime has a magic module that holds extension method symbols.
// TODO(jmesserly): find a cleaner design for this.
if (_isDartRuntime(library)) {
items.add(new JS.ExportDeclaration(
js.call('const # = Object.create(null)', [_dartxVar])));
items.add(new JS.ExportDeclaration(js
.call('const # = Object.create(null)', [_extensionSymbolsModule])));
}
}
@ -332,7 +344,7 @@ class CodeGenerator extends GeneralizingAstVisitor
var jsName = _getJSName(e);
if (jsName == null) return null;
var fullName = ['global']..addAll(jsName);
JS.Expression access = _runtimeLibVar;
JS.Expression access = _runtimeModule;
for (var part in fullName) {
access = new JS.PropertyAccess(access, js.string(part));
}
@ -391,8 +403,8 @@ class CodeGenerator extends GeneralizingAstVisitor
var imports =
libraries.map((l) => new JS.NameSpecifier(_imports[l])).toList();
if (module == coreModuleName) {
imports.add(new JS.NameSpecifier(_runtimeLibVar));
imports.add(new JS.NameSpecifier(_dartxVar));
imports.add(new JS.NameSpecifier(_runtimeModule));
imports.add(new JS.NameSpecifier(_extensionSymbolsModule));
}
items.add(new JS.ImportDeclaration(
namedImports: imports, from: js.string(module, "'")));
@ -508,8 +520,8 @@ class CodeGenerator extends GeneralizingAstVisitor
} else {
// top-level fields, getters, setters need to copy the property
// descriptor.
_moduleItems.add(js.statement('dart.export(#, #, #);',
[libraryName, name.receiver, name.selector]));
_moduleItems.add(_callHelperStatement(
'export(#, #, #);', [libraryName, name.receiver, name.selector]));
}
}
@ -553,7 +565,7 @@ class CodeGenerator extends GeneralizingAstVisitor
// Make sure to check when converting to int.
if (from != types.intType && to == types.intType) {
// TODO(jmesserly): fuse this with notNull check.
return js.call('dart.asInt(#)', jsFrom);
return _callHelper('asInt(#)', jsFrom);
}
// A no-op in JavaScript.
@ -607,7 +619,7 @@ class CodeGenerator extends GeneralizingAstVisitor
FunctionTypeAliasElement element = node.element;
JS.Expression body = annotate(
js.call('dart.typedef(#, () => #)', [
_callHelper('typedef(#, () => #)', [
js.string(element.name, "'"),
_emitType(element.type, nameType: false, lowerTypedef: true)
]),
@ -629,7 +641,7 @@ class CodeGenerator extends GeneralizingAstVisitor
// TODO(jmesserly): if the type fails to resolve, should we generate code
// that throws instead?
assert(options.unsafeForceCompile || options.replCompile);
return js.call('dart.dynamic');
return _callHelper('dynamic');
}
return _emitType(node.type);
}
@ -794,7 +806,7 @@ class CodeGenerator extends GeneralizingAstVisitor
classExpr.name, _emitCallableClassConstructor(unnamedCtor));
// Name the constructor function the same as the class.
return js.call('dart.callableClass(#, #)', [ctor, classExpr]);
return _callHelper('callableClass(#, #)', [ctor, classExpr]);
}
/// Emits a constructor that ensures instances of this class are callable as
@ -825,21 +837,21 @@ class CodeGenerator extends GeneralizingAstVisitor
body.add(js.statement(
'#.is = function is_Object(o) {'
' if (o instanceof this) return true;'
' return dart.is(o, this);'
' return #.is(o, this);'
'}',
className));
[className, _runtimeModule]));
body.add(js.statement(
'#.as = function as_Object(o) {'
' if (o == null || o instanceof this) return o;'
' return dart.as(o, this);'
' return #.as(o, this);'
'}',
className));
[className, _runtimeModule]));
body.add(js.statement(
'#._check = function check_Object(o) {'
' if (o == null || o instanceof this) return o;'
' return dart.check(o, this);'
' return #.check(o, this);'
'}',
className));
[className, _runtimeModule]));
return;
}
if (classElem == stringClass) {
@ -849,15 +861,15 @@ class CodeGenerator extends GeneralizingAstVisitor
body.add(js.statement(
'#.as = function as_String(o) {'
' if (typeof o == "string" || o == null) return o;'
' return dart.as(o, #);'
' return #.as(o, #);'
'}',
[className, className]));
[className, _runtimeModule, className]));
body.add(js.statement(
'#._check = function check_String(o) {'
' if (typeof o == "string" || o == null) return o;'
' return dart.check(o, #);'
' return #.check(o, #);'
'}',
[className, className]));
[className, _runtimeModule, className]));
return;
}
if (classElem == intClass) {
@ -870,16 +882,16 @@ class CodeGenerator extends GeneralizingAstVisitor
'#.as = function as_int(o) {'
' if ((typeof o == "number" && Math.floor(o) == o) || o == null)'
' return o;'
' return dart.as(o, #);'
' return #.as(o, #);'
'}',
[className, className]));
[className, _runtimeModule, className]));
body.add(js.statement(
'#._check = function check_int(o) {'
' if ((typeof o == "number" && Math.floor(o) == o) || o == null)'
' return o;'
' return dart.check(o, #);'
' return #.check(o, #);'
'}',
[className, className]));
[className, _runtimeModule, className]));
return;
}
if (classElem == nullClass) {
@ -888,15 +900,15 @@ class CodeGenerator extends GeneralizingAstVisitor
body.add(js.statement(
'#.as = function as_Null(o) {'
' if (o == null) return o;'
' return dart.as(o, #);'
' return #.as(o, #);'
'}',
[className, className]));
[className, _runtimeModule, className]));
body.add(js.statement(
'#._check = function check_Null(o) {'
' if (o == null) return o;'
' return dart.check(o, #);'
' return #.check(o, #);'
'}',
[className, className]));
[className, _runtimeModule, className]));
return;
}
if (classElem == numClass) {
@ -906,15 +918,15 @@ class CodeGenerator extends GeneralizingAstVisitor
body.add(js.statement(
'#.as = function as_num(o) {'
' if (typeof o == "number" || o == null) return o;'
' return dart.as(o, #);'
' return #.as(o, #);'
'}',
[className, className]));
[className, _runtimeModule, className]));
body.add(js.statement(
'#._check = function check_num(o) {'
' if (typeof o == "number" || o == null) return o;'
' return dart.check(o, #);'
' return #.check(o, #);'
'}',
[className, className]));
[className, _runtimeModule, className]));
return;
}
if (classElem == boolClass) {
@ -924,15 +936,15 @@ class CodeGenerator extends GeneralizingAstVisitor
body.add(js.statement(
'#.as = function as_bool(o) {'
' if (o === true || o === false || o == null) return o;'
' return dart.as(o, #);'
' return #.as(o, #);'
'}',
[className, className]));
[className, _runtimeModule, className]));
body.add(js.statement(
'#._check = function check_bool(o) {'
' if (o === true || o === false || o == null) return o;'
' return dart.check(o, #);'
' return #.check(o, #);'
'}',
[className, className]));
[className, _runtimeModule, className]));
return;
}
// TODO(sra): Add special cases for hot tests like `x is html.Element`.
@ -945,7 +957,7 @@ class CodeGenerator extends GeneralizingAstVisitor
// Place non-instanceof version of checks on Interceptor. All
// interceptor classes will inherit the methods via ES6 class static
// inheritance.
body.add(js.statement('dart.addTypeTests(#);', className));
body.add(_callHelperStatement('addTypeTests(#);', className));
// TODO(sra): We could place on the extension type a pointer to the
// peer constructor and use that for the `instanceof` check, e.g.
@ -983,9 +995,9 @@ class CodeGenerator extends GeneralizingAstVisitor
if (thisIsSimple == superIsSimple) return;
if (thisIsSimple) {
body.add(js.statement('dart.addSimpleTypeTests(#);', className));
body.add(_callHelperStatement('addSimpleTypeTests(#);', className));
} else {
body.add(js.statement('dart.addTypeTests(#);', className));
body.add(_callHelperStatement('addTypeTests(#);', className));
}
}
@ -1103,8 +1115,8 @@ class CodeGenerator extends GeneralizingAstVisitor
// Create static fields for each enum value
for (var i = 0; i < fields.length; ++i) {
result.add(js.statement('#.# = dart.const(new #(#));',
[id, fields[i].name, id, js.number(i)]));
result.add(js.statement('#.# = #.const(new #(#));',
[id, fields[i].name, _runtimeModule, id, js.number(i)]));
}
// Create static values list
@ -1114,8 +1126,8 @@ class CodeGenerator extends GeneralizingAstVisitor
// dart.constList helper internally depends on _interceptors.JSArray.
_declareBeforeUse(_jsArray);
result.add(js.statement(
'#.values = dart.constList(#, #);', [id, values, _emitType(type)]));
result.add(js.statement('#.values = #.constList(#, #);',
[id, _runtimeModule, values, _emitType(type)]));
return _statement(result);
}
@ -1124,7 +1136,7 @@ class CodeGenerator extends GeneralizingAstVisitor
JS.Statement _defineClassTypeArguments(TypeDefiningElement element,
List<TypeParameterElement> formals, JS.Statement body) {
assert(formals.isNotEmpty);
var genericCall = js.call('dart.generic((#) => { #; #; return #; })', [
var genericCall = _callHelper('generic((#) => { #; #; return #; })', [
_emitTypeFormals(formals),
_typeTable.discharge(formals),
body,
@ -1132,7 +1144,7 @@ class CodeGenerator extends GeneralizingAstVisitor
]);
if (element.library.isDartAsync &&
(element.name == "Future" || element.name == "_Future")) {
genericCall = js.call('dart.flattenFutures(#)', [genericCall]);
genericCall = _callHelper('flattenFutures(#)', [genericCall]);
}
var genericDef = js.statement(
'# = #;', [_emitTopLevelName(element, suffix: r'$'), genericCall]);
@ -1190,7 +1202,7 @@ class CodeGenerator extends GeneralizingAstVisitor
var mixins =
type.mixins.map((t) => _emitType(t, nameType: false)).toList();
mixins.insert(0, heritage);
heritage = js.call('dart.mixin(#)', [mixins]);
heritage = _callHelper('mixin(#)', [mixins]);
}
_loader.finishTopLevel(element);
@ -1410,8 +1422,7 @@ class CodeGenerator extends GeneralizingAstVisitor
JS.Expression positionalArgs;
if (method.type.namedParameterTypes.isNotEmpty) {
addProperty(
'namedArguments', js.call('dart.extractNamedArgs(#)', [args]));
addProperty('namedArguments', _callHelper('extractNamedArgs(#)', [args]));
}
if (method is MethodElement) {
@ -1433,8 +1444,8 @@ class CodeGenerator extends GeneralizingAstVisitor
}
}
var fnBody =
js.call('this.noSuchMethod(new dart.InvocationImpl(#, #, #))', [
var fnBody = js.call('this.noSuchMethod(new #.InvocationImpl(#, #, #))', [
_runtimeModule,
_declareMemberName(method),
positionalArgs,
new JS.ObjectInitializer(invocationProps)
@ -1552,8 +1563,8 @@ class CodeGenerator extends GeneralizingAstVisitor
// an ES6 iterator.
return new JS.Method(
js.call('Symbol.iterator'),
js.call('function() { return new dart.JsIterator(this.#); }',
[_emitMemberName('iterator', type: t)]) as JS.Fun);
js.call('function() { return new #.JsIterator(this.#); }',
[_runtimeModule, _emitMemberName('iterator', type: t)]) as JS.Fun);
}
JS.Expression _instantiateAnnotation(Annotation node) {
@ -1590,8 +1601,11 @@ class CodeGenerator extends GeneralizingAstVisitor
void _registerExtensionType(
ClassElement classElem, String jsPeerName, List<JS.Statement> body) {
if (jsPeerName != null) {
body.add(js.statement('dart.registerExtension(dart.global.#, #);',
[_propertyName(jsPeerName), _emitTopLevelName(classElem)]));
body.add(_callHelperStatement('registerExtension(#.global.#, #);', [
_runtimeModule,
_propertyName(jsPeerName),
_emitTopLevelName(classElem)
]));
}
}
@ -1600,23 +1614,23 @@ class CodeGenerator extends GeneralizingAstVisitor
if (jsPeerNames.isNotEmpty && classElem.typeParameters.isNotEmpty) {
for (var peer in jsPeerNames) {
// TODO(jmesserly): we should just extend Array in the first place
var newBaseClass = js.call('dart.global.#', [peer]);
body.add(js.statement(
'dart.setExtensionBaseClass(#, #);', [className, newBaseClass]));
var newBaseClass = _callHelper('global.#', [peer]);
body.add(_callHelperStatement(
'setExtensionBaseClass(#, #);', [className, newBaseClass]));
}
} else if (_hasDeferredSupertype.contains(classElem)) {
var newBaseClass = _emitType(classElem.type.superclass,
nameType: false, subClass: classElem, className: className);
body.add(
js.statement('dart.setBaseClass(#, #);', [className, newBaseClass]));
body.add(_callHelperStatement(
'setBaseClass(#, #);', [className, newBaseClass]));
}
}
void _defineNamedConstructors(List<ConstructorDeclaration> ctors,
List<JS.Statement> body, JS.Expression className, bool isCallable) {
var code = isCallable
? 'dart.defineNamedConstructorCallable(#, #, #);'
: 'dart.defineNamedConstructor(#, #)';
? 'defineNamedConstructorCallable(#, #, #);'
: 'defineNamedConstructor(#, #)';
for (ConstructorDeclaration member in ctors) {
if (member.name != null && member.factoryKeyword == null) {
@ -1625,7 +1639,7 @@ class CodeGenerator extends GeneralizingAstVisitor
args.add(_emitCallableClassConstructor(member.element));
}
body.add(js.statement(code, args));
body.add(_callHelperStatement(code, args));
}
}
}
@ -1658,8 +1672,9 @@ class CodeGenerator extends GeneralizingAstVisitor
List<JS.Statement> body) {
// Metadata
if (options.emitMetadata && metadata.isNotEmpty) {
body.add(js.statement('#[dart.metadata] = () => #;', [
body.add(js.statement('#[#.metadata] = () => #;', [
className,
_runtimeModule,
new JS.ArrayInitializer(
new List<JS.Expression>.from(metadata.map(_instantiateAnnotation)))
]));
@ -1677,7 +1692,7 @@ class CodeGenerator extends GeneralizingAstVisitor
for (var e in extensions) {
methodNames.add(_declareMemberName(e, useExtension: false));
}
body.add(js.statement('dart.defineExtensionMembers(#, #);', [
body.add(_callHelperStatement('defineExtensionMembers(#, #);', [
className,
new JS.ArrayInitializer(methodNames, multiline: methodNames.length > 4)
]));
@ -1694,8 +1709,9 @@ class CodeGenerator extends GeneralizingAstVisitor
JS.Expression className,
List<JS.Statement> body) {
if (classElem.interfaces.isNotEmpty) {
body.add(js.statement('#[dart.implements] = () => #;', [
body.add(js.statement('#[#.implements] = () => #;', [
className,
_runtimeModule,
new JS.ArrayInitializer(
new List<JS.Expression>.from(classElem.interfaces.map(_emitType)))
]));
@ -1818,12 +1834,12 @@ class CodeGenerator extends GeneralizingAstVisitor
}
if (!sigFields.isEmpty || extensions.isNotEmpty) {
var sig = new JS.ObjectInitializer(sigFields);
body.add(js.statement('dart.setSignature(#, #);', [className, sig]));
body.add(_callHelperStatement('setSignature(#, #);', [className, sig]));
}
// Add static property dart._runtimeType to Object.
// All other Dart classes will (statically) inherit this property.
if (classElem == objectClass) {
body.add(js.statement('dart.tagComputed(#, () => #.#);',
body.add(_callHelperStatement('tagComputed(#, () => #.#);',
[className, emitLibraryName(dartCoreLibrary), 'Type']));
}
}
@ -1852,7 +1868,7 @@ class CodeGenerator extends GeneralizingAstVisitor
}
}
if (dartxNames.isNotEmpty) {
body.add(js.statement('dart.defineExtensionNames(#)',
body.add(_callHelperStatement('defineExtensionNames(#)',
[new JS.ArrayInitializer(dartxNames, multiline: true)]));
}
}
@ -2332,7 +2348,7 @@ class CodeGenerator extends GeneralizingAstVisitor
props.add(_loader.emitDeclaration(
setter, (node) => _emitTopLevelProperty(node)));
}
return js.statement('dart.copyProperties(#, { # });',
return _callHelperStatement('copyProperties(#, { # });',
[emitLibraryName(currentLibrary), props]);
}
if (node.isSetter) {
@ -2343,7 +2359,7 @@ class CodeGenerator extends GeneralizingAstVisitor
props.add(_loader.emitDeclaration(
getter, (node) => _emitTopLevelProperty(node)));
}
return js.statement('dart.copyProperties(#, { # });',
return _callHelperStatement('copyProperties(#, { # });',
[emitLibraryName(currentLibrary), props]);
}
@ -2442,9 +2458,9 @@ class CodeGenerator extends GeneralizingAstVisitor
var lazy = topLevel && !_typeIsLoaded(type);
var typeRep = _emitFunctionType(type, definite: true);
if (lazy) {
return js.call('dart.lazyFn(#, () => #)', [fn, typeRep]);
return _callHelper('lazyFn(#, () => #)', [fn, typeRep]);
} else {
return js.call('dart.fn(#, #)', [fn, typeRep]);
return _callHelper('fn(#, #)', [fn, typeRep]);
}
}
@ -2596,7 +2612,7 @@ class CodeGenerator extends GeneralizingAstVisitor
}
var T = _emitType(returnType);
return js.call('dart.#(#)', [
return _callHelper('#(#)', [
kind,
[gen, T]..addAll(visitFormalParameterList(parameters, destructure: false))
]);
@ -2636,7 +2652,7 @@ class CodeGenerator extends GeneralizingAstVisitor
if (typeArgs == null) {
return simpleId;
}
return js.call('dart.gbind(#, #)', [simpleId, typeArgs]);
return _callHelper('gbind(#, #)', [simpleId, typeArgs]);
}
/// Emits a simple identifier, handling implicit `this` as well as
@ -2663,7 +2679,7 @@ class CodeGenerator extends GeneralizingAstVisitor
// If the type is a type literal expression in Dart code, wrap the raw
// runtime type in a "Type" instance.
if (!_isInForeignJS && _isTypeLiteral(node)) {
typeName = js.call('dart.wrapType(#)', typeName);
typeName = _callHelper('wrapType(#)', typeName);
}
return typeName;
@ -2694,8 +2710,8 @@ class CodeGenerator extends GeneralizingAstVisitor
// For instance members, we add implicit-this.
// For method tear-offs, we ensure it's a bound method.
var tearOff = element is MethodElement && !inInvocationContext(node);
var code = (tearOff) ? 'dart.bind(this, #)' : 'this.#';
return js.call(code, member);
if (tearOff) return _callHelper('bind(this, #)', member);
return js.call('this.#', member);
}
if (element is ParameterElement) {
@ -2812,7 +2828,7 @@ class CodeGenerator extends GeneralizingAstVisitor
nameType: nameType,
hoistType: hoistType);
var helper = (definite) ? 'definiteFunctionType' : 'functionType';
var fullType = js.call('dart.${helper}(#)', [parts]);
var fullType = _callHelper('${helper}(#)', [parts]);
if (!nameType) return fullType;
return _typeTable.nameType(type, fullType,
hoistType: hoistType, definite: definite);
@ -2908,11 +2924,11 @@ class CodeGenerator extends GeneralizingAstVisitor
JS.Expression className}) {
// The void and dynamic types are not defined in core.
if (type.isVoid) {
return js.call('dart.void');
return _callHelper('void');
} else if (type.isDynamic) {
return js.call('dart.dynamic');
return _callHelper('dynamic');
} else if (type.isBottom) {
return js.call('dart.bottom');
return _callHelper('bottom');
}
_declareBeforeUse(type.element);
@ -3059,11 +3075,18 @@ class CodeGenerator extends GeneralizingAstVisitor
var l = _visit(_bindValue(vars, 'l', target));
var name = _emitMemberName(id.name);
return new JS.MetaLet(vars, [
js.call('(#[(#[dart._extensionType]) ? dartx[#] : #] = #)',
[l, l, name, name, _visit(rhs)])
js.call('(#[(#[#._extensionType]) ? #[#] : #] = #)', [
l,
l,
_runtimeModule,
name,
_extensionSymbolsModule,
name,
_visit(rhs)
])
]);
}
return js.call('dart.#(#, #, #)', [
return _callHelper('#(#, #, #)', [
_emitDynamicOperationName('dput'),
_visit(target),
_emitMemberName(id.name),
@ -3096,7 +3119,7 @@ class CodeGenerator extends GeneralizingAstVisitor
// TODO(sra): We should get here only for compiler bugs or weirdness due to
// --unsafe-force-compile. Once those paths have been addressed, throw at
// compile time.
return js.call('dart.throwUnimplementedError((#, #, #))',
return _callHelper('throwUnimplementedError((#, #, #))',
[js.string('$lhs ='), _visit(rhs), js.string(problem)]);
}
@ -3346,14 +3369,21 @@ class CodeGenerator extends GeneralizingAstVisitor
var vars = <JS.MetaLetVariable, JS.Expression>{};
var l = _visit(_bindValue(vars, 'l', target));
jsTarget = new JS.MetaLet(vars, [
js.call('(#[(#[dart._extensionType]) ? dartx[#] : #]).bind(#)',
[l, l, memberName, memberName, l])
js.call('(#[(#[#._extensionType]) ? #[#] : #]).bind(#)', [
l,
l,
_runtimeModule,
memberName,
_extensionSymbolsModule,
memberName,
l
])
]);
if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs);
return new JS.Call(jsTarget, args);
}
if (typeArgs != null) {
return js.call('dart.#(#, #, #, #)', [
return _callHelper('#(#, #, #, #)', [
_emitDynamicOperationName('dgsend'),
jsTarget,
new JS.ArrayInitializer(typeArgs),
@ -3361,13 +3391,13 @@ class CodeGenerator extends GeneralizingAstVisitor
args
]);
} else {
return js.call('dart.#(#, #, #)',
return _callHelper('#(#, #, #)',
[_emitDynamicOperationName('dsend'), jsTarget, memberName, args]);
}
}
if (_isObjectMemberCall(target, name)) {
assert(typeArgs == null); // Object methods don't take type args.
return js.call('dart.#(#, #)', [name, jsTarget, args]);
return _callHelper('#(#, #)', [name, jsTarget, args]);
}
jsTarget = new JS.PropertyAccess(jsTarget, memberName);
@ -3380,13 +3410,13 @@ class CodeGenerator extends GeneralizingAstVisitor
InvocationExpression node, JS.Expression fn, List<JS.Expression> args) {
var typeArgs = _emitInvokeTypeArguments(node);
if (typeArgs != null) {
return js.call('dart.dgcall(#, #, #)',
[fn, new JS.ArrayInitializer(typeArgs), args]);
return _callHelper(
'dgcall(#, #, #)', [fn, new JS.ArrayInitializer(typeArgs), args]);
} else {
if (_inWhitelistCode(node, isCall: true)) {
return new JS.Call(fn, args);
}
return js.call('dart.dcall(#, #)', [fn, args]);
return _callHelper('dcall(#, #)', [fn, args]);
}
}
@ -3629,7 +3659,7 @@ class CodeGenerator extends GeneralizingAstVisitor
@override
JS.Statement visitAssertStatement(AssertStatement node) =>
// TODO(jmesserly): only emit in checked mode.
js.statement('dart.assert(#);', _visit(node.condition));
_callHelperStatement('assert(#);', _visit(node.condition));
@override
JS.Statement visitReturnStatement(ReturnStatement node) {
@ -3839,7 +3869,7 @@ class CodeGenerator extends GeneralizingAstVisitor
objExpr = emitLibraryName(target);
}
return js.statement('dart.defineLazy(#, { # });', [objExpr, methods]);
return _callHelperStatement('defineLazy(#, { # });', [objExpr, methods]);
}
PropertyAccessorElement _findAccessor(VariableElement element,
@ -3956,7 +3986,7 @@ class CodeGenerator extends GeneralizingAstVisitor
if (expr == null) return null;
var jsExpr = _visit(expr);
if (!isNullable(expr)) return jsExpr;
return js.call('dart.notNull(#)', jsExpr);
return _callHelper('notNull(#)', jsExpr);
}
@override
@ -3986,7 +4016,8 @@ class CodeGenerator extends GeneralizingAstVisitor
return _emitSend(left, op.lexeme, [right]);
} else {
var bang = op.type == TokenType.BANG_EQ ? '!' : '';
code = '${bang}dart.equals(#, #)';
code = '${bang}#.equals(#, #)';
return js.call(code, [_runtimeModule, _visit(left), _visit(right)]);
}
return js.call(code, [_visit(left), _visit(right)]);
}
@ -4299,7 +4330,7 @@ class CodeGenerator extends GeneralizingAstVisitor
}
JS.Expression _emitConst(JS.Expression expr()) =>
_cacheConst(() => js.call('dart.const(#)', expr()));
_cacheConst(() => _callHelper('const(#)', expr()));
/// Returns a new expression, which can be be used safely *once* on the
/// left hand side, and *once* on the right side of an assignment.
@ -4561,8 +4592,8 @@ class CodeGenerator extends GeneralizingAstVisitor
}
}
if (tail.isEmpty) return _visit(node);
return js.call(
'dart.nullSafe(#, #)', [_visit(node) as JS.Expression, tail.reversed]);
return _callHelper(
'nullSafe(#, #)', [_visit(node) as JS.Expression, tail.reversed]);
}
static Token _getOperator(Expression node) {
@ -4659,11 +4690,11 @@ class CodeGenerator extends GeneralizingAstVisitor
var vars = <JS.MetaLetVariable, JS.Expression>{};
var l = _visit(_bindValue(vars, 'l', target));
return new JS.MetaLet(vars, [
js.call('(#[dart._extensionType]) ? #[dartx[#]] : #.#',
[l, l, name, l, name])
js.call('(#[#._extensionType]) ? #[#[#]] : #.#',
[l, _runtimeModule, l, _extensionSymbolsModule, name, l, name])
]);
}
return js.call('dart.#(#, #)',
return _callHelper('#(#, #)',
[_emitDynamicOperationName('dload'), _visit(target), name]);
}
@ -4680,22 +4711,22 @@ class CodeGenerator extends GeneralizingAstVisitor
if (member != null && member is MethodElement && !isStatic) {
// Tear-off methods: explicitly bind it.
if (isSuper) {
result = js.call('dart.bind(this, #, #.#)', [name, jsTarget, name]);
result = _callHelper('bind(this, #, #.#)', [name, jsTarget, name]);
} else if (_isObjectMemberCall(target, memberName)) {
result = js.call('dart.bind(#, #, dart.#)',
[jsTarget, _propertyName(memberName), memberName]);
result = _callHelper('bind(#, #, #.#)',
[jsTarget, _propertyName(memberName), _runtimeModule, memberName]);
} else {
result = js.call('dart.bind(#, #)', [jsTarget, name]);
result = _callHelper('bind(#, #)', [jsTarget, name]);
}
} else if (_isObjectMemberCall(target, memberName)) {
result = js.call('dart.#(#)', [memberName, jsTarget]);
result = _callHelper('#(#)', [memberName, jsTarget]);
} else {
result = js.call('#.#', [jsTarget, name]);
}
if (typeArgs == null) {
return result;
}
return js.call('dart.gbind(#, #)', [result, typeArgs]);
return _callHelper('gbind(#, #)', [result, typeArgs]);
}
/// Emits a generic send, like an operator method.
@ -4712,18 +4743,26 @@ class CodeGenerator extends GeneralizingAstVisitor
var vars = <JS.MetaLetVariable, JS.Expression>{};
var l = _visit(_bindValue(vars, 'l', target));
return new JS.MetaLet(vars, [
js.call('(#[(#[dart._extensionType]) ? dartx[#] : #]).call(#, #)',
[l, l, memberName, memberName, l, _visitList(args)])
js.call('(#[(#[#._extensionType]) ? #[#] : #]).call(#, #)', [
l,
l,
_runtimeModule,
memberName,
_extensionSymbolsModule,
memberName,
l,
_visitList(args)
])
]);
}
// dynamic dispatch
var dynamicHelper = const {'[]': 'dindex', '[]=': 'dsetindex'}[name];
if (dynamicHelper != null) {
return js.call('dart.$dynamicHelper(#, #)',
return _callHelper('$dynamicHelper(#, #)',
[_visit(target) as JS.Expression, _visitList(args)]);
} else {
return js.call('dart.dsend(#, #, #)',
[_visit(target), memberName, _visitList(args)]);
return _callHelper(
'dsend(#, #, #)', [_visit(target), memberName, _visitList(args)]);
}
}
@ -4767,9 +4806,9 @@ class CodeGenerator extends GeneralizingAstVisitor
visitThrowExpression(ThrowExpression node) {
var expr = _visit(node.expression);
if (node.parent is ExpressionStatement) {
return js.statement('dart.throw(#);', expr);
return _callHelperStatement('throw(#);', expr);
} else {
return js.call('dart.throw(#)', expr);
return _callHelper('throw(#)', expr);
}
}
@ -4972,8 +5011,8 @@ class CodeGenerator extends GeneralizingAstVisitor
}
if (node.stackTraceParameter != null) {
var stackVar = node.stackTraceParameter.name;
body.add(js.statement(
'let # = dart.stackTrace(#);', [stackVar, _visit(name)]));
body.add(js.statement('let # = #.stackTrace(#);',
[stackVar, _runtimeModule, _visit(name)]));
}
}
@ -5055,7 +5094,7 @@ class CodeGenerator extends GeneralizingAstVisitor
_declareBeforeUse(_jsArray);
if (isConst) {
var typeRep = _emitType(elementType);
list = js.call('dart.constList(#, #)', [list, typeRep]);
list = _callHelper('constList(#, #)', [list, typeRep]);
} else {
// Call `new JSArray<E>.of(list)`
var jsArrayType = _jsArray.type.instantiate(type.typeArguments);
@ -5101,7 +5140,7 @@ class CodeGenerator extends GeneralizingAstVisitor
if (reifyTypeArgs) {
types.addAll(typeArgs.map((e) => _emitType(e)));
}
return js.call('dart.map(#, #)', [mapArguments, types]);
return _callHelper('map(#, #)', [mapArguments, types]);
}
if (node.constKeyword != null) return _emitConst(emitMap);
@ -5119,7 +5158,7 @@ class CodeGenerator extends GeneralizingAstVisitor
@override
JS.Expression visitStringInterpolation(StringInterpolation node) {
return new JS.TaggedTemplate(
js.call('dart.str'), new JS.TemplateString(_visitList(node.elements)));
_callHelper('str'), new JS.TemplateString(_visitList(node.elements)));
}
@override
@ -5141,7 +5180,7 @@ class CodeGenerator extends GeneralizingAstVisitor
_unimplementedCall('Unimplemented ${node.runtimeType}: $node');
JS.Expression _unimplementedCall(String comment) {
return js.call('dart.throw(#)', [js.escapedString(comment)]);
return _callHelper('throw(#)', [js.escapedString(comment)]);
}
@override
@ -5198,10 +5237,10 @@ class CodeGenerator extends GeneralizingAstVisitor
}
if (node is AsExpression && CoercionReifier.isImplicitCast(node)) {
assert(node.staticType == types.boolType);
return js.call('dart.test(#)', _visit(node.expression));
return _callHelper('test(#)', _visit(node.expression));
}
JS.Expression result = _visit(node);
if (isNullable(node)) result = js.call('dart.test(#)', result);
if (isNullable(node)) result = _callHelper('test(#)', result);
return result;
}
@ -5302,7 +5341,9 @@ class CodeGenerator extends GeneralizingAstVisitor
!isObjectMember(name);
}
return useExtension ? js.call('dartx.#', result) : result;
return useExtension
? js.call('#.#', [_extensionSymbolsModule, result])
: result;
}
JS.TemporaryId _emitPrivateNameSymbol(LibraryElement library, String name) {
@ -5405,6 +5446,26 @@ class CodeGenerator extends GeneralizingAstVisitor
}
}
JS.Expression _callHelper(String code, [args]) {
if (args is List) {
args.insert(0, _runtimeModule);
} else if (args != null) {
args = [_runtimeModule, args];
} else {
args = _runtimeModule;
}
return js.call('#.$code', args);
}
JS.Statement _callHelperStatement(String code, args) {
if (args is List) {
args.insert(0, _runtimeModule);
} else {
args = [_runtimeModule, args];
}
return js.statement('#.$code', args);
}
/// Maps whitelisted files to a list of whitelisted methods
/// within the file.
///

View file

@ -122,13 +122,17 @@ class _CacheTable {
class _GeneratorTable extends _CacheTable {
final _defs = new HashMap<DartType, JS.Expression>();
final JS.Identifier _runtimeModule;
_GeneratorTable(this._runtimeModule);
JS.Statement _dischargeType(DartType t) {
var name = _names.remove(t);
if (name != null) {
JS.Expression init = _defs.remove(t);
assert(init != null);
return js.statement(
'let # = () => ((# = dart.constFn(#))());', [name, name, init]);
return js.statement('let # = () => ((# = #.constFn(#))());',
[name, name, _runtimeModule, init]);
}
return null;
}
@ -154,10 +158,10 @@ class TypeTable {
final _definiteCacheNames = new _CacheTable();
/// Generator variable names for hoisted types.
final _generators = new _GeneratorTable();
final _GeneratorTable _generators;
/// Generator variable names for hoisted definite function types.
final _definiteGenerators = new _GeneratorTable();
final _GeneratorTable _definiteGenerators;
/// Mapping from type parameters to the types which must have their
/// cache/generator variables discharged at the binding site for the
@ -166,6 +170,10 @@ class TypeTable {
final _scopeDependencies =
new HashMap<TypeParameterElement, List<DartType>>();
TypeTable(JS.Identifier runtime)
: _generators = new _GeneratorTable(runtime),
_definiteGenerators = new _GeneratorTable(runtime);
/// Emit a list of statements declaring the cache variables and generator
/// definitions tracked by the table. If [formals] is present, only
/// emit the definitions which depend on the formals.

View file

@ -0,0 +1,10 @@
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:expect/expect.dart';
main() {
dynamic dart = 123;
Expect.equals(dart.toDouble(), 123.0);
}