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