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 #include "gc_gencopy.h"
10 
11 /*
12 ----------------------------------------------------------------------
13 _svmf_bytes_to_u16
14 ----------------------------------------------------------------------
15 */
16 
17 inline svm_static _svmt_u16
_svmf_bytes_to_u16(_svmt_u8 * bytes)18 _svmf_bytes_to_u16 (_svmt_u8 *bytes)
19 {
20   jint i;
21   _svmt_u16 result = 0;
22 
23   for (i = 0; i < 2; i++)
24     {
25       result = (result << 8) | bytes[i];
26     }
27 
28   return result;
29 }
30 
31 /*
32 ----------------------------------------------------------------------
33 _svmf_bytes_to_s32
34 ----------------------------------------------------------------------
35 */
36 
37 inline svm_static _svmt_s32
_svmf_bytes_to_s32(_svmt_u8 * bytes)38 _svmf_bytes_to_s32 (_svmt_u8 *bytes)
39 {
40   jint i;
41   _svmt_s32 result = 0;
42 
43   for (i = 0; i < 4; i++)
44     {
45       result = (result << 8) | bytes[i];
46     }
47 
48   return result;
49 }
50 
51 /*
52 ----------------------------------------------------------------------
53 _svmf_bytes_to_s16
54 ----------------------------------------------------------------------
55 */
56 
57 inline svm_static _svmt_s16
_svmf_bytes_to_s16(_svmt_u8 * bytes)58 _svmf_bytes_to_s16 (_svmt_u8 *bytes)
59 {
60   jint i;
61   _svmt_s16 result = 0;
62 
63   for (i = 0; i < 2; i++)
64     {
65       result = (result << 8) | bytes[i];
66     }
67 
68   return result;
69 }
70 
71 /*
72 ----------------------------------------------------------------------
73 _svmf_aligned_size_t
74 ----------------------------------------------------------------------
75 */
76 
77 inline static size_t
_svmf_aligned_size_t(size_t size)78 _svmf_aligned_size_t (size_t size)
79 {
80   return (size + (SVM_ALIGNMENT - 1)) & ~((size_t) (SVM_ALIGNMENT - 1));
81 }
82 
83 /*
84 ----------------------------------------------------------------------
85 _svmf_max_jint
86 ----------------------------------------------------------------------
87 */
88 
89 inline static jint
_svmf_max_jint(jint value1,jint value2)90 _svmf_max_jint (jint value1, jint value2)
91 {
92   return (value1 >= value2) ? value1 : value2;
93 }
94 
95 /*
96 ----------------------------------------------------------------------
97 _svmf_min_jint
98 ----------------------------------------------------------------------
99 */
100 
101 inline static jint
_svmf_min_jint(jint value1,jint value2)102 _svmf_min_jint (jint value1, jint value2)
103 {
104   return (value1 <= value2) ? value1 : value2;
105 }
106 
107 /*
108 ----------------------------------------------------------------------
109 _svmf_get_bit
110 ----------------------------------------------------------------------
111 */
112 
113 inline static jboolean
_svmf_get_bit(_svmt_u8 * bytes,jint index)114 _svmf_get_bit (_svmt_u8 *bytes, jint index)
115 {
116   return (bytes[index / 8] >> (index % 8)) & 1;
117 }
118 
119 /*
120 ----------------------------------------------------------------------
121 _svmf_set_bit
122 ----------------------------------------------------------------------
123 */
124 
125 inline static void
_svmf_set_bit(_svmt_u8 * bytes,jint index)126 _svmf_set_bit (_svmt_u8 *bytes, jint index)
127 {
128   bytes[index / 8] |= ((_svmt_u8) 1) << (index % 8);
129 }
130 
131 /*
132 ----------------------------------------------------------------------
133 _svmf_clear_bit
134 ----------------------------------------------------------------------
135 */
136 
137 inline static void
_svmf_clear_bit(_svmt_u8 * bytes,jint index)138 _svmf_clear_bit (_svmt_u8 *bytes, jint index)
139 {
140   bytes[index / 8] &= ~(((_svmt_u8) 1) << (index % 8));
141 }
142 
143 /*
144 ----------------------------------------------------------------------
145 _svmf_is_set_flag
146 ----------------------------------------------------------------------
147 */
148 
149 inline static jboolean
_svmf_is_set_flag(jint value,jint flag)150 _svmf_is_set_flag (jint value, jint flag)
151 {
152   return (value & flag) == flag;
153 }
154 
155 /*
156 ----------------------------------------------------------------------
157 _svmh_set_flag
158 ----------------------------------------------------------------------
159 */
160 
161 inline static void
_svmh_set_flag(jint * pvalue,jint flag)162 _svmh_set_flag (jint *pvalue, jint flag)
163 {
164   *pvalue |= flag;
165 }
166 
167 /*
168 ----------------------------------------------------------------------
169 _svmh_clear_flag
170 ----------------------------------------------------------------------
171 */
172 
173 inline static void
_svmh_clear_flag(jint * pvalue,jint flag)174 _svmh_clear_flag (jint *pvalue, jint flag)
175 {
176   *pvalue &= ~flag;
177 }
178 
179 /*
180 ----------------------------------------------------------------------
181 _svmf_is_interface
182 ----------------------------------------------------------------------
183 */
184 
185 inline static jboolean
_svmf_is_interface(_svmt_class_info * class)186 _svmf_is_interface (_svmt_class_info *class)
187 {
188   return _svmf_is_set_flag (class->access_flags, SVM_ACC_INTERFACE);
189 }
190 
191 /*
192 ----------------------------------------------------------------------
193 _svmf_aligned_to_increment
194 ----------------------------------------------------------------------
195 */
196 
197 inline static size_t
_svmf_aligned_to_increment(size_t size,size_t increment)198 _svmf_aligned_to_increment (size_t size, size_t increment)
199 {
200   return ((size + (increment - 1)) / increment) * increment;
201 }
202 
203 /*
204 ----------------------------------------------------------------------
205 _svmh_validate_min_max_increment
206 ----------------------------------------------------------------------
207 */
208 
209 svm_static jint
_svmh_validate_min_max_increment(size_t * pmin,size_t * pmax,size_t * pincr)210 _svmh_validate_min_max_increment (size_t *pmin, size_t *pmax, size_t *pincr)
211 {
212   *pmin = _svmf_aligned_size_t (*pmin);
213   *pmax = _svmf_aligned_size_t (*pmax);
214   *pincr = _svmf_aligned_size_t (*pincr);
215 
216   /* Allow shortcut for specifying fixed size */
217   if (*pmin == *pmax)
218     {
219       *pincr = 0;
220     }
221   else if (*pincr == 0)
222     {
223       *pmax = *pmin;
224     }
225 
226   /* min must be positive */
227   if (*pmin == 0)
228     {
229       return JNI_ERR;
230     }
231 
232   /* max size of 0 means no maximum */
233   if (*pmax == 0 && *pincr == 0)
234     {
235       return JNI_ERR;
236     }
237 
238   /* if not 0, max size must be >= the min size */
239   if (*pmax > 0 && *pmax < *pmin)
240     {
241       return JNI_ERR;
242     }
243 
244   /* incr should be zero for fixed size, non-zero otherwise */
245   if ((*pmax == *pmin && *pincr != 0) || (*pmax != *pmin && *pincr == 0))
246     {
247       return JNI_ERR;
248     }
249 
250   /* make (max - min) a multiple of incr */
251   if (*pmax > *pmin)
252     {
253       *pmax = *pmin + _svmf_aligned_to_increment (*pmax - *pmin, *pincr);
254 
255       if (*pmax <= *pmin)
256 	{
257 	  return JNI_ERR;
258 	}
259     }
260 
261   return JNI_OK;
262 }
263 
264 /*
265 ----------------------------------------------------------------------
266 _svmf_get_boolean_array_element
267 ----------------------------------------------------------------------
268 */
269 
270 inline static jboolean
_svmf_get_boolean_array_element(_svmt_array_instance * array,jint indx)271 _svmf_get_boolean_array_element (_svmt_array_instance *array, jint indx)
272 {
273   _svmt_u8 *elements;
274 
275 #ifndef _SABLEVM_INLINED_THREADED_INTERPRETER
276   assert (array != NULL);
277   assert (array->vtable->type->is_array);
278   assert (indx >= 0 && indx < array->size);
279 #endif
280 
281   elements = (_svmt_u8 *)
282     (((char *) array) + _svmf_aligned_size_t (sizeof (_svmt_array_instance)));
283 
284   return _svmf_get_bit (elements, indx);
285 }
286 
287 /*
288 ----------------------------------------------------------------------
289 _svmf_set_boolean_array_element
290 ----------------------------------------------------------------------
291 */
292 
293 inline svm_static void
_svmf_set_boolean_array_element(_svmt_array_instance * array,jint indx,jboolean value)294 _svmf_set_boolean_array_element (_svmt_array_instance *array, jint indx,
295 				 jboolean value)
296 {
297   _svmt_u8 *elements;
298 
299 #ifndef _SABLEVM_INLINED_THREADED_INTERPRETER
300   assert (array != NULL);
301   assert (array->vtable->type->is_array);
302   assert (indx >= 0 && indx < array->size);
303 #endif
304 
305   elements = (_svmt_u8 *)
306     (((char *) array) + _svmf_aligned_size_t (sizeof (_svmt_array_instance)));
307 
308   if (value)
309     {
310       _svmf_set_bit (elements, indx);
311     }
312   else
313     {
314       _svmf_clear_bit (elements, indx);
315     }
316 }
317 
318 /*
319 ----------------------------------------------------------------------
320 _svmf_get_reference_array_element
321 ----------------------------------------------------------------------
322 */
323 
324 inline svm_static _svmt_object_instance *
_svmf_get_reference_array_element(_svmt_array_instance * array,jint indx)325 _svmf_get_reference_array_element (_svmt_array_instance *array, jint indx)
326 {
327   _svmt_object_instance **elements;
328 
329 #ifndef _SABLEVM_INLINED_THREADED_INTERPRETER
330   assert (array != NULL);
331   assert (array->vtable->type->is_array);
332   assert (indx >= 0 && indx < array->size);
333 #endif
334 
335 #if defined (_SABLEVM_BIDIRECTIONAL_OBJECT_LAYOUT)
336 
337   elements = (_svmt_object_instance **) array;
338   return elements[(-1) - indx];
339 
340 #else
341 
342   elements = (_svmt_object_instance **)
343     (((char *) array) + _svmf_aligned_size_t (sizeof (_svmt_array_instance)));
344 
345   return elements[indx];
346 
347 #endif
348 }
349 
350 /*
351 ----------------------------------------------------------------------
352 _svmf_printf
353 ----------------------------------------------------------------------
354 */
355 
356 svm_static void
_svmf_printf(_svmt_JNIEnv * env,FILE * stream,const char * format,...)357 _svmf_printf (_svmt_JNIEnv *env, FILE *stream, const char *format, ...)
358 {
359   _svmt_JavaVM *vm = env->vm;
360   va_list ap;
361 
362   va_start (ap, format);
363 
364   (*(vm->vfprintf)) (stream, format, ap);
365 
366 #if (!defined(NDEBUG)) || defined(_SABLEVM_INLINABILITY_TESTING)
367   fflush (NULL);
368 #endif
369 
370   va_end (ap);
371 }
372 
373 /*
374 ----------------------------------------------------------------------
375 _svmf_parse_size_t
376 ----------------------------------------------------------------------
377 */
378 
379 svm_static jint
_svmf_parse_size_t(size_t * size,const char * value)380 _svmf_parse_size_t (size_t *size, const char *value)
381 {
382   size_t result = 0;
383 
384   if (*value == 0)
385     {
386       return JNI_ERR;
387     }
388 
389   do
390     {
391       char c = *value++;
392 
393       if (c >= '0' && c <= '9')
394 	{
395 	  size_t old = result;
396 	  result = (result * 10) + (c - '0');
397 	  if (result < old)
398 	    {
399 	      return JNI_ERR;
400 	    }
401 	}
402       else if (c == 0)
403 	{
404 	  *size = result;
405 	  return JNI_OK;
406 	}
407       else
408 	{
409 	  return JNI_ERR;
410 	}
411     }
412   while (1);
413 }
414 
415 /*
416 ----------------------------------------------------------------------
417 _svmf_get_BOOLEAN_field
418 ----------------------------------------------------------------------
419 */
420 
421 inline static jboolean
_svmf_get_BOOLEAN_field(_svmt_object_instance * instance,size_t offset)422 _svmf_get_BOOLEAN_field (_svmt_object_instance *instance, size_t offset)
423 {
424   return _svmf_get_bit ((_svmt_u8 *) instance, offset);
425 }
426 
427 /*
428 ----------------------------------------------------------------------
429 _svmf_put_BOOLEAN_field
430 ----------------------------------------------------------------------
431 */
432 
433 inline static void
_svmf_put_BOOLEAN_field(_svmt_object_instance * instance,size_t offset,jboolean value)434 _svmf_put_BOOLEAN_field (_svmt_object_instance *instance, size_t offset,
435 			 jboolean value)
436 {
437   if (value)
438     {
439       _svmf_set_bit ((_svmt_u8 *) instance, offset);
440     }
441   else
442     {
443       _svmf_clear_bit ((_svmt_u8 *) instance, offset);
444     }
445 }
446 
447 /*
448 ----------------------------------------------------------------------
449 _svmf_get_REFERENCE_field
450 ----------------------------------------------------------------------
451 */
452 
453 inline static _svmt_object_instance *
_svmf_get_REFERENCE_field(_svmt_object_instance * instance,size_t offset)454 _svmf_get_REFERENCE_field (_svmt_object_instance *instance, size_t offset)
455 {
456   _svmt_object_instance *result =
457     *((_svmt_object_instance **) (void *) (((char *) instance) + offset));
458 
459 #if defined (MAGIC) && !defined (_SABLEVM_INLINED_THREADED_INTERPRETER)
460   assert (result == NULL || strcmp (result->magic, "SableVM") == 0);
461 #endif
462 
463   return result;
464 }
465 
466 /*
467 ----------------------------------------------------------------------
468 _svmf_put_REFERENCE_field
469 ----------------------------------------------------------------------
470 */
471 
472 inline static void
_svmf_put_REFERENCE_field(_svmt_JNIEnv * env SVM_UNUSED,_svmt_object_instance * instance,size_t offset,_svmt_object_instance * value)473 _svmf_put_REFERENCE_field (_svmt_JNIEnv *env SVM_UNUSED,
474 			   _svmt_object_instance *instance, size_t offset,
475 			   _svmt_object_instance *value)
476 {
477   *((_svmt_object_instance **) (void *) (((char *) instance) + offset)) =
478     value;
479 #if defined (_SABLEVM_GC_WRITE_BARRIER)
480   _svmf_write_barrier
481     (env, (_svmt_object_instance **) (void *) ((char *) instance + offset));
482 #endif /* _SABLEVM_GC_WRITE_BARRIER */
483 }
484 
485 /*
486 ----------------------------------------------------------------------
487 _svmf_get_REFERENCE_static
488 ----------------------------------------------------------------------
489 */
490 
491 inline static _svmt_object_instance *
_svmf_get_REFERENCE_static(jvalue * pvalue)492 _svmf_get_REFERENCE_static (jvalue *pvalue)
493 {
494   _svmt_object_instance *result = *(pvalue->l);
495 
496 #if defined (MAGIC) && !defined (_SABLEVM_INLINED_THREADED_INTERPRETER)
497   assert (result == NULL || strcmp (result->magic, "SableVM") == 0);
498 #endif
499 
500   return result;
501 }
502 
503 /*
504 ----------------------------------------------------------------------
505 _svmf_put_REFERENCE_static
506 ----------------------------------------------------------------------
507 */
508 
509 inline static void
_svmf_put_REFERENCE_static(jvalue * pvalue,_svmt_object_instance * value)510 _svmf_put_REFERENCE_static (jvalue *pvalue, _svmt_object_instance *value)
511 {
512   *(pvalue->l) = value;
513 }
514 
515 /*
516 ----------------------------------------------------------------------
517 _svmf_dump_stack_trace
518 ----------------------------------------------------------------------
519 */
520 
521 svm_static void
_svmf_dump_stack_trace(_svmt_JNIEnv * env)522 _svmf_dump_stack_trace (_svmt_JNIEnv *env)
523 {
524   _svmt_JavaVM *vm = env->vm;
525   _svmt_stack_frame *frame = env->stack.current_frame;
526   _svmt_method_info *method = frame->method;
527 
528   jint lineNumber = -1;
529   jboolean isNative = JNI_FALSE;
530 
531   _svmf_printf (env, stderr, "--- stack trace dump (begin) ---\n");
532   _svmf_printf (env, stderr, "Thread ID: %d, Posix ID: %d\n", env->thread.id,
533 		env->thread.pthread);
534 
535   while (method != &vm->stack_bottom_method)
536     {
537       _svmt_class_info *class;
538 
539       /* skip internal frames */
540       if (_svmf_is_set_flag (method->access_flags, SVM_ACC_INTERNAL))
541 	{
542 	  _svmf_printf (env, stderr, "(internal frame)\n");
543 
544 	  frame = (_svmt_stack_frame *) (void *)
545 	    (((char *) frame) - frame->previous_offset);
546 	  method = frame->method;
547 	  continue;
548 	}
549 
550       isNative = _svmf_is_set_flag (method->access_flags, SVM_ACC_NATIVE);
551 
552       class = method->class_info;
553 
554       if ((!isNative) && method->data.code_attribute->line_numbers != NULL)
555 	{
556 	  jint table_length =
557 	    method->data.code_attribute->line_numbers->
558 	    line_number_table_length;
559 	  _svmt_line_number_table *table =
560 	    method->data.code_attribute->line_numbers->line_number_table;
561 	  _svmt_code *pc = frame->pc;
562 	  jint i;
563 
564 	  for (i = 0; i < table_length; i++)
565 	    {
566 	      if ((pc >= table[i].normal_start && pc <= table[i].normal_end)
567 		  || (pc >= table[i].prepare_start
568 		      && pc <= table[i].prepare_end))
569 		{
570 		  lineNumber = table[i].line_number;
571 		  break;
572 		}
573 	    }
574 	}
575 
576       _svmf_printf (env, stderr, "(%s:%d)  %s.%s  %c\n", class->file_name,
577 		    lineNumber, class->name, DREF (method->name, value),
578 		    (jint) (isNative ? 'n' : ' '));
579 
580       lineNumber = -1;
581       isNative = JNI_FALSE;
582 
583       frame = (_svmt_stack_frame *) (void *)
584 	(((char *) frame) - frame->previous_offset);
585       method = frame->method;
586     }
587 
588   _svmf_printf (env, stderr, "--- stack trace dump (end) ---\n");
589 
590 }
591 
592 
593 
594 
595 
596 
597 #ifdef COMMENT
598 
599 #include "includes.h"
600 
601 static jboolean have_identical_package_name
602   (const char *name1, const char *name2);
603 
604 
605 /*
606 ----------------------------------------------------------------------
607 have_identical_package_name
608 ----------------------------------------------------------------------
609 */
610 
611 svm_static jboolean
have_identical_package_name(const char * name1,const char * name2)612 have_identical_package_name (const char *name1, const char *name2)
613 {
614   size_t i, j;
615   size_t length;
616   size_t len1 = strlen (name1);
617   size_t len2 = strlen (name2);
618 
619   length = (len1 >= len2) ? len1 : len2;
620 
621   /* skip common prefix */
622   for (i = 0; i < length; i++)
623     {
624       if (name1[i] != name2[i])
625 	{
626 	  break;
627 	}
628     }
629 
630   /* if the remaining of name1 or name2 contains a '/', then the packages differ */
631   for (j = i; j < len1; j++)
632     {
633       if (name1[j] == '/')
634 	{
635 	  return JNI_FALSE;
636 	}
637     }
638 
639   for (j = i; j < len2; j++)
640     {
641       if (name2[j] == '/')
642 	{
643 	  return JNI_FALSE;
644 	}
645     }
646 
647   return JNI_TRUE;
648 }
649 
650 /*
651 ----------------------------------------------------------------------
652 _svmf_has_same_runtime_package
653 ----------------------------------------------------------------------
654 */
655 
656 jboolean
_svmf_have_same_runtime_package(_svmt_type_info * type1,_svmt_type_info * type2)657 _svmf_have_same_runtime_package (_svmt_type_info *type1,
658 				 _svmt_type_info *type2)
659 {
660   return
661     (type1->class_loader_info == type2->class_loader_info &&
662      have_identical_package_name (type1->name, type2->name))
663     ? JNI_TRUE : JNI_FALSE;
664 }
665 
666 /*
667 ----------------------------------------------------------------------
668 _svmf_debug_print_stack_trace
669 ----------------------------------------------------------------------
670 */
671 
672 void
_svmf_debug_print_stack_trace(_svmt_JNIEnv * env)673 _svmf_debug_print_stack_trace (_svmt_JNIEnv *env)
674 {
675   _svmt_stack_frame *frame = env->stack.current_frame;
676 
677   /*  if (strcmp(DREF(frame->method->name, value), "loadLibrary") == 0)
678      {
679      printf ("gotcha!\n");
680      } */
681 
682   printf ("--------------------\n");
683   while (1)
684     {
685       _svmt_method_info *method = frame->method;
686 
687       if (IS_SET (method->access_flags, SVM_ACC_DUMMY))
688 	{
689 	  printf (" -- \n");
690 	}
691       else if (IS_SET (method->access_flags, SVM_ACC_NATIVE))
692 	{
693 	  printf
694 	    ("%s.%s %s (native)\n",
695 	     method->class_info->name,
696 	     DREF (method->name, value), DREF (method->descriptor, value));
697 	}
698       else if (method->code != method->code_attribute->prepared_code)
699 	{
700 	  printf
701 	    ("%s.%s %s (being prepared)\n",
702 	     method->class_info->name,
703 	     DREF (method->name, value), DREF (method->descriptor, value));
704 	}
705       else
706 	{
707 	  _svmt_bytecode_info *bc_info = method->code_attribute->bc_info;
708 	  jint attributes_count = method->code_attribute->attributes_count;
709 	  jint i;
710 	  _svmt_LineNumberTable_attribute *attribute = NULL;
711 	  size_t offset = frame->pc - method->code;
712 	  jint table_length;
713 	  _svmt_line_number_table *table;
714 	  jboolean printed = JNI_FALSE;
715 
716 	  for (i = 0; i < attributes_count; i++)
717 	    {
718 	      if (strcmp
719 		  (DREF (method->code_attribute->attributes[i]->name, value),
720 		   "LineNumberTable") == 0)
721 		{
722 		  attribute = (_svmt_LineNumberTable_attribute *)
723 		    method->code_attribute->attributes[i];
724 		}
725 	    }
726 
727 	  if (attribute != NULL)
728 	    {
729 	      table_length = attribute->line_number_table_length;
730 	      table = attribute->line_number_table;
731 
732 	      for (i = table_length - 1; i >= 0; i--)
733 		{
734 		  if (offset >=
735 		      bc_info[table[i].start_pc].code_offset +
736 		      bc_info[table[i].start_pc].code_length)
737 		    {
738 		      printf
739 			("%s.%s %s (line %d)\n",
740 			 method->class_info->name,
741 			 DREF (method->name, value),
742 			 DREF (method->descriptor, value),
743 			 table[i].line_number);
744 		      printed = JNI_TRUE;
745 		      break;
746 		    }
747 		}
748 	    }
749 
750 	  if (!printed)
751 	    {
752 	      jint bc_length = method->code_attribute->code_length;
753 	      for (i = 0; i < bc_length; i++)
754 		{
755 		  if (offset ==
756 		      bc_info[i].code_offset + bc_info[i].code_length)
757 		    {
758 		      printf
759 			("%s.%s %s (at bytecode # %d)\n",
760 			 method->class_info->name,
761 			 DREF (method->name, value),
762 			 DREF (method->descriptor, value), i);
763 		      printed = JNI_TRUE;
764 		      break;
765 		    }
766 		}
767 	    }
768 
769 	  if (!printed)
770 	    {
771 	      printf
772 		("%s.%s %s (unknown)\n",
773 		 method->class_info->name,
774 		 DREF (method->name, value),
775 		 DREF (method->descriptor, value));
776 	      break;
777 	    }
778 	}
779 
780       if (frame->previous_offset == 0)
781 	{
782 	  break;
783 	}
784 
785       frame =
786 	(_svmt_stack_frame *) (((char *) frame) - frame->previous_offset);
787     }
788 }
789 
790 
791 #endif /* COMMENT */
792