1 /* |
|
2 * Permission is hereby granted, free of charge, to any person obtaining a copy of |
|
3 * this software and associated documentation files (the "Software"), to deal in |
|
4 * the Software without restriction, including without limitation the rights to |
|
5 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
|
6 * of the Software, and to permit persons to whom the Software is furnished to do |
|
7 * so, subject to the following conditions: |
|
8 * |
|
9 * The above copyright notice and this permission notice shall be included in all |
|
10 * copies or substantial portions of the Software. |
|
11 * |
|
12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
13 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
14 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
15 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
16 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
17 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|
18 * SOFTWARE. |
|
19 */ |
|
20 package jdk.nashorn.internal.runtime.regexp.joni; |
|
21 |
|
22 import java.io.FileOutputStream; |
|
23 import java.io.IOException; |
|
24 |
|
25 import jdk.nashorn.internal.runtime.regexp.joni.constants.AsmConstants; |
|
26 import jdk.internal.org.objectweb.asm.ClassWriter; |
|
27 import jdk.internal.org.objectweb.asm.MethodVisitor; |
|
28 import jdk.internal.org.objectweb.asm.Opcodes; |
|
29 |
|
30 abstract class AsmCompilerSupport extends Compiler implements Opcodes, AsmConstants { |
|
31 protected ClassWriter factory; // matcher allocator, also bit set, code rage and string template container |
|
32 protected MethodVisitor factoryInit;// factory constructor |
|
33 protected String factoryName; |
|
34 |
|
35 protected ClassWriter machine; // matcher |
|
36 protected MethodVisitor machineInit;// matcher constructor |
|
37 protected MethodVisitor match; // actual matcher implementation (the matchAt method) |
|
38 protected String machineName; |
|
39 |
|
40 // we will? try to manage visitMaxs ourselves for efficiency |
|
41 protected int maxStack = 1; |
|
42 protected int maxVars = LAST_INDEX; |
|
43 |
|
44 // for field generation |
|
45 protected int bitsets, ranges, templates; |
|
46 |
|
47 // simple class name postfix scheme for now |
|
48 static int REG_NUM = 0; |
|
49 |
|
50 // dummy class loader for now |
|
51 private static final class DummyClassLoader extends ClassLoader { |
|
52 public Class<?> defineClass(String name, byte[] bytes) { |
|
53 return super.defineClass(name, bytes, 0, bytes.length); |
|
54 } |
|
55 }; |
|
56 |
|
57 private static final DummyClassLoader loader = new DummyClassLoader(); |
|
58 |
|
59 AsmCompilerSupport(Analyser analyser) { |
|
60 super(analyser); |
|
61 } |
|
62 |
|
63 protected final void prepareFactory() { |
|
64 factory = new ClassWriter(ClassWriter.COMPUTE_MAXS); |
|
65 factoryName = "jdk/nashorn/internal/runtime/regexp/joni/MatcherFactory" + REG_NUM; |
|
66 |
|
67 factory.visit(V1_4, ACC_PUBLIC + ACC_FINAL, factoryName, null, "jdk/nashorn/internal/runtime/regexp/joni/MatcherFactory", null); |
|
68 |
|
69 MethodVisitor create = factory.visitMethod(ACC_SYNTHETIC, "create", "(Lorg/joni/Regex;[BII)Lorg/joni/Matcher;", null, null); |
|
70 create.visitTypeInsn(NEW, machineName); |
|
71 create.visitInsn(DUP); // instance |
|
72 create.visitVarInsn(ALOAD, 1); // Regex |
|
73 create.visitVarInsn(ALOAD, 2); // bytes[] |
|
74 create.visitVarInsn(ILOAD, 3); // p |
|
75 create.visitVarInsn(ILOAD, 4); // end |
|
76 create.visitMethodInsn(INVOKESPECIAL, machineName, "<init>", "(Lorg/joni/Regex;[BII)V"); |
|
77 create.visitInsn(ARETURN); |
|
78 create.visitMaxs(0, 0); |
|
79 //create.visitMaxs(6, 5); |
|
80 create.visitEnd(); |
|
81 } |
|
82 |
|
83 protected final void prepareFactoryInit() { |
|
84 factoryInit = factory.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); |
|
85 factoryInit.visitVarInsn(ALOAD, 0); |
|
86 factoryInit.visitMethodInsn(INVOKESPECIAL, "jdk/nashorn/internal/runtime/regexp/joni/MatcherFactory", "<init>", "()V"); |
|
87 } |
|
88 |
|
89 protected final void setupFactoryInit() { |
|
90 factoryInit.visitInsn(RETURN); |
|
91 factoryInit.visitMaxs(0, 0); |
|
92 //init.visitMaxs(1, 1); |
|
93 factoryInit.visitEnd(); |
|
94 } |
|
95 |
|
96 protected final void prepareMachine() { |
|
97 machine = new ClassWriter(ClassWriter.COMPUTE_MAXS); |
|
98 machineName = "jdk/nashorn/internal/runtime/regexp/joni/NativeMachine" + REG_NUM; |
|
99 } |
|
100 |
|
101 protected final void prepareMachineInit() { |
|
102 machine.visit(V1_4, ACC_PUBLIC + ACC_FINAL, machineName, null, "jdk/nashorn/internal/runtime/regexp/joni/NativeMachine", null); |
|
103 machineInit = machine.visitMethod(ACC_PROTECTED, "<init>", "(Lorg/joni/Regex;[BII)V", null, null); |
|
104 machineInit.visitVarInsn(ALOAD, THIS); // this |
|
105 machineInit.visitVarInsn(ALOAD, 1); // Regex |
|
106 machineInit.visitVarInsn(ALOAD, 2); // bytes[] |
|
107 machineInit.visitVarInsn(ILOAD, 3); // p |
|
108 machineInit.visitVarInsn(ILOAD, 4); // end |
|
109 machineInit.visitMethodInsn(INVOKESPECIAL, "jdk/nashorn/internal/runtime/regexp/joni/NativeMachine", "<init>", "(Lorg/joni/Regex;[BII)V"); |
|
110 } |
|
111 |
|
112 protected final void setupMachineInit() { |
|
113 if (bitsets + ranges + templates > 0) { // ok, some of these are in use, we'd like to cache the factory |
|
114 machine.visitField(ACC_PRIVATE + ACC_FINAL, "factory", "L" + factoryName + ";", null, null); |
|
115 machineInit.visitVarInsn(ALOAD, THIS); // this |
|
116 machineInit.visitVarInsn(ALOAD, 1); // this, Regex |
|
117 machineInit.visitFieldInsn(GETFIELD, "jdk/nashorn/internal/runtime/regexp/joni/Regex", "factory", "Lorg/joni/MatcherFactory;"); // this, factory |
|
118 machineInit.visitTypeInsn(CHECKCAST, factoryName); |
|
119 machineInit.visitFieldInsn(PUTFIELD, machineName, "factory", "L" + factoryName + ";"); // [] |
|
120 } |
|
121 |
|
122 machineInit.visitInsn(RETURN); |
|
123 machineInit.visitMaxs(0, 0); |
|
124 //init.visitMaxs(5, 5); |
|
125 machineInit.visitEnd(); |
|
126 } |
|
127 |
|
128 protected final void prepareMachineMatch() { |
|
129 match = machine.visitMethod(ACC_SYNTHETIC, "matchAt", "(III)I", null, null); |
|
130 move(S, SSTART); // s = sstart |
|
131 load("bytes", "[B"); // |
|
132 astore(BYTES); // byte[]bytes = this.bytes |
|
133 } |
|
134 |
|
135 protected final void setupMachineMatch() { |
|
136 match.visitInsn(ICONST_M1); |
|
137 match.visitInsn(IRETURN); |
|
138 |
|
139 match.visitMaxs(maxStack, maxVars); |
|
140 match.visitEnd(); |
|
141 } |
|
142 |
|
143 protected final void setupClasses() { |
|
144 byte[]factoryCode = factory.toByteArray(); |
|
145 byte[]machineCode = machine.toByteArray(); |
|
146 |
|
147 if (Config.DEBUG_ASM) { |
|
148 try { |
|
149 FileOutputStream fos; |
|
150 fos = new FileOutputStream(factoryName.substring(factoryName.lastIndexOf('/') + 1) + ".class"); |
|
151 fos.write(factoryCode); |
|
152 fos.close(); |
|
153 fos = new FileOutputStream(machineName.substring(machineName.lastIndexOf('/') + 1) + ".class"); |
|
154 fos.write(machineCode); |
|
155 fos.close(); |
|
156 } catch (IOException ioe) { |
|
157 ioe.printStackTrace(Config.err); |
|
158 } |
|
159 } |
|
160 |
|
161 loader.defineClass(machineName.replace('/', '.'), machineCode); |
|
162 Class<?> cls = loader.defineClass(factoryName.replace('/', '.'), factoryCode); |
|
163 try { |
|
164 regex.factory = (MatcherFactory)cls.newInstance(); |
|
165 } catch(Exception e) { |
|
166 e.printStackTrace(Config.err); |
|
167 } |
|
168 } |
|
169 |
|
170 protected final void aload(int var) { |
|
171 match.visitVarInsn(ALOAD, var); |
|
172 } |
|
173 |
|
174 protected final void astore(int var) { |
|
175 match.visitVarInsn(ASTORE, var); |
|
176 } |
|
177 |
|
178 protected final void loadThis() { |
|
179 match.visitVarInsn(ALOAD, THIS); |
|
180 } |
|
181 |
|
182 protected final void load(int var) { |
|
183 match.visitVarInsn(ILOAD, var); |
|
184 } |
|
185 |
|
186 protected final void store(int var) { |
|
187 match.visitVarInsn(ISTORE, var); |
|
188 } |
|
189 |
|
190 protected final void move(int to, int from) { |
|
191 load(from); |
|
192 store(to); |
|
193 } |
|
194 |
|
195 protected final void load(String field, String singature) { |
|
196 loadThis(); |
|
197 match.visitFieldInsn(GETFIELD, machineName, field, singature); |
|
198 } |
|
199 |
|
200 protected final void load(String field) { |
|
201 load(field, "I"); |
|
202 } |
|
203 |
|
204 protected final void store(String field, String singature) { |
|
205 loadThis(); |
|
206 match.visitFieldInsn(PUTFIELD, machineName, field, singature); |
|
207 } |
|
208 |
|
209 protected final void store(String field) { |
|
210 store(field, "I"); |
|
211 } |
|
212 |
|
213 protected final String installTemplate(char[] arr, int p, int length) { |
|
214 String templateName = TEMPLATE + ++templates; |
|
215 installArray(templateName, arr, p, length); |
|
216 return templateName; |
|
217 } |
|
218 |
|
219 protected final String installCodeRange(int[]arr) { |
|
220 String coreRangeName = CODERANGE + ++ranges; |
|
221 installArray(coreRangeName, arr); |
|
222 return coreRangeName; |
|
223 } |
|
224 |
|
225 protected final String installBitSet(int[]arr) { |
|
226 String bitsetName = BITSET + ++bitsets; |
|
227 installArray(bitsetName, arr); |
|
228 return bitsetName; |
|
229 } |
|
230 |
|
231 private void installArray(String name, int[]arr) { |
|
232 factory.visitField(ACC_PRIVATE + ACC_FINAL, name, "[I", null, null); |
|
233 factoryInit.visitVarInsn(ALOAD, THIS); // this; |
|
234 loadInt(factoryInit, arr.length); // this, length |
|
235 factoryInit.visitIntInsn(NEWARRAY, T_INT); // this, arr |
|
236 for (int i=0;i < arr.length; i++) buildArray(i, arr[i], IASTORE); |
|
237 factoryInit.visitFieldInsn(PUTFIELD, factoryName, name, "[I"); |
|
238 } |
|
239 |
|
240 private void installArray(String name, char[]arr, int p, int length) { |
|
241 factory.visitField(ACC_PRIVATE + ACC_FINAL, name, "[B", null, null); |
|
242 factoryInit.visitVarInsn(ALOAD, THIS); // this; |
|
243 loadInt(factoryInit, arr.length); // this, length |
|
244 factoryInit.visitIntInsn(NEWARRAY, T_BYTE); // this, arr |
|
245 for (int i=p, j=0; i < p + length; i++, j++) buildArray(j, arr[i] & 0xff, BASTORE); |
|
246 factoryInit.visitFieldInsn(PUTFIELD, factoryName, name, "[B"); |
|
247 } |
|
248 |
|
249 private void buildArray(int index, int value, int type) { |
|
250 factoryInit.visitInsn(DUP); // ... arr, arr |
|
251 loadInt(factoryInit, index); // ... arr, arr, index |
|
252 loadInt(factoryInit, value); // ... arr, arr, index, value |
|
253 factoryInit.visitInsn(type); // ... arr |
|
254 } |
|
255 |
|
256 private void loadInt(MethodVisitor mv, int value) { |
|
257 if (value >= -1 && value <= 5) { |
|
258 mv.visitInsn(value + ICONST_0); // ICONST_0 == 3 |
|
259 } else if (value >= 6 && value <= 127 || value >= -128 && value <= -2) { |
|
260 mv.visitIntInsn(BIPUSH, value); |
|
261 } else if (value >= 128 && value <= 32767 || value >= -32768 && value <= -129) { |
|
262 mv.visitIntInsn(SIPUSH, value); |
|
263 } else { |
|
264 mv.visitLdcInsn(new Integer(value)); |
|
265 } |
|
266 } |
|
267 } |
|