java-gobject-introspection r70 - in trunk: src/org/gnome/gir/compiler stub-examples



Author: walters
Date: Mon Sep 29 01:11:56 2008
New Revision: 70
URL: http://svn.gnome.org/viewvc/java-gobject-introspection?rev=70&view=rev

Log:
Supoprt for array+length arguments


Modified:
   trunk/src/org/gnome/gir/compiler/CodeFactory.java
   trunk/stub-examples/Test.java

Modified: trunk/src/org/gnome/gir/compiler/CodeFactory.java
==============================================================================
--- trunk/src/org/gnome/gir/compiler/CodeFactory.java	(original)
+++ trunk/src/org/gnome/gir/compiler/CodeFactory.java	Mon Sep 29 01:11:56 2008
@@ -39,6 +39,7 @@
 import static org.objectweb.asm.Opcodes.PUTSTATIC;
 import static org.objectweb.asm.Opcodes.RETURN;
 import static org.objectweb.asm.Opcodes.V1_6;
+import static org.objectweb.asm.Type.getType;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -162,6 +163,14 @@
 		return null;
 	}	
 	
+	public Type toJavaArray(TypeInfo containedType) {
+		Type result = toJava(containedType);
+		if (result == null)
+			return null;
+		String descriptor = result.getDescriptor();
+		return Type.getType("[" + descriptor);
+	}
+	
 	public Type toJava(TypeInfo type) {	
 		//Transfer transfer = arg.getOwnershipTransfer();
 		TypeTag tag = type.getTag();
@@ -171,7 +180,9 @@
 			// be a G-I bug
 			return Type.getType(Pointer.class);		
 		} else if (tag.equals(TypeTag.INTERFACE)) {
-			return typeFromInfo(type.getInterface());		
+			return typeFromInfo(type.getInterface());
+		} else if (tag.equals(TypeTag.ARRAY)) {
+			return toJavaArray(type.getParamType(0));
 		} else if (!type.isPointer() || (tag.equals(TypeTag.UTF8) || tag.equals(TypeTag.FILENAME))) {
 			return toTypeBase(tag);
 		} else if (type.isPointer()) {
@@ -207,7 +218,11 @@
 				return Type.getType(Pointer.class);
 			}
 		}
-		return toJava(arg.getType());
+		Type result = toJava(type);
+		if (result == null) {
+			logger.warning(String.format("Unhandled field type %s (type %s)", result, type));
+		}
+		return result;
 	}	
 	
 	public Type toJava(ArgInfo arg) {
@@ -300,35 +315,6 @@
 		return null;
 	}
 	
-	private List<Type> getCallableArgs(CallableInfo callable, boolean isMethod,
-				boolean allowError) {
-		ArgInfo[] args = callable.getArgs();
-		List<Type> types = new ArrayList<Type>();
-		boolean skipFirst = isMethod;
-		for (int i = 0; i < args.length; i++) {
-			ArgInfo arg = args[i];
-			Type t;
-			TypeInfo info = arg.getType();
-			TypeTag tag = info.getTag();			
-			if (tag.equals(TypeTag.ERROR)) {
-				if (allowError)
-					continue;
-				return null;
-			}
-			t = toJava(arg);
-			if (t == null) {
-				logger.warning("Unhandled argument: " + arg);
-				return null;
-			}
-			if (skipFirst)
-				skipFirst = false;
-			else
-				types.add(t);
-		}
-		
-		return types;
-	}
-	
 	private static abstract class ClassCompilation {
 		String namespace;
 		String baseName;
@@ -652,7 +638,7 @@
 		compilation.close();
 	}	
 	
-	private String ucaseToCamel(String ucase) {
+	private static String ucaseToCamel(String ucase) {
 		// So this function works on signal/property names too
 		ucase = ucase.replace('-', '_');
 		String[] components = ucase.split("_");
@@ -666,7 +652,7 @@
 		return builder.toString();
 	}
 	
-	private String ucaseToPascal(String ucase) {
+	private static String ucaseToPascal(String ucase) {
 		String camel = ucaseToCamel(ucase);
 		return Character.toUpperCase(camel.charAt(0)) + camel.substring(1);
 	}	
@@ -769,16 +755,19 @@
 		mv.visitEnd();		
 	}
 	
-	private void compileStaticConstructor(ObjectInfo info, ClassCompilation compilation, FunctionInfo fi) {	
+	private void writeStaticConstructor(ObjectInfo info, ClassCompilation compilation, FunctionInfo fi) {	
 		String globalInternalsName = getInternals(info);
 
 		ArgInfo[] argInfos = fi.getArgs();
-		List<Type> args = getCallableArgs(fi, false, false);		 
-		String descriptor = Type.getMethodDescriptor(typeFromInfo(info), args.toArray(new Type[0]));
+		CallableCompilationContext ctx = tryCompileCallable(fi, false, true, null);
+		if (ctx == null)
+			return;
+		List<Type> args = ctx.argTypes;	 
+		String descriptor = ctx.getDescriptor();
 		
 		int nArgs = args.size();
 		
-		String name = ucaseToCamel(fi.getName());
+		String name = ctx.name;
 		if (name.equals("new"))
 			name = "newDefault";
 		MethodVisitor mv = compilation.writer.visitMethod(ACC_PUBLIC + ACC_STATIC + ACC_FINAL, name, descriptor, null, null);
@@ -821,11 +810,16 @@
 	private void writeConstructor(ObjectInfo info, ClassCompilation compilation, FunctionInfo fi) {	
 		String globalInternalsName = getInternals(info);
 
-		ArgInfo[] argInfos = fi.getArgs();
-		List<Type> args = getCallableArgs(fi, false, false);		
+		CallableCompilationContext ctx = tryCompileCallable(fi);
+		if (ctx.throwsGError) {
+			logger.warning(String.format("Skipping constructor %s which uses GError", 
+					fi.getIdentifier()));
+			return;
+		}
+		List<Type> args = ctx.argTypes;
 		BaseInfo parent = info.getParent(); 
 		String parentInternalType = getInternalNameMapped(parent);
-		String descriptor = Type.getMethodDescriptor(Type.VOID_TYPE, args.toArray(new Type[0]));
+		String descriptor = ctx.getDescriptor();
 		
 		int nArgs = args.size();
 		
@@ -842,7 +836,7 @@
 		mv.visitLdcInsn(Type.getType(Pointer.class));
 		mv.visitIntInsn(BIPUSH, args.size());
 		mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
-		LocalVariableTable locals = new LocalVariableTable(Type.getObjectType(compilation.internalName), args, argInfos, true);
+		LocalVariableTable locals = ctx.allocLocals();
 		for (int i = 0; i < nArgs; i++) {
 			mv.visitInsn(DUP);
 			mv.visitIntInsn(BIPUSH, i);
@@ -1081,9 +1075,6 @@
 	private void compile(ObjectInfo info) {
 		StubClassCompilation compilation = getCompilation(info);
 		
-		if (info.getNamespace().equals("GObject") && info.getName().equals("Object"))
-			return;
-		
 		String internalName = getInternalName(info);
 		BaseInfo parent = info.getParent();
 		String parentInternalName;
@@ -1121,19 +1112,15 @@
 		
 		// First gather the set of all constructors; we need to avoid name clashes
 		for (FunctionInfo fi : info.getMethods()) {
-			boolean isConstructor = (fi.getFlags() & FunctionInfoFlags.IS_CONSTRUCTOR) != 0;
-			if (!isConstructor)
+			CallableCompilationContext ctx = tryCompileCallable(fi);
+			if (ctx == null || !ctx.isConstructor)
 				continue;
-			List<Type> args = getCallableArgs(fi, false, false);
-			if (args == null) {
-				logger.warning("Skipping constructor with unhandled arg signature: " + fi.getSymbol());
-				continue;
-			}
-			if (args.size() == 0) {
+
+			if (ctx.argTypes.size() == 0) {
 				logger.fine("Skipping 0-args constructor: " + fi.getName());
 				continue;
 			}
-			String descriptor = Type.getMethodDescriptor(Type.VOID_TYPE, args.toArray(new Type[0]));			
+			String descriptor = ctx.getDescriptor();
 			if (!ctors.containsKey(descriptor)) {
 				ctors.put(descriptor, new HashSet<FunctionInfo>());
 			}
@@ -1157,7 +1144,7 @@
 				}
 				for (FunctionInfo ctor : ctorGroup) {
 					if (ctor != defaultCtor) {
-						compileStaticConstructor(info, compilation, ctor);
+						writeStaticConstructor(info, compilation, ctor);
 					}
 				}
 			}
@@ -1166,13 +1153,10 @@
 		// Now do methods
 		Set<String> sigs = new HashSet<String>();		
 		for (FunctionInfo fi : info.getMethods()) {	
-			boolean isConstructor = (fi.getFlags() & FunctionInfoFlags.IS_CONSTRUCTOR) != 0;
-			if (isConstructor)
-				continue;
 			if (GOBJECT_METHOD_BLACKLIST.contains(fi.getName()))
 				continue;
 			CallableCompilationContext ctx = tryCompileCallable(fi, sigs);
-			if (ctx == null)
+			if (ctx == null || ctx.isConstructor)
 				continue;
 			writeCallable(ACC_PUBLIC, compilation, fi, ctx);
 		}
@@ -1187,7 +1171,7 @@
 			}
 			Type ifaceType = typeFromInfo(iface);
 			for (SignalInfo sig : iface.getSignals()) {
-				CallableCompilationContext ctx = tryCompileCallable(sig);
+				CallableCompilationContext ctx = tryCompileCallable(sig, null);
 				if (ctx == null)
 					continue;
 				// Insert the object as first parameter
@@ -1259,71 +1243,146 @@
 	}
 	
 	private static final class CallableCompilationContext {
+		CallableInfo info;
+		boolean isMethod;
+		boolean isConstructor;
+		String name;
 		Type returnType;
 		ArgInfo[] args;
+		Type thisType;
 		List<Type> argTypes;
+		List<String> argNames = new ArrayList<String>();
 		boolean throwsGError;
 		boolean isInterfaceMethod = false;
 		InterfaceInfo targetInterface = null;
-		public CallableCompilationContext(Type returnType, ArgInfo[] args,
-				List<Type> argTypes, boolean throwsGError) {
-			this.returnType = returnType;
-			this.args = args;
-			this.argTypes = argTypes;
-			this.throwsGError = throwsGError;
+		Map<Integer, Integer> lengthIndices;
+		
+		public CallableCompilationContext() {
+			// TODO Auto-generated constructor stub
+		}
+
+		public String getDescriptor() {
+			return Type.getMethodDescriptor(this.returnType, argTypes.toArray(new Type[] {}));
+		}
+		
+		public String getSignature() {
+			return getUniqueSignature(name, returnType, argTypes);
+		}
+		
+		public int argOffsetToApi(int offset) {
+			return offset - lengthIndices.size();
+		}
+
+		public LocalVariableTable allocLocals() {
+			return new LocalVariableTable(this);
 		}
 	}
 	
 	private CallableCompilationContext tryCompileCallable(CallableInfo si) {
-		Type returnType = getCallableReturn(si);
-		if (returnType == null) {
-			logger.warning("Skipping callable with unhandled return signature: " + si.getName());
-			return null;
-		}
-		ArgInfo[] argInfos = si.getArgs();		
-		List<Type> args = getCallableArgs(si, false, false);
-		if (args == null) {
-			logger.warning("Skipping callable with unhandled arg signature: " + si.getName());
-			return null;
-		}	
-		return new CallableCompilationContext(returnType, argInfos, args, false);
+		return tryCompileCallable(si, true, null);
 	}
 	
-	private String getUniqueSignature(String name, Type returnType, List<Type> args) {
-		StringBuilder builder = new StringBuilder(name);
-		builder.append("(");
-		for (Type arg: args)
-			builder.append(arg.getDescriptor());
-		builder.append(")");
-		builder.append(returnType.getDescriptor());
-		String signature = builder.toString();
-		return signature;
+	private CallableCompilationContext tryCompileCallable(CallableInfo si, Set<String> seenSignatures) {
+		return tryCompileCallable(si, true, seenSignatures);
 	}
 	
-	private CallableCompilationContext tryCompileCallable(FunctionInfo fi, Set<String> seenSignatures) {
-		Type returnType = getCallableReturn(fi);
-		if (returnType == null) {
-			logger.warning("Skipping function with unhandled return signature: " + fi.getSymbol());
-			return null;
+	private CallableCompilationContext tryCompileCallable(CallableInfo si, boolean allowError,
+			Set<String> seenSignatures) {
+		return tryCompileCallable(si, allowError, false, seenSignatures);
+	}
+	
+	private CallableCompilationContext tryCompileCallable(CallableInfo si, boolean allowError,
+			boolean isStaticCtor,
+			Set<String> seenSignatures) {
+		CallableCompilationContext ctx = new CallableCompilationContext();
+		if (si instanceof FunctionInfo) {
+			FunctionInfo fi = (FunctionInfo) si;
+			int flags = fi.getFlags();
+			ctx.isConstructor = !isStaticCtor && (flags & FunctionInfoFlags.IS_CONSTRUCTOR) != 0;
+			ctx.isMethod = !ctx.isConstructor && (flags & FunctionInfoFlags.IS_METHOD) != 0;
 		}
-		ArgInfo[] argInfos = fi.getArgs();
-		boolean throwsGError = argInfos.length > 0 && 
-			argInfos[argInfos.length-1].getType().getTag().equals(TypeTag.ERROR);
-		List<Type> args = getCallableArgs(fi, (fi.getFlags() & FunctionInfoFlags.IS_METHOD) > 0,
-					throwsGError);
-		if (args == null) {
-			logger.warning("Skipping function with unhandled arg signature: " + fi.getSymbol());
-			return null;
+		ctx.info = si;
+		ctx.args = si.getArgs();
+		if (ctx.isConstructor) {
+			ctx.returnType = Type.VOID_TYPE;
+			ctx.thisType = getCallableReturn(si); 
+		} else {
+			ctx.returnType = getCallableReturn(si);
 		}
-		String name = ucaseToCamel(fi.getName());
-		String signature = getUniqueSignature(name, returnType, args);
-		if (seenSignatures.contains(signature)) {
-			logger.warning("Function " + fi.getSymbol() + " duplicates signature: " 
-						+ signature);
+		if (ctx.returnType == null) {
+			logger.warning("Skipping callable with unhandled return signature: "+ si.getIdentifier());
 			return null;
 		}
-		seenSignatures.add(signature);
-		return new CallableCompilationContext(returnType, argInfos, args, throwsGError);
+		ArgInfo[] args = ctx.args;
+		
+		ctx.throwsGError = args.length > 0 && 
+			args[args.length-1].getType().getTag().equals(TypeTag.ERROR);
+		
+		List<Type> types = new ArrayList<Type>();		
+		boolean skipFirst = ctx.isMethod;
+		ctx.lengthIndices = new HashMap<Integer,Integer>();
+		for (int i = 0; i < args.length; i++) {
+			ArgInfo arg = args[i];
+			Type t;
+			TypeInfo info = arg.getType();
+			TypeTag tag = info.getTag();			
+			if (tag.equals(TypeTag.ERROR)) {
+				if (allowError)
+					continue;
+				logger.warning("Skipping callable with invalid error argument: " + si.getIdentifier());
+				return null;
+			}
+			t = toJava(arg);
+			if (t == null) {
+				logger.warning(String.format("Unhandled argument %s in callable %s", arg, si.getIdentifier()));
+				return null;
+			}
+			if (tag.equals(TypeTag.ARRAY)) {
+				int lenIdx = arg.getType().getArrayLength();
+				if (lenIdx >= 0)
+					ctx.lengthIndices.put(lenIdx, i);
+			}			
+			if (skipFirst) {
+				skipFirst = false;
+				if (ctx.isMethod)
+					ctx.thisType = t;
+			} else {
+				types.add(t);
+				ctx.argNames.add(arg.getName());
+			}
+		}
+		
+		/* Now go through and remove array length indices */
+		List<Type> filteredTypes = new ArrayList<Type>();
+		for (int i = 0; i < types.size(); i++) {
+			Integer index = ctx.lengthIndices.get(i + (ctx.isMethod ? 1 : 0));
+			if (index == null) {		
+				filteredTypes.add(types.get(i));
+			}
+		}
+		
+		ctx.argTypes = filteredTypes;
+		
+		ctx.name = ucaseToCamel(si.getName());
+		
+		if (seenSignatures != null) {
+			String signature = getUniqueSignature(ctx.name, ctx.returnType, ctx.argTypes);
+			if (seenSignatures.contains(signature)) {
+				logger.warning(String.format("Callable %s duplicates signature: %s", 
+						si.getIdentifier(), signature));
+				return null;
+			}
+			seenSignatures.add(signature);
+		}
+
+		return ctx;
+	}
+	
+	private static String getUniqueSignature(String name, Type returnType, List<Type> args) {
+		StringBuilder builder = new StringBuilder(name);
+		builder.append('/');
+		builder.append(Type.getMethodDescriptor(returnType, args.toArray(new Type[] {})));
+		return builder.toString();
 	}
 	
 	private Type writeLoadArgument(MethodVisitor mv, int loadOffset, Type argType) {
@@ -1354,27 +1413,30 @@
 		private Map<String,LocalVariable> locals;
 		private int lastOffset;
 		
-		public LocalVariableTable(Type thisArg, List<Type> args, ArgInfo[] argInfos, boolean isCtor) {
+		public LocalVariableTable(Type thisType, List<Type> args, List<String> argNames) {
 			lastOffset = 0;
 			locals = new LinkedHashMap<String,LocalVariable>();
-			if (thisArg != null) {
-				locals.put("this", new LocalVariable("this", 0, thisArg));
-				lastOffset += thisArg.getSize();
+			if (thisType != null) {
+				locals.put("this", new LocalVariable("this", 0, thisType));
+				lastOffset += thisType.getSize();
 			}
-			if (args == null)
-				return;			
-			final int thisOffset = (thisArg != null && !isCtor) ? 1 : 0;
 			int i = 0;
+			if (args == null)
+				return;
 			for (Type arg: args) {
 				String name;
-				if (argInfos != null)
-					name = argInfos[i+thisOffset].getName();
+				if (argNames != null)
+					name = argNames.get(i);
 				else
 					name = "arg" + i;
 				locals.put(name, new LocalVariable(name, lastOffset, arg));
 				lastOffset += arg.getSize();
 				i++;
-			}
+			}			
+		}
+		
+		public LocalVariableTable(CallableCompilationContext ctx) {
+			this(ctx.thisType, ctx.argTypes, ctx.argNames);
 		}
 		
 		public LocalVariable add(String name, Type type) {
@@ -1399,7 +1461,7 @@
 					return variable;
 				i++;
 			}
-			throw new IllegalArgumentException();
+			throw new IllegalArgumentException(String.format("Index %d is out of range (max %d)", index, locals.size()-1));
 		}
 		
 		public int getOffset(String name) {
@@ -1416,8 +1478,8 @@
 	
 	private void writeCallable(int accessFlags, ClassCompilation compilation, FunctionInfo fi,
 			CallableCompilationContext ctx) {
-		String descriptor = Type.getMethodDescriptor(ctx.returnType, ctx.argTypes.toArray(new Type[0]));
-		String name = ucaseToCamel(fi.getName());
+		String descriptor = ctx.getDescriptor();
+		String name = ctx.name;
 		
 		String[] exceptions = null;
 		if (ctx.throwsGError) {
@@ -1446,9 +1508,7 @@
 			returnTypeBox = ctx.returnType;
 		
 		mv.visitCode();
-		int nArgs = ctx.argTypes.size();
-		LocalVariableTable locals = new LocalVariableTable(includeThis ? Type.getObjectType(compilation.internalName) : null,
-				ctx.argTypes, ctx.args, false);
+		LocalVariableTable locals = ctx.allocLocals();
 		int functionOffset = locals.allocTmp("function", Type.getType(Function.class));
 		int argsOffset = locals.allocTmp("args", Type.getType(Object[].class));
 		int resultOffset = 0;
@@ -1457,9 +1517,8 @@
 		int errorOffset = 0;
 		if (ctx.throwsGError)
 			errorOffset = locals.allocTmp("error", Type.getType(PointerByReference.class));
-		int nInvokeArgs = nArgs;
-		if (includeThis)
-			nInvokeArgs += 1;
+		int nInvokeArgs = ctx.args.length;
+		int nInvokeArgsNoError = nInvokeArgs - (ctx.throwsGError ? 1 : 0);
 		Label jtarget;
 		Label l0 = new Label();
 		mv.visitLabel(l0);
@@ -1476,14 +1535,24 @@
 		mv.visitVarInsn(ASTORE, functionOffset);
 		Label l1 = new Label();
 		mv.visitLabel(l1);
-		mv.visitIntInsn(BIPUSH, nInvokeArgs + (ctx.throwsGError ? 1 : 0));
+		mv.visitIntInsn(BIPUSH, nInvokeArgs);
 		mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
-		for (int i = 0; i < nInvokeArgs; i++) {
+		for (int i = 0; i < nInvokeArgsNoError; i++) {
 			mv.visitInsn(DUP);
 			mv.visitIntInsn(BIPUSH, i);
-			if (!includeThis || i > 0) {
+			Integer arraySource = ctx.lengthIndices.get(i);
+			if (arraySource != null) {
+				ArgInfo source = ctx.args[arraySource];
+				assert source.getType().getTag().equals(TypeTag.ARRAY);
+				int offset = ctx.argOffsetToApi(arraySource);
+				LocalVariable var = locals.get(offset);
+				writeLoadArgument(mv, var.offset, var.type);
+				mv.visitInsn(ARRAYLENGTH);
+				mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(Integer.class), "valueOf", 
+						Type.getMethodDescriptor(getType(Integer.class), new Type[] { Type.INT_TYPE }));				
+			} else if (!includeThis || i > 0) {
 				LocalVariable var = locals.get(i);			
-				writeLoadArgument(mv, var.offset, var.type);			
+				writeLoadArgument(mv, var.offset, var.type);	
 			} else {
 				mv.visitVarInsn(ALOAD, 0);
 			}
@@ -1491,7 +1560,7 @@
 		}
 		if (ctx.throwsGError) {
 			mv.visitInsn(DUP);
-			mv.visitIntInsn(BIPUSH, nInvokeArgs);
+			mv.visitIntInsn(BIPUSH, nInvokeArgsNoError);
 			mv.visitVarInsn(ALOAD, errorOffset);
 			mv.visitInsn(AASTORE);
 		}
@@ -1688,13 +1757,13 @@
 			mv.visitEnd();
 			
 			/* constructor that takes all of the fields */
-			LocalVariableTable locals = new LocalVariableTable(Type.getObjectType(compilation.internalName), null, null, true);			
+			LocalVariableTable locals = new LocalVariableTable(Type.getObjectType(compilation.internalName), null, null);			
 			List<Type> args = new ArrayList<Type>();
 			args.add(Type.getObjectType(compilation.internalName));
 			boolean allArgsPrimitive = true;
 			for (FieldInfo field : fields) {
 				Type argType = toJava(field);
-				if (getPrimitiveBox(argType) == null) {
+				if (argType == null || getPrimitiveBox(argType) == null) {
 					allArgsPrimitive = false;
 					break;
 				}

Modified: trunk/stub-examples/Test.java
==============================================================================
--- trunk/stub-examples/Test.java	(original)
+++ trunk/stub-examples/Test.java	Mon Sep 29 01:11:56 2008
@@ -30,6 +30,13 @@
 		set("foo", arg);
 	}
 	
+	public int bar(String foo, byte[] bytes) {
+		Function target = Internals.library.getFunction("gtk_write_buf");	
+		Object[] args = new Object[] { foo, bytes.length, bytes };
+		Integer result = (Integer) target.invoke(Integer.class, args, Internals.invocationOptions);
+		return result;
+	}
+	
 	public float moo(long q, String z) {
 		Function target = Internals.library.getFunction("gtk_foo_bar");	
 		Object[] args = new Object[] { q, z };



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]