Skip to content
Commits on Source (4)
......@@ -4,7 +4,7 @@
<groupId>org.jruby.joni</groupId>
<artifactId>joni</artifactId>
<packaging>jar</packaging>
<version>2.1.27-SNAPSHOT</version>
<version>2.1.28-SNAPSHOT</version>
<name>Joni</name>
<description>
Java port of Oniguruma: http://www.geocities.jp/kosako3/oniguruma
......@@ -74,12 +74,6 @@
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>6.2.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
......
......@@ -4,5 +4,4 @@ open module org.jruby.joni {
exports org.joni.exception;
requires org.jruby.jcodings;
requires org.objectweb.asm;
}
\ No newline at end of file
/*
* 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 org.joni.ast.AnchorNode;
import org.joni.ast.BackRefNode;
import org.joni.ast.CClassNode;
import org.joni.ast.CTypeNode;
import org.joni.ast.CallNode;
import org.joni.ast.ListNode;
import org.joni.ast.EncloseNode;
import org.joni.ast.QuantifierNode;
final class AsmCompiler extends AsmCompilerSupport {
public AsmCompiler(Analyser analyser) {
super(analyser);
}
@Override
protected void prepare() {
REG_NUM++;
prepareMachine();
prepareMachineInit();
prepareMachineMatch();
prepareFactory();
prepareFactoryInit();
}
@Override
protected void finish() {
setupFactoryInit();
setupMachineInit();
setupMachineMatch();
setupClasses();
}
@Override
protected void compileAltNode(ListNode node) {
}
@Override
protected void addCompileString(byte[]bytes, int p, int mbLength, int strLength, boolean ignoreCase) {
String template = installTemplate(bytes, p, strLength);
}
@Override
protected void compileCClassNode(CClassNode node) {
if (node.bs != null) {
String bitsetName = installBitSet(node.bs.bits);
}
}
@Override
protected void compileCTypeNode(CTypeNode node) {
}
@Override
protected void compileAnyCharNode() {
}
@Override
protected void compileBackrefNode(BackRefNode node) {
}
@Override
protected void compileCallNode(CallNode node) {
}
@Override
protected void compileCECQuantifierNode(QuantifierNode node) {
}
@Override
protected void compileNonCECQuantifierNode(QuantifierNode node) {
}
@Override
protected void compileOptionNode(EncloseNode node) {
}
@Override
protected void compileEncloseNode(EncloseNode node) {
}
@Override
protected void compileAnchorNode(AnchorNode node) {
}
}
/*
* 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.internal.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));
}
}
}
......@@ -83,6 +83,4 @@ public interface Config extends org.jcodings.Config {
final boolean DEBUG_COMPILE_BYTE_CODE_INFO = DEBUG_ALL;
final boolean DEBUG_SEARCH = DEBUG_ALL;
final boolean DEBUG_MATCH = DEBUG_ALL;
final boolean DEBUG_ASM = true;
final boolean DEBUG_ASM_EXEC = true;
}
/*
* 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.constants.internal;
public interface AsmConstants {
final int THIS = 0;
// argument indexes
final int RANGE = 1;
final int SSTART = 2;
final int SPREV = 3;
// local var indexes
final int S = 4; // current index
final int BYTES = 5; // string
final int LAST_INDEX = BYTES + 1;
// frequently used field names (all ints)
final String STR = "str";
final String END = "end";
final String MSA_START = "msaStart";
final String MSA_OPTONS = "msaOptions";
final String MSA_BEST_LEN = "msaBestLen";
final String MSA_BEST_S = "msaBestS";
final String MSA_BEGIN = "msaBegin";
final String MSA_END = "msaEnd";
// generated field names
final String BITSET = "bitset";
final String CODERANGE = "range";
final String TEMPLATE = "template";
}