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