1 /* Cycript - The Truly Universal Scripting Language
2 * Copyright (C) 2009-2016 Jay Freeman (saurik)
5 /* GNU Affero General Public License, Version 3 {{{ */
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include <JavaVM/jni.h>
32 #include "cycript.hpp"
34 #include "Execute.hpp"
35 #include "Internal.hpp"
36 #include "JavaScript.hpp"
37 #include "Pooling.hpp"
39 #define _jnicall(expr) ({ \
41 if (_value != JNI_OK) \
42 CYThrow("_jnicall(%s) == %d", #expr, _value); \
45 #define _envcall(jni, expr) ({ \
46 __typeof__(jni->expr) _value(jni->expr); \
47 if (jthrowable _error = jni->ExceptionOccurred()) { \
48 jni->ExceptionClear(); \
49 throw CYJavaError(CYJavaLocal<jthrowable>(jni, _error)); \
53 #define _envcallv(jni, expr) do { \
55 if (jthrowable _error = jni->ExceptionOccurred()) { \
56 jni->ExceptionClear(); \
57 throw CYJavaError(CYJavaLocal<jthrowable>(jni, _error)); \
63 auto &protect(*reinterpret_cast<CYProtect *>(jprotect)); \
64 _disused JSContextRef context(protect); \
65 _disused JSObjectRef object(protect); \
67 #define CYJavaCatch(value) \
68 catch (const CYException &error) { \
69 jni->Throw(CYCastJavaObject(jni, context, error.CastJSValue(context, "Error")).cast<jthrowable>()); \
74 // Android's jni.h seriously doesn't declare these :/
75 jint
JNI_CreateJavaVM(JavaVM
**, void **, void *);
76 jint
JNI_GetCreatedJavaVMs(JavaVM
**, jsize
, jsize
*);
79 JNIEnv
*GetJNI(JSContextRef context
);
81 #define CYJavaForEachPrimitive \
82 CYJavaForEachPrimitive_(Z, z, Boolean, Boolean, boolean) \
83 CYJavaForEachPrimitive_(B, b, Byte, Byte, byte) \
84 CYJavaForEachPrimitive_(C, c, Char, Character, char) \
85 CYJavaForEachPrimitive_(S, s, Short, Short, short) \
86 CYJavaForEachPrimitive_(I, i, Int, Integer, int) \
87 CYJavaForEachPrimitive_(J, j, Long, Long, long) \
88 CYJavaForEachPrimitive_(F, f, Float, Float, float) \
89 CYJavaForEachPrimitive_(D, d, Double, Double, double)
91 enum CYJavaPrimitive
: char {
92 CYJavaPrimitiveObject
,
94 #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \
95 CYJavaPrimitive ## Type,
96 CYJavaForEachPrimitive
97 #undef CYJavaForEachPrimitive_
100 template <typename Type_
>
101 struct IsJavaPrimitive
{ static const bool value
= false; };
103 #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \
105 struct IsJavaPrimitive<j ## type> { static const bool value = true; };
106 CYJavaForEachPrimitive
107 #undef CYJavaForEachPrimitive_
109 // Java References {{{
110 template <typename Value_
>
115 _finline
CYJavaRef(JNIEnv
*jni
, Value_ value
) :
121 _finline
operator Value_() const {
125 _finline JNIEnv
*jni() const {
129 // XXX: this is only needed to support CYJavaEnv relying on C variadics
130 _finline Value_
get() const {
134 template <typename Other_
>
135 _finline CYJavaRef
<Other_
> cast() const {
136 return {jni_
, static_cast<Other_
>(value_
)};
139 // XXX: this should be tied into CYJavaFrame
141 Value_
value(value_
);
147 template <typename Value_
, void (JNIEnv::*Delete_
)(jobject
)>
148 struct CYJavaDelete
:
151 _finline
CYJavaDelete(JNIEnv
*jni
, Value_ value
) :
152 CYJavaRef
<Value_
>(jni
, value
)
157 if (this->value_
!= NULL
)
158 (this->jni_
->*Delete_
)(this->value_
);
167 template <typename Value_
>
168 struct CYJavaGlobal
:
169 CYJavaDelete
<Value_
, &JNIEnv::DeleteGlobalRef
>
171 typedef CYJavaDelete
<Value_
, &JNIEnv::DeleteGlobalRef
> CYJavaBase
;
174 CYJavaBase(NULL
, NULL
)
178 template <typename Other_
>
179 CYJavaGlobal(const CYJavaRef
<Other_
> &other
) :
180 CYJavaBase(other
.jni_
, static_cast<Other_
>(other
.jni_
->NewGlobalRef(other
.value_
)))
184 CYJavaGlobal(const CYJavaGlobal
<Value_
> &other
) :
185 CYJavaGlobal(static_cast<const CYJavaRef
<Value_
> &>(other
))
189 CYJavaGlobal(CYJavaGlobal
&&value
) :
190 CYJavaBase(value
.jni_
, value
.value_
)
196 template <typename Value_
>
198 CYJavaDelete
<Value_
, &JNIEnv::DeleteLocalRef
>
200 typedef CYJavaDelete
<Value_
, &JNIEnv::DeleteLocalRef
> CYJavaBase
;
203 CYJavaBase(NULL
, NULL
)
207 CYJavaLocal(JNIEnv
*jni
, Value_ value
) :
208 CYJavaBase(jni
, value
)
212 template <typename Other_
>
213 CYJavaLocal(const CYJavaRef
<Other_
> &other
) :
214 CYJavaLocal(other
.jni_
, static_cast<Other_
>(other
.jni_
->NewLocalRef(other
.value_
)))
218 template <typename Other_
>
219 CYJavaLocal(CYJavaRef
<Other_
> &&other
) :
220 CYJavaLocal(other
.jni_
, other
.value_
)
225 CYJavaLocal(CYJavaLocal
&&other
) :
226 CYJavaLocal(static_cast<CYJavaRef
<Value_
> &&>(other
))
230 template <typename Other_
>
231 CYJavaLocal
&operator =(CYJavaLocal
<Other_
> &&other
) {
233 this->jni_
= other
.jni_
;
234 this->value_
= other
.value_
;
241 static CYJavaLocal
<jstring
> CYCastJavaString(const CYJavaRef
<jobject
> &value
);
243 class CYJavaUTF8String
:
247 const CYJavaRef
<jstring
> *value_
;
250 CYJavaUTF8String(const CYJavaRef
<jstring
> &value
) :
254 JNIEnv
*jni(value
.jni());
255 size
= jni
->GetStringUTFLength(value
);
256 data
= jni
->GetStringUTFChars(value
, NULL
);
259 CYJavaUTF8String(const CYJavaRef
<jobject
> &value
) :
260 CYJavaUTF8String(CYCastJavaString(value
))
264 ~CYJavaUTF8String() {
265 if (value_
!= NULL
) {
266 JNIEnv
*jni(value_
->jni());
267 jni
->ReleaseStringUTFChars(*value_
, data
);
271 CYJavaUTF8String(const CYJavaUTF8String
&) = delete;
273 CYJavaUTF8String(CYJavaUTF8String
&&rhs
) :
280 CYJavaUTF8String
CYCastUTF8String(const CYJavaRef
<jstring
> &value
) {
281 return CYJavaUTF8String(value
);
284 JSStringRef
CYCopyJSString(const CYJavaRef
<jstring
> &value
) {
285 return CYCopyJSString(CYCastUTF8String(value
));
292 CYJavaGlobal
<jthrowable
> value_
;
294 CYJavaError(const CYJavaRef
<jthrowable
> &value
) :
299 virtual const char *PoolCString(CYPool
&pool
) const {
300 return CYPoolCString(pool
, CYJavaUTF8String(value_
.cast
<jobject
>()));
303 virtual JSValueRef
CastJSValue(JSContextRef context
, const char *name
) const;
310 CYJavaFrame(JNIEnv
*jni
, jint capacity
) :
313 _assert(jni
->PushLocalFrame(capacity
) == 0);
320 operator JNIEnv
*() const {
324 jobject
operator ()(jobject object
) {
327 return jni
->PopLocalFrame(object
);
336 CYJavaEnv(JNIEnv
*jni
) :
341 template <typename Other_
>
342 CYJavaEnv(const CYJavaRef
<Other_
> &value
) :
347 operator JNIEnv
*() const {
351 JNIEnv
*operator ->() const {
355 CYJavaLocal
<jclass
> FindClass(const char *name
) const {
356 return {jni
, _envcall(jni
, FindClass(name
))};
359 CYJavaLocal
<jclass
> GetObjectClass(jobject object
) const {
360 return {jni
, _envcall(jni
, GetObjectClass(object
))};
363 CYJavaLocal
<jclass
> GetSuperclass(jclass _class
) const {
364 return {jni
, _envcall(jni
, GetSuperclass(_class
))};
367 CYJavaLocal
<jobject
> NewObject(jclass _class
, jmethodID method
, ...) const {
369 va_start(args
, method
);
370 jobject
object(_envcall(jni
, NewObjectV(_class
, method
, args
)));
372 return {jni
, object
};
375 CYJavaLocal
<jobject
> NewObjectA(jclass _class
, jmethodID method
, jvalue
*args
) const {
376 return {jni
, _envcall(jni
, NewObjectA(_class
, method
, args
))};
379 CYJavaLocal
<jstring
> NewString(const jchar
*data
, jsize size
) const {
380 return {jni
, _envcall(jni
, NewString(data
, size
))};
383 #define CYJavaEnv_(Code) \
384 template <typename... Args_> \
385 void Code(Args_ &&... args) const { \
386 _envcallv(jni, Code(cy::Forward<Args_>(args)...)); \
389 #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \
390 CYJavaEnv_(Get ## Typ ## ArrayRegion) \
391 CYJavaEnv_(Set ## Typ ## Field) \
392 CYJavaEnv_(SetStatic ## Typ ## Field)
393 CYJavaForEachPrimitive
394 #undef CYJavaForEachPrimitive_
396 CYJavaEnv_(CallVoidMethod
)
397 CYJavaEnv_(CallStaticVoidMethod
)
398 CYJavaEnv_(CallVoidMethodA
)
399 CYJavaEnv_(CallStaticVoidMethodA
)
400 CYJavaEnv_(SetObjectArrayElement
)
401 CYJavaEnv_(SetObjectField
)
402 CYJavaEnv_(SetStaticObjectField
)
405 #define CYJavaEnv_(Code) \
406 template <typename... Args_> \
407 auto Code(Args_ &&... args) const -> decltype(jni->Code(cy::Forward<Args_>(args)...)) { \
408 return _envcall(jni, Code(cy::Forward<Args_>(args)...)); \
411 #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \
412 CYJavaEnv_(Call ## Typ ## Method) \
413 CYJavaEnv_(CallStatic ## Typ ## Method) \
414 CYJavaEnv_(Call ## Typ ## MethodA) \
415 CYJavaEnv_(CallStatic ## Typ ## MethodA) \
416 CYJavaEnv_(Get ## Typ ## Field) \
417 CYJavaEnv_(GetStatic ## Typ ## Field)
418 CYJavaForEachPrimitive
419 #undef CYJavaForEachPrimitive_
421 CYJavaEnv_(FromReflectedField
)
422 CYJavaEnv_(FromReflectedMethod
)
423 CYJavaEnv_(GetArrayLength
)
424 CYJavaEnv_(GetMethodID
)
425 CYJavaEnv_(GetStaticMethodID
)
426 CYJavaEnv_(IsSameObject
)
429 #define CYJavaEnv_(Code) \
430 template <typename Other_, typename... Args_> \
431 auto Code(Args_ &&... args) const -> CYJavaLocal<Other_> { \
432 return {jni, static_cast<Other_>(_envcall(jni, Code(cy::Forward<Args_>(args)...)))}; \
435 CYJavaEnv_(CallObjectMethod
)
436 CYJavaEnv_(CallStaticObjectMethod
)
437 CYJavaEnv_(CallObjectMethodA
)
438 CYJavaEnv_(CallStaticObjectMethodA
)
439 CYJavaEnv_(GetObjectArrayElement
)
440 CYJavaEnv_(GetObjectField
)
441 CYJavaEnv_(GetStaticObjectField
)
445 static CYJavaLocal
<jstring
> CYCastJavaString(const CYJavaRef
<jobject
> &value
) {
446 CYJavaEnv
jni(value
);
447 auto Object$
(jni
.FindClass("java/lang/Object"));
448 auto Object$
toString(jni
.GetMethodID(Object$
, "toString", "()Ljava/lang/String;"));
449 return jni
.CallObjectMethod
<jstring
>(value
, Object$toString
);
452 template <typename Internal_
, typename Value_
>
456 CYJavaGlobal
<Value_
> value_
;
458 CYJavaValue(const CYJavaRef
<Value_
> &value
) :
463 CYJavaValue(const CYJavaValue
&) = delete;
466 static JSValueRef
CYCastJSValue(JSContextRef context
, const CYJavaRef
<jobject
> &value
);
468 template <typename Other_
>
469 static _finline JSValueRef
CYCastJSValue(JSContextRef context
, const CYJavaRef
<Other_
> &value
) {
470 return CYCastJSValue(context
, value
.template cast
<jobject
>());
473 template <typename Type_
>
474 static _finline JSValueRef
CYJavaCastJSValue(JSContextRef context
, Type_ value
) {
475 return CYCastJSValue(context
, value
);
478 static _finline JSValueRef
CYJavaCastJSValue(JSContextRef context
, jboolean value
) {
479 return CYCastJSValue(context
, static_cast<bool>(value
));
482 JSValueRef
CYJavaError::CastJSValue(JSContextRef context
, const char *name
) const {
483 return CYCastJSValue(context
, value_
);
486 static std::map
<std::string
, CYJavaPrimitive
> Primitives_
;
488 static CYJavaPrimitive
CYJavaGetPrimitive(JSContextRef context
, const CYJavaRef
<jclass
> &type
, jmethodID Class$get$$Name
) {
490 auto string(jni
.CallObjectMethod
<jstring
>(type
, Class$get$$Name
));
493 CYJavaUTF8String
name(string
);
494 auto primitive(Primitives_
.find(name
));
495 return primitive
!= Primitives_
.end() ? primitive
->second
: CYJavaPrimitiveObject
;
498 typedef std::vector
<CYJavaPrimitive
> CYJavaShorty
;
500 static CYJavaShorty
CYJavaGetShorty(JSContextRef context
, const CYJavaRef
<jobjectArray
> &types
, jmethodID Class$get$$Name
) {
501 CYJavaEnv
jni(types
);
502 size_t count(jni
.GetArrayLength(types
));
503 CYJavaShorty
shorty(count
);
504 for (size_t index(0); index
!= count
; ++index
)
505 shorty
[index
] = CYJavaGetPrimitive(context
, jni
.GetObjectArrayElement
<jclass
>(types
, index
), Class$get$$Name
);
511 CYJavaPrimitive primitive_
;
514 typedef std::map
<std::string
, CYJavaField
> CYJavaFieldMap
;
516 struct CYJavaSignature
{
517 CYJavaGlobal
<jobject
> reflected_
;
519 CYJavaPrimitive primitive_
;
520 CYJavaShorty shorty_
;
522 CYJavaSignature(const CYJavaRef
<jobject
> &reflected
, jmethodID method
, CYJavaPrimitive primitive
, const CYJavaShorty
&shorty
) :
523 reflected_(reflected
),
525 primitive_(primitive
),
530 CYJavaSignature(unsigned count
) :
535 bool operator <(const CYJavaSignature
&rhs
) const {
536 return shorty_
.size() < rhs
.shorty_
.size();
540 typedef std::multiset
<CYJavaSignature
> CYJavaOverload
;
542 struct CYJavaMethod
:
543 CYPrivate
<CYJavaMethod
>
545 CYJavaOverload overload_
;
547 CYJavaMethod(const CYJavaOverload
&overload
) :
553 struct CYJavaStaticMethod
:
554 CYPrivate
<CYJavaStaticMethod
>
556 CYJavaOverload overload_
;
558 CYJavaStaticMethod(const CYJavaOverload
&overload
) :
565 CYJavaValue
<CYJavaClass
, jclass
>
569 CYJavaFieldMap static_
;
570 CYJavaFieldMap instance_
;
571 CYJavaOverload overload_
;
573 CYJavaClass(const CYJavaRef
<jclass
> &value
, bool interface
) :
575 interface_(interface
)
580 static JSObjectRef
CYGetJavaClass(JSContextRef context
, const CYJavaRef
<jclass
> &_class
);
582 struct CYJavaObject
:
583 CYJavaValue
<CYJavaObject
, jobject
>
587 CYJavaObject(const CYJavaRef
<jobject
> &value
, CYJavaClass
*table
) :
593 JSValueRef
GetPrototype(JSContextRef context
) const;
596 struct CYJavaInterior
:
597 CYJavaValue
<CYJavaInterior
, jobject
>
601 CYJavaInterior(const CYJavaRef
<jobject
> &value
, CYJavaClass
*table
) :
608 struct CYJavaStaticInterior
:
609 CYJavaValue
<CYJavaStaticInterior
, jclass
>
613 CYJavaStaticInterior(const CYJavaRef
<jclass
> &value
, CYJavaClass
*table
) :
621 CYJavaValue
<CYJavaArray
, jarray
>
623 CYJavaPrimitive primitive_
;
625 CYJavaArray(const CYJavaRef
<jarray
> &value
, CYJavaPrimitive primitive
) :
627 primitive_(primitive
)
631 JSValueRef
GetPrototype(JSContextRef context
) const;
634 struct CYJavaPackage
:
635 CYPrivate
<CYJavaPackage
>
637 typedef std::vector
<std::string
> Path
;
640 _finline
CYJavaPackage(const Path
&package
) :
646 JSValueRef
CYJavaObject::GetPrototype(JSContextRef context
) const {
647 CYJavaEnv
jni(value_
);
648 return CYGetProperty(context
, CYGetJavaClass(context
, jni
.GetObjectClass(value_
)), prototype_s
);
651 JSValueRef
CYJavaArray::GetPrototype(JSContextRef context
) const {
652 return CYGetCachedObject(context
, CYJSString("Array_prototype"));
655 static JSValueRef
CYCastJSValue(JSContextRef context
, const CYJavaRef
<jobject
> &value
) {
657 return CYJSNull(context
);
658 CYJavaEnv
jni(value
);
660 auto _class(jni
.GetObjectClass(value
));
661 if (jni
.IsSameObject(_class
, jni
.FindClass("java/lang/String")))
662 return CYCastJSValue(context
, CYJSString(value
.cast
<jstring
>()));
664 auto Class$
(jni
.FindClass("java/lang/Class"));
665 auto Class$
isArray(jni
.GetMethodID(Class$
, "isArray", "()Z"));
666 if (jni
.CallBooleanMethod(_class
, Class$isArray
)) {
667 auto Class$
getComponentType(jni
.GetMethodID(Class$
, "getComponentType", "()Ljava/lang/Class;"));
668 auto component(jni
.CallObjectMethod
<jclass
>(_class
, Class$getComponentType
));
669 auto Class$
getName(jni
.GetMethodID(Class$
, "getName", "()Ljava/lang/String;"));
670 return CYJavaArray::Make(context
, value
.cast
<jarray
>(), CYJavaGetPrimitive(context
, component
, Class$getName
));
673 auto Wrapper$
(jni
.FindClass("Cycript$Wrapper"));
674 if (jni
.IsSameObject(_class
, Wrapper$
)) {
675 auto Wrapper$
getProtect(jni
.GetMethodID(Wrapper$
, "getProtect", "()J"));
676 auto &protect(*reinterpret_cast<CYProtect
*>(jni
.CallLongMethod(value
, Wrapper$getProtect
)));
680 CYJavaClass
*table(reinterpret_cast<CYJavaClass
*>(JSObjectGetPrivate(CYGetJavaClass(context
, _class
))));
681 return CYJavaObject::Make(context
, value
, table
);
684 static _finline JSObjectRef
CYCastJSObject(JSContextRef context
, const CYJavaRef
<jobject
> &value
) {
685 return CYCastJSObject(context
, CYCastJSValue(context
, value
));
688 static CYJavaLocal
<jstring
> CYCastJavaString(const CYJavaEnv
&jni
, JSContextRef context
, CYUTF16String value
) {
689 return jni
.NewString(value
.data
, value
.size
);
692 static CYJavaLocal
<jstring
> CYCastJavaString(const CYJavaEnv
&jni
, JSContextRef context
, JSStringRef value
) {
693 return CYCastJavaString(jni
, context
, CYCastUTF16String(value
));
696 #define CYCastJava$(T, Type, jtype, Cast) \
697 _disused static CYJavaLocal<jobject> CYCastJava ## Type(const CYJavaEnv &jni, JSContextRef context, JSValueRef value) { \
698 auto Type$(jni.FindClass("java/lang/" #Type)); \
699 auto Type$init$(jni.GetMethodID(Type$, "<init>", "(" #T ")V")); \
700 return jni.NewObject(Type$, Type$init$, static_cast<jtype>(Cast(context, value))); \
703 CYCastJava$
(Z
, Boolean
, jboolean
, CYCastBool
)
704 CYCastJava$
(B
, Byte
, jbyte
, CYCastDouble
)
705 CYCastJava$
(C
, Character
, jchar
, CYCastDouble
)
706 CYCastJava$
(S
, Short
, jshort
, CYCastDouble
)
707 CYCastJava$
(I
, Integer
, jint
, CYCastDouble
)
708 CYCastJava$
(J
, Long
, jlong
, CYCastDouble
)
709 CYCastJava$
(F
, Float
, jfloat
, CYCastDouble
)
710 CYCastJava$
(D
, Double
, jdouble
, CYCastDouble
)
712 static CYJavaClass
*CYGetJavaTable(JSContextRef context
, JSObjectRef object
) {
713 if (!JSValueIsObjectOfClass(context
, object
, CYJavaClass::Class_
))
715 return reinterpret_cast<CYJavaClass
*>(JSObjectGetPrivate(object
));
718 static CYJavaObject
*CYGetJavaObject(JSContextRef context
, JSObjectRef object
) {
719 if (!JSValueIsObjectOfClass(context
, object
, CYJavaObject::Class_
))
721 return reinterpret_cast<CYJavaObject
*>(JSObjectGetPrivate(object
));
724 static CYJavaLocal
<jobject
> CYCastJavaObject(const CYJavaEnv
&jni
, JSContextRef context
, JSObjectRef value
) {
725 if (CYJavaObject
*internal
= CYGetJavaObject(context
, value
))
726 return internal
->value_
;
728 auto Wrapper$
(jni
.FindClass("Cycript$Wrapper"));
729 auto Wrapper$$init$
(jni
.GetMethodID(Wrapper$
, "<init>", "(J)V"));
730 CYProtect
*protect(new CYProtect(context
, value
));
731 return jni
.NewObject(Wrapper$
, Wrapper$$init$
, reinterpret_cast<jlong
>(protect
));
734 static CYJavaLocal
<jobject
> CYCastJavaObject(const CYJavaEnv
&jni
, JSContextRef context
, JSValueRef value
) {
735 switch (JSValueGetType(context
, value
)) {
739 return CYCastJavaBoolean(jni
, context
, value
);
741 return CYCastJavaDouble(jni
, context
, value
);
743 return CYCastJavaString(jni
, context
, CYJSString(context
, value
));
745 return CYCastJavaObject(jni
, context
, CYCastJSObject(context
, value
));
747 case kJSTypeUndefined
:
748 // XXX: I am currently relying on this for dynamic proxy of void method
755 static JSObjectRef
CYGetJavaClass(JSContextRef context
, const CYJavaRef
<jclass
> &value
) {
756 CYJavaEnv
jni(value
);
757 CYJavaFrame
frame(jni
, 64);
759 JSObjectRef
global(CYGetGlobalObject(context
));
760 JSObjectRef
cy(CYCastJSObject(context
, CYGetProperty(context
, global
, cy_s
)));
762 auto Class$
(jni
.FindClass("java/lang/Class"));
763 auto Class$
getName(jni
.GetMethodID(Class$
, "getName", "()Ljava/lang/String;"));
765 CYJSString
name(jni
.CallObjectMethod
<jstring
>(value
, Class$getName
));
766 JSValueRef
cached(CYGetProperty(context
, cy
, name
));
767 if (!JSValueIsUndefined(context
, cached
))
768 return CYCastJSObject(context
, cached
);
770 JSObjectRef constructor
;
771 JSObjectRef prototype
;
775 auto Class$
isInterface(jni
.GetMethodID(Class$
, "isInterface", "()Z"));
777 auto Class$
getDeclaredConstructors(jni
.GetMethodID(Class$
, "getDeclaredConstructors", "()[Ljava/lang/reflect/Constructor;"));
778 auto Class$
getDeclaredFields(jni
.GetMethodID(Class$
, "getDeclaredFields", "()[Ljava/lang/reflect/Field;"));
779 auto Class$
getDeclaredMethods(jni
.GetMethodID(Class$
, "getDeclaredMethods", "()[Ljava/lang/reflect/Method;"));
781 auto Constructor$
(jni
.FindClass("java/lang/reflect/Constructor"));
782 //auto Constructor$getModifiers(jni.GetMethodID(Constructor$, "getModifiers", "()I"));
783 auto Constructor$
getParameterTypes(jni
.GetMethodID(Constructor$
, "getParameterTypes", "()[Ljava/lang/Class;"));
785 auto Field$
(jni
.FindClass("java/lang/reflect/Field"));
786 auto Field$
getModifiers(jni
.GetMethodID(Field$
, "getModifiers", "()I"));
787 auto Field$
getName(jni
.GetMethodID(Field$
, "getName", "()Ljava/lang/String;"));
788 auto Field$
getType(jni
.GetMethodID(Field$
, "getType", "()Ljava/lang/Class;"));
790 auto Method$
(jni
.FindClass("java/lang/reflect/Method"));
791 auto Method$
getModifiers(jni
.GetMethodID(Method$
, "getModifiers", "()I"));
792 auto Method$
getName(jni
.GetMethodID(Method$
, "getName", "()Ljava/lang/String;"));
793 auto Method$
getParameterTypes(jni
.GetMethodID(Method$
, "getParameterTypes", "()[Ljava/lang/Class;"));
794 auto Method$
getReturnType(jni
.GetMethodID(Method$
, "getReturnType", "()Ljava/lang/Class;"));
796 auto Modifier$
(jni
.FindClass("java/lang/reflect/Modifier"));
797 auto Modifier$
isStatic(jni
.GetStaticMethodID(Modifier$
, "isStatic", "(I)Z"));
799 auto interface(jni
.CallBooleanMethod(value
, Class$isInterface
));
800 auto table(new CYJavaClass(value
, interface
));
802 for (CYJavaLocal
<jclass
> prototype(value
); prototype
; prototype
= jni
.GetSuperclass(prototype
)) {
803 auto fields(jni
.CallObjectMethod
<jobjectArray
>(prototype
, Class$getDeclaredFields
));
805 for (jsize
i(0), e(jni
.GetArrayLength(fields
)); i
!= e
; ++i
) {
806 auto field(jni
.GetObjectArrayElement
<jobject
>(fields
, e
- i
- 1));
807 auto modifiers(jni
.CallIntMethod(field
, Field$getModifiers
));
808 auto instance(!jni
.CallStaticBooleanMethod(Modifier$
, Modifier$isStatic
, modifiers
));
809 auto &map(instance
? table
->instance_
: table
->static_
);
810 CYJavaUTF8String
name(jni
.CallObjectMethod
<jstring
>(field
, Field$getName
));
811 auto id(jni
.FromReflectedField(field
));
812 auto type(jni
.CallObjectMethod
<jclass
>(field
, Field$getType
));
813 map
.insert(std::make_pair(std::string(name
), CYJavaField
{id
, CYJavaGetPrimitive(context
, type
, Class$getName
)}));
817 constructor
= JSObjectMake(context
, CYJavaClass::Class_
, table
);
819 prototype
= JSObjectMake(context
, NULL
, NULL
);
820 CYSetProperty(context
, constructor
, prototype_s
, prototype
, kJSPropertyAttributeDontEnum
);
822 auto constructors(jni
.CallObjectMethod
<jobjectArray
>(value
, Class$getDeclaredConstructors
));
824 for (jsize
i(0), e(jni
.GetArrayLength(constructors
)); i
!= e
; ++i
) {
825 auto constructor(jni
.GetObjectArrayElement
<jobject
>(constructors
, i
));
826 auto parameters(jni
.CallObjectMethod
<jobjectArray
>(constructor
, Constructor$getParameterTypes
));
827 CYJavaShorty
shorty(CYJavaGetShorty(context
, parameters
, Class$getName
));
828 auto id(jni
.FromReflectedMethod(constructor
));
829 table
->overload_
.insert(CYJavaSignature(constructor
, id
, CYJavaPrimitiveObject
, shorty
));
832 auto methods(jni
.CallObjectMethod
<jobjectArray
>(value
, Class$getDeclaredMethods
));
834 std::map
<std::pair
<bool, std::string
>, CYJavaOverload
> entries
;
836 for (jsize
i(0), e(jni
.GetArrayLength(methods
)); i
!= e
; ++i
) {
837 auto method(jni
.GetObjectArrayElement
<jobject
>(methods
, i
));
838 auto modifiers(jni
.CallIntMethod(method
, Method$getModifiers
));
839 auto instance(!jni
.CallStaticBooleanMethod(Modifier$
, Modifier$isStatic
, modifiers
));
840 CYJavaUTF8String
name(jni
.CallObjectMethod
<jstring
>(method
, Method$getName
));
841 auto parameters(jni
.CallObjectMethod
<jobjectArray
>(method
, Method$getParameterTypes
));
842 CYJavaShorty
shorty(CYJavaGetShorty(context
, parameters
, Class$getName
));
843 auto type(jni
.CallObjectMethod
<jclass
>(method
, Method$getReturnType
));
844 auto primitive(CYJavaGetPrimitive(context
, type
, Class$getName
));
845 auto id(jni
.FromReflectedMethod(method
));
846 entries
[std::make_pair(instance
, std::string(name
))].insert(CYJavaSignature(method
, id
, primitive
, shorty
));
849 for (const auto &entry
: entries
) {
850 bool instance(entry
.first
.first
);
851 CYJSString
name(entry
.first
.second
);
852 auto &overload(entry
.second
);
854 CYSetProperty(context
, prototype
, name
, CYJavaMethod::Make(context
, overload
), kJSPropertyAttributeDontEnum
| kJSPropertyAttributeDontDelete
);
856 CYSetProperty(context
, constructor
, name
, CYJavaStaticMethod::Make(context
, overload
), kJSPropertyAttributeDontEnum
| kJSPropertyAttributeDontDelete
);
861 // XXX: for some reason kJSPropertyAttributeDontEnum doesn't work if there's already a property with the same name
862 // by not linking the prototypes until after we set the properties, we hide the parent property from this issue :(
864 if (auto super
= jni
.GetSuperclass(value
)) {
865 JSObjectRef
parent(CYGetJavaClass(context
, super
));
866 CYSetPrototype(context
, constructor
, parent
);
867 CYSetPrototype(context
, prototype
, CYGetProperty(context
, parent
, prototype_s
));
870 CYSetProperty(context
, cy
, name
, constructor
);
874 static void CYCastJavaNumeric(jvalue
&value
, CYJavaPrimitive primitive
, JSContextRef context
, JSValueRef argument
) {
876 #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \
877 case CYJavaPrimitive ## Type: \
878 value.t = static_cast<j ## type>(CYCastDouble(context, argument)); \
880 CYJavaForEachPrimitive
881 #undef CYJavaForEachPrimitive_
887 static bool CYCastJavaArguments(const CYJavaFrame
&frame
, const CYJavaShorty
&shorty
, JSContextRef context
, const JSValueRef arguments
[], jvalue
*array
) {
888 CYJavaEnv
jni(frame
);
890 for (size_t index(0); index
!= shorty
.size(); ++index
) {
891 JSValueRef
argument(arguments
[index
]);
892 JSType
type(JSValueGetType(context
, argument
));
893 jvalue
&value(array
[index
]);
895 switch (CYJavaPrimitive primitive
= shorty
[index
]) {
896 case CYJavaPrimitiveObject
:
897 // XXX: figure out a way to tie this in to the CYJavaFrame
898 value
.l
= CYCastJavaObject(jni
, context
, argument
).leak();
901 case CYJavaPrimitiveBoolean
:
902 if (type
!= kJSTypeBoolean
)
904 value
.z
= CYCastBool(context
, argument
);
907 case CYJavaPrimitiveCharacter
:
908 if (type
== kJSTypeNumber
)
909 CYCastJavaNumeric(value
, primitive
, context
, argument
);
910 else if (type
!= kJSTypeString
)
913 CYJSString
string(context
, argument
);
914 if (JSStringGetLength(string
) != 1)
917 value
.c
= JSStringGetCharactersPtr(string
)[0];
921 case CYJavaPrimitiveByte
:
922 case CYJavaPrimitiveShort
:
923 case CYJavaPrimitiveInteger
:
924 case CYJavaPrimitiveLong
:
925 case CYJavaPrimitiveFloat
:
926 case CYJavaPrimitiveDouble
:
927 if (type
!= kJSTypeNumber
)
929 CYCastJavaNumeric(value
, primitive
, context
, argument
);
940 static JSValueRef
JavaMethod_callAsFunction(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef
*exception
) { CYTry
{
941 CYJavaMethod
*internal(reinterpret_cast<CYJavaMethod
*>(JSObjectGetPrivate(object
)));
942 CYJavaObject
*self(CYGetJavaObject(context
, _this
));
943 CYJavaEnv
jni(self
->value_
);
945 CYJavaSignature
bound(count
);
946 for (auto overload(internal
->overload_
.lower_bound(bound
)), e(internal
->overload_
.upper_bound(bound
)); overload
!= e
; ++overload
) {
947 CYJavaFrame
frame(jni
, count
+ 16);
949 if (!CYCastJavaArguments(frame
, overload
->shorty_
, context
, arguments
, array
))
951 jvalue
*values(array
);
952 switch (overload
->primitive_
) {
953 case CYJavaPrimitiveObject
:
954 return CYCastJSValue(context
, jni
.CallObjectMethodA
<jobject
>(self
->value_
, overload
->method_
, values
));
955 case CYJavaPrimitiveVoid
:
956 jni
.CallVoidMethodA(self
->value_
, overload
->method_
, values
);
957 return CYJSUndefined(context
);
958 #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \
959 case CYJavaPrimitive ## Type: \
960 return CYJavaCastJSValue(context, jni.Call ## Typ ## MethodA(self->value_, overload->method_, values));
961 CYJavaForEachPrimitive
962 #undef CYJavaForEachPrimitive_
963 default: _assert(false);
967 CYThrow("invalid method call");
970 static JSValueRef
JavaStaticMethod_callAsFunction(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef
*exception
) { CYTry
{
971 CYJavaMethod
*internal(reinterpret_cast<CYJavaMethod
*>(JSObjectGetPrivate(object
)));
972 CYJavaClass
*table(CYGetJavaTable(context
, _this
));
973 CYJavaEnv
jni(table
->value_
);
975 CYJavaSignature
bound(count
);
976 for (auto overload(internal
->overload_
.lower_bound(bound
)), e(internal
->overload_
.upper_bound(bound
)); overload
!= e
; ++overload
) {
977 CYJavaFrame
frame(jni
, count
+ 16);
979 if (!CYCastJavaArguments(frame
, overload
->shorty_
, context
, arguments
, array
))
981 jvalue
*values(array
);
982 switch (overload
->primitive_
) {
983 case CYJavaPrimitiveObject
:
984 return CYCastJSValue(context
, jni
.CallStaticObjectMethodA
<jobject
>(table
->value_
, overload
->method_
, values
));
985 case CYJavaPrimitiveVoid
:
986 jni
.CallStaticVoidMethodA(table
->value_
, overload
->method_
, values
);
987 return CYJSUndefined(context
);
988 #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \
989 case CYJavaPrimitive ## Type: \
990 return CYJavaCastJSValue(context, jni.CallStatic ## Typ ## MethodA(table->value_, overload->method_, values));
991 CYJavaForEachPrimitive
992 #undef CYJavaForEachPrimitive_
993 default: _assert(false);
997 CYThrow("invalid method call");
1000 static JSObjectRef
JavaClass_callAsConstructor(JSContextRef context
, JSObjectRef object
, size_t count
, const JSValueRef arguments
[], JSValueRef
*exception
) { CYTry
{
1001 CYJavaClass
*table(reinterpret_cast<CYJavaClass
*>(JSObjectGetPrivate(object
)));
1002 CYJavaEnv
jni(table
->value_
);
1003 jclass
_class(table
->value_
);
1005 if (table
->interface_
&& count
== 1) {
1006 auto Cycript$
(jni
.FindClass("Cycript"));
1007 auto Cycript$
Make(jni
.GetStaticMethodID(Cycript$
, "proxy", "(Ljava/lang/Class;LCycript$Wrapper;)Ljava/lang/Object;"));
1008 return CYCastJSObject(context
, jni
.CallObjectMethod
<jobject
>(Cycript$
, Cycript$Make
, _class
, CYCastJavaObject(jni
, context
, CYCastJSObject(context
, arguments
[0])).get()));
1011 CYJavaSignature
bound(count
);
1012 for (auto overload(table
->overload_
.lower_bound(bound
)), e(table
->overload_
.upper_bound(bound
)); overload
!= e
; ++overload
) {
1013 CYJavaFrame
frame(jni
, count
+ 16);
1014 jvalue array
[count
];
1015 if (!CYCastJavaArguments(frame
, overload
->shorty_
, context
, arguments
, array
))
1017 jvalue
*values(array
);
1018 auto object(jni
.NewObjectA(_class
, overload
->method_
, values
));
1019 return CYCastJSObject(context
, object
);
1022 CYThrow("invalid constructor call");
1025 static bool JavaStaticInterior_hasProperty(JSContextRef context
, JSObjectRef object
, JSStringRef property
) {
1026 CYJavaStaticInterior
*internal(reinterpret_cast<CYJavaStaticInterior
*>(JSObjectGetPrivate(object
)));
1027 CYJavaClass
*table(internal
->table_
);
1029 auto name(CYPoolUTF8String(pool
, context
, property
));
1030 auto field(table
->static_
.find(name
));
1031 if (field
== table
->static_
.end())
1036 static JSValueRef
JavaStaticInterior_getProperty(JSContextRef context
, JSObjectRef object
, JSStringRef property
, JSValueRef
*exception
) { CYTry
{
1037 CYJavaStaticInterior
*internal(reinterpret_cast<CYJavaStaticInterior
*>(JSObjectGetPrivate(object
)));
1038 CYJavaClass
*table(internal
->table_
);
1039 CYJavaEnv
jni(table
->value_
);
1041 auto name(CYPoolUTF8String(pool
, context
, property
));
1042 auto field(table
->static_
.find(name
));
1043 if (field
== table
->static_
.end())
1046 switch (field
->second
.primitive_
) {
1047 case CYJavaPrimitiveObject
:
1048 return CYCastJSValue(context
, jni
.GetStaticObjectField
<jobject
>(table
->value_
, field
->second
.field_
));
1049 #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \
1050 case CYJavaPrimitive ## Type: \
1051 return CYJavaCastJSValue(context, jni.GetStatic ## Typ ## Field(table->value_, field->second.field_));
1052 CYJavaForEachPrimitive
1053 #undef CYJavaForEachPrimitive_
1054 default: _assert(false);
1058 static bool JavaStaticInterior_setProperty(JSContextRef context
, JSObjectRef object
, JSStringRef property
, JSValueRef value
, JSValueRef
*exception
) { CYTry
{
1059 CYJavaStaticInterior
*internal(reinterpret_cast<CYJavaStaticInterior
*>(JSObjectGetPrivate(object
)));
1060 CYJavaClass
*table(internal
->table_
);
1061 CYJavaEnv
jni(table
->value_
);
1063 auto name(CYPoolUTF8String(pool
, context
, property
));
1064 auto field(table
->static_
.find(name
));
1065 if (field
== table
->static_
.end())
1068 switch (field
->second
.primitive_
) {
1069 case CYJavaPrimitiveObject
:
1070 jni
.SetStaticObjectField(table
->value_
, field
->second
.field_
, CYCastJavaObject(jni
, context
, value
));
1071 #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \
1072 case CYJavaPrimitive ## Type: \
1073 jni.SetStatic ## Typ ## Field(table->value_, field->second.field_, CYCastDouble(context, value)); \
1075 CYJavaForEachPrimitive
1076 #undef CYJavaForEachPrimitive_
1077 default: _assert(false);
1083 static void JavaStaticInterior_getPropertyNames(JSContextRef context
, JSObjectRef object
, JSPropertyNameAccumulatorRef names
) {
1084 CYJavaStaticInterior
*internal(reinterpret_cast<CYJavaStaticInterior
*>(JSObjectGetPrivate(object
)));
1085 CYJavaClass
*table(internal
->table_
);
1086 for (const auto &field
: table
->static_
)
1087 JSPropertyNameAccumulatorAddName(names
, CYJSString(field
.first
));
1090 static JSValueRef
JavaClass_getProperty_class(JSContextRef context
, JSObjectRef object
, JSStringRef property
, JSValueRef
*exception
) { CYTry
{
1091 CYJavaClass
*table(reinterpret_cast<CYJavaClass
*>(JSObjectGetPrivate(object
)));
1092 return CYCastJSValue(context
, table
->value_
);
1095 static bool JavaInterior_hasProperty(JSContextRef context
, JSObjectRef object
, JSStringRef property
) {
1096 CYJavaInterior
*internal(reinterpret_cast<CYJavaInterior
*>(JSObjectGetPrivate(object
)));
1097 CYJavaClass
*table(internal
->table_
);
1099 auto name(CYPoolUTF8String(pool
, context
, property
));
1100 auto field(table
->instance_
.find(name
));
1101 if (field
== table
->instance_
.end())
1106 static JSValueRef
JavaInterior_getProperty(JSContextRef context
, JSObjectRef object
, JSStringRef property
, JSValueRef
*exception
) { CYTry
{
1107 CYJavaInterior
*internal(reinterpret_cast<CYJavaInterior
*>(JSObjectGetPrivate(object
)));
1108 CYJavaEnv
jni(internal
->value_
);
1109 CYJavaClass
*table(internal
->table_
);
1111 auto name(CYPoolUTF8String(pool
, context
, property
));
1112 auto field(table
->instance_
.find(name
));
1113 if (field
== table
->instance_
.end())
1116 switch (field
->second
.primitive_
) {
1117 case CYJavaPrimitiveObject
:
1118 return CYCastJSValue(context
, jni
.GetObjectField
<jobject
>(internal
->value_
, field
->second
.field_
));
1119 #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \
1120 case CYJavaPrimitive ## Type: \
1121 return CYJavaCastJSValue(context, jni.Get ## Typ ## Field(internal->value_, field->second.field_));
1122 CYJavaForEachPrimitive
1123 #undef CYJavaForEachPrimitive_
1124 default: _assert(false);
1128 static bool JavaInterior_setProperty(JSContextRef context
, JSObjectRef object
, JSStringRef property
, JSValueRef value
, JSValueRef
*exception
) { CYTry
{
1129 CYJavaInterior
*internal(reinterpret_cast<CYJavaInterior
*>(JSObjectGetPrivate(object
)));
1130 CYJavaEnv
jni(internal
->value_
);
1131 CYJavaClass
*table(internal
->table_
);
1133 auto name(CYPoolUTF8String(pool
, context
, property
));
1134 auto field(table
->instance_
.find(name
));
1135 if (field
== table
->instance_
.end())
1138 switch (field
->second
.primitive_
) {
1139 case CYJavaPrimitiveObject
:
1140 jni
.SetObjectField(table
->value_
, field
->second
.field_
, CYCastJavaObject(jni
, context
, value
));
1141 #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \
1142 case CYJavaPrimitive ## Type: \
1143 jni.Set ## Typ ## Field(table->value_, field->second.field_, CYCastDouble(context, value)); \
1145 CYJavaForEachPrimitive
1146 #undef CYJavaForEachPrimitive_
1147 default: _assert(false);
1153 static void JavaInterior_getPropertyNames(JSContextRef context
, JSObjectRef object
, JSPropertyNameAccumulatorRef names
) {
1154 CYJavaInterior
*internal(reinterpret_cast<CYJavaInterior
*>(JSObjectGetPrivate(object
)));
1155 CYJavaClass
*table(internal
->table_
);
1156 for (const auto &field
: table
->instance_
)
1157 JSPropertyNameAccumulatorAddName(names
, CYJSString(field
.first
));
1160 static JSValueRef
JavaObject_getProperty_constructor(JSContextRef context
, JSObjectRef object
, JSStringRef property
, JSValueRef
*exception
) { CYTry
{
1161 CYJavaObject
*internal(reinterpret_cast<CYJavaObject
*>(JSObjectGetPrivate(object
)));
1162 CYJavaEnv
jni(internal
->value_
);
1163 return CYGetJavaClass(context
, jni
.GetObjectClass(internal
->value_
));
1166 static JSValueRef JavaClass_getProperty_$
cyi(JSContextRef context
, JSObjectRef object
, JSStringRef property
, JSValueRef
*exception
) { CYTry
{
1167 CYJavaClass
*internal(reinterpret_cast<CYJavaClass
*>(JSObjectGetPrivate(object
)));
1168 return CYJavaStaticInterior::Make(context
, internal
->value_
, internal
);
1171 static JSValueRef JavaObject_getProperty_$
cyi(JSContextRef context
, JSObjectRef object
, JSStringRef property
, JSValueRef
*exception
) { CYTry
{
1172 CYJavaObject
*internal(reinterpret_cast<CYJavaObject
*>(JSObjectGetPrivate(object
)));
1173 return CYJavaInterior::Make(context
, internal
->value_
, internal
->table_
);
1176 static JSValueRef
JavaClass_callAsFunction_toCYON(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef
*exception
) { CYTry
{
1177 CYJavaClass
*internal(reinterpret_cast<CYJavaClass
*>(JSObjectGetPrivate(_this
)));
1178 CYJavaEnv
jni(internal
->value_
);
1179 auto Class$
(jni
.FindClass("java/lang/Class"));
1180 auto Class$
getCanonicalName(jni
.GetMethodID(Class$
, "getCanonicalName", "()Ljava/lang/String;"));
1181 return CYCastJSValue(context
, CYJSString(jni
.CallObjectMethod
<jstring
>(internal
->value_
, Class$getCanonicalName
)));
1184 static JSValueRef
JavaMethod_callAsFunction_toCYON(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef
*exception
) { CYTry
{
1185 std::ostringstream cyon
;
1186 return CYCastJSValue(context
, CYJSString(cyon
.str()));
1189 static JSValueRef
JavaStaticMethod_callAsFunction_toCYON(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef
*exception
) { CYTry
{
1190 std::ostringstream cyon
;
1191 return CYCastJSValue(context
, CYJSString(cyon
.str()));
1194 static JSValueRef
JavaArray_getProperty(JSContextRef context
, JSObjectRef object
, JSStringRef property
, JSValueRef
*exception
) { CYTry
{
1195 CYJavaArray
*internal(reinterpret_cast<CYJavaArray
*>(JSObjectGetPrivate(object
)));
1196 CYJavaEnv
jni(internal
->value_
);
1197 if (JSStringIsEqual(property
, length_s
))
1198 return CYCastJSValue(context
, jni
.GetArrayLength(internal
->value_
));
1202 if (!CYGetOffset(pool
, context
, property
, offset
))
1205 if (internal
->primitive_
== CYJavaPrimitiveObject
)
1206 return CYCastJSValue(context
, jni
.GetObjectArrayElement
<jobject
>(static_cast<jobjectArray
>(internal
->value_
.value_
), offset
));
1207 else switch (internal
->primitive_
) {
1208 #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \
1209 case CYJavaPrimitive ## Type: { \
1210 j ## type element; \
1211 jni.Get ## Typ ## ArrayRegion(static_cast<j ## type ## Array>(internal->value_.value_), offset, 1, &element); \
1212 return CYJavaCastJSValue(context, element); \
1214 CYJavaForEachPrimitive
1215 #undef CYJavaForEachPrimitive_
1216 default: _assert(false);
1220 static bool JavaArray_setProperty(JSContextRef context
, JSObjectRef object
, JSStringRef property
, JSValueRef value
, JSValueRef
*exception
) { CYTry
{
1221 CYJavaArray
*internal(reinterpret_cast<CYJavaArray
*>(JSObjectGetPrivate(object
)));
1222 CYJavaEnv
jni(internal
->value_
);
1226 if (!CYGetOffset(pool
, context
, property
, offset
))
1229 if (internal
->primitive_
== CYJavaPrimitiveObject
)
1230 jni
.SetObjectArrayElement(static_cast<jobjectArray
>(internal
->value_
.value_
), offset
, CYCastJavaObject(jni
, context
, value
));
1231 else switch (internal
->primitive_
) {
1232 #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \
1233 case CYJavaPrimitive ## Type: { \
1234 j ## type element; \
1235 jni.Get ## Typ ## ArrayRegion(static_cast<j ## type ## Array>(internal->value_.value_), offset, 1, &element); \
1236 return CYJavaCastJSValue(context, element); \
1238 CYJavaForEachPrimitive
1239 #undef CYJavaForEachPrimitive_
1240 default: _assert(false);
1246 static JSValueRef
JavaPackage_callAsFunction_toCYON(JSContextRef context
, JSObjectRef object
, JSObjectRef _this
, size_t count
, const JSValueRef arguments
[], JSValueRef
*exception
) { CYTry
{
1247 CYJavaPackage
*internal(reinterpret_cast<CYJavaPackage
*>(JSObjectGetPrivate(_this
)));
1248 std::ostringstream name
;
1249 for (auto &package
: internal
->package_
)
1250 name
<< package
<< '.';
1252 return CYCastJSValue(context
, CYJSString(name
.str()));
1255 static bool CYJavaPackage_hasProperty(JSContextRef context
, JSObjectRef object
, JSStringRef property
) {
1259 static JSValueRef
CYJavaPackage_getProperty(JSContextRef context
, JSObjectRef object
, JSStringRef property
, JSValueRef
*exception
) { CYTry
{
1260 CYJavaPackage
*internal(reinterpret_cast<CYJavaPackage
*>(JSObjectGetPrivate(object
)));
1261 CYJavaPackage::Path
package(internal
->package_
);
1264 const char *next(CYPoolCString(pool
, context
, property
));
1266 std::ostringstream name
;
1267 for (auto &package
: internal
->package_
)
1268 name
<< package
<< '/';
1271 JNIEnv
*jni(GetJNI(context
));
1272 if (auto _class
= jni
->FindClass(name
.str().c_str()))
1273 return CYGetJavaClass(context
, CYJavaLocal
<jclass
>(jni
, _class
));
1274 jni
->ExceptionClear();
1276 package
.push_back(next
);
1277 return CYJavaPackage::Make(context
, package
);
1280 static void Cycript_delete(JNIEnv
*env
, jclass api
, jlong jprotect
) { CYJavaTry
{
1284 static jobject
Cycript_handle(JNIEnv
*env
, jclass api
, jlong jprotect
, jstring property
, jobjectArray jarguments
) { CYJavaTry
{
1285 JSValueRef
function(CYGetProperty(context
, object
, CYJSString(CYJavaRef
<jstring
>(jni
, property
))));
1286 if (JSValueIsUndefined(context
, function
))
1289 size_t count(jarguments
== NULL
? 0 : jni
.GetArrayLength(jarguments
));
1290 JSValueRef arguments
[count
];
1291 for (size_t index(0); index
!= count
; ++index
)
1292 arguments
[index
] = CYCastJSValue(context
, jni
.GetObjectArrayElement
<jobject
>(jarguments
, index
));
1294 return CYCastJavaObject(jni
, context
, CYCallAsFunction(context
, CYCastJSObject(context
, function
), object
, count
, arguments
)).leak();
1295 } CYJavaCatch(NULL
) }
1297 static JNINativeMethod Cycript_
[] = {
1298 {(char *) "delete", (char *) "(J)V", (void *) &Cycript_delete
},
1299 {(char *) "handle", (char *) "(JLjava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;", (void *) &Cycript_handle
},
1302 JNIEnv
*GetJNI(JSContextRef context
) {
1303 static JavaVM
*jvm(NULL
);
1304 static JNIEnv
*jni(NULL
);
1308 jint
version(JNI_VERSION_1_4
);
1311 JavaVM
*jvms
[capacity
];
1313 _jnicall(JNI_GetCreatedJavaVMs(jvms
, capacity
, &size
));
1317 _jnicall(jvm
->GetEnv(reinterpret_cast<void **>(&jni
), version
));
1320 std::vector
<JavaVMOption
> options
;
1323 std::ostringstream option
;
1324 option
<< "-Djava.class.path=";
1325 option
<< CYPoolLibraryPath(pool
) << "/libcycript.jar";
1326 if (const char *classpath
= getenv("CLASSPATH"))
1327 option
<< ':' << classpath
;
1328 options
.push_back(JavaVMOption
{pool
.strdup(option
.str().c_str()), NULL
});
1331 JavaVMInitArgs args
;
1332 memset(&args
, 0, sizeof(args
));
1333 args
.version
= version
;
1334 args
.nOptions
= options
.size();
1335 args
.options
= options
.data();
1336 _jnicall(JNI_CreateJavaVM(&jvm
, reinterpret_cast<void **>(&jni
), &args
));
1339 auto Cycript$
(CYJavaEnv(jni
).FindClass("Cycript"));
1340 _envcall(jni
, RegisterNatives(Cycript$
, Cycript_
, sizeof(Cycript_
) / sizeof(Cycript_
[0])));
1345 static JSStaticValue JavaClass_staticValues
[3] = {
1346 {"class", &JavaClass_getProperty_class
, NULL
, kJSPropertyAttributeReadOnly
| kJSPropertyAttributeDontEnum
| kJSPropertyAttributeDontDelete
},
1347 {"$cyi", &JavaClass_getProperty_$cyi
, NULL
, kJSPropertyAttributeReadOnly
| kJSPropertyAttributeDontEnum
| kJSPropertyAttributeDontDelete
},
1348 {NULL
, NULL
, NULL
, 0}
1351 static JSStaticFunction JavaClass_staticFunctions
[2] = {
1352 {"toCYON", &JavaClass_callAsFunction_toCYON
, kJSPropertyAttributeDontEnum
| kJSPropertyAttributeDontDelete
},
1356 static JSStaticValue JavaObject_staticValues
[3] = {
1357 {"constructor", &JavaObject_getProperty_constructor
, NULL
, kJSPropertyAttributeReadOnly
| kJSPropertyAttributeDontEnum
| kJSPropertyAttributeDontDelete
},
1358 {"$cyi", &JavaObject_getProperty_$cyi
, NULL
, kJSPropertyAttributeReadOnly
| kJSPropertyAttributeDontEnum
| kJSPropertyAttributeDontDelete
},
1359 {NULL
, NULL
, NULL
, 0}
1362 static JSStaticFunction JavaMethod_staticFunctions
[2] = {
1363 {"toCYON", &JavaMethod_callAsFunction_toCYON
, kJSPropertyAttributeDontEnum
| kJSPropertyAttributeDontDelete
},
1367 static JSStaticFunction JavaStaticMethod_staticFunctions
[2] = {
1368 {"toCYON", &JavaStaticMethod_callAsFunction_toCYON
, kJSPropertyAttributeDontEnum
| kJSPropertyAttributeDontDelete
},
1372 static JSStaticFunction JavaPackage_staticFunctions
[2] = {
1373 {"toCYON", &JavaPackage_callAsFunction_toCYON
, kJSPropertyAttributeDontEnum
| kJSPropertyAttributeDontDelete
},
1377 void CYJava_Initialize() {
1378 Primitives_
.insert(std::make_pair("void", CYJavaPrimitiveVoid
));
1379 #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \
1380 Primitives_.insert(std::make_pair(#type, CYJavaPrimitive ## Type));
1381 CYJavaForEachPrimitive
1382 #undef CYJavaForEachPrimitive_
1384 JSClassDefinition definition
;
1386 definition
= kJSClassDefinitionEmpty
;
1387 definition
.className
= "JavaClass";
1388 definition
.staticValues
= JavaClass_staticValues
;
1389 definition
.staticFunctions
= JavaClass_staticFunctions
;
1390 definition
.callAsConstructor
= &JavaClass_callAsConstructor
;
1391 definition
.finalize
= &CYFinalize
;
1392 CYJavaClass::Class_
= JSClassCreate(&definition
);
1394 definition
= kJSClassDefinitionEmpty
;
1395 definition
.attributes
= kJSClassAttributeNoAutomaticPrototype
;
1396 definition
.className
= "JavaInterior";
1397 definition
.hasProperty
= &JavaInterior_hasProperty
;
1398 definition
.getProperty
= &JavaInterior_getProperty
;
1399 definition
.setProperty
= &JavaInterior_setProperty
;
1400 definition
.getPropertyNames
= &JavaInterior_getPropertyNames
;
1401 definition
.finalize
= &CYFinalize
;
1402 CYJavaInterior::Class_
= JSClassCreate(&definition
);
1404 definition
= kJSClassDefinitionEmpty
;
1405 definition
.className
= "JavaMethod";
1406 definition
.staticFunctions
= JavaMethod_staticFunctions
;
1407 definition
.callAsFunction
= &JavaMethod_callAsFunction
;
1408 definition
.finalize
= &CYFinalize
;
1409 CYJavaMethod::Class_
= JSClassCreate(&definition
);
1411 definition
= kJSClassDefinitionEmpty
;
1412 definition
.className
= "JavaStaticMethod";
1413 definition
.staticFunctions
= JavaStaticMethod_staticFunctions
;
1414 definition
.callAsFunction
= &JavaStaticMethod_callAsFunction
;
1415 definition
.finalize
= &CYFinalize
;
1416 CYJavaStaticMethod::Class_
= JSClassCreate(&definition
);
1418 definition
= kJSClassDefinitionEmpty
;
1419 definition
.attributes
= kJSClassAttributeNoAutomaticPrototype
;
1420 definition
.className
= "JavaObject";
1421 definition
.staticValues
= JavaObject_staticValues
;
1422 definition
.finalize
= &CYFinalize
;
1423 CYJavaObject::Class_
= JSClassCreate(&definition
);
1425 definition
= kJSClassDefinitionEmpty
;
1426 definition
.className
= "JavaArray";
1427 definition
.getProperty
= &JavaArray_getProperty
;
1428 definition
.setProperty
= &JavaArray_setProperty
;
1429 definition
.finalize
= &CYFinalize
;
1430 CYJavaArray::Class_
= JSClassCreate(&definition
);
1432 definition
= kJSClassDefinitionEmpty
;
1433 definition
.className
= "JavaPackage";
1434 definition
.staticFunctions
= JavaPackage_staticFunctions
;
1435 definition
.hasProperty
= &CYJavaPackage_hasProperty
;
1436 definition
.getProperty
= &CYJavaPackage_getProperty
;
1437 definition
.finalize
= &CYFinalize
;
1438 CYJavaPackage::Class_
= JSClassCreate(&definition
);
1440 definition
= kJSClassDefinitionEmpty
;
1441 definition
.attributes
= kJSClassAttributeNoAutomaticPrototype
;
1442 definition
.className
= "JavaStaticInterior";
1443 definition
.hasProperty
= &JavaStaticInterior_hasProperty
;
1444 definition
.getProperty
= &JavaStaticInterior_getProperty
;
1445 definition
.setProperty
= &JavaStaticInterior_setProperty
;
1446 definition
.getPropertyNames
= &JavaStaticInterior_getPropertyNames
;
1447 definition
.finalize
= &CYFinalize
;
1448 CYJavaStaticInterior::Class_
= JSClassCreate(&definition
);
1451 void CYJava_SetupContext(JSContextRef context
) {
1452 JSObjectRef
global(CYGetGlobalObject(context
));
1453 //JSObjectRef cy(CYCastJSObject(context, CYGetProperty(context, global, cy_s)));
1454 JSObjectRef
cycript(CYCastJSObject(context
, CYGetProperty(context
, global
, CYJSString("Cycript"))));
1455 JSObjectRef
all(CYCastJSObject(context
, CYGetProperty(context
, cycript
, CYJSString("all"))));
1456 //JSObjectRef alls(CYCastJSObject(context, CYGetProperty(context, cycript, CYJSString("alls"))));
1458 JSObjectRef
Java(JSObjectMake(context
, NULL
, NULL
));
1459 CYSetProperty(context
, cycript
, CYJSString("Java"), Java
);
1461 JSObjectRef
Packages(CYJavaPackage::Make(context
, CYJavaPackage::Path()));
1462 CYSetProperty(context
, all
, CYJSString("Packages"), Packages
);
1464 for (auto name
: (const char *[]) {"java", "javax", "android", "com", "net", "org"}) {
1465 CYJSString
js(name
);
1466 CYSetProperty(context
, all
, js
, CYGetProperty(context
, Packages
, js
));
1470 static CYHook CYJavaHook
= {
1475 &CYJava_SetupContext
,
1479 CYRegisterHook
CYJava(&CYJavaHook
);