41 import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS; |
41 import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS; |
42 import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup; |
42 import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup; |
43 import static jdk.nashorn.internal.codegen.CompilerConstants.interfaceCallNoLookup; |
43 import static jdk.nashorn.internal.codegen.CompilerConstants.interfaceCallNoLookup; |
44 import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor; |
44 import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor; |
45 import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup; |
45 import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup; |
46 import static jdk.nashorn.internal.codegen.CompilerConstants.staticField; |
|
47 import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor; |
46 import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor; |
48 import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup; |
47 import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup; |
49 import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL; |
48 import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL; |
50 import static jdk.nashorn.internal.ir.Symbol.IS_TEMP; |
49 import static jdk.nashorn.internal.ir.Symbol.IS_TEMP; |
51 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_FAST_SCOPE; |
50 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_FAST_SCOPE; |
58 import java.util.EnumSet; |
57 import java.util.EnumSet; |
59 import java.util.HashSet; |
58 import java.util.HashSet; |
60 import java.util.Iterator; |
59 import java.util.Iterator; |
61 import java.util.LinkedList; |
60 import java.util.LinkedList; |
62 import java.util.List; |
61 import java.util.List; |
63 import java.util.Locale; |
|
64 import java.util.Set; |
62 import java.util.Set; |
65 import java.util.TreeMap; |
63 import java.util.TreeMap; |
66 import jdk.nashorn.internal.codegen.ClassEmitter.Flag; |
64 import jdk.nashorn.internal.codegen.ClassEmitter.Flag; |
67 import jdk.nashorn.internal.codegen.CompilerConstants.Call; |
65 import jdk.nashorn.internal.codegen.CompilerConstants.Call; |
68 import jdk.nashorn.internal.codegen.RuntimeCallSite.SpecializedRuntimeNode; |
66 import jdk.nashorn.internal.codegen.RuntimeCallSite.SpecializedRuntimeNode; |
109 import jdk.nashorn.internal.ir.TryNode; |
107 import jdk.nashorn.internal.ir.TryNode; |
110 import jdk.nashorn.internal.ir.UnaryNode; |
108 import jdk.nashorn.internal.ir.UnaryNode; |
111 import jdk.nashorn.internal.ir.VarNode; |
109 import jdk.nashorn.internal.ir.VarNode; |
112 import jdk.nashorn.internal.ir.WhileNode; |
110 import jdk.nashorn.internal.ir.WhileNode; |
113 import jdk.nashorn.internal.ir.WithNode; |
111 import jdk.nashorn.internal.ir.WithNode; |
114 import jdk.nashorn.internal.ir.debug.ASTWriter; |
|
115 import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor; |
112 import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor; |
116 import jdk.nashorn.internal.ir.visitor.NodeVisitor; |
113 import jdk.nashorn.internal.ir.visitor.NodeVisitor; |
117 import jdk.nashorn.internal.objects.Global; |
114 import jdk.nashorn.internal.objects.Global; |
118 import jdk.nashorn.internal.objects.ScriptFunctionImpl; |
115 import jdk.nashorn.internal.objects.ScriptFunctionImpl; |
119 import jdk.nashorn.internal.parser.Lexer.RegexToken; |
116 import jdk.nashorn.internal.parser.Lexer.RegexToken; |
215 * Load an identity node |
212 * Load an identity node |
216 * |
213 * |
217 * @param identNode an identity node to load |
214 * @param identNode an identity node to load |
218 * @return the method generator used |
215 * @return the method generator used |
219 */ |
216 */ |
220 private MethodEmitter loadIdent(final IdentNode identNode) { |
217 private MethodEmitter loadIdent(final IdentNode identNode, final Type type) { |
221 final Symbol symbol = identNode.getSymbol(); |
218 final Symbol symbol = identNode.getSymbol(); |
222 |
219 |
223 if (!symbol.isScope()) { |
220 if (!symbol.isScope()) { |
224 assert symbol.hasSlot() || symbol.isParam(); |
221 assert symbol.hasSlot() || symbol.isParam(); |
225 return method.load(symbol); |
222 return method.load(symbol).convert(type); |
226 } |
223 } |
227 |
224 |
228 final String name = symbol.getName(); |
225 final String name = symbol.getName(); |
229 final Source source = lc.getCurrentFunction().getSource(); |
226 final Source source = lc.getCurrentFunction().getSource(); |
230 |
227 |
241 method.loadCompilerConstant(SCOPE); |
238 method.loadCompilerConstant(SCOPE); |
242 |
239 |
243 if (isFastScope(symbol)) { |
240 if (isFastScope(symbol)) { |
244 // Only generate shared scope getter for fast-scope symbols so we know we can dial in correct scope. |
241 // Only generate shared scope getter for fast-scope symbols so we know we can dial in correct scope. |
245 if (symbol.getUseCount() > SharedScopeCall.FAST_SCOPE_GET_THRESHOLD) { |
242 if (symbol.getUseCount() > SharedScopeCall.FAST_SCOPE_GET_THRESHOLD) { |
246 return loadSharedScopeVar(identNode.getType(), symbol, flags); |
243 return loadSharedScopeVar(type, symbol, flags); |
247 } |
244 } |
248 return loadFastScopeVar(identNode.getType(), symbol, flags, identNode.isFunction()); |
245 return loadFastScopeVar(type, symbol, flags, identNode.isFunction()); |
249 } |
246 } |
250 return method.dynamicGet(identNode.getType(), identNode.getName(), flags, identNode.isFunction()); |
247 return method.dynamicGet(type, identNode.getName(), flags, identNode.isFunction()); |
251 } |
248 } |
252 } |
249 } |
253 |
250 |
254 /** |
251 /** |
255 * Check if this symbol can be accessed directly with a putfield or getfield or dynamic load |
252 * Check if this symbol can be accessed directly with a putfield or getfield or dynamic load |
311 private MethodEmitter loadFastScopeVar(final Type valueType, final Symbol symbol, final int flags, final boolean isMethod) { |
308 private MethodEmitter loadFastScopeVar(final Type valueType, final Symbol symbol, final int flags, final boolean isMethod) { |
312 loadFastScopeProto(symbol, false); |
309 loadFastScopeProto(symbol, false); |
313 return method.dynamicGet(valueType, symbol.getName(), flags | CALLSITE_FAST_SCOPE, isMethod); |
310 return method.dynamicGet(valueType, symbol.getName(), flags | CALLSITE_FAST_SCOPE, isMethod); |
314 } |
311 } |
315 |
312 |
316 private MethodEmitter storeFastScopeVar(final Type valueType, final Symbol symbol, final int flags) { |
313 private MethodEmitter storeFastScopeVar(final Symbol symbol, final int flags) { |
317 loadFastScopeProto(symbol, true); |
314 loadFastScopeProto(symbol, true); |
318 method.dynamicSet(valueType, symbol.getName(), flags | CALLSITE_FAST_SCOPE); |
315 method.dynamicSet(symbol.getName(), flags | CALLSITE_FAST_SCOPE); |
319 return method; |
316 return method; |
320 } |
317 } |
321 |
318 |
322 private int getScopeProtoDepth(final Block startingBlock, final Symbol symbol) { |
319 private int getScopeProtoDepth(final Block startingBlock, final Symbol symbol) { |
323 int depth = 0; |
320 int depth = 0; |
357 * @param node node to load |
354 * @param node node to load |
358 * |
355 * |
359 * @return the method emitter used |
356 * @return the method emitter used |
360 */ |
357 */ |
361 MethodEmitter load(final Expression node) { |
358 MethodEmitter load(final Expression node) { |
362 return load(node, false); |
359 return load(node, node.hasType() ? node.getType() : null, false); |
363 } |
360 } |
364 |
361 |
365 private MethodEmitter load(final Expression node, final boolean baseAlreadyOnStack) { |
362 private static boolean safeLiteral(final Expression rhs) { |
|
363 return rhs instanceof LiteralNode && !(rhs instanceof ArrayLiteralNode); |
|
364 } |
|
365 |
|
366 MethodEmitter loadBinaryOperands(final Expression lhs, final Expression rhs, final Type type) { |
|
367 return loadBinaryOperands(lhs, rhs, type, false); |
|
368 } |
|
369 |
|
370 private MethodEmitter loadBinaryOperands(final Expression lhs, final Expression rhs, final Type type, final boolean baseAlreadyOnStack) { |
|
371 // ECMAScript 5.1 specification (sections 11.5-11.11 and 11.13) prescribes that when evaluating a binary |
|
372 // expression "LEFT op RIGHT", the order of operations must be: LOAD LEFT, LOAD RIGHT, CONVERT LEFT, CONVERT |
|
373 // RIGHT, EXECUTE OP. Unfortunately, doing it in this order defeats potential optimizations that arise when we |
|
374 // can combine a LOAD with a CONVERT operation (e.g. use a dynamic getter with the conversion target type as its |
|
375 // return value). What we do here is reorder LOAD RIGHT and CONVERT LEFT when possible; it is possible only when |
|
376 // we can prove that executing CONVERT LEFT can't have a side effect that changes the value of LOAD RIGHT. |
|
377 // Basically, if we know that either LEFT is not an object, or RIGHT is a constant literal, then we can do the |
|
378 // reordering and collapse LOAD/CONVERT into a single operation; otherwise we need to do the more costly |
|
379 // separate operations to preserve specification semantics. |
|
380 final Type lhsType = lhs.getType(); |
|
381 if (lhsType.isObject() && !safeLiteral(rhs)) { |
|
382 // Can't reorder. Load and convert separately. |
|
383 load(lhs, lhsType, baseAlreadyOnStack); |
|
384 load(rhs, rhs.getType(), false); |
|
385 // Avoid empty SWAP, SWAP bytecode sequence if CONVERT LEFT is a no-op |
|
386 if (!lhsType.isEquivalentTo(type)) { |
|
387 method.swap(); |
|
388 method.convert(type); |
|
389 method.swap(); |
|
390 } |
|
391 method.convert(type); |
|
392 } else { |
|
393 // Can reorder. Combine load and convert into single operations. |
|
394 load(lhs, type, baseAlreadyOnStack); |
|
395 load(rhs, type, false); |
|
396 } |
|
397 |
|
398 return method; |
|
399 } |
|
400 |
|
401 MethodEmitter loadBinaryOperands(final BinaryNode node) { |
|
402 return loadBinaryOperands(node.lhs(), node.rhs(), node.getType(), false); |
|
403 } |
|
404 |
|
405 private MethodEmitter load(final Expression node, final Type type) { |
|
406 return load(node, type, false); |
|
407 } |
|
408 |
|
409 private MethodEmitter load(final Expression node, final Type type, final boolean baseAlreadyOnStack) { |
366 final Symbol symbol = node.getSymbol(); |
410 final Symbol symbol = node.getSymbol(); |
367 |
411 |
368 // If we lack symbols, we just generate what we see. |
412 // If we lack symbols, we just generate what we see. |
369 if (symbol == null) { |
413 if (symbol == null || type == null) { |
370 node.accept(this); |
414 node.accept(this); |
371 return method; |
415 return method; |
372 } |
416 } |
373 |
417 |
374 /* |
418 /* |
376 * or IndexNode e.g. "x[y]". Both AccessNodes and IndexNodes are |
420 * or IndexNode e.g. "x[y]". Both AccessNodes and IndexNodes are |
377 * BaseNodes and the logic for loading the base object is reused |
421 * BaseNodes and the logic for loading the base object is reused |
378 */ |
422 */ |
379 final CodeGenerator codegen = this; |
423 final CodeGenerator codegen = this; |
380 |
424 |
381 node.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) { |
425 node.accept(new NodeVisitor<LexicalContext>(lc) { |
382 @Override |
426 @Override |
383 public boolean enterIdentNode(final IdentNode identNode) { |
427 public boolean enterIdentNode(final IdentNode identNode) { |
384 loadIdent(identNode); |
428 loadIdent(identNode, type); |
385 return false; |
429 return false; |
386 } |
430 } |
387 |
431 |
388 @Override |
432 @Override |
389 public boolean enterAccessNode(final AccessNode accessNode) { |
433 public boolean enterAccessNode(final AccessNode accessNode) { |
390 if (!baseAlreadyOnStack) { |
434 if (!baseAlreadyOnStack) { |
391 load(accessNode.getBase()).convert(Type.OBJECT); |
435 load(accessNode.getBase()).convert(Type.OBJECT); |
392 } |
436 } |
393 assert method.peekType().isObject(); |
437 assert method.peekType().isObject(); |
394 method.dynamicGet(node.getType(), accessNode.getProperty().getName(), getCallSiteFlags(), accessNode.isFunction()); |
438 method.dynamicGet(type, accessNode.getProperty().getName(), getCallSiteFlags(), accessNode.isFunction()); |
395 return false; |
439 return false; |
396 } |
440 } |
397 |
441 |
398 @Override |
442 @Override |
399 public boolean enterIndexNode(final IndexNode indexNode) { |
443 public boolean enterIndexNode(final IndexNode indexNode) { |
400 if (!baseAlreadyOnStack) { |
444 if (!baseAlreadyOnStack) { |
401 load(indexNode.getBase()).convert(Type.OBJECT); |
445 load(indexNode.getBase()).convert(Type.OBJECT); |
402 load(indexNode.getIndex()); |
446 load(indexNode.getIndex()); |
403 } |
447 } |
404 method.dynamicGetIndex(node.getType(), getCallSiteFlags(), indexNode.isFunction()); |
448 method.dynamicGetIndex(type, getCallSiteFlags(), indexNode.isFunction()); |
405 return false; |
449 return false; |
406 } |
450 } |
407 |
451 |
408 @Override |
452 @Override |
409 public boolean enterFunctionNode(FunctionNode functionNode) { |
453 public boolean enterFunctionNode(FunctionNode functionNode) { |
410 // function nodes will always leave a constructed function object on stack, no need to load the symbol |
454 // function nodes will always leave a constructed function object on stack, no need to load the symbol |
411 // separately as in enterDefault() |
455 // separately as in enterDefault() |
412 functionNode.accept(codegen); |
456 functionNode.accept(codegen); |
|
457 method.convert(type); |
413 return false; |
458 return false; |
414 } |
459 } |
415 |
460 |
416 @Override |
461 @Override |
|
462 public boolean enterCallNode(CallNode callNode) { |
|
463 return codegen.enterCallNode(callNode, type); |
|
464 } |
|
465 |
|
466 @Override |
|
467 public boolean enterLiteralNode(LiteralNode<?> literalNode) { |
|
468 return codegen.enterLiteralNode(literalNode, type); |
|
469 } |
|
470 |
|
471 @Override |
417 public boolean enterDefault(final Node otherNode) { |
472 public boolean enterDefault(final Node otherNode) { |
|
473 final Node currentDiscard = codegen.lc.getCurrentDiscard(); |
418 otherNode.accept(codegen); // generate code for whatever we are looking at. |
474 otherNode.accept(codegen); // generate code for whatever we are looking at. |
419 method.load(symbol); // load the final symbol to the stack (or nop if no slot, then result is already there) |
475 if(currentDiscard != otherNode) { |
|
476 method.load(symbol); // load the final symbol to the stack (or nop if no slot, then result is already there) |
|
477 assert method.peekType() != null; |
|
478 method.convert(type); |
|
479 } |
420 return false; |
480 return false; |
421 } |
481 } |
422 }); |
482 }); |
423 |
483 |
424 return method; |
484 return method; |
581 } |
641 } |
582 |
642 |
583 return argCount; |
643 return argCount; |
584 } |
644 } |
585 |
645 |
|
646 |
586 @Override |
647 @Override |
587 public boolean enterCallNode(final CallNode callNode) { |
648 public boolean enterCallNode(final CallNode callNode) { |
|
649 return enterCallNode(callNode, callNode.getType()); |
|
650 } |
|
651 |
|
652 private boolean enterCallNode(final CallNode callNode, final Type callNodeType) { |
588 lineNumber(callNode.getLineNumber()); |
653 lineNumber(callNode.getLineNumber()); |
589 |
654 |
590 final List<Expression> args = callNode.getArgs(); |
655 final List<Expression> args = callNode.getArgs(); |
591 final Expression function = callNode.getFunction(); |
656 final Expression function = callNode.getFunction(); |
592 final Block currentBlock = lc.getCurrentBlock(); |
657 final Block currentBlock = lc.getCurrentBlock(); |
593 final CodeGeneratorLexicalContext codegenLexicalContext = lc; |
658 final CodeGeneratorLexicalContext codegenLexicalContext = lc; |
594 final Type callNodeType = callNode.getType(); |
|
595 |
659 |
596 function.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) { |
660 function.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) { |
597 |
661 |
598 private MethodEmitter sharedScopeCall(final IdentNode identNode, final int flags) { |
662 private MethodEmitter sharedScopeCall(final IdentNode identNode, final int flags) { |
599 final Symbol symbol = identNode.getSymbol(); |
663 final Symbol symbol = identNode.getSymbol(); |
610 final SharedScopeCall scopeCall = codegenLexicalContext.getScopeCall(unit, symbol, identNode.getType(), callNodeType, paramTypes, scopeCallFlags); |
674 final SharedScopeCall scopeCall = codegenLexicalContext.getScopeCall(unit, symbol, identNode.getType(), callNodeType, paramTypes, scopeCallFlags); |
611 return scopeCall.generateInvoke(method); |
675 return scopeCall.generateInvoke(method); |
612 } |
676 } |
613 |
677 |
614 private void scopeCall(final IdentNode node, final int flags) { |
678 private void scopeCall(final IdentNode node, final int flags) { |
615 load(node); |
679 load(node, Type.OBJECT); // Type.OBJECT as foo() makes no sense if foo == 3 |
616 method.convert(Type.OBJECT); // foo() makes no sense if foo == 3 |
|
617 // ScriptFunction will see CALLSITE_SCOPE and will bind scope accordingly. |
680 // ScriptFunction will see CALLSITE_SCOPE and will bind scope accordingly. |
618 method.loadNull(); //the 'this' |
681 method.loadNull(); //the 'this' |
619 method.dynamicCall(callNodeType, 2 + loadArgs(args), flags); |
682 method.dynamicCall(callNodeType, 2 + loadArgs(args), flags); |
620 } |
683 } |
621 |
684 |
622 private void evalCall(final IdentNode node, final int flags) { |
685 private void evalCall(final IdentNode node, final int flags) { |
623 load(node); |
686 load(node, Type.OBJECT); // Type.OBJECT as foo() makes no sense if foo == 3 |
624 method.convert(Type.OBJECT); // foo() makes no sense if foo == 3 |
|
625 |
687 |
626 final Label not_eval = new Label("not_eval"); |
688 final Label not_eval = new Label("not_eval"); |
627 final Label eval_done = new Label("eval_done"); |
689 final Label eval_done = new Label("eval_done"); |
628 |
690 |
629 // check if this is the real built-in eval |
691 // check if this is the real built-in eval |
636 |
698 |
637 method.loadCompilerConstant(SCOPE); // Load up self (scope). |
699 method.loadCompilerConstant(SCOPE); // Load up self (scope). |
638 |
700 |
639 final CallNode.EvalArgs evalArgs = callNode.getEvalArgs(); |
701 final CallNode.EvalArgs evalArgs = callNode.getEvalArgs(); |
640 // load evaluated code |
702 // load evaluated code |
641 load(evalArgs.getCode()); |
703 load(evalArgs.getCode(), Type.OBJECT); |
642 method.convert(Type.OBJECT); |
|
643 // special/extra 'eval' arguments |
704 // special/extra 'eval' arguments |
644 load(evalArgs.getThis()); |
705 load(evalArgs.getThis()); |
645 method.load(evalArgs.getLocation()); |
706 method.load(evalArgs.getLocation()); |
646 method.load(evalArgs.getStrictMode()); |
707 method.load(evalArgs.getStrictMode()); |
647 method.convert(Type.OBJECT); |
708 method.convert(Type.OBJECT); |
688 return false; |
749 return false; |
689 } |
750 } |
690 |
751 |
691 @Override |
752 @Override |
692 public boolean enterAccessNode(final AccessNode node) { |
753 public boolean enterAccessNode(final AccessNode node) { |
693 load(node.getBase()); |
754 load(node.getBase(), Type.OBJECT); |
694 method.convert(Type.OBJECT); |
|
695 method.dup(); |
755 method.dup(); |
696 method.dynamicGet(node.getType(), node.getProperty().getName(), getCallSiteFlags(), true); |
756 method.dynamicGet(node.getType(), node.getProperty().getName(), getCallSiteFlags(), true); |
697 method.swap(); |
757 method.swap(); |
698 method.dynamicCall(callNodeType, 2 + loadArgs(args), getCallSiteFlags()); |
758 method.dynamicCall(callNodeType, 2 + loadArgs(args), getCallSiteFlags()); |
699 assert method.peekType().equals(callNodeType); |
|
700 |
759 |
701 return false; |
760 return false; |
702 } |
761 } |
703 |
762 |
704 @Override |
763 @Override |
725 return false; |
784 return false; |
726 } |
785 } |
727 |
786 |
728 @Override |
787 @Override |
729 public boolean enterIndexNode(final IndexNode node) { |
788 public boolean enterIndexNode(final IndexNode node) { |
730 load(node.getBase()); |
789 load(node.getBase(), Type.OBJECT); |
731 method.convert(Type.OBJECT); |
|
732 method.dup(); |
790 method.dup(); |
733 load(node.getIndex()); |
|
734 final Type indexType = node.getIndex().getType(); |
791 final Type indexType = node.getIndex().getType(); |
735 if (indexType.isObject() || indexType.isBoolean()) { |
792 if (indexType.isObject() || indexType.isBoolean()) { |
736 method.convert(Type.OBJECT); //TODO |
793 load(node.getIndex(), Type.OBJECT); //TODO |
|
794 } else { |
|
795 load(node.getIndex()); |
737 } |
796 } |
738 method.dynamicGetIndex(node.getType(), getCallSiteFlags(), true); |
797 method.dynamicGetIndex(node.getType(), getCallSiteFlags(), true); |
739 method.swap(); |
798 method.swap(); |
740 method.dynamicCall(callNodeType, 2 + loadArgs(args), getCallSiteFlags()); |
799 method.dynamicCall(callNodeType, 2 + loadArgs(args), getCallSiteFlags()); |
741 assert method.peekType().equals(callNode.getType()); |
|
742 |
800 |
743 return false; |
801 return false; |
744 } |
802 } |
745 |
803 |
746 @Override |
804 @Override |
747 protected boolean enterDefault(final Node node) { |
805 protected boolean enterDefault(final Node node) { |
748 // Load up function. |
806 // Load up function. |
749 load(function); |
807 load(function, Type.OBJECT); //TODO, e.g. booleans can be used as functions |
750 method.convert(Type.OBJECT); //TODO, e.g. booleans can be used as functions |
|
751 method.loadNull(); // ScriptFunction will figure out the correct this when it sees CALLSITE_SCOPE |
808 method.loadNull(); // ScriptFunction will figure out the correct this when it sees CALLSITE_SCOPE |
752 method.dynamicCall(callNodeType, 2 + loadArgs(args), getCallSiteFlags() | CALLSITE_SCOPE); |
809 method.dynamicCall(callNodeType, 2 + loadArgs(args), getCallSiteFlags() | CALLSITE_SCOPE); |
753 assert method.peekType().equals(callNode.getType()); |
|
754 |
810 |
755 return false; |
811 return false; |
756 } |
812 } |
757 }); |
813 }); |
758 |
814 |
851 final Symbol iter = forNode.getIterator(); |
907 final Symbol iter = forNode.getIterator(); |
852 final Label loopLabel = new Label("loop"); |
908 final Label loopLabel = new Label("loop"); |
853 |
909 |
854 final Expression init = forNode.getInit(); |
910 final Expression init = forNode.getInit(); |
855 |
911 |
856 load(modify); |
912 load(modify, Type.OBJECT); |
857 assert modify.getType().isObject(); |
|
858 method.invoke(forNode.isForEach() ? ScriptRuntime.TO_VALUE_ITERATOR : ScriptRuntime.TO_PROPERTY_ITERATOR); |
913 method.invoke(forNode.isForEach() ? ScriptRuntime.TO_VALUE_ITERATOR : ScriptRuntime.TO_PROPERTY_ITERATOR); |
859 method.store(iter); |
914 method.store(iter); |
860 method._goto(forNode.getContinueLabel()); |
915 method._goto(forNode.getContinueLabel()); |
861 method.label(loopLabel); |
916 method.label(loopLabel); |
862 |
917 |
1292 } else if (value instanceof RegexToken) { |
1346 } else if (value instanceof RegexToken) { |
1293 loadRegex((RegexToken)value); |
1347 loadRegex((RegexToken)value); |
1294 } else if (value instanceof Boolean) { |
1348 } else if (value instanceof Boolean) { |
1295 method.load((Boolean)value); |
1349 method.load((Boolean)value); |
1296 } else if (value instanceof Integer) { |
1350 } else if (value instanceof Integer) { |
1297 method.load((Integer)value); |
1351 if(type.isEquivalentTo(Type.NUMBER)) { |
|
1352 method.load(((Integer)value).doubleValue()); |
|
1353 } else if(type.isEquivalentTo(Type.LONG)) { |
|
1354 method.load(((Integer)value).longValue()); |
|
1355 } else { |
|
1356 method.load((Integer)value); |
|
1357 } |
1298 } else if (value instanceof Long) { |
1358 } else if (value instanceof Long) { |
1299 method.load((Long)value); |
1359 if(type.isEquivalentTo(Type.NUMBER)) { |
|
1360 method.load(((Long)value).doubleValue()); |
|
1361 } else { |
|
1362 method.load((Long)value); |
|
1363 } |
1300 } else if (value instanceof Double) { |
1364 } else if (value instanceof Double) { |
1301 method.load((Double)value); |
1365 method.load((Double)value); |
1302 } else if (node instanceof ArrayLiteralNode) { |
1366 } else if (node instanceof ArrayLiteralNode) { |
1303 final ArrayType type = (ArrayType)node.getType(); |
1367 final ArrayLiteralNode arrayLiteral = (ArrayLiteralNode)node; |
1304 loadArray((ArrayLiteralNode)node, type); |
1368 final ArrayType atype = arrayLiteral.getArrayType(); |
1305 globalAllocateArray(type); |
1369 loadArray(arrayLiteral, atype); |
|
1370 globalAllocateArray(atype); |
1306 } else { |
1371 } else { |
1307 assert false : "Unknown literal for " + node.getClass() + " " + value.getClass() + " " + value; |
1372 assert false : "Unknown literal for " + node.getClass() + " " + value.getClass() + " " + value; |
1308 } |
1373 } |
1309 |
1374 |
1310 return method; |
1375 return method; |
1620 return enterCmp(lhs, rhs, Condition.GE, type, symbol); |
1689 return enterCmp(lhs, rhs, Condition.GE, type, symbol); |
1621 case GT: |
1690 case GT: |
1622 return enterCmp(lhs, rhs, Condition.GT, type, symbol); |
1691 return enterCmp(lhs, rhs, Condition.GT, type, symbol); |
1623 case ADD: |
1692 case ADD: |
1624 Type widest = Type.widest(lhs.getType(), rhs.getType()); |
1693 Type widest = Type.widest(lhs.getType(), rhs.getType()); |
1625 load(lhs); |
1694 load(lhs, widest); |
1626 method.convert(widest); |
1695 load(rhs, widest); |
1627 load(rhs); |
|
1628 method.convert(widest); |
|
1629 method.add(); |
1696 method.add(); |
1630 method.convert(type); |
1697 method.convert(type); |
1631 method.store(symbol); |
1698 method.store(symbol); |
1632 return false; |
1699 return false; |
1633 default: |
1700 default: |
1636 break; |
1703 break; |
1637 } |
1704 } |
1638 } |
1705 } |
1639 |
1706 |
1640 if (nullCheck(runtimeNode, args, new FunctionSignature(false, false, runtimeNode.getType(), args).toString())) { |
1707 if (nullCheck(runtimeNode, args, new FunctionSignature(false, false, runtimeNode.getType(), args).toString())) { |
1641 return false; |
1708 return false; |
1642 } |
1709 } |
1643 |
1710 |
1644 if (!runtimeNode.isFinal() && specializationCheck(runtimeNode.getRequest(), runtimeNode, args)) { |
1711 if (!runtimeNode.isFinal() && specializationCheck(runtimeNode.getRequest(), runtimeNode, args)) { |
1645 return false; |
1712 return false; |
1646 } |
1713 } |
1647 |
1714 |
1648 for (final Expression arg : args) { |
1715 for (final Expression arg : args) { |
1649 load(arg).convert(Type.OBJECT); //TODO this should not be necessary below Lower |
1716 load(arg).convert(Type.OBJECT); |
1650 } |
1717 } |
1651 |
1718 |
1652 method.invokestatic( |
1719 method.invokestatic( |
1653 CompilerConstants.className(ScriptRuntime.class), |
1720 CompilerConstants.className(ScriptRuntime.class), |
1654 runtimeNode.getRequest().toString(), |
1721 runtimeNode.getRequest().toString(), |
1901 } |
1968 } |
1902 |
1969 |
1903 method.lookupswitch(defaultLabel, ints, labels); |
1970 method.lookupswitch(defaultLabel, ints, labels); |
1904 } |
1971 } |
1905 } else { |
1972 } else { |
1906 load(expression); |
1973 load(expression, Type.OBJECT); |
1907 |
1974 method.store(tag); |
1908 if (expression.getType().isInteger()) { |
|
1909 method.convert(Type.NUMBER).dup(); |
|
1910 method.store(tag); |
|
1911 method.conditionalJump(Condition.NE, true, defaultLabel); |
|
1912 } else { |
|
1913 assert tag.getSymbolType().isObject(); |
|
1914 method.convert(Type.OBJECT); //e.g. 1 literal pushed and tag is object |
|
1915 method.store(tag); |
|
1916 } |
|
1917 |
1975 |
1918 for (final CaseNode caseNode : cases) { |
1976 for (final CaseNode caseNode : cases) { |
1919 final Expression test = caseNode.getTest(); |
1977 final Expression test = caseNode.getTest(); |
1920 |
1978 |
1921 if (test != null) { |
1979 if (test != null) { |
1922 method.load(tag); |
1980 method.load(tag); |
1923 load(test); |
1981 load(test, Type.OBJECT); |
1924 method.invoke(ScriptRuntime.EQ_STRICT); |
1982 method.invoke(ScriptRuntime.EQ_STRICT); |
1925 method.ifne(caseNode.getEntry()); |
1983 method.ifne(caseNode.getEntry()); |
1926 } |
1984 } |
1927 } |
1985 } |
1928 |
1986 |
1959 final Expression expression = throwNode.getExpression(); |
2017 final Expression expression = throwNode.getExpression(); |
1960 final int position = throwNode.position(); |
2018 final int position = throwNode.position(); |
1961 final int line = throwNode.getLineNumber(); |
2019 final int line = throwNode.getLineNumber(); |
1962 final int column = source.getColumn(position); |
2020 final int column = source.getColumn(position); |
1963 |
2021 |
1964 load(expression); |
2022 load(expression, Type.OBJECT); |
1965 assert expression.getType().isObject(); |
|
1966 |
2023 |
1967 method.load(source.getName()); |
2024 method.load(source.getName()); |
1968 method.load(line); |
2025 method.load(line); |
1969 method.load(column); |
2026 method.load(column); |
1970 method.invoke(ECMAException.THROW_INIT); |
2027 method.invoke(ECMAException.THROW_INIT); |
2085 return false; |
2142 return false; |
2086 } |
2143 } |
2087 |
2144 |
2088 lineNumber(varNode); |
2145 lineNumber(varNode); |
2089 |
2146 |
2090 final Symbol varSymbol = varNode.getName().getSymbol(); |
2147 final IdentNode identNode = varNode.getName(); |
2091 assert varSymbol != null : "variable node " + varNode + " requires a name with a symbol"; |
2148 final Symbol identSymbol = identNode.getSymbol(); |
|
2149 assert identSymbol != null : "variable node " + varNode + " requires a name with a symbol"; |
2092 |
2150 |
2093 assert method != null; |
2151 assert method != null; |
2094 |
2152 |
2095 final boolean needsScope = varSymbol.isScope(); |
2153 final boolean needsScope = identSymbol.isScope(); |
2096 if (needsScope) { |
2154 if (needsScope) { |
2097 method.loadCompilerConstant(SCOPE); |
2155 method.loadCompilerConstant(SCOPE); |
2098 } |
2156 } |
2099 load(init); |
|
2100 |
2157 |
2101 if (needsScope) { |
2158 if (needsScope) { |
|
2159 load(init); |
2102 int flags = CALLSITE_SCOPE | getCallSiteFlags(); |
2160 int flags = CALLSITE_SCOPE | getCallSiteFlags(); |
2103 final IdentNode identNode = varNode.getName(); |
2161 if (isFastScope(identSymbol)) { |
2104 final Type type = identNode.getType(); |
2162 storeFastScopeVar(identSymbol, flags); |
2105 if (isFastScope(varSymbol)) { |
|
2106 storeFastScopeVar(type, varSymbol, flags); |
|
2107 } else { |
2163 } else { |
2108 method.dynamicSet(type, identNode.getName(), flags); |
2164 method.dynamicSet(identNode.getName(), flags); |
2109 } |
2165 } |
2110 } else { |
2166 } else { |
2111 method.convert(varNode.getName().getType()); // aw: convert moved here |
2167 load(init, identNode.getType()); |
2112 method.store(varSymbol); |
2168 method.store(identSymbol); |
2113 } |
2169 } |
2114 |
2170 |
2115 return false; |
2171 return false; |
2116 } |
2172 } |
2117 |
2173 |
2209 return false; |
2264 return false; |
2210 } |
2265 } |
2211 |
2266 |
2212 @Override |
2267 @Override |
2213 public boolean enterADD(final UnaryNode unaryNode) { |
2268 public boolean enterADD(final UnaryNode unaryNode) { |
2214 load(unaryNode.rhs()); |
2269 load(unaryNode.rhs(), unaryNode.getType()); |
2215 assert unaryNode.rhs().getType().isNumber() : unaryNode.rhs().getType() + " "+ unaryNode.getSymbol(); |
2270 assert unaryNode.getType().isNumeric(); |
2216 method.store(unaryNode.getSymbol()); |
2271 method.store(unaryNode.getSymbol()); |
2217 |
|
2218 return false; |
2272 return false; |
2219 } |
2273 } |
2220 |
2274 |
2221 @Override |
2275 @Override |
2222 public boolean enterBIT_NOT(final UnaryNode unaryNode) { |
2276 public boolean enterBIT_NOT(final UnaryNode unaryNode) { |
2223 load(unaryNode.rhs()).convert(Type.INT).load(-1).xor().store(unaryNode.getSymbol()); |
2277 load(unaryNode.rhs(), Type.INT).load(-1).xor().store(unaryNode.getSymbol()); |
2224 return false; |
|
2225 } |
|
2226 |
|
2227 // do this better with convert calls to method. TODO |
|
2228 @Override |
|
2229 public boolean enterCONVERT(final UnaryNode unaryNode) { |
|
2230 final Expression rhs = unaryNode.rhs(); |
|
2231 final Type to = unaryNode.getType(); |
|
2232 |
|
2233 if (to.isObject() && rhs instanceof LiteralNode) { |
|
2234 final LiteralNode<?> literalNode = (LiteralNode<?>)rhs; |
|
2235 final Object value = literalNode.getValue(); |
|
2236 |
|
2237 if (value instanceof Number) { |
|
2238 assert !to.isArray() : "type hygiene - cannot convert number to array: (" + to.getTypeClass().getSimpleName() + ')' + value; |
|
2239 if (value instanceof Integer) { |
|
2240 method.load((Integer)value); |
|
2241 } else if (value instanceof Long) { |
|
2242 method.load((Long)value); |
|
2243 } else if (value instanceof Double) { |
|
2244 method.load((Double)value); |
|
2245 } else { |
|
2246 assert false; |
|
2247 } |
|
2248 method.convert(Type.OBJECT); |
|
2249 } else if (value instanceof Boolean) { |
|
2250 method.getField(staticField(Boolean.class, value.toString().toUpperCase(Locale.ENGLISH), Boolean.class)); |
|
2251 } else { |
|
2252 load(rhs); |
|
2253 method.convert(unaryNode.getType()); |
|
2254 } |
|
2255 } else { |
|
2256 load(rhs); |
|
2257 method.convert(unaryNode.getType()); |
|
2258 } |
|
2259 |
|
2260 method.store(unaryNode.getSymbol()); |
|
2261 |
|
2262 return false; |
2278 return false; |
2263 } |
2279 } |
2264 |
2280 |
2265 @Override |
2281 @Override |
2266 public boolean enterDECINC(final UnaryNode unaryNode) { |
2282 public boolean enterDECINC(final UnaryNode unaryNode) { |
2274 |
2290 |
2275 new SelfModifyingStore<UnaryNode>(unaryNode, rhs) { |
2291 new SelfModifyingStore<UnaryNode>(unaryNode, rhs) { |
2276 |
2292 |
2277 @Override |
2293 @Override |
2278 protected void evaluate() { |
2294 protected void evaluate() { |
2279 load(rhs, true); |
2295 load(rhs, type, true); |
2280 |
|
2281 method.convert(type); |
|
2282 if (!isPostfix) { |
2296 if (!isPostfix) { |
2283 if (type.isInteger()) { |
2297 if (type.isInteger()) { |
2284 method.load(isIncrement ? 1 : -1); |
2298 method.load(isIncrement ? 1 : -1); |
2285 } else if (type.isLong()) { |
2299 } else if (type.isLong()) { |
2286 method.load(isIncrement ? 1L : -1L); |
2300 method.load(isIncrement ? 1L : -1L); |
2342 |
2356 |
2343 @Override |
2357 @Override |
2344 public boolean enterNOT(final UnaryNode unaryNode) { |
2358 public boolean enterNOT(final UnaryNode unaryNode) { |
2345 final Expression rhs = unaryNode.rhs(); |
2359 final Expression rhs = unaryNode.rhs(); |
2346 |
2360 |
2347 load(rhs); |
2361 load(rhs, Type.BOOLEAN); |
2348 |
2362 |
2349 final Label trueLabel = new Label("true"); |
2363 final Label trueLabel = new Label("true"); |
2350 final Label afterLabel = new Label("after"); |
2364 final Label afterLabel = new Label("after"); |
2351 |
2365 |
2352 method.convert(Type.BOOLEAN); |
|
2353 method.ifne(trueLabel); |
2366 method.ifne(trueLabel); |
2354 method.load(true); |
2367 method.load(true); |
2355 method._goto(afterLabel); |
2368 method._goto(afterLabel); |
2356 method.label(trueLabel); |
2369 method.label(trueLabel); |
2357 method.load(false); |
2370 method.load(false); |
2375 |
2388 |
2376 return false; |
2389 return false; |
2377 } |
2390 } |
2378 |
2391 |
2379 private void enterNumericAdd(final Expression lhs, final Expression rhs, final Type type, final Symbol symbol) { |
2392 private void enterNumericAdd(final Expression lhs, final Expression rhs, final Type type, final Symbol symbol) { |
2380 assert lhs.getType().equals(rhs.getType()) && lhs.getType().equals(type) : lhs.getType() + " != " + rhs.getType() + " != " + type + " " + new ASTWriter(lhs) + " " + new ASTWriter(rhs); |
2393 loadBinaryOperands(lhs, rhs, type); |
2381 load(lhs); |
|
2382 load(rhs); |
|
2383 method.add(); //if the symbol is optimistic, it always needs to be written, not on the stack? |
2394 method.add(); //if the symbol is optimistic, it always needs to be written, not on the stack? |
2384 method.store(symbol); |
2395 method.store(symbol); |
2385 } |
2396 } |
2386 |
2397 |
2387 @Override |
2398 @Override |
2437 final Type lhsType = lhs.getType(); |
2447 final Type lhsType = lhs.getType(); |
2438 final Type rhsType = rhs.getType(); |
2448 final Type rhsType = rhs.getType(); |
2439 |
2449 |
2440 if (!lhsType.isEquivalentTo(rhsType)) { |
2450 if (!lhsType.isEquivalentTo(rhsType)) { |
2441 //this is OK if scoped, only locals are wrong |
2451 //this is OK if scoped, only locals are wrong |
2442 assert !(lhs instanceof IdentNode) || lhs.getSymbol().isScope() : new ASTWriter(binaryNode); |
|
2443 } |
2452 } |
2444 |
2453 |
2445 new Store<BinaryNode>(binaryNode, lhs) { |
2454 new Store<BinaryNode>(binaryNode, lhs) { |
2446 @Override |
2455 @Override |
2447 protected void evaluate() { |
2456 protected void evaluate() { |
2448 load(rhs); |
2457 if ((lhs instanceof IdentNode) && !lhs.getSymbol().isScope()) { |
|
2458 load(rhs, lhsType); |
|
2459 } else { |
|
2460 load(rhs); |
|
2461 } |
2449 } |
2462 } |
2450 }.store(); |
2463 }.store(); |
2451 |
2464 |
2452 return false; |
2465 return false; |
2453 } |
2466 } |
2737 final Type rhsType = rhs.getType(); |
2748 final Type rhsType = rhs.getType(); |
2738 |
2749 |
2739 final Type widest = Type.widest(lhsType, rhsType); |
2750 final Type widest = Type.widest(lhsType, rhsType); |
2740 assert widest.isNumeric() || widest.isBoolean() : widest; |
2751 assert widest.isNumeric() || widest.isBoolean() : widest; |
2741 |
2752 |
2742 load(lhs); |
2753 loadBinaryOperands(lhs, rhs, widest); |
2743 method.convert(widest); |
|
2744 load(rhs); |
|
2745 method.convert(widest); |
|
2746 |
|
2747 final Label trueLabel = new Label("trueLabel"); |
2754 final Label trueLabel = new Label("trueLabel"); |
2748 final Label afterLabel = new Label("skip"); |
2755 final Label afterLabel = new Label("skip"); |
2749 |
2756 |
2750 method.conditionalJump(cond, trueLabel); |
2757 method.conditionalJump(cond, trueLabel); |
2751 |
2758 |
2896 Type widest = Type.widest(ternaryNode.getType(), Type.widest(trueExpr.getType(), falseExpr.getType())); |
2909 Type widest = Type.widest(ternaryNode.getType(), Type.widest(trueExpr.getType(), falseExpr.getType())); |
2897 if (trueExpr.getType().isArray() || falseExpr.getType().isArray()) { //loadArray creates a Java array type on the stack, calls global allocate, which creates a native array type |
2910 if (trueExpr.getType().isArray() || falseExpr.getType().isArray()) { //loadArray creates a Java array type on the stack, calls global allocate, which creates a native array type |
2898 widest = Type.OBJECT; |
2911 widest = Type.OBJECT; |
2899 } |
2912 } |
2900 |
2913 |
2901 load(test); |
2914 load(test, Type.BOOLEAN); |
2902 assert test.getType().isBoolean() : "lhs in ternary must be boolean"; |
|
2903 |
|
2904 // we still keep the conversion here as the AccessSpecializer can have separated the types, e.g. var y = x ? x=55 : 17 |
2915 // we still keep the conversion here as the AccessSpecializer can have separated the types, e.g. var y = x ? x=55 : 17 |
2905 // will left as (Object)x=55 : (Object)17 by Lower. Then the first term can be {I}x=55 of type int, which breaks the |
2916 // will left as (Object)x=55 : (Object)17 by Lower. Then the first term can be {I}x=55 of type int, which breaks the |
2906 // symmetry for the temporary slot for this TernaryNode. This is evidence that we assign types and explicit conversions |
2917 // symmetry for the temporary slot for this TernaryNode. This is evidence that we assign types and explicit conversions |
2907 // too early, or Apply the AccessSpecializer too late. We are mostly probably looking for a separate type pass to |
2918 // too early, or Apply the AccessSpecializer too late. We are mostly probably looking for a separate type pass to |
2908 // do this property. Then we never need any conversions in CodeGenerator |
2919 // do this property. Then we never need any conversions in CodeGenerator |
2909 method.ifeq(falseLabel); |
2920 method.ifeq(falseLabel); |
2910 load(trueExpr); |
2921 load(trueExpr, widest); |
2911 method.convert(widest); |
|
2912 method._goto(exitLabel); |
2922 method._goto(exitLabel); |
2913 method.label(falseLabel); |
2923 method.label(falseLabel); |
2914 load(falseExpr); |
2924 load(falseExpr, widest); |
2915 method.convert(widest); |
|
2916 method.label(exitLabel); |
2925 method.label(exitLabel); |
2917 method.store(symbol); |
2926 method.store(symbol); |
2918 |
2927 |
2919 return false; |
2928 return false; |
2920 } |
2929 } |
3042 private void enterBaseNode() { |
3051 private void enterBaseNode() { |
3043 assert target instanceof BaseNode : "error - base node " + target + " must be instanceof BaseNode"; |
3052 assert target instanceof BaseNode : "error - base node " + target + " must be instanceof BaseNode"; |
3044 final BaseNode baseNode = (BaseNode)target; |
3053 final BaseNode baseNode = (BaseNode)target; |
3045 final Expression base = baseNode.getBase(); |
3054 final Expression base = baseNode.getBase(); |
3046 |
3055 |
3047 load(base); |
3056 load(base, Type.OBJECT); |
3048 method.convert(Type.OBJECT); |
|
3049 depth += Type.OBJECT.getSlots(); |
3057 depth += Type.OBJECT.getSlots(); |
3050 |
3058 |
3051 if (isSelfModifying()) { |
3059 if (isSelfModifying()) { |
3052 method.dup(); |
3060 method.dup(); |
3053 } |
3061 } |
3062 @Override |
3070 @Override |
3063 public boolean enterIndexNode(final IndexNode node) { |
3071 public boolean enterIndexNode(final IndexNode node) { |
3064 enterBaseNode(); |
3072 enterBaseNode(); |
3065 |
3073 |
3066 final Expression index = node.getIndex(); |
3074 final Expression index = node.getIndex(); |
3067 // could be boolean here as well |
|
3068 load(index); |
|
3069 if (!index.getType().isNumeric()) { |
3075 if (!index.getType().isNumeric()) { |
3070 method.convert(Type.OBJECT); |
3076 // could be boolean here as well |
|
3077 load(index, Type.OBJECT); |
|
3078 } else { |
|
3079 load(index); |
3071 } |
3080 } |
3072 depth += index.getType().getSlots(); |
3081 depth += index.getType().getSlots(); |
3073 |
3082 |
3074 if (isSelfModifying()) { |
3083 if (isSelfModifying()) { |
3075 //convert "base base index" to "base index base index" |
3084 //convert "base base index" to "base index base index" |
3134 * |
3143 * |
3135 * The case that targetSymbol is in scope (!hasSlot) and we actually |
3144 * The case that targetSymbol is in scope (!hasSlot) and we actually |
3136 * need to do a conversion on non-equivalent types exists, but is |
3145 * need to do a conversion on non-equivalent types exists, but is |
3137 * very rare. See for example test/script/basic/access-specializer.js |
3146 * very rare. See for example test/script/basic/access-specializer.js |
3138 */ |
3147 */ |
3139 method.convert(target.getType()); |
|
3140 |
|
3141 target.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) { |
3148 target.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) { |
3142 @Override |
3149 @Override |
3143 protected boolean enterDefault(Node node) { |
3150 protected boolean enterDefault(Node node) { |
3144 throw new AssertionError("Unexpected node " + node + " in store epilogue"); |
3151 throw new AssertionError("Unexpected node " + node + " in store epilogue"); |
3145 } |
|
3146 |
|
3147 @Override |
|
3148 public boolean enterUnaryNode(final UnaryNode node) { |
|
3149 if (node.tokenType() == TokenType.CONVERT && node.getSymbol() != null) { |
|
3150 method.convert(node.rhs().getType()); |
|
3151 } |
|
3152 return true; |
|
3153 } |
3152 } |
3154 |
3153 |
3155 @Override |
3154 @Override |
3156 public boolean enterIdentNode(final IdentNode node) { |
3155 public boolean enterIdentNode(final IdentNode node) { |
3157 final Symbol symbol = node.getSymbol(); |
3156 final Symbol symbol = node.getSymbol(); |
3158 assert symbol != null; |
3157 assert symbol != null; |
3159 if (symbol.isScope()) { |
3158 if (symbol.isScope()) { |
3160 if (isFastScope(symbol)) { |
3159 if (isFastScope(symbol)) { |
3161 storeFastScopeVar(node.getType(), symbol, CALLSITE_SCOPE | getCallSiteFlags()); |
3160 storeFastScopeVar(symbol, CALLSITE_SCOPE | getCallSiteFlags()); |
3162 } else { |
3161 } else { |
3163 method.dynamicSet(node.getType(), node.getName(), CALLSITE_SCOPE | getCallSiteFlags()); |
3162 method.dynamicSet(node.getName(), CALLSITE_SCOPE | getCallSiteFlags()); |
3164 } |
3163 } |
3165 } else { |
3164 } else { |
|
3165 method.convert(node.getType()); |
3166 method.store(symbol); |
3166 method.store(symbol); |
3167 } |
3167 } |
3168 return false; |
3168 return false; |
3169 |
3169 |
3170 } |
3170 } |
3171 |
3171 |
3172 @Override |
3172 @Override |
3173 public boolean enterAccessNode(final AccessNode node) { |
3173 public boolean enterAccessNode(final AccessNode node) { |
3174 method.dynamicSet(node.getProperty().getType(), node.getProperty().getName(), getCallSiteFlags()); |
3174 method.dynamicSet(node.getProperty().getName(), getCallSiteFlags()); |
3175 return false; |
3175 return false; |
3176 } |
3176 } |
3177 |
3177 |
3178 @Override |
3178 @Override |
3179 public boolean enterIndexNode(final IndexNode node) { |
3179 public boolean enterIndexNode(final IndexNode node) { |