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