1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * This source file is part of SableVM. *
3 * *
4 * See the file "LICENSE" for the copyright information and for *
5 * the terms and conditions for copying, distribution and *
6 * modification of this source file. *
7 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8
9 /*
10 ----------------------------------------------------------------------
11 _svmf_get_jni_frame_free_native_local_count
12 ----------------------------------------------------------------------
13 */
14
15 svm_static jint
_svmf_get_jni_frame_free_native_local_count(_svmt_JNIEnv * env)16 _svmf_get_jni_frame_free_native_local_count (_svmt_JNIEnv *env)
17 {
18 #ifndef NDEBUG
19 _svmt_JavaVM *vm = env->vm;
20 #endif
21
22 _svmt_stack_frame *frame = env->stack.current_frame;
23
24 #ifndef NDEBUG
25 _svmt_method_info *method = frame->method;
26 #endif
27 _svmt_stack_native_reference *lrefs = (_svmt_stack_native_reference *)
28 (void *) (((char *) frame) + frame->end_offset);
29 jint lrefs_count = lrefs[-1].jint;
30 size_t lrefs_size = lrefs[-2].size_t;
31 jint i;
32 jint free_count = 0;
33
34 assert (method == &vm->stack_bottom_method
35 || _svmf_is_set_flag (method->access_flags, SVM_ACC_NATIVE));
36
37 lrefs =
38 (_svmt_stack_native_reference *) (void *) (((char *) lrefs) - lrefs_size);
39
40 for (i = 0; i < lrefs_count; i++)
41 {
42 if (*(lrefs[i].jobject) == NULL)
43 {
44 free_count++;
45 }
46 }
47
48 return free_count;
49 }
50
51 /*
52 ----------------------------------------------------------------------
53 _svmh_new_native_local
54 ----------------------------------------------------------------------
55 */
56
57 svm_static jint
_svmh_new_native_local(_svmt_JNIEnv * env,jobject * pobj)58 _svmh_new_native_local (_svmt_JNIEnv *env, jobject *pobj)
59 {
60 _svmt_JavaVM *vm = env->vm;
61 _svmt_native_ref *native_local = NULL;
62
63 /* do we already have a free reference available? */
64 if (env->native_locals.free_list != NULL)
65 {
66 native_local = env->native_locals.free_list;
67
68 env->native_locals.free_list = native_local->next;
69 if (env->native_locals.free_list != NULL)
70 {
71 assert (env->native_locals.free_list->previous == native_local);
72
73 env->native_locals.free_list->previous = NULL;
74 }
75
76 assert (native_local->previous == NULL);
77
78 native_local->next = env->native_locals.list;
79 env->native_locals.list = native_local;
80 if (native_local->next != NULL)
81 {
82 assert (native_local->next->previous == NULL);
83
84 native_local->next->previous = native_local;
85 }
86
87 *pobj = _svmf_cast_jobject_nref (native_local);
88 return JNI_OK;
89 }
90
91 /* Can we steal a free global native reference? */
92 _svmm_mutex_lock (vm->global_mutex);
93
94 if (vm->native_globals.free_list != NULL)
95 {
96 native_local = vm->native_globals.free_list;
97
98 vm->native_globals.free_list = native_local->next;
99 if (vm->native_globals.free_list != NULL)
100 {
101 assert (vm->native_globals.free_list->previous == native_local);
102
103 vm->native_globals.free_list->previous = NULL;
104 }
105 }
106
107 _svmm_mutex_unlock ();
108
109 if (native_local != NULL)
110 {
111 assert (native_local->previous == NULL);
112
113 native_local->next = env->native_locals.list;
114 env->native_locals.list = native_local;
115 if (native_local->next != NULL)
116 {
117 assert (native_local->next->previous == NULL);
118
119 native_local->next->previous = native_local;
120 }
121
122 *pobj = _svmf_cast_jobject_nref (native_local);
123 return JNI_OK;
124 }
125
126 /* we're out of luck; let's allocate a new reference */
127 if (_svmm_gzalloc_native_ref_no_exception (native_local) != JNI_OK)
128 {
129 _svmf_error_OutOfMemoryError (env);
130 return JNI_ERR;
131 }
132
133 native_local->next = env->native_locals.list;
134 env->native_locals.list = native_local;
135
136 if (native_local->next != NULL)
137 {
138 assert (native_local->next->previous == NULL);
139
140 native_local->next->previous = native_local;
141 }
142
143 *pobj = _svmf_cast_jobject_nref (native_local);
144 return JNI_OK;
145 }
146
147 /*
148 ----------------------------------------------------------------------
149 _svmh_free_native_local
150 ----------------------------------------------------------------------
151 */
152
153 svm_static void
_svmh_free_native_local(_svmt_JNIEnv * env,jobject * pobj)154 _svmh_free_native_local (_svmt_JNIEnv *env, jobject *pobj)
155 {
156 _svmt_native_ref *native_local = _svmf_cast_nref_jobject (*pobj);
157
158 if (native_local->next != NULL)
159 {
160 native_local->next->previous = native_local->previous;
161 }
162
163 if (native_local->previous != NULL)
164 {
165 native_local->previous->next = native_local->next;
166 }
167 else
168 {
169 env->native_locals.list = native_local->next;
170 }
171
172 native_local->ref = NULL;
173 native_local->previous = NULL;
174 native_local->next = env->native_locals.free_list;
175
176 env->native_locals.free_list = native_local;
177
178 if (native_local->next != NULL)
179 {
180 assert (native_local->next->previous == NULL);
181
182 native_local->next->previous = native_local;
183 }
184
185 *pobj = NULL;
186 }
187
188 /*
189 ----------------------------------------------------------------------
190 _svmf_ensure_native_local_capacity
191 ----------------------------------------------------------------------
192 */
193
194 svm_static jint
_svmf_ensure_native_local_capacity(_svmt_JNIEnv * env,jint needed_lrefs_count)195 _svmf_ensure_native_local_capacity (_svmt_JNIEnv *env,
196 jint needed_lrefs_count)
197 {
198 _svmt_stack_frame *frame = env->stack.current_frame;
199
200 _svmt_stack_native_reference *lrefs = (_svmt_stack_native_reference *)
201 (void *) (((char *) frame) + frame->end_offset);
202 jint old_lrefs_count = lrefs[-1].jint;
203 size_t old_lrefs_size = lrefs[-2].size_t;
204 jint free_lrefs_count = _svmf_get_jni_frame_free_native_local_count (env);
205
206 jint new_lrefs_count;
207 size_t new_lrefs_size;
208 size_t size_increase;
209 jint i;
210
211
212 if (free_lrefs_count >= needed_lrefs_count)
213 {
214 return JNI_OK; /* all right, nothing to do */
215 }
216
217 new_lrefs_count = old_lrefs_count + (needed_lrefs_count - free_lrefs_count);
218 new_lrefs_size = _svmf_aligned_size_t
219 ((new_lrefs_count + 2) * sizeof (_svmt_stack_native_reference));
220
221 size_increase = new_lrefs_size - old_lrefs_size;
222
223 if (_svmf_ensure_stack_capacity (env, size_increase) != JNI_OK)
224 {
225 return JNI_ERR;
226 }
227
228 frame = env->stack.current_frame;
229
230 frame->end_offset += size_increase;
231
232 lrefs =
233 (_svmt_stack_native_reference *) (void *) (((char *) frame) +
234 frame->end_offset);
235 lrefs[-1].jint = new_lrefs_count;
236 lrefs[-2].size_t = new_lrefs_size;
237
238 lrefs =
239 (_svmt_stack_native_reference *) (void *) (((char *) lrefs) -
240 new_lrefs_size);
241
242 /* point lrefs to the begin of _new_ references */
243 lrefs = &lrefs[old_lrefs_count];
244
245 /* just in case we've ran out of memory during refs creation */
246 memset (lrefs, 0, (needed_lrefs_count - free_lrefs_count) *
247 sizeof (_svmt_stack_native_reference));
248
249 for (i = 0; i < (needed_lrefs_count - free_lrefs_count); i++)
250 {
251 if (_svmm_new_native_local (env, lrefs[i].jobject) != JNI_OK)
252 {
253 return JNI_ERR;
254 }
255 }
256
257 return JNI_OK;
258 }
259
260 /*
261 ----------------------------------------------------------------------
262 _svmf_get_jni_frame_native_local
263 ----------------------------------------------------------------------
264 */
265
266 /* It is CRITICAL that this function does not cause garbage
267 * collection, or, if it does, it MUST abort execution.
268 */
269
270 /* NOTE: IT IS IMPORTANT to assign a value OTHER THAN NULL into the
271 * returned jobject BEFORE calling this method again. IF YOU DON'T
272 * follow rigorously this rule, you will probably experience problems,
273 * as this function will repeatedly return the exact same jobject.
274 *
275 * This function is provided as a convenient way to avoid checking
276 * return values (as would be necessary with _svmf_new_native_local),
277 * by using stack frame reserved JNI jobjects. Its primary function
278 * is to help implement the JNI mechanism. So, if you're not sure,
279 * simply use _svmm_new_native_local; you'll then be safe.
280 */
281
282 svm_static jobject
_svmf_get_jni_frame_native_local(_svmt_JNIEnv * env)283 _svmf_get_jni_frame_native_local (_svmt_JNIEnv *env)
284 {
285 #ifndef NDEBUG
286 _svmt_JavaVM *vm = env->vm;
287 #endif
288
289 _svmt_stack_frame *frame = env->stack.current_frame;
290
291 #if !defined(NDEBUG) || defined(_SABLEVM_REAL_LIFE_BROKENNESS)
292 _svmt_method_info *method = frame->method;
293 #endif
294
295 _svmt_stack_native_reference *lrefs = (_svmt_stack_native_reference *)
296 (void *) (((char *) frame) + frame->end_offset);
297 jint lrefs_count = lrefs[-1].jint;
298 size_t lrefs_size = lrefs[-2].size_t;
299 jint i;
300
301 assert (method == &vm->stack_bottom_method
302 || _svmf_is_set_flag (method->access_flags, SVM_ACC_NATIVE));
303
304 lrefs =
305 (_svmt_stack_native_reference *) (void *) (((char *) lrefs) - lrefs_size);
306
307 for (i = 0; i < lrefs_count; i++)
308 {
309 if (*(lrefs[i].jobject) == NULL)
310 {
311 return lrefs[i].jobject;
312 }
313 }
314
315 /* we've ran out of existing local references */
316
317 #ifdef _SABLEVM_REAL_LIFE_BROKENNESS
318
319 if (SVM_FRAME_NATIVE_REFS_AUTOADD_STEP > 0)
320 { /* try to autoadd */
321
322 if (env->vm->verbose_jni)
323 {
324 _svmf_printf (env, stderr,
325 "[verbose jni: local reference capacity (%i) exceeded]\n",
326 lrefs_count -
327 method->data.native_method->refargs_count);
328 }
329
330 /* The following can change env->stack.start/end/current_frame
331 and potentially cause GC on failure to create an Exception
332 instance. */
333 if (_svmf_ensure_native_local_capacity
334 (env, SVM_FRAME_NATIVE_REFS_AUTOADD_STEP) != JNI_OK)
335 {
336 goto end;
337 }
338
339 frame = env->stack.current_frame;
340 lrefs = (_svmt_stack_native_reference *)
341 (void *) (((char *) frame) + frame->end_offset);
342 lrefs_size = lrefs[-2].size_t;
343 lrefs =
344 (_svmt_stack_native_reference *) (void *) (((char *) lrefs) -
345 lrefs_size);
346
347
348 /* get the reference again, it must be available this time */
349 return lrefs[i].jobject;
350 }
351
352 #endif
353
354
355 #ifdef _SABLEVM_REAL_LIFE_BROKENNESS
356 end:
357 #endif
358 _svmf_dump_stack_trace (env);
359 _svmf_jni_fatal_error ("Local reference capacity exceeded.\n"
360 "** This is a bug in your application or in the GNU Classpath Library.\n"
361 "** A virtual machine is only required to provide 16 native local\n"
362 "** references per JNI function call. To get more, an application must call\n"
363 "** EnsureLocalCapacity().\n"
364 "** Temporarily, you might want to compile SableVM with the configure option:\n"
365 "** --enable-real-life-brokenness\n"
366 "** See: http://java.sun.com/docs/books/jni/html/pitfalls.html#11229\n");
367
368 return NULL; /* to keep compiler happy. */
369 }
370
371 /*
372 ----------------------------------------------------------------------
373 _svmm_release_jni_frame_native_local
374 ----------------------------------------------------------------------
375 */
376
377 #define _svmm_release_jni_frame_native_local(obj) \
378 _svmh_release_jni_frame_native_local (&obj)
379
380 svm_static void
_svmh_release_jni_frame_native_local(jobject * pobj)381 _svmh_release_jni_frame_native_local (jobject *pobj)
382 {
383 **pobj = NULL;
384 *pobj = NULL;
385 }
386
387 /*
388 ----------------------------------------------------------------------
389 _svmf_get_jni_frame_native_local_array
390 ----------------------------------------------------------------------
391 */
392
393 /* NOTE: IT IS IMPORTANT to assign a value OTHER THAN NULL into the
394 * returned jarray BEFORE calling this method again. IF YOU DON'T
395 * follow rigorously this rule, you will probably experience problems,
396 * as this function will repeatedly return the exact same jarray.
397 *
398 * This function is provided as a convenient way to avoid checking
399 * return values (as would be necessary with
400 * _svmf_new_native_local_array), by using stack frame reserved JNI
401 * jobjects. Its primary function is to help implement the JNI
402 * mechanism. So, if you're not sure, simply use
403 * _svmf_new_native_local_array; you'll then be safe.
404 */
405
406 svm_static jarray
_svmf_get_jni_frame_native_local_array(_svmt_JNIEnv * env)407 _svmf_get_jni_frame_native_local_array (_svmt_JNIEnv *env)
408 {
409 return _svmf_cast_jarray (_svmf_get_jni_frame_native_local (env));
410 }
411
412 /*
413 ----------------------------------------------------------------------
414 _svmm_release_jni_frame_native_local_array
415 ----------------------------------------------------------------------
416 */
417
418 #define _svmm_release_jni_frame_native_local_array(array) \
419 _svmh_release_jni_frame_native_local_array (&array)
420
421 svm_static void
_svmh_release_jni_frame_native_local_array(jarray * parray)422 _svmh_release_jni_frame_native_local_array (jarray *parray)
423 {
424 **parray = NULL;
425 *parray = NULL;
426 }
427