]>
Commit | Line | Data |
---|---|---|
7341eedb JF |
1 | /* Cycript - The Truly Universal Scripting Language |
2 | * Copyright (C) 2009-2016 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 | ||
f2c357f9 JF |
26 | #include <dlfcn.h> |
27 | ||
4b5dc402 | 28 | #if defined(__APPLE__) && !defined(__arm__) |
def90846 JF |
29 | #include <JavaVM/jni.h> |
30 | #else | |
e17ad658 | 31 | #include <jni.h> |
def90846 | 32 | #endif |
dbf05bfd | 33 | |
f2c357f9 JF |
34 | #ifdef __ANDROID__ |
35 | // XXX: this is deprecated?!?!?!?!?!?! | |
36 | #include <sys/system_properties.h> | |
37 | #endif | |
38 | ||
dbf05bfd | 39 | #include "cycript.hpp" |
c9c16dde | 40 | #include "Error.hpp" |
dbf05bfd JF |
41 | #include "Execute.hpp" |
42 | #include "Internal.hpp" | |
43 | #include "JavaScript.hpp" | |
44 | #include "Pooling.hpp" | |
45 | ||
46 | #define _jnicall(expr) ({ \ | |
47 | jint _value(expr); \ | |
48 | if (_value != JNI_OK) \ | |
49 | CYThrow("_jnicall(%s) == %d", #expr, _value); \ | |
50 | }) | |
51 | ||
52 | #define _envcall(jni, expr) ({ \ | |
53 | __typeof__(jni->expr) _value(jni->expr); \ | |
54 | if (jthrowable _error = jni->ExceptionOccurred()) { \ | |
55 | jni->ExceptionClear(); \ | |
fc664744 | 56 | throw CYJavaError(CYJavaLocal<jthrowable>(jni, _error)); \ |
dbf05bfd JF |
57 | } \ |
58 | _value; }) | |
59 | ||
60 | #define _envcallv(jni, expr) do { \ | |
61 | jni->expr; \ | |
62 | if (jthrowable _error = jni->ExceptionOccurred()) { \ | |
63 | jni->ExceptionClear(); \ | |
fc664744 | 64 | throw CYJavaError(CYJavaLocal<jthrowable>(jni, _error)); \ |
dbf05bfd JF |
65 | } \ |
66 | } while (false) | |
67 | ||
c9c16dde | 68 | #define CYJavaTry \ |
fc664744 | 69 | CYJavaEnv jni(env); \ |
824bc1ec JF |
70 | auto &protect(*reinterpret_cast<CYProtect *>(jprotect)); \ |
71 | _disused JSContextRef context(protect); \ | |
72 | _disused JSObjectRef object(protect); \ | |
c9c16dde JF |
73 | try |
74 | #define CYJavaCatch(value) \ | |
75 | catch (const CYException &error) { \ | |
fc664744 | 76 | jni->Throw(CYCastJavaObject(jni, context, error.CastJSValue(context, "Error")).cast<jthrowable>()); \ |
c9c16dde JF |
77 | return value; \ |
78 | } | |
79 | ||
fc664744 JF |
80 | #define CYJavaForEachPrimitive \ |
81 | CYJavaForEachPrimitive_(Z, z, Boolean, Boolean, boolean) \ | |
82 | CYJavaForEachPrimitive_(B, b, Byte, Byte, byte) \ | |
83 | CYJavaForEachPrimitive_(C, c, Char, Character, char) \ | |
84 | CYJavaForEachPrimitive_(S, s, Short, Short, short) \ | |
85 | CYJavaForEachPrimitive_(I, i, Int, Integer, int) \ | |
86 | CYJavaForEachPrimitive_(J, j, Long, Long, long) \ | |
87 | CYJavaForEachPrimitive_(F, f, Float, Float, float) \ | |
88 | CYJavaForEachPrimitive_(D, d, Double, Double, double) | |
c9c16dde | 89 | |
fc664744 JF |
90 | enum CYJavaPrimitive : char { |
91 | CYJavaPrimitiveObject, | |
92 | CYJavaPrimitiveVoid, | |
93 | #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \ | |
94 | CYJavaPrimitive ## Type, | |
95 | CYJavaForEachPrimitive | |
96 | #undef CYJavaForEachPrimitive_ | |
97 | }; | |
dbf05bfd | 98 | |
0e832de4 JF |
99 | template <typename Type_> |
100 | struct IsJavaPrimitive { static const bool value = false; }; | |
101 | ||
102 | #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \ | |
103 | template <> \ | |
104 | struct IsJavaPrimitive<j ## type> { static const bool value = true; }; | |
105 | CYJavaForEachPrimitive | |
106 | #undef CYJavaForEachPrimitive_ | |
107 | ||
fc664744 JF |
108 | // Java References {{{ |
109 | template <typename Value_> | |
110 | struct CYJavaRef { | |
111 | JNIEnv *jni_; | |
112 | Value_ value_; | |
dbf05bfd | 113 | |
fc664744 JF |
114 | _finline CYJavaRef(JNIEnv *jni, Value_ value) : |
115 | jni_(jni), | |
116 | value_(value) | |
117 | { | |
118 | } | |
dbf05bfd | 119 | |
477549f5 JF |
120 | _finline operator Value_() const { |
121 | return value_; | |
fc664744 | 122 | } |
c9c16dde | 123 | |
477549f5 | 124 | _finline JNIEnv *jni() const { |
fc664744 JF |
125 | return jni_; |
126 | } | |
c9c16dde | 127 | |
0e832de4 | 128 | // XXX: this is only needed to support CYJavaEnv relying on C variadics |
fc664744 JF |
129 | _finline Value_ get() const { |
130 | return value_; | |
131 | } | |
c9c16dde | 132 | |
fc664744 JF |
133 | template <typename Other_> |
134 | _finline CYJavaRef<Other_> cast() const { | |
135 | return {jni_, static_cast<Other_>(value_)}; | |
136 | } | |
137 | ||
4e2cc9d3 | 138 | // XXX: this should be tied into CYJavaFrame |
fc664744 JF |
139 | Value_ leak() { |
140 | Value_ value(value_); | |
141 | value_ = NULL; | |
142 | return value; | |
143 | } | |
144 | }; | |
145 | ||
146 | template <typename Value_, void (JNIEnv::*Delete_)(jobject)> | |
147 | struct CYJavaDelete : | |
148 | CYJavaRef<Value_> | |
149 | { | |
150 | _finline CYJavaDelete(JNIEnv *jni, Value_ value) : | |
151 | CYJavaRef<Value_>(jni, value) | |
152 | { | |
153 | } | |
154 | ||
4e2cc9d3 | 155 | void clear() { |
fc664744 JF |
156 | if (this->value_ != NULL) |
157 | (this->jni_->*Delete_)(this->value_); | |
4e2cc9d3 JF |
158 | this->value_ = NULL; |
159 | } | |
160 | ||
161 | ~CYJavaDelete() { | |
162 | clear(); | |
fc664744 JF |
163 | } |
164 | }; | |
165 | ||
166 | template <typename Value_> | |
167 | struct CYJavaGlobal : | |
168 | CYJavaDelete<Value_, &JNIEnv::DeleteGlobalRef> | |
169 | { | |
170 | typedef CYJavaDelete<Value_, &JNIEnv::DeleteGlobalRef> CYJavaBase; | |
171 | ||
172 | CYJavaGlobal() : | |
173 | CYJavaBase(NULL, NULL) | |
174 | { | |
175 | } | |
176 | ||
177 | template <typename Other_> | |
178 | CYJavaGlobal(const CYJavaRef<Other_> &other) : | |
179 | CYJavaBase(other.jni_, static_cast<Other_>(other.jni_->NewGlobalRef(other.value_))) | |
180 | { | |
181 | } | |
182 | ||
183 | CYJavaGlobal(const CYJavaGlobal<Value_> &other) : | |
184 | CYJavaGlobal(static_cast<const CYJavaRef<Value_> &>(other)) | |
185 | { | |
186 | } | |
187 | ||
188 | CYJavaGlobal(CYJavaGlobal &&value) : | |
189 | CYJavaBase(value.jni_, value.value_) | |
190 | { | |
191 | value.value_ = NULL; | |
192 | } | |
92536081 JF |
193 | |
194 | template <typename Other_> | |
195 | CYJavaGlobal &operator =(const CYJavaRef<Other_> &other) { | |
196 | this->~CYJavaGlobal(); | |
197 | new (this) CYJavaGlobal(other); | |
198 | return *this; | |
199 | } | |
fc664744 JF |
200 | }; |
201 | ||
202 | template <typename Value_> | |
203 | struct CYJavaLocal : | |
204 | CYJavaDelete<Value_, &JNIEnv::DeleteLocalRef> | |
205 | { | |
206 | typedef CYJavaDelete<Value_, &JNIEnv::DeleteLocalRef> CYJavaBase; | |
207 | ||
208 | CYJavaLocal() : | |
209 | CYJavaBase(NULL, NULL) | |
210 | { | |
211 | } | |
212 | ||
213 | CYJavaLocal(JNIEnv *jni, Value_ value) : | |
214 | CYJavaBase(jni, value) | |
215 | { | |
216 | } | |
217 | ||
218 | template <typename Other_> | |
219 | CYJavaLocal(const CYJavaRef<Other_> &other) : | |
220 | CYJavaLocal(other.jni_, static_cast<Other_>(other.jni_->NewLocalRef(other.value_))) | |
221 | { | |
222 | } | |
223 | ||
4e2cc9d3 JF |
224 | template <typename Other_> |
225 | CYJavaLocal(CYJavaRef<Other_> &&other) : | |
226 | CYJavaLocal(other.jni_, other.value_) | |
227 | { | |
228 | other.value_ = NULL; | |
229 | } | |
230 | ||
231 | CYJavaLocal(CYJavaLocal &&other) : | |
232 | CYJavaLocal(static_cast<CYJavaRef<Value_> &&>(other)) | |
fc664744 | 233 | { |
fc664744 JF |
234 | } |
235 | ||
4e2cc9d3 JF |
236 | template <typename Other_> |
237 | CYJavaLocal &operator =(CYJavaLocal<Other_> &&other) { | |
238 | this->clear(); | |
239 | this->jni_ = other.jni_; | |
240 | this->value_ = other.value_; | |
241 | other.value_ = NULL; | |
fc664744 JF |
242 | return *this; |
243 | } | |
244 | }; | |
245 | // }}} | |
246 | // Java Strings {{{ | |
247 | static CYJavaLocal<jstring> CYCastJavaString(const CYJavaRef<jobject> &value); | |
dbf05bfd JF |
248 | |
249 | class CYJavaUTF8String : | |
250 | public CYUTF8String | |
251 | { | |
252 | private: | |
3853f099 | 253 | const CYJavaRef<jstring> &value_; |
dbf05bfd JF |
254 | |
255 | public: | |
fc664744 | 256 | CYJavaUTF8String(const CYJavaRef<jstring> &value) : |
3853f099 | 257 | value_(value) |
fc664744 JF |
258 | { |
259 | _assert(value); | |
477549f5 | 260 | JNIEnv *jni(value.jni()); |
fc664744 JF |
261 | size = jni->GetStringUTFLength(value); |
262 | data = jni->GetStringUTFChars(value, NULL); | |
263 | } | |
264 | ||
3853f099 | 265 | CYJavaUTF8String(CYJavaRef<jstring> &&) = delete; |
dbf05bfd JF |
266 | |
267 | ~CYJavaUTF8String() { | |
3853f099 JF |
268 | JNIEnv *jni(value_.jni()); |
269 | jni->ReleaseStringUTFChars(value_, data); | |
dbf05bfd JF |
270 | } |
271 | ||
272 | CYJavaUTF8String(const CYJavaUTF8String &) = delete; | |
dbf05bfd JF |
273 | }; |
274 | ||
fc664744 | 275 | CYJavaUTF8String CYCastUTF8String(const CYJavaRef<jstring> &value) { |
3853f099 | 276 | return {value}; |
dbf05bfd JF |
277 | } |
278 | ||
fc664744 JF |
279 | JSStringRef CYCopyJSString(const CYJavaRef<jstring> &value) { |
280 | return CYCopyJSString(CYCastUTF8String(value)); | |
dbf05bfd | 281 | } |
fc664744 JF |
282 | // }}} |
283 | // Java Error {{{ | |
284 | struct CYJavaError : | |
285 | CYException | |
286 | { | |
287 | CYJavaGlobal<jthrowable> value_; | |
dbf05bfd | 288 | |
fc664744 JF |
289 | CYJavaError(const CYJavaRef<jthrowable> &value) : |
290 | value_(value) | |
291 | { | |
292 | } | |
293 | ||
294 | virtual const char *PoolCString(CYPool &pool) const { | |
3853f099 JF |
295 | auto string(CYCastJavaString(value_.cast<jobject>())); |
296 | return CYPoolCString(pool, CYJavaUTF8String(string)); | |
fc664744 JF |
297 | } |
298 | ||
477549f5 | 299 | virtual JSValueRef CastJSValue(JSContextRef context, const char *name) const; |
fc664744 JF |
300 | }; |
301 | // }}} | |
302 | ||
303 | struct CYJavaFrame { | |
dbf05bfd | 304 | JNIEnv *jni_; |
dbf05bfd | 305 | |
fc664744 JF |
306 | CYJavaFrame(JNIEnv *jni, jint capacity) : |
307 | jni_(jni) | |
dbf05bfd | 308 | { |
fc664744 | 309 | _assert(jni->PushLocalFrame(capacity) == 0); |
dbf05bfd JF |
310 | } |
311 | ||
fc664744 JF |
312 | ~CYJavaFrame() { |
313 | operator ()(NULL); | |
dbf05bfd JF |
314 | } |
315 | ||
4e2cc9d3 JF |
316 | operator JNIEnv *() const { |
317 | return jni_; | |
318 | } | |
319 | ||
fc664744 JF |
320 | jobject operator ()(jobject object) { |
321 | JNIEnv *jni(jni_); | |
322 | jni_ = NULL; | |
323 | return jni->PopLocalFrame(object); | |
dbf05bfd | 324 | } |
fc664744 | 325 | }; |
dbf05bfd | 326 | |
fc664744 JF |
327 | struct CYJavaEnv { |
328 | private: | |
329 | JNIEnv *jni; | |
330 | ||
331 | public: | |
332 | CYJavaEnv(JNIEnv *jni) : | |
333 | jni(jni) | |
dbf05bfd | 334 | { |
dbf05bfd JF |
335 | } |
336 | ||
477549f5 JF |
337 | template <typename Other_> |
338 | CYJavaEnv(const CYJavaRef<Other_> &value) : | |
339 | jni(value.jni()) | |
340 | { | |
341 | } | |
342 | ||
fc664744 JF |
343 | operator JNIEnv *() const { |
344 | return jni; | |
dbf05bfd JF |
345 | } |
346 | ||
fc664744 JF |
347 | JNIEnv *operator ->() const { |
348 | return jni; | |
dbf05bfd JF |
349 | } |
350 | ||
fc664744 JF |
351 | CYJavaLocal<jclass> FindClass(const char *name) const { |
352 | return {jni, _envcall(jni, FindClass(name))}; | |
dbf05bfd JF |
353 | } |
354 | ||
92536081 JF |
355 | CYJavaLocal<jclass> FindClass$(const char *name) const { |
356 | jclass value(jni->FindClass(name)); | |
357 | jni->ExceptionClear(); | |
358 | return {jni, value}; | |
359 | } | |
360 | ||
fc664744 JF |
361 | CYJavaLocal<jclass> GetObjectClass(jobject object) const { |
362 | return {jni, _envcall(jni, GetObjectClass(object))}; | |
363 | } | |
364 | ||
365 | CYJavaLocal<jclass> GetSuperclass(jclass _class) const { | |
366 | return {jni, _envcall(jni, GetSuperclass(_class))}; | |
367 | } | |
368 | ||
369 | CYJavaLocal<jobject> NewObject(jclass _class, jmethodID method, ...) const { | |
370 | va_list args; | |
371 | va_start(args, method); | |
372 | jobject object(_envcall(jni, NewObjectV(_class, method, args))); | |
373 | va_end(args); | |
374 | return {jni, object}; | |
375 | } | |
376 | ||
377 | CYJavaLocal<jobject> NewObjectA(jclass _class, jmethodID method, jvalue *args) const { | |
378 | return {jni, _envcall(jni, NewObjectA(_class, method, args))}; | |
dbf05bfd | 379 | } |
fc664744 | 380 | |
92536081 JF |
381 | CYJavaLocal<jobjectArray> NewObjectArray(jsize length, jclass _class, jobject initial) const { |
382 | return {jni, _envcall(jni, NewObjectArray(length, _class, initial))}; | |
383 | } | |
384 | ||
fc664744 JF |
385 | CYJavaLocal<jstring> NewString(const jchar *data, jsize size) const { |
386 | return {jni, _envcall(jni, NewString(data, size))}; | |
387 | } | |
388 | ||
389 | #define CYJavaEnv_(Code) \ | |
390 | template <typename... Args_> \ | |
391 | void Code(Args_ &&... args) const { \ | |
392 | _envcallv(jni, Code(cy::Forward<Args_>(args)...)); \ | |
393 | } | |
394 | ||
395 | #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \ | |
396 | CYJavaEnv_(Get ## Typ ## ArrayRegion) \ | |
397 | CYJavaEnv_(Set ## Typ ## Field) \ | |
398 | CYJavaEnv_(SetStatic ## Typ ## Field) | |
399 | CYJavaForEachPrimitive | |
400 | #undef CYJavaForEachPrimitive_ | |
401 | ||
402 | CYJavaEnv_(CallVoidMethod) | |
403 | CYJavaEnv_(CallStaticVoidMethod) | |
404 | CYJavaEnv_(CallVoidMethodA) | |
405 | CYJavaEnv_(CallStaticVoidMethodA) | |
406 | CYJavaEnv_(SetObjectArrayElement) | |
407 | CYJavaEnv_(SetObjectField) | |
408 | CYJavaEnv_(SetStaticObjectField) | |
409 | #undef CYJavaEnv_ | |
410 | ||
411 | #define CYJavaEnv_(Code) \ | |
412 | template <typename... Args_> \ | |
0e832de4 | 413 | auto Code(Args_ &&... args) const -> decltype(jni->Code(cy::Forward<Args_>(args)...)) { \ |
fc664744 JF |
414 | return _envcall(jni, Code(cy::Forward<Args_>(args)...)); \ |
415 | } | |
416 | ||
417 | #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \ | |
418 | CYJavaEnv_(Call ## Typ ## Method) \ | |
419 | CYJavaEnv_(CallStatic ## Typ ## Method) \ | |
420 | CYJavaEnv_(Call ## Typ ## MethodA) \ | |
421 | CYJavaEnv_(CallStatic ## Typ ## MethodA) \ | |
422 | CYJavaEnv_(Get ## Typ ## Field) \ | |
423 | CYJavaEnv_(GetStatic ## Typ ## Field) | |
424 | CYJavaForEachPrimitive | |
425 | #undef CYJavaForEachPrimitive_ | |
426 | ||
427 | CYJavaEnv_(FromReflectedField) | |
428 | CYJavaEnv_(FromReflectedMethod) | |
429 | CYJavaEnv_(GetArrayLength) | |
430 | CYJavaEnv_(GetMethodID) | |
431 | CYJavaEnv_(GetStaticMethodID) | |
432 | CYJavaEnv_(IsSameObject) | |
f2c357f9 | 433 | CYJavaEnv_(RegisterNatives) |
fc664744 JF |
434 | #undef CYJavaEnv_ |
435 | ||
436 | #define CYJavaEnv_(Code) \ | |
437 | template <typename Other_, typename... Args_> \ | |
438 | auto Code(Args_ &&... args) const -> CYJavaLocal<Other_> { \ | |
439 | return {jni, static_cast<Other_>(_envcall(jni, Code(cy::Forward<Args_>(args)...)))}; \ | |
440 | } | |
441 | ||
442 | CYJavaEnv_(CallObjectMethod) | |
443 | CYJavaEnv_(CallStaticObjectMethod) | |
444 | CYJavaEnv_(CallObjectMethodA) | |
445 | CYJavaEnv_(CallStaticObjectMethodA) | |
446 | CYJavaEnv_(GetObjectArrayElement) | |
447 | CYJavaEnv_(GetObjectField) | |
448 | CYJavaEnv_(GetStaticObjectField) | |
449 | #undef CYJavaEnv_ | |
dbf05bfd JF |
450 | }; |
451 | ||
fc664744 JF |
452 | static CYJavaLocal<jstring> CYCastJavaString(const CYJavaRef<jobject> &value) { |
453 | CYJavaEnv jni(value); | |
454 | auto Object$(jni.FindClass("java/lang/Object")); | |
455 | auto Object$toString(jni.GetMethodID(Object$, "toString", "()Ljava/lang/String;")); | |
456 | return jni.CallObjectMethod<jstring>(value, Object$toString); | |
457 | } | |
458 | ||
92536081 JF |
459 | static CYJavaLocal<jstring> CYCastJavaString(const CYJavaEnv &jni, CYUTF16String value) { |
460 | return jni.NewString(value.data, value.size); | |
461 | } | |
462 | ||
463 | static CYJavaLocal<jstring> CYCastJavaString(const CYJavaEnv &jni, CYUTF8String value) { | |
464 | // XXX: if there are no nulls then you can do this faster | |
465 | CYPool pool; | |
466 | return CYCastJavaString(jni, CYPoolUTF16String(pool, value)); | |
467 | } | |
468 | ||
469 | static CYJavaLocal<jstring> CYCastJavaString(const CYJavaEnv &jni, const char *value) { | |
470 | return CYCastJavaString(jni, CYUTF8String(value)); | |
471 | } | |
472 | ||
473 | static CYJavaLocal<jstring> CYCastJavaString(const CYJavaEnv &jni, JSContextRef context, JSStringRef value) { | |
474 | return CYCastJavaString(jni, CYCastUTF16String(value)); | |
475 | } | |
476 | ||
477549f5 JF |
477 | static JSValueRef CYCastJSValue(JSContextRef context, const CYJavaRef<jobject> &value); |
478 | ||
479 | template <typename Other_> | |
480 | static _finline JSValueRef CYCastJSValue(JSContextRef context, const CYJavaRef<Other_> &value) { | |
481 | return CYCastJSValue(context, value.template cast<jobject>()); | |
482 | } | |
483 | ||
dbf05bfd JF |
484 | template <typename Type_> |
485 | static _finline JSValueRef CYJavaCastJSValue(JSContextRef context, Type_ value) { | |
486 | return CYCastJSValue(context, value); | |
487 | } | |
488 | ||
489 | static _finline JSValueRef CYJavaCastJSValue(JSContextRef context, jboolean value) { | |
490 | return CYCastJSValue(context, static_cast<bool>(value)); | |
491 | } | |
492 | ||
477549f5 JF |
493 | JSValueRef CYJavaError::CastJSValue(JSContextRef context, const char *name) const { |
494 | return CYCastJSValue(context, value_); | |
495 | } | |
496 | ||
92536081 JF |
497 | struct CYJava : |
498 | CYRoot | |
499 | { | |
500 | CYJavaGlobal<jobject> loader_; | |
501 | jmethodID ClassLoader$loadClass; | |
502 | ||
503 | CYJava() { | |
504 | } | |
505 | ||
506 | bool Setup(JNIEnv *env) { | |
507 | if (loader_) | |
508 | return false; | |
509 | ||
510 | CYJavaEnv jni(env); | |
511 | CYPool pool; | |
512 | ||
513 | auto ClassLoader$(jni.FindClass("java/lang/ClassLoader")); | |
514 | ClassLoader$loadClass = jni.GetMethodID(ClassLoader$, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); | |
515 | ||
516 | auto ClassLoader$getSystemClassLoader(jni.GetStaticMethodID(ClassLoader$, "getSystemClassLoader", "()Ljava/lang/ClassLoader;")); | |
517 | auto parent(jni.CallStaticObjectMethod<jobject>(ClassLoader$, ClassLoader$getSystemClassLoader)); | |
518 | ||
519 | auto path(CYCastJavaString(jni, pool.strcat("file://", CYPoolLibraryPath(pool), "/libcycript.jar", NULL))); | |
520 | ||
521 | auto PathClassLoader$(jni.FindClass$("dalvik/system/PathClassLoader")); | |
522 | if (PathClassLoader$) { | |
523 | auto PathClassLoader$$init$(jni.GetMethodID(PathClassLoader$, "<init>", "(Ljava/lang/String;Ljava/lang/ClassLoader;)V")); | |
524 | loader_ = jni.NewObject(PathClassLoader$, PathClassLoader$$init$, path.get(), parent.get()); | |
525 | } else { | |
526 | auto URL$(jni.FindClass("java/net/URL")); | |
527 | auto URL$$init$(jni.GetMethodID(URL$, "<init>", "(Ljava/lang/String;)V")); | |
528 | ||
529 | auto URLClassLoader$(jni.FindClass("java/net/URLClassLoader")); | |
530 | auto URLClassLoader$$init$(jni.GetMethodID(URLClassLoader$, "<init>", "([Ljava/net/URL;Ljava/lang/ClassLoader;)V")); | |
531 | ||
532 | auto url(jni.NewObject(URL$, URL$$init$, path.get())); | |
533 | auto urls(jni.NewObjectArray(1, URL$, url)); | |
534 | // XXX: .cast().get() <- this is required :/ | |
535 | loader_ = jni.NewObject(URLClassLoader$, URLClassLoader$$init$, urls.cast<jobject>().get(), parent.get()); | |
536 | } | |
537 | ||
538 | return true; | |
539 | } | |
540 | ||
541 | CYJavaLocal<jclass> LoadClass(const char *name) { | |
542 | _assert(loader_); | |
543 | CYJavaEnv jni(loader_); | |
544 | return jni.CallObjectMethod<jclass>(loader_, ClassLoader$loadClass, CYCastJavaString(jni, name).get()); | |
545 | } | |
546 | }; | |
547 | ||
dbf05bfd JF |
548 | static std::map<std::string, CYJavaPrimitive> Primitives_; |
549 | ||
fc664744 JF |
550 | static CYJavaPrimitive CYJavaGetPrimitive(JSContextRef context, const CYJavaRef<jclass> &type, jmethodID Class$get$$Name) { |
551 | CYJavaEnv jni(type); | |
552 | auto string(jni.CallObjectMethod<jstring>(type, Class$get$$Name)); | |
553 | _assert(string); | |
554 | ||
555 | CYJavaUTF8String name(string); | |
dbf05bfd JF |
556 | auto primitive(Primitives_.find(name)); |
557 | return primitive != Primitives_.end() ? primitive->second : CYJavaPrimitiveObject; | |
558 | } | |
559 | ||
560 | typedef std::vector<CYJavaPrimitive> CYJavaShorty; | |
561 | ||
fc664744 JF |
562 | static CYJavaShorty CYJavaGetShorty(JSContextRef context, const CYJavaRef<jobjectArray> &types, jmethodID Class$get$$Name) { |
563 | CYJavaEnv jni(types); | |
564 | size_t count(jni.GetArrayLength(types)); | |
dbf05bfd JF |
565 | CYJavaShorty shorty(count); |
566 | for (size_t index(0); index != count; ++index) | |
fc664744 | 567 | shorty[index] = CYJavaGetPrimitive(context, jni.GetObjectArrayElement<jclass>(types, index), Class$get$$Name); |
dbf05bfd JF |
568 | return shorty; |
569 | } | |
570 | ||
571 | struct CYJavaField { | |
572 | jfieldID field_; | |
573 | CYJavaPrimitive primitive_; | |
574 | }; | |
575 | ||
576 | typedef std::map<std::string, CYJavaField> CYJavaFieldMap; | |
577 | ||
578 | struct CYJavaSignature { | |
4b645e23 | 579 | CYJavaGlobal<jobject> reflected_; |
fc664744 | 580 | jmethodID method_; |
4b645e23 JF |
581 | CYJavaPrimitive primitive_; |
582 | CYJavaShorty shorty_; | |
583 | ||
fc664744 JF |
584 | CYJavaSignature(const CYJavaRef<jobject> &reflected, jmethodID method, CYJavaPrimitive primitive, const CYJavaShorty &shorty) : |
585 | reflected_(reflected), | |
4b645e23 | 586 | method_(method), |
4b645e23 JF |
587 | primitive_(primitive), |
588 | shorty_(shorty) | |
dbf05bfd JF |
589 | { |
590 | } | |
591 | ||
6bbc110e | 592 | // XXX: the shorty doesn't store enough information |
dbf05bfd | 593 | bool operator <(const CYJavaSignature &rhs) const { |
6bbc110e | 594 | return shorty_ < rhs.shorty_; |
dbf05bfd JF |
595 | } |
596 | }; | |
597 | ||
6bbc110e JF |
598 | typedef std::set<CYJavaSignature> CYJavaOverload; |
599 | typedef std::map<unsigned, CYJavaOverload> CYJavaOverloads; | |
dbf05bfd JF |
600 | |
601 | struct CYJavaMethod : | |
d4222ffb | 602 | CYRoot |
dbf05bfd | 603 | { |
7ab9e677 JF |
604 | CYUTF8String type_; |
605 | CYUTF8String name_; | |
6bbc110e | 606 | CYJavaOverloads overloads_; |
dbf05bfd | 607 | |
7ab9e677 JF |
608 | CYJavaMethod(CYUTF8String type, CYUTF8String name, const CYJavaOverloads &overloads) : |
609 | type_(CYPoolUTF8String(*pool_, type)), | |
610 | name_(CYPoolUTF8String(*pool_, name)), | |
6bbc110e | 611 | overloads_(overloads) |
c9c16dde JF |
612 | { |
613 | } | |
614 | }; | |
615 | ||
7ab9e677 JF |
616 | struct CYJavaInstanceMethod : |
617 | CYJavaMethod | |
c9c16dde | 618 | { |
7ab9e677 JF |
619 | using CYJavaMethod::CYJavaMethod; |
620 | }; | |
c9c16dde | 621 | |
7ab9e677 JF |
622 | struct CYJavaStaticMethod : |
623 | CYJavaMethod | |
624 | { | |
625 | using CYJavaMethod::CYJavaMethod; | |
dbf05bfd JF |
626 | }; |
627 | ||
628 | struct CYJavaClass : | |
d4222ffb | 629 | CYRoot |
dbf05bfd | 630 | { |
d4222ffb | 631 | CYJavaGlobal<jclass> value_; |
c9c16dde JF |
632 | bool interface_; |
633 | ||
dbf05bfd JF |
634 | CYJavaFieldMap static_; |
635 | CYJavaFieldMap instance_; | |
6bbc110e | 636 | CYJavaOverloads overloads_; |
dbf05bfd | 637 | |
fc664744 | 638 | CYJavaClass(const CYJavaRef<jclass> &value, bool interface) : |
d4222ffb | 639 | value_(value), |
c9c16dde | 640 | interface_(interface) |
dbf05bfd JF |
641 | { |
642 | } | |
643 | }; | |
644 | ||
fc664744 | 645 | static JSObjectRef CYGetJavaClass(JSContextRef context, const CYJavaRef<jclass> &_class); |
8effd381 | 646 | |
dbf05bfd | 647 | struct CYJavaObject : |
d4222ffb | 648 | CYRoot |
dbf05bfd | 649 | { |
d4222ffb | 650 | CYJavaGlobal<jobject> value_; |
8effd381 JF |
651 | CYJavaClass *table_; |
652 | ||
fc664744 | 653 | CYJavaObject(const CYJavaRef<jobject> &value, CYJavaClass *table) : |
d4222ffb | 654 | value_(value), |
4b645e23 | 655 | table_(table) |
dbf05bfd JF |
656 | { |
657 | } | |
658 | ||
659 | JSValueRef GetPrototype(JSContextRef context) const; | |
660 | }; | |
661 | ||
8effd381 | 662 | struct CYJavaInterior : |
d4222ffb | 663 | CYRoot |
8effd381 | 664 | { |
d4222ffb | 665 | CYJavaGlobal<jobject> value_; |
8effd381 JF |
666 | CYJavaClass *table_; |
667 | ||
fc664744 | 668 | CYJavaInterior(const CYJavaRef<jobject> &value, CYJavaClass *table) : |
d4222ffb | 669 | value_(value), |
8effd381 JF |
670 | table_(table) |
671 | { | |
672 | } | |
673 | }; | |
674 | ||
c9c16dde | 675 | struct CYJavaStaticInterior : |
d4222ffb | 676 | CYRoot |
4b645e23 | 677 | { |
d4222ffb | 678 | CYJavaGlobal<jclass> value_; |
4b645e23 JF |
679 | CYJavaClass *table_; |
680 | ||
fc664744 | 681 | CYJavaStaticInterior(const CYJavaRef<jclass> &value, CYJavaClass *table) : |
d4222ffb | 682 | value_(value), |
4b645e23 JF |
683 | table_(table) |
684 | { | |
685 | } | |
686 | }; | |
687 | ||
688 | struct CYJavaArray : | |
d4222ffb | 689 | CYRoot |
4b645e23 | 690 | { |
d4222ffb | 691 | CYJavaGlobal<jarray> value_; |
4b645e23 JF |
692 | CYJavaPrimitive primitive_; |
693 | ||
fc664744 | 694 | CYJavaArray(const CYJavaRef<jarray> &value, CYJavaPrimitive primitive) : |
d4222ffb | 695 | value_(value), |
4b645e23 JF |
696 | primitive_(primitive) |
697 | { | |
698 | } | |
699 | ||
700 | JSValueRef GetPrototype(JSContextRef context) const; | |
701 | }; | |
702 | ||
dbf05bfd | 703 | struct CYJavaPackage : |
d4222ffb | 704 | CYRoot |
dbf05bfd | 705 | { |
f3e85e94 JF |
706 | JNIEnv *jni_; |
707 | ||
dbf05bfd JF |
708 | typedef std::vector<std::string> Path; |
709 | Path package_; | |
710 | ||
f3e85e94 JF |
711 | _finline CYJavaPackage(JNIEnv *jni, const Path &package) : |
712 | jni_(jni), | |
dbf05bfd JF |
713 | package_(package) |
714 | { | |
715 | } | |
716 | }; | |
717 | ||
dbf05bfd | 718 | JSValueRef CYJavaObject::GetPrototype(JSContextRef context) const { |
fc664744 JF |
719 | CYJavaEnv jni(value_); |
720 | return CYGetProperty(context, CYGetJavaClass(context, jni.GetObjectClass(value_)), prototype_s); | |
dbf05bfd JF |
721 | } |
722 | ||
4b645e23 JF |
723 | JSValueRef CYJavaArray::GetPrototype(JSContextRef context) const { |
724 | return CYGetCachedObject(context, CYJSString("Array_prototype")); | |
725 | } | |
726 | ||
fc664744 JF |
727 | static JSValueRef CYCastJSValue(JSContextRef context, const CYJavaRef<jobject> &value) { |
728 | if (!value) | |
dbf05bfd | 729 | return CYJSNull(context); |
fc664744 JF |
730 | CYJavaEnv jni(value); |
731 | ||
732 | auto _class(jni.GetObjectClass(value)); | |
733 | if (jni.IsSameObject(_class, jni.FindClass("java/lang/String"))) | |
734 | return CYCastJSValue(context, CYJSString(value.cast<jstring>())); | |
735 | ||
736 | auto Class$(jni.FindClass("java/lang/Class")); | |
737 | auto Class$isArray(jni.GetMethodID(Class$, "isArray", "()Z")); | |
738 | if (jni.CallBooleanMethod(_class, Class$isArray)) { | |
739 | auto Class$getComponentType(jni.GetMethodID(Class$, "getComponentType", "()Ljava/lang/Class;")); | |
740 | auto component(jni.CallObjectMethod<jclass>(_class, Class$getComponentType)); | |
741 | auto Class$getName(jni.GetMethodID(Class$, "getName", "()Ljava/lang/String;")); | |
d4222ffb | 742 | return CYPrivate<CYJavaArray>::Make(context, value.cast<jarray>(), CYJavaGetPrimitive(context, component, Class$getName)); |
c9c16dde JF |
743 | } |
744 | ||
92536081 JF |
745 | auto java(reinterpret_cast<CYJava *>(JSObjectGetPrivate(CYGetCachedObject(context, CYJSString("Java"))))); |
746 | auto Wrapper$(java->LoadClass("Cycript$Wrapper")); | |
747 | ||
fc664744 JF |
748 | if (jni.IsSameObject(_class, Wrapper$)) { |
749 | auto Wrapper$getProtect(jni.GetMethodID(Wrapper$, "getProtect", "()J")); | |
750 | auto &protect(*reinterpret_cast<CYProtect *>(jni.CallLongMethod(value, Wrapper$getProtect))); | |
c9c16dde | 751 | return protect; |
4b645e23 JF |
752 | } |
753 | ||
fc664744 | 754 | CYJavaClass *table(reinterpret_cast<CYJavaClass *>(JSObjectGetPrivate(CYGetJavaClass(context, _class)))); |
d4222ffb | 755 | return CYPrivate<CYJavaObject>::Make(context, value, table); |
dbf05bfd JF |
756 | } |
757 | ||
fc664744 JF |
758 | static _finline JSObjectRef CYCastJSObject(JSContextRef context, const CYJavaRef<jobject> &value) { |
759 | return CYCastJSObject(context, CYCastJSValue(context, value)); | |
c9c16dde JF |
760 | } |
761 | ||
dbf05bfd | 762 | #define CYCastJava$(T, Type, jtype, Cast) \ |
fc664744 JF |
763 | _disused static CYJavaLocal<jobject> CYCastJava ## Type(const CYJavaEnv &jni, JSContextRef context, JSValueRef value) { \ |
764 | auto Type$(jni.FindClass("java/lang/" #Type)); \ | |
765 | auto Type$init$(jni.GetMethodID(Type$, "<init>", "(" #T ")V")); \ | |
766 | return jni.NewObject(Type$, Type$init$, static_cast<jtype>(Cast(context, value))); \ | |
dbf05bfd JF |
767 | } |
768 | ||
769 | CYCastJava$(Z, Boolean, jboolean, CYCastBool) | |
770 | CYCastJava$(B, Byte, jbyte, CYCastDouble) | |
771 | CYCastJava$(C, Character, jchar, CYCastDouble) | |
772 | CYCastJava$(S, Short, jshort, CYCastDouble) | |
773 | CYCastJava$(I, Integer, jint, CYCastDouble) | |
774 | CYCastJava$(J, Long, jlong, CYCastDouble) | |
775 | CYCastJava$(F, Float, jfloat, CYCastDouble) | |
776 | CYCastJava$(D, Double, jdouble, CYCastDouble) | |
777 | ||
c9c16dde | 778 | static CYJavaClass *CYGetJavaTable(JSContextRef context, JSObjectRef object) { |
d4222ffb | 779 | if (!JSValueIsObjectOfClass(context, object, CYPrivate<CYJavaClass>::Class_)) |
c9c16dde JF |
780 | return NULL; |
781 | return reinterpret_cast<CYJavaClass *>(JSObjectGetPrivate(object)); | |
782 | } | |
783 | ||
784 | static CYJavaObject *CYGetJavaObject(JSContextRef context, JSObjectRef object) { | |
d4222ffb | 785 | if (!JSValueIsObjectOfClass(context, object, CYPrivate<CYJavaObject>::Class_)) |
c9c16dde JF |
786 | return NULL; |
787 | return reinterpret_cast<CYJavaObject *>(JSObjectGetPrivate(object)); | |
788 | } | |
789 | ||
fc664744 | 790 | static CYJavaLocal<jobject> CYCastJavaObject(const CYJavaEnv &jni, JSContextRef context, JSObjectRef value) { |
c9c16dde | 791 | if (CYJavaObject *internal = CYGetJavaObject(context, value)) |
dbf05bfd | 792 | return internal->value_; |
dbf05bfd | 793 | |
92536081 JF |
794 | auto java(reinterpret_cast<CYJava *>(JSObjectGetPrivate(CYGetCachedObject(context, CYJSString("Java"))))); |
795 | auto Wrapper$(java->LoadClass("Cycript$Wrapper")); | |
796 | ||
fc664744 | 797 | auto Wrapper$$init$(jni.GetMethodID(Wrapper$, "<init>", "(J)V")); |
c9c16dde | 798 | CYProtect *protect(new CYProtect(context, value)); |
fc664744 | 799 | return jni.NewObject(Wrapper$, Wrapper$$init$, reinterpret_cast<jlong>(protect)); |
dbf05bfd JF |
800 | } |
801 | ||
fc664744 | 802 | static CYJavaLocal<jobject> CYCastJavaObject(const CYJavaEnv &jni, JSContextRef context, JSValueRef value) { |
dbf05bfd JF |
803 | switch (JSValueGetType(context, value)) { |
804 | case kJSTypeNull: | |
fc664744 | 805 | return {jni, NULL}; |
dbf05bfd JF |
806 | case kJSTypeBoolean: |
807 | return CYCastJavaBoolean(jni, context, value); | |
808 | case kJSTypeNumber: | |
809 | return CYCastJavaDouble(jni, context, value); | |
810 | case kJSTypeString: | |
c9c16dde | 811 | return CYCastJavaString(jni, context, CYJSString(context, value)); |
dbf05bfd JF |
812 | case kJSTypeObject: |
813 | return CYCastJavaObject(jni, context, CYCastJSObject(context, value)); | |
814 | ||
815 | case kJSTypeUndefined: | |
c9c16dde | 816 | // XXX: I am currently relying on this for dynamic proxy of void method |
fc664744 | 817 | return {jni, NULL}; |
dbf05bfd JF |
818 | default: |
819 | _assert(false); | |
820 | } | |
821 | } | |
822 | ||
fc664744 JF |
823 | static JSObjectRef CYGetJavaClass(JSContextRef context, const CYJavaRef<jclass> &value) { |
824 | CYJavaEnv jni(value); | |
825 | CYJavaFrame frame(jni, 64); | |
826 | ||
dbf05bfd JF |
827 | JSObjectRef global(CYGetGlobalObject(context)); |
828 | JSObjectRef cy(CYCastJSObject(context, CYGetProperty(context, global, cy_s))); | |
829 | ||
fc664744 JF |
830 | auto Class$(jni.FindClass("java/lang/Class")); |
831 | auto Class$getName(jni.GetMethodID(Class$, "getName", "()Ljava/lang/String;")); | |
dbf05bfd | 832 | |
7ab9e677 JF |
833 | auto string(jni.CallObjectMethod<jstring>(value, Class$getName)); |
834 | CYJavaUTF8String utf8(string); | |
835 | CYJSString name(utf8); | |
836 | ||
dbf05bfd JF |
837 | JSValueRef cached(CYGetProperty(context, cy, name)); |
838 | if (!JSValueIsUndefined(context, cached)) | |
839 | return CYCastJSObject(context, cached); | |
840 | ||
fc664744 JF |
841 | JSObjectRef constructor; |
842 | JSObjectRef prototype; | |
c9c16dde | 843 | |
fc664744 | 844 | { |
dbf05bfd | 845 | |
fc664744 | 846 | auto Class$isInterface(jni.GetMethodID(Class$, "isInterface", "()Z")); |
dbf05bfd | 847 | |
fc664744 JF |
848 | auto Class$getDeclaredConstructors(jni.GetMethodID(Class$, "getDeclaredConstructors", "()[Ljava/lang/reflect/Constructor;")); |
849 | auto Class$getDeclaredFields(jni.GetMethodID(Class$, "getDeclaredFields", "()[Ljava/lang/reflect/Field;")); | |
850 | auto Class$getDeclaredMethods(jni.GetMethodID(Class$, "getDeclaredMethods", "()[Ljava/lang/reflect/Method;")); | |
dbf05bfd | 851 | |
fc664744 JF |
852 | auto Constructor$(jni.FindClass("java/lang/reflect/Constructor")); |
853 | //auto Constructor$getModifiers(jni.GetMethodID(Constructor$, "getModifiers", "()I")); | |
854 | auto Constructor$getParameterTypes(jni.GetMethodID(Constructor$, "getParameterTypes", "()[Ljava/lang/Class;")); | |
dbf05bfd | 855 | |
fc664744 JF |
856 | auto Field$(jni.FindClass("java/lang/reflect/Field")); |
857 | auto Field$getModifiers(jni.GetMethodID(Field$, "getModifiers", "()I")); | |
858 | auto Field$getName(jni.GetMethodID(Field$, "getName", "()Ljava/lang/String;")); | |
859 | auto Field$getType(jni.GetMethodID(Field$, "getType", "()Ljava/lang/Class;")); | |
dbf05bfd | 860 | |
fc664744 JF |
861 | auto Method$(jni.FindClass("java/lang/reflect/Method")); |
862 | auto Method$getModifiers(jni.GetMethodID(Method$, "getModifiers", "()I")); | |
863 | auto Method$getName(jni.GetMethodID(Method$, "getName", "()Ljava/lang/String;")); | |
864 | auto Method$getParameterTypes(jni.GetMethodID(Method$, "getParameterTypes", "()[Ljava/lang/Class;")); | |
865 | auto Method$getReturnType(jni.GetMethodID(Method$, "getReturnType", "()Ljava/lang/Class;")); | |
dbf05bfd | 866 | |
fc664744 JF |
867 | auto Modifier$(jni.FindClass("java/lang/reflect/Modifier")); |
868 | auto Modifier$isStatic(jni.GetStaticMethodID(Modifier$, "isStatic", "(I)Z")); | |
dbf05bfd | 869 | |
fc664744 JF |
870 | auto interface(jni.CallBooleanMethod(value, Class$isInterface)); |
871 | auto table(new CYJavaClass(value, interface)); | |
872 | ||
873 | for (CYJavaLocal<jclass> prototype(value); prototype; prototype = jni.GetSuperclass(prototype)) { | |
874 | auto fields(jni.CallObjectMethod<jobjectArray>(prototype, Class$getDeclaredFields)); | |
875 | ||
876 | for (jsize i(0), e(jni.GetArrayLength(fields)); i != e; ++i) { | |
877 | auto field(jni.GetObjectArrayElement<jobject>(fields, e - i - 1)); | |
878 | auto modifiers(jni.CallIntMethod(field, Field$getModifiers)); | |
879 | auto instance(!jni.CallStaticBooleanMethod(Modifier$, Modifier$isStatic, modifiers)); | |
dbf05bfd | 880 | auto &map(instance ? table->instance_ : table->static_); |
3853f099 JF |
881 | auto string(jni.CallObjectMethod<jstring>(field, Field$getName)); |
882 | CYJavaUTF8String name(string); | |
fc664744 JF |
883 | auto id(jni.FromReflectedField(field)); |
884 | auto type(jni.CallObjectMethod<jclass>(field, Field$getType)); | |
885 | map.insert(std::make_pair(std::string(name), CYJavaField{id, CYJavaGetPrimitive(context, type, Class$getName)})); | |
dbf05bfd JF |
886 | } |
887 | } | |
888 | ||
d4222ffb | 889 | constructor = JSObjectMake(context, CYPrivate<CYJavaClass>::Class_, table); |
dbf05bfd | 890 | |
fc664744 | 891 | prototype = JSObjectMake(context, NULL, NULL); |
dbf05bfd JF |
892 | CYSetProperty(context, constructor, prototype_s, prototype, kJSPropertyAttributeDontEnum); |
893 | ||
fc664744 | 894 | auto constructors(jni.CallObjectMethod<jobjectArray>(value, Class$getDeclaredConstructors)); |
dbf05bfd | 895 | |
fc664744 JF |
896 | for (jsize i(0), e(jni.GetArrayLength(constructors)); i != e; ++i) { |
897 | auto constructor(jni.GetObjectArrayElement<jobject>(constructors, i)); | |
898 | auto parameters(jni.CallObjectMethod<jobjectArray>(constructor, Constructor$getParameterTypes)); | |
899 | CYJavaShorty shorty(CYJavaGetShorty(context, parameters, Class$getName)); | |
900 | auto id(jni.FromReflectedMethod(constructor)); | |
6bbc110e | 901 | table->overloads_[shorty.size()].insert(CYJavaSignature(constructor, id, CYJavaPrimitiveObject, shorty)); |
dbf05bfd JF |
902 | } |
903 | ||
6bbc110e JF |
904 | std::map<std::pair<bool, std::string>, CYJavaOverloads> entries; |
905 | ||
906 | bool base(false); | |
907 | for (CYJavaLocal<jclass> prototype(value); prototype; prototype = jni.GetSuperclass(prototype)) { | |
908 | auto methods(jni.CallObjectMethod<jobjectArray>(prototype, Class$getDeclaredMethods)); | |
dbf05bfd | 909 | |
6bbc110e JF |
910 | for (jsize i(0), e(jni.GetArrayLength(methods)); i != e; ++i) { |
911 | auto method(jni.GetObjectArrayElement<jobject>(methods, i)); | |
912 | auto modifiers(jni.CallIntMethod(method, Method$getModifiers)); | |
913 | auto instance(!jni.CallStaticBooleanMethod(Modifier$, Modifier$isStatic, modifiers)); | |
3853f099 JF |
914 | auto string(jni.CallObjectMethod<jstring>(method, Method$getName)); |
915 | CYJavaUTF8String name(string); | |
6bbc110e JF |
916 | |
917 | auto parameters(jni.CallObjectMethod<jobjectArray>(method, Method$getParameterTypes)); | |
918 | CYJavaShorty shorty(CYJavaGetShorty(context, parameters, Class$getName)); | |
919 | ||
920 | CYJavaOverload *overload; | |
921 | if (!base) | |
922 | overload = &entries[std::make_pair(instance, std::string(name))][shorty.size()]; | |
923 | else { | |
924 | auto entry(entries.find(std::make_pair(instance, std::string(name)))); | |
925 | if (entry == entries.end()) | |
926 | continue; | |
927 | overload = &entry->second[shorty.size()]; | |
928 | } | |
929 | ||
930 | auto type(jni.CallObjectMethod<jclass>(method, Method$getReturnType)); | |
931 | auto primitive(CYJavaGetPrimitive(context, type, Class$getName)); | |
932 | auto id(jni.FromReflectedMethod(method)); | |
933 | overload->insert(CYJavaSignature(method, id, primitive, shorty)); | |
934 | } | |
dbf05bfd | 935 | |
6bbc110e | 936 | base = true; |
dbf05bfd JF |
937 | } |
938 | ||
939 | for (const auto &entry : entries) { | |
940 | bool instance(entry.first.first); | |
7ab9e677 | 941 | CYJSString method(entry.first.second); |
dbf05bfd | 942 | auto &overload(entry.second); |
c9c16dde | 943 | if (instance) |
7ab9e677 | 944 | CYSetProperty(context, prototype, method, CYPrivate<CYJavaInstanceMethod>::Make(context, utf8, entry.first.second.c_str(), overload), kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete); |
c9c16dde | 945 | else |
7ab9e677 | 946 | CYSetProperty(context, constructor, method, CYPrivate<CYJavaStaticMethod>::Make(context, utf8, entry.first.second.c_str(), overload), kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete); |
dbf05bfd JF |
947 | } |
948 | ||
fc664744 JF |
949 | } |
950 | ||
dbf05bfd JF |
951 | // XXX: for some reason kJSPropertyAttributeDontEnum doesn't work if there's already a property with the same name |
952 | // by not linking the prototypes until after we set the properties, we hide the parent property from this issue :( | |
953 | ||
fc664744 JF |
954 | if (auto super = jni.GetSuperclass(value)) { |
955 | JSObjectRef parent(CYGetJavaClass(context, super)); | |
4b645e23 | 956 | CYSetPrototype(context, constructor, parent); |
dbf05bfd JF |
957 | CYSetPrototype(context, prototype, CYGetProperty(context, parent, prototype_s)); |
958 | } | |
959 | ||
960 | CYSetProperty(context, cy, name, constructor); | |
961 | return constructor; | |
962 | } | |
963 | ||
4b645e23 JF |
964 | static void CYCastJavaNumeric(jvalue &value, CYJavaPrimitive primitive, JSContextRef context, JSValueRef argument) { |
965 | switch (primitive) { | |
966 | #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \ | |
967 | case CYJavaPrimitive ## Type: \ | |
968 | value.t = static_cast<j ## type>(CYCastDouble(context, argument)); \ | |
969 | break; | |
dbf05bfd JF |
970 | CYJavaForEachPrimitive |
971 | #undef CYJavaForEachPrimitive_ | |
4b645e23 JF |
972 | default: |
973 | _assert(false); | |
974 | } | |
975 | } | |
976 | ||
4e2cc9d3 JF |
977 | static bool CYCastJavaArguments(const CYJavaFrame &frame, const CYJavaShorty &shorty, JSContextRef context, const JSValueRef arguments[], jvalue *array) { |
978 | CYJavaEnv jni(frame); | |
979 | ||
4b645e23 JF |
980 | for (size_t index(0); index != shorty.size(); ++index) { |
981 | JSValueRef argument(arguments[index]); | |
982 | JSType type(JSValueGetType(context, argument)); | |
983 | jvalue &value(array[index]); | |
984 | ||
985 | switch (CYJavaPrimitive primitive = shorty[index]) { | |
986 | case CYJavaPrimitiveObject: | |
4e2cc9d3 | 987 | // XXX: figure out a way to tie this in to the CYJavaFrame |
fc664744 | 988 | value.l = CYCastJavaObject(jni, context, argument).leak(); |
4b645e23 JF |
989 | break; |
990 | ||
991 | case CYJavaPrimitiveBoolean: | |
992 | if (type != kJSTypeBoolean) | |
993 | return false; | |
994 | value.z = CYCastBool(context, argument); | |
995 | break; | |
996 | ||
997 | case CYJavaPrimitiveCharacter: | |
998 | if (type == kJSTypeNumber) | |
999 | CYCastJavaNumeric(value, primitive, context, argument); | |
1000 | else if (type != kJSTypeString) | |
1001 | return false; | |
1002 | else { | |
1003 | CYJSString string(context, argument); | |
1004 | if (JSStringGetLength(string) != 1) | |
1005 | return false; | |
1006 | else | |
1007 | value.c = JSStringGetCharactersPtr(string)[0]; | |
1008 | } | |
1009 | break; | |
1010 | ||
1011 | case CYJavaPrimitiveByte: | |
1012 | case CYJavaPrimitiveShort: | |
1013 | case CYJavaPrimitiveInteger: | |
1014 | case CYJavaPrimitiveLong: | |
1015 | case CYJavaPrimitiveFloat: | |
1016 | case CYJavaPrimitiveDouble: | |
1017 | if (type != kJSTypeNumber) | |
1018 | return false; | |
1019 | CYCastJavaNumeric(value, primitive, context, argument); | |
1020 | break; | |
1021 | ||
dbf05bfd JF |
1022 | default: |
1023 | _assert(false); | |
1024 | } | |
dbf05bfd JF |
1025 | } |
1026 | ||
4b645e23 | 1027 | return true; |
dbf05bfd JF |
1028 | } |
1029 | ||
7ab9e677 JF |
1030 | static JSValueRef JavaInstanceMethod_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { |
1031 | auto internal(CYPrivate<CYJavaInstanceMethod>::Get(context, object)); | |
c9c16dde | 1032 | CYJavaObject *self(CYGetJavaObject(context, _this)); |
447b698c | 1033 | _assert(self != NULL); |
fc664744 | 1034 | CYJavaEnv jni(self->value_); |
c9c16dde | 1035 | |
6bbc110e JF |
1036 | auto overload(internal->overloads_.find(count)); |
1037 | if (overload != internal->overloads_.end()) | |
1038 | for (auto signature(overload->second.begin()); signature != overload->second.end(); ++signature) { | |
4e2cc9d3 | 1039 | CYJavaFrame frame(jni, count + 16); |
c9c16dde | 1040 | jvalue array[count]; |
6bbc110e | 1041 | if (!CYCastJavaArguments(frame, signature->shorty_, context, arguments, array)) |
c9c16dde | 1042 | continue; |
fc664744 | 1043 | jvalue *values(array); |
6bbc110e | 1044 | switch (signature->primitive_) { |
c9c16dde | 1045 | case CYJavaPrimitiveObject: |
6bbc110e | 1046 | return CYCastJSValue(context, jni.CallObjectMethodA<jobject>(self->value_, signature->method_, values)); |
c9c16dde | 1047 | case CYJavaPrimitiveVoid: |
6bbc110e | 1048 | jni.CallVoidMethodA(self->value_, signature->method_, values); |
c9c16dde JF |
1049 | return CYJSUndefined(context); |
1050 | #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \ | |
1051 | case CYJavaPrimitive ## Type: \ | |
6bbc110e | 1052 | return CYJavaCastJSValue(context, jni.Call ## Typ ## MethodA(self->value_, signature->method_, values)); |
c9c16dde JF |
1053 | CYJavaForEachPrimitive |
1054 | #undef CYJavaForEachPrimitive_ | |
1055 | default: _assert(false); | |
1056 | } | |
1057 | } | |
1058 | ||
1059 | CYThrow("invalid method call"); | |
1060 | } CYCatch(NULL) } | |
1061 | ||
1062 | static JSValueRef JavaStaticMethod_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { | |
d4222ffb | 1063 | auto internal(CYPrivate<CYJavaStaticMethod>::Get(context, object)); |
c9c16dde | 1064 | CYJavaClass *table(CYGetJavaTable(context, _this)); |
fc664744 | 1065 | CYJavaEnv jni(table->value_); |
dbf05bfd | 1066 | |
6bbc110e JF |
1067 | auto overload(internal->overloads_.find(count)); |
1068 | if (overload != internal->overloads_.end()) | |
1069 | for (auto signature(overload->second.begin()); signature != overload->second.end(); ++signature) { | |
4e2cc9d3 | 1070 | CYJavaFrame frame(jni, count + 16); |
4b645e23 | 1071 | jvalue array[count]; |
6bbc110e | 1072 | if (!CYCastJavaArguments(frame, signature->shorty_, context, arguments, array)) |
4b645e23 | 1073 | continue; |
fc664744 | 1074 | jvalue *values(array); |
6bbc110e | 1075 | switch (signature->primitive_) { |
4b645e23 | 1076 | case CYJavaPrimitiveObject: |
6bbc110e | 1077 | return CYCastJSValue(context, jni.CallStaticObjectMethodA<jobject>(table->value_, signature->method_, values)); |
c9c16dde | 1078 | case CYJavaPrimitiveVoid: |
6bbc110e | 1079 | jni.CallStaticVoidMethodA(table->value_, signature->method_, values); |
c9c16dde | 1080 | return CYJSUndefined(context); |
4b645e23 JF |
1081 | #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \ |
1082 | case CYJavaPrimitive ## Type: \ | |
6bbc110e | 1083 | return CYJavaCastJSValue(context, jni.CallStatic ## Typ ## MethodA(table->value_, signature->method_, values)); |
4b645e23 JF |
1084 | CYJavaForEachPrimitive |
1085 | #undef CYJavaForEachPrimitive_ | |
1086 | default: _assert(false); | |
1087 | } | |
dbf05bfd JF |
1088 | } |
1089 | ||
1090 | CYThrow("invalid method call"); | |
1091 | } CYCatch(NULL) } | |
1092 | ||
1093 | static JSObjectRef JavaClass_callAsConstructor(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { | |
d4222ffb | 1094 | auto table(CYPrivate<CYJavaClass>::Get(context, object)); |
fc664744 | 1095 | CYJavaEnv jni(table->value_); |
c9c16dde JF |
1096 | jclass _class(table->value_); |
1097 | ||
1098 | if (table->interface_ && count == 1) { | |
92536081 JF |
1099 | auto java(reinterpret_cast<CYJava *>(JSObjectGetPrivate(CYGetCachedObject(context, CYJSString("Java"))))); |
1100 | auto Cycript$(java->LoadClass("Cycript")); | |
0e832de4 JF |
1101 | auto Cycript$Make(jni.GetStaticMethodID(Cycript$, "proxy", "(Ljava/lang/Class;LCycript$Wrapper;)Ljava/lang/Object;")); |
1102 | return CYCastJSObject(context, jni.CallObjectMethod<jobject>(Cycript$, Cycript$Make, _class, CYCastJavaObject(jni, context, CYCastJSObject(context, arguments[0])).get())); | |
c9c16dde | 1103 | } |
dbf05bfd | 1104 | |
6bbc110e JF |
1105 | auto overload(table->overloads_.find(count)); |
1106 | if (overload != table->overloads_.end()) | |
1107 | for (auto signature(overload->second.begin()); signature != overload->second.end(); ++signature) { | |
4e2cc9d3 | 1108 | CYJavaFrame frame(jni, count + 16); |
4b645e23 | 1109 | jvalue array[count]; |
6bbc110e | 1110 | if (!CYCastJavaArguments(frame, signature->shorty_, context, arguments, array)) |
4b645e23 | 1111 | continue; |
fc664744 | 1112 | jvalue *values(array); |
6bbc110e | 1113 | auto object(jni.NewObjectA(_class, signature->method_, values)); |
fc664744 | 1114 | return CYCastJSObject(context, object); |
dbf05bfd JF |
1115 | } |
1116 | ||
1117 | CYThrow("invalid constructor call"); | |
77dd5db9 | 1118 | } CYCatchObject() } |
dbf05bfd | 1119 | |
c9c16dde | 1120 | static bool JavaStaticInterior_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) { |
d4222ffb | 1121 | auto internal(CYPrivate<CYJavaStaticInterior>::Get(context, object)); |
4b645e23 | 1122 | CYJavaClass *table(internal->table_); |
dbf05bfd JF |
1123 | CYPool pool; |
1124 | auto name(CYPoolUTF8String(pool, context, property)); | |
1125 | auto field(table->static_.find(name)); | |
1126 | if (field == table->static_.end()) | |
1127 | return false; | |
1128 | return true; | |
1129 | } | |
1130 | ||
c9c16dde | 1131 | static JSValueRef JavaStaticInterior_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry { |
d4222ffb | 1132 | auto internal(CYPrivate<CYJavaStaticInterior>::Get(context, object)); |
4b645e23 | 1133 | CYJavaClass *table(internal->table_); |
fc664744 | 1134 | CYJavaEnv jni(table->value_); |
dbf05bfd JF |
1135 | CYPool pool; |
1136 | auto name(CYPoolUTF8String(pool, context, property)); | |
1137 | auto field(table->static_.find(name)); | |
1138 | if (field == table->static_.end()) | |
1139 | return NULL; | |
1140 | ||
1141 | switch (field->second.primitive_) { | |
1142 | case CYJavaPrimitiveObject: | |
fc664744 | 1143 | return CYCastJSValue(context, jni.GetStaticObjectField<jobject>(table->value_, field->second.field_)); |
4b645e23 | 1144 | #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \ |
dbf05bfd | 1145 | case CYJavaPrimitive ## Type: \ |
fc664744 | 1146 | return CYJavaCastJSValue(context, jni.GetStatic ## Typ ## Field(table->value_, field->second.field_)); |
dbf05bfd JF |
1147 | CYJavaForEachPrimitive |
1148 | #undef CYJavaForEachPrimitive_ | |
1149 | default: _assert(false); | |
1150 | } | |
1151 | } CYCatch(NULL) } | |
1152 | ||
c9c16dde | 1153 | static bool JavaStaticInterior_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYTry { |
d4222ffb | 1154 | auto internal(CYPrivate<CYJavaStaticInterior>::Get(context, object)); |
4b645e23 | 1155 | CYJavaClass *table(internal->table_); |
fc664744 | 1156 | CYJavaEnv jni(table->value_); |
dbf05bfd JF |
1157 | CYPool pool; |
1158 | auto name(CYPoolUTF8String(pool, context, property)); | |
1159 | auto field(table->static_.find(name)); | |
1160 | if (field == table->static_.end()) | |
1161 | return false; | |
1162 | ||
1163 | switch (field->second.primitive_) { | |
1164 | case CYJavaPrimitiveObject: | |
fc664744 | 1165 | jni.SetStaticObjectField(table->value_, field->second.field_, CYCastJavaObject(jni, context, value)); |
4b645e23 | 1166 | #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \ |
dbf05bfd | 1167 | case CYJavaPrimitive ## Type: \ |
fc664744 | 1168 | jni.SetStatic ## Typ ## Field(table->value_, field->second.field_, CYCastDouble(context, value)); \ |
dbf05bfd JF |
1169 | break; |
1170 | CYJavaForEachPrimitive | |
1171 | #undef CYJavaForEachPrimitive_ | |
1172 | default: _assert(false); | |
1173 | } | |
1174 | ||
1175 | return true; | |
1176 | } CYCatch(false) } | |
1177 | ||
c9c16dde | 1178 | static void JavaStaticInterior_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) { |
d4222ffb | 1179 | auto internal(CYPrivate<CYJavaStaticInterior>::Get(context, object)); |
4b645e23 | 1180 | CYJavaClass *table(internal->table_); |
dbf05bfd JF |
1181 | for (const auto &field : table->static_) |
1182 | JSPropertyNameAccumulatorAddName(names, CYJSString(field.first)); | |
1183 | } | |
1184 | ||
1185 | static JSValueRef JavaClass_getProperty_class(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry { | |
d4222ffb | 1186 | auto table(CYPrivate<CYJavaClass>::Get(context, object)); |
fc664744 | 1187 | return CYCastJSValue(context, table->value_); |
dbf05bfd JF |
1188 | } CYCatch(NULL) } |
1189 | ||
8effd381 | 1190 | static bool JavaInterior_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) { |
d4222ffb | 1191 | auto internal(CYPrivate<CYJavaInterior>::Get(context, object)); |
8effd381 | 1192 | CYJavaClass *table(internal->table_); |
dbf05bfd JF |
1193 | CYPool pool; |
1194 | auto name(CYPoolUTF8String(pool, context, property)); | |
1195 | auto field(table->instance_.find(name)); | |
1196 | if (field == table->instance_.end()) | |
1197 | return false; | |
1198 | return true; | |
1199 | } | |
1200 | ||
8effd381 | 1201 | static JSValueRef JavaInterior_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry { |
d4222ffb | 1202 | auto internal(CYPrivate<CYJavaInterior>::Get(context, object)); |
fc664744 | 1203 | CYJavaEnv jni(internal->value_); |
8effd381 | 1204 | CYJavaClass *table(internal->table_); |
dbf05bfd JF |
1205 | CYPool pool; |
1206 | auto name(CYPoolUTF8String(pool, context, property)); | |
1207 | auto field(table->instance_.find(name)); | |
1208 | if (field == table->instance_.end()) | |
1209 | return NULL; | |
1210 | ||
1211 | switch (field->second.primitive_) { | |
1212 | case CYJavaPrimitiveObject: | |
fc664744 | 1213 | return CYCastJSValue(context, jni.GetObjectField<jobject>(internal->value_, field->second.field_)); |
4b645e23 | 1214 | #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \ |
dbf05bfd | 1215 | case CYJavaPrimitive ## Type: \ |
fc664744 | 1216 | return CYJavaCastJSValue(context, jni.Get ## Typ ## Field(internal->value_, field->second.field_)); |
dbf05bfd JF |
1217 | CYJavaForEachPrimitive |
1218 | #undef CYJavaForEachPrimitive_ | |
1219 | default: _assert(false); | |
1220 | } | |
1221 | } CYCatch(NULL) } | |
1222 | ||
8effd381 | 1223 | static bool JavaInterior_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYTry { |
d4222ffb | 1224 | auto internal(CYPrivate<CYJavaInterior>::Get(context, object)); |
fc664744 | 1225 | CYJavaEnv jni(internal->value_); |
8effd381 | 1226 | CYJavaClass *table(internal->table_); |
dbf05bfd JF |
1227 | CYPool pool; |
1228 | auto name(CYPoolUTF8String(pool, context, property)); | |
1229 | auto field(table->instance_.find(name)); | |
1230 | if (field == table->instance_.end()) | |
1231 | return false; | |
1232 | ||
1233 | switch (field->second.primitive_) { | |
1234 | case CYJavaPrimitiveObject: | |
fc664744 | 1235 | jni.SetObjectField(table->value_, field->second.field_, CYCastJavaObject(jni, context, value)); |
4b645e23 | 1236 | #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \ |
dbf05bfd | 1237 | case CYJavaPrimitive ## Type: \ |
fc664744 | 1238 | jni.Set ## Typ ## Field(table->value_, field->second.field_, CYCastDouble(context, value)); \ |
dbf05bfd JF |
1239 | break; |
1240 | CYJavaForEachPrimitive | |
1241 | #undef CYJavaForEachPrimitive_ | |
1242 | default: _assert(false); | |
1243 | } | |
1244 | ||
1245 | return true; | |
1246 | } CYCatch(false) } | |
1247 | ||
8effd381 | 1248 | static void JavaInterior_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) { |
d4222ffb | 1249 | auto internal(CYPrivate<CYJavaInterior>::Get(context, object)); |
8effd381 | 1250 | CYJavaClass *table(internal->table_); |
dbf05bfd JF |
1251 | for (const auto &field : table->instance_) |
1252 | JSPropertyNameAccumulatorAddName(names, CYJSString(field.first)); | |
1253 | } | |
1254 | ||
1255 | static JSValueRef JavaObject_getProperty_constructor(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry { | |
d4222ffb | 1256 | auto internal(CYPrivate<CYJavaObject>::Get(context, object)); |
fc664744 JF |
1257 | CYJavaEnv jni(internal->value_); |
1258 | return CYGetJavaClass(context, jni.GetObjectClass(internal->value_)); | |
dbf05bfd JF |
1259 | } CYCatch(NULL) } |
1260 | ||
4b645e23 | 1261 | static JSValueRef JavaClass_getProperty_$cyi(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry { |
d4222ffb JF |
1262 | auto internal(CYPrivate<CYJavaClass>::Get(context, object)); |
1263 | return CYPrivate<CYJavaStaticInterior>::Make(context, internal->value_, internal); | |
4b645e23 JF |
1264 | } CYCatch(NULL) } |
1265 | ||
8effd381 | 1266 | static JSValueRef JavaObject_getProperty_$cyi(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry { |
d4222ffb JF |
1267 | auto internal(CYPrivate<CYJavaObject>::Get(context, object)); |
1268 | return CYPrivate<CYJavaInterior>::Make(context, internal->value_, internal->table_); | |
8effd381 JF |
1269 | } CYCatch(NULL) } |
1270 | ||
4b645e23 | 1271 | static JSValueRef JavaClass_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { |
d4222ffb | 1272 | auto internal(CYPrivate<CYJavaClass>::Get(context, _this)); |
fc664744 JF |
1273 | CYJavaEnv jni(internal->value_); |
1274 | auto Class$(jni.FindClass("java/lang/Class")); | |
1275 | auto Class$getCanonicalName(jni.GetMethodID(Class$, "getCanonicalName", "()Ljava/lang/String;")); | |
1276 | return CYCastJSValue(context, CYJSString(jni.CallObjectMethod<jstring>(internal->value_, Class$getCanonicalName))); | |
4b645e23 JF |
1277 | } CYCatch(NULL) } |
1278 | ||
1279 | static JSValueRef JavaMethod_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { | |
7ab9e677 | 1280 | auto internal(CYPrivate<CYJavaMethod>::Get(context, _this)); |
4b645e23 | 1281 | std::ostringstream cyon; |
7ab9e677 JF |
1282 | if (false) |
1283 | cyon << internal->type_ << "." << internal->name_; | |
1284 | else { | |
1285 | bool comma(false); | |
1286 | for (auto overload(internal->overloads_.begin()); overload != internal->overloads_.end(); ++overload) | |
1287 | for (auto signature(overload->second.begin()); signature != overload->second.end(); ++signature) { | |
1288 | if (comma) | |
1289 | cyon << std::endl; | |
1290 | else | |
1291 | comma = true; | |
1292 | auto string(CYCastJavaString(signature->reflected_)); | |
1293 | cyon << CYJavaUTF8String(string); | |
1294 | } | |
1295 | } | |
c9c16dde JF |
1296 | return CYCastJSValue(context, CYJSString(cyon.str())); |
1297 | } CYCatch(NULL) } | |
1298 | ||
4b645e23 | 1299 | static JSValueRef JavaArray_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry { |
d4222ffb | 1300 | auto internal(CYPrivate<CYJavaArray>::Get(context, object)); |
fc664744 | 1301 | CYJavaEnv jni(internal->value_); |
4b645e23 | 1302 | if (JSStringIsEqual(property, length_s)) |
fc664744 | 1303 | return CYCastJSValue(context, jni.GetArrayLength(internal->value_)); |
4b645e23 JF |
1304 | |
1305 | CYPool pool; | |
1306 | ssize_t offset; | |
1307 | if (!CYGetOffset(pool, context, property, offset)) | |
1308 | return NULL; | |
1309 | ||
1310 | if (internal->primitive_ == CYJavaPrimitiveObject) | |
fc664744 | 1311 | return CYCastJSValue(context, jni.GetObjectArrayElement<jobject>(static_cast<jobjectArray>(internal->value_.value_), offset)); |
4b645e23 JF |
1312 | else switch (internal->primitive_) { |
1313 | #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \ | |
1314 | case CYJavaPrimitive ## Type: { \ | |
1315 | j ## type element; \ | |
fc664744 | 1316 | jni.Get ## Typ ## ArrayRegion(static_cast<j ## type ## Array>(internal->value_.value_), offset, 1, &element); \ |
4b645e23 JF |
1317 | return CYJavaCastJSValue(context, element); \ |
1318 | } break; | |
1319 | CYJavaForEachPrimitive | |
1320 | #undef CYJavaForEachPrimitive_ | |
1321 | default: _assert(false); | |
1322 | } | |
1323 | } CYCatch(NULL) } | |
1324 | ||
1325 | static bool JavaArray_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYTry { | |
d4222ffb | 1326 | auto internal(CYPrivate<CYJavaArray>::Get(context, object)); |
fc664744 | 1327 | CYJavaEnv jni(internal->value_); |
4b645e23 JF |
1328 | |
1329 | CYPool pool; | |
1330 | ssize_t offset; | |
1331 | if (!CYGetOffset(pool, context, property, offset)) | |
1332 | return false; | |
1333 | ||
1334 | if (internal->primitive_ == CYJavaPrimitiveObject) | |
fc664744 | 1335 | jni.SetObjectArrayElement(static_cast<jobjectArray>(internal->value_.value_), offset, CYCastJavaObject(jni, context, value)); |
4b645e23 JF |
1336 | else switch (internal->primitive_) { |
1337 | #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \ | |
1338 | case CYJavaPrimitive ## Type: { \ | |
1339 | j ## type element; \ | |
fc664744 | 1340 | jni.Get ## Typ ## ArrayRegion(static_cast<j ## type ## Array>(internal->value_.value_), offset, 1, &element); \ |
4b645e23 JF |
1341 | return CYJavaCastJSValue(context, element); \ |
1342 | } break; | |
1343 | CYJavaForEachPrimitive | |
1344 | #undef CYJavaForEachPrimitive_ | |
1345 | default: _assert(false); | |
1346 | } | |
1347 | ||
1348 | return true; | |
1349 | } CYCatch(false) } | |
1350 | ||
f45374f4 JF |
1351 | static JNIEnv *GetJNI(JSContextRef context, JNIEnv *&env); |
1352 | ||
4b645e23 | 1353 | static JSValueRef JavaPackage_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { |
d4222ffb | 1354 | auto internal(CYPrivate<CYJavaPackage>::Get(context, _this)); |
4b645e23 JF |
1355 | std::ostringstream name; |
1356 | for (auto &package : internal->package_) | |
1357 | name << package << '.'; | |
1358 | name << '*'; | |
1359 | return CYCastJSValue(context, CYJSString(name.str())); | |
1360 | } CYCatch(NULL) } | |
1361 | ||
dbf05bfd JF |
1362 | static bool CYJavaPackage_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) { |
1363 | return true; | |
1364 | } | |
1365 | ||
1366 | static JSValueRef CYJavaPackage_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { CYTry { | |
d4222ffb | 1367 | auto internal(CYPrivate<CYJavaPackage>::Get(context, object)); |
dbf05bfd JF |
1368 | CYJavaPackage::Path package(internal->package_); |
1369 | ||
1370 | CYPool pool; | |
1371 | const char *next(CYPoolCString(pool, context, property)); | |
1372 | ||
1373 | std::ostringstream name; | |
1374 | for (auto &package : internal->package_) | |
1375 | name << package << '/'; | |
1376 | name << next; | |
1377 | ||
f45374f4 JF |
1378 | if (internal->jni_ == NULL) |
1379 | GetJNI(context, internal->jni_); | |
f3e85e94 | 1380 | JNIEnv *jni(internal->jni_); |
f45374f4 | 1381 | |
fc664744 JF |
1382 | if (auto _class = jni->FindClass(name.str().c_str())) |
1383 | return CYGetJavaClass(context, CYJavaLocal<jclass>(jni, _class)); | |
dbf05bfd JF |
1384 | jni->ExceptionClear(); |
1385 | ||
1386 | package.push_back(next); | |
d4222ffb | 1387 | return CYPrivate<CYJavaPackage>::Make(context, jni, package); |
dbf05bfd JF |
1388 | } CYCatch(NULL) } |
1389 | ||
fc664744 | 1390 | static void Cycript_delete(JNIEnv *env, jclass api, jlong jprotect) { CYJavaTry { |
824bc1ec | 1391 | delete &protect; |
c9c16dde JF |
1392 | } CYJavaCatch() } |
1393 | ||
fc664744 JF |
1394 | static jobject Cycript_handle(JNIEnv *env, jclass api, jlong jprotect, jstring property, jobjectArray jarguments) { CYJavaTry { |
1395 | JSValueRef function(CYGetProperty(context, object, CYJSString(CYJavaRef<jstring>(jni, property)))); | |
c9c16dde JF |
1396 | if (JSValueIsUndefined(context, function)) |
1397 | return NULL; | |
1398 | ||
fc664744 | 1399 | size_t count(jarguments == NULL ? 0 : jni.GetArrayLength(jarguments)); |
c9c16dde | 1400 | JSValueRef arguments[count]; |
4e2cc9d3 | 1401 | for (size_t index(0); index != count; ++index) |
fc664744 | 1402 | arguments[index] = CYCastJSValue(context, jni.GetObjectArrayElement<jobject>(jarguments, index)); |
c9c16dde | 1403 | |
4e2cc9d3 | 1404 | return CYCastJavaObject(jni, context, CYCallAsFunction(context, CYCastJSObject(context, function), object, count, arguments)).leak(); |
c9c16dde JF |
1405 | } CYJavaCatch(NULL) } |
1406 | ||
1407 | static JNINativeMethod Cycript_[] = { | |
1408 | {(char *) "delete", (char *) "(J)V", (void *) &Cycript_delete}, | |
1409 | {(char *) "handle", (char *) "(JLjava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;", (void *) &Cycript_handle}, | |
1410 | }; | |
1411 | ||
f2c357f9 JF |
1412 | template <typename Type_> |
1413 | static _finline void dlset(Type_ &function, const char *name, void *handle) { | |
1414 | function = reinterpret_cast<Type_>(dlsym(handle, name)); | |
1415 | } | |
1416 | ||
1417 | jint CYJavaVersion(JNI_VERSION_1_4); | |
1418 | ||
f3e85e94 | 1419 | static JavaVM *CYGetJavaVM(jint (*$JNI_GetCreatedJavaVMs)(JavaVM **, jsize, jsize *)) { |
f2c357f9 JF |
1420 | jsize capacity(16); |
1421 | JavaVM *jvms[capacity]; | |
1422 | jsize size; | |
1423 | _jnicall($JNI_GetCreatedJavaVMs(jvms, capacity, &size)); | |
1424 | if (size == 0) | |
1425 | return NULL; | |
f3e85e94 | 1426 | return jvms[0]; |
f2c357f9 JF |
1427 | } |
1428 | ||
f3e85e94 | 1429 | static JavaVM *CYGetJavaVM(JSContextRef context) { |
f2c357f9 JF |
1430 | CYPool pool; |
1431 | void *handle(RTLD_DEFAULT); | |
1432 | std::string library; | |
fc664744 | 1433 | |
f2c357f9 JF |
1434 | jint (*$JNI_GetCreatedJavaVMs)(JavaVM **jvms, jsize capacity, jsize *size); |
1435 | dlset($JNI_GetCreatedJavaVMs, "JNI_GetCreatedJavaVMs", handle); | |
1436 | ||
1437 | if ($JNI_GetCreatedJavaVMs != NULL) { | |
f3e85e94 JF |
1438 | if (JavaVM *jvm = CYGetJavaVM($JNI_GetCreatedJavaVMs)) |
1439 | return jvm; | |
fc664744 | 1440 | } else { |
f2c357f9 JF |
1441 | std::vector<const char *> guesses; |
1442 | ||
1443 | #ifdef __ANDROID__ | |
1444 | char android[PROP_VALUE_MAX]; | |
1445 | if (__system_property_get("persist.sys.dalvik.vm.lib", android) != 0) | |
1446 | guesses.push_back(android); | |
1447 | #endif | |
1448 | ||
f3e85e94 JF |
1449 | guesses.push_back("/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/jli/libjli.dylib"); |
1450 | //guesses.push_back("/System/Library/Frameworks/JavaVM.framework/JavaVM"); | |
4b5dc402 | 1451 | guesses.push_back("libjvm.dylib"); |
f3e85e94 | 1452 | |
f2c357f9 JF |
1453 | guesses.push_back("libart.so"); |
1454 | guesses.push_back("libdvm.so"); | |
1455 | guesses.push_back("libjvm.so"); | |
1456 | ||
1457 | for (const char *guess : guesses) { | |
1458 | handle = dlopen(guess, RTLD_LAZY | RTLD_GLOBAL); | |
1459 | if (handle != NULL) { | |
1460 | library = guess; | |
1461 | break; | |
1462 | } | |
fc664744 JF |
1463 | } |
1464 | ||
f3e85e94 JF |
1465 | if (library.size() == 0) |
1466 | return NULL; | |
f2c357f9 JF |
1467 | |
1468 | dlset($JNI_GetCreatedJavaVMs, "JNI_GetCreatedJavaVMs", handle); | |
f3e85e94 JF |
1469 | if (JavaVM *jvm = CYGetJavaVM($JNI_GetCreatedJavaVMs)) |
1470 | return jvm; | |
fc664744 JF |
1471 | } |
1472 | ||
f2c357f9 JF |
1473 | std::vector<JavaVMOption> options; |
1474 | ||
92536081 JF |
1475 | if (const char *classpath = getenv("CLASSPATH")) |
1476 | options.push_back(JavaVMOption{pool.strcat("-Djava.class.path=", classpath, NULL), NULL}); | |
f2c357f9 JF |
1477 | |
1478 | // To use libnativehelper to access JNI_GetCreatedJavaVMs, you need JniInvocation. | |
1479 | // ...but there can only be one JniInvocation, and assuradely the other VM has it. | |
1480 | // Essentially, this API makes no sense. We need it for AndroidRuntime, though :/. | |
1481 | ||
1482 | if (void *libnativehelper = dlopen("libnativehelper.so", RTLD_LAZY | RTLD_GLOBAL)) { | |
1483 | class JniInvocation$; | |
1484 | JniInvocation$ *(*JniInvocation$$init$)(JniInvocation$ *self)(NULL); | |
1485 | bool (*JniInvocation$Init)(JniInvocation$ *self, const char *library)(NULL); | |
1486 | JniInvocation$ *(*JniInvocation$finalize)(JniInvocation$ *self)(NULL); | |
1487 | ||
1488 | dlset(JniInvocation$$init$, "_ZN13JniInvocationC1Ev", libnativehelper); | |
1489 | dlset(JniInvocation$Init, "_ZN13JniInvocation4InitEPKc", libnativehelper); | |
1490 | dlset(JniInvocation$finalize, "_ZN13JniInvocationD1Ev", libnativehelper); | |
1491 | ||
95be1645 JF |
1492 | if (JniInvocation$$init$ == NULL) |
1493 | dlclose(libnativehelper); | |
1494 | else { | |
1495 | // XXX: we should attach a pool to the VM itself and deallocate this there | |
1496 | //auto invocation(pool.calloc<JniInvocation$>(1, 1024)); | |
1497 | //_assert(JniInvocation$finalize != NULL); | |
1498 | //pool.atexit(reinterpret_cast<void (*)(void *)>(JniInvocation$finalize), invocation); | |
1499 | ||
1500 | auto invocation(static_cast<JniInvocation$ *>(calloc(1, 1024))); | |
1501 | JniInvocation$$init$(invocation); | |
1502 | ||
1503 | _assert(JniInvocation$Init != NULL); | |
1504 | JniInvocation$Init(invocation, NULL); | |
1505 | ||
1506 | dlset($JNI_GetCreatedJavaVMs, "JNI_GetCreatedJavaVMs", libnativehelper); | |
f3e85e94 JF |
1507 | if (JavaVM *jvm = CYGetJavaVM($JNI_GetCreatedJavaVMs)) |
1508 | return jvm; | |
95be1645 | 1509 | } |
f2c357f9 JF |
1510 | } |
1511 | ||
f3e85e94 JF |
1512 | JavaVM *jvm; |
1513 | JNIEnv *env; | |
1514 | ||
f2c357f9 JF |
1515 | if (void *libandroid_runtime = dlopen("libandroid_runtime.so", RTLD_LAZY | RTLD_GLOBAL)) { |
1516 | class AndroidRuntime$; | |
1517 | AndroidRuntime$ *(*AndroidRuntime$$init$)(AndroidRuntime$ *self, char *args, unsigned int size)(NULL); | |
f3e85e94 JF |
1518 | int (*AndroidRuntime$startVm)(AndroidRuntime$ *self, JavaVM **jvm, JNIEnv **env)(NULL); |
1519 | int (*AndroidRuntime$startReg)(JNIEnv *env)(NULL); | |
f2c357f9 JF |
1520 | int (*AndroidRuntime$addOption)(AndroidRuntime$ *self, const char *option, void *extra)(NULL); |
1521 | int (*AndroidRuntime$addVmArguments)(AndroidRuntime$ *self, int, const char *const argv[])(NULL); | |
1522 | AndroidRuntime$ *(*AndroidRuntime$finalize)(AndroidRuntime$ *self)(NULL); | |
1523 | ||
1524 | dlset(AndroidRuntime$$init$, "_ZN7android14AndroidRuntimeC1EPcj", libandroid_runtime); | |
1525 | dlset(AndroidRuntime$startVm, "_ZN7android14AndroidRuntime7startVmEPP7_JavaVMPP7_JNIEnv", libandroid_runtime); | |
1526 | dlset(AndroidRuntime$startReg, "_ZN7android14AndroidRuntime8startRegEP7_JNIEnv", libandroid_runtime); | |
1527 | dlset(AndroidRuntime$addOption, "_ZN7android14AndroidRuntime9addOptionEPKcPv", libandroid_runtime); | |
1528 | dlset(AndroidRuntime$addVmArguments, "_ZN7android14AndroidRuntime14addVmArgumentsEiPKPKc", libandroid_runtime); | |
1529 | dlset(AndroidRuntime$finalize, "_ZN7android14AndroidRuntimeD1Ev", libandroid_runtime); | |
1530 | ||
1531 | // XXX: it would also be interesting to attach this to a global pool | |
1532 | AndroidRuntime$ *runtime(pool.calloc<AndroidRuntime$>(1, 1024)); | |
1533 | ||
1534 | _assert(AndroidRuntime$$init$ != NULL); | |
1535 | AndroidRuntime$$init$(runtime, NULL, 0); | |
1536 | ||
1537 | if (AndroidRuntime$addOption == NULL) { | |
1538 | _assert(AndroidRuntime$addVmArguments != NULL); | |
1539 | std::vector<const char *> arguments; | |
1540 | for (const auto &option : options) | |
1541 | arguments.push_back(option.optionString); | |
1542 | AndroidRuntime$addVmArguments(runtime, arguments.size(), arguments.data()); | |
1543 | } else for (const auto &option : options) | |
1544 | AndroidRuntime$addOption(runtime, option.optionString, option.extraInfo); | |
1545 | ||
1546 | int failure; | |
1547 | ||
1548 | _assert(AndroidRuntime$startVm != NULL); | |
f3e85e94 | 1549 | failure = AndroidRuntime$startVm(runtime, &jvm, &env); |
f2c357f9 JF |
1550 | _assert(failure == 0); |
1551 | ||
1552 | _assert(AndroidRuntime$startReg != NULL); | |
f3e85e94 | 1553 | failure = AndroidRuntime$startReg(env); |
f2c357f9 JF |
1554 | _assert(failure == 0); |
1555 | ||
f3e85e94 | 1556 | return jvm; |
f2c357f9 JF |
1557 | } |
1558 | ||
1559 | jint (*$JNI_CreateJavaVM)(JavaVM **jvm, void **, void *); | |
1560 | dlset($JNI_CreateJavaVM, "JNI_CreateJavaVM", handle); | |
1561 | ||
1562 | JavaVMInitArgs args; | |
1563 | memset(&args, 0, sizeof(args)); | |
1564 | args.version = CYJavaVersion; | |
1565 | args.nOptions = options.size(); | |
1566 | args.options = options.data(); | |
f3e85e94 JF |
1567 | _jnicall($JNI_CreateJavaVM(&jvm, reinterpret_cast<void **>(&env), &args)); |
1568 | return jvm; | |
f2c357f9 | 1569 | } |
fc664744 | 1570 | |
f45374f4 | 1571 | static JNIEnv *GetJNI(JSContextRef context, JNIEnv *&env) { |
f3e85e94 | 1572 | auto jvm(CYGetJavaVM(context)); |
f45374f4 | 1573 | _assert(jvm != NULL); |
f3e85e94 | 1574 | |
92536081 JF |
1575 | switch (jvm->GetEnv(reinterpret_cast<void **>(&env), CYJavaVersion)) { |
1576 | case JNI_EDETACHED: | |
1577 | _jnicall(jvm->AttachCurrentThreadAsDaemon( | |
1578 | #ifndef __ANDROID__ | |
1579 | reinterpret_cast<void **> | |
1580 | #endif | |
1581 | (&env), NULL)); | |
1582 | break; | |
1583 | case JNI_OK: | |
1584 | break; | |
1585 | default: | |
1586 | _assert(false); | |
1587 | } | |
f45374f4 | 1588 | |
92536081 JF |
1589 | CYJavaEnv jni(env); |
1590 | ||
1591 | auto java(reinterpret_cast<CYJava *>(JSObjectGetPrivate(CYGetCachedObject(context, CYJSString("Java"))))); | |
1592 | if (java->Setup(jni)) { | |
1593 | auto Cycript$(java->LoadClass("Cycript")); | |
1594 | jni.RegisterNatives(Cycript$, Cycript_, sizeof(Cycript_) / sizeof(Cycript_[0])); | |
f3e85e94 | 1595 | |
92536081 JF |
1596 | JSObjectRef java(CYGetCachedObject(context, CYJSString("Java"))); |
1597 | JSValueRef arguments[1]; | |
1598 | arguments[0] = CYCastJSValue(context, CYJSString("setup")); | |
1599 | CYCallAsFunction(context, CYCastJSObject(context, CYGetProperty(context, java, CYJSString("emit"))), java, 1, arguments); | |
1600 | } | |
f45374f4 | 1601 | |
f3e85e94 | 1602 | return env; |
c9c16dde JF |
1603 | } |
1604 | ||
4b645e23 | 1605 | static JSStaticValue JavaClass_staticValues[3] = { |
dbf05bfd | 1606 | {"class", &JavaClass_getProperty_class, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, |
4b645e23 | 1607 | {"$cyi", &JavaClass_getProperty_$cyi, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, |
dbf05bfd JF |
1608 | {NULL, NULL, NULL, 0} |
1609 | }; | |
1610 | ||
4b645e23 JF |
1611 | static JSStaticFunction JavaClass_staticFunctions[2] = { |
1612 | {"toCYON", &JavaClass_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, | |
1613 | {NULL, NULL, 0} | |
1614 | }; | |
1615 | ||
8effd381 | 1616 | static JSStaticValue JavaObject_staticValues[3] = { |
dbf05bfd | 1617 | {"constructor", &JavaObject_getProperty_constructor, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, |
8effd381 | 1618 | {"$cyi", &JavaObject_getProperty_$cyi, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, |
dbf05bfd JF |
1619 | {NULL, NULL, NULL, 0} |
1620 | }; | |
1621 | ||
7ab9e677 | 1622 | static JSStaticFunction JavaInstanceMethod_staticFunctions[2] = { |
4b645e23 JF |
1623 | {"toCYON", &JavaMethod_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, |
1624 | {NULL, NULL, 0} | |
1625 | }; | |
1626 | ||
c9c16dde | 1627 | static JSStaticFunction JavaStaticMethod_staticFunctions[2] = { |
7ab9e677 | 1628 | {"toCYON", &JavaMethod_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, |
c9c16dde JF |
1629 | {NULL, NULL, 0} |
1630 | }; | |
1631 | ||
4b645e23 JF |
1632 | static JSStaticFunction JavaPackage_staticFunctions[2] = { |
1633 | {"toCYON", &JavaPackage_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, | |
dbf05bfd JF |
1634 | {NULL, NULL, 0} |
1635 | }; | |
1636 | ||
1637 | void CYJava_Initialize() { | |
1638 | Primitives_.insert(std::make_pair("void", CYJavaPrimitiveVoid)); | |
4b645e23 | 1639 | #define CYJavaForEachPrimitive_(T, t, Typ, Type, type) \ |
42619b59 JF |
1640 | Primitives_.insert(std::make_pair(#type, CYJavaPrimitive ## Type)); |
1641 | CYJavaForEachPrimitive | |
1642 | #undef CYJavaForEachPrimitive_ | |
dbf05bfd JF |
1643 | |
1644 | JSClassDefinition definition; | |
1645 | ||
92536081 JF |
1646 | definition = kJSClassDefinitionEmpty; |
1647 | definition.attributes = kJSClassAttributeNoAutomaticPrototype; | |
1648 | definition.className = "Java"; | |
1649 | definition.finalize = &CYFinalize; | |
1650 | CYPrivate<CYJava>::Class_ = JSClassCreate(&definition); | |
1651 | ||
dbf05bfd JF |
1652 | definition = kJSClassDefinitionEmpty; |
1653 | definition.className = "JavaClass"; | |
1654 | definition.staticValues = JavaClass_staticValues; | |
4b645e23 | 1655 | definition.staticFunctions = JavaClass_staticFunctions; |
dbf05bfd JF |
1656 | definition.callAsConstructor = &JavaClass_callAsConstructor; |
1657 | definition.finalize = &CYFinalize; | |
d4222ffb | 1658 | CYPrivate<CYJavaClass>::Class_ = JSClassCreate(&definition); |
dbf05bfd | 1659 | |
8effd381 JF |
1660 | definition = kJSClassDefinitionEmpty; |
1661 | definition.attributes = kJSClassAttributeNoAutomaticPrototype; | |
1662 | definition.className = "JavaInterior"; | |
1663 | definition.hasProperty = &JavaInterior_hasProperty; | |
1664 | definition.getProperty = &JavaInterior_getProperty; | |
1665 | definition.setProperty = &JavaInterior_setProperty; | |
1666 | definition.getPropertyNames = &JavaInterior_getPropertyNames; | |
1667 | definition.finalize = &CYFinalize; | |
d4222ffb | 1668 | CYPrivate<CYJavaInterior>::Class_ = JSClassCreate(&definition); |
8effd381 | 1669 | |
dbf05bfd JF |
1670 | definition = kJSClassDefinitionEmpty; |
1671 | definition.className = "JavaMethod"; | |
dbf05bfd | 1672 | definition.finalize = &CYFinalize; |
d4222ffb | 1673 | CYPrivate<CYJavaMethod>::Class_ = JSClassCreate(&definition); |
dbf05bfd | 1674 | |
7ab9e677 JF |
1675 | definition = kJSClassDefinitionEmpty; |
1676 | definition.className = "JavaInstanceMethod"; | |
1677 | definition.parentClass = CYPrivate<CYJavaMethod>::Class_; | |
1678 | definition.staticFunctions = JavaInstanceMethod_staticFunctions; | |
1679 | definition.callAsFunction = &JavaInstanceMethod_callAsFunction; | |
1680 | CYPrivate<CYJavaInstanceMethod>::Class_ = JSClassCreate(&definition); | |
1681 | ||
c9c16dde JF |
1682 | definition = kJSClassDefinitionEmpty; |
1683 | definition.className = "JavaStaticMethod"; | |
7ab9e677 | 1684 | definition.parentClass = CYPrivate<CYJavaMethod>::Class_; |
c9c16dde JF |
1685 | definition.staticFunctions = JavaStaticMethod_staticFunctions; |
1686 | definition.callAsFunction = &JavaStaticMethod_callAsFunction; | |
d4222ffb | 1687 | CYPrivate<CYJavaStaticMethod>::Class_ = JSClassCreate(&definition); |
c9c16dde | 1688 | |
dbf05bfd JF |
1689 | definition = kJSClassDefinitionEmpty; |
1690 | definition.attributes = kJSClassAttributeNoAutomaticPrototype; | |
1691 | definition.className = "JavaObject"; | |
1692 | definition.staticValues = JavaObject_staticValues; | |
dbf05bfd | 1693 | definition.finalize = &CYFinalize; |
d4222ffb | 1694 | CYPrivate<CYJavaObject>::Class_ = JSClassCreate(&definition); |
dbf05bfd | 1695 | |
4b645e23 JF |
1696 | definition = kJSClassDefinitionEmpty; |
1697 | definition.className = "JavaArray"; | |
1698 | definition.getProperty = &JavaArray_getProperty; | |
1699 | definition.setProperty = &JavaArray_setProperty; | |
1700 | definition.finalize = &CYFinalize; | |
d4222ffb | 1701 | CYPrivate<CYJavaArray>::Class_ = JSClassCreate(&definition); |
4b645e23 | 1702 | |
dbf05bfd JF |
1703 | definition = kJSClassDefinitionEmpty; |
1704 | definition.className = "JavaPackage"; | |
1705 | definition.staticFunctions = JavaPackage_staticFunctions; | |
1706 | definition.hasProperty = &CYJavaPackage_hasProperty; | |
1707 | definition.getProperty = &CYJavaPackage_getProperty; | |
1708 | definition.finalize = &CYFinalize; | |
d4222ffb | 1709 | CYPrivate<CYJavaPackage>::Class_ = JSClassCreate(&definition); |
4b645e23 JF |
1710 | |
1711 | definition = kJSClassDefinitionEmpty; | |
1712 | definition.attributes = kJSClassAttributeNoAutomaticPrototype; | |
c9c16dde JF |
1713 | definition.className = "JavaStaticInterior"; |
1714 | definition.hasProperty = &JavaStaticInterior_hasProperty; | |
1715 | definition.getProperty = &JavaStaticInterior_getProperty; | |
1716 | definition.setProperty = &JavaStaticInterior_setProperty; | |
1717 | definition.getPropertyNames = &JavaStaticInterior_getPropertyNames; | |
4b645e23 | 1718 | definition.finalize = &CYFinalize; |
d4222ffb | 1719 | CYPrivate<CYJavaStaticInterior>::Class_ = JSClassCreate(&definition); |
dbf05bfd JF |
1720 | } |
1721 | ||
1722 | void CYJava_SetupContext(JSContextRef context) { | |
1723 | JSObjectRef global(CYGetGlobalObject(context)); | |
f45374f4 | 1724 | JSObjectRef cy(CYCastJSObject(context, CYGetProperty(context, global, cy_s))); |
dbf05bfd JF |
1725 | JSObjectRef cycript(CYCastJSObject(context, CYGetProperty(context, global, CYJSString("Cycript")))); |
1726 | JSObjectRef all(CYCastJSObject(context, CYGetProperty(context, cycript, CYJSString("all")))); | |
1727 | //JSObjectRef alls(CYCastJSObject(context, CYGetProperty(context, cycript, CYJSString("alls")))); | |
1728 | ||
92536081 | 1729 | JSObjectRef Java(CYPrivate<CYJava>::Make(context)); |
dbf05bfd | 1730 | CYSetProperty(context, cycript, CYJSString("Java"), Java); |
f45374f4 | 1731 | CYSetProperty(context, cy, CYJSString("Java"), Java); |
dbf05bfd | 1732 | |
d4222ffb | 1733 | JSObjectRef Packages(CYPrivate<CYJavaPackage>::Make(context, nullptr, CYJavaPackage::Path())); |
f45374f4 | 1734 | CYSetProperty(context, all, CYJSString("Packages"), Packages, kJSPropertyAttributeDontEnum); |
dbf05bfd JF |
1735 | |
1736 | for (auto name : (const char *[]) {"java", "javax", "android", "com", "net", "org"}) { | |
1737 | CYJSString js(name); | |
d4222ffb | 1738 | CYSetProperty(context, all, js, CYPrivate<CYJavaPackage>::Make(context, nullptr, CYJavaPackage::Path(1, name)), kJSPropertyAttributeDontEnum); |
dbf05bfd JF |
1739 | } |
1740 | } | |
1741 | ||
1742 | static CYHook CYJavaHook = { | |
1743 | NULL, | |
1744 | NULL, | |
1745 | NULL, | |
1746 | &CYJava_Initialize, | |
1747 | &CYJava_SetupContext, | |
1748 | NULL, | |
1749 | }; | |
1750 | ||
1751 | CYRegisterHook CYJava(&CYJavaHook); |