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.rop.type.Prototype;
     59 import com.android.dx.util.IntList;
     60 
     61 import java.io.FileWriter;
     62 import java.io.IOException;
     63 import java.io.OutputStream;
     64 import java.io.Reader;
     65 import java.util.ArrayList;
     66 import java.util.Enumeration;
     67 import java.util.Hashtable;
     68 import java.util.Vector;
     69 
     70 //TODO: copyright notice
     71 
     72 /**
     73  * This class represents the public API for Dasm. It has two main methods (readD
     74  * and write) and few utility methods. To compile .d file: -create DAsm instance
     75  * -call readD() to read and parse content of .d file -call write() to write out
     76  * binary representation of .d file. .d file can contain several classes and/or
     77  * intefaces declarations.
     78  */
     79 
     80 public class DAsm {
     81     private static final boolean PARSER_DEBUG = false;
     82 
     83     // number of errors reported in a file.
     84     int errors;
     85 
     86     // options for dex output
     87     DexOptions dexOptions = new DexOptions();
     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()) {
    407             access |= (AccessFlags.ACC_CONSTRUCTOR | AccessFlags.ACC_STATIC);
    408         } else if (method_nat.isInstanceInit()) {
    409             access |= AccessFlags.ACC_CONSTRUCTOR;
    410         }
    411 
    412         method_acc = access;
    413     }
    414 
    415     /**
    416      * called by the .end method directive to end the definition for a method
    417      */
    418     void endMethod() throws DasmError {
    419         if (PARSER_DEBUG) System.out.println("endMethod()");
    420 
    421         // add packed-switch, sparse-switch, fill-array-data data blocks at the
    422         // end of method
    423         int sz = data_blocks.size();
    424         for (int i = 0; i < sz; i++) {
    425             addInsn(data_blocks.elementAt(i));
    426         }
    427         data_blocks.clear();
    428 
    429         // check jump targets
    430         if (unprocessed_relative_goto_addr.size() != 0) {
    431             report_error("Relative forward jump offset too big.");
    432         }
    433         Enumeration<String> e = labels_table.keys();
    434         while (e.hasMoreElements()) {
    435             String key = e.nextElement();
    436             LabelTableEntry lte = labels_table.get(key);
    437             if (lte.planted == false) {
    438                 report_error("Label " + key + " not found.");
    439             }
    440         }
    441 
    442         TypeList tl = createTypeListFromStrings(throw_list);
    443 
    444         CstMethodRef meth = new CstMethodRef(classDef.getThisClass(),
    445                 method_nat);
    446         DalvCode code = null;
    447         // output_finisher may be null at this point if method is native
    448         if (output_finisher != null)
    449             code = new DalvCode(PositionList.NONE, output_finisher,
    450                     catch_builder);
    451         enc_method = new EncodedMethod(meth, method_acc, code, tl);
    452 
    453         if (meth.isInstanceInit() || meth.isClassInit()
    454                 || (method_acc & AccessFlags.ACC_STATIC) != 0
    455                 || (method_acc & AccessFlags.ACC_PRIVATE) != 0) {
    456             classDef.addDirectMethod(enc_method);
    457         } else {
    458             classDef.addVirtualMethod(enc_method);
    459         }
    460         catch_builder = null;
    461         labels_table = null;
    462     }
    463 
    464     /**
    465      * used by the .limit regs directive
    466      */
    467     void setRegsSize(int v) throws DasmError {
    468         if (PARSER_DEBUG) System.out.println("setRegsSize(" + v + ")");
    469         regs_count = v;
    470     }
    471 
    472     /**
    473      * used by the .throws directive
    474      */
    475     void addThrow(String name) throws DasmError {
    476         if (PARSER_DEBUG) System.out.println("addThrow(" + name + ")");
    477         throw_list.add(name);
    478     }
    479 
    480     /**
    481      * used by the .catch directive
    482      */
    483     void addCatch(String name, String start_lab, String end_lab,
    484             String branch_lab) throws DasmError {
    485         if (PARSER_DEBUG)
    486             System.out.println("addCatch(" + name + ", " + start_lab + ", "
    487                     + end_lab + ", " + branch_lab + ")");
    488         catch_builder.add(name, start_lab, end_lab, branch_lab);
    489     }
    490 
    491     void addCatch(String name, int start_off, int end_off, int branch_off)
    492             throws DasmError {
    493         if (PARSER_DEBUG)
    494             System.out.println("addCatch(" + name + ", " + start_off + ", "
    495                     + end_off + ", " + branch_off + ")");
    496         throw new IllegalStateException(
    497                 "addCatch(String, int, int, int) is not implemented yet");
    498     }
    499 
    500 
    501     /**
    502      * defines a label
    503      */
    504     void plantLabel(String name) throws DasmError {
    505         if (PARSER_DEBUG) System.out.println("plantLabel(" + name + ")");
    506         createOutputFinisher();
    507         LabelTableEntry lte = labels_table.get(name);
    508         if (lte != null) {
    509             if (lte.planted == true)
    510                 report_error("Label " + name + " already defined");
    511             else {
    512                 lte.planted = true;
    513                 addInsn(lte.code_address);
    514             }
    515         } else {
    516             CodeAddress code_address = new CodeAddress(createSourcePosition());
    517             addInsn(code_address);
    518             labels_table.put(name, new LabelTableEntry(code_address, true));
    519         }
    520     }
    521 
    522 
    523     /**
    524      * used for instructions that take no arguments Format: 10x
    525      */
    526     void addOpcode(String name) throws DasmError {
    527         if (PARSER_DEBUG) System.out.println("addOpcode(" + name + ")");
    528         createOutputFinisher();
    529         DopInfo insn = DopInfo.get(name);
    530         if (insn.args.equals("")) {
    531             DalvInsn dalvInsn = new SimpleInsn(insn.opcode,
    532                     createSourcePosition(), RegisterSpecList.EMPTY);
    533             addInsn(dalvInsn);
    534         } else {
    535             throwDasmError("Missing arguments for instruction " + name);
    536         }
    537     }
    538 
    539     /**
    540      * used for instructions that take a word as a parameter (register name is
    541      * treated as word) Format: 11x, 10t, 20t, 30t
    542      */
    543     void addOpcode(String name, String val) throws DasmError {
    544         if (PARSER_DEBUG)
    545             System.out.println("addOpcode(" + name + ", " + val + ")");
    546         createOutputFinisher();
    547         DopInfo insn = DopInfo.get(name);
    548         if (insn.args.compareToIgnoreCase(DopInfo.ARG_REGISTER) == 0) {
    549             int reg_num = -1;
    550 
    551             try {
    552                 reg_num = getRegNumberFromString(val);
    553             } catch (IllegalArgumentException e) {
    554                 throwDasmError("Bad arguments for instruction " + name + "("
    555                         + val + ")");
    556             }
    557             // TODO: is Type.INT suitable for any opcodes? Or it should be
    558             // Type.OBJECT for return-object, for example?
    559             RegisterSpec reg_spec = RegisterSpec.make(reg_num, Type.INT);
    560             DalvInsn dalvInsn = new SimpleInsn(insn.opcode,
    561                     createSourcePosition(), RegisterSpecList.make(reg_spec));
    562             addInsn(dalvInsn);
    563         } else if (insn.args.compareToIgnoreCase(DopInfo.ARG_ADDRESS) == 0) {
    564             LabelTableEntry lte = labels_table.get(val);
    565             if (lte == null) {
    566                 CodeAddress code_address = new CodeAddress(
    567                         SourcePosition.NO_INFO);
    568                 lte = new LabelTableEntry(code_address, false);
    569                 labels_table.put(val, lte);
    570             }
    571             DalvInsn dalvInsn = new TargetInsn(insn.opcode,
    572                     createSourcePosition(), RegisterSpecList.EMPTY,
    573                     lte.code_address);
    574             addInsn(dalvInsn);
    575         } else {
    576             throwDasmError("Bad arguments for instruction " + name + "(" + val
    577                     + ")");
    578         }
    579     }
    580 
    581     /**
    582      * used for relative branch targets (ie $+5, $-12, ...) Format: relative
    583      * 10t, 20t, 30t
    584      */
    585     void addRelativeGoto(String name, int val) throws DasmError {
    586         if (PARSER_DEBUG)
    587             System.out.println("addRelativeGoto(" + name + ", " + val + ")");
    588         createOutputFinisher();
    589         DopInfo insn = DopInfo.get(name);
    590         if (insn.args.compareToIgnoreCase(DopInfo.ARG_ADDRESS) == 0) {
    591             if (val == 0)
    592                 throwDasmError("Bad arguments for instruction " + name + "("
    593                         + val + ")");
    594 
    595             CodeAddress code_address = new CodeAddress(SourcePosition.NO_INFO);
    596             if (val < 0) {
    597                 output_finisher.insert(current_insn_number + val, code_address);
    598                 current_insn_number++;
    599             } else {
    600                 unprocessed_relative_goto_addr.put(current_insn_number + val,
    601                         code_address);
    602             }
    603             DalvInsn dalvInsn = new TargetInsn(insn.opcode,
    604                     createSourcePosition(), RegisterSpecList.EMPTY,
    605                     code_address);
    606             addInsn(dalvInsn);
    607 
    608         } else {
    609             throwDasmError("Bad arguments for instruction " + name + "(" + val
    610                     + ")");
    611         }
    612     }
    613 
    614     /**
    615      * used for instructions that take two word parameters (register name is
    616      * treated as word) Format: 12x, 22x, 32x, 21t, 21c (string@, type@), 31c,
    617      * 35c, 3rc
    618      */
    619     void addOpcode(String name, String v1, String v2) throws DasmError {
    620         if (PARSER_DEBUG)
    621             System.out.println("addOpcode(" + name + ", " + v1 + ", " + v2
    622                     + ")");
    623         createOutputFinisher();
    624         DopInfo insn = DopInfo.get(name);
    625 
    626         if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_REG) == 0) {
    627             int reg1_num = -1, reg2_num = -1;
    628 
    629             try {
    630                 reg1_num = getRegNumberFromString(v1);
    631             } catch (IllegalArgumentException e) {
    632                 throwDasmError("Bad arguments for instruction " + name + "("
    633                         + v1 + ")");
    634             }
    635 
    636             try {
    637                 reg2_num = getRegNumberFromString(v2);
    638             } catch (IllegalArgumentException e) {
    639                 throwDasmError("Bad arguments for instruction " + name + "("
    640                         + v2 + ")");
    641             }
    642             // TODO: is Type.INT suitable for any opcodes?
    643             RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
    644             RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, Type.INT);
    645             DalvInsn dalvInsn = new SimpleInsn(insn.opcode,
    646                     createSourcePosition(), RegisterSpecList.make(reg1_spec,
    647                             reg2_spec));
    648             addInsn(dalvInsn);
    649         } else if (insn.args.compareToIgnoreCase(
    650                 DopInfo.ARG_REG_ADDRESS) == 0) {
    651             int reg1_num = -1;
    652 
    653             try {
    654                 reg1_num = getRegNumberFromString(v1);
    655             } catch (IllegalArgumentException e) {
    656                 throwDasmError("Bad arguments for instruction " + name + "("
    657                         + v1 + ")");
    658             }
    659 
    660             LabelTableEntry lte = labels_table.get(v2);
    661             if (lte == null) {
    662                 CodeAddress code_address = new CodeAddress(
    663                         SourcePosition.NO_INFO);
    664                 lte = new LabelTableEntry(code_address, false);
    665                 labels_table.put(v2, lte);
    666             }
    667 
    668             RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
    669             DalvInsn dalvInsn = new TargetInsn(insn.opcode,
    670                     createSourcePosition(), RegisterSpecList.make(reg1_spec),
    671                     lte.code_address);
    672             addInsn(dalvInsn);
    673         } else if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_STRING) == 0) {
    674             int reg1_num = -1;
    675 
    676             try {
    677                 reg1_num = getRegNumberFromString(v1);
    678             } catch (IllegalArgumentException e) {
    679                 throwDasmError("Bad arguments for instruction " + name + "("
    680                         + v1 + ")");
    681             }
    682             RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.STRING);
    683             Constant constant = new CstString(v2);
    684             DalvInsn dalvInsn = new CstInsn(insn.opcode,
    685                     createSourcePosition(), RegisterSpecList.make(reg1_spec),
    686                     constant);
    687             addInsn(dalvInsn);
    688         } else if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_TYPE) == 0) {
    689             int reg1_num = -1;
    690 
    691             try {
    692                 reg1_num = getRegNumberFromString(v1);
    693             } catch (IllegalArgumentException e) {
    694                 throwDasmError("Bad arguments for instruction " + name + "("
    695                         + v1 + ")");
    696             }
    697             Type type;
    698             try {
    699                 // try to intern it as primitive type first
    700                 type = Type.intern(v2);
    701             } catch (IllegalArgumentException e) {
    702                 type = Type.internClassName(v2);
    703             }
    704 
    705             RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, type);
    706             Constant constant = CstType.intern(type);
    707             DalvInsn dalvInsn = new CstInsn(insn.opcode,
    708                     createSourcePosition(), RegisterSpecList.make(reg1_spec),
    709                     constant);
    710             addInsn(dalvInsn);
    711         } else if (insn.args.compareToIgnoreCase(DopInfo.ARG_REGLIST_TYPE) == 0
    712                 || insn.args.compareToIgnoreCase(
    713                         DopInfo.ARG_REGLIST_METHOD) == 0
    714                 || insn.args.compareToIgnoreCase(
    715                         DopInfo.ARG_REGLIST_INTFMETHOD) == 0) {
    716             RegisterSpecList reg_spec_list = RegisterSpecList.EMPTY;
    717             String regs[] = Utils.splitRegList(v1);
    718             if (regs != null) {
    719                 int rn = regs.length;
    720                 if (rn == 0 || rn > 5)
    721                     throwDasmError("Bad arguments for instruction " + name
    722                             + "(" + v1 + ")");
    723                 int reg_num[] = new int[rn];
    724 
    725                 reg_spec_list = new RegisterSpecList(rn);
    726 
    727                 for (int i = 0; i < rn; i++) {
    728                     try {
    729                         reg_num[i] = getRegNumberFromString(regs[i]);
    730                     } catch (IllegalArgumentException e) {
    731                         throwDasmError("Bad arguments for instruction " + name
    732                                 + "(" + v1 + ")");
    733                     }
    734                     reg_spec_list.set(i, RegisterSpec
    735                             .make(reg_num[i], Type.INT));
    736                 }
    737             }
    738             Constant constant;
    739             if (insn.args.compareToIgnoreCase(DopInfo.ARG_REGLIST_TYPE) == 0) {
    740                 // filled-new-array
    741                 Type type;
    742                 try {
    743                     type = Type.intern(v2);
    744                 } catch (IllegalArgumentException e) {
    745                     // in case of exception, try to intern type as a class name
    746                     // (Lclass_name;)
    747                     type = Type.internClassName(v2);
    748                 }
    749                 constant = CstType.intern(type);
    750             } else {
    751                 // invoke-kind
    752                 String[] names = Utils.getClassMethodSignatureFromString(v2);
    753                 CstNat method_nat = new CstNat(new CstString(names[1]),
    754                         new CstString(names[2]));
    755 
    756                 /*
    757                  * if(insn.args.compareToIgnoreCase(
    758                  *          DopInfo.ARG_REGLIST_INTFMETHOD
    759                  * ) == 0) constant = new
    760                  * CstInterfaceMethodRef(CstType.intern(Type
    761                  * .internClassName(names[0])), method_nat); else
    762                  */
    763                 constant = new CstMethodRef(CstType.intern(Type
    764                         .internClassName(names[0])), method_nat);
    765             }
    766 
    767             DalvInsn dalvInsn = new CstInsn(insn.opcode,
    768                     createSourcePosition(), reg_spec_list, constant);
    769             addInsn(dalvInsn);
    770 
    771         } else if (insn.args.compareToIgnoreCase(
    772                         DopInfo.ARG_REGRANGE_TYPE) == 0
    773                 || insn.args.compareToIgnoreCase(
    774                         DopInfo.ARG_REGRANGE_METHOD) == 0
    775                 || insn.args.compareToIgnoreCase(
    776                         DopInfo.ARG_REGRANGE_INTFMETHOD) == 0) {
    777             String regs[] = Utils.splitRegList(v1);
    778             RegisterSpecList reg_spec_list;
    779             if (regs != null && regs.length > 0) {
    780                 int regC = -1, regN = -1;
    781                 try {
    782                     regC = getRegNumberFromString(regs[0]);
    783                 } catch (IllegalArgumentException e) {
    784                     throwDasmError("Bad arguments for instruction " + name
    785                             + "(" + v1 + ")");
    786                 }
    787 
    788                 if (regs.length > 1) {
    789                     try {
    790                         regN = getRegNumberFromString(regs[1]);
    791                     } catch (IllegalArgumentException e) {
    792                         throwDasmError("Bad arguments for instruction " + name
    793                                 + "(" + v1 + ")");
    794                     }
    795 
    796                     if (regC >= regN)
    797                         throwDasmError("Bad arguments for instruction " + name
    798                                 + "(" + v1 + ")");
    799                 } else
    800                     regN = regC;
    801 
    802 
    803                 int sz = regN - regC + 1;
    804                 reg_spec_list = new RegisterSpecList(sz);
    805 
    806                 for (int i = 0; i < sz; i++) {
    807                     reg_spec_list.set(i, RegisterSpec.make(regC + i, Type.INT));
    808                 }
    809             } else
    810                 reg_spec_list = RegisterSpecList.EMPTY;
    811 
    812             Constant constant;
    813             if (insn.args.compareToIgnoreCase(DopInfo.ARG_REGRANGE_TYPE) == 0) {
    814                 // filled-new-array/range
    815                 Type type;
    816                 try {
    817                     type = Type.intern(v2);
    818                 } catch (IllegalArgumentException e) {
    819                     // in case of exception, try to intern type as a class name
    820                     // (Lclass_name;)
    821                     type = Type.internClassName(v2);
    822                 }
    823                 constant = CstType.intern(type);
    824             } else {
    825                 // invoke-kind/range
    826                 String[] names = Utils.getClassMethodSignatureFromString(v2);
    827                 CstNat method_nat = new CstNat(new CstString(names[1]),
    828                         new CstString(names[2]));
    829 
    830                 /*
    831                  * if(insn.args.compareToIgnoreCase(
    832                  *         DopInfo.ARG_REGRANGE_INTFMETHOD
    833                  * ) == 0) constant = new
    834                  * CstInterfaceMethodRef(CstType.intern(Type
    835                  * .internClassName(names[0])), method_nat); else
    836                  */
    837                 constant = new CstMethodRef(CstType.intern(Type
    838                         .internClassName(names[0])), method_nat);
    839             }
    840 
    841             DalvInsn dalvInsn = new CstInsn(insn.opcode,
    842                     createSourcePosition(), reg_spec_list, constant);
    843             addInsn(dalvInsn);
    844 
    845         } else {
    846             throwDasmError("Bad arguments for instruction " + name + "(" + v1
    847                     + ", " + v2 + ")");
    848         }
    849     }
    850 
    851     /**
    852      * used for relative branch targets (ie $+5, $-12, ...) Format: relative 21t
    853      */
    854     void addRelativeGoto(String name, String v1, int val) throws DasmError {
    855         if (PARSER_DEBUG)
    856             System.out.println("addRelativeGoto(" + name + ", " + v1 + ", "
    857                     + val + ")");
    858         createOutputFinisher();
    859         DopInfo insn = DopInfo.get(name);
    860         if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_ADDRESS) == 0) {
    861             if (val == 0)
    862                 throwDasmError("Bad arguments for instruction " + name + "("
    863                         + val + ")");
    864 
    865             int reg1_num = -1;
    866             try {
    867                 reg1_num = getRegNumberFromString(v1);
    868             } catch (IllegalArgumentException e) {
    869                 throwDasmError("Bad arguments for instruction " + name + "("
    870                         + v1 + ")");
    871             }
    872 
    873             RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
    874             RegisterSpecList rsl = RegisterSpecList.make(reg1_spec);
    875             CodeAddress code_address = new CodeAddress(SourcePosition.NO_INFO);
    876             if (val < 0) {
    877                 output_finisher.insert(current_insn_number + val, code_address);
    878                 current_insn_number++;
    879             } else {
    880                 unprocessed_relative_goto_addr.put(current_insn_number + val,
    881                         code_address);
    882             }
    883             DalvInsn dalvInsn = new TargetInsn(insn.opcode,
    884                     createSourcePosition(), rsl, code_address);
    885             addInsn(dalvInsn);
    886 
    887         } else {
    888             throwDasmError("Bad arguments for instruction " + name + "(" + val
    889                     + ")");
    890         }
    891     }
    892 
    893     /**
    894      * used for instructions that take one word parameter (register name is
    895      * treated as word) and one literal Format: 11n, 21s, 31i, 21h, 51l
    896      */
    897     void addOpcode(String name, String v1, Number v2) throws DasmError {
    898         if (PARSER_DEBUG)
    899             System.out.println("addOpcode(" + name + ", " + v1 + ", " + v2
    900                     + ")");
    901         createOutputFinisher();
    902         DopInfo insn = DopInfo.get(name);
    903         if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_LITERAL) == 0) {
    904             int reg1_num = -1;
    905 
    906             try {
    907                 reg1_num = getRegNumberFromString(v1);
    908             } catch (IllegalArgumentException e) {
    909                 throwDasmError("Bad arguments for instruction " + name + "("
    910                         + v1 + ")");
    911             }
    912 
    913             RegisterSpec reg1_spec;
    914             Constant constant;
    915             // create Constant of type suitable for value specified in
    916             // instruction
    917             if (v2 instanceof Long
    918                     || (v2 instanceof Integer &&
    919                             insn.opcode.getFormat() == Form51l.THE_ONE)) {
    920                 reg1_spec = RegisterSpec.make(reg1_num, Type.LONG);
    921                 constant = CstLong.make(v2.longValue());
    922             } else if (v2 instanceof Float
    923                     && insn.opcode.getFormat() != Form51l.THE_ONE) {
    924                 reg1_spec = RegisterSpec.make(reg1_num, Type.FLOAT);
    925                 constant = CstFloat.make(Float.floatToIntBits(v2.floatValue()));
    926             } else if (v2 instanceof Double
    927                     || (v2 instanceof Float &&
    928                             insn.opcode.getFormat() == Form51l.THE_ONE)) {
    929                 reg1_spec = RegisterSpec.make(reg1_num, Type.DOUBLE);
    930                 constant = CstDouble.make(Double.doubleToLongBits(v2
    931                         .doubleValue()));
    932             } else {
    933                 reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
    934                 constant = CstInteger.make(v2.intValue());
    935             }
    936 
    937             DalvInsn dalvInsn = new CstInsn(insn.opcode,
    938                     createSourcePosition(), RegisterSpecList.make(reg1_spec),
    939                     constant);
    940             addInsn(dalvInsn);
    941         } else {
    942             throwDasmError("Bad arguments for instruction " + name + "(" + v1
    943                     + ", " + v2 + ")");
    944         }
    945 
    946     }
    947 
    948     /**
    949      * used for instructions that take three word parameters (register name is
    950      * treated as word) Format: 23x, 22t, 21c (field@), 22c (type@)
    951      */
    952     void addOpcode(String name, String v1, String v2, String v3)
    953             throws DasmError {
    954         if (PARSER_DEBUG)
    955             System.out.println("addOpcode(" + name + ", " + v1 + ", " + v2
    956                     + ", " + v3 + ")");
    957         createOutputFinisher();
    958         DopInfo insn = DopInfo.get(name);
    959 
    960         if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_REG_REG) == 0) {
    961             int reg1_num = -1, reg2_num = -1, reg3_num = -1;
    962 
    963             try {
    964                 reg1_num = getRegNumberFromString(v1);
    965             } catch (IllegalArgumentException e) {
    966                 throwDasmError("Bad arguments for instruction " + name + "("
    967                         + v1 + ")");
    968             }
    969 
    970             try {
    971                 reg2_num = getRegNumberFromString(v2);
    972             } catch (IllegalArgumentException e) {
    973                 throwDasmError("Bad arguments for instruction " + name + "("
    974                         + v2 + ")");
    975             }
    976 
    977             try {
    978                 reg3_num = getRegNumberFromString(v3);
    979             } catch (IllegalArgumentException e) {
    980                 throwDasmError("Bad arguments for instruction " + name + "("
    981                         + v3 + ")");
    982             }
    983             // TODO: is Type.INT suitable for any opcodes?
    984             RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
    985             RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, Type.INT);
    986             RegisterSpec reg3_spec = RegisterSpec.make(reg3_num, Type.INT);
    987             DalvInsn dalvInsn = new SimpleInsn(insn.opcode,
    988                     createSourcePosition(), RegisterSpecList.make(reg1_spec,
    989                             reg2_spec, reg3_spec));
    990             addInsn(dalvInsn);
    991         } else if (insn.args.compareToIgnoreCase(
    992                 DopInfo.ARG_REG_REG_ADDRESS) == 0) {
    993             int reg1_num = -1, reg2_num = -1;
    994 
    995             try {
    996                 reg1_num = getRegNumberFromString(v1);
    997             } catch (IllegalArgumentException e) {
    998                 throwDasmError("Bad arguments for instruction " + name + "("
    999                         + v1 + ")");
   1000             }
   1001 
   1002             try {
   1003                 reg2_num = getRegNumberFromString(v2);
   1004             } catch (IllegalArgumentException e) {
   1005                 throwDasmError("Bad arguments for instruction " + name + "("
   1006                         + v2 + ")");
   1007             }
   1008 
   1009             LabelTableEntry lte = labels_table.get(v3);
   1010             if (lte == null) {
   1011                 CodeAddress code_address = new CodeAddress(
   1012                         SourcePosition.NO_INFO);
   1013                 lte = new LabelTableEntry(code_address, false);
   1014                 labels_table.put(v3, lte);
   1015             }
   1016 
   1017             RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
   1018             RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, Type.INT);
   1019 
   1020             DalvInsn dalvInsn = new TargetInsn(insn.opcode,
   1021                     createSourcePosition(), RegisterSpecList.make(reg1_spec,
   1022                             reg2_spec), lte.code_address);
   1023             addInsn(dalvInsn);
   1024         } else if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_FIELD) == 0) {
   1025             int reg1_num = -1;
   1026 
   1027             try {
   1028                 reg1_num = getRegNumberFromString(v1);
   1029             } catch (IllegalArgumentException e) {
   1030                 throwDasmError("Bad arguments for instruction " + name + "("
   1031                         + v1 + ")");
   1032             }
   1033             // TODO: is Type.INT suitable?
   1034             RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
   1035 
   1036             String[] names = Utils.getClassFieldFromString(v2);
   1037 
   1038             CstNat field_nat = new CstNat(new CstString(names[1]),
   1039                     new CstString(v3));
   1040 
   1041             Constant constant = new CstFieldRef(CstType.intern(Type
   1042                     .internClassName(names[0])), field_nat);
   1043             DalvInsn dalvInsn = new CstInsn(insn.opcode,
   1044                     createSourcePosition(), RegisterSpecList.make(reg1_spec),
   1045                     constant);
   1046             addInsn(dalvInsn);
   1047         } else if (insn.args.compareToIgnoreCase(
   1048                 DopInfo.ARG_REG_REG_TYPE) == 0) {
   1049             int reg1_num = -1, reg2_num = -1;
   1050 
   1051             try {
   1052                 reg1_num = getRegNumberFromString(v1);
   1053             } catch (IllegalArgumentException e) {
   1054                 throwDasmError("Bad arguments for instruction " + name + "("
   1055                         + v1 + ")");
   1056             }
   1057 
   1058             try {
   1059                 reg2_num = getRegNumberFromString(v2);
   1060             } catch (IllegalArgumentException e) {
   1061                 throwDasmError("Bad arguments for instruction " + name + "("
   1062                         + v2 + ")");
   1063             }
   1064 
   1065             Type type = Type.internClassName(v3);
   1066             RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, type);
   1067             RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, type);
   1068             Constant constant = CstType.intern(type);
   1069             DalvInsn dalvInsn = new CstInsn(insn.opcode,
   1070                     createSourcePosition(), RegisterSpecList.make(reg1_spec,
   1071                             reg2_spec), constant);
   1072             addInsn(dalvInsn);
   1073         } else {
   1074             throwDasmError("Bad arguments for instruction " + name + "(" + v1
   1075                     + ", " + v2 + ", " + v3 + ")");
   1076         }
   1077     }
   1078 
   1079     /**
   1080      * Format: 22c (field@)
   1081      */
   1082     void addOpcode(String name, String v1, String v2, String v3, String v4)
   1083             throws DasmError {
   1084         if (PARSER_DEBUG)
   1085             System.out.println("addOpcode(" + name + ", " + v1 + ", " + v2
   1086                     + ", " + v3 + ", " + v4 + ")");
   1087         createOutputFinisher();
   1088         DopInfo insn = DopInfo.get(name);
   1089         if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_REG_FIELD) == 0) {
   1090             int reg1_num = -1, reg2_num = -1;
   1091 
   1092             try {
   1093                 reg1_num = getRegNumberFromString(v1);
   1094             } catch (IllegalArgumentException e) {
   1095                 throwDasmError("Bad arguments for instruction " + name + "("
   1096                         + v1 + ")");
   1097             }
   1098             try {
   1099                 reg2_num = getRegNumberFromString(v2);
   1100             } catch (IllegalArgumentException e) {
   1101                 throwDasmError("Bad arguments for instruction " + name + "("
   1102                         + v2 + ")");
   1103             }
   1104             // TODO: is Type.INT suitable?
   1105             RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
   1106             RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, Type.INT);
   1107 
   1108             String[] names = Utils.getClassFieldFromString(v3);
   1109 
   1110             CstNat field_nat = new CstNat(new CstString(names[1]),
   1111                     new CstString(v4));
   1112 
   1113             Constant constant = new CstFieldRef(CstType.intern(Type
   1114                     .internClassName(names[0])), field_nat);
   1115             DalvInsn dalvInsn = new CstInsn(insn.opcode,
   1116                     createSourcePosition(), RegisterSpecList.make(reg1_spec,
   1117                             reg2_spec), constant);
   1118             addInsn(dalvInsn);
   1119         } else if (insn.args.compareToIgnoreCase(
   1120                 DopInfo.ARG_REGRANGE_TYPE) == 0) {
   1121             String regs[] = Utils.splitRegList(v1);
   1122             if (regs.length != 2)
   1123                 throwDasmError("Bad arguments for instruction " + name + "("
   1124                         + v1 + ")");
   1125 
   1126             int regC = -1, regN = -1;
   1127             try {
   1128                 regC = getRegNumberFromString(regs[0]);
   1129             } catch (IllegalArgumentException e) {
   1130                 throwDasmError("Bad arguments for instruction " + name + "("
   1131                         + v1 + ")");
   1132             }
   1133             try {
   1134                 regN = getRegNumberFromString(regs[1]);
   1135             } catch (IllegalArgumentException e) {
   1136                 throwDasmError("Bad arguments for instruction " + name + "("
   1137                         + v1 + ")");
   1138             }
   1139 
   1140             if (regC >= regN)
   1141                 throwDasmError("Bad arguments for instruction " + name + "("
   1142                         + v1 + ")");
   1143 
   1144             int sz = regN - regC + 1;
   1145             RegisterSpecList reg_spec_list = new RegisterSpecList(sz);
   1146 
   1147             for (int i = 0; i < sz; i++) {
   1148                 reg_spec_list.set(i, RegisterSpec.make(regC + i, Type.INT));
   1149             }
   1150 
   1151             Type type;
   1152             try {
   1153                 type = Type.intern(v2);
   1154             } catch (IllegalArgumentException e) {
   1155                 // in case of exception, try to intern type as a class name
   1156                 // (Lclass_name;)
   1157                 type = Type.internClassName(v2);
   1158             }
   1159             Constant constant = CstType.intern(type);
   1160 
   1161             DalvInsn dalvInsn = new CstInsn(insn.opcode,
   1162                     createSourcePosition(), reg_spec_list, constant);
   1163             addInsn(dalvInsn);
   1164 
   1165         } else {
   1166             throwDasmError("Bad arguments for instruction " + name + "(" + v1
   1167                     + ", " + v2 + ", " + v3 + ", " + v4 + ")");
   1168         }
   1169     }
   1170 
   1171     /**
   1172      * used for relative branch targets (ie $+5, $-12, ...) Format: relative 22t
   1173      */
   1174     void addRelativeGoto(String name, String v1, String v2, int val)
   1175             throws DasmError {
   1176         if (PARSER_DEBUG)
   1177             System.out.println("addRelativeGoto(" + name + ", " + v1 + ", "
   1178                     + v2 + ", " + val + ")");
   1179         createOutputFinisher();
   1180         DopInfo insn = DopInfo.get(name);
   1181         if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_REG_ADDRESS) == 0) {
   1182             if (val == 0)
   1183                 throwDasmError("Bad arguments for instruction " + name + "("
   1184                         + val + ")");
   1185 
   1186             int reg1_num = -1, reg2_num = -1;
   1187 
   1188             try {
   1189                 reg1_num = getRegNumberFromString(v1);
   1190             } catch (IllegalArgumentException e) {
   1191                 throwDasmError("Bad arguments for instruction " + name + "("
   1192                         + v1 + ")");
   1193             }
   1194 
   1195             try {
   1196                 reg2_num = getRegNumberFromString(v2);
   1197             } catch (IllegalArgumentException e) {
   1198                 throwDasmError("Bad arguments for instruction " + name + "("
   1199                         + v2 + ")");
   1200             }
   1201 
   1202             RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
   1203             RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, Type.INT);
   1204             RegisterSpecList rsl = RegisterSpecList.make(reg1_spec, reg2_spec);
   1205             CodeAddress code_address = new CodeAddress(SourcePosition.NO_INFO);
   1206             if (val < 0) {
   1207                 output_finisher.insert(current_insn_number + val, code_address);
   1208                 current_insn_number++;
   1209             } else {
   1210                 unprocessed_relative_goto_addr.put(current_insn_number + val,
   1211                         code_address);
   1212             }
   1213             DalvInsn dalvInsn = new TargetInsn(insn.opcode,
   1214                     createSourcePosition(), rsl, code_address);
   1215             addInsn(dalvInsn);
   1216 
   1217         } else {
   1218             throwDasmError("Bad arguments for instruction " + name + "(" + val
   1219                     + ")");
   1220         }
   1221     }
   1222 
   1223     /**
   1224      * used for instructions that take two word parameters (register name is
   1225      * treated as word) and one literal Format: 22b, 22s
   1226      */
   1227     void addOpcode(String name, String v1, String v2, int v3) throws DasmError {
   1228         if (PARSER_DEBUG)
   1229             System.out.println("addOpcode(" + name + ", " + v1 + ", " + v2
   1230                     + ")");
   1231         createOutputFinisher();
   1232         DopInfo insn = DopInfo.get(name);
   1233 
   1234         if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_REG_LITERAL) == 0) {
   1235             int reg1_num = -1, reg2_num = -1;
   1236 
   1237             try {
   1238                 reg1_num = getRegNumberFromString(v1);
   1239             } catch (IllegalArgumentException e) {
   1240                 throwDasmError("Bad arguments for instruction " + name + "("
   1241                         + v1 + ")");
   1242             }
   1243 
   1244             try {
   1245                 reg2_num = getRegNumberFromString(v2);
   1246             } catch (IllegalArgumentException e) {
   1247                 throwDasmError("Bad arguments for instruction " + name + "("
   1248                         + v2 + ")");
   1249             }
   1250             // TODO: is Type.INT suitable for any opcodes?
   1251             RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT);
   1252             RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, Type.INT);
   1253             Constant constant = CstInteger.make(v3);
   1254             DalvInsn dalvInsn = new CstInsn(insn.opcode,
   1255                     createSourcePosition(), RegisterSpecList.make(reg1_spec,
   1256                             reg2_spec), constant);
   1257             addInsn(dalvInsn);
   1258         } else {
   1259             throwDasmError("Bad arguments for instruction " + name + "(" + v1
   1260                     + ", " + v2 + ", " + v3 + ")");
   1261         }
   1262     }
   1263 
   1264     /**
   1265      * used for fill-array-data instruction Format: 31t fill-array-data
   1266      * instruction has the syntax: fill-array-data &lt;register&gt; &lt;type&gt;
   1267      * &lt;value1&gt; &lt;value2&gt; .... fill-array-data-end For example:
   1268      * fill-array-data v7 I 1 2 3 4 5 fill-array-data-end
   1269      */
   1270     void newFillArrayData(String reg, String type) throws DasmError {
   1271         if (PARSER_DEBUG)
   1272             System.out.println("newFillArrayData(" + reg + ", " + type + ")");
   1273 
   1274         try {
   1275             fill_data_reg = getRegNumberFromString(reg);
   1276         } catch (IllegalArgumentException e) {
   1277             throwDasmError("Bad arguments for fill-array-data (" + reg + ")");
   1278         }
   1279 
   1280         fill_array_data_type = type;
   1281         fill_array_data_values = new Vector<Number>();
   1282     }
   1283 
   1284     /**
   1285      * add new value to data block
   1286      */
   1287     void addFillArrayData(Number num) throws DasmError {
   1288         if (PARSER_DEBUG) System.out.println("addFillArrayData(" + num + ")");
   1289         fill_array_data_values.add(num);
   1290     }
   1291 
   1292     /**
   1293      * called by fill-array-data-end
   1294      */
   1295     void endFillArrayData() throws DasmError {
   1296         if (PARSER_DEBUG) System.out.println("endFillArrayData");
   1297         int sz = fill_array_data_values.size();
   1298         ArrayList<Constant> values = new ArrayList<Constant>(sz);
   1299         CstType arrayType = CstType.intern(Type.intern("["
   1300                 + fill_array_data_type));
   1301         for (int i = 0; i < sz; i++) {
   1302             Constant constant;
   1303             Number num = fill_array_data_values.elementAt(i);
   1304             if (arrayType == CstType.LONG_ARRAY) {
   1305                 constant = CstLong.make(num.longValue());
   1306             } else if (arrayType == CstType.FLOAT_ARRAY) {
   1307                 constant = CstFloat
   1308                         .make(Float.floatToIntBits(num.floatValue()));
   1309             } else if (arrayType == CstType.DOUBLE_ARRAY) {
   1310                 constant = CstDouble.make(Double.doubleToLongBits(num
   1311                         .doubleValue()));
   1312             } else if (arrayType == CstType.BOOLEAN_ARRAY) {
   1313                 constant = CstBoolean.make(num.intValue());
   1314             } else if (arrayType == CstType.BYTE_ARRAY) {
   1315                 constant = CstByte.make(num.intValue());
   1316             } else if (arrayType == CstType.CHAR_ARRAY) {
   1317                 constant = CstChar.make(num.intValue());
   1318             } else if (arrayType == CstType.SHORT_ARRAY) {
   1319                 constant = CstShort.make(num.intValue());
   1320             } else {
   1321                 constant = CstInteger.make(num.intValue());
   1322             }
   1323             values.add(constant);
   1324         }
   1325 
   1326         CodeAddress insn_addr = new CodeAddress(createSourcePosition());
   1327         CodeAddress data_addr = new CodeAddress(SourcePosition.NO_INFO);
   1328         DalvInsn dalvInsn = new TargetInsn(Dops.FILL_ARRAY_DATA,
   1329                 createSourcePosition(), RegisterSpecList
   1330                         .make(RegisterSpec.make(fill_data_reg, Type
   1331                                 .intern(fill_array_data_type))), data_addr);
   1332         OddSpacer spacer = new OddSpacer(SourcePosition.NO_INFO);
   1333         ArrayData array_data = new ArrayData(SourcePosition.NO_INFO, insn_addr,
   1334                 values, arrayType);
   1335 
   1336         addInsn(insn_addr);
   1337         addInsn(dalvInsn);
   1338         data_blocks.add(spacer);
   1339         data_blocks.add(data_addr);
   1340         data_blocks.add(array_data);
   1341 
   1342         fill_array_data_values = null;
   1343         fill_array_data_type = null;
   1344     }
   1345 
   1346     /**
   1347      * used for packed-switch instruction Format: 31t packed-switch instruction
   1348      * has the syntax: packed-switch &lt;register&gt; &lt;lowest&gt;
   1349      * &lt;label1&gt; &lt;label2&gt; .... packed-switch-end For example:
   1350      * packed-switch v3, -1 Label9 Label6 Label6 Label12 Label12
   1351      * packed-switch-end
   1352      */
   1353     void newPackedSwitch(String reg, int first_key) throws DasmError {
   1354         if (PARSER_DEBUG)
   1355             System.out.println("newPackedSwitch(" + reg + ", " + first_key
   1356                     + ")");
   1357 
   1358         try {
   1359             switch_reg = getRegNumberFromString(reg);
   1360         } catch (IllegalArgumentException e) {
   1361             throwDasmError("Bad arguments for packed-switch (" + reg + ")");
   1362         }
   1363 
   1364         packed_switch_first_key = first_key;
   1365         packed_switch_current_key = 0;
   1366         switch_targets = new Vector<Object>();
   1367         switch_keys = new IntList();
   1368     }
   1369 
   1370     /**
   1371      * add new target to packed-switch
   1372      */
   1373     void addPackedSwitchData(String target) throws DasmError {
   1374         if (PARSER_DEBUG)
   1375             System.out.println("addPackedSwitchData(" + target + ")");
   1376         switch_targets.add(target);
   1377         switch_keys.add(packed_switch_first_key + packed_switch_current_key);
   1378         packed_switch_current_key++;
   1379     }
   1380 
   1381     /**
   1382      * add new target to packed-switch
   1383      */
   1384     void addPackedSwitchData(int target) throws DasmError {
   1385         if (PARSER_DEBUG)
   1386             System.out.println("addPackedSwitchData(" + target + ")");
   1387         switch_targets.add(new Integer(target));
   1388         switch_keys.add(packed_switch_first_key + packed_switch_current_key);
   1389         packed_switch_current_key++;
   1390     }
   1391 
   1392     /**
   1393      * used for sparse-switch instruction Format: 31t sparse-switch instruction
   1394      * has the syntax: sparse-switch &lt;register&gt; &lt;lowest&gt;
   1395      * &lt;int1&gt; : &lt;label1&gt; &lt;int2&gt; : &lt;label2&gt; ....
   1396      * sparse-switch-end For example: sparse-switch v3 -1 : Label9 10 : Label12
   1397      * 15 : Label12 sparse-switch-end
   1398      */
   1399     void newSparseSwitch(String reg) throws DasmError {
   1400         if (PARSER_DEBUG) System.out.println("newSparseSwitch(" + reg + ")");
   1401 
   1402         try {
   1403             switch_reg = getRegNumberFromString(reg);
   1404         } catch (IllegalArgumentException e) {
   1405             throwDasmError("Bad arguments for sparse-switch (" + reg + ")");
   1406         }
   1407 
   1408         switch_targets = new Vector<Object>();
   1409         switch_keys = new IntList();
   1410     }
   1411 
   1412     /**
   1413      * add new target to sparse-switch
   1414      */
   1415     void addSparseSwitchData(int key, String target) throws DasmError {
   1416         if (PARSER_DEBUG)
   1417             System.out.println("addSparseSwitchData(" + key + ", " + target
   1418                     + ")");
   1419         switch_targets.add(target);
   1420         switch_keys.add(key);
   1421     }
   1422 
   1423     /**
   1424      * add new target to sparse-switch
   1425      */
   1426     void addSparseSwitchData(int key, int target) throws DasmError {
   1427         if (PARSER_DEBUG)
   1428             System.out.println("addSparseSwitchData(" + key + ", " + target
   1429                     + ")");
   1430         switch_targets.add(new Integer(target));
   1431         switch_keys.add(key);
   1432     }
   1433 
   1434     /**
   1435      * called by sparse-switch-end or packed-switch-end
   1436      */
   1437     void endSwitch() throws DasmError {
   1438         if (PARSER_DEBUG) System.out.println("endSwitch");
   1439         int sz = switch_targets.size();
   1440 
   1441         CodeAddress targets[] = new CodeAddress[sz];
   1442         for (int i = 0; i < sz; i++) {
   1443             Object o = switch_targets.elementAt(i);
   1444             CodeAddress addr;
   1445             if (o instanceof String) {
   1446                 String t = (String) o;
   1447                 LabelTableEntry lte = labels_table.get(t);
   1448                 if (lte == null) {
   1449                     CodeAddress code_address = new CodeAddress(
   1450                             SourcePosition.NO_INFO);
   1451                     lte = new LabelTableEntry(code_address, false);
   1452                     labels_table.put(t, lte);
   1453                 }
   1454                 addr = lte.code_address;
   1455             } else {
   1456                 Integer t = (Integer) o;
   1457 
   1458                 addr = new CodeAddress(SourcePosition.NO_INFO);
   1459                 if (t < 0) {
   1460                     output_finisher.insert(current_insn_number + t, addr);
   1461                     current_insn_number++;
   1462                 } else {
   1463                     unprocessed_relative_goto_addr.put(current_insn_number + t,
   1464                             addr);
   1465                 }
   1466             }
   1467             targets[i] = addr;
   1468         }
   1469 
   1470         CodeAddress insn_addr = new CodeAddress(createSourcePosition());
   1471         CodeAddress data_addr = new CodeAddress(SourcePosition.NO_INFO);
   1472         OddSpacer spacer = new OddSpacer(SourcePosition.NO_INFO);
   1473         SwitchData switch_data = new SwitchData(SourcePosition.NO_INFO,
   1474                 insn_addr, switch_keys, targets);
   1475         DalvInsn dalvInsn = new TargetInsn(switch_data.isPacked()
   1476                 ? Dops.PACKED_SWITCH : Dops.SPARSE_SWITCH,
   1477                 createSourcePosition(), RegisterSpecList.make(RegisterSpec
   1478                         .make(switch_reg, Type.INT)), data_addr);
   1479 
   1480         addInsn(insn_addr);
   1481         addInsn(dalvInsn);
   1482         data_blocks.add(spacer);
   1483         data_blocks.add(data_addr);
   1484         data_blocks.add(switch_data);
   1485 
   1486         switch_targets = null;
   1487         switch_keys = null;
   1488     }
   1489 
   1490     /*
   1491      * ========================================================================
   1492      * === UTILITY METHODS
   1493      * ========================================================================
   1494      */
   1495 
   1496     /**
   1497      * Creates instance of SourcePosition for current line
   1498      */
   1499     protected SourcePosition createSourcePosition() {
   1500         return new SourcePosition(new CstString(filename), -1, line_num);
   1501     }
   1502 
   1503     /**
   1504      * Creates TypeList from list of types
   1505      */
   1506     protected TypeList createTypeListFromStrings(Vector<String> strings) {
   1507         StdTypeList tl;
   1508 
   1509         if (strings.size() == 0)
   1510             tl = StdTypeList.EMPTY;
   1511         else {
   1512             int sz = strings.size();
   1513             tl = new StdTypeList(sz);
   1514             for (int i = 0; i < sz; i++) {
   1515                 tl.set(i, Type.internClassName(strings.elementAt(i)));
   1516             }
   1517         }
   1518         return tl;
   1519     }
   1520 
   1521     /**
   1522      * Creates processor of instruction list.
   1523      */
   1524     private void createOutputFinisher() {
   1525         if (output_finisher == null) {
   1526             dexOptions.ALIGN_64BIT_REGS_IN_OUTPUT_FINISHER = false;
   1527             int paramSize = Prototype.intern(method_nat.getDescriptor()
   1528                 .getString()).getParameterTypes().getWordCount();
   1529             output_finisher = new OutputFinisher(dexOptions, 5, regs_count, paramSize);
   1530         }
   1531     }
   1532 
   1533     /**
   1534      * Returns register number from "vX" string.
   1535      */
   1536     private int getRegNumberFromString(String val)
   1537             throws IllegalArgumentException {
   1538         int reg_num;
   1539         int l = RegisterSpec.PREFIX.length();
   1540         if (val.length() <= l
   1541                 || val.substring(0, l).compareToIgnoreCase(
   1542                         RegisterSpec.PREFIX) != 0)
   1543             throw new IllegalArgumentException("Wrong register name prefix");
   1544 
   1545         try {
   1546             reg_num = Integer.parseInt(val.substring(l));
   1547         } catch (Exception e) {
   1548             throw new IllegalArgumentException("Wrong register name");
   1549         }
   1550         return reg_num;
   1551     }
   1552 
   1553     /**
   1554      * Adds new instruction to instruction list.
   1555      */
   1556     private void addInsn(DalvInsn insn) {
   1557         createOutputFinisher();
   1558         CodeAddress code_address = unprocessed_relative_goto_addr
   1559                 .get(current_insn_number);
   1560         if (code_address != null) {
   1561             output_finisher.add(code_address);
   1562             unprocessed_relative_goto_addr.remove(current_insn_number);
   1563             current_insn_number++;
   1564         }
   1565         output_finisher.add(insn);
   1566         current_insn_number++;
   1567     }
   1568 
   1569     /*
   1570      * ========================================================================
   1571      * === READER and WRITER
   1572      * ========================================================================
   1573      */
   1574 
   1575     /**
   1576      * Writes the binary data for the class represented by this ClassFile object
   1577      * to the specified output stream, using the Java Class File format. Throws
   1578      * either an IOException or a dasmError if something goes wrong.
   1579      */
   1580     public void write(OutputStream outp, FileWriter human_readable)
   1581             throws IOException, DasmError {
   1582         dexFile.writeTo(outp, human_readable, true);
   1583     }
   1584 
   1585     /**
   1586      * Parses a .d file, converting it internally into a binary representation.
   1587      * If something goes wrong, this throws one of an IOException, or a
   1588      * dasmError, or one of a few other exceptions.
   1589      *
   1590      * @param input
   1591      *            is the stream containing the Dalvik assembly code for the
   1592      *            class.
   1593      * @param name
   1594      *            is the name of the stream. This name will be concatenated to
   1595      *            error messages printed to System.err.
   1596      * @param numberLines
   1597      *            true if you want DAsm to generate line numbers automatically,
   1598      *            based on the assembly source, or false if you are using the
   1599      *            ".line" directive and don't want DAsm to help out.
   1600      */
   1601     public void readD(Reader input, String name, boolean numberLines)
   1602             throws IOException, Exception {
   1603 
   1604         // TODO: numberLines?
   1605         errors = 0;
   1606         filename = name;
   1607         source_name = name;
   1608         class_header = false;
   1609         classDef = null;
   1610         dexFile = new DexFile(dexOptions);
   1611 
   1612         scanner = new Scanner(input);
   1613         parser parse_obj = new parser(this, scanner);
   1614 
   1615 
   1616         if (PARSER_DEBUG) {
   1617             // for debugging
   1618             parse_obj.debug_parse();
   1619         } else {
   1620             parse_obj.parse();
   1621         }
   1622 
   1623     }
   1624 }
   1625