vm/src/main/java/org/apidesign/vm4brwsr/LocalsMapper.java
author Lubomir Nerad <lubomir.nerad@oracle.com>
Wed, 12 Dec 2012 11:04:02 +0100
branchregisters
changeset 307 eaf4e8387065
child 310 ec7d8bc17725
permissions -rwxr-xr-x
Type specific local variables
     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.javap.RuntimeConstants;
    22 import org.apidesign.javap.TypeArray;
    23 
    24 public final class LocalsMapper {
    25     private final TypeArray argTypeRecords;
    26     private final TypeArray localTypeRecords;
    27 
    28     public LocalsMapper(final TypeArray stackMapArgs) {
    29         final TypeArray initTypeRecords = new TypeArray();
    30         updateRecords(initTypeRecords, stackMapArgs);
    31 
    32         argTypeRecords = initTypeRecords;
    33         localTypeRecords = new TypeArray(initTypeRecords);
    34     }
    35 
    36     public void outputArguments(final Appendable out) throws IOException {
    37         final int argRecordCount = argTypeRecords.getSize();
    38         if (argRecordCount > 0) {
    39             Variable variable = getVariable(argTypeRecords, 0);
    40             out.append(variable);
    41 
    42             int i = variable.isCategory2() ? 2 : 1;
    43             while (i < argRecordCount) {
    44                 variable = getVariable(argTypeRecords, i);
    45                 out.append(", ");
    46                 out.append(variable);
    47                 i += variable.isCategory2() ? 2 : 1;
    48             }
    49         }
    50     }
    51 
    52     public void syncWithFrameLocals(final TypeArray frameLocals) {
    53         updateRecords(localTypeRecords, frameLocals);
    54     }
    55 
    56     public Variable setI(final int index) {
    57         return setT(index, VarType.INTEGER);
    58     }
    59 
    60     public Variable setL(final int index) {
    61         return setT(index, VarType.LONG);
    62     }
    63 
    64     public Variable setF(final int index) {
    65         return setT(index, VarType.FLOAT);
    66     }
    67 
    68     public Variable setD(final int index) {
    69         return setT(index, VarType.DOUBLE);
    70     }
    71 
    72     public Variable setA(final int index) {
    73         return setT(index, VarType.REFERENCE);
    74     }
    75 
    76     public Variable setT(final int index, final int type) {
    77         updateRecord(localTypeRecords, index, type);
    78         return Variable.getLocalVariable(type, index);
    79     }
    80 
    81     public Variable getI(final int index) {
    82         return getT(index, VarType.INTEGER);
    83     }
    84 
    85     public Variable getL(final int index) {
    86         return getT(index, VarType.LONG);
    87     }
    88 
    89     public Variable getF(final int index) {
    90         return getT(index, VarType.FLOAT);
    91     }
    92 
    93     public Variable getD(final int index) {
    94         return getT(index, VarType.DOUBLE);
    95     }
    96 
    97     public Variable getA(final int index) {
    98         return getT(index, VarType.REFERENCE);
    99     }
   100 
   101     public Variable getT(final int index, final int type) {
   102         final int oldRecordValue = localTypeRecords.get(index);
   103         if ((oldRecordValue & 0xff) != type) {
   104             throw new IllegalStateException("Type mismatch");
   105         }
   106 
   107         return Variable.getLocalVariable(type, index);
   108     }
   109 
   110     private static void updateRecords(final TypeArray typeRecords,
   111                                       final TypeArray stackMapTypes) {
   112         final int srcSize = stackMapTypes.getSize();
   113         for (int i = 0, dstIndex = 0; i < srcSize; ++i) {
   114             final int smType = stackMapTypes.get(i);
   115             if (smType == RuntimeConstants.ITEM_Bogus) {
   116                 ++dstIndex;
   117                 continue;
   118             }
   119             final int varType = VarType.fromStackMapType(smType);
   120             updateRecord(typeRecords, dstIndex, varType);
   121             dstIndex += VarType.isCategory2(varType) ? 2 : 1;
   122         }
   123     }
   124 
   125     private static void updateRecord(final TypeArray typeRecords,
   126                                      final int index, final int type) {
   127         if (typeRecords.getSize() < (index + 1)) {
   128             typeRecords.setSize(index + 1);
   129         }
   130 
   131         final int oldRecordValue = typeRecords.get(index);
   132         final int usedTypesMask =
   133                 (oldRecordValue >> 8) | (1 << type);
   134         typeRecords.set(index, (usedTypesMask << 8) | type);
   135     }
   136 
   137     private static Variable getVariable(final TypeArray typeRecords,
   138                                         final int index) {
   139         return Variable.getLocalVariable(typeRecords.get(index) & 0xff, index);
   140     }
   141 }