Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Swift 3.1 #1

Open
spearway opened this issue Apr 19, 2017 · 26 comments
Open

Swift 3.1 #1

spearway opened this issue Apr 19, 2017 · 26 comments

Comments

@spearway
Copy link

It looks like there is a new issue with swift 3.1. Since the upgrade there was a number of warning and the thread crashes during the JVM creation:
-> 0x10f5002b4: movl (%rsi), %eax
0x10f5002b6: leaq 0xf8(%rbp), %rsi
0x10f5002bd: vmovdqu %ymm0, (%rsi)
0x10f5002c1: vmovdqu %ymm7, 0x20(%rsi)
0x10f5002c6: vmovdqu %ymm8, 0x40(%rsi)
0x10f5002cb: vmovdqu %ymm15, 0x60(%rsi)

@spearway
Copy link
Author

In particular There is a warning I am very suspicious of:
warning: 'unsafeBitCast' from 'UnsafeMutablePointer' to 'UnsafeMutablePointer<UnsafeMutableRawPointer?>' (aka 'UnsafeMutablePointer<Optional>') changes pointee type and may lead to undefined behavior; use the 'withMemoryRebound' method on 'UnsafeMutablePointer' to rebind the type of memory
return try body( unsafeBitCast( ptr, to: UnsafeMutablePointer<UnsafeMutableRawPointer?>.self ) )

@johnno1962
Copy link
Member

johnno1962 commented Apr 19, 2017

I’ve not tested it with Swift 3.1 yet. Let me recompile everything and see if there is something that needs looking at.

@johnno1962
Copy link
Member

johnno1962 commented Apr 19, 2017

Seems to work on OSX with this JVM https://support.apple.com/kb/DL1572?locale=en_GB even with the warnings.

What OS/JVM version are you using?

@spearway
Copy link
Author

I am running with Java 1.8 from Oracle on Sierra 10.12. I get a segmentation fault. The real bizzare thing I that if I force the thread to continue it actually load the JVM.

@johnno1962
Copy link
Member

johnno1962 commented Apr 19, 2017

Are you using Swift Package Manager or Xcode?

@spearway
Copy link
Author

Swift module manager
I have a Swift application that load the JVM in the background with the are embedded in the app wrapper. We are using the JVM as server to call Java libraries.

func findAndLoadJVM() {
    do {
        print("JVM arguments \(self.args)")
        // We need to first find the right JRE
        do {
            let jreBundle = args.jreBundle!
            let jreBundleLoaded: Bool = ((try? jreBundle.loadAndReturnError()) != nil)
            if (!jreBundleLoaded) {
                throw JVMError.failToLoadRequestedJVM
            }
        } catch let error as NSError {
            print("Error: \(error.domain)")
            throw JVMError.failToLoadRequestedJVM
        }

        // Now initialize it
        if (JNI.initJVM(options: self.args.jvmOptions)) {
            print("We have a JVM")
            _  = JNI.AttachCurrentThread()
            let mainClassName = self.args.javaMainClass.replacingOccurrences(of: ".", with: "/")
            JNI.CachedFindClass(mainClassName, &JavaAppLauncher.mainClassCache)
            if (JavaAppLauncher.mainClassCache == nil) {
                // Could not find the main class
                throw JVMError.failToFindMainClass
            } else {
                print("We have a main class \(mainClassName)")
                var __args = [jvalue]( repeating: jvalue(), count: 1 )
                var __locals = [jobject]()
                __args[0] = JNIType.encode( value: self.args.jvmArguments, locals: &__locals )
                
                JNIMethod.CallStaticVoidMethod(className: mainClassName, classCache: &JavaAppLauncher.mainClassCache, methodName: "main", methodSig: "([Ljava/lang/String;)V", methodCache: &JavaAppLauncher.mainMethodCache, args: &__args, locals: &__locals)

            }
            defer {
                JNI.DetachCurrentThread()
            }
         } else {
            // Could not initialize the JVM
            throw JVMError.failToInitialize
        }
    } catch let e {
        print("Error while instantiating the JVM " + e.localizedDescription)
    } 
}

@spearway
Copy link
Author

This look like an allocation issue between Java/JNI and Swift. This is why I was suspicious of the withPointerToRawPointer warning

@spearway
Copy link
Author

I also noted that the JNI_OnLoad never get called. How does this work?

@johnno1962
Copy link
Member

johnno1962 commented Apr 20, 2017

I’ve pushed some small changes to the java_util package due to a duplicated implementation of clone() and rebuilt and retested using SPM the examples project using jdk1.8.0_131 and it seems to work. I don’t think the new warnings you mention are the problem or things wouldn’t work at all!

What is the path to the JDK bundle you are loading?

I imagine you’re having a threading problem related to attaching/detaching the JVM. In theory the java_swift code attaches and leaves attatched the current thread when you calll JNI.initJVM so you shouldn’t need to attach it yourself. I’d also remove the explict deferred detach as there is a cache of attached JVMs used for JNI.env which may get out of sync though why this would be a problem suddenly on Swift 3.1 I don’t know.

JNI_OnLoad is intended for Android and I’d not worry about it.

@spearway
Copy link
Author

I don't think it is an issue with the attach/detach The first call never returns "JNI.initJVM(options: self.args.jvmOptions)" I traced it and the JNI_CreateJavaVM( &self.jvm, $0, &vmArgs ) crashes.

@johnno1962
Copy link
Member

Is this an AppKit application? I’ve never been able to use the Oracle JDK from inside Xcode. Also, have you tried not loading the bundle to select the JDK. That’s the only other thing I can think of that’s different.

@spearway
Copy link
Author

Yes it is. From within Xcode it does not run. However (and I am quite ashamed not to have tried it before) when run from the finder (double click) it runs and does not report any error in the console. This is very strange and I don't really understand what is going on.

@spearway
Copy link
Author

I did fix the warning following the method at https://swift.org/migration-guide/se-0107-migrate.html

        var penv: UnsafeMutableRawPointer? = nil
        if ( JNI_CreateJavaVM( &self.jvm, &penv, &vmArgs ) != jint(JNI_OK) ) {
            self.report( "JNI_CreateJavaVM failed", file, line )
            return false
        }
        self.envCache[pthread_self()] = penv!.assumingMemoryBound(to: JNIEnv?.self)
        self.api = self.env!.pointee!.pointee

Which has the added advantage of legibility

@johnno1962
Copy link
Member

I may get rid of withPointerToRawPointer as you suggest. Have you tried initialising the JVM from the main thread?

@spearway
Copy link
Author

No I have not, but would it not be an issue as it would monopolize the main thread. I will have a look.

@spearway
Copy link
Author

It stops exactly at the same place on the main thread.

@johnno1962
Copy link
Member

And this is all new to Swift 3.1? Very odd. You’ll have to take the program to pieces and put it back together part by part. Can you try the 1.6 JVM?

@spearway
Copy link
Author

I am actually not sure. I had an app that was purely a wrapper and I never tried to run it from within Xcode. This is a new app and I have no way of turning the clock back…

The 1.6 JVM is not an option as the Java code is 1.8 dependent.

@spearway
Copy link
Author

Because it run standalone and does not log anything in the console I am starting to question Xcode. This may be an artifact of running ind bug mode in Xcode. However this is really annoying, the debugger is really helpful.

@johnno1962
Copy link
Member

johnno1962 commented Apr 20, 2017

I’ve never had the Orcale JVM work inside Xcode. It must interact with the debugger. Have you tried unchecking “debug executable” in the scheme? You say If you continue after the crash it works? The example program in the project works with JDK 1.8 using SPM but only 1.6 in Xcode.

@spearway
Copy link
Author

if you do "pr h -p true -n true -s false SIGSEGV" and continue it appears to work. I have not done a lot of testing yet.

@johnno1962
Copy link
Member

Crikey, what does that do?

@spearway
Copy link
Author

spearway commented Apr 20, 2017

it tell the debugger not to stop that thread on a SIGSEGV
This is kind of bizarre

@johnno1962
Copy link
Member

It’s part of the “normal” code path for the JVM which traps it which is overridden by the debugger?

@johnno1962
Copy link
Member

johnno1962 commented Apr 21, 2017

Some more info here. Seems to be a project configuration/linking issue somehow. I’ve got to the point where the SwiftJava/examples target works in Xcode with the Oracle JVM but the JDBC target which uses AppKit does not. One night assume this is to do with AppKit but I’ve started a new C project for a command line program that just tries to load the JVM and it always traps in the place you show above.

#import <Foundation/Foundation.h>
#import "jni.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        struct JavaVMInitArgs vmArgs;
        vmArgs.version = JNI_VERSION_1_6;
        vmArgs.nOptions = 0;
        struct JavaVMOption opt[1];
        vmArgs.options = opt;

        JavaVM *jvm;
        JNIEnv *env;
        JNI_CreateJavaVM( &jvm, &env, &vmArgs);
        NSLog(@"Hello, World!");
    }
    return 0;
}

@johnno1962
Copy link
Member

johnno1962 commented Jun 20, 2017

Filed a radar and a bug with Oracle about this: http://bugreport.java.com/bugreport/bug_info.do?bug_id=88A0C05DB15AF0C2BA2605D8BF388A37

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants