Java tutorial
/* * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is furnished to do * so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.joni; import java.io.FileOutputStream; import java.io.IOException; import org.joni.constants.AsmConstants; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; abstract class AsmCompilerSupport extends Compiler implements Opcodes, AsmConstants { protected ClassWriter factory; // matcher allocator, also bit set, code rage and string template container protected MethodVisitor factoryInit;// factory constructor protected String factoryName; protected ClassWriter machine; // matcher protected MethodVisitor machineInit;// matcher constructor protected MethodVisitor match; // actual matcher implementation (the matchAt method) protected String machineName; // we will? try to manage visitMaxs ourselves for efficiency protected int maxStack = 1; protected int maxVars = LAST_INDEX; // for field generation protected int bitsets, ranges, templates; // simple class name postfix scheme for now static int REG_NUM = 0; // dummy class loader for now private static final class DummyClassLoader extends ClassLoader { public Class<?> defineClass(String name, byte[] bytes) { return super.defineClass(name, bytes, 0, bytes.length); } }; private static final DummyClassLoader loader = new DummyClassLoader(); AsmCompilerSupport(Analyser analyser) { super(analyser); } protected final void prepareFactory() { factory = new ClassWriter(ClassWriter.COMPUTE_MAXS); factoryName = "org/joni/MatcherFactory" + REG_NUM; factory.visit(V1_4, ACC_PUBLIC + ACC_FINAL, factoryName, null, "org/joni/MatcherFactory", null); MethodVisitor create = factory.visitMethod(ACC_SYNTHETIC, "create", "(Lorg/joni/Regex;[BII)Lorg/joni/Matcher;", null, null); create.visitTypeInsn(NEW, machineName); create.visitInsn(DUP); // instance create.visitVarInsn(ALOAD, 1); // Regex create.visitVarInsn(ALOAD, 2); // bytes[] create.visitVarInsn(ILOAD, 3); // p create.visitVarInsn(ILOAD, 4); // end create.visitMethodInsn(INVOKESPECIAL, machineName, "<init>", "(Lorg/joni/Regex;[BII)V"); create.visitInsn(ARETURN); create.visitMaxs(0, 0); //create.visitMaxs(6, 5); create.visitEnd(); } protected final void prepareFactoryInit() { factoryInit = factory.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); factoryInit.visitVarInsn(ALOAD, 0); factoryInit.visitMethodInsn(INVOKESPECIAL, "org/joni/MatcherFactory", "<init>", "()V"); } protected final void setupFactoryInit() { factoryInit.visitInsn(RETURN); factoryInit.visitMaxs(0, 0); //init.visitMaxs(1, 1); factoryInit.visitEnd(); } protected final void prepareMachine() { machine = new ClassWriter(ClassWriter.COMPUTE_MAXS); machineName = "org/joni/NativeMachine" + REG_NUM; } protected final void prepareMachineInit() { machine.visit(V1_4, ACC_PUBLIC + ACC_FINAL, machineName, null, "org/joni/NativeMachine", null); machineInit = machine.visitMethod(ACC_PROTECTED, "<init>", "(Lorg/joni/Regex;[BII)V", null, null); machineInit.visitVarInsn(ALOAD, THIS); // this machineInit.visitVarInsn(ALOAD, 1); // Regex machineInit.visitVarInsn(ALOAD, 2); // bytes[] machineInit.visitVarInsn(ILOAD, 3); // p machineInit.visitVarInsn(ILOAD, 4); // end machineInit.visitMethodInsn(INVOKESPECIAL, "org/joni/NativeMachine", "<init>", "(Lorg/joni/Regex;[BII)V"); } protected final void setupMachineInit() { if (bitsets + ranges + templates > 0) { // ok, some of these are in use, we'd like to cache the factory machine.visitField(ACC_PRIVATE + ACC_FINAL, "factory", "L" + factoryName + ";", null, null); machineInit.visitVarInsn(ALOAD, THIS); // this machineInit.visitVarInsn(ALOAD, 1); // this, Regex machineInit.visitFieldInsn(GETFIELD, "org/joni/Regex", "factory", "Lorg/joni/MatcherFactory;"); // this, factory machineInit.visitTypeInsn(CHECKCAST, factoryName); machineInit.visitFieldInsn(PUTFIELD, machineName, "factory", "L" + factoryName + ";"); // [] } machineInit.visitInsn(RETURN); machineInit.visitMaxs(0, 0); //init.visitMaxs(5, 5); machineInit.visitEnd(); } protected final void prepareMachineMatch() { match = machine.visitMethod(ACC_SYNTHETIC, "matchAt", "(III)I", null, null); move(S, SSTART); // s = sstart load("bytes", "[B"); // astore(BYTES); // byte[]bytes = this.bytes } protected final void setupMachineMatch() { match.visitInsn(ICONST_M1); match.visitInsn(IRETURN); match.visitMaxs(maxStack, maxVars); match.visitEnd(); } protected final void setupClasses() { byte[] factoryCode = factory.toByteArray(); byte[] machineCode = machine.toByteArray(); if (Config.DEBUG_ASM) { try { FileOutputStream fos; fos = new FileOutputStream(factoryName.substring(factoryName.lastIndexOf('/') + 1) + ".class"); fos.write(factoryCode); fos.close(); fos = new FileOutputStream(machineName.substring(machineName.lastIndexOf('/') + 1) + ".class"); fos.write(machineCode); fos.close(); } catch (IOException ioe) { ioe.printStackTrace(Config.err); } } loader.defineClass(machineName.replace('/', '.'), machineCode); Class<?> cls = loader.defineClass(factoryName.replace('/', '.'), factoryCode); try { regex.factory = (MatcherFactory) cls.newInstance(); } catch (Exception e) { e.printStackTrace(Config.err); } } protected final void aload(int var) { match.visitVarInsn(ALOAD, var); } protected final void astore(int var) { match.visitVarInsn(ASTORE, var); } protected final void loadThis() { match.visitVarInsn(ALOAD, THIS); } protected final void load(int var) { match.visitVarInsn(ILOAD, var); } protected final void store(int var) { match.visitVarInsn(ISTORE, var); } protected final void move(int to, int from) { load(from); store(to); } protected final void load(String field, String singature) { loadThis(); match.visitFieldInsn(GETFIELD, machineName, field, singature); } protected final void load(String field) { load(field, "I"); } protected final void store(String field, String singature) { loadThis(); match.visitFieldInsn(PUTFIELD, machineName, field, singature); } protected final void store(String field) { store(field, "I"); } protected final String installTemplate(byte[] arr, int p, int length) { String templateName = TEMPLATE + ++templates; installArray(templateName, arr, p, length); return templateName; } protected final String installCodeRange(int[] arr) { String coreRangeName = CODERANGE + ++ranges; installArray(coreRangeName, arr); return coreRangeName; } protected final String installBitSet(int[] arr) { String bitsetName = BITSET + ++bitsets; installArray(bitsetName, arr); return bitsetName; } private void installArray(String name, int[] arr) { factory.visitField(ACC_PRIVATE + ACC_FINAL, name, "[I", null, null); factoryInit.visitVarInsn(ALOAD, THIS); // this; loadInt(factoryInit, arr.length); // this, length factoryInit.visitIntInsn(NEWARRAY, T_INT); // this, arr for (int i = 0; i < arr.length; i++) buildArray(i, arr[i], IASTORE); factoryInit.visitFieldInsn(PUTFIELD, factoryName, name, "[I"); } private void installArray(String name, byte[] arr, int p, int length) { factory.visitField(ACC_PRIVATE + ACC_FINAL, name, "[B", null, null); factoryInit.visitVarInsn(ALOAD, THIS); // this; loadInt(factoryInit, arr.length); // this, length factoryInit.visitIntInsn(NEWARRAY, T_BYTE); // this, arr for (int i = p, j = 0; i < p + length; i++, j++) buildArray(j, arr[i] & 0xff, BASTORE); factoryInit.visitFieldInsn(PUTFIELD, factoryName, name, "[B"); } private void buildArray(int index, int value, int type) { factoryInit.visitInsn(DUP); // ... arr, arr loadInt(factoryInit, index); // ... arr, arr, index loadInt(factoryInit, value); // ... arr, arr, index, value factoryInit.visitInsn(type); // ... arr } private void loadInt(MethodVisitor mv, int value) { if (value >= -1 && value <= 5) { mv.visitInsn(value + ICONST_0); // ICONST_0 == 3 } else if (value >= 6 && value <= 127 || value >= -128 && value <= -2) { mv.visitIntInsn(BIPUSH, value); } else if (value >= 128 && value <= 32767 || value >= -32768 && value <= -129) { mv.visitIntInsn(SIPUSH, value); } else { mv.visitLdcInsn(new Integer(value)); } } }