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

Side by Side Diff: lib/src/codegen/js_codegen.dart

Issue 1184843002: fixes #192, encode dynamic info in checker (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 6 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library dev_compiler.src.codegen.js_codegen; 5 library dev_compiler.src.codegen.js_codegen;
6 6
7 import 'dart:collection' show HashSet, HashMap, SplayTreeSet; 7 import 'dart:collection' show HashSet, HashMap, SplayTreeSet;
8 8
9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator;
10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; 10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator;
(...skipping 1458 matching lines...) Expand 10 before | Expand all | Expand 10 after
1469 Expression target = null; 1469 Expression target = null;
1470 SimpleIdentifier id; 1470 SimpleIdentifier id;
1471 if (lhs is PropertyAccess) { 1471 if (lhs is PropertyAccess) {
1472 target = _getTarget(lhs); 1472 target = _getTarget(lhs);
1473 id = lhs.propertyName; 1473 id = lhs.propertyName;
1474 } else if (lhs is PrefixedIdentifier) { 1474 } else if (lhs is PrefixedIdentifier) {
1475 target = lhs.prefix; 1475 target = lhs.prefix;
1476 id = lhs.identifier; 1476 id = lhs.identifier;
1477 } 1477 }
1478 1478
1479 if (target != null && rules.isDynamicTarget(target)) { 1479 if (target != null && DynamicInvoke.get(target)) {
1480 return js.call('dart.$DPUT(#, #, #)', [ 1480 return js.call('dart.$DPUT(#, #, #)', [
1481 _visit(target), 1481 _visit(target),
1482 _emitMemberName(id.name, type: getStaticType(target)), 1482 _emitMemberName(id.name, type: getStaticType(target)),
1483 _visit(rhs) 1483 _visit(rhs)
1484 ]); 1484 ]);
1485 } 1485 }
1486 1486
1487 return _visit(rhs).toAssignExpression(_visit(lhs)); 1487 return _visit(rhs).toAssignExpression(_visit(lhs));
1488 } 1488 }
1489 1489
(...skipping 20 matching lines...) Expand all
1510 1510
1511 @override 1511 @override
1512 visitMethodInvocation(MethodInvocation node) { 1512 visitMethodInvocation(MethodInvocation node) {
1513 var target = node.isCascaded ? _cascadeTarget : node.target; 1513 var target = node.isCascaded ? _cascadeTarget : node.target;
1514 1514
1515 var result = _emitForeignJS(node); 1515 var result = _emitForeignJS(node);
1516 if (result != null) return result; 1516 if (result != null) return result;
1517 1517
1518 String code; 1518 String code;
1519 if (target == null || isLibraryPrefix(target)) { 1519 if (target == null || isLibraryPrefix(target)) {
1520 if (rules.isDynamicCall(node.methodName)) { 1520 if (DynamicInvoke.get(node.methodName)) {
1521 code = 'dart.$DCALL(#, #)'; 1521 code = 'dart.$DCALL(#, #)';
1522 } else { 1522 } else {
1523 code = '#(#)'; 1523 code = '#(#)';
1524 } 1524 }
1525 return js.call( 1525 return js.call(
1526 code, [_visit(node.methodName), _visit(node.argumentList)]); 1526 code, [_visit(node.methodName), _visit(node.argumentList)]);
1527 } 1527 }
1528 1528
1529 var type = getStaticType(target); 1529 var type = getStaticType(target);
1530 var name = node.methodName.name; 1530 var name = node.methodName.name;
1531 var element = node.methodName.staticElement; 1531 var element = node.methodName.staticElement;
1532 bool isStatic = element is ExecutableElement && element.isStatic; 1532 bool isStatic = element is ExecutableElement && element.isStatic;
1533 var memberName = _emitMemberName(name, type: type, isStatic: isStatic); 1533 var memberName = _emitMemberName(name, type: type, isStatic: isStatic);
1534 1534
1535 if (rules.isDynamicTarget(target)) { 1535 if (DynamicInvoke.get(target)) {
1536 code = 'dart.$DSEND(#, #, #)'; 1536 code = 'dart.$DSEND(#, #, #)';
1537 } else if (rules.isDynamicCall(node.methodName)) { 1537 } else if (DynamicInvoke.get(node.methodName)) {
1538 // This is a dynamic call to a statically know target. For example: 1538 // This is a dynamic call to a statically know target. For example:
1539 // class Foo { Function bar; } 1539 // class Foo { Function bar; }
1540 // new Foo().bar(); // dynamic call 1540 // new Foo().bar(); // dynamic call
1541 code = 'dart.$DCALL(#.#, #)'; 1541 code = 'dart.$DCALL(#.#, #)';
1542 } else if (_requiresStaticDispatch(target, name)) { 1542 } else if (_requiresStaticDispatch(target, name)) {
1543 assert(rules.objectMembers[name] is FunctionType); 1543 assert(rules.objectMembers[name] is FunctionType);
1544 // Object methods require a helper for null checks. 1544 // Object methods require a helper for null checks.
1545 return js.call('dart.#(#, #)', [ 1545 return js.call('dart.#(#, #)', [
1546 memberName, 1546 memberName,
1547 _visit(target), 1547 _visit(target),
(...skipping 21 matching lines...) Expand all
1569 assert(result is JS.Expression || node.parent is ExpressionStatement); 1569 assert(result is JS.Expression || node.parent is ExpressionStatement);
1570 return result; 1570 return result;
1571 } 1571 }
1572 return null; 1572 return null;
1573 } 1573 }
1574 1574
1575 @override 1575 @override
1576 JS.Expression visitFunctionExpressionInvocation( 1576 JS.Expression visitFunctionExpressionInvocation(
1577 FunctionExpressionInvocation node) { 1577 FunctionExpressionInvocation node) {
1578 var code; 1578 var code;
1579 if (rules.isDynamicCall(node.function)) { 1579 if (DynamicInvoke.get(node.function)) {
1580 code = 'dart.$DCALL(#, #)'; 1580 code = 'dart.$DCALL(#, #)';
1581 } else { 1581 } else {
1582 code = '#(#)'; 1582 code = '#(#)';
1583 } 1583 }
1584 return js.call(code, [_visit(node.function), _visit(node.argumentList)]); 1584 return js.call(code, [_visit(node.function), _visit(node.argumentList)]);
1585 } 1585 }
1586 1586
1587 @override 1587 @override
1588 List<JS.Expression> visitArgumentList(ArgumentList node) { 1588 List<JS.Expression> visitArgumentList(ArgumentList node) {
1589 var args = <JS.Expression>[]; 1589 var args = <JS.Expression>[];
(...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after
1980 // See [_isTemporary]. 1980 // See [_isTemporary].
1981 // TODO(jmesserly): alternatives are 1981 // TODO(jmesserly): alternatives are
1982 // * (ab)use Element.isSynthetic, which isn't currently used for 1982 // * (ab)use Element.isSynthetic, which isn't currently used for
1983 // LocalVariableElementImpl, so we could repurpose to mean "temp". 1983 // LocalVariableElementImpl, so we could repurpose to mean "temp".
1984 // * add a new property to LocalVariableElementImpl. 1984 // * add a new property to LocalVariableElementImpl.
1985 // * create a new subtype of LocalVariableElementImpl to mark a temp. 1985 // * create a new subtype of LocalVariableElementImpl to mark a temp.
1986 var id = 1986 var id =
1987 new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, name, -1)); 1987 new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, name, -1));
1988 id.staticElement = new TemporaryVariableElement.forNode(id); 1988 id.staticElement = new TemporaryVariableElement.forNode(id);
1989 id.staticType = type; 1989 id.staticType = type;
1990 DynamicInvoke.set(id, type.isDynamic);
Jennifer Messerly 2015/06/12 18:18:09 this is the downside, it's one more bit to copy ..
1990 return id; 1991 return id;
1991 } 1992 }
1992 1993
1993 JS.Expression _emitConst(JS.Expression expr()) { 1994 JS.Expression _emitConst(JS.Expression expr()) {
1994 // TODO(jmesserly): emit the constants at top level if possible. 1995 // TODO(jmesserly): emit the constants at top level if possible.
1995 // This wasn't quite working, so disabled for now. 1996 // This wasn't quite working, so disabled for now.
1996 return js.call('dart.const(#)', expr()); 1997 return js.call('dart.const(#)', expr());
1997 } 1998 }
1998 1999
1999 /// Returns a new expression, which can be be used safely *once* on the 2000 /// Returns a new expression, which can be be used safely *once* on the
2000 /// left hand side, and *once* on the right side of an assignment. 2001 /// left hand side, and *once* on the right side of an assignment.
2001 /// For example: `expr1[expr2] += y` can be compiled as 2002 /// For example: `expr1[expr2] += y` can be compiled as
2002 /// `expr1[expr2] = expr1[expr2] + y`. 2003 /// `expr1[expr2] = expr1[expr2] + y`.
2003 /// 2004 ///
2004 /// The temporary scope will ensure `expr1` and `expr2` are only evaluated 2005 /// The temporary scope will ensure `expr1` and `expr2` are only evaluated
2005 /// once: `((x1, x2) => x1[x2] = x1[x2] + y)(expr1, expr2)`. 2006 /// once: `((x1, x2) => x1[x2] = x1[x2] + y)(expr1, expr2)`.
2006 /// 2007 ///
2007 /// If the expression does not end up using `x1` or `x2` more than once, or 2008 /// If the expression does not end up using `x1` or `x2` more than once, or
2008 /// if those expressions can be treated as stateless (e.g. they are 2009 /// if those expressions can be treated as stateless (e.g. they are
2009 /// non-mutated variables), then the resulting code will be simplified 2010 /// non-mutated variables), then the resulting code will be simplified
2010 /// automatically. 2011 /// automatically.
2011 /// 2012 ///
2012 /// [scope] can be mutated to contain any new temporaries that were created, 2013 /// [scope] can be mutated to contain any new temporaries that were created,
2013 /// unless [expr] is a SimpleIdentifier, in which case a temporary is not 2014 /// unless [expr] is a SimpleIdentifier, in which case a temporary is not
2014 /// needed. 2015 /// needed.
2015 Expression _bindLeftHandSide( 2016 Expression _bindLeftHandSide(
2016 Map<String, JS.Expression> scope, Expression expr, {Expression context}) { 2017 Map<String, JS.Expression> scope, Expression expr, {Expression context}) {
2018 Expression result;
2017 if (expr is IndexExpression) { 2019 if (expr is IndexExpression) {
2018 IndexExpression index = expr; 2020 IndexExpression index = expr;
2019 return new IndexExpression.forTarget( 2021 result = new IndexExpression.forTarget(
2020 _bindValue(scope, 'o', index.target, context: context), 2022 _bindValue(scope, 'o', index.target, context: context),
2021 index.leftBracket, 2023 index.leftBracket,
2022 _bindValue(scope, 'i', index.index, context: context), 2024 _bindValue(scope, 'i', index.index, context: context),
2023 index.rightBracket)..staticType = expr.staticType; 2025 index.rightBracket);
2024 } else if (expr is PropertyAccess) { 2026 } else if (expr is PropertyAccess) {
2025 PropertyAccess prop = expr; 2027 PropertyAccess prop = expr;
2026 return new PropertyAccess( 2028 result = new PropertyAccess(
2027 _bindValue(scope, 'o', _getTarget(prop), context: context), 2029 _bindValue(scope, 'o', _getTarget(prop), context: context),
2028 prop.operator, prop.propertyName)..staticType = expr.staticType; 2030 prop.operator, prop.propertyName);
2029 } else if (expr is PrefixedIdentifier) { 2031 } else if (expr is PrefixedIdentifier) {
2030 PrefixedIdentifier ident = expr; 2032 PrefixedIdentifier ident = expr;
2031 return new PrefixedIdentifier( 2033 result = new PrefixedIdentifier(
2032 _bindValue(scope, 'o', ident.prefix, context: context), ident.period, 2034 _bindValue(scope, 'o', ident.prefix, context: context), ident.period,
2033 ident.identifier)..staticType = expr.staticType; 2035 ident.identifier);
2036 } else {
2037 return expr as SimpleIdentifier;
2034 } 2038 }
2035 return expr as SimpleIdentifier; 2039 result.staticType = expr.staticType;
2040 DynamicInvoke.set(result, DynamicInvoke.get(expr));
2041 return result;
2036 } 2042 }
2037 2043
2038 /// Creates a temporary to contain the value of [expr]. The temporary can be 2044 /// Creates a temporary to contain the value of [expr]. The temporary can be
2039 /// used multiple times in the resulting expression. For example: 2045 /// used multiple times in the resulting expression. For example:
2040 /// `expr ** 2` could be compiled as `expr * expr`. The temporary scope will 2046 /// `expr ** 2` could be compiled as `expr * expr`. The temporary scope will
2041 /// ensure `expr` is only evaluated once: `(x => x * x)(expr)`. 2047 /// ensure `expr` is only evaluated once: `(x => x * x)(expr)`.
2042 /// 2048 ///
2043 /// If the expression does not end up using `x` more than once, or if those 2049 /// If the expression does not end up using `x` more than once, or if those
2044 /// expressions can be treated as stateless (e.g. they are non-mutated 2050 /// expressions can be treated as stateless (e.g. they are non-mutated
2045 /// variables), then the resulting code will be simplified automatically. 2051 /// variables), then the resulting code will be simplified automatically.
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
2201 var member = memberId.staticElement; 2207 var member = memberId.staticElement;
2202 if (member is PropertyAccessorElement) { 2208 if (member is PropertyAccessorElement) {
2203 member = (member as PropertyAccessorElement).variable; 2209 member = (member as PropertyAccessorElement).variable;
2204 } 2210 }
2205 bool isStatic = member is ClassMemberElement && member.isStatic; 2211 bool isStatic = member is ClassMemberElement && member.isStatic;
2206 if (isStatic) { 2212 if (isStatic) {
2207 _loader.declareBeforeUse(member); 2213 _loader.declareBeforeUse(member);
2208 } 2214 }
2209 var name = _emitMemberName(memberId.name, 2215 var name = _emitMemberName(memberId.name,
2210 type: getStaticType(target), isStatic: isStatic); 2216 type: getStaticType(target), isStatic: isStatic);
2211 if (rules.isDynamicTarget(target)) { 2217 if (DynamicInvoke.get(target)) {
2212 return js.call('dart.$DLOAD(#, #)', [_visit(target), name]); 2218 return js.call('dart.$DLOAD(#, #)', [_visit(target), name]);
2213 } 2219 }
2214 2220
2215 String code; 2221 String code;
2216 if (member != null && member is MethodElement && !isStatic) { 2222 if (member != null && member is MethodElement && !isStatic) {
2217 // Tear-off methods: explicitly bind it. 2223 // Tear-off methods: explicitly bind it.
2218 // TODO(leafp): Attach runtime types to these static tearoffs 2224 // TODO(leafp): Attach runtime types to these static tearoffs
2219 if (_requiresStaticDispatch(target, memberId.name)) { 2225 if (_requiresStaticDispatch(target, memberId.name)) {
2220 return js.call('dart.#.bind(#)', [name, _visit(target)]); 2226 return js.call('dart.#.bind(#)', [name, _visit(target)]);
2221 } 2227 }
2222 code = 'dart.bind(#, #)'; 2228 code = 'dart.bind(#, #)';
2223 } else if (_requiresStaticDispatch(target, memberId.name)) { 2229 } else if (_requiresStaticDispatch(target, memberId.name)) {
2224 return js.call('dart.#(#)', [name, _visit(target)]); 2230 return js.call('dart.#(#)', [name, _visit(target)]);
2225 } else { 2231 } else {
2226 code = '#.#'; 2232 code = '#.#';
2227 } 2233 }
2228 2234
2229 return js.call(code, [_visit(target), name]); 2235 return js.call(code, [_visit(target), name]);
2230 } 2236 }
2231 2237
2232 /// Emits a generic send, like an operator method. 2238 /// Emits a generic send, like an operator method.
2233 /// 2239 ///
2234 /// **Please note** this function does not support method invocation syntax 2240 /// **Please note** this function does not support method invocation syntax
2235 /// `obj.name(args)` because that could be a getter followed by a call. 2241 /// `obj.name(args)` because that could be a getter followed by a call.
2236 /// See [visitMethodInvocation]. 2242 /// See [visitMethodInvocation].
2237 JS.Expression _emitSend( 2243 JS.Expression _emitSend(
2238 Expression target, String name, List<Expression> args) { 2244 Expression target, String name, List<Expression> args) {
2239 var type = getStaticType(target); 2245 var type = getStaticType(target);
2240 var memberName = _emitMemberName(name, unary: args.isEmpty, type: type); 2246 var memberName = _emitMemberName(name, unary: args.isEmpty, type: type);
2241 if (rules.isDynamicTarget(target)) { 2247 if (DynamicInvoke.get(target)) {
2242 // dynamic dispatch 2248 // dynamic dispatch
2243 var dynamicHelper = const {'[]': DINDEX, '[]=': DSETINDEX}[name]; 2249 var dynamicHelper = const {'[]': DINDEX, '[]=': DSETINDEX}[name];
2244 if (dynamicHelper != null) { 2250 if (dynamicHelper != null) {
2245 return js.call( 2251 return js.call(
2246 'dart.$dynamicHelper(#, #)', [_visit(target), _visitList(args)]); 2252 'dart.$dynamicHelper(#, #)', [_visit(target), _visitList(args)]);
2247 } 2253 }
2248 return js.call('dart.$DSEND(#, #, #)', [ 2254 return js.call('dart.$DSEND(#, #, #)', [
2249 _visit(target), 2255 _visit(target),
2250 memberName, 2256 memberName,
2251 _visitList(args) 2257 _visitList(args)
(...skipping 534 matching lines...) Expand 10 before | Expand all | Expand 10 after
2786 2792
2787 /// A special kind of element created by the compiler, signifying a temporary 2793 /// A special kind of element created by the compiler, signifying a temporary
2788 /// variable. These objects use instance equality, and should be shared 2794 /// variable. These objects use instance equality, and should be shared
2789 /// everywhere in the tree where they are treated as the same variable. 2795 /// everywhere in the tree where they are treated as the same variable.
2790 class TemporaryVariableElement extends LocalVariableElementImpl { 2796 class TemporaryVariableElement extends LocalVariableElementImpl {
2791 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); 2797 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name);
2792 2798
2793 int get hashCode => identityHashCode(this); 2799 int get hashCode => identityHashCode(this);
2794 bool operator ==(Object other) => identical(this, other); 2800 bool operator ==(Object other) => identical(this, other);
2795 } 2801 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698