[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:
Jeremy Huddleston Sequoia 2020-05-17 14:10:18 -07:00
parent dd60699ea5
commit 55b3ebec85
38 changed files with 4006 additions and 0 deletions

9
apple/JavaNativeFoundation/.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
build
DerivedData
.DS_Store
*~
*.rej
*.orig
cscope.*
tags
TAGS

View File

@ -0,0 +1,2 @@
project.xcworkspace
xcuserdata

View File

@ -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 */;
}

View 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

View 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);
}

View File

@ -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

View File

@ -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
}

View 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

View 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;
}

View File

@ -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

View 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

View 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

View 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);
}

View File

@ -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

View File

@ -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

View 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

View 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);
}

View 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

View 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;
}

View 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

View 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)];
}

View 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

View 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

View File

@ -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

View File

@ -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

View 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

View 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);
}

View 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

View 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

View 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@
*
* 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

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -0,0 +1,5 @@
framework module JavaNativeFoundation [extern_c] {
umbrella header "JavaNativeFoundation.h"
export *
module * { export * }
}

View 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

View 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;
}

View File

@ -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

View 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