rt/vm/src/main/java/org/apidesign/vm4brwsr/StackMapper.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Wed, 07 May 2014 10:01:54 +0200
branchclosure
changeset 1543 bafa63ac44a2
parent 1467 5538c1eb03be
child 1787 ea12a3bb4b33
permissions -rw-r--r--
Shortening constructor calls and access to arrays
     1 /**
     2  * Back 2 Browser Bytecode Translator
     3  * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     4  *
     5  * This program is free software: you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation, version 2 of the License.
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program. Look for COPYING file in the top folder.
    16  * If not, see http://opensource.org/licenses/GPL-2.0.
    17  */
    18 package org.apidesign.vm4brwsr;
    19 
    20 import java.io.IOException;
    21 import org.apidesign.vm4brwsr.ByteCodeParser.TypeArray;
    22 
    23 final class StackMapper {
    24     private final TypeArray stackTypeIndexPairs;
    25     private final StringArray stackValues;
    26     private boolean dirty;
    27 
    28     public StackMapper() {
    29         stackTypeIndexPairs = new TypeArray();
    30         stackValues = new StringArray();
    31     }
    32 
    33     public void clear() {
    34         stackTypeIndexPairs.clear();
    35         stackValues.clear();
    36         dirty = false;
    37     }
    38 
    39     public void syncWithFrameStack(final TypeArray frameStack) {
    40         clear();
    41 
    42         final int size = frameStack.getSize();
    43         for (int i = 0; i < size; ++i) {
    44             pushTypeImpl(VarType.fromStackMapType(frameStack.get(i)));
    45         }
    46     }
    47 
    48     public Variable pushI() {
    49         return pushT(VarType.INTEGER);
    50     }
    51 
    52     public Variable pushL() {
    53         return pushT(VarType.LONG);
    54     }
    55 
    56     public Variable pushF() {
    57         return pushT(VarType.FLOAT);
    58     }
    59 
    60     public Variable pushD() {
    61         return pushT(VarType.DOUBLE);
    62     }
    63 
    64     public Variable pushA() {
    65         return pushT(VarType.REFERENCE);
    66     }
    67 
    68     public Variable pushT(final int type) {
    69         return getVariable(pushTypeImpl(type));
    70     }
    71 
    72     void assign(Appendable out, int varType, CharSequence s) throws IOException {
    73         pushTypeAndValue(varType, s);
    74     }
    75     
    76     void replace(Appendable out, int varType, String format, CharSequence... arr) 
    77     throws IOException {
    78         StringBuilder sb = new StringBuilder();
    79         ByteCodeToJavaScript.emitImpl(sb, format, arr);
    80         String[] values = stackValues.toArray();
    81         final int last = stackTypeIndexPairs.getSize() - 1;
    82         values[last] = sb.toString();
    83         dirty = true;
    84         final int value = (last << 8) | (varType & 0xff);
    85         stackTypeIndexPairs.set(last, value);
    86     }
    87     
    88     void flush(Appendable out) throws IOException {
    89         int count = stackTypeIndexPairs.getSize();
    90         for (int i = 0; i < count; i++) {
    91             String val = stackValues.getAndClear(i, true);
    92             if (val == null) {
    93                 continue;
    94             }
    95             CharSequence var = getVariable(stackTypeIndexPairs.get(i));
    96             ByteCodeToJavaScript.emitImpl(out, "var @1 = @2;", var, val);
    97         }
    98         dirty = false;
    99     }
   100     
   101     public boolean isDirty() {
   102         return dirty;
   103     }
   104     
   105     public CharSequence popI() {
   106         return popT(VarType.INTEGER);
   107     }
   108 
   109     public CharSequence popL() {
   110         return popT(VarType.LONG);
   111     }
   112 
   113     public CharSequence popF() {
   114         return popT(VarType.FLOAT);
   115     }
   116 
   117     public CharSequence popD() {
   118         return popT(VarType.DOUBLE);
   119     }
   120 
   121     public CharSequence popA() {
   122         return popT(VarType.REFERENCE);
   123     }
   124 
   125     public CharSequence popT(final int type) {
   126         final CharSequence variable = getT(0, type);
   127         popImpl(1);
   128         return variable;
   129     }
   130 
   131     public CharSequence popValue() {
   132         final CharSequence variable = getT(0, -1);
   133         popImpl(1);
   134         return variable;
   135     }
   136     public Variable pop(Appendable out) throws IOException {
   137         flush(out);
   138         final Variable variable = get(0);
   139         popImpl(1);
   140         return variable;
   141     }
   142 
   143     public void pop(final int count) {
   144         final int stackSize = stackTypeIndexPairs.getSize();
   145         if (count > stackSize) {
   146             throw new IllegalStateException("Stack underflow");
   147         }
   148         popImpl(count);
   149     }
   150 
   151     public CharSequence getI(final int indexFromTop) {
   152         return getT(indexFromTop, VarType.INTEGER);
   153     }
   154 
   155     public CharSequence getL(final int indexFromTop) {
   156         return getT(indexFromTop, VarType.LONG);
   157     }
   158 
   159     public CharSequence getF(final int indexFromTop) {
   160         return getT(indexFromTop, VarType.FLOAT);
   161     }
   162 
   163     public CharSequence getD(final int indexFromTop) {
   164         return getT(indexFromTop, VarType.DOUBLE);
   165     }
   166 
   167     public CharSequence getA(final int indexFromTop) {
   168         return getT(indexFromTop, VarType.REFERENCE);
   169     }
   170 
   171     public CharSequence getT(final int indexFromTop, final int type) {
   172         return getT(indexFromTop, type, true);
   173     }
   174     public CharSequence getT(final int indexFromTop, final int type, boolean clear) {
   175         final int stackSize = stackTypeIndexPairs.getSize();
   176         if (indexFromTop >= stackSize) {
   177             throw new IllegalStateException("Stack underflow");
   178         }
   179         final int stackValue =
   180                 stackTypeIndexPairs.get(stackSize - indexFromTop - 1);
   181         if (type != -1 && (stackValue & 0xff) != type) {
   182             throw new IllegalStateException("Type mismatch");
   183         }
   184         String value =
   185             stackValues.getAndClear(stackSize - indexFromTop - 1, clear);
   186         if (value != null) {
   187             return value;
   188         }
   189         return getVariable(stackValue);
   190     }
   191 
   192     public Variable get(final int indexFromTop) {
   193         final int stackSize = stackTypeIndexPairs.getSize();
   194         if (indexFromTop >= stackSize) {
   195             throw new IllegalStateException("Stack underflow");
   196         }
   197         final int stackValue =
   198                 stackTypeIndexPairs.get(stackSize - indexFromTop - 1);
   199 
   200         return getVariable(stackValue);
   201     }
   202 
   203     private int pushTypeImpl(final int type) {
   204         final int count = stackTypeIndexPairs.getSize();
   205         final int value = (count << 8) | (type & 0xff);
   206         stackTypeIndexPairs.add(value);
   207         
   208         addStackValue(count, null);
   209         return value;
   210     }
   211 
   212     private void pushTypeAndValue(final int type, CharSequence v) {
   213         final int count = stackTypeIndexPairs.getSize();
   214         final int value = (count << 8) | (type & 0xff);
   215         stackTypeIndexPairs.add(value);
   216         final String val = v.toString();
   217         addStackValue(count, val);
   218     }
   219 
   220     private void addStackValue(int at, final String val) {
   221         final String[] arr = stackValues.toArray();
   222         if (arr.length > at) {
   223             arr[at] = val;
   224         } else {
   225             stackValues.add(val);
   226         }
   227         dirty = true;
   228     }
   229 
   230     private void popImpl(final int count) {
   231         final int stackSize = stackTypeIndexPairs.getSize();
   232         stackTypeIndexPairs.setSize(stackSize - count);
   233     }
   234 
   235     public Variable getVariable(final int typeAndIndex) {
   236         final int type = typeAndIndex & 0xff;
   237         final int index = typeAndIndex >> 8;
   238 
   239         return Variable.getStackVariable(type, index);
   240     }
   241 }