diff options
Diffstat (limited to 'src')
4 files changed, 198 insertions, 6 deletions
diff --git a/src/classes/com/sun/gluegen/JavaConfiguration.java b/src/classes/com/sun/gluegen/JavaConfiguration.java index 152d9cf80..ae8c46eaa 100644 --- a/src/classes/com/sun/gluegen/JavaConfiguration.java +++ b/src/classes/com/sun/gluegen/JavaConfiguration.java @@ -116,6 +116,8 @@ public class JavaConfiguration { private Map/*<String,String>*/ javaMethodRenames = new HashMap(); private Map/*<String,List<String>>*/ javaPrologues = new HashMap(); private Map/*<String,List<String>>*/ javaEpilogues = new HashMap(); + private Map/*<String,Map<Integer,String>>*/ rangeChecks = new HashMap(); + private Map/*<String,Map<Integer,String>>*/ byteRangeChecks = new HashMap(); /** Reads the configuration file. @param filename path to file that should be read @@ -569,6 +571,22 @@ public class JavaConfiguration { return res; } + /** Returns a map of Integer argument numbers to expressions to be + used to range check the given arguments to the given function. + Returns null if there were no range check expressions supplied + for this function. */ + public Map/*<Integer, String>*/ rangeCheckExpressions(String functionName) { + return (Map/*<Integer, String>*/) rangeChecks.get(functionName); + } + + /** Returns a map of Integer argument numbers to expressions to be + used to range check (in size of bytes) the given arguments to + the given function. Returns null if there were no range check + expressions supplied for this function. */ + public Map/*<Integer, String>*/ byteRangeCheckExpressions(String functionName) { + return (Map/*<Integer, String>*/) byteRangeChecks.get(functionName); + } + //---------------------------------------------------------------------- // Internals only below this point // @@ -686,6 +704,14 @@ public class JavaConfiguration { readJavaPrologueOrEpilogue(tok, filename, lineNo, false); // Warning: make sure delimiters are reset at the top of this loop // because readJavaPrologueOrEpilogue changes them. + } else if (cmd.equalsIgnoreCase("RangeCheck")) { + readRangeCheck(tok, filename, lineNo, false); + // Warning: make sure delimiters are reset at the top of this loop + // because RangeCheck changes them. + } else if (cmd.equalsIgnoreCase("RangeCheckBytes")) { + readRangeCheck(tok, filename, lineNo, true); + // Warning: make sure delimiters are reset at the top of this loop + // because RangeCheckBytes changes them. } else { throw new RuntimeException("Unknown command \"" + cmd + "\" in command file " + filename + @@ -1131,6 +1157,33 @@ public class JavaConfiguration { } } + protected void readRangeCheck(StringTokenizer tok, String filename, int lineNo, boolean inBytes) { + try { + String functionName = tok.nextToken(); + int argNum = Integer.parseInt(tok.nextToken()); + String restOfLine = tok.nextToken("\n\r\f"); + restOfLine = restOfLine.trim(); + Map/*<Integer, String>*/ checksForFunction = null; + if (inBytes) { + checksForFunction = (Map/*<Integer, String>*/) byteRangeChecks.get(functionName); + } else { + checksForFunction = (Map/*<Integer, String>*/) rangeChecks.get(functionName); + } + if (checksForFunction == null) { + checksForFunction = new HashMap/*<Integer, String>*/(); + if (inBytes) { + byteRangeChecks.put(functionName, checksForFunction); + } else { + rangeChecks.put(functionName, checksForFunction); + } + } + checksForFunction.put(new Integer(argNum), restOfLine); + } catch (Exception e) { + throw new RuntimeException("Error parsing \"RangeCheck" + (inBytes ? "Bytes" : "") + "\" command at line " + lineNo + + " in file \"" + filename + "\"", e); + } + } + protected static TypeInfo parseTypeInfo(String cType, JavaType javaType) { String typeName = null; int pointerDepth = 0; diff --git a/src/classes/com/sun/gluegen/JavaEmitter.java b/src/classes/com/sun/gluegen/JavaEmitter.java index d4bafb7a8..f0799067e 100644 --- a/src/classes/com/sun/gluegen/JavaEmitter.java +++ b/src/classes/com/sun/gluegen/JavaEmitter.java @@ -377,6 +377,8 @@ public class JavaEmitter implements GlueEmitter { emitter.setReturnedArrayLengthExpression(cfg.returnedArrayLength(binding.getName())); emitter.setPrologue(prologue); emitter.setEpilogue(epilogue); + emitter.setRangeCheckExpressions(cfg.rangeCheckExpressions(binding.getName())); + emitter.setByteRangeCheckExpressions(cfg.byteRangeCheckExpressions(binding.getName())); allEmitters.add(emitter); } @@ -430,6 +432,8 @@ public class JavaEmitter implements GlueEmitter { } emitter.addModifier(JavaMethodBindingEmitter.NATIVE); emitter.setReturnedArrayLengthExpression(cfg.returnedArrayLength(binding.getName())); + emitter.setRangeCheckExpressions(cfg.rangeCheckExpressions(binding.getName())); + emitter.setByteRangeCheckExpressions(cfg.byteRangeCheckExpressions(binding.getName())); allEmitters.add(emitter); // Optionally emit the entry point taking arrays which handles @@ -455,6 +459,8 @@ public class JavaEmitter implements GlueEmitter { } emitter.addModifier(JavaMethodBindingEmitter.NATIVE); emitter.setReturnedArrayLengthExpression(cfg.returnedArrayLength(binding.getName())); + emitter.setRangeCheckExpressions(cfg.rangeCheckExpressions(binding.getName())); + emitter.setByteRangeCheckExpressions(cfg.byteRangeCheckExpressions(binding.getName())); allEmitters.add(emitter); } } diff --git a/src/classes/com/sun/gluegen/JavaMethodBindingEmitter.java b/src/classes/com/sun/gluegen/JavaMethodBindingEmitter.java index 5a7e065f7..7e08977a6 100644 --- a/src/classes/com/sun/gluegen/JavaMethodBindingEmitter.java +++ b/src/classes/com/sun/gluegen/JavaMethodBindingEmitter.java @@ -87,6 +87,10 @@ public class JavaMethodBindingEmitter extends FunctionEmitter // number of elements of the returned array. private String returnedArrayLengthExpression; + // Range-check expressions for various Buffer arguments + private Map/*<Integer, String>*/ rangeCheckExpressions; + private Map/*<Integer, String>*/ byteRangeCheckExpressions; + public JavaMethodBindingEmitter(MethodBinding binding, PrintWriter output, String runtimeExceptionType, @@ -126,9 +130,11 @@ public class JavaMethodBindingEmitter extends FunctionEmitter forDirectBufferImplementation = arg.forDirectBufferImplementation; forIndirectBufferAndArrayImplementation = arg.forIndirectBufferAndArrayImplementation; isUnimplemented = arg.isUnimplemented; - returnedArrayLengthExpression = arg.returnedArrayLengthExpression; prologue = arg.prologue; epilogue = arg.epilogue; + returnedArrayLengthExpression = arg.returnedArrayLengthExpression; + rangeCheckExpressions = arg.rangeCheckExpressions; + byteRangeCheckExpressions = arg.byteRangeCheckExpressions; } public final MethodBinding getBinding() { return binding; } @@ -193,6 +199,14 @@ public class JavaMethodBindingEmitter extends FunctionEmitter this.forImplementingMethodCall = impl; } + public void setRangeCheckExpressions(Map/*<Integer, String>*/ rangeChecks) { + this.rangeCheckExpressions = rangeChecks; + } + + public void setByteRangeCheckExpressions(Map/*<Integer, String>*/ rangeChecks) { + this.byteRangeCheckExpressions = rangeChecks; + } + protected void emitReturnType(PrintWriter writer) { writer.print(getReturnTypeString(false)); @@ -424,6 +438,44 @@ public class JavaMethodBindingEmitter extends FunctionEmitter } } } + + emitManuallySpecifiedRangeChecks(rangeCheckExpressions, false, writer); + emitManuallySpecifiedRangeChecks(byteRangeCheckExpressions, true, writer); + } + + protected void emitManuallySpecifiedRangeChecks(Map/*<Integer, String>*/ rangeChecks, + boolean inBytes, + PrintWriter writer) { + if (rangeChecks == null) { + return; + } + + // Check lengths of arrays and buffers with user-specified checks + for (Iterator iter = rangeChecks.keySet().iterator(); iter.hasNext(); ) { + Integer argNumBox = (Integer) iter.next(); + int argNum = argNumBox.intValue(); + JavaType type = binding.getJavaArgumentType(argNum); + String argName = getArgumentName(argNum); + if (type.isPrimitiveArray()) { + String offsetArg = offsetArgName(argNum); + if (inBytes) { + throw new RuntimeException("Can not specify RangeCheckBytes for primitive array arguments (failed on function " + + binding.getName() + ", argument " + argName + ")"); + } + writer.println(" BufferFactory.rangeCheck(" + argName + ", " + offsetArg + ", " + + new MessageFormat((String) rangeChecks.get(argNumBox)).format(argumentNameArray()) + + ");"); + } else if (!type.isPrimitive()) { + // Assume it's a Buffer + writer.print(" BufferFactory.rangeCheck"); + if (inBytes) { + writer.print("Bytes"); + } + writer.println("(" + argName + ", " + + new MessageFormat((String) rangeChecks.get(argNumBox)).format(argumentNameArray()) + + ");"); + } + } } protected void emitCall(MethodBinding binding, PrintWriter writer, boolean direct) { @@ -601,11 +653,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter writer.print(" return " + returnType.getName() + ".create(_res.order(ByteOrder.nativeOrder()))"); } else { writer.println(" _res.order(ByteOrder.nativeOrder());"); - String[] argumentNames = new String[binding.getNumArguments()]; - for (int i = 0; i < binding.getNumArguments(); i++) { - argumentNames[i] = getArgumentName(i); - } - String expr = new MessageFormat(fmt).format(argumentNames); + String expr = new MessageFormat(fmt).format(argumentNameArray()); PointerType cReturnTypePointer = binding.getCReturnType().asPointer(); CompoundType cReturnType = null; if (cReturnTypePointer != null) { @@ -648,6 +696,14 @@ public class JavaMethodBindingEmitter extends FunctionEmitter } } + protected String[] argumentNameArray() { + String[] argumentNames = new String[binding.getNumArguments()]; + for (int i = 0; i < binding.getNumArguments(); i++) { + argumentNames[i] = getArgumentName(i); + } + return argumentNames; + } + public static String javaThisArgumentName() { return "jthis0"; } diff --git a/src/classes/com/sun/gluegen/runtime/BufferFactory.java b/src/classes/com/sun/gluegen/runtime/BufferFactory.java index ca66e6915..dd8856a43 100644 --- a/src/classes/com/sun/gluegen/runtime/BufferFactory.java +++ b/src/classes/com/sun/gluegen/runtime/BufferFactory.java @@ -161,4 +161,81 @@ public class BufferFactory { throw new RuntimeException("Unknown buffer type " + buf.getClass().getName()); } + + public static void rangeCheck(byte[] array, int offset, int minElementsRemaining) { + if (array.length < offset + minElementsRemaining) { + throw new ArrayIndexOutOfBoundsException("Required " + minElementsRemaining + " elements in array, only had " + (array.length - offset)); + } + } + + public static void rangeCheck(char[] array, int offset, int minElementsRemaining) { + if (array.length < offset + minElementsRemaining) { + throw new ArrayIndexOutOfBoundsException("Required " + minElementsRemaining + " elements in array, only had " + (array.length - offset)); + } + } + + public static void rangeCheck(short[] array, int offset, int minElementsRemaining) { + if (array.length < offset + minElementsRemaining) { + throw new ArrayIndexOutOfBoundsException("Required " + minElementsRemaining + " elements in array, only had " + (array.length - offset)); + } + } + + public static void rangeCheck(int[] array, int offset, int minElementsRemaining) { + if (array.length < offset + minElementsRemaining) { + throw new ArrayIndexOutOfBoundsException("Required " + minElementsRemaining + " elements in array, only had " + (array.length - offset)); + } + } + + public static void rangeCheck(long[] array, int offset, int minElementsRemaining) { + if (array.length < offset + minElementsRemaining) { + throw new ArrayIndexOutOfBoundsException("Required " + minElementsRemaining + " elements in array, only had " + (array.length - offset)); + } + } + + public static void rangeCheck(float[] array, int offset, int minElementsRemaining) { + if (array.length < offset + minElementsRemaining) { + throw new ArrayIndexOutOfBoundsException("Required " + minElementsRemaining + " elements in array, only had " + (array.length - offset)); + } + } + + public static void rangeCheck(double[] array, int offset, int minElementsRemaining) { + if (array.length < offset + minElementsRemaining) { + throw new ArrayIndexOutOfBoundsException("Required " + minElementsRemaining + " elements in array, only had " + (array.length - offset)); + } + } + + public static void rangeCheck(Buffer buffer, int minElementsRemaining) { + if (buffer == null) { + return; + } + + if (buffer.remaining() < minElementsRemaining) { + throw new IndexOutOfBoundsException("Required " + minElementsRemaining + " remaining elements in buffer, only had " + buffer.remaining()); + } + } + + public static void rangeCheckBytes(Buffer buffer, int minBytesRemaining) { + if (buffer == null) { + return; + } + + int elementsRemaining = buffer.remaining(); + int bytesRemaining = 0; + if (buffer instanceof ByteBuffer) { + bytesRemaining = elementsRemaining; + } else if (buffer instanceof FloatBuffer) { + bytesRemaining = elementsRemaining * SIZEOF_FLOAT; + } else if (buffer instanceof IntBuffer) { + bytesRemaining = elementsRemaining * SIZEOF_INT; + } else if (buffer instanceof ShortBuffer) { + bytesRemaining = elementsRemaining * SIZEOF_SHORT; + } else if (buffer instanceof DoubleBuffer) { + bytesRemaining = elementsRemaining * SIZEOF_DOUBLE; + } else if (buffer instanceof LongBuffer) { + bytesRemaining = elementsRemaining * SIZEOF_LONG; + } + if (bytesRemaining < minBytesRemaining) { + throw new IndexOutOfBoundsException("Required " + minBytesRemaining + " remaining bytes in buffer, only had " + bytesRemaining); + } + } } |