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