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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_builder.dart

Issue 574683002: Use ConstExp for storing constants. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fixes and further implementation. Created 6 years, 2 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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 dart2js.ir_builder; 5 library dart2js.ir_builder;
6 6
7 import 'cps_ir_nodes.dart' as ir; 7 import 'cps_ir_nodes.dart' as ir;
8 import '../elements/elements.dart'; 8 import '../elements/elements.dart';
9 import '../dart2jslib.dart'; 9 import '../dart2jslib.dart';
10 import '../dart_types.dart'; 10 import '../dart_types.dart';
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after
315 } 315 }
316 316
317 ir.Primitive continueWithExpression(ir.Expression build(ir.Continuation k)) { 317 ir.Primitive continueWithExpression(ir.Expression build(ir.Continuation k)) {
318 ir.Parameter v = new ir.Parameter(null); 318 ir.Parameter v = new ir.Parameter(null);
319 ir.Continuation k = new ir.Continuation([v]); 319 ir.Continuation k = new ir.Continuation([v]);
320 ir.Expression expression = build(k); 320 ir.Expression expression = build(k);
321 add(new ir.LetCont(k, expression)); 321 add(new ir.LetCont(k, expression));
322 return v; 322 return v;
323 } 323 }
324 324
325 ir.Constant makeConst(ConstExp exp, Constant value) { 325 ir.Constant makeConst(ConstExp exp) {
326 return new ir.Constant(exp, value); 326 return new ir.Constant(exp);
327 } 327 }
328 328
329 ir.Constant makePrimConst(PrimitiveConstant value) { 329 ir.Constant makePrimConst(PrimitiveConstant value) {
330 return makeConst(new PrimitiveConstExp(value), value); 330 return makeConst(new PrimitiveConstExp(value));
331 } 331 }
332 332
333 // TODO(johnniwinther): Build constants directly through [ConstExp] when these 333 // TODO(johnniwinther): Build constants directly through [ConstExp] when these
334 // are created from analyzer2dart. 334 // are created from analyzer2dart.
335 ir.Node buildPrimConst(PrimitiveConstant constant) { 335 ir.Node buildPrimConst(PrimitiveConstant constant) {
336 assert(isOpen); 336 assert(isOpen);
337 ir.Node prim = makePrimConst(constant); 337 ir.Node prim = makePrimConst(constant);
338 add(new ir.LetPrim(prim)); 338 add(new ir.LetPrim(prim));
339 return prim; 339 return prim;
340 } 340 }
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
458 // assigned in the delimited subexpression to their reaching definition --- 458 // assigned in the delimited subexpression to their reaching definition ---
459 // that is, the definition in effect at the hole in 'current'. These are 459 // that is, the definition in effect at the hole in 'current'. These are
460 // used to determine if a join-point continuation needs to be passed 460 // used to determine if a join-point continuation needs to be passed
461 // arguments, and what the arguments are. 461 // arguments, and what the arguments are.
462 462
463 /// A stack of collectors for breaks. 463 /// A stack of collectors for breaks.
464 final List<JumpCollector> breakCollectors; 464 final List<JumpCollector> breakCollectors;
465 /// A stack of collectors for continues. 465 /// A stack of collectors for continues.
466 final List<JumpCollector> continueCollectors; 466 final List<JumpCollector> continueCollectors;
467 467
468 ConstExpBuilder constantBuilder;
469
470 final List<ConstDeclaration> localConstants; 468 final List<ConstDeclaration> localConstants;
471 469
472 FunctionElement currentFunction; 470 FunctionElement currentFunction;
473 final DetectClosureVariables closureLocals; 471 final DetectClosureVariables closureLocals;
474 472
475 /// Construct a top-level visitor. 473 /// Construct a top-level visitor.
476 IrBuilderVisitor(TreeElements elements, this.compiler, this.sourceFile) 474 IrBuilderVisitor(TreeElements elements, this.compiler, this.sourceFile)
477 : breakCollectors = <JumpCollector>[], 475 : breakCollectors = <JumpCollector>[],
478 continueCollectors = <JumpCollector>[], 476 continueCollectors = <JumpCollector>[],
479 localConstants = <ConstDeclaration>[], 477 localConstants = <ConstDeclaration>[],
480 closureLocals = new DetectClosureVariables(elements), 478 closureLocals = new DetectClosureVariables(elements),
481 super(elements) { 479 super(elements) {
482 constantSystem = compiler.backend.constantSystem; 480 constantSystem = compiler.backend.constantSystem;
483 constantBuilder = new ConstExpBuilder(this);
484 } 481 }
485 482
486 /// Construct a delimited visitor for visiting a subtree. 483 /// Construct a delimited visitor for visiting a subtree.
487 /// 484 ///
488 /// The delimited visitor has its own compile-time environment mapping 485 /// The delimited visitor has its own compile-time environment mapping
489 /// local variables to their values, which is initially a copy of the parent 486 /// local variables to their values, which is initially a copy of the parent
490 /// environment. It has its own context for building an IR expression, so 487 /// environment. It has its own context for building an IR expression, so
491 /// the built expression is not plugged into the parent's context. 488 /// the built expression is not plugged into the parent's context.
492 IrBuilderVisitor.delimited(IrBuilderVisitor parent) 489 IrBuilderVisitor.delimited(IrBuilderVisitor parent)
493 : compiler = parent.compiler, 490 : compiler = parent.compiler,
494 sourceFile = parent.sourceFile, 491 sourceFile = parent.sourceFile,
495 breakCollectors = parent.breakCollectors, 492 breakCollectors = parent.breakCollectors,
496 continueCollectors = parent.continueCollectors, 493 continueCollectors = parent.continueCollectors,
497 constantBuilder = parent.constantBuilder,
498 localConstants = parent.localConstants, 494 localConstants = parent.localConstants,
499 currentFunction = parent.currentFunction, 495 currentFunction = parent.currentFunction,
500 closureLocals = parent.closureLocals, 496 closureLocals = parent.closureLocals,
501 super(parent.elements) { 497 super(parent.elements) {
502 constantSystem = parent.constantSystem; 498 constantSystem = parent.constantSystem;
503 returnContinuation = parent.returnContinuation; 499 returnContinuation = parent.returnContinuation;
504 environment = new Environment.from(parent.environment); 500 environment = new Environment.from(parent.environment);
505 } 501 }
506 502
507 /// Construct a visitor for a recursive continuation. 503 /// Construct a visitor for a recursive continuation.
508 /// 504 ///
509 /// The recursive continuation builder has fresh parameters (i.e. SSA phis) 505 /// The recursive continuation builder has fresh parameters (i.e. SSA phis)
510 /// for all the local variables in the parent, because the invocation sites 506 /// for all the local variables in the parent, because the invocation sites
511 /// of the continuation are not all known when the builder is created. The 507 /// of the continuation are not all known when the builder is created. The
512 /// recursive invocations will be passed values for all the local variables, 508 /// recursive invocations will be passed values for all the local variables,
513 /// which may be eliminated later if they are redundant---if they take on 509 /// which may be eliminated later if they are redundant---if they take on
514 /// the same value at all invocation sites. 510 /// the same value at all invocation sites.
515 IrBuilderVisitor.recursive(IrBuilderVisitor parent) 511 IrBuilderVisitor.recursive(IrBuilderVisitor parent)
516 : compiler = parent.compiler, 512 : compiler = parent.compiler,
517 sourceFile = parent.sourceFile, 513 sourceFile = parent.sourceFile,
518 breakCollectors = parent.breakCollectors, 514 breakCollectors = parent.breakCollectors,
519 continueCollectors = parent.continueCollectors, 515 continueCollectors = parent.continueCollectors,
520 constantBuilder = parent.constantBuilder,
521 localConstants = parent.localConstants, 516 localConstants = parent.localConstants,
522 currentFunction = parent.currentFunction, 517 currentFunction = parent.currentFunction,
523 closureLocals = parent.closureLocals, 518 closureLocals = parent.closureLocals,
524 super(parent.elements) { 519 super(parent.elements) {
525 constantSystem = parent.constantSystem; 520 constantSystem = parent.constantSystem;
526 returnContinuation = parent.returnContinuation; 521 returnContinuation = parent.returnContinuation;
527 parent.environment.index2variable.forEach(createParameter); 522 parent.environment.index2variable.forEach(createParameter);
528 } 523 }
529 524
530 /** 525 /**
(...skipping 18 matching lines...) Expand all
549 _root = _current = null; 544 _root = _current = null;
550 545
551 FunctionSignature signature = element.functionSignature; 546 FunctionSignature signature = element.functionSignature;
552 signature.orderedForEachParameter((ParameterElement parameterElement) { 547 signature.orderedForEachParameter((ParameterElement parameterElement) {
553 createParameter(parameterElement, 548 createParameter(parameterElement,
554 isClosureVariable: isClosureVariable(parameterElement)); 549 isClosureVariable: isClosureVariable(parameterElement));
555 }); 550 });
556 551
557 List<ConstExp> defaults = new List<ConstExp>(); 552 List<ConstExp> defaults = new List<ConstExp>();
558 signature.orderedOptionalParameters.forEach((ParameterElement element) { 553 signature.orderedOptionalParameters.forEach((ParameterElement element) {
559 if (element.initializer != null) { 554 defaults.add(getConstantForVariable(element));
560 defaults.add(constantBuilder.visit(element.initializer));
561 } else {
562 defaults.add(new PrimitiveConstExp(constantSystem.createNull()));
563 }
564 }); 555 });
565 556
566 visit(function.body); 557 visit(function.body);
567 return buildFunctionDefinition(element, localConstants, defaults); 558 return buildFunctionDefinition(element, localConstants, defaults);
568 } 559 }
569 560
570 ir.Primitive visit(ast.Node node) => node.accept(this); 561 ir.Primitive visit(ast.Node node) => node.accept(this);
571 562
572 // ==== Statements ==== 563 // ==== Statements ====
573 // Build(Block(stamements), C) = C' 564 // Build(Block(stamements), C) = C'
(...skipping 580 matching lines...) Expand 10 before | Expand all | Expand 10 after
1154 return null; 1145 return null;
1155 } 1146 }
1156 1147
1157 ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) { 1148 ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) {
1158 assert(isOpen); 1149 assert(isOpen);
1159 if (node.modifiers.isConst) { 1150 if (node.modifiers.isConst) {
1160 for (ast.SendSet definition in node.definitions.nodes) { 1151 for (ast.SendSet definition in node.definitions.nodes) {
1161 assert(!definition.arguments.isEmpty); 1152 assert(!definition.arguments.isEmpty);
1162 assert(definition.arguments.tail.isEmpty); 1153 assert(definition.arguments.tail.isEmpty);
1163 VariableElement element = elements[definition]; 1154 VariableElement element = elements[definition];
1164 ConstExp value = constantBuilder.visit(definition.arguments.head); 1155 ConstExp value = getConstantForVariable(element);
1165 localConstants.add(new ConstDeclaration(element, value)); 1156 localConstants.add(new ConstDeclaration(element, value));
1166 } 1157 }
1167 } else { 1158 } else {
1168 for (ast.Node definition in node.definitions.nodes) { 1159 for (ast.Node definition in node.definitions.nodes) {
1169 Element element = elements[definition]; 1160 Element element = elements[definition];
1170 ir.Primitive initialValue; 1161 ir.Primitive initialValue;
1171 // Definitions are either SendSets if there is an initializer, or 1162 // Definitions are either SendSets if there is an initializer, or
1172 // Identifiers if there is no initializer. 1163 // Identifiers if there is no initializer.
1173 if (definition is ast.SendSet) { 1164 if (definition is ast.SendSet) {
1174 assert(!definition.arguments.isEmpty); 1165 assert(!definition.arguments.isEmpty);
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
1275 ir.Primitive visitLiteralNull(ast.LiteralNull node) { 1266 ir.Primitive visitLiteralNull(ast.LiteralNull node) {
1276 assert(isOpen); 1267 assert(isOpen);
1277 return translateConstant(node); 1268 return translateConstant(node);
1278 } 1269 }
1279 1270
1280 ir.Primitive visitLiteralString(ast.LiteralString node) { 1271 ir.Primitive visitLiteralString(ast.LiteralString node) {
1281 assert(isOpen); 1272 assert(isOpen);
1282 return translateConstant(node); 1273 return translateConstant(node);
1283 } 1274 }
1284 1275
1285 Constant getConstantForNode(ast.Node node) { 1276 ConstExp getConstantForNode(ast.Node node) {
1286 Constant constant = 1277 ConstExp constant =
1287 compiler.backend.constantCompilerTask.compileNode(node, elements); 1278 compiler.backend.constantCompilerTask.compileNode(node, elements);
1288 assert(invariant(node, constant != null, 1279 assert(invariant(node, constant != null,
1289 message: 'No constant computed for $node')); 1280 message: 'No constant computed for $node'));
1290 return constant; 1281 return constant;
1291 } 1282 }
1292 1283
1284 ConstExp getConstantForVariable(VariableElement element) {
1285 ConstExp constant =
1286 compiler.backend.constants.getConstantForVariable(element);
1287 assert(invariant(element, constant != null,
1288 message: 'No constant computed for $element'));
1289 return constant;
1290 }
1291
1293 ir.Primitive visitLiteralList(ast.LiteralList node) { 1292 ir.Primitive visitLiteralList(ast.LiteralList node) {
1294 assert(isOpen); 1293 assert(isOpen);
1295 if (node.isConst) { 1294 if (node.isConst) {
1296 return translateConstant(node); 1295 return translateConstant(node);
1297 } 1296 }
1298 List<ir.Primitive> values = node.elements.nodes.mapToList(visit); 1297 List<ir.Primitive> values = node.elements.nodes.mapToList(visit);
1299 GenericType type = elements.getType(node); 1298 GenericType type = elements.getType(node);
1300 ir.Primitive result = new ir.LiteralList(type, values); 1299 ir.Primitive result = new ir.LiteralList(type, values);
1301 add(new ir.LetPrim(result)); 1300 add(new ir.LetPrim(result));
1302 return result; 1301 return result;
(...skipping 562 matching lines...) Expand 10 before | Expand all | Expand 10 after
1865 var it = node.parts.iterator; 1864 var it = node.parts.iterator;
1866 while (it.moveNext()) { 1865 while (it.moveNext()) {
1867 ast.StringInterpolationPart part = it.current; 1866 ast.StringInterpolationPart part = it.current;
1868 arguments.add(visit(part.expression)); 1867 arguments.add(visit(part.expression));
1869 arguments.add(visitLiteralString(part.string)); 1868 arguments.add(visitLiteralString(part.string));
1870 } 1869 }
1871 return continueWithExpression( 1870 return continueWithExpression(
1872 (k) => new ir.ConcatenateStrings(k, arguments)); 1871 (k) => new ir.ConcatenateStrings(k, arguments));
1873 } 1872 }
1874 1873
1875 ir.Primitive translateConstant(ast.Node node, [Constant value]) { 1874 ir.Primitive translateConstant(ast.Node node, [ConstExp constant]) {
1876 assert(isOpen); 1875 assert(isOpen);
1877 if (value == null) { 1876 if (constant == null) {
1878 value = getConstantForNode(node); 1877 constant = getConstantForNode(node);
1879 } 1878 }
1880 ir.Primitive primitive = makeConst(constantBuilder.visit(node), value); 1879 ir.Primitive primitive = makeConst(constant);
1881 add(new ir.LetPrim(primitive)); 1880 add(new ir.LetPrim(primitive));
1882 return primitive; 1881 return primitive;
1883 } 1882 }
1884 1883
1885 ir.FunctionDefinition makeSubFunction(ast.FunctionExpression node) { 1884 ir.FunctionDefinition makeSubFunction(ast.FunctionExpression node) {
1886 return new IrBuilderVisitor(elements, compiler, sourceFile) 1885 return new IrBuilderVisitor(elements, compiler, sourceFile)
1887 .buildFunctionInternal(elements[node]); 1886 .buildFunctionInternal(elements[node]);
1888 } 1887 }
1889 1888
1890 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) { 1889 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) {
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
1924 } 1923 }
1925 rethrow; 1924 rethrow;
1926 } 1925 }
1927 } 1926 }
1928 1927
1929 void internalError(String reason, {ast.Node node}) { 1928 void internalError(String reason, {ast.Node node}) {
1930 giveup(node); 1929 giveup(node);
1931 } 1930 }
1932 } 1931 }
1933 1932
1934 /// Translates constant expressions from the AST to the [ConstExp] language.
1935 class ConstExpBuilder extends ast.Visitor<ConstExp> {
1936 final IrBuilderVisitor parent;
1937 final TreeElements elements;
1938 final ConstantSystem constantSystem;
1939 final ConstantCompiler constantCompiler;
1940
1941 ConstExpBuilder(IrBuilderVisitor parent)
1942 : this.parent = parent,
1943 this.elements = parent.elements,
1944 this.constantSystem = parent.constantSystem,
1945 this.constantCompiler = parent.compiler.backend.constantCompilerTask;
1946
1947 Constant computeConstant(ast.Node node) {
1948 return constantCompiler.compileNode(node, elements);
1949 }
1950
1951 /// True if the given constant is small enough that inlining it is likely
1952 /// to be profitable. Always false for non-primitive constants.
1953 bool isSmallConstant(Constant constant) {
1954 if (constant is BoolConstant || constant is NullConstant) {
1955 return true;
1956 }
1957 if (constant is IntConstant) {
1958 return -10 < constant.value && constant.value < 100;
1959 }
1960 if (constant is DoubleConstant) {
1961 return constant.isZero || constant.isOne;
1962 }
1963 if (constant is StringConstant) {
1964 ast.DartString string = constant.value;
1965 if (string is ast.LiteralDartString) {
1966 return string.length < 4;
1967 }
1968 if (string is ast.SourceBasedDartString) {
1969 return string.length < 4;
1970 }
1971 }
1972 return false;
1973 }
1974
1975 ConstExp visit(ast.Node node) => node.accept(this);
1976
1977 ConstExp visitStringJuxtaposition(ast.StringJuxtaposition node) {
1978 ConstExp first = visit(node.first);
1979 ConstExp second = visit(node.second);
1980 return new ConcatenateConstExp([first, second]);
1981 }
1982
1983 ConstExp visitStringInterpolation(ast.StringInterpolation node) {
1984 List<ConstExp> arguments = <ConstExp>[];
1985 arguments.add(visitLiteralString(node.string));
1986 var it = node.parts.iterator;
1987 while (it.moveNext()) {
1988 ast.StringInterpolationPart part = it.current;
1989 arguments.add(visit(part.expression));
1990 arguments.add(visitLiteralString(part.string));
1991 }
1992 return new ConcatenateConstExp(arguments);
1993 }
1994
1995 ConstExp visitNewExpression(ast.NewExpression node) {
1996 FunctionElement element = elements[node.send];
1997 // The resolver will already have thrown an error if the constructor was
1998 // unresolved.
1999 assert(invariant(node, !Elements.isUnresolved(element)));
2000
2001 Selector selector = elements.getSelector(node.send);
2002 ast.Node selectorNode = node.send.selector;
2003 GenericType type = elements.getType(node);
2004 List<ConstExp> args = node.send.arguments.mapToList(visit, growable:false);
2005 return new ConstructorConstExp(type, element, selector, args);
2006 }
2007
2008 ConstExp visitNamedArgument(ast.NamedArgument node) {
2009 return visit(node.expression);
2010 }
2011
2012 ConstExp visitSend(ast.Send node) {
2013 Element element = elements[node];
2014 if (node.isOperator) {
2015 return new PrimitiveConstExp(computeConstant(node));
2016 }
2017 if (Elements.isStaticOrTopLevelFunction(element)) {
2018 return new FunctionConstExp(element);
2019 }
2020 if (Elements.isLocal(element) ||
2021 Elements.isStaticOrTopLevelField(element)) {
2022 // If the constant is small, inline it instead of using the declared const
2023 Constant value = constantCompiler.getConstantForVariable(element);
2024 if (isSmallConstant(value))
2025 return new PrimitiveConstExp(value);
2026 else
2027 return new VariableConstExp(element);
2028 }
2029 DartType type = elements.getTypeLiteralType(node);
2030 if (type != null) {
2031 return new TypeConstExp(type);
2032 }
2033 throw "Unexpected constant Send: $node";
2034 }
2035
2036 ConstExp visitParenthesizedExpression(ast.ParenthesizedExpression node) {
2037 return visit(node.expression);
2038 }
2039
2040 ConstExp visitLiteralList(ast.LiteralList node) {
2041 List<ConstExp> values = node.elements.nodes.mapToList(visit);
2042 GenericType type = elements.getType(node);
2043 return new ListConstExp(type, values);
2044 }
2045
2046 ConstExp visitLiteralMap(ast.LiteralMap node) {
2047 List<ConstExp> keys = new List<ConstExp>();
2048 List<ConstExp> values = new List<ConstExp>();
2049 node.entries.nodes.forEach((ast.LiteralMapEntry node) {
2050 keys.add(visit(node.key));
2051 values.add(visit(node.value));
2052 });
2053 GenericType type = elements.getType(node);
2054 return new MapConstExp(type, keys, values);
2055 }
2056
2057 ConstExp visitLiteralSymbol(ast.LiteralSymbol node) {
2058 return new SymbolConstExp(node.slowNameString);
2059 }
2060
2061 ConstExp visitLiteralInt(ast.LiteralInt node) {
2062 return new PrimitiveConstExp(constantSystem.createInt(node.value));
2063 }
2064
2065 ConstExp visitLiteralDouble(ast.LiteralDouble node) {
2066 return new PrimitiveConstExp(constantSystem.createDouble(node.value));
2067 }
2068
2069 ConstExp visitLiteralString(ast.LiteralString node) {
2070 return new PrimitiveConstExp(constantSystem.createString(node.dartString));
2071 }
2072
2073 ConstExp visitLiteralBool(ast.LiteralBool node) {
2074 return new PrimitiveConstExp(constantSystem.createBool(node.value));
2075 }
2076
2077 ConstExp visitLiteralNull(ast.LiteralNull node) {
2078 return new PrimitiveConstExp(constantSystem.createNull());
2079 }
2080
2081 ConstExp visitConditional(ast.Conditional node) {
2082 BoolConstant condition = computeConstant(node.condition);
2083 return visit(condition.isTrue ? node.thenExpression : node.elseExpression);
2084 }
2085
2086 ConstExp visitNode(ast.Node node) {
2087 throw "Unexpected constant: $node";
2088 }
2089
2090 }
2091
2092 /// Classifies local variables and local functions as 'closure variables'. 1933 /// Classifies local variables and local functions as 'closure variables'.
2093 /// A closure variable is one that is accessed from an inner function nested 1934 /// A closure variable is one that is accessed from an inner function nested
2094 /// one or more levels inside the one that declares it. 1935 /// one or more levels inside the one that declares it.
2095 class DetectClosureVariables extends ast.Visitor { 1936 class DetectClosureVariables extends ast.Visitor {
2096 final TreeElements elements; 1937 final TreeElements elements;
2097 DetectClosureVariables(this.elements); 1938 DetectClosureVariables(this.elements);
2098 1939
2099 FunctionElement currentFunction; 1940 FunctionElement currentFunction;
2100 Set<Local> usedFromClosure = new Set<Local>(); 1941 Set<Local> usedFromClosure = new Set<Local>();
2101 Set<FunctionElement> recursiveFunctions = new Set<FunctionElement>(); 1942 Set<FunctionElement> recursiveFunctions = new Set<FunctionElement>();
(...skipping 22 matching lines...) Expand all
2124 } 1965 }
2125 1966
2126 visitFunctionExpression(ast.FunctionExpression node) { 1967 visitFunctionExpression(ast.FunctionExpression node) {
2127 FunctionElement oldFunction = currentFunction; 1968 FunctionElement oldFunction = currentFunction;
2128 currentFunction = elements[node]; 1969 currentFunction = elements[node];
2129 visit(node.body); 1970 visit(node.body);
2130 currentFunction = oldFunction; 1971 currentFunction = oldFunction;
2131 } 1972 }
2132 1973
2133 } 1974 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698