1674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen/*
2674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Copyright 2003,2004 The Apache Software Foundation
3674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen *
4674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen *  Licensed under the Apache License, Version 2.0 (the "License");
5674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * you may not use this file except in compliance with the License.
6674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * You may obtain a copy of the License at
7674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen *
8674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen *      http://www.apache.org/licenses/LICENSE-2.0
9674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen *
10674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen *  Unless required by applicable law or agreed to in writing, software
11674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * distributed under the License is distributed on an "AS IS" BASIS,
12674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * See the License for the specific language governing permissions and
14674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * limitations under the License.
15674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */
16674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenpackage org.mockito.cglib.core;
17674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
18674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport java.math.BigDecimal;
19674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport java.math.BigInteger;
20674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport java.util.*;
21674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
22674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.Label;
23674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.Type;
24674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
25674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenpublic class EmitUtils {
26674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature CSTRUCT_NULL =
27674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseConstructor("");
28674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature CSTRUCT_THROWABLE =
29674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseConstructor("Throwable");
30674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
31674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature GET_NAME =
32674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseSignature("String getName()");
33674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature HASH_CODE =
34674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseSignature("int hashCode()");
35674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature EQUALS =
36674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseSignature("boolean equals(Object)");
37674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature STRING_LENGTH =
38674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseSignature("int length()");
39674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature STRING_CHAR_AT =
40674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseSignature("char charAt(int)");
41674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature FOR_NAME =
42674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseSignature("Class forName(String)");
43674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature DOUBLE_TO_LONG_BITS =
44674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseSignature("long doubleToLongBits(double)");
45674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature FLOAT_TO_INT_BITS =
46674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseSignature("int floatToIntBits(float)");
47674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature TO_STRING =
48674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseSignature("String toString()");
49674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature APPEND_STRING =
50674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseSignature("StringBuffer append(String)");
51674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature APPEND_INT =
52674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseSignature("StringBuffer append(int)");
53674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature APPEND_DOUBLE =
54674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseSignature("StringBuffer append(double)");
55674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature APPEND_FLOAT =
56674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseSignature("StringBuffer append(float)");
57674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature APPEND_CHAR =
58674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseSignature("StringBuffer append(char)");
59674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature APPEND_LONG =
60674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseSignature("StringBuffer append(long)");
61674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature APPEND_BOOLEAN =
62674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseSignature("StringBuffer append(boolean)");
63674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature LENGTH =
64674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseSignature("int length()");
65674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature SET_LENGTH =
66674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseSignature("void setLength(int)");
67674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature GET_DECLARED_METHOD =
68674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseSignature("java.lang.reflect.Method getDeclaredMethod(String, Class[])");
69674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
70674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
71674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
72674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static final ArrayDelimiters DEFAULT_DELIMITERS = new ArrayDelimiters("{", ", ", "}");
73674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
74674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private EmitUtils() {
75674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
76674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
77674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static void factory_method(ClassEmitter ce, Signature sig) {
78674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, sig, null);
79674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.new_instance_this();
80674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.dup();
81674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_args();
82674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_constructor_this(TypeUtils.parseConstructor(sig.getArgumentTypes()));
83674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.return_value();
84674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.end_method();
85674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
86674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
87674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static void null_constructor(ClassEmitter ce) {
88674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, CSTRUCT_NULL, null);
89674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_this();
90674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.super_invoke_constructor();
91674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.return_value();
92674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.end_method();
93674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
94674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
95674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
96674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Process an array on the stack. Assumes the top item on the stack
97674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * is an array of the specified type. For each element in the array,
98674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * puts the element on the stack and triggers the callback.
99674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param type the type of the array (type.isArray() must be true)
100674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param callback the callback triggered for each element
101674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
102674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static void process_array(CodeEmitter e, Type type, ProcessArrayCallback callback) {
103674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Type componentType = TypeUtils.getComponentType(type);
104674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Local array = e.make_local();
105674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Local loopvar = e.make_local(Type.INT_TYPE);
106674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Label loopbody = e.make_label();
107674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Label checkloop = e.make_label();
108674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.store_local(array);
109674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.push(0);
110674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.store_local(loopvar);
111674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.goTo(checkloop);
112674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
113674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.mark(loopbody);
114674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_local(array);
115674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_local(loopvar);
116674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.array_load(componentType);
117674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        callback.processElement(componentType);
118674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.iinc(loopvar, 1);
119674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
120674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.mark(checkloop);
121674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_local(loopvar);
122674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_local(array);
123674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.arraylength();
124674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.if_icmp(e.LT, loopbody);
125674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
126674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
127674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
128674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Process two arrays on the stack in parallel. Assumes the top two items on the stack
129674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * are arrays of the specified class. The arrays must be the same length. For each pair
130674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * of elements in the arrays, puts the pair on the stack and triggers the callback.
131674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param type the type of the arrays (type.isArray() must be true)
132674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param callback the callback triggered for each pair of elements
133674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
134674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static void process_arrays(CodeEmitter e, Type type, ProcessArrayCallback callback) {
135674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Type componentType = TypeUtils.getComponentType(type);
136674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Local array1 = e.make_local();
137674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Local array2 = e.make_local();
138674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Local loopvar = e.make_local(Type.INT_TYPE);
139674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Label loopbody = e.make_label();
140674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Label checkloop = e.make_label();
141674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.store_local(array1);
142674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.store_local(array2);
143674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.push(0);
144674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.store_local(loopvar);
145674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.goTo(checkloop);
146674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
147674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.mark(loopbody);
148674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_local(array1);
149674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_local(loopvar);
150674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.array_load(componentType);
151674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_local(array2);
152674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_local(loopvar);
153674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.array_load(componentType);
154674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        callback.processElement(componentType);
155674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.iinc(loopvar, 1);
156674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
157674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.mark(checkloop);
158674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_local(loopvar);
159674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_local(array1);
160674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.arraylength();
161674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.if_icmp(e.LT, loopbody);
162674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
163674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
164674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static void string_switch(CodeEmitter e, String[] strings, int switchStyle, ObjectSwitchCallback callback) {
165674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        try {
166674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            switch (switchStyle) {
167674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            case Constants.SWITCH_STYLE_TRIE:
168674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                string_switch_trie(e, strings, callback);
169674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                break;
170674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            case Constants.SWITCH_STYLE_HASH:
171674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                string_switch_hash(e, strings, callback, false);
172674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                break;
173674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            case Constants.SWITCH_STYLE_HASHONLY:
174674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                string_switch_hash(e, strings, callback, true);
175674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                break;
176674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            default:
177674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                throw new IllegalArgumentException("unknown switch style " + switchStyle);
178674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
179674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } catch (RuntimeException ex) {
180674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            throw ex;
181674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } catch (Error ex) {
182674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            throw ex;
183674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } catch (Exception ex) {
184674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            throw new CodeGenerationException(ex);
185674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
186674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
187674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
188674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static void string_switch_trie(final CodeEmitter e,
189674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                           String[] strings,
190674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                           final ObjectSwitchCallback callback) throws Exception {
191674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final Label def = e.make_label();
192674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final Label end = e.make_label();
193674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final Map buckets = CollectionUtils.bucket(Arrays.asList(strings), new Transformer() {
194674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            public Object transform(Object value) {
195674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                return new Integer(((String)value).length());
196674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
197674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        });
198674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.dup();
199674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_virtual(Constants.TYPE_STRING, STRING_LENGTH);
200674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.process_switch(getSwitchKeys(buckets), new ProcessSwitchCallback() {
201674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                public void processCase(int key, Label ignore_end) throws Exception {
202674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    List bucket = (List)buckets.get(new Integer(key));
203674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    stringSwitchHelper(e, bucket, callback, def, end, 0);
204674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                }
205674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                public void processDefault() {
206674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    e.goTo(def);
207674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                }
208674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            });
209674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.mark(def);
210674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.pop();
211674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        callback.processDefault();
212674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.mark(end);
213674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
214674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
215674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static void stringSwitchHelper(final CodeEmitter e,
216674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                           List strings,
217674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                           final ObjectSwitchCallback callback,
218674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                           final Label def,
219674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                           final Label end,
220674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                           final int index) throws Exception {
221674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final int len = ((String)strings.get(0)).length();
222674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final Map buckets = CollectionUtils.bucket(strings, new Transformer() {
223674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            public Object transform(Object value) {
224674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                return new Integer(((String)value).charAt(index));
225674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
226674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        });
227674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.dup();
228674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.push(index);
229674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_virtual(Constants.TYPE_STRING, STRING_CHAR_AT);
230674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.process_switch(getSwitchKeys(buckets), new ProcessSwitchCallback() {
231674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                public void processCase(int key, Label ignore_end) throws Exception {
232674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    List bucket = (List)buckets.get(new Integer(key));
233674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    if (index + 1 == len) {
234674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        e.pop();
235674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        callback.processCase(bucket.get(0), end);
236674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    } else {
237674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        stringSwitchHelper(e, bucket, callback, def, end, index + 1);
238674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    }
239674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                }
240674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                public void processDefault() {
241674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    e.goTo(def);
242674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                }
243674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            });
244674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
245674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
246674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    static int[] getSwitchKeys(Map buckets) {
247674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        int[] keys = new int[buckets.size()];
248674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        int index = 0;
249674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        for (Iterator it = buckets.keySet().iterator(); it.hasNext();) {
250674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            keys[index++] = ((Integer)it.next()).intValue();
251674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
252674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Arrays.sort(keys);
253674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return keys;
254674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
255674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
256674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static void string_switch_hash(final CodeEmitter e,
257674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                           final String[] strings,
258674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                           final ObjectSwitchCallback callback,
259674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                           final boolean skipEquals) throws Exception {
260674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final Map buckets = CollectionUtils.bucket(Arrays.asList(strings), new Transformer() {
261674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            public Object transform(Object value) {
262674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                return new Integer(value.hashCode());
263674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
264674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        });
265674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final Label def = e.make_label();
266674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final Label end = e.make_label();
267674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.dup();
268674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_virtual(Constants.TYPE_OBJECT, HASH_CODE);
269674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.process_switch(getSwitchKeys(buckets), new ProcessSwitchCallback() {
270674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            public void processCase(int key, Label ignore_end) throws Exception {
271674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                List bucket = (List)buckets.get(new Integer(key));
272674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                Label next = null;
273674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                if (skipEquals && bucket.size() == 1) {
274674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    if (skipEquals)
275674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        e.pop();
276674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    callback.processCase((String)bucket.get(0), end);
277674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                } else {
278674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    for (Iterator it = bucket.iterator(); it.hasNext();) {
279674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        String string = (String)it.next();
280674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        if (next != null) {
281674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            e.mark(next);
282674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        }
283674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        if (it.hasNext()) {
284674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            e.dup();
285674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        }
286674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        e.push(string);
287674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        e.invoke_virtual(Constants.TYPE_OBJECT, EQUALS);
288674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        if (it.hasNext()) {
289674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            e.if_jump(e.EQ, next = e.make_label());
290674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            e.pop();
291674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        } else {
292674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            e.if_jump(e.EQ, def);
293674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        }
294674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        callback.processCase(string, end);
295674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    }
296674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                }
297674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
298674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            public void processDefault() {
299674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.pop();
300674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
301674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        });
302674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.mark(def);
303674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        callback.processDefault();
304674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.mark(end);
305674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
306674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
307674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static void load_class_this(CodeEmitter e) {
308674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        load_class_helper(e, e.getClassEmitter().getClassType());
309674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
310674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
311674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static void load_class(CodeEmitter e, Type type) {
312674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (TypeUtils.isPrimitive(type)) {
313674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (type == Type.VOID_TYPE) {
314674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                throw new IllegalArgumentException("cannot load void type");
315674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
316674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.getstatic(TypeUtils.getBoxedType(type), "TYPE", Constants.TYPE_CLASS);
317674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } else {
318674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            load_class_helper(e, type);
319674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
320674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
321674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
322674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static void load_class_helper(CodeEmitter e, final Type type) {
323674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (e.isStaticHook()) {
324674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            // have to fall back on non-optimized load
325674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.push(TypeUtils.emulateClassGetName(type));
326674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.invoke_static(Constants.TYPE_CLASS, FOR_NAME);
327674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } else {
328674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            ClassEmitter ce = e.getClassEmitter();
329674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            String typeName = TypeUtils.emulateClassGetName(type);
330674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
331674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            // TODO: can end up with duplicated field names when using chained transformers; incorporate static hook # somehow
332674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            String fieldName = "CGLIB$load_class$" + TypeUtils.escapeType(typeName);
333674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (!ce.isFieldDeclared(fieldName)) {
334674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                ce.declare_field(Constants.PRIVATE_FINAL_STATIC, fieldName, Constants.TYPE_CLASS, null);
335674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                CodeEmitter hook = ce.getStaticHook();
336674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                hook.push(typeName);
337674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                hook.invoke_static(Constants.TYPE_CLASS, FOR_NAME);
338674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                hook.putstatic(ce.getClassType(), fieldName, Constants.TYPE_CLASS);
339674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
340674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.getfield(fieldName);
341674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
342674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
343674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
344674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static void push_array(CodeEmitter e, Object[] array) {
345674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.push(array.length);
346674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.newarray(Type.getType(remapComponentType(array.getClass().getComponentType())));
347674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        for (int i = 0; i < array.length; i++) {
348674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.dup();
349674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.push(i);
350674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            push_object(e, array[i]);
351674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.aastore();
352674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
353674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
354674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
355674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static Class remapComponentType(Class componentType) {
356674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (componentType.equals(Type.class))
357674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            return Class.class;
358674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return componentType;
359674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
360674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
361674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static void push_object(CodeEmitter e, Object obj) {
362674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (obj == null) {
363674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.aconst_null();
364674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } else {
365674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            Class type = obj.getClass();
366674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (type.isArray()) {
367674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                push_array(e, (Object[])obj);
368674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            } else if (obj instanceof String) {
369674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.push((String)obj);
370674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            } else if (obj instanceof Type) {
371674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                load_class(e, (Type)obj);
372674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            } else if (obj instanceof Class) {
373674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                load_class(e, Type.getType((Class)obj));
374674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            } else if (obj instanceof BigInteger) {
375674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.new_instance(Constants.TYPE_BIG_INTEGER);
376674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.dup();
377674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.push(obj.toString());
378674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.invoke_constructor(Constants.TYPE_BIG_INTEGER);
379674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            } else if (obj instanceof BigDecimal) {
380674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.new_instance(Constants.TYPE_BIG_DECIMAL);
381674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.dup();
382674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.push(obj.toString());
383674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.invoke_constructor(Constants.TYPE_BIG_DECIMAL);
384674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            } else {
385674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                throw new IllegalArgumentException("unknown type: " + obj.getClass());
386674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
387674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
388674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
389674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
390674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static void hash_code(CodeEmitter e, Type type, int multiplier, Customizer customizer) {
391674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (TypeUtils.isArray(type)) {
392674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            hash_array(e, type, multiplier, customizer);
393674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } else {
394674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.swap(Type.INT_TYPE, type);
395674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.push(multiplier);
396674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.math(e.MUL, Type.INT_TYPE);
397674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.swap(type, Type.INT_TYPE);
398674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (TypeUtils.isPrimitive(type)) {
399674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                hash_primitive(e, type);
400674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            } else {
401674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                hash_object(e, type, customizer);
402674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
403674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.math(e.ADD, Type.INT_TYPE);
404674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
405674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
406674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
407674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static void hash_array(final CodeEmitter e, Type type, final int multiplier, final Customizer customizer) {
408674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Label skip = e.make_label();
409674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Label end = e.make_label();
410674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.dup();
411674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.ifnull(skip);
412674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        EmitUtils.process_array(e, type, new ProcessArrayCallback() {
413674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            public void processElement(Type type) {
414674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                hash_code(e, type, multiplier, customizer);
415674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
416674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        });
417674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.goTo(end);
418674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.mark(skip);
419674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.pop();
420674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.mark(end);
421674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
422674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
423674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static void hash_object(CodeEmitter e, Type type, Customizer customizer) {
424674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        // (f == null) ? 0 : f.hashCode();
425674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Label skip = e.make_label();
426674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Label end = e.make_label();
427674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.dup();
428674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.ifnull(skip);
429674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (customizer != null) {
430674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            customizer.customize(e, type);
431674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
432674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_virtual(Constants.TYPE_OBJECT, HASH_CODE);
433674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.goTo(end);
434674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.mark(skip);
435674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.pop();
436674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.push(0);
437674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.mark(end);
438674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
439674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
440674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static void hash_primitive(CodeEmitter e, Type type) {
441674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        switch (type.getSort()) {
442674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        case Type.BOOLEAN:
443674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            // f ? 0 : 1
444674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.push(1);
445674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.math(e.XOR, Type.INT_TYPE);
446674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            break;
447674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        case Type.FLOAT:
448674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            // Float.floatToIntBits(f)
449674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.invoke_static(Constants.TYPE_FLOAT, FLOAT_TO_INT_BITS);
450674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            break;
451674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        case Type.DOUBLE:
452674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            // Double.doubleToLongBits(f), hash_code(Long.TYPE)
453674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.invoke_static(Constants.TYPE_DOUBLE, DOUBLE_TO_LONG_BITS);
454674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            // fall through
455674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        case Type.LONG:
456674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            hash_long(e);
457674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
458674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
459674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
460674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static void hash_long(CodeEmitter e) {
461674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        // (int)(f ^ (f >>> 32))
462674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.dup2();
463674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.push(32);
464674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.math(e.USHR, Type.LONG_TYPE);
465674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.math(e.XOR, Type.LONG_TYPE);
466674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.cast_numeric(Type.LONG_TYPE, Type.INT_TYPE);
467674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
468674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
469674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen//     public static void not_equals(CodeEmitter e, Type type, Label notEquals) {
470674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen//         not_equals(e, type, notEquals, null);
471674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen//     }
472674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
473674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
474674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Branches to the specified label if the top two items on the stack
475674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * are not equal. The items must both be of the specified
476674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * class. Equality is determined by comparing primitive values
477674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * directly and by invoking the <code>equals</code> method for
478674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Objects. Arrays are recursively processed in the same manner.
479674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
480674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static void not_equals(final CodeEmitter e, Type type, final Label notEquals, final Customizer customizer) {
481674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        (new ProcessArrayCallback() {
482674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            public void processElement(Type type) {
483674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                not_equals_helper(e, type, notEquals, customizer, this);
484674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
485674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }).processElement(type);
486674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
487674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
488674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static void not_equals_helper(CodeEmitter e,
489674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                          Type type,
490674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                          Label notEquals,
491674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                          Customizer customizer,
492674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                          ProcessArrayCallback callback) {
493674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (TypeUtils.isPrimitive(type)) {
494674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.if_cmp(type, e.NE, notEquals);
495674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } else {
496674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            Label end = e.make_label();
497674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            nullcmp(e, notEquals, end);
498674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (TypeUtils.isArray(type)) {
499674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                Label checkContents = e.make_label();
500674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.dup2();
501674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.arraylength();
502674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.swap();
503674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.arraylength();
504674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.if_icmp(e.EQ, checkContents);
505674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.pop2();
506674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.goTo(notEquals);
507674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.mark(checkContents);
508674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                EmitUtils.process_arrays(e, type, callback);
509674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            } else {
510674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                if (customizer != null) {
511674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    customizer.customize(e, type);
512674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    e.swap();
513674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    customizer.customize(e, type);
514674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                }
515674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.invoke_virtual(Constants.TYPE_OBJECT, EQUALS);
516674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.if_jump(e.EQ, notEquals);
517674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
518674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.mark(end);
519674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
520674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
521674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
522674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
523674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * If both objects on the top of the stack are non-null, does nothing.
524674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * If one is null, or both are null, both are popped off and execution
525674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * branches to the respective label.
526674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param oneNull label to branch to if only one of the objects is null
527674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * @param bothNull label to branch to if both of the objects are null
528674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
529674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static void nullcmp(CodeEmitter e, Label oneNull, Label bothNull) {
530674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.dup2();
531674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Label nonNull = e.make_label();
532674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Label oneNullHelper = e.make_label();
533674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Label end = e.make_label();
534674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.ifnonnull(nonNull);
535674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.ifnonnull(oneNullHelper);
536674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.pop2();
537674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.goTo(bothNull);
538674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
539674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.mark(nonNull);
540674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.ifnull(oneNullHelper);
541674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.goTo(end);
542674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
543674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.mark(oneNullHelper);
544674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.pop2();
545674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.goTo(oneNull);
546674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
547674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.mark(end);
548674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
549674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
550674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /*
551674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static void to_string(CodeEmitter e,
552674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                 Type type,
553674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                 ArrayDelimiters delims,
554674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                 Customizer customizer) {
555674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.new_instance(Constants.TYPE_STRING_BUFFER);
556674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.dup();
557674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_constructor(Constants.TYPE_STRING_BUFFER);
558674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.swap();
559674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        append_string(e, type, delims, customizer);
560674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_virtual(Constants.TYPE_STRING_BUFFER, TO_STRING);
561674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
562674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    */
563674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
564674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static void append_string(final CodeEmitter e,
565674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                     Type type,
566674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                     final ArrayDelimiters delims,
567674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                     final Customizer customizer) {
568674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final ArrayDelimiters d = (delims != null) ? delims : DEFAULT_DELIMITERS;
569674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        ProcessArrayCallback callback = new ProcessArrayCallback() {
570674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            public void processElement(Type type) {
571674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                append_string_helper(e, type, d, customizer, this);
572674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.push(d.inside);
573674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING);
574674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
575674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        };
576674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        append_string_helper(e, type, d, customizer, callback);
577674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
578674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
579674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static void append_string_helper(CodeEmitter e,
580674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                             Type type,
581674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                             ArrayDelimiters delims,
582674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                             Customizer customizer,
583674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                             ProcessArrayCallback callback) {
584674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Label skip = e.make_label();
585674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Label end = e.make_label();
586674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (TypeUtils.isPrimitive(type)) {
587674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            switch (type.getSort()) {
588674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            case Type.INT:
589674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            case Type.SHORT:
590674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            case Type.BYTE:
591674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_INT);
592674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                break;
593674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            case Type.DOUBLE:
594674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_DOUBLE);
595674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                break;
596674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            case Type.FLOAT:
597674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_FLOAT);
598674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                break;
599674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            case Type.LONG:
600674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_LONG);
601674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                break;
602674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            case Type.BOOLEAN:
603674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_BOOLEAN);
604674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                break;
605674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            case Type.CHAR:
606674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_CHAR);
607674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                break;
608674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
609674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } else if (TypeUtils.isArray(type)) {
610674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.dup();
611674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.ifnull(skip);
612674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.swap();
613674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (delims != null && delims.before != null && !"".equals(delims.before)) {
614674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.push(delims.before);
615674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING);
616674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.swap();
617674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
618674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            EmitUtils.process_array(e, type, callback);
619674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            shrinkStringBuffer(e, 2);
620674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (delims != null && delims.after != null && !"".equals(delims.after)) {
621674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.push(delims.after);
622674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING);
623674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
624674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } else {
625674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.dup();
626674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.ifnull(skip);
627674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (customizer != null) {
628674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                customizer.customize(e, type);
629674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
630674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.invoke_virtual(Constants.TYPE_OBJECT, TO_STRING);
631674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING);
632674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
633674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.goTo(end);
634674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.mark(skip);
635674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.pop();
636674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.push("null");
637674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING);
638674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.mark(end);
639674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
640674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
641674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static void shrinkStringBuffer(CodeEmitter e, int amt) {
642674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.dup();
643674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.dup();
644674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_virtual(Constants.TYPE_STRING_BUFFER, LENGTH);
645674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.push(amt);
646674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.math(e.SUB, Type.INT_TYPE);
647674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_virtual(Constants.TYPE_STRING_BUFFER, SET_LENGTH);
648674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
649674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
650674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static class ArrayDelimiters {
651674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        private String before;
652674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        private String inside;
653674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        private String after;
654674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
655674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        public ArrayDelimiters(String before, String inside, String after) {
656674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            this.before = before;
657674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            this.inside = inside;
658674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            this.after = after;
659674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
660674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
661674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
662674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static void load_method(CodeEmitter e, MethodInfo method) {
663674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        load_class(e, method.getClassInfo().getType());
664674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.push(method.getSignature().getName());
665674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        push_object(e, method.getSignature().getArgumentTypes());
666674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_virtual(Constants.TYPE_CLASS, GET_DECLARED_METHOD);
667674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
668674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
669674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private interface ParameterTyper {
670674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Type[] getParameterTypes(MethodInfo member);
671674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
672674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
673674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static void method_switch(CodeEmitter e,
674674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                     List methods,
675674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                     ObjectSwitchCallback callback) {
676674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        member_switch_helper(e, methods, callback, true);
677674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
678674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
679674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static void constructor_switch(CodeEmitter e,
680674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                          List constructors,
681674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                          ObjectSwitchCallback callback) {
682674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        member_switch_helper(e, constructors, callback, false);
683674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
684674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
685674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static void member_switch_helper(final CodeEmitter e,
686674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                             List members,
687674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                             final ObjectSwitchCallback callback,
688674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                             boolean useName) {
689674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        try {
690674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            final Map cache = new HashMap();
691674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            final ParameterTyper cached = new ParameterTyper() {
692674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    public Type[] getParameterTypes(MethodInfo member) {
693674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        Type[] types = (Type[])cache.get(member);
694674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        if (types == null) {
695674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            cache.put(member, types = member.getSignature().getArgumentTypes());
696674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        }
697674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        return types;
698674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    }
699674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                };
700674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            final Label def = e.make_label();
701674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            final Label end = e.make_label();
702674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (useName) {
703674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.swap();
704674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                final Map buckets = CollectionUtils.bucket(members, new Transformer() {
705674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        public Object transform(Object value) {
706674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            return ((MethodInfo)value).getSignature().getName();
707674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        }
708674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    });
709674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                String[] names = (String[])buckets.keySet().toArray(new String[buckets.size()]);
710674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                EmitUtils.string_switch(e, names, Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
711674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        public void processCase(Object key, Label dontUseEnd) throws Exception {
712674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            member_helper_size(e, (List)buckets.get(key), callback, cached, def, end);
713674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        }
714674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        public void processDefault() throws Exception {
715674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            e.goTo(def);
716674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        }
717674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    });
718674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            } else {
719674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                member_helper_size(e, members, callback, cached, def, end);
720674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
721674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.mark(def);
722674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.pop();
723674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            callback.processDefault();
724674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.mark(end);
725674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } catch (RuntimeException ex) {
726674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            throw ex;
727674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } catch (Error ex) {
728674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            throw ex;
729674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } catch (Exception ex) {
730674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            throw new CodeGenerationException(ex);
731674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
732674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
733674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
734674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static void member_helper_size(final CodeEmitter e,
735674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                           List members,
736674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                           final ObjectSwitchCallback callback,
737674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                           final ParameterTyper typer,
738674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                           final Label def,
739674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                           final Label end) throws Exception {
740674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        final Map buckets = CollectionUtils.bucket(members, new Transformer() {
741674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            public Object transform(Object value) {
742674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                return new Integer(typer.getParameterTypes((MethodInfo)value).length);
743674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
744674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        });
745674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.dup();
746674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.arraylength();
747674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.process_switch(EmitUtils.getSwitchKeys(buckets), new ProcessSwitchCallback() {
748674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            public void processCase(int key, Label dontUseEnd) throws Exception {
749674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                List bucket = (List)buckets.get(new Integer(key));
750674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                member_helper_type(e, bucket, callback, typer, def, end, new BitSet());
751674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
752674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            public void processDefault() throws Exception {
753674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.goTo(def);
754674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
755674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        });
756674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
757674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
758674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static void member_helper_type(final CodeEmitter e,
759674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                           List members,
760674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                           final ObjectSwitchCallback callback,
761674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                           final ParameterTyper typer,
762674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                           final Label def,
763674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                           final Label end,
764674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                           final BitSet checked) throws Exception {
765674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (members.size() == 1) {
766674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            MethodInfo member = (MethodInfo)members.get(0);
767674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            Type[] types = typer.getParameterTypes(member);
768674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            // need to check classes that have not already been checked via switches
769674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            for (int i = 0; i < types.length; i++) {
770674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                if (checked == null || !checked.get(i)) {
771674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    e.dup();
772674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    e.aaload(i);
773674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    e.invoke_virtual(Constants.TYPE_CLASS, GET_NAME);
774674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    e.push(TypeUtils.emulateClassGetName(types[i]));
775674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    e.invoke_virtual(Constants.TYPE_OBJECT, EQUALS);
776674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    e.if_jump(e.EQ, def);
777674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                }
778674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
779674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.pop();
780674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            callback.processCase(member, end);
781674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } else {
782674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            // choose the index that has the best chance of uniquely identifying member
783674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            Type[] example = typer.getParameterTypes((MethodInfo)members.get(0));
784674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            Map buckets = null;
785674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            int index = -1;
786674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            for (int i = 0; i < example.length; i++) {
787674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                final int j = i;
788674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                Map test = CollectionUtils.bucket(members, new Transformer() {
789674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    public Object transform(Object value) {
790674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        return TypeUtils.emulateClassGetName(typer.getParameterTypes((MethodInfo)value)[j]);
791674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    }
792674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                });
793674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                if (buckets == null || test.size() > buckets.size()) {
794674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    buckets = test;
795674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    index = i;
796674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                }
797674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
798674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (buckets == null || buckets.size() == 1) {
799674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                // TODO: switch by returnType
800674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                // must have two methods with same name, types, and different return types
801674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.goTo(def);
802674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            } else {
803674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                checked.set(index);
804674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
805674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.dup();
806674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.aaload(index);
807674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.invoke_virtual(Constants.TYPE_CLASS, GET_NAME);
808674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
809674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                final Map fbuckets = buckets;
810674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                String[] names = (String[])buckets.keySet().toArray(new String[buckets.size()]);
811674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                EmitUtils.string_switch(e, names, Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
812674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    public void processCase(Object key, Label dontUseEnd) throws Exception {
813674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        member_helper_type(e, (List)fbuckets.get(key), callback, typer, def, end, checked);
814674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    }
815674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    public void processDefault() throws Exception {
816674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        e.goTo(def);
817674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    }
818674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                });
819674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
820674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
821674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
822674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
823674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static void wrap_throwable(Block block, Type wrapper) {
824674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        CodeEmitter e = block.getCodeEmitter();
825674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.catch_exception(block, Constants.TYPE_THROWABLE);
826674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.new_instance(wrapper);
827674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.dup_x1();
828674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.swap();
829674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_constructor(wrapper, CSTRUCT_THROWABLE);
830674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.athrow();
831674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
832674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
833674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static void add_properties(ClassEmitter ce, String[] names, Type[] types) {
834674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        for (int i = 0; i < names.length; i++) {
835674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            String fieldName = "$cglib_prop_" + names[i];
836674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            ce.declare_field(Constants.ACC_PRIVATE, fieldName, types[i], null);
837674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            EmitUtils.add_property(ce, names[i], types[i], fieldName);
838674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
839674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
840674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
841674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static void add_property(ClassEmitter ce, String name, Type type, String fieldName) {
842674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        String property = TypeUtils.upperFirst(name);
843674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        CodeEmitter e;
844674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e = ce.begin_method(Constants.ACC_PUBLIC,
845674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            new Signature("get" + property,
846674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                          type,
847674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                          Constants.TYPES_EMPTY),
848674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            null);
849674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_this();
850674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.getfield(fieldName);
851674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.return_value();
852674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.end_method();
853674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
854674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e = ce.begin_method(Constants.ACC_PUBLIC,
855674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            new Signature("set" + property,
856674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                          Type.VOID_TYPE,
857674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                          new Type[]{ type }),
858674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            null);
859674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_this();
860674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_arg(0);
861674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.putfield(fieldName);
862674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.return_value();
863674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.end_method();
864674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
865674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
866674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /* generates:
867674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen       } catch (RuntimeException e) {
868674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen         throw e;
869674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen       } catch (Error e) {
870674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen         throw e;
871674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen       } catch (<DeclaredException> e) {
872674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen         throw e;
873674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen       } catch (Throwable e) {
874674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen         throw new <Wrapper>(e);
875674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen       }
876674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    */
877674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static void wrap_undeclared_throwable(CodeEmitter e, Block handler, Type[] exceptions, Type wrapper) {
878674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Set set = (exceptions == null) ? Collections.EMPTY_SET : new HashSet(Arrays.asList(exceptions));
879674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
880674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (set.contains(Constants.TYPE_THROWABLE))
881674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            return;
882674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
883674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        boolean needThrow = exceptions != null;
884674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (!set.contains(Constants.TYPE_RUNTIME_EXCEPTION)) {
885674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.catch_exception(handler, Constants.TYPE_RUNTIME_EXCEPTION);
886674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            needThrow = true;
887674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
888674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (!set.contains(Constants.TYPE_ERROR)) {
889674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.catch_exception(handler, Constants.TYPE_ERROR);
890674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            needThrow = true;
891674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
892674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (exceptions != null) {
893674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            for (int i = 0; i < exceptions.length; i++) {
894674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                e.catch_exception(handler, exceptions[i]);
895674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
896674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
897674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (needThrow) {
898674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.athrow();
899674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
900674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        // e -> eo -> oeo -> ooe -> o
901674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.catch_exception(handler, Constants.TYPE_THROWABLE);
902674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.new_instance(wrapper);
903674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.dup_x1();
904674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.swap();
905674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_constructor(wrapper, CSTRUCT_THROWABLE);
906674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.athrow();
907674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
908674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
909674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static CodeEmitter begin_method(ClassEmitter e, MethodInfo method) {
910674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return begin_method(e, method, method.getModifiers());
911674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
912674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
913674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static CodeEmitter begin_method(ClassEmitter e, MethodInfo method, int access) {
914674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return e.begin_method(access,
915674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                              method.getSignature(),
916674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                              method.getExceptionTypes());
917674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
918674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen}
919