Home | History | Annotate | Download | only in dasm
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package dasm;
     18 
     19 import com.android.dx.dex.DexOptions;
     20 import com.android.dx.dex.code.ArrayData;
     21 import com.android.dx.dex.code.CodeAddress;
     22 import com.android.dx.dex.code.CstInsn;
     23 import com.android.dx.dex.code.DalvCode;
     24 import com.android.dx.dex.code.DalvInsn;
     25 import com.android.dx.dex.code.Dops;
     26 import com.android.dx.dex.code.OddSpacer;
     27 import com.android.dx.dex.code.OutputFinisher;
     28 import com.android.dx.dex.code.PositionList;
     29 import com.android.dx.dex.code.SimpleInsn;
     30 import com.android.dx.dex.code.SwitchData;
     31 import com.android.dx.dex.code.TargetInsn;
     32 import com.android.dx.dex.code.form.Form51l;
     33 import com.android.dx.dex.file.ClassDefItem;
     34 import com.android.dx.dex.file.DexFile;
     35 import com.android.dx.dex.file.EncodedField;
     36 import com.android.dx.dex.file.EncodedMethod;
     37 import com.android.dx.rop.code.AccessFlags;
     38 import com.android.dx.rop.code.RegisterSpec;
     39 import com.android.dx.rop.code.RegisterSpecList;
     40 import com.android.dx.rop.code.SourcePosition;
     41 import com.android.dx.rop.cst.Constant;
     42 import com.android.dx.rop.cst.CstBoolean;
     43 import com.android.dx.rop.cst.CstByte;
     44 import com.android.dx.rop.cst.CstChar;
     45 import com.android.dx.rop.cst.CstDouble;
     46 import com.android.dx.rop.cst.CstFieldRef;
     47 import com.android.dx.rop.cst.CstFloat;
     48 import com.android.dx.rop.cst.CstInteger;
     49 import com.android.dx.rop.cst.CstLong;
     50 import com.android.dx.rop.cst.CstMethodRef;
     51 import com.android.dx.rop.cst.CstNat;
     52 import com.android.dx.rop.cst.CstShort;
     53 import com.android.dx.rop.cst.CstString;
     54 import com.android.dx.rop.cst.CstType;
     55 import com.android.dx.rop.type.StdTypeList;
     56 import com.android.dx.rop.type.Type;
     57 import com.android.dx.rop.type.TypeList;
     58 import com.android.dx.util.IntList;
     59 
     60 import java.io.FileWriter;
     61 import java.io.IOException;
     62 import java.io.OutputStream;
     63 import java.io.Reader;
     64 import java.util.ArrayList;
     65 import java.util.Enumeration;
     66 import java.util.Hashtable;
     67 import java.util.Vector;
     68 
     69 //TODO: copyright notice
     70 
     71 /**
     72  * This class represents the public API for Dasm. It has two main methods (readD
     73  * and write) and few utility methods. To compile .d file: -create DAsm instance
     74  * -call readD() to read and parse content of .d file -call write() to write out
     75  * binary representation of .d file. .d file can contain several classes and/or
     76  * intefaces declarations.
     77  */
     78 
     79 public class DAsm {
     80     private static final boolean PARSER_DEBUG = false;
     81 
     82     // number of errors reported in a file.
     83     int errors;
     84 
     85     // options for dex output
     86     DexOptions dexOptions = new DexOptions();
     87 
     88     // file being processed
     89     DexFile dexFile;
     90     int line_num;
     91     Scanner scanner;
     92 
     93     // state info for the class being built
     94     boolean class_header;
     95     String class_name;
     96     int class_acc;
     97     String superclass_name;
     98     String source_name;
     99     String filename;
    100     Vector<String> interfaces = new Vector<String>();
    101     ClassDefItem classDef;
    102 
    103     // method being built
    104     EncodedMethod enc_method;
    105     CstNat method_nat;
    106     int method_acc;
    107     int regs_count;
    108     OutputFinisher output_finisher;
    109 
    110     /**
    111      * list of exceptions that method can throw.
    112      */
    113     Vector<String> throw_list = new Vector<String>();
    114 
    115     /**
    116      * Constructor of CatchTable instances from method data.
    117      */
    118     DasmCatchBuilder catch_builder;
    119 
    120     /**
    121      * Holds CodeAddress associated with particular label and <i>planted</i>
    122      * attribute specifying that CodeAddress was added to instructions array.
    123      * <i>planted</i> is false if this label is a target of forward branch and
    124      * it was not added to instructions array yet.
    125      */
    126     class LabelTableEntry {
    127         LabelTableEntry(CodeAddress code_address, boolean planted) {
    128             this.code_address = code_address;
    129             this.planted = planted;
    130         }
    131 
    132         CodeAddress code_address;
    133         boolean planted;
    134     }
    135 
    136     /**
    137      * Hold a translation table "LabelX" -> CodeAddress, planted.
    138      */
    139     Hashtable<String, LabelTableEntry> labels_table;
    140 
    141     /**
    142      * used by relative forward jumps. When relative forward offset is found,
    143      * CodeAddress is placed into unprocessed_relative_goto_addr. When addInsn
    144      * method is called, it checks if there was a jump to current instruction
    145      * and moves CodeAddress from unprocessed_relative_goto_addr into
    146      * output_finisher.
    147      */
    148     int current_insn_number;
    149     Hashtable<Integer, CodeAddress> unprocessed_relative_goto_addr =
    150             new Hashtable<Integer, CodeAddress>();
    151 
    152     // fill-array-data data
    153     int fill_data_reg;
    154     String fill_array_data_type;
    155     Vector<Number> fill_array_data_values;
    156 
    157     // packed-switch and sparse-switch data
    158     int switch_reg;
    159     Vector<Object> switch_targets;
    160     IntList switch_keys;
    161     int packed_switch_first_key;
    162     int packed_switch_current_key;
    163 
    164     /**
    165      * holds sparse-switch, packed-switch and fill-array-data data blocks to be
    166      * added at the end of method
    167      */
    168     Vector<DalvInsn> data_blocks = new Vector<DalvInsn>();
    169 
    170     /**
    171      * Returns the number of warnings/errors encountered while parsing a file. 0
    172      * if everything went OK.
    173      */
    174     public int errorCount() {
    175         return errors;
    176     }
    177 
    178     void report_error(String msg) {
    179         errors++;
    180         System.out.println("Line " + line_num + ": " + msg);
    181     }
    182 
    183     void throwDasmError(String msg) throws DasmError {
    184         throw new DasmError("Line " + line_num + ": " + msg);
    185     }
    186 
    187     /**
    188      * used by .line directive
    189      */
    190     void addLineInfo(int line_num) throws DasmError {
    191         throw new IllegalStateException(".line not implemented");
    192     }
    193 
    194     void addLine(int line_num) throws DasmError {
    195         throw new IllegalStateException(".line not implemented");
    196     }
    197 
    198     /**
    199      * used by the .var directive
    200      */
    201     void addVar(String startLab, String endLab, String name, String desc,
    202             String sign, int var_num) throws DasmError {
    203         throw new IllegalStateException(".var is not implemented");
    204     }
    205 
    206     void addVar(int startOffset, int endOffset, String name, String desc,
    207             String sign, int var_num) throws DasmError {
    208         throw new IllegalStateException(".var is not implemented");
    209     }
    210 
    211 
    212     /**
    213      * Used by the parser to tell DAsm what the line number for the next
    214      * statement is. DAsm's autoNumber mechanism uses this info.
    215      */
    216     void setLine(int l) {
    217         if (PARSER_DEBUG) System.out.println("setLine(" + l + ")");
    218         line_num = l;
    219     }
    220 
    221     /**
    222      * called by the .inner directive
    223      */
    224     void addInner(short iacc, String name, String inner, String outer) {
    225         throw new IllegalStateException(".inner is not implemented");
    226     }
    227 
    228     /*
    229      * ========================================================================
    230      * === FILE HEADER
    231      * ========================================================================
    232      */
    233 
    234     /**
    235      * called by the .source directive
    236      */
    237     void setSource(String name) {
    238         if (PARSER_DEBUG) System.out.println("setSource(" + name + ")");
    239         source_name = name;
    240     }
    241 
    242     /**
    243      * called by the .bytecode directive
    244      */
    245     void setVersion(Number version) {
    246         throw new IllegalStateException(".bytecode is not implemented");
    247     }
    248 
    249     /**
    250      * called by the .class directive
    251      */
    252     void setClass(String name, int acc) {
    253         if (PARSER_DEBUG)
    254             System.out.println("setClass(" + name + ", " + acc + ")");
    255         class_name = name;
    256         class_acc = acc;
    257         class_header = true;
    258         interfaces.clear();
    259         superclass_name = null;
    260     }
    261 
    262     /**
    263      * Returns the name of the class in the file (i.e. the string given to the
    264      * .class parameter). If there're several classes in one file, returns name
    265      * of last class.
    266      */
    267     public String getClassName() {
    268         return class_name;
    269     }
    270 
    271     /**
    272      * called by the .super directive
    273      */
    274     void setSuperClass(String name) {
    275         if (PARSER_DEBUG) System.out.println("setSuperClass(" + name + ")");
    276         superclass_name = name;
    277     }
    278 
    279     /**
    280      * called by the .implements directive
    281      */
    282     void addInterface(String name) {
    283         if (PARSER_DEBUG) System.out.println("addInterface(" + name + ")");
    284 
    285         int sz = interfaces.size();
    286         boolean found = false;
    287         // search for duplicates
    288         for (int i = 0; i < sz; i++) {
    289             String s = interfaces.elementAt(i);
    290             if (s.compareTo(name) == 0) {
    291                 found = true;
    292                 break;
    293             }
    294 
    295         }
    296         if (found == false) interfaces.add(name);
    297     }
    298 
    299     /**
    300      * called by the .signature directive
    301      */
    302     void setSignature(String str) throws DasmError {
    303         throw new IllegalStateException(".signature is not implemented");
    304     }
    305 
    306     /**
    307      * called by the .enclosing directive
    308      */
    309     void setEnclosingMethod(String str) {
    310         throw new IllegalStateException(".enclosing is not implemented");
    311     }
    312 
    313     /**
    314      * called by the .attribute directive
    315      */
    316     void addGenericAttr(String name, String file) throws DasmError {
    317         throw new IllegalStateException(".attribute is not implemented");
    318     }
    319 
    320     /**
    321      * called at end of dasm-header (resolve class variables)
    322      */
    323     void endHeader() {
    324 
    325         TypeList tl = createTypeListFromStrings(interfaces);
    326 
    327         classDef = new ClassDefItem(CstType.intern(Type
    328                 .internClassName(class_name)), class_acc,
    329                 superclass_name != null ? CstType.intern(Type
    330                         .internClassName(superclass_name)) : null, tl,
    331                 new CstString(source_name));
    332         dexFile.add(classDef);
    333         class_header = false;
    334     }
    335 
    336     /*
    337      * ========================================================================
    338      * === FIELDS
    339      * ========================================================================
    340      */
    341 
    342     /**
    343      * called by the .field directive to begin 'prompted' field
    344      */
    345     void beginField(short access, String name, String desc, Object value)
    346             throws DasmError {
    347         throw new IllegalStateException(
    348                 "multiline fields are not implemented yet");
    349     }
    350 
    351     /**
    352      * called by the .end field directive to end 'prompted' field
    353      */
    354     void endField() throws DasmError {
    355         throw new IllegalStateException(
    356                 "multiline fields are not implemented yet");
    357     }
    358 
    359     /**
    360      * called by the .field directive
    361      */
    362     void addField(short access, String name, String desc, String sig,
    363             Object value) throws DasmError {
    364         if (PARSER_DEBUG)
    365             System.out.println("addField(" + name + ", " + desc + ", " + sig
    366                     + ", " + access + ", "
    367                     + (value == null ? "null" : value.toString()) + ")");
    368 
    369         CstNat nat = new CstNat(new CstString(name), new CstString(desc));
    370         CstFieldRef field = new CstFieldRef(classDef.getThisClass(), nat);
    371         EncodedField ef = new EncodedField(field, access);
    372         if ((access & AccessFlags.ACC_STATIC) != 0) {
    373             // TODO: value?
    374             if (value != null)
    375                 throw new IllegalStateException(
    376                         "addField: field initialization not implemented yet");
    377             classDef.addStaticField(ef, null);
    378         } else
    379             classDef.addInstanceField(ef);
    380     }
    381 
    382 
    383     /*
    384      * ========================================================================
    385      * === METHODS
    386      * ========================================================================
    387      */
    388 
    389     /**
    390      * called by the .method directive to start the definition for a method
    391      */
    392     void newMethod(String name, String descriptor, int access) {
    393         if (PARSER_DEBUG)
    394             System.out.println("newMethod(" + name + ", " + descriptor + ", "
    395                     + access + ")");
    396 
    397         output_finisher = null;
    398         throw_list.clear();
    399         unprocessed_relative_goto_addr.clear();
    400         labels_table = new Hashtable<String, LabelTableEntry>();
    401         catch_builder = new DasmCatchBuilder(labels_table);
    402         current_insn_number = 0;
    403         regs_count = 1;
    404 
    405         method_nat = new CstNat(new CstString(name), new CstString(descriptor));
    406         if (method_nat.isClassInit()) access |= AccessFlags.ACC_STATIC;
    407         if (method_nat.isInstanceInit()) access |= AccessFlags.ACC_CONSTRUCTOR;
    408 
    409         method_acc = access;
    410     }
    411 
    412     /**
    413      * called by the .end method directive to end the definition for a method
    414      */
    415     void endMethod() throws DasmError {
    416         if (PARSER_DEBUG) System.out.println("endMethod()");
    417 
    418         // add packed-switch, sparse-switch, fill-array-data data blocks at the
    419         // end of method
    420         int sz = data_blocks.size();
    421         for (int i = 0; i < sz; i++) {
    422             addInsn(data_blocks.elementAt(i));
    423         }
    424         data_blocks.clear();
    425 
    426         // check jump targets
    427         if (unprocessed_relative_goto_addr.size() != 0) {
    428             report_error("Relative forward jump offset too big.");
    429         }
    430         Enumeration<String> e = labels_table.keys();
    431         while (e.hasMoreElements()) {
    432             String key = e.nextElement();
    433             LabelTableEntry lte = labels_table.get(key);
    434             if (lte.planted == false) {
    435                 report_error("Label " + key + " not found.");
    436             }
    437         }
    438 
    439         TypeList tl = createTypeListFromStrings(throw_list);
    440 
    441         CstMethodRef meth = new CstMethodRef(classDef.getThisClass(),
    442                 method_nat);
    443         DalvCode code = null;
    444         // output_finisher may be null at this point if method is native
    445         if (output_finisher != null)
    446             code = new DalvCode(PositionList.NONE, output_finisher,
    447                     catch_builder);
    448         enc_method = new EncodedMethod(meth, method_acc, code, tl);
    449 
    450         if (meth.isInstanceInit() || meth.isClassInit()
    451                 || (method_acc & AccessFlags.ACC_STATIC) != 0
    452                 || (method_acc & AccessFlags.ACC_PRIVATE) != 0) {
    453             classDef.addDirectMethod(enc_method);
    454         } else {
    455             classDef.addVirtualMethod(enc_method);
    456         }
    457         catch_builder = null;
    458         labels_table = null;
    459     }
    460 
    461     /**
    462      * used by the .limit regs directive
    463      */
    464     void setRegsSize(int v) throws DasmError {
    465         if (PARSER_DEBUG) System.out.println("setRegsSize(" + v + ")");
    466         regs_count = v;
    467     }
    468 
    469     /**
    470      * used by the .throws directive
    471      */
    472     void addThrow(String name) throws DasmError {
    473         if (PARSER_DEBUG) System.out.println("addThrow(" + name + ")");
    474         throw_list.add(name);
    475     }
    476 
    477     /**
    478      * used by the .catch directive
    479      */
    480     void addCatch(String name, String start_lab, String end_lab,
    481             String branch_lab) throws DasmError {
    482         if (PARSER_DEBUG)
    483             System.out.println("addCatch(" + name + ", " + start_lab + ", "
    484                     + end_lab + ", " + branch_lab + ")");
    485         catch_builder.add(name, start_lab, end_lab, branch_lab);
    486     }
    487 
    488     void addCatch(String name, int start_off, int end_off, int branch_off)
    489             throws DasmError {
    490         if (PARSER_DEBUG)
    491             System.out.println("addCatch(" + name + ", " + start_off + ", "
    492                     + end_off + ", " + branch_off + ")");
    493         throw new IllegalStateException(
    494                 "addCatch(String, int, int, int) is not implemented yet");
    495     }
    496 
    497 
    498     /**
    499      * defines a label
    500      */
    501     void plantLabel(String name) throws DasmError {
    502         if (PARSER_DEBUG) System.out.println("plantLabel(" + name + ")");
    503         createOutputFinisher();
    504         LabelTableEntry lte = labels_table.get(name);
    505         if (lte != null) {
    506             if (lte.planted == true)
    507                 report_error("Label " + name + " already defined");
    508             else {
    509                 lte.planted = true;
    510                 addInsn(lte.code_address);
    511             }
    512         } else {
    513             CodeAddress code_address = new CodeAddress(createSourcePosition());
    514             addInsn(code_address);
    515             labels_table.put(name, new LabelTableEntry(code_address, true));
    516         }
    517     }
    518 
    519 
    520     /**
    521      * used for instructions that take no arguments Format: 10x
    522      */
    523     void addOpcode(String name) throws DasmError {
    524         if (PARSER_DEBUG) System.out.println("addOpcode(" + name + ")");
    525         createOutputFinisher();
    526         DopInfo insn = DopInfo.get(name);
    527         if (insn.args.equals("")) {
    528             DalvInsn dalvInsn = new SimpleInsn(insn.opcode,
    529                     createSourcePosition(), RegisterSpecList.EMPTY);
    530             addInsn(dalvInsn);
    531         } else {
    532             throwDasmError("Missing arguments for instruction " + name);
    533         }
    534     }
    535 
    536     /**
    537      * used for instructions that take a word as a parameter (register name is
    538      * treated as word) Format: 11x, 10t, 20t, 30t
    539      */
    540     void addOpcode(String name, String val) throws DasmError {
    541         if (PARSER_DEBUG)
    542             System.out.println("addOpcode(" + name + ", " + val + ")");
    543         createOutputFinisher();
    544         DopInfo insn = DopInfo.get(name);
    545         if (insn.args.compareToIgnoreCase(DopInfo.ARG_REGISTER) == 0) {
    546             int reg_num = -1;
    547 
    548             try {
    549                 reg_num = getRegNumberFromString(val);
    550             } catch (IllegalArgumentException e) {
    551                 throwDasmError("Bad arguments for instruction " + name + "("
    552                         + val + ")");
    553             }
    554             // TODO: is Type.INT suitable for any opcodes? Or it should be
    555             // Type.OBJECT for return-object, for example?
    556             RegisterSpec reg_spec = RegisterSpec.make(reg_num, Type.INT);
    557             DalvInsn dalvInsn = new SimpleInsn(insn.opcode,
    558                     createSourcePosition(), RegisterSpecList.make(reg_spec));
    559             addInsn(dalvInsn);
    560         } else if (insn.args.compareToIgnoreCase(DopInfo.ARG_ADDRESS) == 0) {
    561             LabelTableEntry lte = labels_table.get(val);
    562             if (lte == null) {
    563                 CodeAddress code_address = new CodeAddress(
    564                         SourcePosition.NO_INFO);
    565                 lte = new LabelTableEntry(code_address, false);
    566                 labels_table.put(val, lte);
    567             }
    568             DalvInsn dalvInsn = new TargetInsn(insn.opcode,
    569                     createSourcePosition(), RegisterSpecList.EMPTY,
    570                     lte.code_address);
    571             addInsn(dalvInsn);
    572         } else {
    573             throwDasmError("Bad arguments for instruction " + name + "(" + val
    574                     + ")");
    575         }
    576     }
    577 
    578     /**
    579      * used for relative branch targets (ie $+5, $-12, ...) Format: relative
    580      * 10t, 20t, 30t
    581      */
    582     void addRelativeGoto(String name, int val) throws DasmError {
    583         if (PARSER_DEBUG)
    584             System.out.println("addRelativeGoto(" + name + ", " + val + ")");
    585         createOutputFinisher();
    586         DopInfo insn = DopInfo.get(name);
    587         if (insn.args.compareToIgnoreCase(DopInfo.ARG_ADDRESS) == 0) {
    588             if (val == 0)
    589                 throwDasmError("Bad arguments for instruction " + name + "("
    590                         + val + ")");
    591 
    592             CodeAddress code_address = new CodeAddress(SourcePosition.NO_INFO);
    593             if (val < 0) {
    594                 output_finisher.insert(current_insn_number + val, code_address);
    595                 current_insn_number++;
    596             } else {
    597                 unprocessed_relative_goto_addr.put(current_insn_number + val,
    598                         code_address);
    599             }
    600             DalvInsn dalvInsn = new TargetInsn(insn.opcode,
    601                     createSourcePosition(), RegisterSpecList.EMPTY,
    602                     code_address);
    603             addInsn(dalvInsn);
    604 
    605         } else {
    606             throwDasmError("Bad arguments for instruction " + name + "(" + val
    607                     + ")");
    608         }
    609     }
    610 
    611     /**
    612      * used for instructions that take two word parameters (register name is
    613      * treated as word) Format: 12x, 22x, 32x, 21t, 21c (string@, type@), 31c,
    614      * 35c, 3rc
    615      */
    616     void addOpcode(String name, String v1, String v2) throws DasmError {
    617         if (PARSER_DEBUG)
    618             System.out.println("addOpcode(" + name + ", " + v1 + ", " + v2
    619                     + ")");
    620         createOutputFinisher();
    621         DopInfo insn = DopInfo.get(name);
    622 
    623         if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_REG) == 0) {
    624             int reg1_num = -1, reg2_num = -1;
    625 
    626             try {
    627                 reg1_num = getRegNumberFromString(v1);
    628             } catch (IllegalArgumentException e) {
    629                 throwDasmError("Bad arguments for instruction " + name + "("
    630                         + v1 + ")");
    631             }
    632 
    633             try {
    634                 reg2_num = getRegNumberFromString(v2);
    635             } catch (IllegalArgumentException e) {
    636                 throwDasmError("Bad arguments for instruction " + name + "("
    637                         + v2 + ")");
    638             }
    639             // TODO: is Type.INT suitable for any opcodes?
    640             RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
    641             RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, Type.INT);
    642             DalvInsn dalvInsn = new SimpleInsn(insn.opcode,
    643                     createSourcePosition(), RegisterSpecList.make(reg1_spec,
    644                             reg2_spec));
    645             addInsn(dalvInsn);
    646         } else if (insn.args.compareToIgnoreCase(
    647                 DopInfo.ARG_REG_ADDRESS) == 0) {
    648             int reg1_num = -1;
    649 
    650             try {
    651                 reg1_num = getRegNumberFromString(v1);
    652             } catch (IllegalArgumentException e) {
    653                 throwDasmError("Bad arguments for instruction " + name + "("
    654                         + v1 + ")");
    655             }
    656 
    657             LabelTableEntry lte = labels_table.get(v2);
    658             if (lte == null) {
    659                 CodeAddress code_address = new CodeAddress(
    660                         SourcePosition.NO_INFO);
    661                 lte = new LabelTableEntry(code_address, false);
    662                 labels_table.put(v2, lte);
    663             }
    664 
    665             RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
    666             DalvInsn dalvInsn = new TargetInsn(insn.opcode,
    667                     createSourcePosition(), RegisterSpecList.make(reg1_spec),
    668                     lte.code_address);
    669             addInsn(dalvInsn);
    670         } else if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_STRING) == 0) {
    671             int reg1_num = -1;
    672 
    673             try {
    674                 reg1_num = getRegNumberFromString(v1);
    675             } catch (IllegalArgumentException e) {
    676                 throwDasmError("Bad arguments for instruction " + name + "("
    677                         + v1 + ")");
    678             }
    679             RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.STRING);
    680             Constant constant = new CstString(v2);
    681             DalvInsn dalvInsn = new CstInsn(insn.opcode,
    682                     createSourcePosition(), RegisterSpecList.make(reg1_spec),
    683                     constant);
    684             addInsn(dalvInsn);
    685         } else if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_TYPE) == 0) {
    686             int reg1_num = -1;
    687 
    688             try {
    689                 reg1_num = getRegNumberFromString(v1);
    690             } catch (IllegalArgumentException e) {
    691                 throwDasmError("Bad arguments for instruction " + name + "("
    692                         + v1 + ")");
    693             }
    694             Type type;
    695             try {
    696                 // try to intern it as primitive type first
    697                 type = Type.intern(v2);
    698             } catch (IllegalArgumentException e) {
    699                 type = Type.internClassName(v2);
    700             }
    701 
    702             RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, type);
    703             Constant constant = CstType.intern(type);
    704             DalvInsn dalvInsn = new CstInsn(insn.opcode,
    705                     createSourcePosition(), RegisterSpecList.make(reg1_spec),
    706                     constant);
    707             addInsn(dalvInsn);
    708         } else if (insn.args.compareToIgnoreCase(DopInfo.ARG_REGLIST_TYPE) == 0
    709                 || insn.args.compareToIgnoreCase(
    710                         DopInfo.ARG_REGLIST_METHOD) == 0
    711                 || insn.args.compareToIgnoreCase(
    712                         DopInfo.ARG_REGLIST_INTFMETHOD) == 0) {
    713             RegisterSpecList reg_spec_list = RegisterSpecList.EMPTY;
    714             String regs[] = Utils.splitRegList(v1);
    715             if (regs != null) {
    716                 int rn = regs.length;
    717                 if (rn == 0 || rn > 5)
    718                     throwDasmError("Bad arguments for instruction " + name
    719                             + "(" + v1 + ")");
    720                 int reg_num[] = new int[rn];
    721 
    722                 reg_spec_list = new RegisterSpecList(rn);
    723 
    724                 for (int i = 0; i < rn; i++) {
    725                     try {
    726                         reg_num[i] = getRegNumberFromString(regs[i]);
    727                     } catch (IllegalArgumentException e) {
    728                         throwDasmError("Bad arguments for instruction " + name
    729                                 + "(" + v1 + ")");
    730                     }
    731                     reg_spec_list.set(i, RegisterSpec
    732                             .make(reg_num[i], Type.INT));
    733                 }
    734             }
    735             Constant constant;
    736             if (insn.args.compareToIgnoreCase(DopInfo.ARG_REGLIST_TYPE) == 0) {
    737                 // filled-new-array
    738                 Type type;
    739                 try {
    740                     type = Type.intern(v2);
    741                 } catch (IllegalArgumentException e) {
    742                     // in case of exception, try to intern type as a class name
    743                     // (Lclass_name;)
    744                     type = Type.internClassName(v2);
    745                 }
    746                 constant = CstType.intern(type);
    747             } else {
    748                 // invoke-kind
    749                 String[] names = Utils.getClassMethodSignatureFromString(v2);
    750                 CstNat method_nat = new CstNat(new CstString(names[1]),
    751                         new CstString(names[2]));
    752 
    753                 /*
    754                  * if(insn.args.compareToIgnoreCase(
    755                  *          DopInfo.ARG_REGLIST_INTFMETHOD
    756                  * ) == 0) constant = new
    757                  * CstInterfaceMethodRef(CstType.intern(Type
    758                  * .internClassName(names[0])), method_nat); else
    759                  */
    760                 constant = new CstMethodRef(CstType.intern(Type
    761                         .internClassName(names[0])), method_nat);
    762             }
    763 
    764             DalvInsn dalvInsn = new CstInsn(insn.opcode,
    765                     createSourcePosition(), reg_spec_list, constant);
    766             addInsn(dalvInsn);
    767 
    768         } else if (insn.args.compareToIgnoreCase(
    769                         DopInfo.ARG_REGRANGE_TYPE) == 0
    770                 || insn.args.compareToIgnoreCase(
    771                         DopInfo.ARG_REGRANGE_METHOD) == 0
    772                 || insn.args.compareToIgnoreCase(
    773                         DopInfo.ARG_REGRANGE_INTFMETHOD) == 0) {
    774             String regs[] = Utils.splitRegList(v1);
    775             RegisterSpecList reg_spec_list;
    776             if (regs != null && regs.length > 0) {
    777                 int regC = -1, regN = -1;
    778                 try {
    779                     regC = getRegNumberFromString(regs[0]);
    780                 } catch (IllegalArgumentException e) {
    781                     throwDasmError("Bad arguments for instruction " + name
    782                             + "(" + v1 + ")");
    783                 }
    784 
    785                 if (regs.length > 1) {
    786                     try {
    787                         regN = getRegNumberFromString(regs[1]);
    788                     } catch (IllegalArgumentException e) {
    789                         throwDasmError("Bad arguments for instruction " + name
    790                                 + "(" + v1 + ")");
    791                     }
    792 
    793                     if (regC >= regN)
    794                         throwDasmError("Bad arguments for instruction " + name
    795                                 + "(" + v1 + ")");
    796                 } else
    797                     regN = regC;
    798 
    799 
    800                 int sz = regN - regC + 1;
    801                 reg_spec_list = new RegisterSpecList(sz);
    802 
    803                 for (int i = 0; i < sz; i++) {
    804                     reg_spec_list.set(i, RegisterSpec.make(regC + i, Type.INT));
    805                 }
    806             } else
    807                 reg_spec_list = RegisterSpecList.EMPTY;
    808 
    809             Constant constant;
    810             if (insn.args.compareToIgnoreCase(DopInfo.ARG_REGRANGE_TYPE) == 0) {
    811                 // filled-new-array/range
    812                 Type type;
    813                 try {
    814                     type = Type.intern(v2);
    815                 } catch (IllegalArgumentException e) {
    816                     // in case of exception, try to intern type as a class name
    817                     // (Lclass_name;)
    818                     type = Type.internClassName(v2);
    819                 }
    820                 constant = CstType.intern(type);
    821             } else {
    822                 // invoke-kind/range
    823                 String[] names = Utils.getClassMethodSignatureFromString(v2);
    824                 CstNat method_nat = new CstNat(new CstString(names[1]),
    825                         new CstString(names[2]));
    826 
    827                 /*
    828                  * if(insn.args.compareToIgnoreCase(
    829                  *         DopInfo.ARG_REGRANGE_INTFMETHOD
    830                  * ) == 0) constant = new
    831                  * CstInterfaceMethodRef(CstType.intern(Type
    832                  * .internClassName(names[0])), method_nat); else
    833                  */
    834                 constant = new CstMethodRef(CstType.intern(Type
    835                         .internClassName(names[0])), method_nat);
    836             }
    837 
    838             DalvInsn dalvInsn = new CstInsn(insn.opcode,
    839                     createSourcePosition(), reg_spec_list, constant);
    840             addInsn(dalvInsn);
    841 
    842         } else {
    843             throwDasmError("Bad arguments for instruction " + name + "(" + v1
    844                     + ", " + v2 + ")");
    845         }
    846     }
    847 
    848     /**
    849      * used for relative branch targets (ie $+5, $-12, ...) Format: relative 21t
    850      */
    851     void addRelativeGoto(String name, String v1, int val) throws DasmError {
    852         if (PARSER_DEBUG)
    853             System.out.println("addRelativeGoto(" + name + ", " + v1 + ", "
    854                     + val + ")");
    855         createOutputFinisher();
    856         DopInfo insn = DopInfo.get(name);
    857         if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_ADDRESS) == 0) {
    858             if (val == 0)
    859                 throwDasmError("Bad arguments for instruction " + name + "("
    860                         + val + ")");
    861 
    862             int reg1_num = -1;
    863             try {
    864                 reg1_num = getRegNumberFromString(v1);
    865             } catch (IllegalArgumentException e) {
    866                 throwDasmError("Bad arguments for instruction " + name + "("
    867                         + v1 + ")");
    868             }
    869 
    870             RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
    871             RegisterSpecList rsl = RegisterSpecList.make(reg1_spec);
    872             CodeAddress code_address = new CodeAddress(SourcePosition.NO_INFO);
    873             if (val < 0) {
    874                 output_finisher.insert(current_insn_number + val, code_address);
    875                 current_insn_number++;
    876             } else {
    877                 unprocessed_relative_goto_addr.put(current_insn_number + val,
    878                         code_address);
    879             }
    880             DalvInsn dalvInsn = new TargetInsn(insn.opcode,
    881                     createSourcePosition(), rsl, code_address);
    882             addInsn(dalvInsn);
    883 
    884         } else {
    885             throwDasmError("Bad arguments for instruction " + name + "(" + val
    886                     + ")");
    887         }
    888     }
    889 
    890     /**
    891      * used for instructions that take one word parameter (register name is
    892      * treated as word) and one literal Format: 11n, 21s, 31i, 21h, 51l
    893      */
    894     void addOpcode(String name, String v1, Number v2) throws DasmError {
    895         if (PARSER_DEBUG)
    896             System.out.println("addOpcode(" + name + ", " + v1 + ", " + v2
    897                     + ")");
    898         createOutputFinisher();
    899         DopInfo insn = DopInfo.get(name);
    900         if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_LITERAL) == 0) {
    901             int reg1_num = -1;
    902 
    903             try {
    904                 reg1_num = getRegNumberFromString(v1);
    905             } catch (IllegalArgumentException e) {
    906                 throwDasmError("Bad arguments for instruction " + name + "("
    907                         + v1 + ")");
    908             }
    909 
    910             RegisterSpec reg1_spec;
    911             Constant constant;
    912             // create Constant of type suitable for value specified in
    913             // instruction
    914             if (v2 instanceof Long
    915                     || (v2 instanceof Integer &&
    916                             insn.opcode.getFormat() == Form51l.THE_ONE)) {
    917                 reg1_spec = RegisterSpec.make(reg1_num, Type.LONG);
    918                 constant = CstLong.make(v2.longValue());
    919             } else if (v2 instanceof Float
    920                     && insn.opcode.getFormat() != Form51l.THE_ONE) {
    921                 reg1_spec = RegisterSpec.make(reg1_num, Type.FLOAT);
    922                 constant = CstFloat.make(Float.floatToIntBits(v2.floatValue()));
    923             } else if (v2 instanceof Double
    924                     || (v2 instanceof Float &&
    925                             insn.opcode.getFormat() == Form51l.THE_ONE)) {
    926                 reg1_spec = RegisterSpec.make(reg1_num, Type.DOUBLE);
    927                 constant = CstDouble.make(Double.doubleToLongBits(v2
    928                         .doubleValue()));
    929             } else {
    930                 reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
    931                 constant = CstInteger.make(v2.intValue());
    932             }
    933 
    934             DalvInsn dalvInsn = new CstInsn(insn.opcode,
    935                     createSourcePosition(), RegisterSpecList.make(reg1_spec),
    936                     constant);
    937             addInsn(dalvInsn);
    938         } else {
    939             throwDasmError("Bad arguments for instruction " + name + "(" + v1
    940                     + ", " + v2 + ")");
    941         }
    942 
    943     }
    944 
    945     /**
    946      * used for instructions that take three word parameters (register name is
    947      * treated as word) Format: 23x, 22t, 21c (field@), 22c (type@)
    948      */
    949     void addOpcode(String name, String v1, String v2, String v3)
    950             throws DasmError {
    951         if (PARSER_DEBUG)
    952             System.out.println("addOpcode(" + name + ", " + v1 + ", " + v2
    953                     + ", " + v3 + ")");
    954         createOutputFinisher();
    955         DopInfo insn = DopInfo.get(name);
    956 
    957         if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_REG_REG) == 0) {
    958             int reg1_num = -1, reg2_num = -1, reg3_num = -1;
    959 
    960             try {
    961                 reg1_num = getRegNumberFromString(v1);
    962             } catch (IllegalArgumentException e) {
    963                 throwDasmError("Bad arguments for instruction " + name + "("
    964                         + v1 + ")");
    965             }
    966 
    967             try {
    968                 reg2_num = getRegNumberFromString(v2);
    969             } catch (IllegalArgumentException e) {
    970                 throwDasmError("Bad arguments for instruction " + name + "("
    971                         + v2 + ")");
    972             }
    973 
    974             try {
    975                 reg3_num = getRegNumberFromString(v3);
    976             } catch (IllegalArgumentException e) {
    977                 throwDasmError("Bad arguments for instruction " + name + "("
    978                         + v3 + ")");
    979             }
    980             // TODO: is Type.INT suitable for any opcodes?
    981             RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
    982             RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, Type.INT);
    983             RegisterSpec reg3_spec = RegisterSpec.make(reg3_num, Type.INT);
    984             DalvInsn dalvInsn = new SimpleInsn(insn.opcode,
    985                     createSourcePosition(), RegisterSpecList.make(reg1_spec,
    986                             reg2_spec, reg3_spec));
    987             addInsn(dalvInsn);
    988         } else if (insn.args.compareToIgnoreCase(
    989                 DopInfo.ARG_REG_REG_ADDRESS) == 0) {
    990             int reg1_num = -1, reg2_num = -1;
    991 
    992             try {
    993                 reg1_num = getRegNumberFromString(v1);
    994             } catch (IllegalArgumentException e) {
    995                 throwDasmError("Bad arguments for instruction " + name + "("
    996                         + v1 + ")");
    997             }
    998 
    999             try {
   1000                 reg2_num = getRegNumberFromString(v2);
   1001             } catch (IllegalArgumentException e) {
   1002                 throwDasmError("Bad arguments for instruction " + name + "("
   1003                         + v2 + ")");
   1004             }
   1005 
   1006             LabelTableEntry lte = labels_table.get(v3);
   1007             if (lte == null) {
   1008                 CodeAddress code_address = new CodeAddress(
   1009                         SourcePosition.NO_INFO);
   1010                 lte = new LabelTableEntry(code_address, false);
   1011                 labels_table.put(v3, lte);
   1012             }
   1013 
   1014             RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
   1015             RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, Type.INT);
   1016 
   1017             DalvInsn dalvInsn = new TargetInsn(insn.opcode,
   1018                     createSourcePosition(), RegisterSpecList.make(reg1_spec,
   1019                             reg2_spec), lte.code_address);
   1020             addInsn(dalvInsn);
   1021         } else if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_FIELD) == 0) {
   1022             int reg1_num = -1;
   1023 
   1024             try {
   1025                 reg1_num = getRegNumberFromString(v1);
   1026             } catch (IllegalArgumentException e) {
   1027                 throwDasmError("Bad arguments for instruction " + name + "("
   1028                         + v1 + ")");
   1029             }
   1030             // TODO: is Type.INT suitable?
   1031             RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
   1032 
   1033             String[] names = Utils.getClassFieldFromString(v2);
   1034 
   1035             CstNat field_nat = new CstNat(new CstString(names[1]),
   1036                     new CstString(v3));
   1037 
   1038             Constant constant = new CstFieldRef(CstType.intern(Type
   1039                     .internClassName(names[0])), field_nat);
   1040             DalvInsn dalvInsn = new CstInsn(insn.opcode,
   1041                     createSourcePosition(), RegisterSpecList.make(reg1_spec),
   1042                     constant);
   1043             addInsn(dalvInsn);
   1044         } else if (insn.args.compareToIgnoreCase(
   1045                 DopInfo.ARG_REG_REG_TYPE) == 0) {
   1046             int reg1_num = -1, reg2_num = -1;
   1047 
   1048             try {
   1049                 reg1_num = getRegNumberFromString(v1);
   1050             } catch (IllegalArgumentException e) {
   1051                 throwDasmError("Bad arguments for instruction " + name + "("
   1052                         + v1 + ")");
   1053             }
   1054 
   1055             try {
   1056                 reg2_num = getRegNumberFromString(v2);
   1057             } catch (IllegalArgumentException e) {
   1058                 throwDasmError("Bad arguments for instruction " + name + "("
   1059                         + v2 + ")");
   1060             }
   1061 
   1062             Type type = Type.internClassName(v3);
   1063             RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, type);
   1064             RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, type);
   1065             Constant constant = CstType.intern(type);
   1066             DalvInsn dalvInsn = new CstInsn(insn.opcode,
   1067                     createSourcePosition(), RegisterSpecList.make(reg1_spec,
   1068                             reg2_spec), constant);
   1069             addInsn(dalvInsn);
   1070         } else {
   1071             throwDasmError("Bad arguments for instruction " + name + "(" + v1
   1072                     + ", " + v2 + ", " + v3 + ")");
   1073         }
   1074     }
   1075 
   1076     /**
   1077      * Format: 22c (field@)
   1078      */
   1079     void addOpcode(String name, String v1, String v2, String v3, String v4)
   1080             throws DasmError {
   1081         if (PARSER_DEBUG)
   1082             System.out.println("addOpcode(" + name + ", " + v1 + ", " + v2
   1083                     + ", " + v3 + ", " + v4 + ")");
   1084         createOutputFinisher();
   1085         DopInfo insn = DopInfo.get(name);
   1086         if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_REG_FIELD) == 0) {
   1087             int reg1_num = -1, reg2_num = -1;
   1088 
   1089             try {
   1090                 reg1_num = getRegNumberFromString(v1);
   1091             } catch (IllegalArgumentException e) {
   1092                 throwDasmError("Bad arguments for instruction " + name + "("
   1093                         + v1 + ")");
   1094             }
   1095             try {
   1096                 reg2_num = getRegNumberFromString(v2);
   1097             } catch (IllegalArgumentException e) {
   1098                 throwDasmError("Bad arguments for instruction " + name + "("
   1099                         + v2 + ")");
   1100             }
   1101             // TODO: is Type.INT suitable?
   1102             RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
   1103             RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, Type.INT);
   1104 
   1105             String[] names = Utils.getClassFieldFromString(v3);
   1106 
   1107             CstNat field_nat = new CstNat(new CstString(names[1]),
   1108                     new CstString(v4));
   1109 
   1110             Constant constant = new CstFieldRef(CstType.intern(Type
   1111                     .internClassName(names[0])), field_nat);
   1112             DalvInsn dalvInsn = new CstInsn(insn.opcode,
   1113                     createSourcePosition(), RegisterSpecList.make(reg1_spec,
   1114                             reg2_spec), constant);
   1115             addInsn(dalvInsn);
   1116         } else if (insn.args.compareToIgnoreCase(
   1117                 DopInfo.ARG_REGRANGE_TYPE) == 0) {
   1118             String regs[] = Utils.splitRegList(v1);
   1119             if (regs.length != 2)
   1120                 throwDasmError("Bad arguments for instruction " + name + "("
   1121                         + v1 + ")");
   1122 
   1123             int regC = -1, regN = -1;
   1124             try {
   1125                 regC = getRegNumberFromString(regs[0]);
   1126             } catch (IllegalArgumentException e) {
   1127                 throwDasmError("Bad arguments for instruction " + name + "("
   1128                         + v1 + ")");
   1129             }
   1130             try {
   1131                 regN = getRegNumberFromString(regs[1]);
   1132             } catch (IllegalArgumentException e) {
   1133                 throwDasmError("Bad arguments for instruction " + name + "("
   1134                         + v1 + ")");
   1135             }
   1136 
   1137             if (regC >= regN)
   1138                 throwDasmError("Bad arguments for instruction " + name + "("
   1139                         + v1 + ")");
   1140 
   1141             int sz = regN - regC + 1;
   1142             RegisterSpecList reg_spec_list = new RegisterSpecList(sz);
   1143 
   1144             for (int i = 0; i < sz; i++) {
   1145                 reg_spec_list.set(i, RegisterSpec.make(regC + i, Type.INT));
   1146             }
   1147 
   1148             Type type;
   1149             try {
   1150                 type = Type.intern(v2);
   1151             } catch (IllegalArgumentException e) {
   1152                 // in case of exception, try to intern type as a class name
   1153                 // (Lclass_name;)
   1154                 type = Type.internClassName(v2);
   1155             }
   1156             Constant constant = CstType.intern(type);
   1157 
   1158             DalvInsn dalvInsn = new CstInsn(insn.opcode,
   1159                     createSourcePosition(), reg_spec_list, constant);
   1160             addInsn(dalvInsn);
   1161 
   1162         } else {
   1163             throwDasmError("Bad arguments for instruction " + name + "(" + v1
   1164                     + ", " + v2 + ", " + v3 + ", " + v4 + ")");
   1165         }
   1166     }
   1167 
   1168     /**
   1169      * used for relative branch targets (ie $+5, $-12, ...) Format: relative 22t
   1170      */
   1171     void addRelativeGoto(String name, String v1, String v2, int val)
   1172             throws DasmError {
   1173         if (PARSER_DEBUG)
   1174             System.out.println("addRelativeGoto(" + name + ", " + v1 + ", "
   1175                     + v2 + ", " + val + ")");
   1176         createOutputFinisher();
   1177         DopInfo insn = DopInfo.get(name);
   1178         if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_REG_ADDRESS) == 0) {
   1179             if (val == 0)
   1180                 throwDasmError("Bad arguments for instruction " + name + "("
   1181                         + val + ")");
   1182 
   1183             int reg1_num = -1, reg2_num = -1;
   1184 
   1185             try {
   1186                 reg1_num = getRegNumberFromString(v1);
   1187             } catch (IllegalArgumentException e) {
   1188                 throwDasmError("Bad arguments for instruction " + name + "("
   1189                         + v1 + ")");
   1190             }
   1191 
   1192             try {
   1193                 reg2_num = getRegNumberFromString(v2);
   1194             } catch (IllegalArgumentException e) {
   1195                 throwDasmError("Bad arguments for instruction " + name + "("
   1196                         + v2 + ")");
   1197             }
   1198 
   1199             RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
   1200             RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, Type.INT);
   1201             RegisterSpecList rsl = RegisterSpecList.make(reg1_spec, reg2_spec);
   1202             CodeAddress code_address = new CodeAddress(SourcePosition.NO_INFO);
   1203             if (val < 0) {
   1204                 output_finisher.insert(current_insn_number + val, code_address);
   1205                 current_insn_number++;
   1206             } else {
   1207                 unprocessed_relative_goto_addr.put(current_insn_number + val,
   1208                         code_address);
   1209             }
   1210             DalvInsn dalvInsn = new TargetInsn(insn.opcode,
   1211                     createSourcePosition(), rsl, code_address);
   1212             addInsn(dalvInsn);
   1213 
   1214         } else {
   1215             throwDasmError("Bad arguments for instruction " + name + "(" + val
   1216                     + ")");
   1217         }
   1218     }
   1219 
   1220     /**
   1221      * used for instructions that take two word parameters (register name is
   1222      * treated as word) and one literal Format: 22b, 22s
   1223      */
   1224     void addOpcode(String name, String v1, String v2, int v3) throws DasmError {
   1225         if (PARSER_DEBUG)
   1226             System.out.println("addOpcode(" + name + ", " + v1 + ", " + v2
   1227                     + ")");
   1228         createOutputFinisher();
   1229         DopInfo insn = DopInfo.get(name);
   1230 
   1231         if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_REG_LITERAL) == 0) {
   1232             int reg1_num = -1, reg2_num = -1;
   1233 
   1234             try {
   1235                 reg1_num = getRegNumberFromString(v1);
   1236             } catch (IllegalArgumentException e) {
   1237                 throwDasmError("Bad arguments for instruction " + name + "("
   1238                         + v1 + ")");
   1239             }
   1240 
   1241             try {
   1242                 reg2_num = getRegNumberFromString(v2);
   1243             } catch (IllegalArgumentException e) {
   1244                 throwDasmError("Bad arguments for instruction " + name + "("
   1245                         + v2 + ")");
   1246             }
   1247             // TODO: is Type.INT suitable for any opcodes?
   1248             RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
   1249             RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, Type.INT);
   1250             Constant constant = CstInteger.make(v3);
   1251             DalvInsn dalvInsn = new CstInsn(insn.opcode,
   1252                     createSourcePosition(), RegisterSpecList.make(reg1_spec,
   1253                             reg2_spec), constant);
   1254             addInsn(dalvInsn);
   1255         } else {
   1256             throwDasmError("Bad arguments for instruction " + name + "(" + v1
   1257                     + ", " + v2 + ", " + v3 + ")");
   1258         }
   1259     }
   1260 
   1261     /**
   1262      * used for fill-array-data instruction Format: 31t fill-array-data
   1263      * instruction has the syntax: fill-array-data &lt;register&gt; &lt;type&gt;
   1264      * &lt;value1&gt; &lt;value2&gt; .... fill-array-data-end For example:
   1265      * fill-array-data v7 I 1 2 3 4 5 fill-array-data-end
   1266      */
   1267     void newFillArrayData(String reg, String type) throws DasmError {
   1268         if (PARSER_DEBUG)
   1269             System.out.println("newFillArrayData(" + reg + ", " + type + ")");
   1270 
   1271         try {
   1272             fill_data_reg = getRegNumberFromString(reg);
   1273         } catch (IllegalArgumentException e) {
   1274             throwDasmError("Bad arguments for fill-array-data (" + reg + ")");
   1275         }
   1276 
   1277         fill_array_data_type = type;
   1278         fill_array_data_values = new Vector<Number>();
   1279     }
   1280 
   1281     /**
   1282      * add new value to data block
   1283      */
   1284     void addFillArrayData(Number num) throws DasmError {
   1285         if (PARSER_DEBUG) System.out.println("addFillArrayData(" + num + ")");
   1286         fill_array_data_values.add(num);
   1287     }
   1288 
   1289     /**
   1290      * called by fill-array-data-end
   1291      */
   1292     void endFillArrayData() throws DasmError {
   1293         if (PARSER_DEBUG) System.out.println("endFillArrayData");
   1294         int sz = fill_array_data_values.size();
   1295         ArrayList<Constant> values = new ArrayList<Constant>(sz);
   1296         CstType arrayType = CstType.intern(Type.intern("["
   1297                 + fill_array_data_type));
   1298         for (int i = 0; i < sz; i++) {
   1299             Constant constant;
   1300             Number num = fill_array_data_values.elementAt(i);
   1301             if (arrayType == CstType.LONG_ARRAY) {
   1302                 constant = CstLong.make(num.longValue());
   1303             } else if (arrayType == CstType.FLOAT_ARRAY) {
   1304                 constant = CstFloat
   1305                         .make(Float.floatToIntBits(num.floatValue()));
   1306             } else if (arrayType == CstType.DOUBLE_ARRAY) {
   1307                 constant = CstDouble.make(Double.doubleToLongBits(num
   1308                         .doubleValue()));
   1309             } else if (arrayType == CstType.BOOLEAN_ARRAY) {
   1310                 constant = CstBoolean.make(num.intValue());
   1311             } else if (arrayType == CstType.BYTE_ARRAY) {
   1312                 constant = CstByte.make(num.intValue());
   1313             } else if (arrayType == CstType.CHAR_ARRAY) {
   1314                 constant = CstChar.make(num.intValue());
   1315             } else if (arrayType == CstType.SHORT_ARRAY) {
   1316                 constant = CstShort.make(num.intValue());
   1317             } else {
   1318                 constant = CstInteger.make(num.intValue());
   1319             }
   1320             values.add(constant);
   1321         }
   1322 
   1323         CodeAddress insn_addr = new CodeAddress(createSourcePosition());
   1324         CodeAddress data_addr = new CodeAddress(SourcePosition.NO_INFO);
   1325         DalvInsn dalvInsn = new TargetInsn(Dops.FILL_ARRAY_DATA,
   1326                 createSourcePosition(), RegisterSpecList
   1327                         .make(RegisterSpec.make(fill_data_reg, Type
   1328                                 .intern(fill_array_data_type))), data_addr);
   1329         OddSpacer spacer = new OddSpacer(SourcePosition.NO_INFO);
   1330         ArrayData array_data = new ArrayData(SourcePosition.NO_INFO, insn_addr,
   1331                 values, arrayType);
   1332 
   1333         addInsn(insn_addr);
   1334         addInsn(dalvInsn);
   1335         data_blocks.add(spacer);
   1336         data_blocks.add(data_addr);
   1337         data_blocks.add(array_data);
   1338 
   1339         fill_array_data_values = null;
   1340         fill_array_data_type = null;
   1341     }
   1342 
   1343     /**
   1344      * used for packed-switch instruction Format: 31t packed-switch instruction
   1345      * has the syntax: packed-switch &lt;register&gt; &lt;lowest&gt;
   1346      * &lt;label1&gt; &lt;label2&gt; .... packed-switch-end For example:
   1347      * packed-switch v3, -1 Label9 Label6 Label6 Label12 Label12
   1348      * packed-switch-end
   1349      */
   1350     void newPackedSwitch(String reg, int first_key) throws DasmError {
   1351         if (PARSER_DEBUG)
   1352             System.out.println("newPackedSwitch(" + reg + ", " + first_key
   1353                     + ")");
   1354 
   1355         try {
   1356             switch_reg = getRegNumberFromString(reg);
   1357         } catch (IllegalArgumentException e) {
   1358             throwDasmError("Bad arguments for packed-switch (" + reg + ")");
   1359         }
   1360 
   1361         packed_switch_first_key = first_key;
   1362         packed_switch_current_key = 0;
   1363         switch_targets = new Vector<Object>();
   1364         switch_keys = new IntList();
   1365     }
   1366 
   1367     /**
   1368      * add new target to packed-switch
   1369      */
   1370     void addPackedSwitchData(String target) throws DasmError {
   1371         if (PARSER_DEBUG)
   1372             System.out.println("addPackedSwitchData(" + target + ")");
   1373         switch_targets.add(target);
   1374         switch_keys.add(packed_switch_first_key + packed_switch_current_key);
   1375         packed_switch_current_key++;
   1376     }
   1377 
   1378     /**
   1379      * add new target to packed-switch
   1380      */
   1381     void addPackedSwitchData(int target) throws DasmError {
   1382         if (PARSER_DEBUG)
   1383             System.out.println("addPackedSwitchData(" + target + ")");
   1384         switch_targets.add(new Integer(target));
   1385         switch_keys.add(packed_switch_first_key + packed_switch_current_key);
   1386         packed_switch_current_key++;
   1387     }
   1388 
   1389     /**
   1390      * used for sparse-switch instruction Format: 31t sparse-switch instruction
   1391      * has the syntax: sparse-switch &lt;register&gt; &lt;lowest&gt;
   1392      * &lt;int1&gt; : &lt;label1&gt; &lt;int2&gt; : &lt;label2&gt; ....
   1393      * sparse-switch-end For example: sparse-switch v3 -1 : Label9 10 : Label12
   1394      * 15 : Label12 sparse-switch-end
   1395      */
   1396     void newSparseSwitch(String reg) throws DasmError {
   1397         if (PARSER_DEBUG) System.out.println("newSparseSwitch(" + reg + ")");
   1398 
   1399         try {
   1400             switch_reg = getRegNumberFromString(reg);
   1401         } catch (IllegalArgumentException e) {
   1402             throwDasmError("Bad arguments for sparse-switch (" + reg + ")");
   1403         }
   1404 
   1405         switch_targets = new Vector<Object>();
   1406         switch_keys = new IntList();
   1407     }
   1408 
   1409     /**
   1410      * add new target to sparse-switch
   1411      */
   1412     void addSparseSwitchData(int key, String target) throws DasmError {
   1413         if (PARSER_DEBUG)
   1414             System.out.println("addSparseSwitchData(" + key + ", " + target
   1415                     + ")");
   1416         switch_targets.add(target);
   1417         switch_keys.add(key);
   1418     }
   1419 
   1420     /**
   1421      * add new target to sparse-switch
   1422      */
   1423     void addSparseSwitchData(int key, int target) throws DasmError {
   1424         if (PARSER_DEBUG)
   1425             System.out.println("addSparseSwitchData(" + key + ", " + target
   1426                     + ")");
   1427         switch_targets.add(new Integer(target));
   1428         switch_keys.add(key);
   1429     }
   1430 
   1431     /**
   1432      * called by sparse-switch-end or packed-switch-end
   1433      */
   1434     void endSwitch() throws DasmError {
   1435         if (PARSER_DEBUG) System.out.println("endSwitch");
   1436         int sz = switch_targets.size();
   1437 
   1438         CodeAddress targets[] = new CodeAddress[sz];
   1439         for (int i = 0; i < sz; i++) {
   1440             Object o = switch_targets.elementAt(i);
   1441             CodeAddress addr;
   1442             if (o instanceof String) {
   1443                 String t = (String) o;
   1444                 LabelTableEntry lte = labels_table.get(t);
   1445                 if (lte == null) {
   1446                     CodeAddress code_address = new CodeAddress(
   1447                             SourcePosition.NO_INFO);
   1448                     lte = new LabelTableEntry(code_address, false);
   1449                     labels_table.put(t, lte);
   1450                 }
   1451                 addr = lte.code_address;
   1452             } else {
   1453                 Integer t = (Integer) o;
   1454 
   1455                 addr = new CodeAddress(SourcePosition.NO_INFO);
   1456                 if (t < 0) {
   1457                     output_finisher.insert(current_insn_number + t, addr);
   1458                     current_insn_number++;
   1459                 } else {
   1460                     unprocessed_relative_goto_addr.put(current_insn_number + t,
   1461                             addr);
   1462                 }
   1463             }
   1464             targets[i] = addr;
   1465         }
   1466 
   1467         CodeAddress insn_addr = new CodeAddress(createSourcePosition());
   1468         CodeAddress data_addr = new CodeAddress(SourcePosition.NO_INFO);
   1469         OddSpacer spacer = new OddSpacer(SourcePosition.NO_INFO);
   1470         SwitchData switch_data = new SwitchData(SourcePosition.NO_INFO,
   1471                 insn_addr, switch_keys, targets);
   1472         DalvInsn dalvInsn = new TargetInsn(switch_data.isPacked()
   1473                 ? Dops.PACKED_SWITCH : Dops.SPARSE_SWITCH,
   1474                 createSourcePosition(), RegisterSpecList.make(RegisterSpec
   1475                         .make(switch_reg, Type.INT)), data_addr);
   1476 
   1477         addInsn(insn_addr);
   1478         addInsn(dalvInsn);
   1479         data_blocks.add(spacer);
   1480         data_blocks.add(data_addr);
   1481         data_blocks.add(switch_data);
   1482 
   1483         switch_targets = null;
   1484         switch_keys = null;
   1485     }
   1486 
   1487     /*
   1488      * ========================================================================
   1489      * === UTILITY METHODS
   1490      * ========================================================================
   1491      */
   1492 
   1493     /**
   1494      * Creates instance of SourcePosition for current line
   1495      */
   1496     protected SourcePosition createSourcePosition() {
   1497         return new SourcePosition(new CstString(filename), -1, line_num);
   1498     }
   1499 
   1500     /**
   1501      * Creates TypeList from list of types
   1502      */
   1503     protected TypeList createTypeListFromStrings(Vector<String> strings) {
   1504         StdTypeList tl;
   1505 
   1506         if (strings.size() == 0)
   1507             tl = StdTypeList.EMPTY;
   1508         else {
   1509             int sz = strings.size();
   1510             tl = new StdTypeList(sz);
   1511             for (int i = 0; i < sz; i++) {
   1512                 tl.set(i, Type.internClassName(strings.elementAt(i)));
   1513             }
   1514         }
   1515         return tl;
   1516     }
   1517 
   1518     /**
   1519      * Creates processor of instruction list.
   1520      */
   1521     private void createOutputFinisher() {
   1522         if (output_finisher == null)
   1523             output_finisher = new OutputFinisher(dexOptions, 5, regs_count);
   1524     }
   1525 
   1526     /**
   1527      * Returns register number from "vX" string.
   1528      */
   1529     private int getRegNumberFromString(String val)
   1530             throws IllegalArgumentException {
   1531         int reg_num;
   1532         int l = RegisterSpec.PREFIX.length();
   1533         if (val.length() <= l
   1534                 || val.substring(0, l).compareToIgnoreCase(
   1535                         RegisterSpec.PREFIX) != 0)
   1536             throw new IllegalArgumentException("Wrong register name prefix");
   1537 
   1538         try {
   1539             reg_num = Integer.parseInt(val.substring(l));
   1540         } catch (Exception e) {
   1541             throw new IllegalArgumentException("Wrong register name");
   1542         }
   1543         return reg_num;
   1544     }
   1545 
   1546     /**
   1547      * Adds new instruction to instruction list.
   1548      */
   1549     private void addInsn(DalvInsn insn) {
   1550         createOutputFinisher();
   1551         CodeAddress code_address = unprocessed_relative_goto_addr
   1552                 .get(current_insn_number);
   1553         if (code_address != null) {
   1554             output_finisher.add(code_address);
   1555             unprocessed_relative_goto_addr.remove(current_insn_number);
   1556             current_insn_number++;
   1557         }
   1558         output_finisher.add(insn);
   1559         current_insn_number++;
   1560     }
   1561 
   1562     /*
   1563      * ========================================================================
   1564      * === READER and WRITER
   1565      * ========================================================================
   1566      */
   1567 
   1568     /**
   1569      * Writes the binary data for the class represented by this ClassFile object
   1570      * to the specified output stream, using the Java Class File format. Throws
   1571      * either an IOException or a dasmError if something goes wrong.
   1572      */
   1573     public void write(OutputStream outp, FileWriter human_readable)
   1574             throws IOException, DasmError {
   1575         dexFile.writeTo(outp, human_readable, true);
   1576     }
   1577 
   1578     /**
   1579      * Parses a .d file, converting it internally into a binary representation.
   1580      * If something goes wrong, this throws one of an IOException, or a
   1581      * dasmError, or one of a few other exceptions.
   1582      *
   1583      * @param input
   1584      *            is the stream containing the Dalvik assembly code for the
   1585      *            class.
   1586      * @param name
   1587      *            is the name of the stream. This name will be concatenated to
   1588      *            error messages printed to System.err.
   1589      * @param numberLines
   1590      *            true if you want DAsm to generate line numbers automatically,
   1591      *            based on the assembly source, or false if you are using the
   1592      *            ".line" directive and don't want DAsm to help out.
   1593      */
   1594     public void readD(Reader input, String name, boolean numberLines)
   1595             throws IOException, Exception {
   1596 
   1597         // TODO: numberLines?
   1598         errors = 0;
   1599         filename = name;
   1600         source_name = name;
   1601         class_header = false;
   1602         classDef = null;
   1603         dexFile = new DexFile(dexOptions);
   1604 
   1605         scanner = new Scanner(input);
   1606         parser parse_obj = new parser(this, scanner);
   1607 
   1608 
   1609         if (PARSER_DEBUG) {
   1610             // for debugging
   1611             parse_obj.debug_parse();
   1612         } else {
   1613             parse_obj.parse();
   1614         }
   1615 
   1616     }
   1617 }
   1618