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