src/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java

Mon, 03 Nov 2014 11:47:41 +0100

author
lagergren
date
Mon, 03 Nov 2014 11:47:41 +0100
changeset 1082
e1e27c4262be
parent 1004
698280da463a
child 1205
4112748288bb
child 1226
8b3f832bea55
permissions
-rw-r--r--

8060204: Fix warnings in Joni and tests
Reviewed-by: hannesw, sundar, attila

     1 /*
     2  * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package jdk.nashorn.internal.codegen;
    28 import java.util.ArrayDeque;
    29 import java.util.Collection;
    30 import java.util.Collections;
    31 import java.util.Deque;
    32 import java.util.HashMap;
    33 import java.util.Map;
    34 import jdk.nashorn.internal.IntDeque;
    35 import jdk.nashorn.internal.codegen.types.Type;
    36 import jdk.nashorn.internal.ir.Block;
    37 import jdk.nashorn.internal.ir.FunctionNode;
    38 import jdk.nashorn.internal.ir.LexicalContext;
    39 import jdk.nashorn.internal.ir.LexicalContextNode;
    40 import jdk.nashorn.internal.ir.Node;
    41 import jdk.nashorn.internal.ir.Symbol;
    42 import jdk.nashorn.internal.ir.WithNode;
    44 /**
    45  * A lexical context that also tracks if we have any dynamic scopes in the context. Such scopes can have new
    46  * variables introduced into them at run time - a with block or a function directly containing an eval call.
    47  * Furthermore, this class keeps track of current discard state, which the current method emitter being used is,
    48  * the current compile unit, and local variable indexes
    49  */
    50 final class CodeGeneratorLexicalContext extends LexicalContext {
    51     private int dynamicScopeCount;
    53     /** Map of shared scope call sites */
    54     private final Map<SharedScopeCall, SharedScopeCall> scopeCalls = new HashMap<>();
    56     /** Compile unit stack - every time we start a sub method (e.g. a split) we push one */
    57     private final Deque<CompileUnit> compileUnits = new ArrayDeque<>();
    59     /** Method emitter stack - every time we start a sub method (e.g. a split) we push one */
    60     private final Deque<MethodEmitter> methodEmitters = new ArrayDeque<>();
    62     /** The discard stack - whenever we enter a discard node we keep track of its return value status -
    63      *  i.e. should we keep it or throw it away */
    64     private final Deque<Node> discard = new ArrayDeque<>();
    66     private final Deque<Map<String, Collection<Label>>> unwarrantedOptimismHandlers = new ArrayDeque<>();
    67     private final Deque<StringBuilder> slotTypesDescriptors = new ArrayDeque<>();
    68     private final IntDeque splitNodes = new IntDeque();
    70     /** A stack tracking the next free local variable slot in the blocks. There's one entry for every block
    71      *  currently on the lexical context stack. */
    72     private int[] nextFreeSlots = new int[16];
    74     /** size of next free slot vector */
    75     private int nextFreeSlotsSize;
    77     private boolean isWithBoundary(final LexicalContextNode node) {
    78         return node instanceof Block && !isEmpty() && peek() instanceof WithNode;
    79     }
    81     @Override
    82     public <T extends LexicalContextNode> T push(final T node) {
    83         if (isWithBoundary(node)) {
    84             dynamicScopeCount++;
    85         } else if (node instanceof FunctionNode) {
    86             if (((FunctionNode)node).inDynamicContext()) {
    87                 dynamicScopeCount++;
    88             }
    89             splitNodes.push(0);
    90         }
    91         return super.push(node);
    92     }
    94     void enterSplitNode() {
    95         splitNodes.getAndIncrement();
    96         pushFreeSlots(methodEmitters.peek().getUsedSlotsWithLiveTemporaries());
    97     }
    99     void exitSplitNode() {
   100         final int count = splitNodes.decrementAndGet();
   101         assert count >= 0;
   102     }
   104     @Override
   105     public <T extends LexicalContextNode> T pop(final T node) {
   106         final T popped = super.pop(node);
   107         if (isWithBoundary(node)) {
   108             dynamicScopeCount--;
   109             assert dynamicScopeCount >= 0;
   110         } else if (node instanceof FunctionNode) {
   111             if (((FunctionNode)node).inDynamicContext()) {
   112                 dynamicScopeCount--;
   113                 assert dynamicScopeCount >= 0;
   114             }
   115             assert splitNodes.peek() == 0;
   116             splitNodes.pop();
   117         }
   118         return popped;
   119     }
   121     boolean inDynamicScope() {
   122         return dynamicScopeCount > 0;
   123     }
   125     boolean inSplitNode() {
   126         return !splitNodes.isEmpty() && splitNodes.peek() > 0;
   127     }
   129     MethodEmitter pushMethodEmitter(final MethodEmitter newMethod) {
   130         methodEmitters.push(newMethod);
   131         return newMethod;
   132     }
   134     MethodEmitter popMethodEmitter(final MethodEmitter oldMethod) {
   135         assert methodEmitters.peek() == oldMethod;
   136         methodEmitters.pop();
   137         return methodEmitters.isEmpty() ? null : methodEmitters.peek();
   138     }
   140     void pushUnwarrantedOptimismHandlers() {
   141         unwarrantedOptimismHandlers.push(new HashMap<String, Collection<Label>>());
   142         slotTypesDescriptors.push(new StringBuilder());
   143     }
   145     Map<String, Collection<Label>> getUnwarrantedOptimismHandlers() {
   146         return unwarrantedOptimismHandlers.peek();
   147     }
   149     Map<String, Collection<Label>> popUnwarrantedOptimismHandlers() {
   150         slotTypesDescriptors.pop();
   151         return unwarrantedOptimismHandlers.pop();
   152     }
   154     CompileUnit pushCompileUnit(final CompileUnit newUnit) {
   155         compileUnits.push(newUnit);
   156         return newUnit;
   157     }
   159     CompileUnit popCompileUnit(final CompileUnit oldUnit) {
   160         assert compileUnits.peek() == oldUnit;
   161         final CompileUnit unit = compileUnits.pop();
   162         assert unit.hasCode() : "compile unit popped without code";
   163         unit.setUsed();
   164         return compileUnits.isEmpty() ? null : compileUnits.peek();
   165     }
   167     boolean hasCompileUnits() {
   168         return !compileUnits.isEmpty();
   169     }
   171     Collection<SharedScopeCall> getScopeCalls() {
   172         return Collections.unmodifiableCollection(scopeCalls.values());
   173     }
   175     /**
   176      * Get a shared static method representing a dynamic scope callsite.
   177      *
   178      * @param unit current compile unit
   179      * @param symbol the symbol
   180      * @param valueType the value type of the symbol
   181      * @param returnType the return type
   182      * @param paramTypes the parameter types
   183      * @param flags the callsite flags
   184      * @return an object representing a shared scope call
   185      */
   186     SharedScopeCall getScopeCall(final CompileUnit unit, final Symbol symbol, final Type valueType, final Type returnType, final Type[] paramTypes, final int flags) {
   187         final SharedScopeCall scopeCall = new SharedScopeCall(symbol, valueType, returnType, paramTypes, flags);
   188         if (scopeCalls.containsKey(scopeCall)) {
   189             return scopeCalls.get(scopeCall);
   190         }
   191         scopeCall.setClassAndName(unit, getCurrentFunction().uniqueName(":scopeCall"));
   192         scopeCalls.put(scopeCall, scopeCall);
   193         return scopeCall;
   194     }
   196     /**
   197      * Get a shared static method representing a dynamic scope get access.
   198      *
   199      * @param unit current compile unit
   200      * @param symbol the symbol
   201      * @param valueType the type of the variable
   202      * @param flags the callsite flags
   203      * @return an object representing a shared scope call
   204      */
   205     SharedScopeCall getScopeGet(final CompileUnit unit, final Symbol symbol, final Type valueType, final int flags) {
   206         return getScopeCall(unit, symbol, valueType, valueType, null, flags);
   207     }
   209     void onEnterBlock(final Block block) {
   210         pushFreeSlots(assignSlots(block, isFunctionBody() ? 0 : getUsedSlotCount()));
   211     }
   213     private void pushFreeSlots(final int freeSlots) {
   214         if (nextFreeSlotsSize == nextFreeSlots.length) {
   215             final int[] newNextFreeSlots = new int[nextFreeSlotsSize * 2];
   216             System.arraycopy(nextFreeSlots, 0, newNextFreeSlots, 0, nextFreeSlotsSize);
   217             nextFreeSlots = newNextFreeSlots;
   218         }
   219         nextFreeSlots[nextFreeSlotsSize++] = freeSlots;
   220     }
   222     int getUsedSlotCount() {
   223         return nextFreeSlots[nextFreeSlotsSize - 1];
   224     }
   226     void releaseSlots() {
   227         --nextFreeSlotsSize;
   228         final int undefinedFromSlot = nextFreeSlotsSize == 0 ? 0 : nextFreeSlots[nextFreeSlotsSize - 1];
   229         if(!slotTypesDescriptors.isEmpty()) {
   230             slotTypesDescriptors.peek().setLength(undefinedFromSlot);
   231         }
   232         methodEmitters.peek().undefineLocalVariables(undefinedFromSlot, false);
   233     }
   235     private int assignSlots(final Block block, final int firstSlot) {
   236         int fromSlot = firstSlot;
   237         final MethodEmitter method = methodEmitters.peek();
   238         for (final Symbol symbol : block.getSymbols()) {
   239             if (symbol.hasSlot()) {
   240                 symbol.setFirstSlot(fromSlot);
   241                 final int toSlot = fromSlot + symbol.slotCount();
   242                 method.defineBlockLocalVariable(fromSlot, toSlot);
   243                 fromSlot = toSlot;
   244             }
   245         }
   246         return fromSlot;
   247     }
   249     static Type getTypeForSlotDescriptor(final char typeDesc) {
   250         // Recognizing both lowercase and uppercase as we're using both to signify symbol boundaries; see
   251         // MethodEmitter.markSymbolBoundariesInLvarTypesDescriptor().
   252         switch (typeDesc) {
   253             case 'I':
   254             case 'i':
   255                 return Type.INT;
   256             case 'J':
   257             case 'j':
   258                 return Type.LONG;
   259             case 'D':
   260             case 'd':
   261                 return Type.NUMBER;
   262             case 'A':
   263             case 'a':
   264                 return Type.OBJECT;
   265             case 'U':
   266             case 'u':
   267                 return Type.UNKNOWN;
   268             default:
   269                 throw new AssertionError();
   270         }
   271     }
   273     void pushDiscard(final Node node) {
   274         discard.push(node);
   275     }
   277     Node popDiscard() {
   278         return discard.pop();
   279     }
   281     Node getCurrentDiscard() {
   282         return discard.peek();
   283     }
   285     int quickSlot(final Type type) {
   286         return methodEmitters.peek().defineTemporaryLocalVariable(type.getSlots());
   287     }
   288 }

mercurial