118 if (lastDot == -1) {
119 return cn;
120 }
121 return cn.substring(lastDot + 1);
122 }
123
124 /**
125 * Checks if various symbols that were provisionally marked as needing a slot ended up unused, and marks them as not
126 * needing a slot after all.
127 * @param functionNode the function node
128 * @return the passed in node, for easy chaining
129 */
130 private static FunctionNode removeUnusedSlots(final FunctionNode functionNode) {
131 if (!functionNode.needsCallee()) {
132 functionNode.compilerConstant(CALLEE).setNeedsSlot(false);
133 }
134 if (!(functionNode.hasScopeBlock() || functionNode.needsParentScope())) {
135 functionNode.compilerConstant(SCOPE).setNeedsSlot(false);
136 }
137 // Named function expressions that end up not referencing themselves won't need a local slot for the self symbol.
138 if(!functionNode.isDeclared() && !functionNode.usesSelfSymbol() && !functionNode.isAnonymous()) {
139 final Symbol selfSymbol = functionNode.getBody().getExistingSymbol(functionNode.getIdent().getName());
140 if(selfSymbol != null) {
141 if(selfSymbol.isFunctionSelf()) {
142 selfSymbol.setNeedsSlot(false);
143 selfSymbol.clearFlag(Symbol.IS_VAR);
144 }
145 } else {
146 assert functionNode.isProgram();
147 }
148 }
149 return functionNode;
150 }
151
152 private final Deque<Set<String>> thisProperties = new ArrayDeque<>();
153 private final Map<String, Symbol> globalSymbols = new HashMap<>(); //reuse the same global symbol
154 private final Compiler compiler;
155
156 public AssignSymbols(final Compiler compiler) {
157 super(new LexicalContext());
158 this.compiler = compiler;
159 this.log = initLogger(compiler.getContext());
160 this.debug = log.isEnabled();
161 }
162
163 @Override
164 public DebugLogger getLogger() {
165 return log;
166 }
167
473 start(catchNode);
474
475 // define block-local exception variable
476 final String exname = exception.getName();
477 // If the name of the exception starts with ":e", this is a synthetic catch block, likely a catch-all. Its
478 // symbol is naturally internal, and should be treated as such.
479 final boolean isInternal = exname.startsWith(EXCEPTION_PREFIX.symbolName());
480 // IS_LET flag is required to make sure symbol is not visible outside catch block. However, we need to
481 // clear the IS_LET flag after creation to allow redefinition of symbol inside the catch block.
482 final Symbol symbol = defineSymbol(block, exname, catchNode, IS_VAR | IS_LET | (isInternal ? IS_INTERNAL : 0) | HAS_OBJECT_VALUE);
483 symbol.clearFlag(IS_LET);
484
485 return true;
486 }
487
488 private void enterFunctionBody() {
489 final FunctionNode functionNode = lc.getCurrentFunction();
490 final Block body = lc.getCurrentBlock();
491
492 initFunctionWideVariables(functionNode, body);
493
494 if (!functionNode.isProgram() && !functionNode.isDeclared() && !functionNode.isAnonymous()) {
495 // It's neither declared nor program - it's a function expression then; assign it a self-symbol unless it's
496 // anonymous.
497 final String name = functionNode.getIdent().getName();
498 assert name != null;
499 assert body.getExistingSymbol(name) == null;
500 defineSymbol(body, name, functionNode, IS_VAR | IS_FUNCTION_SELF | HAS_OBJECT_VALUE);
501 if(functionNode.allVarsInScope()) { // basically, has deep eval
502 lc.setFlag(functionNode, FunctionNode.USES_SELF_SYMBOL);
503 }
504 }
505
506 acceptDeclarations(functionNode, body);
507 }
508
509 @Override
510 public boolean enterFunctionNode(final FunctionNode functionNode) {
511 start(functionNode, false);
512
513 thisProperties.push(new HashSet<String>());
514
515 // Every function has a body, even the ones skipped on reparse (they have an empty one). We're
516 // asserting this as even for those, enterBlock() must be invoked to correctly process symbols that
517 // are used in them.
518 assert functionNode.getBody() != null;
519
520 return true;
521 }
522
523 @Override
524 public boolean enterVarNode(final VarNode varNode) {
525 start(varNode);
526 // Normally, a symbol assigned in a var statement is not live for its RHS. Since we also represent function
|
118 if (lastDot == -1) {
119 return cn;
120 }
121 return cn.substring(lastDot + 1);
122 }
123
124 /**
125 * Checks if various symbols that were provisionally marked as needing a slot ended up unused, and marks them as not
126 * needing a slot after all.
127 * @param functionNode the function node
128 * @return the passed in node, for easy chaining
129 */
130 private static FunctionNode removeUnusedSlots(final FunctionNode functionNode) {
131 if (!functionNode.needsCallee()) {
132 functionNode.compilerConstant(CALLEE).setNeedsSlot(false);
133 }
134 if (!(functionNode.hasScopeBlock() || functionNode.needsParentScope())) {
135 functionNode.compilerConstant(SCOPE).setNeedsSlot(false);
136 }
137 // Named function expressions that end up not referencing themselves won't need a local slot for the self symbol.
138 if(functionNode.isNamedFunctionExpression() && !functionNode.usesSelfSymbol()) {
139 final Symbol selfSymbol = functionNode.getBody().getExistingSymbol(functionNode.getIdent().getName());
140 if(selfSymbol != null && selfSymbol.isFunctionSelf()) {
141 selfSymbol.setNeedsSlot(false);
142 selfSymbol.clearFlag(Symbol.IS_VAR);
143 }
144 }
145 return functionNode;
146 }
147
148 private final Deque<Set<String>> thisProperties = new ArrayDeque<>();
149 private final Map<String, Symbol> globalSymbols = new HashMap<>(); //reuse the same global symbol
150 private final Compiler compiler;
151
152 public AssignSymbols(final Compiler compiler) {
153 super(new LexicalContext());
154 this.compiler = compiler;
155 this.log = initLogger(compiler.getContext());
156 this.debug = log.isEnabled();
157 }
158
159 @Override
160 public DebugLogger getLogger() {
161 return log;
162 }
163
469 start(catchNode);
470
471 // define block-local exception variable
472 final String exname = exception.getName();
473 // If the name of the exception starts with ":e", this is a synthetic catch block, likely a catch-all. Its
474 // symbol is naturally internal, and should be treated as such.
475 final boolean isInternal = exname.startsWith(EXCEPTION_PREFIX.symbolName());
476 // IS_LET flag is required to make sure symbol is not visible outside catch block. However, we need to
477 // clear the IS_LET flag after creation to allow redefinition of symbol inside the catch block.
478 final Symbol symbol = defineSymbol(block, exname, catchNode, IS_VAR | IS_LET | (isInternal ? IS_INTERNAL : 0) | HAS_OBJECT_VALUE);
479 symbol.clearFlag(IS_LET);
480
481 return true;
482 }
483
484 private void enterFunctionBody() {
485 final FunctionNode functionNode = lc.getCurrentFunction();
486 final Block body = lc.getCurrentBlock();
487
488 initFunctionWideVariables(functionNode, body);
489 acceptDeclarations(functionNode, body);
490 defineFunctionSelfSymbol(functionNode, body);
491 }
492
493 private void defineFunctionSelfSymbol(final FunctionNode functionNode, final Block body) {
494 // Function self-symbol is only declared as a local variable for named function expressions. Declared functions
495 // don't need it as they are local variables in their declaring scope.
496 if (!functionNode.isNamedFunctionExpression()) {
497 return;
498 }
499
500 final String name = functionNode.getIdent().getName();
501 assert name != null; // As it's a named function expression.
502
503 if (body.getExistingSymbol(name) != null) {
504 // Body already has a declaration for the name. It's either a parameter "function x(x)" or a
505 // top-level variable "function x() { ... var x; ... }".
506 return;
507 }
508
509 defineSymbol(body, name, functionNode, IS_VAR | IS_FUNCTION_SELF | HAS_OBJECT_VALUE);
510 if(functionNode.allVarsInScope()) { // basically, has deep eval
511 // We must conservatively presume that eval'd code can dynamically use the function symbol.
512 lc.setFlag(functionNode, FunctionNode.USES_SELF_SYMBOL);
513 }
514 }
515
516 @Override
517 public boolean enterFunctionNode(final FunctionNode functionNode) {
518 start(functionNode, false);
519
520 thisProperties.push(new HashSet<String>());
521
522 // Every function has a body, even the ones skipped on reparse (they have an empty one). We're
523 // asserting this as even for those, enterBlock() must be invoked to correctly process symbols that
524 // are used in them.
525 assert functionNode.getBody() != null;
526
527 return true;
528 }
529
530 @Override
531 public boolean enterVarNode(final VarNode varNode) {
532 start(varNode);
533 // Normally, a symbol assigned in a var statement is not live for its RHS. Since we also represent function
|