]> git.saurik.com Git - cycript.git/blob - Java/Execute.cpp
Got exceptions bridged, back and forth, with Java.
[cycript.git] / Java / Execute.cpp
1 /* Cycript - Optimizing JavaScript Compiler/Runtime
2 * Copyright (C) 2009-2015 Jay Freeman (saurik)
3 */
4
5 /* GNU Affero General Public License, Version 3 {{{ */
6 /*
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.
11
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.
16
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/>.
19 **/
20 /* }}} */
21
22 #include <map>
23 #include <sstream>
24 #include <vector>
25
26 #ifdef __APPLE__
27 #include <JavaVM/jni.h>
28 #else
29 #include <jni.h>
30 #endif
31
32 #include "cycript.hpp"
33 #include "Error.hpp"
34 #include "Execute.hpp"
35 #include "Internal.hpp"
36 #include "JavaScript.hpp"
37 #include "Pooling.hpp"
38
39 #define _jnicall(expr) ({ \
40 jint _value(expr); \
41 if (_value != JNI_OK) \
42 CYThrow("_jnicall(%s) == %d", #expr, _value); \
43 })
44
45 #define _envcall(jni, expr) ({ \
46 __typeof__(jni->expr) _value(jni->expr); \
47 if (jthrowable _error = jni->ExceptionOccurred()) { \
48 jni->ExceptionClear(); \
49 throw CYJSError(context, CYCastJSValue(context, jni, _error)); \
50 } \
51 _value; })
52
53 #define _envcallv(jni, expr) do { \
54 jni->expr; \
55 if (jthrowable _error = jni->ExceptionOccurred()) { \
56 jni->ExceptionClear(); \
57 throw CYJSError(context, CYCastJSValue(context, jni, _error)); \
58 } \
59 } while (false)
60
61 #define CYJavaTry \
62 auto &protect(*reinterpret_cast<CYProtect *>(jprotect)); \
63 _disused JSContextRef context(protect); \
64 _disused JSObjectRef object(protect); \
65 try
66 #define CYJavaCatch(value) \
67 catch (const CYException &error) { \
68 jni->Throw(static_cast<jthrowable>(CYCastJavaObject(jni, context, error.CastJSValue(context, "Error")))); \
69 return value; \
70 }
71
72 extern "C" {
73 // Android's jni.h seriously doesn't declare these :/
74 jint JNI_CreateJavaVM(JavaVM **, void **, void *);
75 jint JNI_GetCreatedJavaVMs(JavaVM **, jsize, jsize *);
76 }
77
78 static JSValueRef CYCastJSValue(JSContextRef context, JNIEnv *jni, jobject value);
79
80 static void CYRegisterNatives(JSContextRef context, JNIEnv *jni);
81
82 JNIEnv *GetJNI(JSContextRef context) {
83 static JavaVM *jvm(NULL);
84 static JNIEnv *jni(NULL);
85
86 if (jni != NULL)
87 return jni;
88 jint version(JNI_VERSION_1_4);
89
90 jsize capacity(16);
91 JavaVM *jvms[capacity];
92 jsize size;
93 _jnicall(JNI_GetCreatedJavaVMs(jvms, capacity, &size));
94
95 if (size != 0) {
96 jvm = jvms[0];
97 _jnicall(jvm->GetEnv(reinterpret_cast<void **>(&jni), version));
98 } else {
99 CYPool pool;
100 std::vector<JavaVMOption> options;
101
102 {
103 std::ostringstream option;
104 option << "-Djava.class.path=";
105 option << CYPoolLibraryPath(pool) << "/libcycript.jar";
106 if (const char *classpath = getenv("CLASSPATH"))
107 option << ':' << classpath;
108 options.push_back(JavaVMOption{pool.strdup(option.str().c_str()), NULL});
109 }
110
111 JavaVMInitArgs args;
112 memset(&args, 0, sizeof(args));
113 args.version = version;
114 args.nOptions = options.size();
115 args.options = options.data();
116 _jnicall(JNI_CreateJavaVM(&jvm, reinterpret_cast<void **>(&jni), &args));
117 }
118
119 CYRegisterNatives(context, jni);
120
121 return jni;
122 }
123
124 class CYJavaUTF8String :
125 public CYUTF8String
126 {
127 private:
128 JNIEnv *jni_;
129 jstring value_;
130
131 public:
132 CYJavaUTF8String(JNIEnv *jni, jstring value) :
133 jni_(jni),
134 value_(value)
135 {
136 _assert(value != NULL);
137 size = jni_->GetStringUTFLength(value_);
138 data = jni_->GetStringUTFChars(value_, NULL);
139 }
140
141 ~CYJavaUTF8String() {
142 if (value_ != NULL)
143 jni_->ReleaseStringUTFChars(value_, data);
144 }
145
146 CYJavaUTF8String(const CYJavaUTF8String &) = delete;
147
148 CYJavaUTF8String(CYJavaUTF8String &&rhs) :
149 jni_(rhs.jni_),
150 value_(rhs.value_)
151 {
152 rhs.value_ = NULL;
153 }
154 };
155
156 CYJavaUTF8String CYCastUTF8String(JNIEnv *jni, jstring value) {
157 return CYJavaUTF8String(jni, value);
158 }
159
160 JSStringRef CYCopyJSString(JNIEnv *jni, jstring value) {
161 return CYCopyJSString(CYCastUTF8String(jni, value));
162 }
163
164 template <typename Value_>
165 struct CYJavaGlobal {
166 JNIEnv *jni_;
167 Value_ value_;
168
169 CYJavaGlobal() :
170 jni_(NULL),
171 value_(NULL)
172 {
173 }
174
175 CYJavaGlobal(JNIEnv *jni, Value_ value) :
176 jni_(jni),
177 value_(static_cast<Value_>(jni_->NewGlobalRef(value)))
178 {
179 }
180
181 CYJavaGlobal(const CYJavaGlobal &value) :
182 CYJavaGlobal(value.jni_, value.value_)
183 {
184 }
185
186 CYJavaGlobal(CYJavaGlobal &&value) :
187 jni_(value.jni_),
188 value_(value.value_)
189 {
190 value.value_ = NULL;
191 }
192
193 ~CYJavaGlobal() {
194 if (value_ != NULL)
195 jni_->DeleteGlobalRef(value_);
196 }
197
198 operator bool() const {
199 return value_ != NULL;
200 }
201
202 operator JNIEnv *() const {
203 return jni_;
204 }
205
206 operator Value_() const {
207 return value_;
208 }
209 };
210
211 template <typename Internal_, typename Value_>
212 struct CYJavaValue :
213 CYPrivate<Internal_>
214 {
215 CYJavaGlobal<Value_> value_;
216
217 CYJavaValue(JNIEnv *jni, Value_ value) :
218 value_(jni, value)
219 {
220 }
221
222 CYJavaValue(const CYJavaValue &) = delete;
223 };
224
225 #define CYJavaForEachPrimitive \
226 CYJavaForEachPrimitive_(Z, z, Boolean, Boolean, boolean) \
227 CYJavaForEachPrimitive_(B, b, Byte, Byte, byte) \
228 CYJavaForEachPrimitive_(C, c, Char, Character, char) \
229 CYJavaForEachPrimitive_(S, s, Short, Short, short) \
230 CYJavaForEachPrimitive_(I, i, Int, Integer, int) \
231 CYJavaForEachPrimitive_(J, j, Long, Long, long) \
232 CYJavaForEachPrimitive_(F, f, Float, Float, float) \
233 CYJavaForEachPrimitive_(D, d, Double, Double, double)
234
235 enum CYJavaPrimitive : char {
236 CYJavaPrimitiveObject,
237 CYJavaPrimitiveVoid,
238 #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \
239 CYJavaPrimitive ## Type,
240 CYJavaForEachPrimitive
241 #undef CYJavaForEachPrimitive_
242 };
243
244 template <typename Type_>
245 static _finline JSValueRef CYJavaCastJSValue(JSContextRef context, Type_ value) {
246 return CYCastJSValue(context, value);
247 }
248
249 static _finline JSValueRef CYJavaCastJSValue(JSContextRef context, jboolean value) {
250 return CYCastJSValue(context, static_cast<bool>(value));
251 }
252
253 static std::map<std::string, CYJavaPrimitive> Primitives_;
254
255 static CYJavaPrimitive CYJavaGetPrimitive(JSContextRef context, JNIEnv *jni, jobject type, jmethodID Class$get$$Name) {
256 jstring string(static_cast<jstring>(_envcall(jni, CallObjectMethod(type, Class$get$$Name))));
257 _assert(string != NULL);
258 CYJavaUTF8String name(jni, string);
259 auto primitive(Primitives_.find(name));
260 return primitive != Primitives_.end() ? primitive->second : CYJavaPrimitiveObject;
261 }
262
263 typedef std::vector<CYJavaPrimitive> CYJavaShorty;
264
265 static CYJavaShorty CYJavaGetShorty(JSContextRef context, JNIEnv *jni, jobjectArray types, jmethodID Class$get$$Name) {
266 size_t count(_envcall(jni, GetArrayLength(types)));
267 CYJavaShorty shorty(count);
268 for (size_t index(0); index != count; ++index)
269 shorty[index] = CYJavaGetPrimitive(context, jni, _envcall(jni, GetObjectArrayElement(types, index)), Class$get$$Name);
270 return shorty;
271 }
272
273 struct CYJavaField {
274 jfieldID field_;
275 CYJavaPrimitive primitive_;
276 };
277
278 typedef std::map<std::string, CYJavaField> CYJavaFieldMap;
279
280 struct CYJavaSignature {
281 jmethodID method_;
282 CYJavaGlobal<jobject> reflected_;
283 CYJavaPrimitive primitive_;
284 CYJavaShorty shorty_;
285
286 CYJavaSignature(JNIEnv *jni, jmethodID method, jobject reflected, CYJavaPrimitive primitive, const CYJavaShorty &shorty) :
287 method_(method),
288 reflected_(jni, reflected),
289 primitive_(primitive),
290 shorty_(shorty)
291 {
292 }
293
294 CYJavaSignature(unsigned count) :
295 shorty_(count)
296 {
297 }
298
299 bool operator <(const CYJavaSignature &rhs) const {
300 return shorty_.size() < rhs.shorty_.size();
301 }
302 };
303
304 typedef std::multiset<CYJavaSignature> CYJavaOverload;
305
306 struct CYJavaMethod :
307 CYPrivate<CYJavaMethod>
308 {
309 CYJavaOverload overload_;
310
311 CYJavaMethod(const CYJavaOverload &overload) :
312 overload_(overload)
313 {
314 }
315 };
316
317 struct CYJavaStaticMethod :
318 CYPrivate<CYJavaStaticMethod>
319 {
320 CYJavaOverload overload_;
321
322 CYJavaStaticMethod(const CYJavaOverload &overload) :
323 overload_(overload)
324 {
325 }
326 };
327
328 struct CYJavaClass :
329 CYJavaValue<CYJavaClass, jclass>
330 {
331 bool interface_;
332
333 CYJavaFieldMap static_;
334 CYJavaFieldMap instance_;
335 CYJavaOverload overload_;
336
337 CYJavaClass(JNIEnv *jni, jclass value, bool interface) :
338 CYJavaValue(jni, value),
339 interface_(interface)
340 {
341 }
342 };
343
344 static JSObjectRef CYGetJavaClass(JSContextRef context, JNIEnv *jni, jclass _class);
345
346 struct CYJavaObject :
347 CYJavaValue<CYJavaObject, jobject>
348 {
349 CYJavaClass *table_;
350
351 CYJavaObject(JNIEnv *jni, jobject value, CYJavaClass *table) :
352 CYJavaValue(jni, value),
353 table_(table)
354 {
355 }
356
357 JSValueRef GetPrototype(JSContextRef context) const;
358 };
359
360 struct CYJavaInterior :
361 CYJavaValue<CYJavaInterior, jobject>
362 {
363 CYJavaClass *table_;
364
365 CYJavaInterior(JNIEnv *jni, jobject value, CYJavaClass *table) :
366 CYJavaValue(jni, value),
367 table_(table)
368 {
369 }
370 };
371
372 struct CYJavaStaticInterior :
373 CYJavaValue<CYJavaStaticInterior, jobject>
374 {
375 CYJavaClass *table_;
376
377 CYJavaStaticInterior(JNIEnv *jni, jobject value, CYJavaClass *table) :
378 CYJavaValue(jni, value),
379 table_(table)
380 {
381 }
382 };
383
384 struct CYJavaArray :
385 CYJavaValue<CYJavaArray, jarray>
386 {
387 CYJavaPrimitive primitive_;
388
389 CYJavaArray(JNIEnv *jni, jarray value, CYJavaPrimitive primitive) :
390 CYJavaValue(jni, value),
391 primitive_(primitive)
392 {
393 }
394
395 JSValueRef GetPrototype(JSContextRef context) const;
396 };
397
398 struct CYJavaPackage :
399 CYPrivate<CYJavaPackage>
400 {
401 typedef std::vector<std::string> Path;
402 Path package_;
403
404 _finline CYJavaPackage(const Path &package) :
405 package_(package)
406 {
407 }
408 };
409
410 JSValueRef CYJavaObject::GetPrototype(JSContextRef context) const {
411 JNIEnv *jni(value_);
412 return CYGetProperty(context, CYGetJavaClass(context, jni, _envcall(jni, GetObjectClass(value_))), prototype_s);
413 }
414
415 JSValueRef CYJavaArray::GetPrototype(JSContextRef context) const {
416 return CYGetCachedObject(context, CYJSString("Array_prototype"));
417 }
418
419 static JSValueRef CYCastJSValue(JSContextRef context, JNIEnv *jni, jobject value) {
420 if (value == NULL)
421 return CYJSNull(context);
422
423 jclass _class(_envcall(jni, GetObjectClass(value)));
424 if (_envcall(jni, IsSameObject(_class, _envcall(jni, FindClass("java/lang/String")))))
425 return CYCastJSValue(context, CYJSString(jni, static_cast<jstring>(value)));
426
427 jclass Class$(_envcall(jni, FindClass("java/lang/Class")));
428 jmethodID Class$isArray(_envcall(jni, GetMethodID(Class$, "isArray", "()Z")));
429 if (_envcall(jni, CallBooleanMethod(_class, Class$isArray))) {
430 jmethodID Class$getComponentType(_envcall(jni, GetMethodID(Class$, "getComponentType", "()Ljava/lang/Class;")));
431 jclass component(static_cast<jclass>(_envcall(jni, CallObjectMethod(_class, Class$getComponentType))));
432 jmethodID Class$getName(_envcall(jni, GetMethodID(Class$, "getName", "()Ljava/lang/String;")));
433 return CYJavaArray::Make(context, jni, static_cast<jarray>(value), CYJavaGetPrimitive(context, jni, component, Class$getName));
434 }
435
436 jclass Wrapper$(_envcall(jni, FindClass("Cycript$Wrapper")));
437 if (_envcall(jni, IsSameObject(_class, Wrapper$))) {
438 jmethodID Wrapper$getProtect(_envcall(jni, GetMethodID(Wrapper$, "getProtect", "()J")));
439 auto &protect(*reinterpret_cast<CYProtect *>(_envcall(jni, CallLongMethod(value, Wrapper$getProtect))));
440 return protect;
441 }
442
443 CYJavaClass *table(reinterpret_cast<CYJavaClass *>(JSObjectGetPrivate(CYGetJavaClass(context, jni, _class))));
444 return CYJavaObject::Make(context, jni, value, table);
445 }
446
447 static _finline JSObjectRef CYCastJSObject(JSContextRef context, JNIEnv *jni, jobject value) {
448 return CYCastJSObject(context, CYCastJSValue(context, jni, value));
449 }
450
451 static jstring CYCastJavaString(JNIEnv *jni, JSContextRef context, CYUTF16String value) {
452 return _envcall(jni, NewString(value.data, value.size));
453 }
454
455 static jstring CYCastJavaString(JNIEnv *jni, JSContextRef context, JSStringRef value) {
456 return CYCastJavaString(jni, context, CYCastUTF16String(value));
457 }
458
459 #define CYCastJava$(T, Type, jtype, Cast) \
460 _disused static jobject CYCastJava ## Type(JNIEnv *jni, JSContextRef context, JSValueRef value) { \
461 jclass Type$(_envcall(jni, FindClass("java/lang/" #Type))); \
462 jmethodID Type$init$(_envcall(jni, GetMethodID(Type$, "<init>", "(" #T ")V"))); \
463 return _envcall(jni, NewObject(Type$, Type$init$, static_cast<jtype>(Cast(context, value)))); \
464 }
465
466 CYCastJava$(Z, Boolean, jboolean, CYCastBool)
467 CYCastJava$(B, Byte, jbyte, CYCastDouble)
468 CYCastJava$(C, Character, jchar, CYCastDouble)
469 CYCastJava$(S, Short, jshort, CYCastDouble)
470 CYCastJava$(I, Integer, jint, CYCastDouble)
471 CYCastJava$(J, Long, jlong, CYCastDouble)
472 CYCastJava$(F, Float, jfloat, CYCastDouble)
473 CYCastJava$(D, Double, jdouble, CYCastDouble)
474
475 static CYJavaClass *CYGetJavaTable(JSContextRef context, JSObjectRef object) {
476 if (!JSValueIsObjectOfClass(context, object, CYJavaClass::Class_))
477 return NULL;
478 return reinterpret_cast<CYJavaClass *>(JSObjectGetPrivate(object));
479 }
480
481 static CYJavaObject *CYGetJavaObject(JSContextRef context, JSObjectRef object) {
482 if (!JSValueIsObjectOfClass(context, object, CYJavaObject::Class_))
483 return NULL;
484 return reinterpret_cast<CYJavaObject *>(JSObjectGetPrivate(object));
485 }
486
487 static jobject CYCastJavaObject(JNIEnv *jni, JSContextRef context, JSObjectRef value) {
488 if (CYJavaObject *internal = CYGetJavaObject(context, value))
489 return internal->value_;
490
491 jclass Wrapper$(_envcall(jni, FindClass("Cycript$Wrapper")));
492 jmethodID Wrapper$$init$(_envcall(jni, GetMethodID(Wrapper$, "<init>", "(J)V")));
493 CYProtect *protect(new CYProtect(context, value));
494 return _envcall(jni, NewObject(Wrapper$, Wrapper$$init$, reinterpret_cast<jlong>(protect)));
495 }
496
497 static jobject CYCastJavaObject(JNIEnv *jni, JSContextRef context, JSValueRef value) {
498 switch (JSValueGetType(context, value)) {
499 case kJSTypeNull:
500 return NULL;
501 case kJSTypeBoolean:
502 return CYCastJavaBoolean(jni, context, value);
503 case kJSTypeNumber:
504 return CYCastJavaDouble(jni, context, value);
505 case kJSTypeString:
506 return CYCastJavaString(jni, context, CYJSString(context, value));
507 case kJSTypeObject:
508 return CYCastJavaObject(jni, context, CYCastJSObject(context, value));
509
510 case kJSTypeUndefined:
511 // XXX: I am currently relying on this for dynamic proxy of void method
512 return NULL;
513 default:
514 _assert(false);
515 }
516 }
517
518 static JSObjectRef CYGetJavaClass(JSContextRef context, JNIEnv *jni, jclass value) {
519 JSObjectRef global(CYGetGlobalObject(context));
520 JSObjectRef cy(CYCastJSObject(context, CYGetProperty(context, global, cy_s)));
521
522 jclass Class$(_envcall(jni, FindClass("java/lang/Class")));
523 jmethodID Class$getName(_envcall(jni, GetMethodID(Class$, "getName", "()Ljava/lang/String;")));
524
525 CYJSString name(jni, static_cast<jstring>(_envcall(jni, CallObjectMethod(value, Class$getName))));
526 JSValueRef cached(CYGetProperty(context, cy, name));
527 if (!JSValueIsUndefined(context, cached))
528 return CYCastJSObject(context, cached);
529
530 jmethodID Class$isInterface(_envcall(jni, GetMethodID(Class$, "isInterface", "()Z")));
531
532 jmethodID Class$getDeclaredConstructors(_envcall(jni, GetMethodID(Class$, "getDeclaredConstructors", "()[Ljava/lang/reflect/Constructor;")));
533 jmethodID Class$getDeclaredFields(_envcall(jni, GetMethodID(Class$, "getDeclaredFields", "()[Ljava/lang/reflect/Field;")));
534 jmethodID Class$getDeclaredMethods(_envcall(jni, GetMethodID(Class$, "getDeclaredMethods", "()[Ljava/lang/reflect/Method;")));
535
536 jclass Constructor$(_envcall(jni, FindClass("java/lang/reflect/Constructor")));
537 //jmethodID Constructor$getModifiers(_envcall(jni, GetMethodID(Constructor$, "getModifiers", "()I")));
538 jmethodID Constructor$getParameterTypes(_envcall(jni, GetMethodID(Constructor$, "getParameterTypes", "()[Ljava/lang/Class;")));
539
540 jclass Field$(_envcall(jni, FindClass("java/lang/reflect/Field")));
541 jmethodID Field$getModifiers(_envcall(jni, GetMethodID(Field$, "getModifiers", "()I")));
542 jmethodID Field$getName(_envcall(jni, GetMethodID(Field$, "getName", "()Ljava/lang/String;")));
543 jmethodID Field$getType(_envcall(jni, GetMethodID(Field$, "getType", "()Ljava/lang/Class;")));
544
545 jclass Method$(_envcall(jni, FindClass("java/lang/reflect/Method")));
546 jmethodID Method$getModifiers(_envcall(jni, GetMethodID(Method$, "getModifiers", "()I")));
547 jmethodID Method$getName(_envcall(jni, GetMethodID(Method$, "getName", "()Ljava/lang/String;")));
548 jmethodID Method$getParameterTypes(_envcall(jni, GetMethodID(Method$, "getParameterTypes", "()[Ljava/lang/Class;")));
549 jmethodID Method$getReturnType(_envcall(jni, GetMethodID(Method$, "getReturnType", "()Ljava/lang/Class;")));
550
551 jclass Modifier$(_envcall(jni, FindClass("java/lang/reflect/Modifier")));
552 jmethodID Modifier$isStatic(_envcall(jni, GetStaticMethodID(Modifier$, "isStatic", "(I)Z")));
553
554 bool interface(_envcall(jni, CallBooleanMethod(value, Class$isInterface)));
555 CYJavaClass *table(new CYJavaClass(jni, value, interface));
556
557 for (jclass prototype(value); prototype != NULL; prototype = _envcall(jni, GetSuperclass(prototype))) {
558 jobjectArray fields(static_cast<jobjectArray>(_envcall(jni, CallObjectMethod(prototype, Class$getDeclaredFields))));
559
560 for (jsize i(0), e(_envcall(jni, GetArrayLength(fields))); i != e; ++i) {
561 jobject field(_envcall(jni, GetObjectArrayElement(fields, e - i - 1)));
562 jint modifiers(_envcall(jni, CallIntMethod(field, Field$getModifiers)));
563 bool instance(!_envcall(jni, CallStaticBooleanMethod(Modifier$, Modifier$isStatic, modifiers)));
564 auto &map(instance ? table->instance_ : table->static_);
565 CYJavaUTF8String name(jni, static_cast<jstring>(_envcall(jni, CallObjectMethod(field, Field$getName))));
566 jfieldID id(_envcall(jni, FromReflectedField(field)));
567 jobject type(_envcall(jni, CallObjectMethod(field, Field$getType)));
568 map.insert(std::make_pair(std::string(name), CYJavaField{id, CYJavaGetPrimitive(context, jni, type, Class$getName)}));
569 }
570 }
571
572 JSObjectRef constructor(JSObjectMake(context, CYJavaClass::Class_, table));
573
574 JSObjectRef prototype(JSObjectMake(context, NULL, NULL));
575 CYSetProperty(context, constructor, prototype_s, prototype, kJSPropertyAttributeDontEnum);
576
577 jobjectArray constructors(static_cast<jobjectArray>(_envcall(jni, CallObjectMethod(value, Class$getDeclaredConstructors))));
578
579 for (jsize i(0), e(_envcall(jni, GetArrayLength(constructors))); i != e; ++i) {
580 jobject constructor(_envcall(jni, GetObjectArrayElement(constructors, i)));
581 jobjectArray parameters(static_cast<jobjectArray>(_envcall(jni, CallObjectMethod(constructor, Constructor$getParameterTypes))));
582 CYJavaShorty shorty(CYJavaGetShorty(context, jni, parameters, Class$getName));
583 jmethodID id(_envcall(jni, FromReflectedMethod(constructor)));
584 table->overload_.insert(CYJavaSignature(jni, id, constructor, CYJavaPrimitiveObject, shorty));
585 }
586
587 jobjectArray methods(static_cast<jobjectArray>(_envcall(jni, CallObjectMethod(value, Class$getDeclaredMethods))));
588
589 std::map<std::pair<bool, std::string>, CYJavaOverload> entries;
590
591 for (jsize i(0), e(_envcall(jni, GetArrayLength(methods))); i != e; ++i) {
592 jobject method(_envcall(jni, GetObjectArrayElement(methods, i)));
593 jint modifiers(_envcall(jni, CallIntMethod(method, Method$getModifiers)));
594 bool instance(!_envcall(jni, CallStaticBooleanMethod(Modifier$, Modifier$isStatic, modifiers)));
595 CYJavaUTF8String name(jni, static_cast<jstring>(_envcall(jni, CallObjectMethod(method, Method$getName))));
596 jobjectArray parameters(static_cast<jobjectArray>(_envcall(jni, CallObjectMethod(method, Method$getParameterTypes))));
597 CYJavaShorty shorty(CYJavaGetShorty(context, jni, parameters, Class$getName));
598 jobject type(_envcall(jni, CallObjectMethod(method, Method$getReturnType)));
599 auto primitive(CYJavaGetPrimitive(context, jni, type, Class$getName));
600 jmethodID id(_envcall(jni, FromReflectedMethod(method)));
601 entries[std::make_pair(instance, std::string(name))].insert(CYJavaSignature(jni, id, method, primitive, shorty));
602 }
603
604 for (const auto &entry : entries) {
605 bool instance(entry.first.first);
606 CYJSString name(entry.first.second);
607 auto &overload(entry.second);
608 if (instance)
609 CYSetProperty(context, prototype, name, CYJavaMethod::Make(context, overload), kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete);
610 else
611 CYSetProperty(context, constructor, name, CYJavaStaticMethod::Make(context, overload), kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete);
612 }
613
614 // XXX: for some reason kJSPropertyAttributeDontEnum doesn't work if there's already a property with the same name
615 // by not linking the prototypes until after we set the properties, we hide the parent property from this issue :(
616
617 if (jclass super = _envcall(jni, GetSuperclass(value))) {
618 JSObjectRef parent(CYGetJavaClass(context, jni, super));
619 CYSetPrototype(context, constructor, parent);
620 CYSetPrototype(context, prototype, CYGetProperty(context, parent, prototype_s));
621 }
622
623 CYSetProperty(context, cy, name, constructor);
624 return constructor;
625 }
626
627 static void CYCastJavaNumeric(jvalue &value, CYJavaPrimitive primitive, JSContextRef context, JSValueRef argument) {
628 switch (primitive) {
629 #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \
630 case CYJavaPrimitive ## Type: \
631 value.t = static_cast<j ## type>(CYCastDouble(context, argument)); \
632 break;
633 CYJavaForEachPrimitive
634 #undef CYJavaForEachPrimitive_
635 default:
636 _assert(false);
637 }
638 }
639
640 static bool CYCastJavaArguments(JNIEnv *jni, const CYJavaShorty &shorty, JSContextRef context, const JSValueRef arguments[], jvalue *array) {
641 for (size_t index(0); index != shorty.size(); ++index) {
642 JSValueRef argument(arguments[index]);
643 JSType type(JSValueGetType(context, argument));
644 jvalue &value(array[index]);
645
646 switch (CYJavaPrimitive primitive = shorty[index]) {
647 case CYJavaPrimitiveObject:
648 value.l = CYCastJavaObject(jni, context, argument);
649 break;
650
651 case CYJavaPrimitiveBoolean:
652 if (type != kJSTypeBoolean)
653 return false;
654 value.z = CYCastBool(context, argument);
655 break;
656
657 case CYJavaPrimitiveCharacter:
658 if (type == kJSTypeNumber)
659 CYCastJavaNumeric(value, primitive, context, argument);
660 else if (type != kJSTypeString)
661 return false;
662 else {
663 CYJSString string(context, argument);
664 if (JSStringGetLength(string) != 1)
665 return false;
666 else
667 value.c = JSStringGetCharactersPtr(string)[0];
668 }
669 break;
670
671 case CYJavaPrimitiveByte:
672 case CYJavaPrimitiveShort:
673 case CYJavaPrimitiveInteger:
674 case CYJavaPrimitiveLong:
675 case CYJavaPrimitiveFloat:
676 case CYJavaPrimitiveDouble:
677 if (type != kJSTypeNumber)
678 return false;
679 CYCastJavaNumeric(value, primitive, context, argument);
680 break;
681
682 default:
683 _assert(false);
684 }
685 }
686
687 return true;
688 }
689
690 static JSValueRef JavaMethod_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
691 CYJavaMethod *internal(reinterpret_cast<CYJavaMethod *>(JSObjectGetPrivate(object)));
692 CYJavaObject *self(CYGetJavaObject(context, _this));
693 JNIEnv *jni(self->value_);
694
695 CYJavaSignature bound(count);
696 for (auto overload(internal->overload_.lower_bound(bound)), e(internal->overload_.upper_bound(bound)); overload != e; ++overload) {
697 jvalue array[count];
698 if (!CYCastJavaArguments(jni, overload->shorty_, context, arguments, array))
699 continue;
700 switch (overload->primitive_) {
701 case CYJavaPrimitiveObject:
702 return CYCastJSValue(context, jni, _envcall(jni, CallObjectMethodA(self->value_, overload->method_, array)));
703 case CYJavaPrimitiveVoid:
704 _envcallv(jni, CallVoidMethodA(self->value_, overload->method_, array));
705 return CYJSUndefined(context);
706 #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \
707 case CYJavaPrimitive ## Type: \
708 return CYJavaCastJSValue(context, _envcall(jni, Call ## Typ ## MethodA(self->value_, overload->method_, array)));
709 CYJavaForEachPrimitive
710 #undef CYJavaForEachPrimitive_
711 default: _assert(false);
712 }
713 }
714
715 CYThrow("invalid method call");
716 } CYCatch(NULL) }
717
718 static JSValueRef JavaStaticMethod_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
719 CYJavaMethod *internal(reinterpret_cast<CYJavaMethod *>(JSObjectGetPrivate(object)));
720 CYJavaClass *table(CYGetJavaTable(context, _this));
721 JNIEnv *jni(table->value_);
722
723 CYJavaSignature bound(count);
724 for (auto overload(internal->overload_.lower_bound(bound)), e(internal->overload_.upper_bound(bound)); overload != e; ++overload) {
725 jvalue array[count];
726 if (!CYCastJavaArguments(jni, overload->shorty_, context, arguments, array))
727 continue;
728 switch (overload->primitive_) {
729 case CYJavaPrimitiveObject:
730 return CYCastJSValue(context, jni, _envcall(jni, CallStaticObjectMethodA(table->value_, overload->method_, array)));
731 case CYJavaPrimitiveVoid:
732 _envcallv(jni, CallStaticVoidMethodA(table->value_, overload->method_, array));
733 return CYJSUndefined(context);
734 #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \
735 case CYJavaPrimitive ## Type: \
736 return CYJavaCastJSValue(context, _envcall(jni, CallStatic ## Typ ## MethodA(table->value_, overload->method_, array)));
737 CYJavaForEachPrimitive
738 #undef CYJavaForEachPrimitive_
739 default: _assert(false);
740 }
741 }
742
743 CYThrow("invalid method call");
744 } CYCatch(NULL) }
745
746 static JSObjectRef JavaClass_callAsConstructor(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
747 CYJavaClass *table(reinterpret_cast<CYJavaClass *>(JSObjectGetPrivate(object)));
748 JNIEnv *jni(table->value_);
749 jclass _class(table->value_);
750
751 if (table->interface_ && count == 1) {
752 JSObjectRef target(CYCastJSObject(context, arguments[0]));
753 jclass Cycript$(_envcall(jni, FindClass("Cycript")));
754 jmethodID Cycript$Make(_envcall(jni, GetStaticMethodID(Cycript$, "proxy", "(Ljava/lang/Class;J)Ljava/lang/Object;")));
755 CYProtect *protect(new CYProtect(context, target));
756 return CYCastJSObject(context, jni, _envcall(jni, CallObjectMethod(Cycript$, Cycript$Make, _class, reinterpret_cast<jlong>(protect))));
757 }
758
759 CYJavaSignature bound(count);
760 for (auto overload(table->overload_.lower_bound(bound)), e(table->overload_.upper_bound(bound)); overload != e; ++overload) {
761 jvalue array[count];
762 if (!CYCastJavaArguments(jni, overload->shorty_, context, arguments, array))
763 continue;
764 jobject object(_envcall(jni, NewObjectA(_class, overload->method_, array)));
765 return CYCastJSObject(context, jni, object);
766 }
767
768 CYThrow("invalid constructor call");
769 } CYCatch(NULL) }
770
771 static bool JavaStaticInterior_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) {
772 CYJavaStaticInterior *internal(reinterpret_cast<CYJavaStaticInterior *>(JSObjectGetPrivate(object)));
773 CYJavaClass *table(internal->table_);
774 CYPool pool;
775 auto name(CYPoolUTF8String(pool, context, property));
776 auto field(table->static_.find(name));
777 if (field == table->static_.end())
778 return false;
779 return true;
780 }
781
782 static JSValueRef JavaStaticInterior_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
783 CYJavaStaticInterior *internal(reinterpret_cast<CYJavaStaticInterior *>(JSObjectGetPrivate(object)));
784 CYJavaClass *table(internal->table_);
785 JNIEnv *jni(table->value_);
786 CYPool pool;
787 auto name(CYPoolUTF8String(pool, context, property));
788 auto field(table->static_.find(name));
789 if (field == table->static_.end())
790 return NULL;
791
792 switch (field->second.primitive_) {
793 case CYJavaPrimitiveObject:
794 return CYCastJSValue(context, jni, _envcall(jni, GetStaticObjectField(table->value_, field->second.field_)));
795 #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \
796 case CYJavaPrimitive ## Type: \
797 return CYJavaCastJSValue(context, _envcall(jni, GetStatic ## Typ ## Field(table->value_, field->second.field_)));
798 CYJavaForEachPrimitive
799 #undef CYJavaForEachPrimitive_
800 default: _assert(false);
801 }
802 } CYCatch(NULL) }
803
804 static bool JavaStaticInterior_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYTry {
805 CYJavaStaticInterior *internal(reinterpret_cast<CYJavaStaticInterior *>(JSObjectGetPrivate(object)));
806 CYJavaClass *table(internal->table_);
807 JNIEnv *jni(table->value_);
808 CYPool pool;
809 auto name(CYPoolUTF8String(pool, context, property));
810 auto field(table->static_.find(name));
811 if (field == table->static_.end())
812 return false;
813
814 switch (field->second.primitive_) {
815 case CYJavaPrimitiveObject:
816 _envcallv(jni, SetStaticObjectField(table->value_, field->second.field_, CYCastJavaObject(jni, context, value)));
817 #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \
818 case CYJavaPrimitive ## Type: \
819 _envcallv(jni, SetStatic ## Typ ## Field(table->value_, field->second.field_, CYCastDouble(context, value))); \
820 break;
821 CYJavaForEachPrimitive
822 #undef CYJavaForEachPrimitive_
823 default: _assert(false);
824 }
825
826 return true;
827 } CYCatch(false) }
828
829 static void JavaStaticInterior_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
830 CYJavaStaticInterior *internal(reinterpret_cast<CYJavaStaticInterior *>(JSObjectGetPrivate(object)));
831 CYJavaClass *table(internal->table_);
832 for (const auto &field : table->static_)
833 JSPropertyNameAccumulatorAddName(names, CYJSString(field.first));
834 }
835
836 static JSValueRef JavaClass_getProperty_class(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
837 CYJavaClass *table(reinterpret_cast<CYJavaClass *>(JSObjectGetPrivate(object)));
838 return CYCastJSValue(context, table->value_, table->value_);
839 } CYCatch(NULL) }
840
841 static bool JavaInterior_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) {
842 CYJavaInterior *internal(reinterpret_cast<CYJavaInterior *>(JSObjectGetPrivate(object)));
843 CYJavaClass *table(internal->table_);
844 CYPool pool;
845 auto name(CYPoolUTF8String(pool, context, property));
846 auto field(table->instance_.find(name));
847 if (field == table->instance_.end())
848 return false;
849 return true;
850 }
851
852 static JSValueRef JavaInterior_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
853 CYJavaInterior *internal(reinterpret_cast<CYJavaInterior *>(JSObjectGetPrivate(object)));
854 JNIEnv *jni(internal->value_);
855 CYJavaClass *table(internal->table_);
856 CYPool pool;
857 auto name(CYPoolUTF8String(pool, context, property));
858 auto field(table->instance_.find(name));
859 if (field == table->instance_.end())
860 return NULL;
861
862 switch (field->second.primitive_) {
863 case CYJavaPrimitiveObject:
864 return CYCastJSValue(context, jni, _envcall(jni, GetObjectField(internal->value_, field->second.field_)));
865 #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \
866 case CYJavaPrimitive ## Type: \
867 return CYJavaCastJSValue(context, _envcall(jni, Get ## Typ ## Field(internal->value_, field->second.field_)));
868 CYJavaForEachPrimitive
869 #undef CYJavaForEachPrimitive_
870 default: _assert(false);
871 }
872 } CYCatch(NULL) }
873
874 static bool JavaInterior_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYTry {
875 CYJavaInterior *internal(reinterpret_cast<CYJavaInterior *>(JSObjectGetPrivate(object)));
876 JNIEnv *jni(internal->value_);
877 CYJavaClass *table(internal->table_);
878 CYPool pool;
879 auto name(CYPoolUTF8String(pool, context, property));
880 auto field(table->instance_.find(name));
881 if (field == table->instance_.end())
882 return false;
883
884 switch (field->second.primitive_) {
885 case CYJavaPrimitiveObject:
886 _envcallv(jni, SetObjectField(table->value_, field->second.field_, CYCastJavaObject(jni, context, value)));
887 #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \
888 case CYJavaPrimitive ## Type: \
889 _envcallv(jni, Set ## Typ ## Field(table->value_, field->second.field_, CYCastDouble(context, value))); \
890 break;
891 CYJavaForEachPrimitive
892 #undef CYJavaForEachPrimitive_
893 default: _assert(false);
894 }
895
896 return true;
897 } CYCatch(false) }
898
899 static void JavaInterior_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
900 CYJavaInterior *internal(reinterpret_cast<CYJavaInterior *>(JSObjectGetPrivate(object)));
901 CYJavaClass *table(internal->table_);
902 for (const auto &field : table->instance_)
903 JSPropertyNameAccumulatorAddName(names, CYJSString(field.first));
904 }
905
906 static JSValueRef JavaObject_getProperty_constructor(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
907 CYJavaObject *internal(reinterpret_cast<CYJavaObject *>(JSObjectGetPrivate(object)));
908 JNIEnv *jni(internal->value_);
909 return CYGetJavaClass(context, jni, _envcall(jni, GetObjectClass(internal->value_)));
910 } CYCatch(NULL) }
911
912 static JSValueRef JavaClass_getProperty_$cyi(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
913 CYJavaClass *internal(reinterpret_cast<CYJavaClass *>(JSObjectGetPrivate(object)));
914 JNIEnv *jni(internal->value_);
915 return CYJavaStaticInterior::Make(context, jni, internal->value_, internal);
916 } CYCatch(NULL) }
917
918 static JSValueRef JavaObject_getProperty_$cyi(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
919 CYJavaObject *internal(reinterpret_cast<CYJavaObject *>(JSObjectGetPrivate(object)));
920 JNIEnv *jni(internal->value_);
921 return CYJavaInterior::Make(context, jni, internal->value_, internal->table_);
922 } CYCatch(NULL) }
923
924 static JSValueRef JavaClass_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
925 CYJavaClass *internal(reinterpret_cast<CYJavaClass *>(JSObjectGetPrivate(_this)));
926 JNIEnv *jni(internal->value_);
927 jclass Class$(_envcall(jni, FindClass("java/lang/Class")));
928 jmethodID Class$getCanonicalName(_envcall(jni, GetMethodID(Class$, "getCanonicalName", "()Ljava/lang/String;")));
929 return CYCastJSValue(context, CYJSString(jni, static_cast<jstring>(_envcall(jni, CallObjectMethod(internal->value_, Class$getCanonicalName)))));
930 } CYCatch(NULL) }
931
932 static JSValueRef JavaMethod_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
933 std::ostringstream cyon;
934 return CYCastJSValue(context, CYJSString(cyon.str()));
935 } CYCatch(NULL) }
936
937 static JSValueRef JavaStaticMethod_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
938 std::ostringstream cyon;
939 return CYCastJSValue(context, CYJSString(cyon.str()));
940 } CYCatch(NULL) }
941
942 static JSValueRef JavaArray_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
943 CYJavaArray *internal(reinterpret_cast<CYJavaArray *>(JSObjectGetPrivate(object)));
944 JNIEnv *jni(internal->value_);
945 if (JSStringIsEqual(property, length_s))
946 return CYCastJSValue(context, _envcall(jni, GetArrayLength(internal->value_)));
947
948 CYPool pool;
949 ssize_t offset;
950 if (!CYGetOffset(pool, context, property, offset))
951 return NULL;
952
953 if (internal->primitive_ == CYJavaPrimitiveObject)
954 return CYCastJSValue(context, jni, _envcall(jni, GetObjectArrayElement(static_cast<jobjectArray>(internal->value_.value_), offset)));
955 else switch (internal->primitive_) {
956 #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \
957 case CYJavaPrimitive ## Type: { \
958 j ## type element; \
959 _envcallv(jni, Get ## Typ ## ArrayRegion(static_cast<j ## type ## Array>(internal->value_.value_), offset, 1, &element)); \
960 return CYJavaCastJSValue(context, element); \
961 } break;
962 CYJavaForEachPrimitive
963 #undef CYJavaForEachPrimitive_
964 default: _assert(false);
965 }
966 } CYCatch(NULL) }
967
968 static bool JavaArray_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYTry {
969 CYJavaArray *internal(reinterpret_cast<CYJavaArray *>(JSObjectGetPrivate(object)));
970 JNIEnv *jni(internal->value_);
971
972 CYPool pool;
973 ssize_t offset;
974 if (!CYGetOffset(pool, context, property, offset))
975 return false;
976
977 if (internal->primitive_ == CYJavaPrimitiveObject)
978 _envcallv(jni, SetObjectArrayElement(static_cast<jobjectArray>(internal->value_.value_), offset, CYCastJavaObject(jni, context, value)));
979 else switch (internal->primitive_) {
980 #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \
981 case CYJavaPrimitive ## Type: { \
982 j ## type element; \
983 _envcallv(jni, Get ## Typ ## ArrayRegion(static_cast<j ## type ## Array>(internal->value_.value_), offset, 1, &element)); \
984 return CYJavaCastJSValue(context, element); \
985 } break;
986 CYJavaForEachPrimitive
987 #undef CYJavaForEachPrimitive_
988 default: _assert(false);
989 }
990
991 return true;
992 } CYCatch(false) }
993
994 static JSValueRef JavaPackage_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
995 CYJavaPackage *internal(reinterpret_cast<CYJavaPackage *>(JSObjectGetPrivate(_this)));
996 std::ostringstream name;
997 for (auto &package : internal->package_)
998 name << package << '.';
999 name << '*';
1000 return CYCastJSValue(context, CYJSString(name.str()));
1001 } CYCatch(NULL) }
1002
1003 static bool CYJavaPackage_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) {
1004 return true;
1005 }
1006
1007 static JSValueRef CYJavaPackage_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry {
1008 CYJavaPackage *internal(reinterpret_cast<CYJavaPackage *>(JSObjectGetPrivate(object)));
1009 CYJavaPackage::Path package(internal->package_);
1010
1011 CYPool pool;
1012 const char *next(CYPoolCString(pool, context, property));
1013
1014 std::ostringstream name;
1015 for (auto &package : internal->package_)
1016 name << package << '/';
1017 name << next;
1018
1019 JNIEnv *jni(GetJNI(context));
1020 if (jclass _class = jni->FindClass(name.str().c_str()))
1021 return CYGetJavaClass(context, jni, _class);
1022 jni->ExceptionClear();
1023
1024 package.push_back(next);
1025 return CYJavaPackage::Make(context, package);
1026 } CYCatch(NULL) }
1027
1028 static void Cycript_delete(JNIEnv *jni, jclass api, jlong jprotect) { CYJavaTry {
1029 delete &protect;
1030 } CYJavaCatch() }
1031
1032 static jobject Cycript_handle(JNIEnv *jni, jclass api, jlong jprotect, jstring property, jobjectArray jarguments) { CYJavaTry {
1033 JSValueRef function(CYGetProperty(context, object, CYJSString(jni, property)));
1034 if (JSValueIsUndefined(context, function))
1035 return NULL;
1036
1037 size_t count(jarguments == NULL ? 0 : _envcall(jni, GetArrayLength(jarguments)));
1038 JSValueRef arguments[count];
1039 for (size_t index(0); index != count; ++index)
1040 arguments[index] = CYCastJSValue(context, jni, _envcall(jni, GetObjectArrayElement(jarguments, index)));
1041
1042 return CYCastJavaObject(jni, context, CYCallAsFunction(context, CYCastJSObject(context, function), object, count, arguments));
1043 } CYJavaCatch(NULL) }
1044
1045 static JNINativeMethod Cycript_[] = {
1046 {(char *) "delete", (char *) "(J)V", (void *) &Cycript_delete},
1047 {(char *) "handle", (char *) "(JLjava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;", (void *) &Cycript_handle},
1048 };
1049
1050 static void CYRegisterNatives(JSContextRef context, JNIEnv *jni) {
1051 jclass Cycript$(_envcall(jni, FindClass("Cycript")));
1052 _envcall(jni, RegisterNatives(Cycript$, Cycript_, sizeof(Cycript_) / sizeof(Cycript_[0])));
1053 }
1054
1055 static JSStaticValue JavaClass_staticValues[3] = {
1056 {"class", &JavaClass_getProperty_class, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1057 {"$cyi", &JavaClass_getProperty_$cyi, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1058 {NULL, NULL, NULL, 0}
1059 };
1060
1061 static JSStaticFunction JavaClass_staticFunctions[2] = {
1062 {"toCYON", &JavaClass_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1063 {NULL, NULL, 0}
1064 };
1065
1066 static JSStaticValue JavaObject_staticValues[3] = {
1067 {"constructor", &JavaObject_getProperty_constructor, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1068 {"$cyi", &JavaObject_getProperty_$cyi, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1069 {NULL, NULL, NULL, 0}
1070 };
1071
1072 static JSStaticFunction JavaMethod_staticFunctions[2] = {
1073 {"toCYON", &JavaMethod_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1074 {NULL, NULL, 0}
1075 };
1076
1077 static JSStaticFunction JavaStaticMethod_staticFunctions[2] = {
1078 {"toCYON", &JavaStaticMethod_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1079 {NULL, NULL, 0}
1080 };
1081
1082 static JSStaticFunction JavaPackage_staticFunctions[2] = {
1083 {"toCYON", &JavaPackage_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
1084 {NULL, NULL, 0}
1085 };
1086
1087 void CYJava_Initialize() {
1088 Primitives_.insert(std::make_pair("void", CYJavaPrimitiveVoid));
1089 #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \
1090 Primitives_.insert(std::make_pair(#type, CYJavaPrimitive ## Type));
1091 CYJavaForEachPrimitive
1092 #undef CYJavaForEachPrimitive_
1093
1094 JSClassDefinition definition;
1095
1096 definition = kJSClassDefinitionEmpty;
1097 definition.className = "JavaClass";
1098 definition.staticValues = JavaClass_staticValues;
1099 definition.staticFunctions = JavaClass_staticFunctions;
1100 definition.callAsConstructor = &JavaClass_callAsConstructor;
1101 definition.finalize = &CYFinalize;
1102 CYJavaClass::Class_ = JSClassCreate(&definition);
1103
1104 definition = kJSClassDefinitionEmpty;
1105 definition.attributes = kJSClassAttributeNoAutomaticPrototype;
1106 definition.className = "JavaInterior";
1107 definition.hasProperty = &JavaInterior_hasProperty;
1108 definition.getProperty = &JavaInterior_getProperty;
1109 definition.setProperty = &JavaInterior_setProperty;
1110 definition.getPropertyNames = &JavaInterior_getPropertyNames;
1111 definition.finalize = &CYFinalize;
1112 CYJavaInterior::Class_ = JSClassCreate(&definition);
1113
1114 definition = kJSClassDefinitionEmpty;
1115 definition.className = "JavaMethod";
1116 definition.staticFunctions = JavaMethod_staticFunctions;
1117 definition.callAsFunction = &JavaMethod_callAsFunction;
1118 definition.finalize = &CYFinalize;
1119 CYJavaMethod::Class_ = JSClassCreate(&definition);
1120
1121 definition = kJSClassDefinitionEmpty;
1122 definition.className = "JavaStaticMethod";
1123 definition.staticFunctions = JavaStaticMethod_staticFunctions;
1124 definition.callAsFunction = &JavaStaticMethod_callAsFunction;
1125 definition.finalize = &CYFinalize;
1126 CYJavaStaticMethod::Class_ = JSClassCreate(&definition);
1127
1128 definition = kJSClassDefinitionEmpty;
1129 definition.attributes = kJSClassAttributeNoAutomaticPrototype;
1130 definition.className = "JavaObject";
1131 definition.staticValues = JavaObject_staticValues;
1132 definition.finalize = &CYFinalize;
1133 CYJavaObject::Class_ = JSClassCreate(&definition);
1134
1135 definition = kJSClassDefinitionEmpty;
1136 definition.className = "JavaArray";
1137 definition.getProperty = &JavaArray_getProperty;
1138 definition.setProperty = &JavaArray_setProperty;
1139 definition.finalize = &CYFinalize;
1140 CYJavaArray::Class_ = JSClassCreate(&definition);
1141
1142 definition = kJSClassDefinitionEmpty;
1143 definition.className = "JavaPackage";
1144 definition.staticFunctions = JavaPackage_staticFunctions;
1145 definition.hasProperty = &CYJavaPackage_hasProperty;
1146 definition.getProperty = &CYJavaPackage_getProperty;
1147 definition.finalize = &CYFinalize;
1148 CYJavaPackage::Class_ = JSClassCreate(&definition);
1149
1150 definition = kJSClassDefinitionEmpty;
1151 definition.attributes = kJSClassAttributeNoAutomaticPrototype;
1152 definition.className = "JavaStaticInterior";
1153 definition.hasProperty = &JavaStaticInterior_hasProperty;
1154 definition.getProperty = &JavaStaticInterior_getProperty;
1155 definition.setProperty = &JavaStaticInterior_setProperty;
1156 definition.getPropertyNames = &JavaStaticInterior_getPropertyNames;
1157 definition.finalize = &CYFinalize;
1158 CYJavaStaticInterior::Class_ = JSClassCreate(&definition);
1159 }
1160
1161 void CYJava_SetupContext(JSContextRef context) {
1162 JSObjectRef global(CYGetGlobalObject(context));
1163 //JSObjectRef cy(CYCastJSObject(context, CYGetProperty(context, global, cy_s)));
1164 JSObjectRef cycript(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Cycript"))));
1165 JSObjectRef all(CYCastJSObject(context, CYGetProperty(context, cycript, CYJSString("all"))));
1166 //JSObjectRef alls(CYCastJSObject(context, CYGetProperty(context, cycript, CYJSString("alls"))));
1167
1168 JSObjectRef Java(JSObjectMake(context, NULL, NULL));
1169 CYSetProperty(context, cycript, CYJSString("Java"), Java);
1170
1171 JSObjectRef Packages(CYJavaPackage::Make(context, CYJavaPackage::Path()));
1172 CYSetProperty(context, all, CYJSString("Packages"), Packages);
1173
1174 for (auto name : (const char *[]) {"java", "javax", "android", "com", "net", "org"}) {
1175 CYJSString js(name);
1176 CYSetProperty(context, all, js, CYGetProperty(context, Packages, js));
1177 }
1178 }
1179
1180 static CYHook CYJavaHook = {
1181 NULL,
1182 NULL,
1183 NULL,
1184 &CYJava_Initialize,
1185 &CYJava_SetupContext,
1186 NULL,
1187 };
1188
1189 CYRegisterHook CYJava(&CYJavaHook);