Revision: 5683
          http://jnode.svn.sourceforge.net/jnode/?rev=5683&view=rev
Author:   crawley
Date:     2009-10-15 14:50:26 +0000 (Thu, 15 Oct 2009)

Log Message:
-----------
Fixes to get the JNode bootimage build working with Jikes compiler.  The
most important one changes the way that JNode native methods are handled.
Previously, the compiler would simply use the bytecodes from the replacement
method as the actual method, but this crashed because Jikes used the wrong 
constant pool.  Now, we generate bytecodes for the actual method on the fly.

Modified Paths:
--------------
    branches/jikesRVM/core/descriptors/org.classpath.core.xml
    branches/jikesRVM/core/src/core/com/ibm/JikesRVM/classloader/VM_Method.java
    branches/jikesRVM/core/src/core/org/jnode/vm/JvmType.java
    branches/jikesRVM/core/src/core/org/jnode/vm/classmgr/ClassDecoder.java
    branches/jikesRVM/core/src/core/org/jnode/vm/classmgr/VmCP.java

Added Paths:
-----------
    
branches/jikesRVM/core/src/core/org/jnode/vm/classmgr/NativeStubGenerator.java

Modified: branches/jikesRVM/core/descriptors/org.classpath.core.xml
===================================================================
--- branches/jikesRVM/core/descriptors/org.classpath.core.xml   2009-10-06 
14:18:58 UTC (rev 5682)
+++ branches/jikesRVM/core/descriptors/org.classpath.core.xml   2009-10-15 
14:50:26 UTC (rev 5683)
@@ -43,12 +43,13 @@
       <export name="sun.security.acl.GroupImpl"/>
       <export name="sun.security.action.*"/>
       <export name="sun.security.jca.*"/>
-      <export name="sun.security.pkcs.ParsingException"/>
+      <export name="sun.security.pkcs.*"/>
       <export name="sun.security.provider.SecureRandom"/>
       <export name="sun.security.provider.PolicyFile"/>
       <export name="sun.security.provider.PolicyParser"/>
+      <export name="sun.security.timestamp.TimestampToken"/> 
       <export name="sun.security.util.*"/> 
-      <export name="sun.security.x509.X509CertImpl"/>
+      <export name="sun.security.x509.*"/>
 
       <export name="sun.misc.Service"/>
       <export name="sun.misc.ServiceConfigurationError"/>

Modified: 
branches/jikesRVM/core/src/core/com/ibm/JikesRVM/classloader/VM_Method.java
===================================================================
--- branches/jikesRVM/core/src/core/com/ibm/JikesRVM/classloader/VM_Method.java 
2009-10-06 14:18:58 UTC (rev 5682)
+++ branches/jikesRVM/core/src/core/com/ibm/JikesRVM/classloader/VM_Method.java 
2009-10-15 14:50:26 UTC (rev 5683)
@@ -127,7 +127,7 @@
                int n = method.getBytecode().getExceptionHandlers().size();
                if (n!=0) eMap = new 
VM_ExceptionHandlerMap(method.getBytecode().getExceptionHandlers(), dc, n);
                VmLineNumberMap jnodeLineMap = 
method.getBytecode().getLineNrs(); 
-               int [] lineMap = new int[jnodeLineMap.getLength()];
+               int [] lineMap = new int[jnodeLineMap == null ? 0 : 
jnodeLineMap.getLength()];
                for (int i = 0; i < lineMap.length; i++) {
                        int startPC = jnodeLineMap.getStartPCAt(i);
                        int lineNumber = jnodeLineMap.getLineNrAt(i);

Modified: branches/jikesRVM/core/src/core/org/jnode/vm/JvmType.java
===================================================================
--- branches/jikesRVM/core/src/core/org/jnode/vm/JvmType.java   2009-10-06 
14:18:58 UTC (rev 5682)
+++ branches/jikesRVM/core/src/core/org/jnode/vm/JvmType.java   2009-10-15 
14:50:26 UTC (rev 5683)
@@ -259,7 +259,68 @@
         return types;
     }
 
+
+
     /**
+     * Gets the argument signatures for a method signature.
+     *
+     * @param signature
+     * @return the argument type signatures as an array of strings
+     */
+    public static String[] getArgumentSignatures(String signature) {
+        final int len = signature.length();
+        final String[] types = new String[getArgumentCount(signature)];
+        int cnt = 0;
+        int start;
+        for (int i = 1; i < len; i++) {
+            final String t;
+            switch (signature.charAt(i)) {
+                case 'Z':
+                case 'B':
+                case 'C':
+                case 'S':
+                case 'I':
+                case 'F':
+                case 'J':
+                case 'D':
+                    t = Character.toString(signature.charAt(i));
+                    break;
+                case 'L':
+                       start = i;
+                    while (signature.charAt(i) != ';') {
+                        i++;
+                    }
+                    t = signature.substring(start, i + 1);
+                    break;
+                case '[':
+                       start = i;
+                    while (signature.charAt(i) == '[') {
+                        i++;
+                    }
+                    if (signature.charAt(i) == 'L') {
+                        while (signature.charAt(i) != ';') {
+                            i++;
+                        }
+                    }
+                    t = signature.substring(start, i + 1);
+                    break;
+                case ')':
+                    // the end
+                    i = len;
+                    t = null;
+                    break;
+                default:
+                    throw new IllegalArgumentException("Unknown type"
+                        + signature.substring(i));
+            }
+            if (t != null) {
+                types[cnt++] = t;
+            }
+        }
+        return types;
+    }
+
+    /**
      * Gets the return type of a method signature.
      *
      * @param signature
@@ -276,6 +337,17 @@
     }
 
     /**
+     * Gets the return type signature of a method signature.
+     *
+     * @param signature
+     * @return the return type signature
+     */
+    public static String getReturnSignature(String signature) {
+        final int endIdx = signature.indexOf(')');
+        return signature.substring(endIdx + 1);
+    }
+
+    /**
      * Test if the given internal type value a floating point type.
      *
      * @param type the type value

Modified: 
branches/jikesRVM/core/src/core/org/jnode/vm/classmgr/ClassDecoder.java
===================================================================
--- branches/jikesRVM/core/src/core/org/jnode/vm/classmgr/ClassDecoder.java     
2009-10-06 14:18:58 UTC (rev 5682)
+++ branches/jikesRVM/core/src/core/org/jnode/vm/classmgr/ClassDecoder.java     
2009-10-15 14:50:26 UTC (rev 5683)
@@ -54,6 +54,16 @@
  * @author Ewout Prangsma (e...@users.sourceforge.net)
  */
 public final class ClassDecoder {
+       
+       // This constant controls how we deal with native method replacement.  
The first
+       // step is to find a suitable replacement method in the 
"Native<ClassName>" class.  
+       // If that works, we then need to arrange that the replacement is used. 
 The old
+       // way to do this was to simply attach the bytecodes for the 
replacement method
+       // to the native method and mark it as non-native.  That doesn't work 
with Jikes
+       // (because of issues with using the right constant pool.)  So the 
alternative is
+       // to generate bytecodes to turn the native method into a stub method 
that calls
+       // the replacement method.  This is controlled by the following 
constant. 
+       private static boolean GENERATE_STUB_METHODS = true;
 
     // ------------------------------------------
     // VM ClassLoader Code
@@ -497,7 +507,7 @@
             nativeType = cl.loadClass(nativeClassName, false);
         } catch (ClassNotFoundException ex) {
             if (verbose) {
-                BootLog.error("Native class replacement (" + nativeClassName
+                BootLog.error("Native replacement class (" + nativeClassName
                     + ") not found");
             }
             return null;
@@ -508,20 +518,26 @@
             signature = "(" + 
Signature.toSignature(method.getDeclaringClass()) + signature.substring(1);
         }
 
-        final VmMethod nativeMethod = 
nativeType.getNativeMethodReplacement(method.getName(), signature);
+        final VmMethod replacementMethod = 
+               nativeType.getNativeMethodReplacement(method.getName(), 
signature);
 
-        if (nativeMethod == null) {
+        if (replacementMethod == null) {
             if (verbose) {
-                BootLog.error("Native method replacement (" + method
-                    + ") not found");
+                BootLog.error("Native method replacement (" + nativeClassName 
+ 
+                               "." + method + " with signature '" + signature 
+ "') not found");
             }
             return null;
         }
-        if (!nativeMethod.isStatic()) {
+        if (!replacementMethod.isStatic()) {
             throw new ClassFormatError(
-                "Native method replacement must be static");
+                "Native method replacement must be static (" + nativeClassName 
+ 
+                "." + method + " with signature '" + signature + "')");
         }
-        return nativeMethod.getBytecode();
+        if (GENERATE_STUB_METHODS) {
+               return NativeStubGenerator.generate(method, replacementMethod);
+        } else {
+            return replacementMethod.getBytecode();
+        }
     }
 
     /**

Added: 
branches/jikesRVM/core/src/core/org/jnode/vm/classmgr/NativeStubGenerator.java
===================================================================
--- 
branches/jikesRVM/core/src/core/org/jnode/vm/classmgr/NativeStubGenerator.java  
                            (rev 0)
+++ 
branches/jikesRVM/core/src/core/org/jnode/vm/classmgr/NativeStubGenerator.java  
    2009-10-15 14:50:26 UTC (rev 5683)
@@ -0,0 +1,194 @@
+/*
+ * $Id: ClassDecoder.java 5682 2009-10-06 14:18:58Z crawley $
+ *
+ * Copyright (C) 2003-2009 JNode.org
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; If not, write to the Free Software Foundation, 
Inc., 
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package org.jnode.vm.classmgr;
+
+import org.jnode.vm.JvmType;
+import org.jnode.vm.bytecode.BytecodeWriter;
+
+/**
+ * This class is used to generate the bytecodes for native code replacement 
stubs.
+ * Only 32bit vms are supported for now, since we are using 
JvmType.getCategory().
+ * 
+ * @author craw...@jnode.org
+ */
+public class NativeStubGenerator {
+
+       /**
+        * Create the bytecodes for a stub replacement for the native method.  
This
+        * will add entries to the method's constant pool as required.
+        * 
+        * @param nativeMethod the native method to be replaced
+        * @param replacementMethod the (non-native) Java method that will do 
the work
+        * @return the bytecodes for the stub method to replace the native 
method.
+        */
+       public static VmByteCode generate(VmMethod nativeMethod, VmMethod 
replacementMethod) {
+               VmCP cp = nativeMethod.getDeclaringClass().getCP();
+               int classIndex = findOrAddConstClass(
+                               cp, 
replacementMethod.getDeclaringClass().getName());
+               int methodIndex = findOrAddConstMethod(
+                               cp, classIndex, replacementMethod.getName(), 
replacementMethod.signature);
+               BytecodeWriter bw = new BytecodeWriter(1024);
+               // (We cannot use method.getNoArguments, method.getArgumentType 
because they
+               // depend on org.jnode.vm.classmgr.Signature, which in turn 
assumes that
+               // the primitive type classes have been initialized.  Instead, 
we use the
+               // JvmType class to unpick the method signature.)
+               String signature = nativeMethod.getSignature();
+               int slotOffset = nativeMethod.isStatic() ? 0 : 
JvmType.getCategory(JvmType.REFERENCE);
+               int slot = slotOffset;
+               int[] argTypes = JvmType.getArgumentTypes(signature);
+               // Generate a stack load instruction for each argument
+               if (!nativeMethod.isStatic()) {
+                       genArgLoad(bw, JvmType.REFERENCE, 0);
+               }
+               for (int i = 0; i < argTypes.length; i++) {
+                       genArgLoad(bw, argTypes[i], slot);
+                       slot += JvmType.getCategory(argTypes[i]);
+               }
+               // Generate the invoke instruction to call the replacement 
method
+               bw.invokestatic(methodIndex);
+               // Generate the return instruction depending on the return type
+               int returnType = JvmType.getReturnType(signature);
+               int returnTypeSize = JvmType.getCategory(returnType);
+               switch (returnType) {
+               case JvmType.BOOLEAN:
+               case JvmType.BYTE:
+               case JvmType.CHAR:
+               case JvmType.SHORT:
+               case JvmType.INT:
+                       bw.ireturn();
+                       break;
+               case JvmType.LONG:
+                       bw.lreturn();
+                       break;
+               case JvmType.FLOAT:
+                       bw.freturn();
+                       break;
+               case JvmType.DOUBLE:
+                       bw.dreturn();
+                       break;
+               case JvmType.REFERENCE:
+                       bw.areturn();
+                       break;
+           default:
+               bw.return_();
+               }
+               int endPos = bw.getLength();
+               // Prepare a locals table with an entry for each argument.
+               int localOffset; 
+               VmLocalVariable[] locals;
+               if (nativeMethod.isStatic()) {
+                       localOffset = 0;
+                       locals = new VmLocalVariable[argTypes.length];
+               } else {
+                       localOffset = 1;
+                       locals = new VmLocalVariable[argTypes.length + 
localOffset];
+                       locals[0] = new VmLocalVariable(
+                                       (char) 0, (char) endPos, (char) 0, 
(char) 0, (char) 0);
+               }
+               slot = slotOffset;
+               String[] argSignatures = 
JvmType.getArgumentSignatures(signature);
+               for (int i = 0; i < argTypes.length; i++) {
+                       int nameIndex = findOrAddUTF8(cp, "arg" + i);
+                       int descriptorIndex = findOrAddUTF8(cp, 
argSignatures[i]);
+                       locals[i + localOffset] = new VmLocalVariable(
+                                       (char) 0, (char) endPos, (char) 
nameIndex, (char) descriptorIndex, (char) slot);
+                       slot += JvmType.getCategory(argTypes[i]);
+               }
+               // Put it all together
+               return new VmByteCode(nativeMethod, bw.toByteBuffer(), 
locals.length, 
+                               Math.max(slot, returnTypeSize),
+                               new VmInterpretedExceptionHandler[0], 
+                               new VmLineNumberMap(new char[]{0, 1}),
+                               new VmLocalVariableTable(locals));
+       }
+
+       private static void genArgLoad(BytecodeWriter bw, int type, int slot) {
+               switch (type) {
+               case JvmType.BOOLEAN:
+               case JvmType.BYTE:
+               case JvmType.CHAR:
+               case JvmType.SHORT:
+               case JvmType.INT:
+                       bw.iload(slot);
+                       break;
+               case JvmType.LONG:
+                       bw.lload(slot);
+                       break;
+               case JvmType.FLOAT:
+                       bw.fload(slot);
+                       break;
+               case JvmType.DOUBLE:
+                       bw.dload(slot);
+                       break;
+               case JvmType.REFERENCE:
+                       bw.aload(slot);
+                       break;
+           default:
+               throw new AssertionError("Unexpected arg type (" + type + ")");
+               }
+       }
+
+       private static int findOrAddConstMethod(VmCP cp, int classIndex, String 
name,
+                       String signature) {
+               VmConstClass classRef = cp.getConstClass(classIndex);
+               for (int i = 0; i < cp.getLength(); i++) {
+                       Object obj = cp.getAny(i);
+                       if (obj instanceof VmConstMethodRef) {
+                               VmConstMethodRef ref = (VmConstMethodRef) obj;
+                               if 
(ref.getClassName().equals(classRef.getClassName()) &&
+                                               ref.getName().equals(name) && 
ref.getSignature().equals(signature)) {
+                                       return i;
+                               }
+                       }
+               }
+               VmConstMethodRef ref = new VmConstMethodRef(classRef, name, 
signature);
+               int index = cp.getUnusedIndex();
+               cp.setConstMethodRef(index, ref);
+               return index;
+       }
+
+       private static int findOrAddConstClass(VmCP cp, String name) {
+               for (int i = 0; i < cp.getLength(); i++) {
+                       Object obj = cp.getAny(i);
+                       if (obj instanceof VmConstClass) {
+                               VmConstClass ref = (VmConstClass) obj;
+                               if (ref.getClassName().equals(name)) {
+                                       return i;
+                               }
+                       }
+               }
+               VmConstClass ref = new VmConstClass(name);
+               int index = cp.getUnusedIndex();
+               cp.setConstClass(index, ref);
+               return index;
+       }
+
+       private static int findOrAddUTF8(VmCP cp, String name) {
+               for (int i = 0; i < cp.getLength(); i++) {
+                       if (name.equals(cp.getAny(i))) {
+                               return i;
+                       }
+               }
+               int index = cp.getUnusedIndex();
+               cp.setUTF8(index, name);
+               return index;
+       }
+}

Modified: branches/jikesRVM/core/src/core/org/jnode/vm/classmgr/VmCP.java
===================================================================
--- branches/jikesRVM/core/src/core/org/jnode/vm/classmgr/VmCP.java     
2009-10-06 14:18:58 UTC (rev 5682)
+++ branches/jikesRVM/core/src/core/org/jnode/vm/classmgr/VmCP.java     
2009-10-15 14:50:26 UTC (rev 5683)
@@ -305,7 +305,7 @@
      * @param index The index where to read
      * @param data  The Object to write
      */
-    private void set(int index, Object data) {
+    public void set(int index, Object data) {
         if (data == null) {
             throw new NullPointerException(
                 "Cannot set a null data");
@@ -316,6 +316,15 @@
     final void reset(int index) {
         cp[index] = null;
     }
+    
+    public int getUnusedIndex() {
+       if (used == cp.length) {
+               Object[] newCP = new Object[cp.length + 1];
+               System.arraycopy(cp, 0, newCP, 0, cp.length);
+               cp = newCP;
+       }
+       return used++;
+    }
 
        public VmType getParentType() {
                return parentType;


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay 
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
Jnode-svn-commits mailing list
Jnode-svn-commits@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jnode-svn-commits

Reply via email to