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 {
LabelTableEntry(CodeAddress code_address, boolean planted)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      */
errorCount()174     public int errorCount() {
175         return errors;
176     }
177 
report_error(String msg)178     void report_error(String msg) {
179         errors++;
180         System.out.println("Line " + line_num + ": " + msg);
181     }
182 
throwDasmError(String msg)183     void throwDasmError(String msg) throws DasmError {
184         throw new DasmError("Line " + line_num + ": " + msg);
185     }
186 
187     /**
188      * used by .line directive
189      */
addLineInfo(int line_num)190     void addLineInfo(int line_num) throws DasmError {
191         throw new IllegalStateException(".line not implemented");
192     }
193 
addLine(int line_num)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      */
addVar(String startLab, String endLab, String name, String desc, String sign, int var_num)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 
addVar(int startOffset, int endOffset, String name, String desc, String sign, int var_num)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      */
setLine(int l)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      */
addInner(short iacc, String name, String inner, String outer)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      */
setSource(String name)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      */
setVersion(Number version)245     void setVersion(Number version) {
246         throw new IllegalStateException(".bytecode is not implemented");
247     }
248 
249     /**
250      * called by the .class directive
251      */
setClass(String name, int acc)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      */
getClassName()267     public String getClassName() {
268         return class_name;
269     }
270 
271     /**
272      * called by the .super directive
273      */
setSuperClass(String name)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      */
addInterface(String name)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      */
setSignature(String str)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      */
setEnclosingMethod(String str)309     void setEnclosingMethod(String str) {
310         throw new IllegalStateException(".enclosing is not implemented");
311     }
312 
313     /**
314      * called by the .attribute directive
315      */
addGenericAttr(String name, String file)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      */
endHeader()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      */
beginField(short access, String name, String desc, Object value)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      */
endField()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      */
addField(short access, String name, String desc, String sig, Object value)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      */
newMethod(String name, String descriptor, int access)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      */
endMethod()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      */
setRegsSize(int v)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      */
addThrow(String name)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      */
addCatch(String name, String start_lab, String end_lab, String branch_lab)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 
addCatch(String name, int start_off, int end_off, int branch_off)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      */
plantLabel(String name)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      */
addOpcode(String name)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      */
addOpcode(String name, String val)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      */
addRelativeGoto(String name, int val)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      */
addOpcode(String name, String v1, String v2)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      */
addRelativeGoto(String name, String v1, int val)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      */
addOpcode(String name, String v1, Number v2)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      */
addOpcode(String name, String v1, String v2, String v3)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      */
addOpcode(String name, String v1, String v2, String v3, String v4)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      */
addRelativeGoto(String name, String v1, String v2, int val)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      */
addOpcode(String name, String v1, String v2, int v3)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      */
newFillArrayData(String reg, String type)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      */
addFillArrayData(Number num)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      */
endFillArrayData()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      */
newPackedSwitch(String reg, int first_key)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      */
addPackedSwitchData(String target)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      */
addPackedSwitchData(int target)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      */
newSparseSwitch(String reg)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      */
addSparseSwitchData(int key, String target)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      */
addSparseSwitchData(int key, int target)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      */
endSwitch()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      */
createSourcePosition()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      */
createTypeListFromStrings(Vector<String> strings)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      */
createOutputFinisher()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      */
getRegNumberFromString(String val)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      */
addInsn(DalvInsn insn)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      */
write(OutputStream outp, FileWriter human_readable)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      */
readD(Reader input, String name, boolean numberLines)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