1/*
2 * Copyright (C) 2012 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
17package com.google.dexmaker.examples;
18
19import com.google.dexmaker.BinaryOp;
20import com.google.dexmaker.Code;
21import com.google.dexmaker.DexMaker;
22import com.google.dexmaker.FieldId;
23import com.google.dexmaker.Local;
24import com.google.dexmaker.MethodId;
25import com.google.dexmaker.TypeId;
26import java.io.File;
27import java.io.PrintStream;
28import java.lang.reflect.Modifier;
29
30public final class HelloWorldMaker {
31    public static void main(String[] args) throws Exception {
32        DexMaker dexMaker = new DexMaker();
33
34        // Generate a HelloWorld class.
35        TypeId<?> helloWorld = TypeId.get("LHelloWorld;");
36        dexMaker.declare(helloWorld, "HelloWorld.generated", Modifier.PUBLIC, TypeId.OBJECT);
37        generateHelloMethod(dexMaker, helloWorld);
38
39        // Create the dex file and load it.
40        File outputDir = new File(".");
41        ClassLoader loader = dexMaker.generateAndLoad(HelloWorldMaker.class.getClassLoader(),
42                outputDir);
43        Class<?> helloWorldClass = loader.loadClass("HelloWorld");
44
45        // Execute our newly-generated code in-process.
46        helloWorldClass.getMethod("hello").invoke(null);
47    }
48
49    /**
50     * Generates Dalvik bytecode equivalent to the following method.
51     *    public static void hello() {
52     *        int a = 0xabcd;
53     *        int b = 0xaaaa;
54     *        int c = a - b;
55     *        String s = Integer.toHexString(c);
56     *        System.out.println(s);
57     *        return;
58     *    }
59     */
60    private static void generateHelloMethod(DexMaker dexMaker, TypeId<?> declaringType) {
61        // Lookup some types we'll need along the way.
62        TypeId<System> systemType = TypeId.get(System.class);
63        TypeId<PrintStream> printStreamType = TypeId.get(PrintStream.class);
64
65        // Identify the 'hello()' method on declaringType.
66        MethodId hello = declaringType.getMethod(TypeId.VOID, "hello");
67
68        // Declare that method on the dexMaker. Use the returned Code instance
69        // as a builder that we can append instructions to.
70        Code code = dexMaker.declare(hello, Modifier.STATIC | Modifier.PUBLIC);
71
72        // Declare all the locals we'll need up front. The API requires this.
73        Local<Integer> a = code.newLocal(TypeId.INT);
74        Local<Integer> b = code.newLocal(TypeId.INT);
75        Local<Integer> c = code.newLocal(TypeId.INT);
76        Local<String> s = code.newLocal(TypeId.STRING);
77        Local<PrintStream> localSystemOut = code.newLocal(printStreamType);
78
79        // int a = 0xabcd;
80        code.loadConstant(a, 0xabcd);
81
82        // int b = 0xaaaa;
83        code.loadConstant(b, 0xaaaa);
84
85        // int c = a - b;
86        code.op(BinaryOp.SUBTRACT, c, a, b);
87
88        // String s = Integer.toHexString(c);
89        MethodId<Integer, String> toHexString
90                = TypeId.get(Integer.class).getMethod(TypeId.STRING, "toHexString", TypeId.INT);
91        code.invokeStatic(toHexString, s, c);
92
93        // System.out.println(s);
94        FieldId<System, PrintStream> systemOutField = systemType.getField(printStreamType, "out");
95        code.sget(systemOutField, localSystemOut);
96        MethodId<PrintStream, Void> printlnMethod = printStreamType.getMethod(
97                TypeId.VOID, "println", TypeId.STRING);
98        code.invokeVirtual(printlnMethod, null, localSystemOut, s);
99
100        // return;
101        code.returnVoid();
102    }
103}