mirror of
https://github.com/darlinghq/darling-openjdk.git
synced 2024-11-23 04:19:43 +00:00
[macos] Add JavaNativeFoundation
* Imported JavaNativeFoundation-80 as shipped with macOS 11 Beta * Added license information to all source files * Removed linker redirection support (only needed for the system framework) * Updated dylib id to be @rpath-relative * Updated to use jni.h from the JDK rather than the old copy in the macOS SDK Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
This commit is contained in:
parent
dd60699ea5
commit
55b3ebec85
9
apple/JavaNativeFoundation/.gitignore
vendored
Normal file
9
apple/JavaNativeFoundation/.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
build
|
||||
DerivedData
|
||||
.DS_Store
|
||||
*~
|
||||
*.rej
|
||||
*.orig
|
||||
cscope.*
|
||||
tags
|
||||
TAGS
|
2
apple/JavaNativeFoundation/JavaNativeFoundation.xcodeproj/.gitignore
vendored
Normal file
2
apple/JavaNativeFoundation/JavaNativeFoundation.xcodeproj/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
project.xcworkspace
|
||||
xcuserdata
|
@ -0,0 +1,380 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 45;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
2C69E26310782500003EB656 /* JNFDate.h in Headers */ = {isa = PBXBuildFile; fileRef = 2C69E261107824FF003EB656 /* JNFDate.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
2C69E26410782500003EB656 /* JNFDate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C69E26210782500003EB656 /* JNFDate.m */; };
|
||||
3F012B3323DEDA5A00B98AC3 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0867D6A5FE840307C02AAC07 /* AppKit.framework */; };
|
||||
3F012B3423DEDA9600B98AC3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0867D69BFE84028FC02AAC07 /* Foundation.framework */; };
|
||||
3F012B3623DEDABE00B98AC3 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F012B3523DEDABE00B98AC3 /* CoreFoundation.framework */; };
|
||||
8900DAEB0CB0365300EE572C /* JNFTypeCoercion.h in Headers */ = {isa = PBXBuildFile; fileRef = 8900DAE90CB0365300EE572C /* JNFTypeCoercion.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8900DAEC0CB0365300EE572C /* JNFTypeCoercion.m in Sources */ = {isa = PBXBuildFile; fileRef = 8900DAEA0CB0365300EE572C /* JNFTypeCoercion.m */; };
|
||||
89260F6E0CB622FC00FA4947 /* JNFThread.h in Headers */ = {isa = PBXBuildFile; fileRef = 89260F6C0CB622FC00FA4947 /* JNFThread.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
89260F6F0CB622FC00FA4947 /* JNFThread.m in Sources */ = {isa = PBXBuildFile; fileRef = 89260F6D0CB622FC00FA4947 /* JNFThread.m */; };
|
||||
8927F56D0D8F1E27008C35E3 /* JNFJObjectWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 8927F56B0D8F1E27008C35E3 /* JNFJObjectWrapper.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8927F56E0D8F1E27008C35E3 /* JNFJObjectWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 8927F56C0D8F1E27008C35E3 /* JNFJObjectWrapper.m */; };
|
||||
89A8E9F80FA60E2D006CC298 /* JNFRunnable.h in Headers */ = {isa = PBXBuildFile; fileRef = 89A8E9F60FA60E2D006CC298 /* JNFRunnable.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
89A8E9F90FA60E2D006CC298 /* JNFRunnable.m in Sources */ = {isa = PBXBuildFile; fileRef = 89A8E9F70FA60E2D006CC298 /* JNFRunnable.m */; };
|
||||
89AC839F0CAF4BD600480894 /* debug.h in Headers */ = {isa = PBXBuildFile; fileRef = 89AC83880CAF4BD600480894 /* debug.h */; };
|
||||
89AC83A00CAF4BD600480894 /* debug.m in Sources */ = {isa = PBXBuildFile; fileRef = 89AC83890CAF4BD600480894 /* debug.m */; };
|
||||
89AC83A10CAF4BD600480894 /* JNFAssert.h in Headers */ = {isa = PBXBuildFile; fileRef = 89AC838A0CAF4BD600480894 /* JNFAssert.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
89AC83A20CAF4BD600480894 /* JNFAssert.m in Sources */ = {isa = PBXBuildFile; fileRef = 89AC838B0CAF4BD600480894 /* JNFAssert.m */; };
|
||||
89AC83A30CAF4BD600480894 /* JNFAutoreleasePool.h in Headers */ = {isa = PBXBuildFile; fileRef = 89AC838C0CAF4BD600480894 /* JNFAutoreleasePool.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
89AC83A40CAF4BD600480894 /* JNFAutoreleasePool.m in Sources */ = {isa = PBXBuildFile; fileRef = 89AC838D0CAF4BD600480894 /* JNFAutoreleasePool.m */; };
|
||||
89AC83A70CAF4BD600480894 /* JNFException.h in Headers */ = {isa = PBXBuildFile; fileRef = 89AC83900CAF4BD600480894 /* JNFException.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
89AC83A80CAF4BD600480894 /* JNFException.m in Sources */ = {isa = PBXBuildFile; fileRef = 89AC83910CAF4BD600480894 /* JNFException.m */; };
|
||||
89AC83A90CAF4BD600480894 /* JavaNativeFoundation.h in Headers */ = {isa = PBXBuildFile; fileRef = 89AC83920CAF4BD600480894 /* JavaNativeFoundation.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
89AC83AA0CAF4BD600480894 /* JNFJNI.h in Headers */ = {isa = PBXBuildFile; fileRef = 89AC83930CAF4BD600480894 /* JNFJNI.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
89AC83AB0CAF4BD600480894 /* JNFJNI.m in Sources */ = {isa = PBXBuildFile; fileRef = 89AC83940CAF4BD600480894 /* JNFJNI.m */; };
|
||||
89AC83AC0CAF4BD600480894 /* JNFNumber.h in Headers */ = {isa = PBXBuildFile; fileRef = 89AC83950CAF4BD600480894 /* JNFNumber.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
89AC83AD0CAF4BD600480894 /* JNFNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = 89AC83960CAF4BD600480894 /* JNFNumber.m */; };
|
||||
89AC83AE0CAF4BD600480894 /* JNFObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 89AC83970CAF4BD600480894 /* JNFObject.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
89AC83AF0CAF4BD600480894 /* JNFObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 89AC83980CAF4BD600480894 /* JNFObject.m */; };
|
||||
89AC83B00CAF4BD600480894 /* JNFPath.h in Headers */ = {isa = PBXBuildFile; fileRef = 89AC83990CAF4BD600480894 /* JNFPath.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
89AC83B10CAF4BD600480894 /* JNFPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 89AC839A0CAF4BD600480894 /* JNFPath.m */; };
|
||||
89AC83B20CAF4BD600480894 /* JNFString.h in Headers */ = {isa = PBXBuildFile; fileRef = 89AC839B0CAF4BD600480894 /* JNFString.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
89AC83B30CAF4BD600480894 /* JNFString.m in Sources */ = {isa = PBXBuildFile; fileRef = 89AC839C0CAF4BD600480894 /* JNFString.m */; };
|
||||
89B69B370F47D3C500C86CA9 /* JNFRunLoop.h in Headers */ = {isa = PBXBuildFile; fileRef = 89B69B350F47D3C500C86CA9 /* JNFRunLoop.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
89B69B380F47D3C500C86CA9 /* JNFRunLoop.m in Sources */ = {isa = PBXBuildFile; fileRef = 89B69B360F47D3C500C86CA9 /* JNFRunLoop.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
0867D69BFE84028FC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||
0867D6A5FE840307C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
|
||||
2C69E261107824FF003EB656 /* JNFDate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JNFDate.h; sourceTree = "<group>"; };
|
||||
2C69E26210782500003EB656 /* JNFDate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JNFDate.m; sourceTree = "<group>"; };
|
||||
3F012B3523DEDABE00B98AC3 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
|
||||
3FA4788A23E37879005466BA /* common.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = common.xcconfig; sourceTree = "<group>"; };
|
||||
3FA4788B23E37879005466BA /* JavaNativeFoundation.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = JavaNativeFoundation.xcconfig; sourceTree = "<group>"; };
|
||||
8900DAE90CB0365300EE572C /* JNFTypeCoercion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JNFTypeCoercion.h; sourceTree = "<group>"; };
|
||||
8900DAEA0CB0365300EE572C /* JNFTypeCoercion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JNFTypeCoercion.m; sourceTree = "<group>"; };
|
||||
89260F6C0CB622FC00FA4947 /* JNFThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JNFThread.h; sourceTree = "<group>"; };
|
||||
89260F6D0CB622FC00FA4947 /* JNFThread.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JNFThread.m; sourceTree = "<group>"; };
|
||||
8927F56B0D8F1E27008C35E3 /* JNFJObjectWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JNFJObjectWrapper.h; sourceTree = "<group>"; };
|
||||
8927F56C0D8F1E27008C35E3 /* JNFJObjectWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JNFJObjectWrapper.m; sourceTree = "<group>"; };
|
||||
89A8E9F60FA60E2D006CC298 /* JNFRunnable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JNFRunnable.h; sourceTree = "<group>"; };
|
||||
89A8E9F70FA60E2D006CC298 /* JNFRunnable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JNFRunnable.m; sourceTree = "<group>"; };
|
||||
89AC83880CAF4BD600480894 /* debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = debug.h; sourceTree = "<group>"; };
|
||||
89AC83890CAF4BD600480894 /* debug.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = debug.m; sourceTree = "<group>"; };
|
||||
89AC838A0CAF4BD600480894 /* JNFAssert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JNFAssert.h; sourceTree = "<group>"; };
|
||||
89AC838B0CAF4BD600480894 /* JNFAssert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JNFAssert.m; sourceTree = "<group>"; };
|
||||
89AC838C0CAF4BD600480894 /* JNFAutoreleasePool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JNFAutoreleasePool.h; sourceTree = "<group>"; };
|
||||
89AC838D0CAF4BD600480894 /* JNFAutoreleasePool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JNFAutoreleasePool.m; sourceTree = "<group>"; };
|
||||
89AC83900CAF4BD600480894 /* JNFException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JNFException.h; sourceTree = "<group>"; };
|
||||
89AC83910CAF4BD600480894 /* JNFException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JNFException.m; sourceTree = "<group>"; };
|
||||
89AC83920CAF4BD600480894 /* JavaNativeFoundation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JavaNativeFoundation.h; sourceTree = "<group>"; };
|
||||
89AC83930CAF4BD600480894 /* JNFJNI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JNFJNI.h; sourceTree = "<group>"; };
|
||||
89AC83940CAF4BD600480894 /* JNFJNI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JNFJNI.m; sourceTree = "<group>"; };
|
||||
89AC83950CAF4BD600480894 /* JNFNumber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JNFNumber.h; sourceTree = "<group>"; };
|
||||
89AC83960CAF4BD600480894 /* JNFNumber.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JNFNumber.m; sourceTree = "<group>"; };
|
||||
89AC83970CAF4BD600480894 /* JNFObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JNFObject.h; sourceTree = "<group>"; };
|
||||
89AC83980CAF4BD600480894 /* JNFObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JNFObject.m; sourceTree = "<group>"; };
|
||||
89AC83990CAF4BD600480894 /* JNFPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JNFPath.h; sourceTree = "<group>"; };
|
||||
89AC839A0CAF4BD600480894 /* JNFPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JNFPath.m; sourceTree = "<group>"; };
|
||||
89AC839B0CAF4BD600480894 /* JNFString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JNFString.h; sourceTree = "<group>"; };
|
||||
89AC839C0CAF4BD600480894 /* JNFString.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JNFString.m; sourceTree = "<group>"; };
|
||||
89AC83B80CAF4BE400480894 /* JavaNativeFoundation-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "JavaNativeFoundation-Info.plist"; sourceTree = "<group>"; };
|
||||
89B69B350F47D3C500C86CA9 /* JNFRunLoop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JNFRunLoop.h; sourceTree = "<group>"; };
|
||||
89B69B360F47D3C500C86CA9 /* JNFRunLoop.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JNFRunLoop.m; sourceTree = "<group>"; };
|
||||
8DC2EF5B0486A6940098B216 /* JavaNativeFoundation.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JavaNativeFoundation.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
8DC2EF560486A6940098B216 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
3F012B3323DEDA5A00B98AC3 /* AppKit.framework in Frameworks */,
|
||||
3F012B3623DEDABE00B98AC3 /* CoreFoundation.framework in Frameworks */,
|
||||
3F012B3423DEDA9600B98AC3 /* Foundation.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
034768DFFF38A50411DB9C8B /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8DC2EF5B0486A6940098B216 /* JavaNativeFoundation.framework */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0867D691FE84028FC02AAC07 /* JavaFoundation */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3FA4788923E37879005466BA /* xcconfig */,
|
||||
89AC83870CAF4BD600480894 /* JavaNativeFoundation */,
|
||||
1058C7B0FEA5585E11CA2CBB /* Frameworks */,
|
||||
034768DFFF38A50411DB9C8B /* Products */,
|
||||
);
|
||||
name = JavaFoundation;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1058C7B0FEA5585E11CA2CBB /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3F012B3523DEDABE00B98AC3 /* CoreFoundation.framework */,
|
||||
0867D6A5FE840307C02AAC07 /* AppKit.framework */,
|
||||
0867D69BFE84028FC02AAC07 /* Foundation.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3FA4788923E37879005466BA /* xcconfig */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3FA4788A23E37879005466BA /* common.xcconfig */,
|
||||
3FA4788B23E37879005466BA /* JavaNativeFoundation.xcconfig */,
|
||||
);
|
||||
path = xcconfig;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
89A01F7B0DA099070015CD2A /* autorelease */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
89AC838C0CAF4BD600480894 /* JNFAutoreleasePool.h */,
|
||||
89AC838D0CAF4BD600480894 /* JNFAutoreleasePool.m */,
|
||||
);
|
||||
name = autorelease;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
89A01F7E0DA0991E0015CD2A /* debug */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
89AC838A0CAF4BD600480894 /* JNFAssert.h */,
|
||||
89AC838B0CAF4BD600480894 /* JNFAssert.m */,
|
||||
89AC83880CAF4BD600480894 /* debug.h */,
|
||||
89AC83890CAF4BD600480894 /* debug.m */,
|
||||
);
|
||||
name = debug;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
89A01F800DA0994A0015CD2A /* conversion */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
89AC839B0CAF4BD600480894 /* JNFString.h */,
|
||||
89AC839C0CAF4BD600480894 /* JNFString.m */,
|
||||
89AC83950CAF4BD600480894 /* JNFNumber.h */,
|
||||
89AC83960CAF4BD600480894 /* JNFNumber.m */,
|
||||
2C69E261107824FF003EB656 /* JNFDate.h */,
|
||||
2C69E26210782500003EB656 /* JNFDate.m */,
|
||||
89AC83990CAF4BD600480894 /* JNFPath.h */,
|
||||
89AC839A0CAF4BD600480894 /* JNFPath.m */,
|
||||
8900DAE90CB0365300EE572C /* JNFTypeCoercion.h */,
|
||||
8900DAEA0CB0365300EE572C /* JNFTypeCoercion.m */,
|
||||
);
|
||||
name = conversion;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
89A01F900DA099DC0015CD2A /* threading */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8927F56B0D8F1E27008C35E3 /* JNFJObjectWrapper.h */,
|
||||
8927F56C0D8F1E27008C35E3 /* JNFJObjectWrapper.m */,
|
||||
89260F6C0CB622FC00FA4947 /* JNFThread.h */,
|
||||
89260F6D0CB622FC00FA4947 /* JNFThread.m */,
|
||||
89B69B350F47D3C500C86CA9 /* JNFRunLoop.h */,
|
||||
89B69B360F47D3C500C86CA9 /* JNFRunLoop.m */,
|
||||
89A8E9F60FA60E2D006CC298 /* JNFRunnable.h */,
|
||||
89A8E9F70FA60E2D006CC298 /* JNFRunnable.m */,
|
||||
);
|
||||
name = threading;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
89A01F910DA09A540015CD2A /* basics */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
89AC83930CAF4BD600480894 /* JNFJNI.h */,
|
||||
89AC83940CAF4BD600480894 /* JNFJNI.m */,
|
||||
89AC83970CAF4BD600480894 /* JNFObject.h */,
|
||||
89AC83980CAF4BD600480894 /* JNFObject.m */,
|
||||
89AC83900CAF4BD600480894 /* JNFException.h */,
|
||||
89AC83910CAF4BD600480894 /* JNFException.m */,
|
||||
);
|
||||
name = basics;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
89AC83870CAF4BD600480894 /* JavaNativeFoundation */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
89AC83B80CAF4BE400480894 /* JavaNativeFoundation-Info.plist */,
|
||||
89AC83920CAF4BD600480894 /* JavaNativeFoundation.h */,
|
||||
89A01F910DA09A540015CD2A /* basics */,
|
||||
89A01F800DA0994A0015CD2A /* conversion */,
|
||||
89A01F900DA099DC0015CD2A /* threading */,
|
||||
89A01F7B0DA099070015CD2A /* autorelease */,
|
||||
89A01F7E0DA0991E0015CD2A /* debug */,
|
||||
);
|
||||
path = JavaNativeFoundation;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
8DC2EF500486A6940098B216 /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
89AC839F0CAF4BD600480894 /* debug.h in Headers */,
|
||||
89AC83A10CAF4BD600480894 /* JNFAssert.h in Headers */,
|
||||
89AC83A30CAF4BD600480894 /* JNFAutoreleasePool.h in Headers */,
|
||||
89AC83A70CAF4BD600480894 /* JNFException.h in Headers */,
|
||||
89AC83A90CAF4BD600480894 /* JavaNativeFoundation.h in Headers */,
|
||||
89AC83AA0CAF4BD600480894 /* JNFJNI.h in Headers */,
|
||||
89AC83AC0CAF4BD600480894 /* JNFNumber.h in Headers */,
|
||||
89AC83AE0CAF4BD600480894 /* JNFObject.h in Headers */,
|
||||
89AC83B00CAF4BD600480894 /* JNFPath.h in Headers */,
|
||||
89AC83B20CAF4BD600480894 /* JNFString.h in Headers */,
|
||||
8900DAEB0CB0365300EE572C /* JNFTypeCoercion.h in Headers */,
|
||||
89260F6E0CB622FC00FA4947 /* JNFThread.h in Headers */,
|
||||
8927F56D0D8F1E27008C35E3 /* JNFJObjectWrapper.h in Headers */,
|
||||
89B69B370F47D3C500C86CA9 /* JNFRunLoop.h in Headers */,
|
||||
89A8E9F80FA60E2D006CC298 /* JNFRunnable.h in Headers */,
|
||||
2C69E26310782500003EB656 /* JNFDate.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
8DC2EF4F0486A6940098B216 /* JavaNativeFoundation */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "JavaNativeFoundation" */;
|
||||
buildPhases = (
|
||||
8DC2EF500486A6940098B216 /* Headers */,
|
||||
8DC2EF520486A6940098B216 /* Resources */,
|
||||
8DC2EF540486A6940098B216 /* Sources */,
|
||||
8DC2EF560486A6940098B216 /* Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = JavaNativeFoundation;
|
||||
productInstallPath = "$(HOME)/Library/Frameworks";
|
||||
productName = JavaFoundation;
|
||||
productReference = 8DC2EF5B0486A6940098B216 /* JavaNativeFoundation.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
0867D690FE84028FC02AAC07 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 1200;
|
||||
};
|
||||
buildConfigurationList = 1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "JavaNativeFoundation" */;
|
||||
compatibilityVersion = "Xcode 3.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 1;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 0867D691FE84028FC02AAC07 /* JavaFoundation */;
|
||||
productRefGroup = 034768DFFF38A50411DB9C8B /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
8DC2EF4F0486A6940098B216 /* JavaNativeFoundation */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
8DC2EF520486A6940098B216 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
8DC2EF540486A6940098B216 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
89AC83A00CAF4BD600480894 /* debug.m in Sources */,
|
||||
89AC83A20CAF4BD600480894 /* JNFAssert.m in Sources */,
|
||||
89AC83A40CAF4BD600480894 /* JNFAutoreleasePool.m in Sources */,
|
||||
89AC83A80CAF4BD600480894 /* JNFException.m in Sources */,
|
||||
89AC83AB0CAF4BD600480894 /* JNFJNI.m in Sources */,
|
||||
89AC83AD0CAF4BD600480894 /* JNFNumber.m in Sources */,
|
||||
89AC83AF0CAF4BD600480894 /* JNFObject.m in Sources */,
|
||||
89AC83B10CAF4BD600480894 /* JNFPath.m in Sources */,
|
||||
89AC83B30CAF4BD600480894 /* JNFString.m in Sources */,
|
||||
8900DAEC0CB0365300EE572C /* JNFTypeCoercion.m in Sources */,
|
||||
89260F6F0CB622FC00FA4947 /* JNFThread.m in Sources */,
|
||||
8927F56E0D8F1E27008C35E3 /* JNFJObjectWrapper.m in Sources */,
|
||||
89B69B380F47D3C500C86CA9 /* JNFRunLoop.m in Sources */,
|
||||
89A8E9F90FA60E2D006CC298 /* JNFRunnable.m in Sources */,
|
||||
2C69E26410782500003EB656 /* JNFDate.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
1DEB91AE08733DA50010E9CD /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 3FA4788B23E37879005466BA /* JavaNativeFoundation.xcconfig */;
|
||||
buildSettings = {
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
1DEB91AF08733DA50010E9CD /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 3FA4788B23E37879005466BA /* JavaNativeFoundation.xcconfig */;
|
||||
buildSettings = {
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
1DEB91B208733DA50010E9CD /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 3FA4788A23E37879005466BA /* common.xcconfig */;
|
||||
buildSettings = {
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
1DEB91B308733DA50010E9CD /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 3FA4788A23E37879005466BA /* common.xcconfig */;
|
||||
buildSettings = {
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "JavaNativeFoundation" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
1DEB91AE08733DA50010E9CD /* Debug */,
|
||||
1DEB91AF08733DA50010E9CD /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "JavaNativeFoundation" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
1DEB91B208733DA50010E9CD /* Debug */,
|
||||
1DEB91B308733DA50010E9CD /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 0867D690FE84028FC02AAC07 /* Project object */;
|
||||
}
|
93
apple/JavaNativeFoundation/JavaNativeFoundation/JNFAssert.h
Normal file
93
apple/JavaNativeFoundation/JavaNativeFoundation/JNFAssert.h
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*
|
||||
* Assertions used by the JNF_COCOA_ENTER()/JNF_COCOA_EXIT() and class
|
||||
* caching macros. When building debug builds, improper use of the caching
|
||||
* macros will trigger warnings output to the console.
|
||||
*/
|
||||
|
||||
#import <JavaNativeFoundation/JNFJNI.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#define JAVA_ASSERTIONS_ON
|
||||
#endif /* DEBUG */
|
||||
|
||||
// Use the WARN macro to send a message to stderr in the
|
||||
// debug build. It gets removed from the optimized build
|
||||
// during preprocessing.
|
||||
#ifdef DEBUG
|
||||
#define JNF_WARN JNFDebugWarning
|
||||
#else
|
||||
#define JNF_WARN if (0) JNFDebugWarning
|
||||
#endif /* DEBUG */
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
JNF_EXPORT extern void JNFDebugWarning(const char *fmt, ...);
|
||||
|
||||
JNF_EXPORT extern void JNFAssertionFailure(const char *file, int line, const char *condition, const char *msg);
|
||||
|
||||
#ifdef JAVA_ASSERTIONS_ON
|
||||
|
||||
#define JNF_ASSERT_FAILURE(condition, msg) \
|
||||
JNFAssertionFailure(__FILE__, __LINE__, condition, msg) \
|
||||
|
||||
|
||||
#define JNF_ASSERT_MSG(condition, msg) \
|
||||
do { \
|
||||
if (!(condition)) { \
|
||||
JNF_ASSERT_FAILURE(#condition, msg); \
|
||||
} \
|
||||
} while(0) \
|
||||
|
||||
|
||||
#define JNF_ASSERT_COND(condition) \
|
||||
JNF_ASSERT_MSG(condition, NULL) \
|
||||
|
||||
|
||||
#define JNF_EXCEPTION_WARN(env, msg) \
|
||||
do { \
|
||||
(*(env))->ExceptionDescribe(env); \
|
||||
JNF_ASSERT_FAILURE("Java exception thrown", msg); \
|
||||
} while (0) \
|
||||
|
||||
|
||||
#define JNF_ASSERT_NO_EXCEPTION_MSG(env, msg) \
|
||||
if ((*(env))->ExceptionOccurred(env)) { \
|
||||
JNF_EXCEPTION_WARN(env, msg); \
|
||||
} \
|
||||
|
||||
|
||||
#define JNF_ASSERT_NO_EXCEPTION(env) \
|
||||
JNF_ASSERT_NO_EXCEPTION_MSG(env, NULL) \
|
||||
|
||||
#else
|
||||
|
||||
#define JNF_ASSERT_COND(condition)
|
||||
#define JNF_ASSERT_MSG(condition, msg)
|
||||
#define JNF_EXCEPTION_WARN(env, msg)
|
||||
#define JNF_ASSERT_NO_EXCEPTION(env)
|
||||
#define JNF_ASSERT_NO_EXCEPTION_MSG(env, msg)
|
||||
|
||||
#endif /* JAVA_ASSERTIONS_ON */
|
||||
|
||||
JNF_EXPORT extern void JNFDumpJavaStack(JNIEnv *env);
|
||||
|
||||
__END_DECLS
|
60
apple/JavaNativeFoundation/JavaNativeFoundation/JNFAssert.m
Normal file
60
apple/JavaNativeFoundation/JavaNativeFoundation/JNFAssert.m
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#import "JNFJNI.h"
|
||||
#import "JNFAssert.h"
|
||||
|
||||
#import "debug.h"
|
||||
|
||||
static void JNFDebugMessageV(const char *fmt, va_list args) {
|
||||
// Prints a message and breaks into debugger.
|
||||
fprintf(stderr, "JavaNativeFoundation: ");
|
||||
vfprintf(stderr, fmt, args);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
static void JNFDebugMessage(const char *fmt, ...) {
|
||||
// Takes printf args and then calls DebugBreak
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
JNFDebugMessageV(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void JNFDebugWarning(const char *fmt, ...) {
|
||||
// Takes printf args and then calls DebugBreak
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
JNFDebugMessageV(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void JNFAssertionFailure(const char *file, int line, const char *condition, const char *msg) {
|
||||
JNFDebugMessage("Assertion failure: %s", condition);
|
||||
if (msg) JNFDebugMessage(msg);
|
||||
JNFDebugMessage("File %s; Line %d", file, line);
|
||||
}
|
||||
|
||||
void JNFDumpJavaStack(JNIEnv *env) {
|
||||
static JNF_CLASS_CACHE(jc_Thread, "java/lang/Thread");
|
||||
static JNF_STATIC_MEMBER_CACHE(jsm_Thread_dumpStack, jc_Thread, "dumpStack", "()V");
|
||||
JNFCallVoidMethod(env, jc_Thread.cls, jsm_Thread_dumpStack);
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*
|
||||
* Utility class used by the JNF_COCOA_ENTER()/JNF_COCOA_EXIT() macros
|
||||
* from JNFJNI.h. Do not use this class or releated functions directly.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <JavaNativeFoundation/JNFJNI.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
typedef void JNFAutoreleasePoolToken;
|
||||
|
||||
// JNFNativeMethodEnter - called on entry to each native method by the
|
||||
// JNF_COCOA_ENTER(env) macro in JNFJNI.h
|
||||
JNF_EXPORT extern JNFAutoreleasePoolToken *JNFNativeMethodEnter(void);
|
||||
|
||||
// JNFNativeMethodExit - called on exit from each native method by the
|
||||
// JNF_COCOA_EXIT(env) macro in JNFJNI.h
|
||||
JNF_EXPORT extern void JNFNativeMethodExit(JNFAutoreleasePoolToken *token);
|
||||
|
||||
__END_DECLS
|
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*
|
||||
* The JNFAutoreleasePool manages setting up and tearing down autorelease
|
||||
* pools for Java calls into the Cocoa frameworks.
|
||||
*
|
||||
* The external entry point into this machinery is JNFMethodEnter() and JNFMethodExit().
|
||||
*/
|
||||
|
||||
#import "JNFAutoreleasePool.h"
|
||||
|
||||
#import <mach/mach_time.h>
|
||||
|
||||
// These are vended by the Objective-C runtime, but they are unfortunately
|
||||
// not available as API in the macOS SDK. We are following suit with swift
|
||||
// and clang in declaring them inline here. They canot be removed or changed
|
||||
// in the OS without major bincompat ramifications.
|
||||
//
|
||||
// These were added in macOS 10.7.
|
||||
void * _Nonnull objc_autoreleasePoolPush(void);
|
||||
void objc_autoreleasePoolPop(void * _Nonnull context);
|
||||
|
||||
#if TIMED
|
||||
static int64_t elapsedTime = 0;
|
||||
#endif
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark External API
|
||||
|
||||
// JNFNativeMethodEnter - called on entry to each native method
|
||||
//
|
||||
// It sets up an autorelease pool, and will return a token if
|
||||
// JNFNativeMethodExit should be called. It attempts to consider
|
||||
// how much time has elapsed since the last autorelease pop.
|
||||
|
||||
JNFAutoreleasePoolToken *JNFNativeMethodEnter() {
|
||||
#if TIMED
|
||||
int64_t start = mach_absolute_time();
|
||||
#endif
|
||||
|
||||
JNFAutoreleasePoolToken * const tokenToReturn = objc_autoreleasePoolPush();
|
||||
|
||||
#if TIMED
|
||||
elapsedTime += (mach_absolute_time() - start);
|
||||
#endif
|
||||
|
||||
return tokenToReturn;
|
||||
}
|
||||
|
||||
|
||||
// JNFNativeMethodExit - called on exit from native methods
|
||||
//
|
||||
// This method is only called on exit from the first
|
||||
// native method to appear in the execution stack.
|
||||
// This function does not need to be called on exit
|
||||
// from the inner native methods (as an optimization).
|
||||
// JNFNativeMethodEnter sets the token to non-nil if
|
||||
// JNFNativeMethodExit needs to be called on exit.
|
||||
|
||||
void JNFNativeMethodExit(JNFAutoreleasePoolToken *token) {
|
||||
|
||||
#if TIMED
|
||||
int64_t start = mach_absolute_time();
|
||||
#endif
|
||||
|
||||
objc_autoreleasePoolPop(token);
|
||||
|
||||
#if TIMED
|
||||
elapsedTime += (mach_absolute_time() - start);
|
||||
|
||||
NSLog(@"elapsedTime: %llu", elapsedTime);
|
||||
// elapsedTime = 0;
|
||||
#endif
|
||||
}
|
54
apple/JavaNativeFoundation/JavaNativeFoundation/JNFDate.h
Normal file
54
apple/JavaNativeFoundation/JavaNativeFoundation/JNFDate.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*
|
||||
* Functions to convert between date container classes.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSDate.h>
|
||||
|
||||
#import <JavaNativeFoundation/JNFJNI.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Converts java.util.Calendar and java.util.Date to an NSDate
|
||||
* NOTE: Return value is auto-released.
|
||||
*/
|
||||
JNF_EXPORT extern NSDate *JNFJavaToNSDate(JNIEnv *env, jobject date);
|
||||
|
||||
/*
|
||||
* Converts an NSDate to a java.util.Calendar
|
||||
* NOTE: This returns a JNI local ref. Any code that calls this should call DeleteLocalRef when done with the return value.
|
||||
*/
|
||||
JNF_EXPORT extern jobject JNFNSToJavaCalendar(JNIEnv *env, NSDate *date);
|
||||
|
||||
/*
|
||||
* Converts a millisecond time interval since the Java Jan 1, 1970 epoch into an
|
||||
* NSTimeInterval since Mac OS X's Jan 1, 2001 epoch.
|
||||
*/
|
||||
JNF_EXPORT extern NSTimeInterval JNFJavaMillisToNSTimeInterval(jlong javaMillisSince1970);
|
||||
|
||||
/*
|
||||
* Converts an NSTimeInterval since the Mac OS X Jan 1, 2001 epoch into a
|
||||
* Java millisecond time interval since Java's Jan 1, 1970 epoch.
|
||||
*/
|
||||
JNF_EXPORT extern jlong JNFNSTimeIntervalToJavaMillis(NSTimeInterval intervalSince2001);
|
||||
|
||||
__END_DECLS
|
72
apple/JavaNativeFoundation/JavaNativeFoundation/JNFDate.m
Normal file
72
apple/JavaNativeFoundation/JavaNativeFoundation/JNFDate.m
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#import "JNFDate.h"
|
||||
#import "JNFJNI.h"
|
||||
|
||||
|
||||
static JNF_CLASS_CACHE(sjc_Calendar, "java/util/Calendar");
|
||||
static JNF_CLASS_CACHE(sjc_Date, "java/util/Date");
|
||||
|
||||
JNF_EXPORT extern NSTimeInterval JNFJavaMillisToNSTimeInterval(jlong javaMillisSince1970)
|
||||
{
|
||||
return (NSTimeInterval)(((double)javaMillisSince1970 / 1000.0) - NSTimeIntervalSince1970);
|
||||
}
|
||||
|
||||
JNF_EXPORT extern jlong JNFNSTimeIntervalToJavaMillis(NSTimeInterval intervalSince2001)
|
||||
{
|
||||
return (jlong)((intervalSince2001 + NSTimeIntervalSince1970) * 1000.0);
|
||||
}
|
||||
|
||||
JNF_EXPORT extern NSDate *JNFJavaToNSDate(JNIEnv *env, jobject date)
|
||||
{
|
||||
if (date == NULL) return nil;
|
||||
|
||||
jlong millis = 0;
|
||||
if (JNFIsInstanceOf(env, date, &sjc_Calendar)) {
|
||||
static JNF_MEMBER_CACHE(jm_getTimeInMillis, sjc_Calendar, "getTimeInMillis", "()J");
|
||||
millis = JNFCallLongMethod(env, date, jm_getTimeInMillis);
|
||||
} else if (JNFIsInstanceOf(env, date, &sjc_Date)) {
|
||||
static JNF_MEMBER_CACHE(jm_getTime, sjc_Date, "getTime", "()J");
|
||||
millis = JNFCallLongMethod(env, date, jm_getTime);
|
||||
}
|
||||
|
||||
if (millis == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [NSDate dateWithTimeIntervalSince1970:((double)millis / 1000.0)];
|
||||
}
|
||||
|
||||
JNF_EXPORT extern jobject JNFNSToJavaCalendar(JNIEnv *env, NSDate *date)
|
||||
{
|
||||
if (date == nil) return NULL;
|
||||
|
||||
const jlong millis = (jlong)([date timeIntervalSince1970] * 1000.0);
|
||||
|
||||
static JNF_STATIC_MEMBER_CACHE(jsm_getInstance, sjc_Calendar, "getInstance", "()Ljava/util/Calendar;");
|
||||
jobject calendar = JNFCallStaticObjectMethod(env, jsm_getInstance);
|
||||
|
||||
static JNF_MEMBER_CACHE(jm_setTimeInMillis, sjc_Calendar, "setTimeInMillis", "(J)V");
|
||||
JNFCallVoidMethod(env, calendar, jm_setTimeInMillis, millis);
|
||||
|
||||
return calendar;
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*
|
||||
* JNFExceptions handle bridging exceptions between Foundation and Java. NSExceptions are
|
||||
* caught by the JNF_COCOA_ENTER()/JNF_COCOA_EXIT() macros, and transformed and thrown as
|
||||
* Java exceptions at the JNI boundry. The macros in JNFJNI.h also check for Java exceptions
|
||||
* and rethrow them as NSExceptions until they hit an @try/@catch block, or the
|
||||
* JNF_COCOA_ENTER()/JNF_COCOA_EXIT() macros.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <JavaNativeFoundation/JNFJNI.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
// Some exception class names.
|
||||
// These strings contain the full class name of each Java exception, so
|
||||
// they are handy to use when you need to throw an exception.
|
||||
JNF_EXPORT extern const char *kOutOfMemoryError;
|
||||
JNF_EXPORT extern const char *kClassNotFoundException;
|
||||
JNF_EXPORT extern const char *kNullPointerException;
|
||||
JNF_EXPORT extern const char *kIllegalAccessException;
|
||||
JNF_EXPORT extern const char *kIllegalArgumentException;
|
||||
JNF_EXPORT extern const char *kNoSuchFieldException;
|
||||
JNF_EXPORT extern const char *kNoSuchMethodException;
|
||||
JNF_EXPORT extern const char *kRuntimeException;
|
||||
|
||||
// JNFException - a subclass of NSException that wraps a Java exception
|
||||
//
|
||||
// When a java exception is thrown out to a native method, use +raiseUnnamedException:
|
||||
// to turn it into an NSException. When returning out of a native method in
|
||||
// which an NSException has been raised, use the -raiseToJava: method to turn
|
||||
// it back into a Java exception and "throw" it, in the Java sense.
|
||||
|
||||
JNF_EXPORT
|
||||
@interface JNFException : NSException
|
||||
|
||||
+ (void)raiseUnnamedException:(JNIEnv *)env;
|
||||
+ (void)raise:(JNIEnv *)env throwable:(jthrowable)throwable;
|
||||
+ (void)raise:(JNIEnv *)env as:(const char *)javaExceptionType reason:(const char *)reasonMsg;
|
||||
|
||||
- init:(JNIEnv *)env throwable:(jthrowable)throwable;
|
||||
- init:(JNIEnv *)env as:(const char *)javaExceptionType reason:(const char *)reasonMsg;
|
||||
|
||||
+ (void)throwToJava:(JNIEnv *)env exception:(NSException *)exception;
|
||||
+ (void)throwToJava:(JNIEnv *)env exception:(NSException *)exception as:(const char *)javaExceptionType;
|
||||
|
||||
- (void)raiseToJava:(JNIEnv *)env;
|
||||
|
||||
@end
|
||||
|
||||
__END_DECLS
|
279
apple/JavaNativeFoundation/JavaNativeFoundation/JNFException.m
Normal file
279
apple/JavaNativeFoundation/JavaNativeFoundation/JNFException.m
Normal file
@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#import "JNFException.h"
|
||||
|
||||
#import <stdlib.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import "JNFObject.h"
|
||||
#import "JNFString.h"
|
||||
#import "JNFAssert.h"
|
||||
#import "JNFThread.h"
|
||||
#import "debug.h"
|
||||
|
||||
|
||||
#define JAVA_LANG "java/lang/"
|
||||
const char* kOutOfMemoryError = JAVA_LANG "OutOfMemoryError";
|
||||
const char* kClassNotFoundException = JAVA_LANG "ClassNotFoundException";
|
||||
const char* kNullPointerException = JAVA_LANG "NullPointerException";
|
||||
const char* kIllegalAccessException = JAVA_LANG "IllegalAccessException";
|
||||
const char* kIllegalArgumentException = JAVA_LANG "IllegalArgumentException";
|
||||
const char* kNoSuchFieldException = JAVA_LANG "NoSuchFieldException";
|
||||
const char* kNoSuchMethodException = JAVA_LANG "NoSuchMethodException";
|
||||
const char* kRuntimeException = JAVA_LANG "RuntimeException";
|
||||
|
||||
@interface JNFException ()
|
||||
@property (readwrite, nonatomic, assign) jthrowable javaException;
|
||||
@end
|
||||
|
||||
@interface JNFException(_JNFPrivateExceptionLifecycle)
|
||||
|
||||
- (void) _setThrowable:(jthrowable)throwable withEnv:(JNIEnv *)env;
|
||||
- (void) _clearThrowableWithEnv:(JNIEnv *)env;
|
||||
- (void) _setThrowable:(jthrowable)throwable withNonNullEnv:(JNIEnv *)env;
|
||||
- (void) _clearThrowableWithNonNullEnv:(JNIEnv *)env;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation JNFException
|
||||
|
||||
- initUnnamed:(JNIEnv *)env {
|
||||
JNF_ASSERT_COND(env);
|
||||
jthrowable throwable = (*env)->ExceptionOccurred(env);
|
||||
if (throwable) return [self init:env throwable:throwable];
|
||||
|
||||
return [self initWithName:@"JavaNativeException" reason:@"See Java exception" userInfo:nil];
|
||||
}
|
||||
|
||||
+ (void)raiseUnnamedException:(JNIEnv *)env {
|
||||
JNF_ASSERT_COND(env);
|
||||
[[[[JNFException alloc] initUnnamed:env] autorelease] raise];
|
||||
}
|
||||
|
||||
+ (void)raise:(JNIEnv *)env throwable:(jthrowable)throwable {
|
||||
JNF_ASSERT_COND(env);
|
||||
[[[[JNFException alloc] init:env throwable:throwable] autorelease] raise];
|
||||
}
|
||||
|
||||
+ (void)raise:(JNIEnv *)env as:(const char *)javaExceptionType reason:(const char *)reasonMsg {
|
||||
JNF_ASSERT_COND(env);
|
||||
[[[[JNFException alloc] init:env as:javaExceptionType reason:reasonMsg] autorelease] raise];
|
||||
}
|
||||
|
||||
- init:(JNIEnv *)env throwable:(jthrowable)throwable {
|
||||
[self _setThrowable:throwable withEnv:env];
|
||||
(*env)->ExceptionClear(env); // The exception will be rethrown in -raiseToJava
|
||||
|
||||
static jclass jc_Throwable = NULL;
|
||||
if (jc_Throwable == NULL) {
|
||||
jc_Throwable = (*env)->FindClass(env, "java/lang/Throwable");
|
||||
jthrowable unexpected = (*env)->ExceptionOccurred(env);
|
||||
if (unexpected) {
|
||||
(*env)->ExceptionClear(env);
|
||||
return [self initWithName:@"JavaNativeException" reason:@"Internal JNF Error: could not find Throwable class" userInfo:nil];
|
||||
}
|
||||
}
|
||||
|
||||
static jmethodID jm_Throwable_getMessage = NULL;
|
||||
if (jm_Throwable_getMessage == NULL && jc_Throwable != NULL) {
|
||||
jm_Throwable_getMessage = (*env)->GetMethodID(env, jc_Throwable, "toString", "()Ljava/lang/String;");
|
||||
jthrowable unexpected = (*env)->ExceptionOccurred(env);
|
||||
if (unexpected) {
|
||||
(*env)->ExceptionClear(env);
|
||||
return [self initWithName:@"JavaNativeException" reason:@"Internal JNF Error: could not find Throwable.toString() method" userInfo:nil];
|
||||
}
|
||||
}
|
||||
|
||||
if (jm_Throwable_getMessage == NULL) {
|
||||
return [self initWithName:@"JavaNativeException" reason:@"Internal JNF Error: exception occurred, unable to determine cause" userInfo:nil];
|
||||
}
|
||||
|
||||
jobject msg = (*env)->CallObjectMethod(env, throwable, jm_Throwable_getMessage);
|
||||
jthrowable unexpected = (*env)->ExceptionOccurred(env);
|
||||
if (unexpected) {
|
||||
(*env)->ExceptionClear(env);
|
||||
return [self initWithName:@"JavaNativeException" reason:@"Internal JNF Error: failed calling Throwable.toString()" userInfo:nil];
|
||||
}
|
||||
|
||||
NSString *reason = JNFJavaToNSString(env, msg);
|
||||
(*env)->DeleteLocalRef(env, msg);
|
||||
return [self initWithName:@"JavaNativeException" reason:reason userInfo:nil];
|
||||
}
|
||||
|
||||
- init:(JNIEnv *)env as:(const char *)javaExceptionType reason:(const char *)reasonMsg {
|
||||
jclass exceptionClass = NULL;
|
||||
char *buf = NULL;
|
||||
|
||||
JNF_ASSERT_COND(env);
|
||||
if (javaExceptionType != NULL) {
|
||||
exceptionClass = (*env)->FindClass(env, javaExceptionType);
|
||||
}
|
||||
|
||||
if (exceptionClass == NULL) {
|
||||
// Try to throw an AWTError exception
|
||||
static jthrowable panicExceptionClass = NULL;
|
||||
const char* panicExceptionName = kRuntimeException;
|
||||
if (panicExceptionClass == NULL) {
|
||||
jclass cls = (*env)->FindClass(env, panicExceptionName);
|
||||
if (cls != NULL) {
|
||||
panicExceptionClass = (*env)->NewGlobalRef(env, cls);
|
||||
}
|
||||
}
|
||||
|
||||
exceptionClass = panicExceptionClass;
|
||||
if (javaExceptionType == NULL) {
|
||||
reasonMsg = "Missing Java exception class name while trying to throw a new Java exception";
|
||||
} else {
|
||||
// Quick and dirty thread-safe message buffer.
|
||||
buf = calloc(1, 512);
|
||||
if (buf != NULL) {
|
||||
sprintf(buf, "Unknown throwable class: %s.80", javaExceptionType);
|
||||
reasonMsg = buf;
|
||||
} else {
|
||||
reasonMsg = "Unknown throwable class, out of memory!";
|
||||
}
|
||||
}
|
||||
javaExceptionType = panicExceptionName;
|
||||
}
|
||||
|
||||
// Can't throw squat if there's no class to throw
|
||||
if (exceptionClass != NULL) {
|
||||
(*env)->ThrowNew(env, exceptionClass, reasonMsg);
|
||||
jthrowable ex = (*env)->ExceptionOccurred(env);
|
||||
if (ex) {
|
||||
(*env)->ExceptionClear(env); // Exception will be rethrown in -raiseToJava
|
||||
}
|
||||
[self _setThrowable:ex withEnv:env];
|
||||
}
|
||||
|
||||
if (reasonMsg == NULL) reasonMsg = "unknown";
|
||||
|
||||
@try {
|
||||
return [self initWithName:[NSString stringWithUTF8String:javaExceptionType]
|
||||
reason:[NSString stringWithUTF8String:reasonMsg]
|
||||
userInfo:nil];
|
||||
} @finally {
|
||||
if (buf != NULL) free(buf);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (void)throwToJava:(JNIEnv *)env exception:(NSException *)exception {
|
||||
[self throwToJava:env exception:exception as:kRuntimeException];
|
||||
}
|
||||
|
||||
+ (void)throwToJava:(JNIEnv *)env exception:(NSException *)exception as:(const char *)javaExceptionType{
|
||||
if (![exception isKindOfClass:[JNFException class]]) {
|
||||
exception = [[JNFException alloc] init:env as:javaExceptionType reason:[[NSString stringWithFormat:@"Non-Java exception raised, not handled! (Original problem: %@)", [exception reason]] UTF8String]];
|
||||
[exception autorelease];
|
||||
JNF_WARN("NSException not handled by native method. Passing to Java.");
|
||||
}
|
||||
|
||||
[(JNFException *)exception raiseToJava:env];
|
||||
}
|
||||
|
||||
- (void)raiseToJava:(JNIEnv *)env {
|
||||
jthrowable const javaException = self.javaException;
|
||||
|
||||
JNF_ASSERT_COND(env);
|
||||
JNF_ASSERT_COND(javaException != NULL);
|
||||
(*env)->Throw(env, javaException);
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
jthrowable const javaException = self.javaException;
|
||||
NSString *desc = [super description];
|
||||
if (!javaException) return desc;
|
||||
|
||||
@try {
|
||||
JNFThreadContext ctx = JNFThreadDetachImmediately;
|
||||
JNIEnv *env = JNFObtainEnv(&ctx);
|
||||
if (!env) {
|
||||
NSLog(@"JavaNativeFoundation: NULL JNIEnv error occurred obtaining Java exception description");
|
||||
return desc;
|
||||
}
|
||||
(*env)->ExceptionClear(env);
|
||||
NSString *stackTrace = JNFGetStackTraceAsNSString(env, javaException);
|
||||
JNFReleaseEnv(env, &ctx);
|
||||
|
||||
return stackTrace;
|
||||
} @catch (NSException *e) {
|
||||
// we clearly blew up trying to print our own exception, so we should
|
||||
// not try to do that again, even if it looks helpful - its a trap!
|
||||
NSLog(@"JavaNativeFoundation error occurred obtaining Java exception description");
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
||||
- (void) _setThrowable:(jthrowable)throwable withEnv:(JNIEnv *)env {
|
||||
if (env) {
|
||||
[self _clearThrowableWithNonNullEnv:env];
|
||||
[self _setThrowable:throwable withNonNullEnv:env];
|
||||
return;
|
||||
}
|
||||
|
||||
JNFThreadContext threadContext = JNFThreadDetachImmediately;
|
||||
env = JNFObtainEnv(&threadContext);
|
||||
if (env == NULL) return;
|
||||
|
||||
[self _clearThrowableWithNonNullEnv:env];
|
||||
[self _setThrowable:throwable withEnv:env];
|
||||
|
||||
JNFReleaseEnv(env, &threadContext);
|
||||
}
|
||||
|
||||
- (void) _clearThrowableWithEnv:(JNIEnv *)env {
|
||||
if (env) {
|
||||
[self _clearThrowableWithNonNullEnv:env];
|
||||
return;
|
||||
}
|
||||
|
||||
JNFThreadContext threadContext = JNFThreadDetachImmediately;
|
||||
env = JNFObtainEnv(&threadContext);
|
||||
if (env == NULL) return; // leak?
|
||||
|
||||
[self _clearThrowableWithNonNullEnv:env];
|
||||
|
||||
JNFReleaseEnv(env, &threadContext);
|
||||
}
|
||||
|
||||
- (void) _setThrowable:(jthrowable)throwable withNonNullEnv:(JNIEnv *)env {
|
||||
if (!throwable) return;
|
||||
self.javaException = (*env)->NewGlobalRef(env, throwable);
|
||||
}
|
||||
|
||||
// delete and clear
|
||||
- (void) _clearThrowableWithNonNullEnv:(JNIEnv *)env {
|
||||
jthrowable const javaException = self.javaException;
|
||||
if (!javaException) return;
|
||||
self.javaException = NULL;
|
||||
(*env)->DeleteGlobalRef(env, javaException);
|
||||
}
|
||||
|
||||
- (void) dealloc {
|
||||
[self _clearThrowableWithEnv:NULL];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
286
apple/JavaNativeFoundation/JavaNativeFoundation/JNFJNI.h
Normal file
286
apple/JavaNativeFoundation/JavaNativeFoundation/JNFJNI.h
Normal file
@ -0,0 +1,286 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*
|
||||
* The basic building blocks of writing Java JNI code that interacts with Objective-C.
|
||||
*
|
||||
* All JNI functions should call JNF_COCOA_ENTER()/JNF_COCOA_EXIT() to properly
|
||||
* catch thrown NSExceptions and periodically flush the autorelease pool for the
|
||||
* current thread. JNF_COCOA_DURING()/JNF_COCOA_HANDLE() should only be used when
|
||||
* AppKit is known to not be initialized yet.
|
||||
*
|
||||
* JNF_CLASS_CACHE()/JNF_MEMBER_CACHE()/JNF_STATIC_MEMBER_CACHE()/JNF_CTOR_CACHE()
|
||||
* all cache references to Java classes, methods, and variables for use by the
|
||||
* GET/SET/CALL functions. These functions check for Java exceptions, immediately
|
||||
* re-throwing them as JNFExceptions, and are simpler than their pure JNI equivalents.
|
||||
*/
|
||||
|
||||
#import <jni.h>
|
||||
#import <os/availability.h>
|
||||
#import <sys/cdefs.h>
|
||||
|
||||
#define JNF_EXPORT __attribute__ ((visibility ("default"))) API_UNAVAILABLE(ios)
|
||||
|
||||
#import <JavaNativeFoundation/JNFException.h>
|
||||
#import <JavaNativeFoundation/JNFAutoreleasePool.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
// from jlong.h
|
||||
// All pointers in and out of JNI functions should be expressed as jlongs
|
||||
// to accomodate for both 32-bit and 64-bit pointer sizes
|
||||
#ifndef jlong_to_ptr
|
||||
#define jlong_to_ptr(a) ((void *)(uintptr_t)(a))
|
||||
#endif
|
||||
|
||||
#ifndef ptr_to_jlong
|
||||
#define ptr_to_jlong(a) ((jlong)(uintptr_t)(a))
|
||||
#endif
|
||||
|
||||
// JNF_COCOA_DURING - Outermost exception scope for a JNI native method
|
||||
//
|
||||
// Use this macro only if you don't want any autorelease pool set or
|
||||
// other JNFThreadContext setup (ie, if the AppKit isn't running
|
||||
// yet). Usually, you want to use JNF_COCOA_ENTER & JNF_COCOA_EXIT
|
||||
#define JNF_COCOA_DURING(env) \
|
||||
@try {
|
||||
|
||||
|
||||
// JNF_COCOA_HANDLE - Close of JNF_COCOA_DURING
|
||||
//
|
||||
// Use this macro to match an JNF_COCOA_DURING
|
||||
// This macro ensures that no NSException is thrown into
|
||||
// the VM. It turns NSExceptions into Java exceptions.
|
||||
#define JNF_COCOA_HANDLE(env) \
|
||||
} @catch(NSException *localException) { \
|
||||
[JNFException throwToJava:env exception:localException]; \
|
||||
} \
|
||||
|
||||
|
||||
// JNF_COCOA_ENTER - Place at the beginning of every JNI method
|
||||
//
|
||||
// Sets up an exception handler and an autorelease pool if one is
|
||||
// not already setup.
|
||||
//
|
||||
// Note: if the native method executes before AppKit is
|
||||
// initialized, use JNF_COCOA_DURING.
|
||||
#define JNF_COCOA_ENTER(env) \
|
||||
{ \
|
||||
JNFAutoreleasePoolToken* _token = JNFNativeMethodEnter(); \
|
||||
JNF_COCOA_DURING(env)
|
||||
|
||||
|
||||
// JNF_COCOA_EXIT - Place at the end of every JNI method
|
||||
//
|
||||
// Catches NSExceptions and re-throws them as Java exceptions.
|
||||
// Use this macro to match JNF_COCOA_ENTER.
|
||||
#define JNF_COCOA_EXIT(env) \
|
||||
JNF_COCOA_HANDLE(env) \
|
||||
@finally { \
|
||||
if (_token) JNFNativeMethodExit(_token); \
|
||||
} \
|
||||
}
|
||||
|
||||
// JNF_CHECK_AND_RETHROW_EXCEPTION - rethrows exceptions from Java
|
||||
//
|
||||
// Takes an exception thrown from Java, and transforms it into an
|
||||
// NSException. The NSException should bubble up to the upper-most
|
||||
// JNF_COCOA_ENTER/JNF_COCOA_EXIT pair, and then be re-thrown as
|
||||
// a Java exception when returning from JNI. This check should be
|
||||
// done after raw JNI operations which could cause a Java exception
|
||||
// to be be thrown. The JNF{Get/Set/Call} macros below do this
|
||||
// check automatically.
|
||||
#define JNF_CHECK_AND_RETHROW_EXCEPTION(env) \
|
||||
{ \
|
||||
jthrowable _exception = (*env)->ExceptionOccurred(env); \
|
||||
if (_exception) [JNFException raise:env throwable:_exception]; \
|
||||
}
|
||||
|
||||
|
||||
// Use JNF_CLASS_CACHE, JNF_MEMBER_CACHE, JNF_STATIC_MEMBER_CACHE
|
||||
// and JNF_CTOR_CACHE as convenient ways to create
|
||||
// JNFClassInfo and JNFMemberInfo records that can
|
||||
// be passed to the utility functions that follow.
|
||||
|
||||
// JNF_CLASS_CACHE - Create a JNFClassInfo struct
|
||||
//
|
||||
// Use this macro to define a JNFClassInfo struct.
|
||||
// For example:
|
||||
// JNF_CLASS_CACHE(jc_java_awt_Font, "java/awt/Font");
|
||||
// defines the symbol jc_java_awt_Font to point to the
|
||||
// appropriately initialized JNFClassInfo struct.
|
||||
// The "jc_" prefix is short for "java class."
|
||||
#define JNF_CLASS_CACHE(cache_symbol, name) \
|
||||
JNFClassInfo cache_symbol = {name, NULL}
|
||||
|
||||
// JNF_MEMBER_CACHE - Create a JNFMemberInfo struct
|
||||
//
|
||||
// This macro creates and initializes a JNFMemberInfo
|
||||
// struct, and defines a pointer to it. Example:
|
||||
// JNF_MEMBER_CACHE(jm_Font_isBold, jc_java_awt_Font, "isBold", "Z");
|
||||
// This defines the symbol jm_Font_isBold to point to a
|
||||
// JNFMemberInfo struct that represents the isBold method
|
||||
// of the class java.awt.Font. Use this macro for both
|
||||
// fields and methods.
|
||||
#define JNF_MEMBER_CACHE(cache_symbol, class_cache_symbol, name, sig) \
|
||||
JNFMemberInfo _ ## cache_symbol = {name, sig, NO, &class_cache_symbol, {NULL}}, *cache_symbol=&_ ## cache_symbol
|
||||
|
||||
// JNF_STATIC_MEMBER_CACHE - Create a JNFMemberInfo struct for static members
|
||||
//
|
||||
// Same as JNF_MEMBER_CACHE, but used for static fields and mehods.
|
||||
#define JNF_STATIC_MEMBER_CACHE(cache_symbol, class_cache_symbol, name, sig) \
|
||||
JNFMemberInfo _ ## cache_symbol = {name, sig, YES, &class_cache_symbol, {NULL}}, *cache_symbol=&_ ## cache_symbol
|
||||
|
||||
// JNF_CTOR_CACHE - Create a JNFMemberInfo struct for a constructor
|
||||
//
|
||||
// Same as JNF_MEMBER_CACHE, but for constructors
|
||||
#define JNF_CTOR_CACHE(cache_symbol, class_cache_symbol, sig) \
|
||||
JNFMemberInfo _ ## cache_symbol = {"<init>", sig, NO, &class_cache_symbol, {NULL}}, *cache_symbol=&_ ## cache_symbol
|
||||
|
||||
|
||||
// JNFClassInfo - struct for caching a java class reference
|
||||
//
|
||||
// Create one of these by using the JNF_CLASS_CACHE macro (below).
|
||||
// The class ref is resolved lazily.
|
||||
typedef struct _JNFClassInfo {
|
||||
const char *name; // fully/qualified/ClassName
|
||||
jclass cls; // The JNI global class reference.
|
||||
} JNFClassInfo;
|
||||
|
||||
// JNFMemberInfo - struct for caching a field or method ID
|
||||
//
|
||||
// Create these by using the JNF_MEMBER_CACHE macro (below).
|
||||
// The member ID is resolved lazily.
|
||||
typedef struct _JNFMemberInfo {
|
||||
const char *name; // The name of the member
|
||||
const char *sig; // The signature of the member
|
||||
BOOL isStatic; // Is this member declared static?
|
||||
JNFClassInfo *classInfo; // points to the JNFClassInfo struct of
|
||||
// which this field/method is a member.
|
||||
union _j {
|
||||
jfieldID fieldID; // If field, the JNI field ID
|
||||
jmethodID methodID; // If method, the JNI method ID
|
||||
} j;
|
||||
} JNFMemberInfo;
|
||||
|
||||
|
||||
/*
|
||||
* JNI Utility Functions
|
||||
*
|
||||
* These functions make use of class and method ID caching, so they
|
||||
* are more efficient than simply calling their JNI equivalents directly.
|
||||
* They also detect Java exceptions and throw a corresponding
|
||||
* NSException when JNI returns with a Java exception.
|
||||
* Therefore, you should be prepared to handle exceptions
|
||||
* before they propagate either back to the VM or up
|
||||
* to the run loop.
|
||||
*/
|
||||
|
||||
// JNFIsInstanceOf - returns whether obj is an instance of clazz
|
||||
JNF_EXPORT extern BOOL JNFIsInstanceOf(JNIEnv *env, jobject obj, JNFClassInfo *clazz);
|
||||
|
||||
// Creating instances
|
||||
JNF_EXPORT extern jobject JNFNewObject(JNIEnv *env, JNFMemberInfo *constructor, ...);
|
||||
|
||||
// Creating arrays
|
||||
JNF_EXPORT extern jobjectArray JNFNewObjectArray (JNIEnv *env, JNFClassInfo *clazz, jsize length);
|
||||
JNF_EXPORT extern jbooleanArray JNFNewBooleanArray (JNIEnv *env, jsize length);
|
||||
JNF_EXPORT extern jbyteArray JNFNewByteArray (JNIEnv *env, jsize length);
|
||||
JNF_EXPORT extern jcharArray JNFNewCharArray (JNIEnv *env, jsize length);
|
||||
JNF_EXPORT extern jshortArray JNFNewShortArray (JNIEnv *env, jsize length);
|
||||
JNF_EXPORT extern jintArray JNFNewIntArray (JNIEnv *env, jsize length);
|
||||
JNF_EXPORT extern jlongArray JNFNewLongArray (JNIEnv *env, jsize length);
|
||||
JNF_EXPORT extern jfloatArray JNFNewFloatArray (JNIEnv *env, jsize length);
|
||||
JNF_EXPORT extern jdoubleArray JNFNewDoubleArray (JNIEnv *env, jsize length);
|
||||
|
||||
// Non-static getters
|
||||
JNF_EXPORT extern jobject JNFGetObjectField (JNIEnv *env, jobject obj, JNFMemberInfo *field);
|
||||
JNF_EXPORT extern jboolean JNFGetBooleanField(JNIEnv *env, jobject obj, JNFMemberInfo *field);
|
||||
JNF_EXPORT extern jbyte JNFGetByteField (JNIEnv *env, jobject obj, JNFMemberInfo *field);
|
||||
JNF_EXPORT extern jchar JNFGetCharField (JNIEnv *env, jobject obj, JNFMemberInfo *field);
|
||||
JNF_EXPORT extern jshort JNFGetShortField (JNIEnv *env, jobject obj, JNFMemberInfo *field);
|
||||
JNF_EXPORT extern jint JNFGetIntField (JNIEnv *env, jobject obj, JNFMemberInfo *field);
|
||||
JNF_EXPORT extern jlong JNFGetLongField (JNIEnv *env, jobject obj, JNFMemberInfo *field);
|
||||
JNF_EXPORT extern jfloat JNFGetFloatField (JNIEnv *env, jobject obj, JNFMemberInfo *field);
|
||||
JNF_EXPORT extern jdouble JNFGetDoubleField (JNIEnv *env, jobject obj, JNFMemberInfo *field);
|
||||
|
||||
// Static getters
|
||||
JNF_EXPORT extern jobject JNFGetStaticObjectField (JNIEnv *env, JNFMemberInfo *field);
|
||||
JNF_EXPORT extern jboolean JNFGetStaticBooleanField(JNIEnv *env, JNFMemberInfo *field);
|
||||
JNF_EXPORT extern jbyte JNFGetStaticByteField (JNIEnv *env, JNFMemberInfo *field);
|
||||
JNF_EXPORT extern jchar JNFGetStaticCharField (JNIEnv *env, JNFMemberInfo *field);
|
||||
JNF_EXPORT extern jshort JNFGetStaticShortField (JNIEnv *env, JNFMemberInfo *field);
|
||||
JNF_EXPORT extern jint JNFGetStaticIntField (JNIEnv *env, JNFMemberInfo *field);
|
||||
JNF_EXPORT extern jlong JNFGetStaticLongField (JNIEnv *env, JNFMemberInfo *field);
|
||||
JNF_EXPORT extern jfloat JNFGetStaticFloatField (JNIEnv *env, JNFMemberInfo *field);
|
||||
JNF_EXPORT extern jdouble JNFGetStaticDoubleField (JNIEnv *env, JNFMemberInfo *field);
|
||||
|
||||
// Non-static setters
|
||||
JNF_EXPORT extern void JNFSetObjectField (JNIEnv *env, jobject obj, JNFMemberInfo *field, jobject val);
|
||||
JNF_EXPORT extern void JNFSetBooleanField(JNIEnv *env, jobject obj, JNFMemberInfo *field, jboolean val);
|
||||
JNF_EXPORT extern void JNFSetByteField (JNIEnv *env, jobject obj, JNFMemberInfo *field, jbyte val);
|
||||
JNF_EXPORT extern void JNFSetCharField (JNIEnv *env, jobject obj, JNFMemberInfo *field, jchar val);
|
||||
JNF_EXPORT extern void JNFSetShortField (JNIEnv *env, jobject obj, JNFMemberInfo *field, jshort val);
|
||||
JNF_EXPORT extern void JNFSetIntField (JNIEnv *env, jobject obj, JNFMemberInfo *field, jint val);
|
||||
JNF_EXPORT extern void JNFSetLongField (JNIEnv *env, jobject obj, JNFMemberInfo *field, jlong val);
|
||||
JNF_EXPORT extern void JNFSetFloatField (JNIEnv *env, jobject obj, JNFMemberInfo *field, jfloat val);
|
||||
JNF_EXPORT extern void JNFSetDoubleField (JNIEnv *env, jobject obj, JNFMemberInfo *field, jdouble val);
|
||||
|
||||
// Static setters
|
||||
JNF_EXPORT extern void JNFSetStaticObjectField (JNIEnv *env, JNFMemberInfo *field, jobject val);
|
||||
JNF_EXPORT extern void JNFSetStaticBooleanField(JNIEnv *env, JNFMemberInfo *field, jboolean val);
|
||||
JNF_EXPORT extern void JNFSetStaticByteField (JNIEnv *env, JNFMemberInfo *field, jbyte val);
|
||||
JNF_EXPORT extern void JNFSetStaticCharField (JNIEnv *env, JNFMemberInfo *field, jchar val);
|
||||
JNF_EXPORT extern void JNFSetStaticShortField (JNIEnv *env, JNFMemberInfo *field, jshort val);
|
||||
JNF_EXPORT extern void JNFSetStaticIntField (JNIEnv *env, JNFMemberInfo *field, jint val);
|
||||
JNF_EXPORT extern void JNFSetStaticLongField (JNIEnv *env, JNFMemberInfo *field, jlong val);
|
||||
JNF_EXPORT extern void JNFSetStaticFloatField (JNIEnv *env, JNFMemberInfo *field, jfloat val);
|
||||
JNF_EXPORT extern void JNFSetStaticDoubleField (JNIEnv *env, JNFMemberInfo *field, jdouble val);
|
||||
|
||||
// Calling instance methods
|
||||
JNF_EXPORT extern void JNFCallVoidMethod (JNIEnv *env, jobject obj, JNFMemberInfo *method, ...);
|
||||
JNF_EXPORT extern jobject JNFCallObjectMethod (JNIEnv *env, jobject obj, JNFMemberInfo *method, ...);
|
||||
JNF_EXPORT extern jboolean JNFCallBooleanMethod(JNIEnv *env, jobject obj, JNFMemberInfo *method, ...);
|
||||
JNF_EXPORT extern jbyte JNFCallByteMethod (JNIEnv *env, jobject obj, JNFMemberInfo *method, ...);
|
||||
JNF_EXPORT extern jchar JNFCallCharMethod (JNIEnv *env, jobject obj, JNFMemberInfo *method, ...);
|
||||
JNF_EXPORT extern jshort JNFCallShortMethod (JNIEnv *env, jobject obj, JNFMemberInfo *method, ...);
|
||||
JNF_EXPORT extern jint JNFCallIntMethod (JNIEnv *env, jobject obj, JNFMemberInfo *method, ...);
|
||||
JNF_EXPORT extern jlong JNFCallLongMethod (JNIEnv *env, jobject obj, JNFMemberInfo *method, ...);
|
||||
JNF_EXPORT extern jfloat JNFCallFloatMethod (JNIEnv *env, jobject obj, JNFMemberInfo *method, ...);
|
||||
JNF_EXPORT extern jdouble JNFCallDoubleMethod (JNIEnv *env, jobject obj, JNFMemberInfo *method, ...);
|
||||
|
||||
// Calling static methods
|
||||
JNF_EXPORT extern void JNFCallStaticVoidMethod (JNIEnv *env, JNFMemberInfo *method, ...);
|
||||
JNF_EXPORT extern jobject JNFCallStaticObjectMethod (JNIEnv *env, JNFMemberInfo *method, ...);
|
||||
JNF_EXPORT extern jboolean JNFCallStaticBooleanMethod(JNIEnv *env, JNFMemberInfo *method, ...);
|
||||
JNF_EXPORT extern jbyte JNFCallStaticByteMethod (JNIEnv *env, JNFMemberInfo *method, ...);
|
||||
JNF_EXPORT extern jchar JNFCallStaticCharMethod (JNIEnv *env, JNFMemberInfo *method, ...);
|
||||
JNF_EXPORT extern jshort JNFCallStaticShortMethod (JNIEnv *env, JNFMemberInfo *method, ...);
|
||||
JNF_EXPORT extern jint JNFCallStaticIntMethod (JNIEnv *env, JNFMemberInfo *method, ...);
|
||||
JNF_EXPORT extern jlong JNFCallStaticLongMethod (JNIEnv *env, JNFMemberInfo *method, ...);
|
||||
JNF_EXPORT extern jfloat JNFCallStaticFloatMethod (JNIEnv *env, JNFMemberInfo *method, ...);
|
||||
JNF_EXPORT extern jdouble JNFCallStaticDoubleMethod (JNIEnv *env, JNFMemberInfo *method, ...);
|
||||
|
||||
// Global references
|
||||
JNF_EXPORT extern jobject JNFNewGlobalRef(JNIEnv *env, jobject obj);
|
||||
JNF_EXPORT extern void JNFDeleteGlobalRef(JNIEnv *env, jobject globalRef);
|
||||
JNF_EXPORT extern jobject JNFNewWeakGlobalRef(JNIEnv *env, jobject obj);
|
||||
JNF_EXPORT extern void JNFDeleteWeakGlobalRef(JNIEnv *env, jobject globalRef);
|
||||
|
||||
__END_DECLS
|
435
apple/JavaNativeFoundation/JavaNativeFoundation/JNFJNI.m
Normal file
435
apple/JavaNativeFoundation/JavaNativeFoundation/JNFJNI.m
Normal file
@ -0,0 +1,435 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#import "JNFJNI.h"
|
||||
|
||||
#import "JNFAssert.h"
|
||||
#import "debug.h"
|
||||
|
||||
// constants ripped from jvm.h
|
||||
#define JVM_SIGNATURE_ARRAY '['
|
||||
#define JVM_SIGNATURE_BYTE 'B'
|
||||
#define JVM_SIGNATURE_CHAR 'C'
|
||||
#define JVM_SIGNATURE_CLASS 'L'
|
||||
#define JVM_SIGNATURE_ENDCLASS ';'
|
||||
#define JVM_SIGNATURE_ENUM 'E'
|
||||
#define JVM_SIGNATURE_FLOAT 'F'
|
||||
#define JVM_SIGNATURE_DOUBLE 'D'
|
||||
#define JVM_SIGNATURE_FUNC '('
|
||||
#define JVM_SIGNATURE_ENDFUNC ')'
|
||||
#define JVM_SIGNATURE_INT 'I'
|
||||
#define JVM_SIGNATURE_LONG 'J'
|
||||
#define JVM_SIGNATURE_SHORT 'S'
|
||||
#define JVM_SIGNATURE_VOID 'V'
|
||||
#define JVM_SIGNATURE_BOOLEAN 'Z'
|
||||
|
||||
// IS_METHOD - Does the parameter point to a method member?
|
||||
//
|
||||
// This is used mostly in asserts.
|
||||
#define IS_METHOD(member) (*(member->sig) == SIGNATURE_FUNC)
|
||||
|
||||
static inline BOOL isMethod(JNFMemberInfo *member) {
|
||||
return (*(member->sig)) == JVM_SIGNATURE_FUNC;
|
||||
}
|
||||
|
||||
static void JNFLookupClass(JNIEnv *env, JNFClassInfo *class) {
|
||||
jclass localCls = NULL;
|
||||
JNF_ASSERT_COND(class);
|
||||
localCls = (*env)->FindClass(env, class->name);
|
||||
if (localCls == NULL) [JNFException raiseUnnamedException:env];
|
||||
|
||||
class->cls = JNFNewGlobalRef(env, localCls);
|
||||
(*env)->DeleteLocalRef(env, localCls);
|
||||
if (class->cls == NULL) [JNFException raiseUnnamedException:env];
|
||||
}
|
||||
|
||||
static void JNFLookupMemberID(JNIEnv *env, JNFMemberInfo *member) {
|
||||
JNF_ASSERT_COND(member);
|
||||
JNF_ASSERT_COND(member->classInfo);
|
||||
|
||||
if (member->classInfo->cls == NULL) JNFLookupClass(env, member->classInfo);
|
||||
|
||||
if (isMethod(member)) {
|
||||
member->j.methodID = member->isStatic ?
|
||||
(*env)->GetStaticMethodID(env, member->classInfo->cls, member->name, member->sig) :
|
||||
(*env)->GetMethodID(env, member->classInfo->cls, member->name, member->sig);
|
||||
} else { // This member is a field
|
||||
member->j.fieldID = member->isStatic ?
|
||||
(*env)->GetStaticFieldID(env, member->classInfo->cls, member->name, member->sig) :
|
||||
(*env)->GetFieldID(env, member->classInfo->cls, member->name, member->sig);
|
||||
}
|
||||
|
||||
// If NULL, then exception occurred
|
||||
if (member->j.methodID == NULL) [JNFException raiseUnnamedException:env];
|
||||
}
|
||||
|
||||
BOOL JNFIsInstanceOf(JNIEnv *env, jobject obj, JNFClassInfo *clazz) {
|
||||
if (clazz->cls == NULL) JNFLookupClass(env, clazz);
|
||||
return (BOOL)(*env)->IsInstanceOf(env, obj, clazz->cls);
|
||||
}
|
||||
|
||||
//
|
||||
// A whole mess o' macros
|
||||
//
|
||||
// All of these macros provide caching of class refs and member IDs,
|
||||
// which speeds all member accesses following the first. In addition,
|
||||
// Java exceptions are caught and turned into NSExceptions,
|
||||
// so error handling is much easier on the native side.
|
||||
//
|
||||
// You can use these if you need them for optimization, but it's generally
|
||||
// easier and better to use the utility functions in jni_utilities.h.
|
||||
|
||||
// LOOKUP_MEMBER_ID - Lookup a fieldID if needed
|
||||
//
|
||||
// Give this macro a JNFMemberInfo*, and it will
|
||||
// lookup and cache the field ID as needed.
|
||||
#define LOOKUP_MEMBER_ID(env, member) \
|
||||
if (member->j.fieldID == NULL) \
|
||||
JNFLookupMemberID(env, member)
|
||||
|
||||
#ifdef RAWT_DEBUG
|
||||
#define VERIFY_MEMBERS
|
||||
#endif
|
||||
|
||||
#ifdef VERIFY_MEMBERS
|
||||
#define VERIFY_FIELD(env, obj, field, sig) VerifyMember(env, obj, field, sig, NO)
|
||||
#define VERIFY_METHOD(env, obj, method, sig) VerifyMember(env, obj, method, sig, YES)
|
||||
#else
|
||||
#define VERIFY_FIELD(env, obj, member, sig)
|
||||
#define VERIFY_METHOD(env, obj, member, sig)
|
||||
#endif /* RAWT_DEBUG */
|
||||
|
||||
// GET_FIELD - Safe way to get a java field
|
||||
//
|
||||
// This macro takes care of the caching and exception
|
||||
// propgation.
|
||||
#define GET_FIELD(env, obj, field, result, sig, jni_call) \
|
||||
LOOKUP_MEMBER_ID(env, field); \
|
||||
VERIFY_FIELD(env, obj, field, sig); \
|
||||
result = (*env)->jni_call(env, obj, field->j.fieldID); \
|
||||
JNF_CHECK_AND_RETHROW_EXCEPTION(env);
|
||||
|
||||
// GET_STATIC_FIELD
|
||||
//
|
||||
#define GET_STATIC_FIELD(env, field, result, sig, jni_call) \
|
||||
LOOKUP_MEMBER_ID(env, field); \
|
||||
VERIFY_FIELD(env, NULL, field, sig); \
|
||||
result = (*env)->jni_call(env, field->classInfo->cls, field->j.fieldID); \
|
||||
JNF_CHECK_AND_RETHROW_EXCEPTION(env);
|
||||
|
||||
// SET_FIELD - Safe way to set a java field
|
||||
//
|
||||
// Similar to GET_FIELD
|
||||
#define SET_FIELD(env, obj, field, val, sig, jni_call) \
|
||||
LOOKUP_MEMBER_ID(env, field); \
|
||||
VERIFY_FIELD(env, obj, field, sig); \
|
||||
(*env)->jni_call(env, obj, field->j.fieldID, val); \
|
||||
JNF_CHECK_AND_RETHROW_EXCEPTION(env);
|
||||
|
||||
// SET_STATIC_FIELD
|
||||
//
|
||||
#define SET_STATIC_FIELD(env, field, val, sig, jni_call) \
|
||||
LOOKUP_MEMBER_ID(env, field); \
|
||||
VERIFY_FIELD(env, NULL, field, sig); \
|
||||
(*env)->jni_call(env, field->classInfo->cls, field->j.fieldID, val); \
|
||||
JNF_CHECK_AND_RETHROW_EXCEPTION(env);
|
||||
|
||||
// CALL_VOID_METHOD
|
||||
//
|
||||
// "args" is a va_list
|
||||
#define CALL_VOID_METHOD(env, obj, method, jni_call, args) \
|
||||
LOOKUP_MEMBER_ID(env, method); \
|
||||
VERIFY_METHOD(env, obj, method, JVM_SIGNATURE_VOID); \
|
||||
(*env)->jni_call(env, obj, method->j.methodID, args); \
|
||||
JNF_CHECK_AND_RETHROW_EXCEPTION(env);
|
||||
|
||||
// CALL_STATIC_VOID_METHOD
|
||||
//
|
||||
// "args" is a va_list
|
||||
#define CALL_STATIC_VOID_METHOD(env, method, jni_call, args) \
|
||||
LOOKUP_MEMBER_ID(env, method); \
|
||||
VERIFY_METHOD(env, NULL, method, JVM_SIGNATURE_VOID); \
|
||||
(*env)->jni_call(env, method->classInfo->cls, method->j.methodID, args); \
|
||||
JNF_CHECK_AND_RETHROW_EXCEPTION(env);
|
||||
|
||||
// CALL_METHOD - Call a method that returns a value
|
||||
//
|
||||
// "args" is a va_list
|
||||
#define CALL_METHOD(env, obj, method, result, sig, jni_call, args ) \
|
||||
LOOKUP_MEMBER_ID(env, method); \
|
||||
VERIFY_METHOD(env, obj, method, sig); \
|
||||
result = (*env)->jni_call(env, obj, method->j.methodID, args); \
|
||||
JNF_CHECK_AND_RETHROW_EXCEPTION(env);
|
||||
|
||||
// CALL_STATIC_METHOD - Call a static method that returns a value
|
||||
//
|
||||
// "args" is a va_list
|
||||
#define CALL_STATIC_METHOD(env, method, result, sig, jni_call, args) \
|
||||
LOOKUP_MEMBER_ID(env, method); \
|
||||
VERIFY_METHOD(env, NULL, method, sig); \
|
||||
result = (*env)->jni_call(env, method->classInfo->cls, method->j.methodID, args); \
|
||||
JNF_CHECK_AND_RETHROW_EXCEPTION(env);
|
||||
|
||||
|
||||
// NEW_OBJECT - Create instances
|
||||
//
|
||||
// "constructor" is a JNFMemberInfo* to a constructor method
|
||||
// "args" is a va_list of arguments
|
||||
#define NEW_OBJECT(env, constructor, obj, args) \
|
||||
LOOKUP_MEMBER_ID(env, constructor); \
|
||||
VERIFY_METHOD(env, NULL, constructor, JVM_SIGNATURE_VOID); \
|
||||
obj = (*env)->NewObjectV(env, constructor->classInfo->cls, constructor->j.methodID, args); \
|
||||
JNF_CHECK_AND_RETHROW_EXCEPTION(env);
|
||||
|
||||
|
||||
//
|
||||
// Non-static getters & setters
|
||||
#define GET_FIELD_IMPLEMENTATION(type, sig, jni_call) \
|
||||
type JNF ## jni_call(JNIEnv *env, jobject obj, JNFMemberInfo* field) { \
|
||||
type result; \
|
||||
JNF_ASSERT_COND(!field->isStatic); \
|
||||
GET_FIELD(env, obj, field, result, sig, jni_call); \
|
||||
return result; \
|
||||
}
|
||||
|
||||
#define SET_FIELD_IMPLEMENTATION(type, sig, jni_call) \
|
||||
void JNF ## jni_call(JNIEnv *env, jobject obj, JNFMemberInfo* field, type val) {\
|
||||
JNF_ASSERT_COND(!field->isStatic); \
|
||||
SET_FIELD(env, obj, field, val, sig, jni_call); \
|
||||
}
|
||||
|
||||
//
|
||||
// Non-static getter implemenations
|
||||
GET_FIELD_IMPLEMENTATION(jobject, JVM_SIGNATURE_ENDCLASS, GetObjectField)
|
||||
GET_FIELD_IMPLEMENTATION(jboolean, JVM_SIGNATURE_BOOLEAN, GetBooleanField)
|
||||
GET_FIELD_IMPLEMENTATION(jbyte, JVM_SIGNATURE_BYTE, GetByteField)
|
||||
GET_FIELD_IMPLEMENTATION(jchar, JVM_SIGNATURE_CHAR, GetCharField)
|
||||
GET_FIELD_IMPLEMENTATION(jshort, JVM_SIGNATURE_SHORT, GetShortField)
|
||||
GET_FIELD_IMPLEMENTATION(jint, JVM_SIGNATURE_INT, GetIntField)
|
||||
GET_FIELD_IMPLEMENTATION(jlong, JVM_SIGNATURE_LONG, GetLongField)
|
||||
GET_FIELD_IMPLEMENTATION(jfloat, JVM_SIGNATURE_FLOAT, GetFloatField)
|
||||
GET_FIELD_IMPLEMENTATION(jdouble, JVM_SIGNATURE_DOUBLE, GetDoubleField)
|
||||
|
||||
//
|
||||
// Non-static setter implemenations
|
||||
SET_FIELD_IMPLEMENTATION(jobject, JVM_SIGNATURE_ENDCLASS, SetObjectField)
|
||||
SET_FIELD_IMPLEMENTATION(jboolean, JVM_SIGNATURE_BOOLEAN, SetBooleanField)
|
||||
SET_FIELD_IMPLEMENTATION(jbyte, JVM_SIGNATURE_BYTE, SetByteField)
|
||||
SET_FIELD_IMPLEMENTATION(jchar, JVM_SIGNATURE_CHAR, SetCharField)
|
||||
SET_FIELD_IMPLEMENTATION(jshort, JVM_SIGNATURE_SHORT, SetShortField)
|
||||
SET_FIELD_IMPLEMENTATION(jint, JVM_SIGNATURE_INT, SetIntField)
|
||||
SET_FIELD_IMPLEMENTATION(jlong, JVM_SIGNATURE_LONG, SetLongField)
|
||||
SET_FIELD_IMPLEMENTATION(jfloat, JVM_SIGNATURE_FLOAT, SetFloatField)
|
||||
SET_FIELD_IMPLEMENTATION(jdouble, JVM_SIGNATURE_DOUBLE, SetDoubleField)
|
||||
|
||||
//
|
||||
// Static getters & setters
|
||||
#define GET_STATIC_FIELD_IMPLEMENTATION(type, sig, jni_call) \
|
||||
type JNF ## jni_call(JNIEnv *env, JNFMemberInfo* field) { \
|
||||
type result; \
|
||||
JNF_ASSERT_COND(field->isStatic); \
|
||||
GET_STATIC_FIELD(env, field, result, sig, jni_call); \
|
||||
return result; \
|
||||
}
|
||||
|
||||
#define SET_STATIC_FIELD_IMPLEMENTATION(type, sig, jni_call) \
|
||||
void JNF ## jni_call(JNIEnv *env, JNFMemberInfo* field, type val) { \
|
||||
JNF_ASSERT_COND(field->isStatic); \
|
||||
SET_STATIC_FIELD(env, field, val, sig, jni_call); \
|
||||
}
|
||||
|
||||
//
|
||||
// Static getter implementations
|
||||
GET_STATIC_FIELD_IMPLEMENTATION(jobject, JVM_SIGNATURE_ENDCLASS, GetStaticObjectField)
|
||||
GET_STATIC_FIELD_IMPLEMENTATION(jboolean, JVM_SIGNATURE_BOOLEAN, GetStaticBooleanField)
|
||||
GET_STATIC_FIELD_IMPLEMENTATION(jbyte, JVM_SIGNATURE_BYTE, GetStaticByteField)
|
||||
GET_STATIC_FIELD_IMPLEMENTATION(jchar, JVM_SIGNATURE_CHAR, GetStaticCharField)
|
||||
GET_STATIC_FIELD_IMPLEMENTATION(jshort, JVM_SIGNATURE_SHORT, GetStaticShortField)
|
||||
GET_STATIC_FIELD_IMPLEMENTATION(jint, JVM_SIGNATURE_INT, GetStaticIntField)
|
||||
GET_STATIC_FIELD_IMPLEMENTATION(jlong, JVM_SIGNATURE_LONG, GetStaticLongField)
|
||||
GET_STATIC_FIELD_IMPLEMENTATION(jfloat, JVM_SIGNATURE_FLOAT, GetStaticFloatField)
|
||||
GET_STATIC_FIELD_IMPLEMENTATION(jdouble, JVM_SIGNATURE_DOUBLE, GetStaticDoubleField)
|
||||
|
||||
//
|
||||
// Static setter implemenations
|
||||
SET_STATIC_FIELD_IMPLEMENTATION(jobject, JVM_SIGNATURE_ENDCLASS, SetStaticObjectField)
|
||||
SET_STATIC_FIELD_IMPLEMENTATION(jboolean, JVM_SIGNATURE_BOOLEAN, SetStaticBooleanField)
|
||||
SET_STATIC_FIELD_IMPLEMENTATION(jbyte, JVM_SIGNATURE_BYTE, SetStaticByteField)
|
||||
SET_STATIC_FIELD_IMPLEMENTATION(jchar, JVM_SIGNATURE_CHAR, SetStaticCharField)
|
||||
SET_STATIC_FIELD_IMPLEMENTATION(jshort, JVM_SIGNATURE_SHORT, SetStaticShortField)
|
||||
SET_STATIC_FIELD_IMPLEMENTATION(jint, JVM_SIGNATURE_INT, SetStaticIntField)
|
||||
SET_STATIC_FIELD_IMPLEMENTATION(jlong, JVM_SIGNATURE_LONG, SetStaticLongField)
|
||||
SET_STATIC_FIELD_IMPLEMENTATION(jfloat, JVM_SIGNATURE_FLOAT, SetStaticFloatField)
|
||||
SET_STATIC_FIELD_IMPLEMENTATION(jdouble, JVM_SIGNATURE_DOUBLE, SetStaticDoubleField)
|
||||
|
||||
|
||||
//
|
||||
// Calling instance methods
|
||||
//
|
||||
// FIX: if an exception is thrown, va_end is not called.
|
||||
// On i386, va_end is a null macro. Check on PPC to verify the same.
|
||||
void JNFCallVoidMethod(JNIEnv *env, jobject obj, JNFMemberInfo* method, ...) {
|
||||
va_list args;
|
||||
JNF_ASSERT_COND(!method->isStatic);
|
||||
va_start(args, method);
|
||||
CALL_VOID_METHOD(env, obj, method, CallVoidMethodV, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#define CALL_METHOD_IMPLEMENTATION(type, sig, jni_call) \
|
||||
type JNF ## jni_call(JNIEnv *env, jobject obj, JNFMemberInfo* method, ...) {\
|
||||
type result; \
|
||||
va_list args; \
|
||||
JNF_ASSERT_COND(!method->isStatic); \
|
||||
va_start(args, method); \
|
||||
CALL_METHOD(env, obj, method, result, sig, jni_call ## V, args); \
|
||||
va_end(args); \
|
||||
return result; \
|
||||
}
|
||||
|
||||
CALL_METHOD_IMPLEMENTATION(jobject, JVM_SIGNATURE_ENDCLASS, CallObjectMethod)
|
||||
CALL_METHOD_IMPLEMENTATION(jboolean, JVM_SIGNATURE_BOOLEAN, CallBooleanMethod)
|
||||
CALL_METHOD_IMPLEMENTATION(jbyte, JVM_SIGNATURE_BYTE, CallByteMethod)
|
||||
CALL_METHOD_IMPLEMENTATION(jchar, JVM_SIGNATURE_CHAR, CallCharMethod)
|
||||
CALL_METHOD_IMPLEMENTATION(jshort, JVM_SIGNATURE_SHORT, CallShortMethod)
|
||||
CALL_METHOD_IMPLEMENTATION(jint, JVM_SIGNATURE_INT, CallIntMethod)
|
||||
CALL_METHOD_IMPLEMENTATION(jlong, JVM_SIGNATURE_LONG, CallLongMethod)
|
||||
CALL_METHOD_IMPLEMENTATION(jfloat, JVM_SIGNATURE_FLOAT, CallFloatMethod)
|
||||
CALL_METHOD_IMPLEMENTATION(jdouble, JVM_SIGNATURE_DOUBLE, CallDoubleMethod)
|
||||
|
||||
//
|
||||
// Calling static methods
|
||||
//
|
||||
// FIX: if an exception is thrown, va_end is not called.
|
||||
// On i386, va_end is a null macro. Check on PPC to verify the same.
|
||||
void JNFCallStaticVoidMethod(JNIEnv *env, JNFMemberInfo* method, ...) {
|
||||
va_list args;
|
||||
JNF_ASSERT_COND(method->isStatic);
|
||||
va_start(args, method);
|
||||
CALL_STATIC_VOID_METHOD(env, method, CallStaticVoidMethodV, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#define CALL_STATIC_METHOD_IMPLEMENTATION(type, sig, jni_call) \
|
||||
type JNF ## jni_call(JNIEnv *env, JNFMemberInfo* method, ...) { \
|
||||
type result; \
|
||||
va_list args; \
|
||||
JNF_ASSERT_COND(method->isStatic); \
|
||||
va_start(args, method); \
|
||||
CALL_STATIC_METHOD(env, method, result, sig, jni_call ## V, args); \
|
||||
va_end(args); \
|
||||
return result; \
|
||||
}
|
||||
|
||||
CALL_STATIC_METHOD_IMPLEMENTATION(jobject, JVM_SIGNATURE_ENDCLASS, CallStaticObjectMethod)
|
||||
CALL_STATIC_METHOD_IMPLEMENTATION(jboolean, JVM_SIGNATURE_BOOLEAN, CallStaticBooleanMethod)
|
||||
CALL_STATIC_METHOD_IMPLEMENTATION(jbyte, JVM_SIGNATURE_BYTE, CallStaticByteMethod)
|
||||
CALL_STATIC_METHOD_IMPLEMENTATION(jchar, JVM_SIGNATURE_CHAR, CallStaticCharMethod)
|
||||
CALL_STATIC_METHOD_IMPLEMENTATION(jshort, JVM_SIGNATURE_SHORT, CallStaticShortMethod)
|
||||
CALL_STATIC_METHOD_IMPLEMENTATION(jint, JVM_SIGNATURE_INT, CallStaticIntMethod)
|
||||
CALL_STATIC_METHOD_IMPLEMENTATION(jlong, JVM_SIGNATURE_LONG, CallStaticLongMethod)
|
||||
CALL_STATIC_METHOD_IMPLEMENTATION(jfloat, JVM_SIGNATURE_FLOAT, CallStaticFloatMethod)
|
||||
CALL_STATIC_METHOD_IMPLEMENTATION(jdouble, JVM_SIGNATURE_DOUBLE, CallStaticDoubleMethod)
|
||||
|
||||
//
|
||||
// Creating new object instances
|
||||
jobject JNFNewObject(JNIEnv *env, JNFMemberInfo* constructor, ...)
|
||||
{
|
||||
jobject newobj;
|
||||
va_list args;
|
||||
JNF_ASSERT_COND(!constructor->isStatic);
|
||||
va_start(args, constructor);
|
||||
NEW_OBJECT(env, constructor, newobj, args);
|
||||
va_end(args);
|
||||
return newobj;
|
||||
}
|
||||
|
||||
jobjectArray JNFNewObjectArray(JNIEnv *env, JNFClassInfo *clazz, jsize length)
|
||||
{
|
||||
if (clazz->cls == NULL) JNFLookupClass(env, clazz);
|
||||
JNF_ASSERT_COND(clazz->cls);
|
||||
jobjectArray newArray = (*env)->NewObjectArray(env, length, clazz->cls, NULL);
|
||||
JNF_CHECK_AND_RETHROW_EXCEPTION(env);
|
||||
return newArray;
|
||||
}
|
||||
|
||||
#define NEW_PRIMITIVE_ARRAY(primitiveArrayType, methodName) \
|
||||
primitiveArrayType JNF ## methodName(JNIEnv *env, jsize length) { \
|
||||
primitiveArrayType array = (*env)->methodName(env, length); \
|
||||
JNF_CHECK_AND_RETHROW_EXCEPTION(env); \
|
||||
return array; \
|
||||
}
|
||||
|
||||
NEW_PRIMITIVE_ARRAY(jbooleanArray, NewBooleanArray)
|
||||
NEW_PRIMITIVE_ARRAY(jbyteArray, NewByteArray)
|
||||
NEW_PRIMITIVE_ARRAY(jcharArray, NewCharArray)
|
||||
NEW_PRIMITIVE_ARRAY(jshortArray, NewShortArray)
|
||||
NEW_PRIMITIVE_ARRAY(jintArray, NewIntArray)
|
||||
NEW_PRIMITIVE_ARRAY(jlongArray, NewLongArray)
|
||||
NEW_PRIMITIVE_ARRAY(jfloatArray, NewFloatArray)
|
||||
NEW_PRIMITIVE_ARRAY(jdoubleArray, NewDoubleArray)
|
||||
|
||||
|
||||
// Class-related functions
|
||||
|
||||
// A bottleneck for creating global references
|
||||
jobject JNFNewGlobalRef(JNIEnv *env, jobject obj)
|
||||
{
|
||||
if (!obj) return NULL;
|
||||
|
||||
jobject globalRef = (*env)->NewGlobalRef(env, obj);
|
||||
if (!globalRef) JNF_CHECK_AND_RETHROW_EXCEPTION(env);
|
||||
|
||||
// JNF_WARN("Created global ref %#08lx to object:", globalRef);
|
||||
// JNFDumpJavaObject(env, globalRef);
|
||||
return globalRef;
|
||||
}
|
||||
|
||||
// A bottleneck for deleting global references.
|
||||
void JNFDeleteGlobalRef(JNIEnv *env, jobject globalRef)
|
||||
{
|
||||
if (!globalRef) return;
|
||||
// JNF_WARN("Deleting global ref %#08lx to object:", globalRef);
|
||||
// JNFDumpJavaObject(env, globalRef);
|
||||
(*env)->DeleteGlobalRef(env, globalRef);
|
||||
}
|
||||
|
||||
// A bottleneck for creating weak global references
|
||||
jobject JNFNewWeakGlobalRef(JNIEnv *env, jobject obj)
|
||||
{
|
||||
if (!obj) return NULL;
|
||||
|
||||
jobject globalRef = (*env)->NewWeakGlobalRef(env, obj);
|
||||
if (!globalRef) JNF_CHECK_AND_RETHROW_EXCEPTION(env);
|
||||
|
||||
// JNF_WARN("Created global ref %#08lx to object:", globalRef);
|
||||
// JNFDumpJavaObject(env, globalRef);
|
||||
return globalRef;
|
||||
}
|
||||
|
||||
// A bottleneck for deleting weak global references.
|
||||
void JNFDeleteWeakGlobalRef(JNIEnv *env, jobject globalRef)
|
||||
{
|
||||
if (!globalRef) return;
|
||||
// JNF_WARN("Deleting global ref %#08lx to object:", globalRef);
|
||||
// JNFDumpJavaObject(env, globalRef);
|
||||
(*env)->DeleteWeakGlobalRef(env, globalRef);
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*
|
||||
* Simple wrapper classes to hold Java Objects in JNI global references.
|
||||
*
|
||||
* This is used to pass Java objects across thread boundries, often through
|
||||
* -performSelectorOnMainThread invocations. This wrapper properly creates a
|
||||
* new global ref, and clears it on -dealloc or -finalize, attaching to the
|
||||
* current VM, attaching the current thread if necessary, releasing the global
|
||||
* ref, and detaching the thread from the VM if it attached it.
|
||||
*
|
||||
* Destruction of this wrapper is expensive if the jobject has not been
|
||||
* pre-cleared, because it must re-attach to the JVM.
|
||||
*
|
||||
* The JNFWeakJObjectWrapper manages a weak global reference which may become
|
||||
* invalid if the JVM garbage collects the original object.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <JavaNativeFoundation/JNFJNI.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
JNF_EXPORT
|
||||
@interface JNFJObjectWrapper : NSObject
|
||||
|
||||
+ (JNFJObjectWrapper *) wrapperWithJObject:(jobject)jObjectIn withEnv:(JNIEnv *)env;
|
||||
- (id) initWithJObject:(jobject)jObjectIn withEnv:(JNIEnv *)env;
|
||||
- (void) setJObject:(jobject)jObjectIn withEnv:(JNIEnv *)env; // clears any pre-existing global-ref
|
||||
- (jobject) jObjectWithEnv:(JNIEnv *)env; // returns a new local-ref, must be released with DeleteLocalRef
|
||||
|
||||
@property (readonly, nonatomic, assign) jobject jObject;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
JNF_EXPORT
|
||||
@interface JNFWeakJObjectWrapper : JNFJObjectWrapper { }
|
||||
|
||||
+ (JNFWeakJObjectWrapper *) wrapperWithJObject:(jobject)jObjectIn withEnv:(JNIEnv *)env;
|
||||
|
||||
@end
|
||||
|
||||
__END_DECLS
|
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#import "JNFJObjectWrapper.h"
|
||||
|
||||
#import "JNFJNI.h"
|
||||
#import "JNFThread.h"
|
||||
|
||||
@interface JNFJObjectWrapper ()
|
||||
@property (readwrite, nonatomic, assign) jobject jObject;
|
||||
@end
|
||||
|
||||
@implementation JNFJObjectWrapper
|
||||
|
||||
- (jobject) _getWithEnv:(__unused JNIEnv *)env {
|
||||
return self.jObject;
|
||||
}
|
||||
|
||||
- (jobject) _createObj:(jobject)jObjectIn withEnv:(JNIEnv *)env {
|
||||
return JNFNewGlobalRef(env, jObjectIn);
|
||||
}
|
||||
|
||||
- (void) _destroyObj:(jobject)jObjectIn withEnv:(JNIEnv *)env {
|
||||
JNFDeleteGlobalRef(env, jObjectIn);
|
||||
}
|
||||
|
||||
+ (JNFJObjectWrapper *) wrapperWithJObject:(jobject)jObjectIn withEnv:(JNIEnv *)env {
|
||||
return [[[JNFJObjectWrapper alloc] initWithJObject:jObjectIn withEnv:env] autorelease];
|
||||
}
|
||||
|
||||
- (id) initWithJObject:(jobject)jObjectIn withEnv:(JNIEnv *)env {
|
||||
self = [super init];
|
||||
if (!self) return self;
|
||||
|
||||
if (jObjectIn) {
|
||||
self.jObject = [self _createObj:jObjectIn withEnv:env];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (jobject) jObjectWithEnv:(JNIEnv *)env {
|
||||
jobject validObj = [self _getWithEnv:env];
|
||||
if (!validObj) return NULL;
|
||||
|
||||
return (*env)->NewLocalRef(env, validObj);
|
||||
}
|
||||
|
||||
- (void) setJObject:(jobject)jObjectIn withEnv:(JNIEnv *)env {
|
||||
jobject const jobj = self.jObject;
|
||||
if (jobj == jObjectIn) return;
|
||||
|
||||
if (jobj) {
|
||||
[self _destroyObj:jobj withEnv:env];
|
||||
}
|
||||
|
||||
if (jObjectIn) {
|
||||
self.jObject = [self _createObj:jObjectIn withEnv:env];
|
||||
} else {
|
||||
self.jObject = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
- (void) clearJObjectReference {
|
||||
jobject const jobj = self.jObject;
|
||||
if (!jobj) return;
|
||||
|
||||
JNFThreadContext threadContext = JNFThreadDetachImmediately;
|
||||
JNIEnv *env = JNFObtainEnv(&threadContext);
|
||||
if (env == NULL) return; // leak?
|
||||
|
||||
[self _destroyObj:jobj withEnv:env];
|
||||
self.jObject = NULL;
|
||||
|
||||
JNFReleaseEnv(env, &threadContext);
|
||||
}
|
||||
|
||||
- (void) dealloc {
|
||||
[self clearJObjectReference];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation JNFWeakJObjectWrapper
|
||||
|
||||
+ (JNFWeakJObjectWrapper *) wrapperWithJObject:(jobject)jObjectIn withEnv:(JNIEnv *)env {
|
||||
return [[[JNFWeakJObjectWrapper alloc] initWithJObject:jObjectIn withEnv:env] autorelease];
|
||||
}
|
||||
|
||||
- (jobject) _getWithEnv:(JNIEnv *)env {
|
||||
jobject const jobj = self.jObject;
|
||||
|
||||
if ((*env)->IsSameObject(env, jobj, NULL) == JNI_TRUE) {
|
||||
self.jObject = NULL; // object went invalid
|
||||
return NULL;
|
||||
}
|
||||
return jobj;
|
||||
}
|
||||
|
||||
- (jobject) _createObj:(jobject)jObjectIn withEnv:(JNIEnv *)env {
|
||||
return JNFNewWeakGlobalRef(env, jObjectIn);
|
||||
}
|
||||
|
||||
- (void) _destroyObj:(jobject)jObjectIn withEnv:(JNIEnv *)env {
|
||||
JNFDeleteWeakGlobalRef(env, jObjectIn);
|
||||
}
|
||||
|
||||
@end
|
53
apple/JavaNativeFoundation/JavaNativeFoundation/JNFNumber.h
Normal file
53
apple/JavaNativeFoundation/JavaNativeFoundation/JNFNumber.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*
|
||||
* Functions that convert between number container classes.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSValue.h>
|
||||
|
||||
#import <JavaNativeFoundation/JNFJNI.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Converts java.lang.Number to an NSNumber
|
||||
* NOTE: Return value is auto-released, so if you need to hang on to it, you should retain it.
|
||||
*/
|
||||
JNF_EXPORT extern NSNumber *JNFJavaToNSNumber(JNIEnv *env, jobject n);
|
||||
|
||||
/*
|
||||
* Converts an NSNumber to a java.lang.Number
|
||||
* Only returns java.lang.Longs or java.lang.Doubles.
|
||||
* NOTE: This returns a JNI Local Ref. Any code that calls must call DeleteLocalRef with the return value.
|
||||
*/
|
||||
JNF_EXPORT extern jobject JNFNSToJavaNumber(JNIEnv *env, NSNumber *n);
|
||||
|
||||
/*
|
||||
* Converts a java.lang.Boolean constants to the CFBooleanRef constants
|
||||
*/
|
||||
JNF_EXPORT extern CFBooleanRef JNFJavaToCFBoolean(JNIEnv* env, jobject b);
|
||||
|
||||
/*
|
||||
* Converts a CFBooleanRef constants to the java.lang.Boolean constants
|
||||
*/
|
||||
JNF_EXPORT extern jobject JNFCFToJavaBoolean(JNIEnv *env, CFBooleanRef b);
|
||||
|
||||
__END_DECLS
|
90
apple/JavaNativeFoundation/JavaNativeFoundation/JNFNumber.m
Normal file
90
apple/JavaNativeFoundation/JavaNativeFoundation/JNFNumber.m
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#import "JNFNumber.h"
|
||||
#import "JNFJNI.h"
|
||||
|
||||
static JNF_CLASS_CACHE(sjc_Long, "java/lang/Long");
|
||||
static JNF_CLASS_CACHE(sjc_Double, "java/lang/Double");
|
||||
static JNF_CLASS_CACHE(sjc_Boolean, "java/lang/Boolean");
|
||||
|
||||
NSNumber *JNFJavaToNSNumber(JNIEnv* env, jobject n)
|
||||
{
|
||||
if (n == NULL) return nil;
|
||||
|
||||
static JNF_CLASS_CACHE(sjc_Number, "java/lang/Number");
|
||||
static JNF_CLASS_CACHE(sjc_Integer, "java/lang/Integer");
|
||||
static JNF_CLASS_CACHE(sjc_Float, "java/lang/Float");
|
||||
static JNF_CLASS_CACHE(sjc_Byte, "java/lang/Byte");
|
||||
static JNF_CLASS_CACHE(sjc_Short, "java/lang/Short");
|
||||
|
||||
// AWT_THREADING Safe (known object)
|
||||
if (JNFIsInstanceOf(env, n, &sjc_Integer)) {
|
||||
static JNF_MEMBER_CACHE(jm_intValue, sjc_Number, "intValue", "()I");
|
||||
return [NSNumber numberWithInt:JNFCallIntMethod(env, n, jm_intValue)];
|
||||
} else if (JNFIsInstanceOf(env, n, &sjc_Long)) {
|
||||
static JNF_MEMBER_CACHE(jm_longValue, sjc_Number, "longValue", "()J");
|
||||
return [NSNumber numberWithLongLong:JNFCallLongMethod(env, n, jm_longValue)];
|
||||
} else if (JNFIsInstanceOf(env, n, &sjc_Float)) {
|
||||
static JNF_MEMBER_CACHE(jm_floatValue, sjc_Number, "floatValue", "()F");
|
||||
return [NSNumber numberWithFloat:JNFCallFloatMethod(env, n, jm_floatValue)];
|
||||
} else if (JNFIsInstanceOf(env, n, &sjc_Double)) {
|
||||
static JNF_MEMBER_CACHE(jm_doubleValue, sjc_Number, "doubleValue", "()D");
|
||||
return [NSNumber numberWithDouble:JNFCallDoubleMethod(env, n, jm_doubleValue)];
|
||||
} else if (JNFIsInstanceOf(env, n, &sjc_Byte)) {
|
||||
static JNF_MEMBER_CACHE(jm_byteValue, sjc_Number, "byteValue", "()B");
|
||||
return [NSNumber numberWithChar:JNFCallByteMethod(env, n, jm_byteValue)];
|
||||
} else if (JNFIsInstanceOf(env, n, &sjc_Short)) {
|
||||
static JNF_MEMBER_CACHE(jm_shortValue, sjc_Number, "shortValue", "()S");
|
||||
return [NSNumber numberWithShort:JNFCallShortMethod(env, n, jm_shortValue)];
|
||||
}
|
||||
|
||||
return [NSNumber numberWithInt:0];
|
||||
}
|
||||
|
||||
jobject JNFNSToJavaNumber(JNIEnv *env, NSNumber *n)
|
||||
{
|
||||
if (n == nil) return NULL;
|
||||
|
||||
if (CFNumberIsFloatType((CFNumberRef)n)) {
|
||||
static JNF_CTOR_CACHE(jm_Double, sjc_Double, "(D)V");
|
||||
return JNFNewObject(env, jm_Double, [n doubleValue]); // AWT_THREADING Safe (known object)
|
||||
} else {
|
||||
static JNF_CTOR_CACHE(jm_Long, sjc_Long, "(J)V");
|
||||
return JNFNewObject(env, jm_Long, [n longLongValue]); // AWT_THREADING Safe (known object)
|
||||
}
|
||||
}
|
||||
|
||||
CFBooleanRef JNFJavaToCFBoolean(JNIEnv* env, jobject b)
|
||||
{
|
||||
if (b == NULL) return NULL;
|
||||
if (!JNFIsInstanceOf(env, b, &sjc_Boolean)) return NULL;
|
||||
static JNF_MEMBER_CACHE(jm_booleanValue, sjc_Boolean, "booleanValue", "()Z");
|
||||
return JNFCallBooleanMethod(env, b, jm_booleanValue) ? kCFBooleanTrue : kCFBooleanTrue;
|
||||
}
|
||||
|
||||
jobject JNFCFToJavaBoolean(JNIEnv *env, CFBooleanRef b)
|
||||
{
|
||||
if (b == NULL) return NULL;
|
||||
static JNF_STATIC_MEMBER_CACHE(js_TRUE, sjc_Boolean, "TRUE", "java/lang/Boolean");
|
||||
static JNF_STATIC_MEMBER_CACHE(js_FALSE, sjc_Boolean, "FALSE", "java/lang/Boolean");
|
||||
return JNFGetStaticObjectField(env, (b == kCFBooleanTrue) ? js_TRUE : js_FALSE);
|
||||
}
|
45
apple/JavaNativeFoundation/JavaNativeFoundation/JNFObject.h
Normal file
45
apple/JavaNativeFoundation/JavaNativeFoundation/JNFObject.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*
|
||||
* Functions that access some of the base functionality of java.lang.Object.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import <JavaNativeFoundation/JNFJNI.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Returns Object.equals() for the two items
|
||||
*/
|
||||
JNF_EXPORT extern BOOL JNFObjectEquals(JNIEnv* env, jobject a, jobject b);
|
||||
|
||||
/*
|
||||
* Returns Object.toString() as an NSString
|
||||
*/
|
||||
JNF_EXPORT extern NSString *JNFObjectToString(JNIEnv *env, jobject obj);
|
||||
|
||||
/*
|
||||
* Returns Object.getClass().toString() as an NSString. Useful in gdb.
|
||||
*/
|
||||
JNF_EXPORT extern NSString *JNFObjectClassName(JNIEnv* env, jobject obj);
|
||||
|
||||
__END_DECLS
|
56
apple/JavaNativeFoundation/JavaNativeFoundation/JNFObject.m
Normal file
56
apple/JavaNativeFoundation/JavaNativeFoundation/JNFObject.m
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#import "JNFObject.h"
|
||||
|
||||
#import "JNFJNI.h"
|
||||
#import "JNFString.h"
|
||||
|
||||
static JNF_CLASS_CACHE(sjc_Object, "java/lang/Object");
|
||||
|
||||
BOOL JNFObjectEquals(JNIEnv* env, jobject a, jobject b)
|
||||
{
|
||||
if ((a == NULL) && (b == NULL)) return YES;
|
||||
if ((a == NULL) || (b == NULL)) return NO;
|
||||
|
||||
static JNF_MEMBER_CACHE(jm_equals, sjc_Object, "equals", "(Ljava/lang/Object;)Z");
|
||||
return (BOOL)JNFCallBooleanMethod(env, a, jm_equals, b); // AWT_THREADING Safe (!appKit)
|
||||
}
|
||||
|
||||
NSString *JNFObjectToString(JNIEnv *env, jobject obj)
|
||||
{
|
||||
static JNF_MEMBER_CACHE(jm_toString, sjc_Object, "toString", "()Ljava/lang/String;");
|
||||
jobject name = JNFCallObjectMethod(env, obj, jm_toString); // AWT_THREADING Safe (known object)
|
||||
|
||||
id result = JNFJavaToNSString(env, name);
|
||||
(*env)->DeleteLocalRef(env, name);
|
||||
return result;
|
||||
}
|
||||
|
||||
NSString *JNFObjectClassName(JNIEnv* env, jobject obj)
|
||||
{
|
||||
static JNF_MEMBER_CACHE(jm_getClass, sjc_Object, "getClass", "()Ljava/lang/Class;");
|
||||
|
||||
jobject clz = JNFCallObjectMethod(env, obj, jm_getClass); // AWT_THREADING Safe (known object)
|
||||
NSString *result = JNFObjectToString(env, clz);
|
||||
(*env)->DeleteLocalRef(env, clz);
|
||||
return result;
|
||||
}
|
44
apple/JavaNativeFoundation/JavaNativeFoundation/JNFPath.h
Normal file
44
apple/JavaNativeFoundation/JavaNativeFoundation/JNFPath.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*
|
||||
* Functions that create strings that are in the proper format for holding
|
||||
* paths in Java and native.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import <JavaNativeFoundation/JNFJNI.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Returns a jstring in precomposed UTF16 format that is compatable with Java's
|
||||
* expectation of the UTF16 format for strings to be displayed.
|
||||
*/
|
||||
JNF_EXPORT extern jstring JNFNormalizedJavaStringForPath(JNIEnv *env, NSString *path);
|
||||
|
||||
/*
|
||||
* Returns an NSString in decomposed UTF16 format that is compatable with HFS's
|
||||
* expectation of the UTF16 format for file system paths.
|
||||
* NOTE: this NSString is autoreleased.
|
||||
*/
|
||||
JNF_EXPORT extern NSString *JNFNormalizedNSStringForPath(JNIEnv *env, jstring path);
|
||||
|
||||
__END_DECLS
|
49
apple/JavaNativeFoundation/JavaNativeFoundation/JNFPath.m
Normal file
49
apple/JavaNativeFoundation/JavaNativeFoundation/JNFPath.m
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#import "JNFPath.h"
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#import "JNFString.h"
|
||||
|
||||
jstring JNFNormalizedJavaStringForPath(JNIEnv *env, NSString *inString)
|
||||
{
|
||||
if (inString == nil) return NULL;
|
||||
|
||||
CFMutableStringRef mutableDisplayName = CFStringCreateMutableCopy(NULL, 0, (CFStringRef)inString);
|
||||
CFStringNormalize(mutableDisplayName, kCFStringNormalizationFormC);
|
||||
jstring returnValue = JNFNSToJavaString(env, (NSString *)mutableDisplayName);
|
||||
CFRelease(mutableDisplayName);
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
NSString *JNFNormalizedNSStringForPath(JNIEnv *env, jstring javaString)
|
||||
{
|
||||
if (javaString == NULL) return nil;
|
||||
|
||||
// We were given a filename, so convert it to a compatible representation for the file system.
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
NSString *fileName = JNFJavaToNSString(env, javaString);
|
||||
const char *compatibleFilename = [fm fileSystemRepresentationWithPath:fileName];
|
||||
return [fm stringWithFileSystemRepresentation:compatibleFilename length:strlen(compatibleFilename)];
|
||||
}
|
42
apple/JavaNativeFoundation/JavaNativeFoundation/JNFRunLoop.h
Normal file
42
apple/JavaNativeFoundation/JavaNativeFoundation/JNFRunLoop.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*
|
||||
* Used to perform selectors and blocks in the Java runloop mode.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <JavaNativeFoundation/JNFJNI.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
JNF_EXPORT extern NSString *JNFRunLoopDidStartNotification;
|
||||
|
||||
JNF_EXPORT
|
||||
@interface JNFRunLoop : NSObject { }
|
||||
|
||||
+ (NSString *)javaRunLoopMode;
|
||||
+ (void)performOnMainThread:(SEL)aSelector on:(id)target withObject:(id)arg waitUntilDone:(BOOL)wait;
|
||||
#if __BLOCKS__
|
||||
+ (void)performOnMainThreadWaiting:(BOOL)waitUntilDone withBlock:(void (^)(void))block;
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
__END_DECLS
|
69
apple/JavaNativeFoundation/JavaNativeFoundation/JNFRunLoop.m
Normal file
69
apple/JavaNativeFoundation/JavaNativeFoundation/JNFRunLoop.m
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#import "JNFRunLoop.h"
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
|
||||
NSString *JNFRunLoopDidStartNotification = @"JNFRunLoopDidStartNotification";
|
||||
|
||||
static NSString *AWTRunLoopMode = @"AWTRunLoopMode";
|
||||
static NSArray *sPerformModes = nil;
|
||||
|
||||
@implementation JNFRunLoop
|
||||
|
||||
+ (void)initialize {
|
||||
if (sPerformModes) return;
|
||||
sPerformModes = [[NSArray alloc] initWithObjects:NSDefaultRunLoopMode, NSModalPanelRunLoopMode, NSEventTrackingRunLoopMode, AWTRunLoopMode, nil];
|
||||
}
|
||||
|
||||
+ (NSString *)javaRunLoopMode {
|
||||
return AWTRunLoopMode;
|
||||
}
|
||||
|
||||
+ (void)performOnMainThread:(SEL)aSelector on:(id)target withObject:(id)arg waitUntilDone:(BOOL)waitUntilDone {
|
||||
[target performSelectorOnMainThread:aSelector withObject:arg waitUntilDone:waitUntilDone modes:sPerformModes];
|
||||
}
|
||||
|
||||
#if __BLOCKS__
|
||||
|
||||
+ (void)_performDirectBlock:(void (^)(void))block {
|
||||
block();
|
||||
}
|
||||
|
||||
+ (void)_performCopiedBlock:(void (^)(void))newBlock {
|
||||
newBlock();
|
||||
Block_release(newBlock);
|
||||
}
|
||||
|
||||
+ (void)performOnMainThreadWaiting:(BOOL)waitUntilDone withBlock:(void (^)(void))block {
|
||||
if (waitUntilDone) {
|
||||
[self performOnMainThread:@selector(_performDirectBlock:) on:self withObject:block waitUntilDone:YES];
|
||||
} else {
|
||||
void (^newBlock)(void) = Block_copy(block);
|
||||
[self performOnMainThread:@selector(_performCopiedBlock:) on:self withObject:newBlock waitUntilDone:NO];
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@end
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*
|
||||
* Creates NSInvocations which wrap java.lang.Runnables.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <JavaNativeFoundation/JNFJNI.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
JNF_EXPORT
|
||||
@interface JNFRunnable : NSObject { }
|
||||
+ (NSInvocation *) invocationWithRunnable:(jobject)runnable withEnv:(JNIEnv *)env;
|
||||
#if __BLOCKS__
|
||||
+ (void(^)(void)) blockWithRunnable:(jobject)runnable withEnv:(JNIEnv *)env;
|
||||
#endif
|
||||
@end
|
||||
|
||||
__END_DECLS
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#import "JNFRunnable.h"
|
||||
#import "JNFThread.h"
|
||||
#import "JNFJObjectWrapper.h"
|
||||
|
||||
|
||||
static JNF_CLASS_CACHE(jc_Runnable, "java/lang/Runnable");
|
||||
static JNF_MEMBER_CACHE(jm_run, jc_Runnable, "run", "()V");
|
||||
|
||||
@interface JNFRunnableWrapper : JNFJObjectWrapper { }
|
||||
- (void) invokeRunnable;
|
||||
@end
|
||||
|
||||
@implementation JNFRunnableWrapper
|
||||
|
||||
- (void) invokeRunnable {
|
||||
JNFThreadContext ctx = JNFThreadDetachOnThreadDeath | JNFThreadSetSystemClassLoaderOnAttach | JNFThreadAttachAsDaemon;
|
||||
JNIEnv *env = JNFObtainEnv(&ctx);
|
||||
JNFCallVoidMethod(env, [self jObjectWithEnv:env], jm_run);
|
||||
JNFReleaseEnv(env, &ctx);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation JNFRunnable
|
||||
|
||||
+ (NSInvocation *) invocationWithRunnable:(jobject)runnable withEnv:(JNIEnv *)env {
|
||||
SEL sel = @selector(invokeRunnable);
|
||||
NSMethodSignature *sig = [JNFRunnableWrapper instanceMethodSignatureForSelector:sel];
|
||||
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig];
|
||||
[invocation retainArguments];
|
||||
[invocation setSelector:sel];
|
||||
|
||||
JNFRunnableWrapper *runnableWrapper = [[JNFRunnableWrapper alloc] initWithJObject:runnable withEnv:env];
|
||||
[invocation setTarget:runnableWrapper];
|
||||
[runnableWrapper release];
|
||||
|
||||
return invocation;
|
||||
}
|
||||
|
||||
#if __BLOCKS__
|
||||
+ (void(^)(void)) blockWithRunnable:(jobject)runnable withEnv:(JNIEnv *)env {
|
||||
JNFJObjectWrapper *runnableWrapper = [JNFJObjectWrapper wrapperWithJObject:runnable withEnv:env];
|
||||
|
||||
return [[^() {
|
||||
JNFThreadContext ctx = JNFThreadDetachOnThreadDeath | JNFThreadSetSystemClassLoaderOnAttach | JNFThreadAttachAsDaemon;
|
||||
JNIEnv *_block_local_env = JNFObtainEnv(&ctx);
|
||||
JNFCallVoidMethod(env, [runnableWrapper jObjectWithEnv:_block_local_env], jm_run);
|
||||
JNFReleaseEnv(_block_local_env, &ctx);
|
||||
} copy] autorelease];
|
||||
}
|
||||
#endif
|
||||
|
||||
@end
|
60
apple/JavaNativeFoundation/JavaNativeFoundation/JNFString.h
Normal file
60
apple/JavaNativeFoundation/JavaNativeFoundation/JNFString.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*
|
||||
* Functions that create NSStrings, UTF16 unichars, or UTF8 chars from java.lang.Strings
|
||||
*/
|
||||
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import <JavaNativeFoundation/JNFJNI.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
// Returns an NSString given a java.lang.String object
|
||||
// NOTE: Return value is auto-released, so if you need to hang on to it, you should retain it.
|
||||
JNF_EXPORT extern NSString *JNFJavaToNSString(JNIEnv *env, jstring javaString);
|
||||
|
||||
// Returns a java.lang.String object as a JNI local ref.
|
||||
// NOTE: This returns a JNI Local Ref. Any code that calls this should call DeleteLocalRef with the return value.
|
||||
JNF_EXPORT extern jstring JNFNSToJavaString(JNIEnv *env, NSString *nsString);
|
||||
|
||||
/*
|
||||
* Gets UTF16 unichars from a Java string, and checks for errors and raises a JNFException if
|
||||
* the unichars cannot be obtained from Java.
|
||||
*/
|
||||
JNF_EXPORT extern const unichar *JNFGetStringUTF16UniChars(JNIEnv *env, jstring javaString);
|
||||
|
||||
/*
|
||||
* Releases the unichars obtained from JNFGetStringUTF16UniChars()
|
||||
*/
|
||||
JNF_EXPORT extern void JNFReleaseStringUTF16UniChars(JNIEnv *env, jstring javaString, const unichar *unichars);
|
||||
|
||||
/*
|
||||
* Gets UTF8 chars from a Java string, and checks for errors and raises a JNFException if
|
||||
* the chars cannot be obtained from Java.
|
||||
*/
|
||||
JNF_EXPORT extern const char *JNFGetStringUTF8Chars(JNIEnv *env, jstring javaString);
|
||||
|
||||
/*
|
||||
* Releases the chars obtained from JNFGetStringUTF8Chars()
|
||||
*/
|
||||
JNF_EXPORT extern void JNFReleaseStringUTF8Chars(JNIEnv *env, jstring javaString, const char *chars);
|
||||
|
||||
__END_DECLS
|
100
apple/JavaNativeFoundation/JavaNativeFoundation/JNFString.m
Normal file
100
apple/JavaNativeFoundation/JavaNativeFoundation/JNFString.m
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#import "JNFString.h"
|
||||
|
||||
#import "JNFJNI.h"
|
||||
#import "JNFAssert.h"
|
||||
#import "debug.h"
|
||||
|
||||
#define STACK_BUFFER_SIZE 64
|
||||
|
||||
/*
|
||||
* Utility function to convert java String to NSString. We don't go through intermediate cString
|
||||
* representation, since we are trying to preserve unicode characters from Java to NSString.
|
||||
*/
|
||||
NSString *JNFJavaToNSString(JNIEnv *env, jstring javaString)
|
||||
{
|
||||
// We try very hard to only allocate and memcopy once.
|
||||
if (javaString == NULL) return nil;
|
||||
|
||||
jsize length = (*env)->GetStringLength(env, javaString);
|
||||
unichar *buffer = (unichar *)calloc((size_t)length, sizeof(unichar));
|
||||
(*env)->GetStringRegion(env, javaString, 0, length, buffer);
|
||||
NSString *str = (NSString *)CFStringCreateWithCharactersNoCopy(NULL, buffer, length, kCFAllocatorMalloc);
|
||||
// NSLog(@"%@", str);
|
||||
return [(NSString *)CFMakeCollectable(str) autorelease];
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility function to convert NSString to Java string. We don't go through intermediate cString
|
||||
* representation, since we are trying to preserve unicode characters in translation.
|
||||
*/
|
||||
jstring JNFNSToJavaString(JNIEnv *env, NSString *nsString)
|
||||
{
|
||||
jstring res = nil;
|
||||
if (nsString == nil) return NULL;
|
||||
|
||||
unsigned long length = [nsString length];
|
||||
unichar *buffer;
|
||||
unichar stackBuffer[STACK_BUFFER_SIZE];
|
||||
if (length > STACK_BUFFER_SIZE) {
|
||||
buffer = (unichar *)calloc(length, sizeof(unichar));
|
||||
} else {
|
||||
buffer = stackBuffer;
|
||||
}
|
||||
|
||||
JNF_ASSERT_COND(buffer != NULL);
|
||||
[nsString getCharacters:buffer];
|
||||
res = (*env)->NewString(env, buffer, (jsize)length);
|
||||
if (buffer != stackBuffer) free(buffer);
|
||||
return res;
|
||||
}
|
||||
|
||||
const unichar *JNFGetStringUTF16UniChars(JNIEnv *env, jstring javaString)
|
||||
{
|
||||
const jchar *unichars = NULL;
|
||||
JNF_ASSERT_COND(javaString != NULL);
|
||||
unichars = (*env)->GetStringChars(env, javaString, NULL);
|
||||
if (unichars == NULL) [JNFException raise:env as:kNullPointerException reason:"unable to obtain characters from GetStringChars"];
|
||||
return (const unichar *)unichars;
|
||||
}
|
||||
|
||||
void JNFReleaseStringUTF16UniChars(JNIEnv *env, jstring javaString, const unichar *unichars)
|
||||
{
|
||||
JNF_ASSERT_COND(unichars != NULL);
|
||||
(*env)->ReleaseStringChars(env, javaString, (const jchar *)unichars);
|
||||
}
|
||||
|
||||
const char *JNFGetStringUTF8Chars(JNIEnv *env, jstring javaString)
|
||||
{
|
||||
const char *chars = NULL;
|
||||
JNF_ASSERT_COND(javaString != NULL);
|
||||
chars = (*env)->GetStringUTFChars(env, javaString, NULL);
|
||||
if (chars == NULL) [JNFException raise:env as:kNullPointerException reason:"unable to obtain characters from GetStringUTFChars"];
|
||||
return chars;
|
||||
}
|
||||
|
||||
void JNFReleaseStringUTF8Chars(JNIEnv *env, jstring javaString, const char *chars)
|
||||
{
|
||||
JNF_ASSERT_COND(chars != NULL);
|
||||
(*env)->ReleaseStringUTFChars(env, javaString, (const char *)chars);
|
||||
}
|
69
apple/JavaNativeFoundation/JavaNativeFoundation/JNFThread.h
Normal file
69
apple/JavaNativeFoundation/JavaNativeFoundation/JNFThread.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*
|
||||
* Functions to help obtain a JNIEnv pointer in places where one cannot be passed
|
||||
* though (callbacks, catagory functions, etc). Use sparingly.
|
||||
*/
|
||||
|
||||
#import <os/availability.h>
|
||||
#import <JavaNativeFoundation/JNFJNI.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
// Options only apply if thread was not already attached to the JVM.
|
||||
enum {
|
||||
JNFThreadDetachImmediately = (1 << 1),
|
||||
JNFThreadDetachOnThreadDeath = (1 << 2),
|
||||
JNFThreadSetSystemClassLoaderOnAttach = (1 << 3),
|
||||
JNFThreadAttachAsDaemon = (1 << 4)
|
||||
};
|
||||
|
||||
typedef jlong JNFThreadContext;
|
||||
|
||||
|
||||
/*
|
||||
* Attaches the current thread to the Java VM if needed, and obtains a JNI environment
|
||||
* to interact with the VM. Use a provided JNIEnv pointer for your current thread
|
||||
* whenever possible, since this method is particularly expensive to the Java VM if
|
||||
* used repeatedly.
|
||||
*
|
||||
* Provide a pointer to a JNFThreadContext to pass to JNFReleaseEnv().
|
||||
*/
|
||||
JNF_EXPORT extern JNIEnv *JNFObtainEnv(JNFThreadContext *context) API_DEPRECATED("This functionality is no longer supported and may stop working in a future version of macOS.", macos(10.10, 10.16));
|
||||
|
||||
/*
|
||||
* Release the JNIEnv for this thread, and detaches the current thread from the VM if
|
||||
* it was not already attached.
|
||||
*/
|
||||
JNF_EXPORT extern void JNFReleaseEnv(JNIEnv *env, JNFThreadContext *context) API_DEPRECATED("This functionality is no longer supported and may stop working in a future version of macOS.", macos(10.10, 10.16));
|
||||
|
||||
|
||||
#if __BLOCKS__
|
||||
|
||||
/*
|
||||
* Performs the same attach/detach as JNFObtainEnv() and JNFReleaseEnv(), but executes a
|
||||
* block that accepts the obtained JNIEnv.
|
||||
*/
|
||||
typedef void (^JNIEnvBlock)(JNIEnv *);
|
||||
JNF_EXPORT extern void JNFPerformEnvBlock(JNFThreadContext context, JNIEnvBlock block) API_DEPRECATED("This functionality is no longer supported and may stop working in a future version of macOS.", macos(10.10, 10.16));
|
||||
|
||||
#endif
|
||||
|
||||
__END_DECLS
|
165
apple/JavaNativeFoundation/JavaNativeFoundation/JNFThread.m
Normal file
165
apple/JavaNativeFoundation/JavaNativeFoundation/JNFThread.m
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#import "JNFThread.h"
|
||||
|
||||
#import <dlfcn.h>
|
||||
#import <pthread.h>
|
||||
|
||||
static JavaVM *GetGlobalVM() { // obtains a connection to the current VM
|
||||
static JavaVM *globalVM;
|
||||
|
||||
if (globalVM != NULL) {
|
||||
return globalVM;
|
||||
}
|
||||
|
||||
void *jvmHandle = dlopen("@rpath/libjvm.dylib", RTLD_NOW);
|
||||
if (!jvmHandle) {
|
||||
NSLog(@"JavaNativeFoundation: %s: Failed to locate @rpath/libjvm.dylib for JNI_GetCreatedJavaVMs(). A JVM must be loaded before calling this function.", __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jint (*_JNI_GetCreatedJavaVMs)(JavaVM **, jsize, jsize *) = dlsym(jvmHandle, "JNI_GetCreatedJavaVMs");
|
||||
if (!_JNI_GetCreatedJavaVMs) {
|
||||
NSLog(@"JavaNativeFoundation: %s: Failed to locate JNI_GetCreatedJavaVMs symbol in @rpath/libjvm.dylib", __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JavaVM *vmArray;
|
||||
jsize numVMs = 0;
|
||||
if (_JNI_GetCreatedJavaVMs(&vmArray, 1, &numVMs) == 0 && numVMs >= 1) {
|
||||
globalVM = &vmArray[0];
|
||||
}
|
||||
|
||||
if (globalVM == NULL) {
|
||||
NSLog(@"JavaNativeFoundation: %s: JNI_GetCreatedJavaVMs() failed to get any VM.", __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return globalVM;
|
||||
}
|
||||
|
||||
// private marker to indicate if we need to detach on release
|
||||
enum {
|
||||
JNFThreadWillDetachOnRelease = (1 << 12)
|
||||
};
|
||||
|
||||
static void setSystemClassLoader(JNIEnv *env) {
|
||||
// setup the context class loader for this new thread coming into the JVM
|
||||
JNF_CLASS_CACHE(jc_Thread, "java/lang/Thread");
|
||||
JNF_STATIC_MEMBER_CACHE(jm_currentThread, jc_Thread, "currentThread", "()Ljava/lang/Thread;");
|
||||
jobject currentThread = JNFCallStaticObjectMethod(env, jm_currentThread);
|
||||
|
||||
JNF_CLASS_CACHE(jc_ClassLoader, "java/lang/ClassLoader");
|
||||
JNF_STATIC_MEMBER_CACHE(jm_getSystemClassLoader, jc_ClassLoader, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
|
||||
jobject systemClassLoader = JNFCallStaticObjectMethod(env, jm_getSystemClassLoader);
|
||||
|
||||
JNF_MEMBER_CACHE(jm_setContextClassLoader, jc_Thread, "setContextClassLoader", "(Ljava/lang/ClassLoader;)V");
|
||||
JNFCallVoidMethod(env, currentThread, jm_setContextClassLoader, systemClassLoader);
|
||||
}
|
||||
|
||||
static JNFThreadContext GetEnvUsingJVM(JavaVM *jvm, void **envPtr, BOOL shouldDetachOnRelease, BOOL setClassLoader, BOOL attachAsDaemon) {
|
||||
jint status = (*jvm)->GetEnv(jvm, envPtr, JNI_VERSION_1_4);
|
||||
if (status == JNI_OK) {
|
||||
// common path
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (status != JNI_EDETACHED) {
|
||||
// can't use JNF_ASSERT macros, since we don't really know if we have an env :(
|
||||
NSLog(@"JavaNativeFoundation: JNFObtainEnv unable to obtain JNIEnv (%d)", (int)status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// we need to attach
|
||||
if (attachAsDaemon) {
|
||||
status = (*jvm)->AttachCurrentThreadAsDaemon(jvm, envPtr, NULL);
|
||||
} else {
|
||||
status = (*jvm)->AttachCurrentThread(jvm, envPtr, NULL);
|
||||
}
|
||||
|
||||
if (status != JNI_OK) {
|
||||
// failed - need to clear our mark to detach, if present
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (setClassLoader) {
|
||||
setSystemClassLoader((JNIEnv *)(*envPtr));
|
||||
}
|
||||
|
||||
// by default, we detach at pthread death, but if requested, we will detach on env-release
|
||||
if (shouldDetachOnRelease) {
|
||||
return JNFThreadWillDetachOnRelease;
|
||||
}
|
||||
|
||||
// we don't do anything in this case, because HotSpot on Mac OS X will detach for us.
|
||||
// <rdar://problem/4466820> Can we install a pthread_atexit handler to detach if we haven't already?
|
||||
return 0;
|
||||
}
|
||||
|
||||
// public call to obtain an env, and attach the current thread to the VM in needed
|
||||
JNIEnv *JNFObtainEnv(JNFThreadContext *context) {
|
||||
JavaVM *jvm = GetGlobalVM();
|
||||
if (!jvm) {
|
||||
*context = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JNFThreadContext ctx = *context;
|
||||
BOOL shouldDetachOnRelease = (0 != (ctx & JNFThreadDetachImmediately));
|
||||
BOOL setClassLoader = (0 != (ctx & JNFThreadSetSystemClassLoaderOnAttach));
|
||||
BOOL attachAsDaemon = (0 != (ctx & JNFThreadAttachAsDaemon));
|
||||
|
||||
void *env = NULL;
|
||||
*context = GetEnvUsingJVM(jvm, &env, shouldDetachOnRelease, setClassLoader, attachAsDaemon);
|
||||
return (JNIEnv *)env;
|
||||
}
|
||||
|
||||
void JNFReleaseEnv(__unused JNIEnv *env, JNFThreadContext *context) {
|
||||
if ((*context & JNFThreadWillDetachOnRelease) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
JavaVM *jvm = GetGlobalVM();
|
||||
if (!jvm) return;
|
||||
|
||||
jint status = (*jvm)->DetachCurrentThread(jvm);
|
||||
if (status != JNI_OK) {
|
||||
// can't use JNF_ASSERT macros, since we don't really know if we have an env :(
|
||||
NSLog(@"JavaNativeFoundation: %s: unable to release JNIEnv (%d)", __FUNCTION__, (int)status);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if __BLOCKS__
|
||||
|
||||
JNF_EXPORT extern void JNFPerformEnvBlock(JNFThreadContext context, JNIEnvBlock block) {
|
||||
JNIEnv *env = JNFObtainEnv(&context);
|
||||
if (env == NULL) [NSException raise:@"Unable to obtain JNIEnv" format:@"Unable to obtain JNIEnv for context: %p", (void *)context];
|
||||
|
||||
@try {
|
||||
block(env);
|
||||
} @finally {
|
||||
JNFReleaseEnv(env, &context);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*
|
||||
* Type Coercion system that translates between Java VM objects and Objective-C Foundation objects.
|
||||
*
|
||||
* JNFTypeCoercions are registered into JNFTypeCoercers, which can be chained to other
|
||||
* JNFTypeCoercers using -deriveCoercer or -initWithParent. If the set of Coercions
|
||||
* in a Coercer aren't capable of converting an object, the Coercer will delegate up to
|
||||
* it's parent.
|
||||
*
|
||||
* Coercions are registered by Objective-C class and Java class name. If an object is an
|
||||
* instance of the registered class name, the coercion will be invoked. Default
|
||||
* implementations for several basic types are provided by JNFDefaultCoercions, and can
|
||||
* be installed in any order. More specific coercions should be placed farther down
|
||||
* a coercer chain, and more generic coercions should be placed higher. A Coercer can be
|
||||
* initialized with a basic Coercion that may want to handle "all cases", like calling
|
||||
* Object.toString() and -describe on all objects passed to it.
|
||||
*
|
||||
* Coercions are passed the Coercion-object that was originally invoked on the
|
||||
* target object. This permits the lowest level Coercion to be used for subsequent
|
||||
* object translations for composite objects. The provided List, Map, and Set Coercions
|
||||
* only handle object hierarchies, and will infinitely recurse if confronted with a
|
||||
* cycle in the object graph.
|
||||
*
|
||||
* Null and nil are both perfectly valid return types for Coercions, and do not indicate
|
||||
* a failure to coerce an object. Coercers are not thread safe.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <JavaNativeFoundation/JNFJNI.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
@class JNFTypeCoercion;
|
||||
|
||||
JNF_EXPORT
|
||||
@protocol JNFTypeCoercion
|
||||
|
||||
- (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer;
|
||||
- (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
JNF_EXPORT
|
||||
@interface JNFTypeCoercer : NSObject <JNFTypeCoercion>
|
||||
|
||||
- (id) init;
|
||||
- (id) initWithParent:(NSObject <JNFTypeCoercion> *)parentIn;
|
||||
- (JNFTypeCoercer *) deriveCoercer;
|
||||
- (void) addCoercion:(NSObject <JNFTypeCoercion> *)coercion forNSClass:(Class)nsClass javaClass:(NSString *)javaClassName;
|
||||
|
||||
- (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env;
|
||||
- (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
JNF_EXPORT
|
||||
@interface JNFDefaultCoercions : NSObject { }
|
||||
|
||||
+ (void) addStringCoercionTo:(JNFTypeCoercer *)coercer;
|
||||
+ (void) addNumberCoercionTo:(JNFTypeCoercer *)coercer;
|
||||
+ (void) addDateCoercionTo:(JNFTypeCoercer *)coercer;
|
||||
+ (void) addListCoercionTo:(JNFTypeCoercer *)coercer;
|
||||
+ (void) addMapCoercionTo:(JNFTypeCoercer *)coercer;
|
||||
+ (void) addSetCoercionTo:(JNFTypeCoercer *)coercer;
|
||||
|
||||
+ (JNFTypeCoercer *) defaultCoercer; // returns autoreleased copy, not shared, not thread safe
|
||||
|
||||
@end
|
||||
|
||||
__END_DECLS
|
@ -0,0 +1,471 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#import "JNFTypeCoercion.h"
|
||||
|
||||
#import "JNFJNI.h"
|
||||
#import "JNFObject.h"
|
||||
#import "JNFString.h"
|
||||
#import "JNFNumber.h"
|
||||
#import "JNFDate.h"
|
||||
#import "JNFJObjectWrapper.h"
|
||||
|
||||
// #define DEBUG 1
|
||||
|
||||
@interface JNFInternalJavaClassToCoersionHolder : JNFJObjectWrapper
|
||||
|
||||
- (id) initWithCoercion:(NSObject <JNFTypeCoercion> *)coercionIn className:(NSString *)className withEnv:(JNIEnv *)env;
|
||||
- (BOOL) isClassFor:(jobject)obj withEnv:(JNIEnv *)env;
|
||||
- (NSObject <JNFTypeCoercion> *)coercion;
|
||||
|
||||
@property (nonatomic, readwrite, strong) NSObject <JNFTypeCoercion> *coercion;
|
||||
|
||||
@end
|
||||
|
||||
@interface JNFTypeCoercer ()
|
||||
|
||||
@property (nonatomic, readwrite, strong) NSObject <JNFTypeCoercion> *parent;
|
||||
@property (nonatomic, readwrite, strong) NSMutableDictionary *nsClassToCoercion;
|
||||
@property (nonatomic, readwrite, strong) NSMutableDictionary *javaClassNameToCoercion;
|
||||
@property (nonatomic, readwrite, strong) NSArray *javaClassToCoercion;
|
||||
|
||||
@end
|
||||
|
||||
@implementation JNFTypeCoercer
|
||||
|
||||
- (id) init {
|
||||
return [self initWithParent:nil];
|
||||
}
|
||||
|
||||
- (id) initWithParent:(NSObject <JNFTypeCoercion> *)parentIn {
|
||||
self = [super init];
|
||||
if (!self) return self;
|
||||
|
||||
self.parent = parentIn;
|
||||
self.nsClassToCoercion = [NSMutableDictionary dictionary];
|
||||
self.javaClassNameToCoercion = [NSMutableDictionary dictionary];
|
||||
self.javaClassToCoercion = nil;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc {
|
||||
self.parent = nil;
|
||||
self.nsClassToCoercion = nil;
|
||||
self.javaClassNameToCoercion = nil;
|
||||
self.javaClassToCoercion = nil;
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (JNFTypeCoercer *) deriveCoercer {
|
||||
return [[[JNFTypeCoercer alloc] initWithParent:self] autorelease];
|
||||
}
|
||||
|
||||
- (void) addCoercion:(NSObject <JNFTypeCoercion> *)coercion forNSClass:(Class)nsClass javaClass:(NSString *)javaClassName {
|
||||
if (nsClass) [self.nsClassToCoercion setObject:coercion forKey:(id)nsClass];
|
||||
if (javaClassName) [self.javaClassNameToCoercion setObject:coercion forKey:javaClassName];
|
||||
self.javaClassToCoercion = nil; // invalidate Java Class cache
|
||||
}
|
||||
|
||||
- (NSObject <JNFTypeCoercion> *) findCoercerForNSObject:(id)obj {
|
||||
NSMutableDictionary * const nsClassToCoercion = self.nsClassToCoercion;
|
||||
NSObject <JNFTypeCoercion> *coercer = [nsClassToCoercion objectForKey:[obj class]];
|
||||
if (coercer) return coercer;
|
||||
|
||||
NSEnumerator *classes = [nsClassToCoercion keyEnumerator];
|
||||
Class clazzIter;
|
||||
while ((clazzIter = [classes nextObject]) != nil) {
|
||||
if ([obj isKindOfClass:clazzIter]) {
|
||||
return [nsClassToCoercion objectForKey:clazzIter];
|
||||
}
|
||||
}
|
||||
|
||||
return self.parent;
|
||||
}
|
||||
|
||||
- (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer {
|
||||
return [[self findCoercerForNSObject:obj] coerceNSObject:obj withEnv:env usingCoercer:coercer];
|
||||
}
|
||||
|
||||
- (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env {
|
||||
return [self coerceNSObject:obj withEnv:env usingCoercer:(JNFTypeCoercion *)self];
|
||||
}
|
||||
|
||||
|
||||
- (NSArray *) javaClassCacheUsingEnv:(JNIEnv *)env {
|
||||
NSArray * const javaClassToCoercion = self.javaClassToCoercion;
|
||||
if (javaClassToCoercion) return javaClassToCoercion;
|
||||
|
||||
NSMutableArray *array = [[NSMutableArray alloc] init];
|
||||
|
||||
NSMutableDictionary * const javaClassNameToCoercion = self.javaClassNameToCoercion;
|
||||
NSEnumerator *classNames = [javaClassNameToCoercion keyEnumerator];
|
||||
NSString *className;
|
||||
while ((className = [classNames nextObject]) != nil) {
|
||||
NSObject <JNFTypeCoercion> *coercion = [javaClassNameToCoercion objectForKey:className];
|
||||
JNFInternalJavaClassToCoersionHolder *holder = [[JNFInternalJavaClassToCoersionHolder alloc] initWithCoercion:coercion className:className withEnv:env];
|
||||
[array addObject:holder];
|
||||
[holder release];
|
||||
}
|
||||
|
||||
self.javaClassToCoercion = array;
|
||||
return [array autorelease];
|
||||
}
|
||||
|
||||
- (NSObject <JNFTypeCoercion> *) findCoercerForJavaObject:(jobject)obj withEnv:(JNIEnv *)env {
|
||||
if (obj == NULL) return nil;
|
||||
|
||||
NSMutableDictionary * const javaClassNameToCoercion = self.javaClassNameToCoercion;
|
||||
NSString *javaClazzName = JNFObjectClassName(env, obj);
|
||||
NSObject <JNFTypeCoercion> *coercer = [javaClassNameToCoercion objectForKey:javaClazzName];
|
||||
if (coercer) return coercer;
|
||||
|
||||
#ifdef DEBUG
|
||||
NSLog(@"attempting to find coercer for: %@", javaClazzName);
|
||||
#endif
|
||||
|
||||
NSArray *javaClassCache = [self javaClassCacheUsingEnv:env];
|
||||
NSEnumerator *holderIter = [javaClassCache objectEnumerator];
|
||||
JNFInternalJavaClassToCoersionHolder *holder;
|
||||
while ((holder = [holderIter nextObject]) != nil) {
|
||||
if ([holder isClassFor:obj withEnv:env]) {
|
||||
NSObject <JNFTypeCoercion> *coercion = [holder coercion];
|
||||
[javaClassNameToCoercion setObject:coercion forKey:javaClazzName];
|
||||
return coercion;
|
||||
}
|
||||
}
|
||||
|
||||
return self.parent;
|
||||
}
|
||||
|
||||
- (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer {
|
||||
NSObject <JNFTypeCoercion> *coercion = [self findCoercerForJavaObject:obj withEnv:env];
|
||||
id nsObj = [coercion coerceJavaObject:obj withEnv:env usingCoercer:coercer];
|
||||
if (nsObj == nil) return [NSNull null];
|
||||
return nsObj;
|
||||
}
|
||||
|
||||
- (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env {
|
||||
return [self coerceJavaObject:obj withEnv:env usingCoercer:(JNFTypeCoercion *)self];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation JNFInternalJavaClassToCoersionHolder
|
||||
|
||||
- (id) initWithCoercion:(NSObject <JNFTypeCoercion> *)coercionIn className:(NSString *)className withEnv:(JNIEnv *)env {
|
||||
const char *classNameCStr = [className cStringUsingEncoding:NSUTF8StringEncoding];
|
||||
jclass clz = (*env)->FindClass(env, classNameCStr);
|
||||
if (clz == NULL) [JNFException raise:env as:kClassNotFoundException reason:"Unable to create type converter."];
|
||||
|
||||
self = [super initWithJObject:clz withEnv:env];
|
||||
if (!self) return self;
|
||||
|
||||
self.coercion = coercionIn;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object {
|
||||
jclass javaClazz = [self jObject];
|
||||
|
||||
if ([object isKindOfClass:[self class]]) {
|
||||
return [((JNFInternalJavaClassToCoersionHolder *)object) jObject] == javaClazz;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void) dealloc {
|
||||
self.coercion = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSUInteger)hash {
|
||||
jclass javaClazz = [self jObject];
|
||||
return (NSUInteger)ptr_to_jlong(javaClazz);
|
||||
}
|
||||
|
||||
- (BOOL) isClassFor:(jobject)obj withEnv:(JNIEnv *)env {
|
||||
if (obj == NULL) return JNI_FALSE;
|
||||
#ifdef DEBUG
|
||||
NSLog(@"is (%@(%@)) a kind of (%@)?", JNFToString(env, obj), JNFClassName(env, obj), JNFToString(env, javaClazz));
|
||||
#endif
|
||||
|
||||
jclass javaClazz = [self jObject];
|
||||
return (BOOL)(*env)->IsInstanceOf(env, obj, javaClazz);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface JNFStringCoercion : NSObject <JNFTypeCoercion> { }
|
||||
@end
|
||||
|
||||
@implementation JNFStringCoercion
|
||||
|
||||
- (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env usingCoercer:(__unused JNFTypeCoercion *)coercer {
|
||||
return JNFNSToJavaString(env, (NSString *)obj);
|
||||
}
|
||||
|
||||
- (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env usingCoercer:(__unused JNFTypeCoercion *)coercer {
|
||||
return JNFJavaToNSString(env, (jstring)obj);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface JNFNumberCoercion : NSObject <JNFTypeCoercion> { }
|
||||
@end
|
||||
|
||||
@implementation JNFNumberCoercion
|
||||
|
||||
- (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env usingCoercer:(__unused JNFTypeCoercion *)coercer {
|
||||
return JNFNSToJavaNumber(env, (NSNumber *)obj);
|
||||
}
|
||||
|
||||
- (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env usingCoercer:(__unused JNFTypeCoercion *)coercer {
|
||||
return JNFJavaToNSNumber(env, obj);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface JNFDateCoercion : NSObject <JNFTypeCoercion> { }
|
||||
@end
|
||||
|
||||
@implementation JNFDateCoercion
|
||||
|
||||
- (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env usingCoercer:(__unused JNFTypeCoercion *)coercer {
|
||||
return JNFNSToJavaCalendar(env, (NSDate *)obj);
|
||||
}
|
||||
|
||||
- (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env usingCoercer:(__unused JNFTypeCoercion *)coercer {
|
||||
return JNFJavaToNSDate(env, obj);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
static JNF_CLASS_CACHE(jc_Iterator, "java/util/Iterator");
|
||||
static JNF_MEMBER_CACHE(jm_Iterator_hasNext, jc_Iterator, "hasNext", "()Z");
|
||||
static JNF_MEMBER_CACHE(jm_Iterator_next, jc_Iterator, "next", "()Ljava/lang/Object;");
|
||||
|
||||
@interface JNFMapCoercion : NSObject <JNFTypeCoercion> { }
|
||||
@end
|
||||
|
||||
@implementation JNFMapCoercion
|
||||
|
||||
- (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer {
|
||||
static JNF_CLASS_CACHE(jc_HashMap, "java/util/HashMap");
|
||||
static JNF_CTOR_CACHE(jm_HashMap_ctor, jc_HashMap, "()V");
|
||||
static JNF_MEMBER_CACHE(jm_HashMap_put, jc_HashMap, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
|
||||
NSDictionary *nsDict = (NSDictionary *)obj;
|
||||
NSEnumerator *keyEnum = [nsDict keyEnumerator];
|
||||
|
||||
jobject jHashMap = JNFNewObject(env, jm_HashMap_ctor);
|
||||
|
||||
id key;
|
||||
while ((key = [keyEnum nextObject]) != nil) {
|
||||
jobject jkey = [coercer coerceNSObject:key withEnv:env usingCoercer:coercer];
|
||||
|
||||
id value = [nsDict objectForKey:key];
|
||||
jobject java_value = [coercer coerceNSObject:value withEnv:env usingCoercer:coercer];
|
||||
|
||||
JNFCallObjectMethod(env, jHashMap, jm_HashMap_put, jkey, java_value);
|
||||
|
||||
if (jkey != NULL) (*env)->DeleteLocalRef(env, jkey);
|
||||
if (java_value != NULL) (*env)->DeleteLocalRef(env, java_value);
|
||||
}
|
||||
|
||||
return jHashMap;
|
||||
}
|
||||
|
||||
- (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer {
|
||||
static JNF_CLASS_CACHE(jc_Map, "java/util/Map");
|
||||
static JNF_MEMBER_CACHE(jm_Map_keySet, jc_Map, "keySet", "()Ljava/util/Set;");
|
||||
static JNF_MEMBER_CACHE(jm_Map_get, jc_Map, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
|
||||
static JNF_CLASS_CACHE(jc_Set, "java/util/Set");
|
||||
static JNF_MEMBER_CACHE(jm_Set_iterator, jc_Set, "iterator", "()Ljava/util/Iterator;");
|
||||
|
||||
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
|
||||
jobject jKeySet = JNFCallObjectMethod(env, obj, jm_Map_keySet);
|
||||
jobject jKeyIter = JNFCallObjectMethod(env, jKeySet, jm_Set_iterator);
|
||||
if (jKeySet != NULL) (*env)->DeleteLocalRef(env, jKeySet);
|
||||
|
||||
while (JNFCallBooleanMethod(env, jKeyIter, jm_Iterator_hasNext)) {
|
||||
jobject jkey = JNFCallObjectMethod(env, jKeyIter, jm_Iterator_next);
|
||||
id nsKey = [coercer coerceJavaObject:jkey withEnv:env usingCoercer:coercer];
|
||||
|
||||
jobject java_value = JNFCallObjectMethod(env, obj, jm_Map_get, jkey);
|
||||
if (jkey != NULL) (*env)->DeleteLocalRef(env, jkey);
|
||||
|
||||
id nsValue = [coercer coerceJavaObject:java_value withEnv:env usingCoercer:coercer];
|
||||
if (java_value != NULL) (*env)->DeleteLocalRef(env, java_value);
|
||||
|
||||
[dict setObject:nsValue forKey:nsKey];
|
||||
}
|
||||
|
||||
return [dict autorelease];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface JNFListCoercion : NSObject <JNFTypeCoercion> { }
|
||||
@end
|
||||
|
||||
@implementation JNFListCoercion
|
||||
|
||||
- (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer {
|
||||
static JNF_CLASS_CACHE(jc_List, "java/util/ArrayList");
|
||||
static JNF_CTOR_CACHE(jm_List_ctor, jc_List, "(I)V");
|
||||
static JNF_MEMBER_CACHE(jm_List_add, jc_List, "add", "(Ljava/lang/Object;)Z");
|
||||
|
||||
NSArray *nsArray = (NSArray *)obj;
|
||||
unsigned long count = [nsArray count];
|
||||
|
||||
jobject javaArray = JNFNewObject(env, jm_List_ctor, (jint)count);
|
||||
|
||||
unsigned long i;
|
||||
for (i = 0; i < count; i++) {
|
||||
id iThObj = [nsArray objectAtIndex:i];
|
||||
jobject iThJObj = [coercer coerceNSObject:iThObj withEnv:env usingCoercer:coercer];
|
||||
JNFCallBooleanMethod(env, javaArray, jm_List_add, iThJObj);
|
||||
if (iThJObj != NULL) (*env)->DeleteLocalRef(env, iThJObj);
|
||||
}
|
||||
|
||||
return javaArray;
|
||||
}
|
||||
|
||||
- (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer {
|
||||
static JNF_CLASS_CACHE(jc_List, "java/util/List");
|
||||
static JNF_MEMBER_CACHE(jm_List_iterator, jc_List, "iterator", "()Ljava/util/Iterator;");
|
||||
|
||||
jobject jIterator = JNFCallObjectMethod(env, obj, jm_List_iterator);
|
||||
|
||||
NSMutableArray *nsArray = [[NSMutableArray alloc] init];
|
||||
while (JNFCallBooleanMethod(env, jIterator, jm_Iterator_hasNext)) {
|
||||
jobject jobj = JNFCallObjectMethod(env, jIterator, jm_Iterator_next);
|
||||
id nsObj = [coercer coerceJavaObject:jobj withEnv:env usingCoercer:coercer];
|
||||
if (jobj != NULL) (*env)->DeleteLocalRef(env, jobj);
|
||||
[nsArray addObject:nsObj];
|
||||
}
|
||||
|
||||
return [nsArray autorelease];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface JNFSetCoercion : NSObject <JNFTypeCoercion> { }
|
||||
@end
|
||||
|
||||
@implementation JNFSetCoercion
|
||||
|
||||
- (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer {
|
||||
static JNF_CLASS_CACHE(jc_Set, "java/util/HashSet");
|
||||
static JNF_CTOR_CACHE(jm_Set_ctor, jc_Set, "()V");
|
||||
static JNF_MEMBER_CACHE(jm_Set_add, jc_Set, "add", "(Ljava/lang/Object;)Z");
|
||||
|
||||
NSSet *nsSet = (NSSet *)obj;
|
||||
NSEnumerator *enumerator = [nsSet objectEnumerator];
|
||||
|
||||
jobject javaSet = JNFNewObject(env, jm_Set_ctor);
|
||||
id next;
|
||||
while ((next = [enumerator nextObject]) != nil) {
|
||||
jobject jnext = [coercer coerceNSObject:next withEnv:env usingCoercer:coercer];
|
||||
if (jnext != NULL) {
|
||||
JNFCallBooleanMethod(env, javaSet, jm_Set_add, jnext);
|
||||
(*env)->DeleteLocalRef(env, jnext);
|
||||
}
|
||||
}
|
||||
|
||||
return javaSet;
|
||||
}
|
||||
|
||||
- (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer {
|
||||
static JNF_CLASS_CACHE(jc_Set, "java/util/Set");
|
||||
static JNF_MEMBER_CACHE(jm_Set_iterator, jc_Set, "iterator", "()Ljava/util/Iterator;");
|
||||
|
||||
jobject jIterator = JNFCallObjectMethod(env, obj, jm_Set_iterator);
|
||||
|
||||
NSMutableSet *nsSet = [[NSMutableSet alloc] init];
|
||||
while (JNFCallBooleanMethod(env, jIterator, jm_Iterator_hasNext)) {
|
||||
jobject jobj = JNFCallObjectMethod(env, jIterator, jm_Iterator_next);
|
||||
if (jobj != NULL) {
|
||||
id nsObj = [coercer coerceJavaObject:jobj withEnv:env usingCoercer:coercer];
|
||||
(*env)->DeleteLocalRef(env, jobj);
|
||||
[nsSet addObject:nsObj];
|
||||
}
|
||||
}
|
||||
|
||||
return [nsSet autorelease];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation JNFDefaultCoercions
|
||||
|
||||
+ (void) addStringCoercionTo:(JNFTypeCoercer *)coercer {
|
||||
[coercer addCoercion:[[[JNFStringCoercion alloc] init] autorelease] forNSClass:[NSString class] javaClass:@"java/lang/String"];
|
||||
}
|
||||
|
||||
+ (void) addNumberCoercionTo:(JNFTypeCoercer *)coercer {
|
||||
[coercer addCoercion:[[[JNFNumberCoercion alloc] init] autorelease] forNSClass:[NSNumber class] javaClass:@"java/lang/Number"];
|
||||
}
|
||||
|
||||
+ (void) addDateCoercionTo:(JNFTypeCoercer *)coercer {
|
||||
id dateCoercion = [[[JNFDateCoercion alloc] init] autorelease];
|
||||
[coercer addCoercion:dateCoercion forNSClass:[NSDate class] javaClass:@"java/util/Calendar"];
|
||||
[coercer addCoercion:dateCoercion forNSClass:[NSDate class] javaClass:@"java/util/Date"];
|
||||
}
|
||||
|
||||
+ (void) addListCoercionTo:(JNFTypeCoercer *)coercer {
|
||||
[coercer addCoercion:[[[JNFListCoercion alloc] init] autorelease] forNSClass:[NSArray class] javaClass:@"java/util/List"];
|
||||
}
|
||||
|
||||
+ (void) addMapCoercionTo:(JNFTypeCoercer *)coercer {
|
||||
[coercer addCoercion:[[[JNFMapCoercion alloc] init] autorelease] forNSClass:[NSDictionary class] javaClass:@"java/util/Map"];
|
||||
}
|
||||
|
||||
+ (void) addSetCoercionTo:(JNFTypeCoercer *)coercer {
|
||||
[coercer addCoercion:[[[JNFSetCoercion alloc] init] autorelease] forNSClass:[NSSet class] javaClass:@"java/util/Set"];
|
||||
}
|
||||
|
||||
+ (JNFTypeCoercer *) defaultCoercer {
|
||||
JNFTypeCoercer *coercer = [[[JNFTypeCoercer alloc] initWithParent:nil] autorelease];
|
||||
|
||||
[JNFDefaultCoercions addStringCoercionTo:coercer];
|
||||
[JNFDefaultCoercions addNumberCoercionTo:coercer];
|
||||
[JNFDefaultCoercions addDateCoercionTo:coercer];
|
||||
[JNFDefaultCoercions addListCoercionTo:coercer];
|
||||
[JNFDefaultCoercions addMapCoercionTo:coercer];
|
||||
[JNFDefaultCoercions addSetCoercionTo:coercer];
|
||||
|
||||
return coercer;
|
||||
}
|
||||
|
||||
@end
|
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2008-2020 Apple Inc.\nAll Rights Reserved.</string>
|
||||
</dict>
|
||||
</plist>
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*
|
||||
* This umbrella header should be included by all JNI/Cocoa source files
|
||||
* for easy building. Use this file instead of importing individual JNF
|
||||
* headers.
|
||||
*/
|
||||
|
||||
#import <JavaNativeFoundation/JNFJNI.h>
|
||||
#import <JavaNativeFoundation/JNFObject.h>
|
||||
#import <JavaNativeFoundation/JNFJObjectWrapper.h>
|
||||
#import <JavaNativeFoundation/JNFString.h>
|
||||
#import <JavaNativeFoundation/JNFNumber.h>
|
||||
#import <JavaNativeFoundation/JNFDate.h>
|
||||
#import <JavaNativeFoundation/JNFPath.h>
|
||||
#import <JavaNativeFoundation/JNFTypeCoercion.h>
|
||||
#import <JavaNativeFoundation/JNFThread.h>
|
||||
#import <JavaNativeFoundation/JNFRunnable.h>
|
||||
#import <JavaNativeFoundation/JNFRunLoop.h>
|
||||
#import <JavaNativeFoundation/JNFException.h>
|
||||
#import <JavaNativeFoundation/JNFAssert.h>
|
@ -0,0 +1,5 @@
|
||||
framework module JavaNativeFoundation [extern_c] {
|
||||
umbrella header "JavaNativeFoundation.h"
|
||||
export *
|
||||
module * { export * }
|
||||
}
|
42
apple/JavaNativeFoundation/JavaNativeFoundation/debug.h
Normal file
42
apple/JavaNativeFoundation/JavaNativeFoundation/debug.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*
|
||||
* Internal functions to Java Native Foundation.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <JavaNativeFoundation/JNFJNI.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
//
|
||||
// Debugging support
|
||||
//
|
||||
|
||||
// prints a stack trace from the Java VM (can be called from gdb)
|
||||
void JNFJavaStackTrace(JNIEnv *env);
|
||||
|
||||
// dump some info about a generic Java object.
|
||||
void JNFDumpJavaObject(JNIEnv *env, jobject obj);
|
||||
|
||||
// prints a Java stack trace into a string
|
||||
NSString *JNFGetStackTraceAsNSString(JNIEnv *env, jthrowable throwable);
|
||||
|
||||
__END_DECLS
|
98
apple/JavaNativeFoundation/JavaNativeFoundation/debug.m
Normal file
98
apple/JavaNativeFoundation/JavaNativeFoundation/debug.m
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2020 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_START@
|
||||
*
|
||||
* The contents of this file are licensed under the terms of the
|
||||
* GNU Public License (version 2 only) with the "Classpath" exception.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only with
|
||||
* classpath exception, as published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* @GPLv2-CPE_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
#import "debug.h"
|
||||
|
||||
#import "JNFAssert.h"
|
||||
#import "JNFObject.h"
|
||||
|
||||
/*
|
||||
* Utility function to print the Java stack backtrace.
|
||||
* In gdb, if you have a value for the JNIEnv on the thread
|
||||
* you want to trace, you can do a gdb "print" of this function
|
||||
* to get the stack trace for the thread.
|
||||
*/
|
||||
void JNFJavaStackTrace(JNIEnv *env) {
|
||||
jthrowable obj_javaException;
|
||||
if ((obj_javaException = (*env)->ExceptionOccurred(env)) != NULL) (*env)->ExceptionClear(env);
|
||||
|
||||
jclass cls_Thread = (*env)->FindClass(env, "java/lang/Thread");
|
||||
jmethodID mid_currentThread = (*env)->GetStaticMethodID(env, cls_Thread, "currentThread", "()Ljava/lang/Thread;");
|
||||
jobject obj_currentThread = (*env)->CallStaticObjectMethod(env, cls_Thread, mid_currentThread);
|
||||
jclass cls_currentThread = (*env)->GetObjectClass(env, obj_currentThread);
|
||||
jmethodID mid_getName = (*env)->GetMethodID(env, cls_currentThread, "getName", "()Ljava/lang/String;");
|
||||
jobject obj_threadName = (*env)->CallObjectMethod(env, obj_currentThread, mid_getName);
|
||||
(*env)->DeleteLocalRef(env, obj_currentThread);
|
||||
|
||||
const char *threadName = (*env)->GetStringUTFChars(env, obj_threadName, NULL);
|
||||
JNF_WARN("Stack trace from Java thread \"%s\":", threadName);
|
||||
(*env)->ReleaseStringUTFChars(env, obj_threadName, threadName);
|
||||
(*env)->DeleteLocalRef(env, obj_threadName);
|
||||
|
||||
jmethodID mid_dumpStack = (*env)->GetStaticMethodID(env, cls_Thread, "dumpStack", "()V");
|
||||
(*env)->CallStaticVoidMethod(env, cls_Thread, mid_dumpStack);
|
||||
(*env)->DeleteLocalRef(env, cls_Thread);
|
||||
|
||||
if (obj_javaException) (*env)->Throw(env, obj_javaException);
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility function to dump some info about a generic Java object.
|
||||
* To be called from gdb. Like JNFJavaStackTrace, you need to have
|
||||
* a valid value for the JNIEnv to call this function.
|
||||
*/
|
||||
void JNFDumpJavaObject(JNIEnv *env, jobject obj) {
|
||||
jthrowable obj_javaException;
|
||||
if ((obj_javaException = (*env)->ExceptionOccurred(env)) != NULL) (*env)->ExceptionClear(env);
|
||||
|
||||
jclass cls_CToolkit = (*env)->FindClass(env, "apple/awt/CToolkit");
|
||||
jmethodID mid_dumpObject = (*env)->GetStaticMethodID(env, cls_CToolkit, "dumpObject", "(Ljava/lang/Object;)V");
|
||||
(*env)->CallStaticVoidMethod(env, cls_CToolkit, mid_dumpObject, obj);
|
||||
(*env)->DeleteLocalRef(env, cls_CToolkit);
|
||||
|
||||
if (obj_javaException) (*env)->Throw(env, obj_javaException);
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility function to print a Java stack trace into a string
|
||||
*/
|
||||
NSString *JNFGetStackTraceAsNSString(JNIEnv *env, jthrowable throwable) {
|
||||
// Writer writer = new StringWriter();
|
||||
JNF_CLASS_CACHE(jc_StringWriter, "java/io/StringWriter");
|
||||
JNF_CTOR_CACHE(jct_StringWriter, jc_StringWriter, "()V");
|
||||
jobject writer = JNFNewObject(env, jct_StringWriter);
|
||||
|
||||
// PrintWriter printWriter = new PrintWriter(writer);
|
||||
JNF_CLASS_CACHE(jc_PrintWriter, "java/io/PrintWriter");
|
||||
JNF_CTOR_CACHE(jct_PrintWriter, jc_PrintWriter, "(Ljava/io/Writer;)V");
|
||||
jobject printWriter = JNFNewObject(env, jct_PrintWriter, writer);
|
||||
|
||||
// throwable.printStackTrace(printWriter);
|
||||
JNF_CLASS_CACHE(jc_Throwable, "java/lang/Throwable");
|
||||
JNF_MEMBER_CACHE(jm_printStackTrace, jc_Throwable, "printStackTrace", "(Ljava/io/PrintWriter;)V");
|
||||
JNFCallVoidMethod(env, throwable, jm_printStackTrace, printWriter);
|
||||
(*env)->DeleteLocalRef(env, printWriter);
|
||||
|
||||
// return writer.toString();
|
||||
NSString *stackTraceAsString = JNFObjectToString(env, writer);
|
||||
(*env)->DeleteLocalRef(env, writer);
|
||||
return stackTraceAsString;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
DEFINES_MODULE = YES
|
||||
INSTALL_PATH = /
|
||||
DYLIB_INSTALL_NAME_BASE = @rpath
|
||||
|
||||
HEADER_SEARCH_PATHS = $(SRCROOT)/../../src/java.base/share/native/include $(SRCROOT)/../../src/java.base/unix/native/include
|
||||
|
||||
// TODO: These should be removed as issues are addressed
|
||||
CLANG_ENABLE_OBJC_ARC = NO
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES
|
212
apple/JavaNativeFoundation/xcconfig/common.xcconfig
Normal file
212
apple/JavaNativeFoundation/xcconfig/common.xcconfig
Normal file
@ -0,0 +1,212 @@
|
||||
// Target information
|
||||
|
||||
CODE_SIGN_IDENTITY = -
|
||||
CURRENT_PROJECT_VERSION = 80
|
||||
PRODUCT_NAME = $(TARGET_NAME)
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.apple.$(TARGET_NAME:rfc1034identifier)
|
||||
VERSIONING_SYSTEM = apple-generic
|
||||
VERSION_INFO_PREFIX=__attribute__((visibility("hidden")))
|
||||
|
||||
// Architectures and deployment targets
|
||||
ONLY_ACTIVE_ARCH = NO
|
||||
SDKROOT = macosx
|
||||
|
||||
IS_ZIPPERED = NO
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.14
|
||||
|
||||
// Pre-includes
|
||||
|
||||
INCLUDE_TARGET_LOCALIZATION_PREHEADER = -include $(SRCROOT)/$(TARGET_NAME)/$(TARGET_NAME)-Localization.h
|
||||
INCLUDE_PREHEADERS = -include $(SRCROOT)/$(TARGET_NAME)/$(TARGET_NAME)-Localization.h
|
||||
|
||||
// Xcode project setting defaults
|
||||
|
||||
ALWAYS_SEARCH_USER_PATHS = NO
|
||||
COPY_PHASE_STRIP = NO
|
||||
DEBUG_INFORMATION_FORMAT = dwarf-with-dsym
|
||||
DEFINES_MODULE = NO
|
||||
DYLIB_COMPATIBILITY_VERSION = 1
|
||||
DYLIB_CURRENT_VERSION = $(CURRENT_PROJECT_VERSION)
|
||||
ENABLE_NS_ASSERTIONS = YES
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES
|
||||
ENABLE_TESTABILITY = NO
|
||||
INFOPLIST_FILE = $(TARGET_NAME)/$(TARGET_NAME)-Info.plist
|
||||
INFOPLIST_OUTPUT_FORMAT = binary
|
||||
LLVM_LTO = NO
|
||||
LLVM_LTO[config=Release*] = Classic
|
||||
MODULEMAP_FILE = $(TARGET_NAME)/Modules/module.modulemap
|
||||
MODULEMAP_PRIVATE_FILE =
|
||||
OTHER_CFLAGS = $(OTHER_CFLAGS_$(CONFIGURATION))
|
||||
OTHER_LDFLAGS = $(OTHER_LDFLAGS_$(CONFIGURATION))
|
||||
PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO
|
||||
RUN_CLANG_STATIC_ANALYZER = NO
|
||||
SKIP_INSTALL = NO
|
||||
STRIP_INSTALLED_PRODUCT = NO
|
||||
STRIP_INSTALLED_PRODUCT[config=Release*] = YES
|
||||
SUPPORTED_PLATFORMS = macosx
|
||||
USE_HEADERMAP = YES
|
||||
|
||||
// Clang directives section
|
||||
|
||||
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = NO
|
||||
CLANG_CXX_LANGUAGE_STANDARD = gnu++17
|
||||
CLANG_CXX_LIBRARY = libc++
|
||||
CLANG_ENABLE_OBJC_ARC = YES
|
||||
CLANG_ENABLE_MODULES = YES
|
||||
CLANG_ENABLE_OBJC_WEAK = YES
|
||||
CLANG_LINK_OBJC_RUNTIME = YES
|
||||
CLANG_MODULES_AUTOLINK = YES
|
||||
|
||||
// Clang warnings section
|
||||
|
||||
CLANG_WARN_ASSIGN_ENUM = YES
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES
|
||||
CLANG_WARN_BOOL_CONVERSION = YES
|
||||
CLANG_WARN_COMMA = YES
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES
|
||||
CLANG_WARN_CXX0X_EXTENSIONS = YES
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES
|
||||
CLANG_WARN_EMPTY_BODY = YES
|
||||
CLANG_WARN_ENUM_CONVERSION = YES
|
||||
CLANG_WARN_FLOAT_CONVERSION = YES
|
||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES
|
||||
CLANG_WARN_INFINITE_RECURSION = YES
|
||||
CLANG_WARN_INT_CONVERSION = YES
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES
|
||||
CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES
|
||||
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
|
||||
CLANG_WARN_OBJC_INTERFACE_IVARS = YES
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES
|
||||
CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = NO
|
||||
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES
|
||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES
|
||||
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
|
||||
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES
|
||||
|
||||
WARNING_CFLAGS = $(inherited) -Wno-error=deprecated -Wno-error=#warnings
|
||||
|
||||
// GCC preprocessor section
|
||||
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = NO
|
||||
GCC_PREFIX_HEADER =
|
||||
|
||||
// GCC directives section
|
||||
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11
|
||||
GCC_CHAR_IS_UNSIGNED_CHAR = NO
|
||||
GCC_CW_ASM_SYNTAX = NO
|
||||
GCC_DYNAMIC_NO_PIC = NO
|
||||
GCC_ENABLE_ASM_KEYWORD = YES
|
||||
GCC_ENABLE_BUILTIN_FUNCTIONS = NO
|
||||
GCC_ENABLE_BUILTIN_FUNCTIONS[config=Release*] = YES
|
||||
GCC_ENABLE_CPP_EXCEPTIONS = NO
|
||||
GCC_ENABLE_CPP_RTTI = NO
|
||||
GCC_ENABLE_KERNEL_DEVELOPMENT = NO
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = NO
|
||||
GCC_ENABLE_PASCAL_STRINGS = NO
|
||||
GCC_ENABLE_TRIGRAPHS = NO
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = YES
|
||||
GCC_INCREASE_PRECOMPILED_HEADER_SHARING = YES
|
||||
GCC_INPUT_FILETYPE = automatic
|
||||
GCC_LINK_WITH_DYNAMIC_LIBRARIES = YES
|
||||
GCC_NO_COMMON_BLOCKS = YES
|
||||
GCC_OPTIMIZATION_LEVEL = 0
|
||||
GCC_OPTIMIZATION_LEVEL[config=Release*] = s
|
||||
GCC_REUSE_STRINGS = YES
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = YES
|
||||
GCC_STRICT_ALIASING = YES
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES
|
||||
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES
|
||||
GCC_UNROLL_LOOPS = NO
|
||||
GCC_USE_STANDARD_INCLUDE_SEARCHING = YES
|
||||
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES
|
||||
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES
|
||||
GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES
|
||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES
|
||||
GCC_WARN_ABOUT_MISSING_NEWLINE = YES
|
||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES
|
||||
GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR
|
||||
GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = YES
|
||||
GCC_WARN_CHECK_SWITCH_STATEMENTS = YES
|
||||
GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES
|
||||
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES
|
||||
GCC_WARN_INHIBIT_ALL_WARNINGS = NO
|
||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES
|
||||
GCC_WARN_MISSING_PARENTHESES = YES
|
||||
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES
|
||||
GCC_WARN_PEDANTIC = NO
|
||||
GCC_WARN_SHADOW = YES
|
||||
GCC_WARN_SIGN_COMPARE = YES
|
||||
GCC_WARN_STRICT_SELECTOR_MATCH = YES
|
||||
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = YES
|
||||
GCC_WARN_UNUSED_FUNCTION = YES
|
||||
GCC_WARN_UNUSED_LABEL = YES
|
||||
GCC_WARN_UNUSED_PARAMETER = YES
|
||||
GCC_WARN_UNUSED_VALUE = YES
|
||||
GCC_WARN_UNUSED_VARIABLE = YES
|
||||
|
||||
// Address sanitizers section
|
||||
|
||||
CLANG_ADDRESS_SANITIZER_CONTAINER_OVERFLOW = YES
|
||||
|
||||
// Undefined behavior sanitizers section
|
||||
|
||||
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_INTEGER = YES
|
||||
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES
|
||||
|
||||
// Static analyzer section
|
||||
|
||||
CLANG_STATIC_ANALYZER_MODE = Shallow
|
||||
CLANG_STATIC_ANALYZER_MODE_ON_ANALYZE_ACTION = Deep
|
||||
|
||||
CLANG_ANALYZER_DEADCODE_DEADSTORES = YES
|
||||
CLANG_ANALYZER_GCD = YES
|
||||
CLANG_ANALYZER_GCD_PERFORMANCE = YES
|
||||
CLANG_ANALYZER_LOCALIZABILITY_EMPTY_CONTEXT = NO
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = NO
|
||||
CLANG_ANALYZER_MEMORY_MANAGEMENT = YES
|
||||
CLANG_ANALYZER_NONNULL = YES
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES
|
||||
CLANG_ANALYZER_OBJC_ATSYNC = YES
|
||||
CLANG_ANALYZER_OBJC_COLLECTIONS = YES
|
||||
CLANG_ANALYZER_OBJC_DEALLOC = YES
|
||||
CLANG_ANALYZER_OBJC_GENERICS = YES
|
||||
CLANG_ANALYZER_OBJC_INCOMP_METHOD_TYPES = YES
|
||||
CLANG_ANALYZER_OBJC_NSCFERROR = YES
|
||||
CLANG_ANALYZER_OBJC_RETAIN_COUNT = YES
|
||||
CLANG_ANALYZER_OBJC_SELF_INIT = YES
|
||||
CLANG_ANALYZER_OBJC_UNUSED_IVARS = YES
|
||||
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES
|
||||
CLANG_ANALYZER_SECURITY_KEYCHAIN_API = YES
|
||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_GETPW_GETS = YES
|
||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_MKSTEMP = YES
|
||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES
|
||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES
|
||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_UNCHECKEDRETURN = YES
|
||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_VFORK = YES
|
||||
|
||||
CLANG_ANALYZER_OTHER_FLAGS = -analyzer-checker=nullability.NullablePassedToNonnull
|
||||
|
||||
// Text-based API
|
||||
|
||||
GENERATE_TEXT_BASED_STUBS = NO
|
||||
INLINE_PRIVATE_FRAMEWORKS = NO
|
||||
SUPPORTS_TEXT_BASED_API = YES
|
||||
TEXT_BASED_API_FILE =
|
||||
TAPI_VERIFY_MODE = Pedantic
|
Loading…
Reference in New Issue
Block a user