1 /* src/vm/jit/x86_64/patcher.c - x86_64 code patching functions
3 Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 Contact: cacao@cacaojvm.org
27 Authors: Christian Thalinger
31 $Id: patcher.c 4357 2006-01-22 23:33:38Z twisti $
39 #include "mm/memory.h"
40 #include "native/native.h"
41 #include "vm/builtin.h"
44 #include "vm/initialize.h"
45 #include "vm/options.h"
46 #include "vm/references.h"
47 #include "vm/resolve.h"
48 #include "vm/jit/patcher.h"
51 /* patcher_get_putstatic *******************************************************
55 <patched call position>
56 4d 8b 15 86 fe ff ff mov -378(%rip),%r10
57 49 8b 32 mov (%r10),%rsi
59 *******************************************************************************/
61 bool patcher_get_putstatic(u1 *sp)
71 /* get stuff from the stack */
73 ra = (u1 *) *((ptrint *) (sp + 4 * 8));
74 o = (java_objectheader *) *((ptrint *) (sp + 3 * 8));
75 mcode = *((u8 *) (sp + 2 * 8));
76 uf = (unresolved_field *) *((ptrint *) (sp + 1 * 8));
77 disp = *((s4 *) (sp + 0 * 8));
79 /* calculate and set the new return address */
82 *((ptrint *) (sp + 4 * 8)) = (ptrint) ra;
86 /* get the fieldinfo */
88 if (!(fi = resolve_field_eager(uf))) {
94 /* check if the field's class is initialized */
96 if (!(fi->class->state & CLASS_INITIALIZED)) {
97 if (!initialize_class(fi->class)) {
104 /* patch back original code */
106 *((u8 *) ra) = mcode;
108 /* if we show disassembly, we have to skip the nop's */
110 if (opt_showdisassemble)
113 /* get RIP offset from machine instruction */
115 offset = *((u4 *) (ra + 3));
117 /* patch the field value's address (+ 7: is the size of the RIP move) */
119 *((ptrint *) (ra + 7 + offset)) = (ptrint) &(fi->value);
121 PATCHER_MARK_PATCHED_MONITOREXIT;
127 /* patcher_get_putfield ********************************************************
131 <patched call position>
132 45 8b 8f 00 00 00 00 mov 0x0(%r15),%r9d
134 *******************************************************************************/
136 bool patcher_get_putfield(u1 *sp)
139 java_objectheader *o;
141 unresolved_field *uf;
145 /* get stuff from the stack */
147 ra = (u1 *) *((ptrint *) (sp + 4 * 8));
148 o = (java_objectheader *) *((ptrint *) (sp + 3 * 8));
149 mcode = *((u8 *) (sp + 2 * 8));
150 uf = (unresolved_field *) *((ptrint *) (sp + 1 * 8));
152 /* calculate and set the new return address */
155 *((ptrint *) (sp + 4 * 8)) = (ptrint) ra;
157 PATCHER_MONITORENTER;
159 /* get the fieldinfo */
161 if (!(fi = resolve_field_eager(uf))) {
167 /* patch back original code (instruction code is smaller than 8 bytes) */
169 *((u4 *) (ra + 0)) = (u4) mcode;
170 *((u1 *) (ra + 4)) = (u1) (mcode >> 32);
172 /* if we show disassembly, we have to skip the nop's */
174 if (opt_showdisassemble)
177 /* patch the field's offset: we check for the field type, because the */
178 /* instructions have different lengths */
180 if (IS_INT_LNG_TYPE(fi->type)) {
181 /* check for special case: %rsp or %r12 as base register */
186 *((u4 *) (ra + 4)) = (u4) (fi->offset);
188 *((u4 *) (ra + 3)) = (u4) (fi->offset);
191 /* check for special case: %rsp or %r12 as base register */
196 *((u4 *) (ra + 6)) = (u4) (fi->offset);
198 *((u4 *) (ra + 5)) = (u4) (fi->offset);
201 PATCHER_MARK_PATCHED_MONITOREXIT;
207 /* patcher_putfieldconst *******************************************************
211 <patched call position>
212 41 c7 85 00 00 00 00 7b 00 00 00 movl $0x7b,0x0(%r13)
214 *******************************************************************************/
216 bool patcher_putfieldconst(u1 *sp)
219 java_objectheader *o;
221 unresolved_field *uf;
224 /* get stuff from the stack */
226 ra = (u1 *) *((ptrint *) (sp + 4 * 8));
227 o = (java_objectheader *) *((ptrint *) (sp + 3 * 8));
228 mcode = *((u8 *) (sp + 2 * 8));
229 uf = (unresolved_field *) *((ptrint *) (sp + 1 * 8));
231 /* calculate and set the new return address */
234 *((ptrint *) (sp + 4 * 8)) = (ptrint) ra;
236 PATCHER_MONITORENTER;
238 /* get the fieldinfo */
240 if (!(fi = resolve_field_eager(uf))) {
246 /* patch back original code */
248 *((u8 *) ra) = mcode;
250 /* if we show disassembly, we have to skip the nop's */
252 if (opt_showdisassemble)
255 /* patch the field's offset */
257 if (IS_2_WORD_TYPE(fi->type) || IS_ADR_TYPE(fi->type)) {
258 /* handle special case when the base register is %r12 */
260 if (*(ra + 2) == 0x84) {
261 *((u4 *) (ra + 4)) = (u4) (fi->offset);
262 *((u4 *) (ra + 12 + 4)) = (u4) (fi->offset + 4);
265 *((u4 *) (ra + 3)) = (u4) (fi->offset);
266 *((u4 *) (ra + 11 + 3)) = (u4) (fi->offset + 4);
270 /* handle special case when the base register is %r12 */
272 if (*(ra + 2) == 0x84)
273 *((u4 *) (ra + 4)) = (u4) (fi->offset);
275 *((u4 *) (ra + 3)) = (u4) (fi->offset);
278 PATCHER_MARK_PATCHED_MONITOREXIT;
284 /* patcher_aconst **************************************************************
288 <patched call position>
289 48 bf a0 f0 92 00 00 00 00 00 mov $0x92f0a0,%rdi
291 *******************************************************************************/
293 bool patcher_aconst(u1 *sp)
296 java_objectheader *o;
298 constant_classref *cr;
301 /* get stuff from the stack */
303 ra = (u1 *) *((ptrint *) (sp + 4 * 8));
304 o = (java_objectheader *) *((ptrint *) (sp + 3 * 8));
305 mcode = *((u8 *) (sp + 2 * 8));
306 cr = (constant_classref *) *((ptrint *) (sp + 1 * 8));
308 /* calculate and set the new return address */
311 *((ptrint *) (sp + 4 * 8)) = (ptrint) ra;
313 PATCHER_MONITORENTER;
315 /* get the classinfo */
317 if (!(c = resolve_classref_eager(cr))) {
323 /* patch back original code */
325 *((u8 *) ra) = mcode;
327 /* if we show disassembly, we have to skip the nop's */
329 if (opt_showdisassemble)
332 /* patch the classinfo pointer */
334 *((ptrint *) (ra + 2)) = (ptrint) c;
336 PATCHER_MARK_PATCHED_MONITOREXIT;
342 /* patcher_builtin_multianewarray **********************************************
346 <patched call position>
347 48 bf 02 00 00 00 00 00 00 00 mov $0x2,%rdi
348 48 be 30 40 b2 00 00 00 00 00 mov $0xb24030,%rsi
349 48 89 e2 mov %rsp,%rdx
350 48 b8 7c 96 4b 00 00 00 00 00 mov $0x4b967c,%rax
353 *******************************************************************************/
355 bool patcher_builtin_multianewarray(u1 *sp)
358 java_objectheader *o;
360 constant_classref *cr;
363 /* get stuff from the stack */
365 ra = (u1 *) *((ptrint *) (sp + 4 * 8));
366 o = (java_objectheader *) *((ptrint *) (sp + 3 * 8));
367 mcode = *((u8 *) (sp + 2 * 8));
368 cr = (constant_classref *) *((ptrint *) (sp + 1 * 8));
370 /* calculate and set the new return address */
373 *((ptrint *) (sp + 4 * 8)) = (ptrint) ra;
375 PATCHER_MONITORENTER;
377 /* get the classinfo */
379 if (!(c = resolve_classref_eager(cr))) {
385 /* patch back original code */
387 *((u8 *) ra) = mcode;
389 /* if we show disassembly, we have to skip the nop's */
391 if (opt_showdisassemble)
394 /* patch the classinfo pointer */
396 *((ptrint *) (ra + 10 + 2)) = (ptrint) c;
398 /* patch new function address */
400 *((ptrint *) (ra + 10 + 10 + 3 + 2)) = (ptrint) BUILTIN_multianewarray;
402 PATCHER_MARK_PATCHED_MONITOREXIT;
408 /* patcher_builtin_arraycheckcast **********************************************
412 <patched call position>
413 48 be b8 3f b2 00 00 00 00 00 mov $0xb23fb8,%rsi
414 48 b8 00 00 00 00 00 00 00 00 mov $0x0,%rax
417 *******************************************************************************/
419 bool patcher_builtin_arraycheckcast(u1 *sp)
422 java_objectheader *o;
424 constant_classref *cr;
427 /* get stuff from the stack */
429 ra = (u1 *) *((ptrint *) (sp + 4 * 8));
430 o = (java_objectheader *) *((ptrint *) (sp + 3 * 8));
431 mcode = *((u8 *) (sp + 2 * 8));
432 cr = (constant_classref *) *((ptrint *) (sp + 1 * 8));
434 /* calculate and set the new return address */
437 *((ptrint *) (sp + 4 * 8)) = (ptrint) ra;
439 PATCHER_MONITORENTER;
441 /* get the classinfo */
443 if (!(c = resolve_classref_eager(cr))) {
449 /* patch back original code */
451 *((u8 *) ra) = mcode;
453 /* if we show disassembly, we have to skip the nop's */
455 if (opt_showdisassemble)
458 /* patch the classinfo pointer */
460 *((ptrint *) (ra + 2)) = (ptrint) c;
462 PATCHER_MARK_PATCHED_MONITOREXIT;
468 /* patcher_invokestatic_special ************************************************
472 <patched call position>
473 49 ba 00 00 00 00 00 00 00 00 mov $0x0,%r10
476 *******************************************************************************/
478 bool patcher_invokestatic_special(u1 *sp)
481 java_objectheader *o;
483 unresolved_method *um;
486 /* get stuff from the stack */
488 ra = (u1 *) *((ptrint *) (sp + 4 * 8));
489 o = (java_objectheader *) *((ptrint *) (sp + 3 * 8));
490 mcode = *((u8 *) (sp + 2 * 8));
491 um = (unresolved_method *) *((ptrint *) (sp + 1 * 8));
493 /* calculate and set the new return address */
496 *((ptrint *) (sp + 4 * 8)) = (ptrint) ra;
498 PATCHER_MONITORENTER;
500 /* get the fieldinfo */
502 if (!(m = resolve_method_eager(um))) {
507 /* patch back original code */
509 *((u8 *) ra) = mcode;
511 /* if we show disassembly, we have to skip the nop's */
513 if (opt_showdisassemble)
516 /* patch stubroutine */
518 *((ptrint *) (ra + 2)) = (ptrint) m->stubroutine;
520 PATCHER_MARK_PATCHED_MONITOREXIT;
526 /* patcher_invokevirtual *******************************************************
530 <patched call position>
531 4c 8b 17 mov (%rdi),%r10
532 49 8b 82 00 00 00 00 mov 0x0(%r10),%rax
535 *******************************************************************************/
537 bool patcher_invokevirtual(u1 *sp)
540 java_objectheader *o;
542 unresolved_method *um;
545 /* get stuff from the stack */
547 ra = (u1 *) *((ptrint *) (sp + 4 * 8));
548 o = (java_objectheader *) *((ptrint *) (sp + 3 * 8));
549 mcode = *((u8 *) (sp + 2 * 8));
550 um = (unresolved_method *) *((ptrint *) (sp + 1 * 8));
552 /* calculate and set the new return address */
555 *((ptrint *) (sp + 4 * 8)) = (ptrint) ra;
557 PATCHER_MONITORENTER;
559 /* get the fieldinfo */
561 if (!(m = resolve_method_eager(um))) {
567 /* patch back original code */
569 *((u8 *) ra) = mcode;
571 /* if we show disassembly, we have to skip the nop's */
573 if (opt_showdisassemble)
576 /* patch vftbl index */
578 *((s4 *) (ra + 3 + 3)) = (s4) (OFFSET(vftbl_t, table[0]) +
579 sizeof(methodptr) * m->vftblindex);
581 PATCHER_MARK_PATCHED_MONITOREXIT;
587 /* patcher_invokeinterface *****************************************************
591 <patched call position>
592 4c 8b 17 mov (%rdi),%r10
593 4d 8b 92 00 00 00 00 mov 0x0(%r10),%r10
594 49 8b 82 00 00 00 00 mov 0x0(%r10),%rax
597 *******************************************************************************/
599 bool patcher_invokeinterface(u1 *sp)
602 java_objectheader *o;
604 unresolved_method *um;
607 /* get stuff from the stack */
609 ra = (u1 *) *((ptrint *) (sp + 4 * 8));
610 o = (java_objectheader *) *((ptrint *) (sp + 3 * 8));
611 mcode = *((u8 *) (sp + 2 * 8));
612 um = (unresolved_method *) *((ptrint *) (sp + 1 * 8));
614 /* calculate and set the new return address */
617 *((ptrint *) (sp + 4 * 8)) = (ptrint) ra;
619 PATCHER_MONITORENTER;
621 /* get the fieldinfo */
623 if (!(m = resolve_method_eager(um))) {
629 /* patch back original code */
631 *((u8 *) ra) = mcode;
633 /* if we show disassembly, we have to skip the nop's */
635 if (opt_showdisassemble)
638 /* patch interfacetable index */
640 *((s4 *) (ra + 3 + 3)) = (s4) (OFFSET(vftbl_t, interfacetable[0]) -
641 sizeof(methodptr) * m->class->index);
643 /* patch method offset */
645 *((s4 *) (ra + 3 + 7 + 3)) =
646 (s4) (sizeof(methodptr) * (m - m->class->methods));
648 PATCHER_MARK_PATCHED_MONITOREXIT;
654 /* patcher_checkcast_instanceof_flags ******************************************
658 <patched call position>
659 41 ba 00 00 00 00 mov $0x0,%r10d
660 41 81 e2 00 02 00 00 and $0x200,%r10d
661 0f 84 35 00 00 00 je 0x00002aaaaab01479
663 *******************************************************************************/
665 bool patcher_checkcast_instanceof_flags(u1 *sp)
668 java_objectheader *o;
670 constant_classref *cr;
673 /* get stuff from the stack */
675 ra = (u1 *) *((ptrint *) (sp + 4 * 8));
676 o = (java_objectheader *) *((ptrint *) (sp + 3 * 8));
677 mcode = *((u8 *) (sp + 2 * 8));
678 cr = (constant_classref *) *((ptrint *) (sp + 1 * 8));
680 /* calculate and set the new return address */
683 *((ptrint *) (sp + 4 * 8)) = (ptrint) ra;
685 PATCHER_MONITORENTER;
687 /* get the fieldinfo */
689 if (!(c = resolve_classref_eager(cr))) {
695 /* patch back original code */
697 *((u8 *) ra) = mcode;
699 /* if we show disassembly, we have to skip the nop's */
701 if (opt_showdisassemble)
704 /* patch class flags */
706 *((s4 *) (ra + 2)) = (s4) c->flags;
708 PATCHER_MARK_PATCHED_MONITOREXIT;
714 /* patcher_checkcast_instanceof_interface **************************************
718 <patched call position>
719 45 8b 9a 1c 00 00 00 mov 0x1c(%r10),%r11d
720 49 81 eb 00 00 00 00 sub $0x0,%r11
721 4d 85 db test %r11,%r11
722 0f 8e 94 04 00 00 jle 0x00002aaaaab018f8
723 4d 8b 9a 00 00 00 00 mov 0x0(%r10),%r11
725 *******************************************************************************/
727 bool patcher_checkcast_instanceof_interface(u1 *sp)
730 java_objectheader *o;
732 constant_classref *cr;
735 /* get stuff from the stack */
737 ra = (u1 *) *((ptrint *) (sp + 4 * 8));
738 o = (java_objectheader *) *((ptrint *) (sp + 3 * 8));
739 mcode = *((u8 *) (sp + 2 * 8));
740 cr = (constant_classref *) *((ptrint *) (sp + 1 * 8));
742 /* calculate and set the new return address */
745 *((ptrint *) (sp + 4 * 8)) = (ptrint) ra;
747 PATCHER_MONITORENTER;
749 /* get the fieldinfo */
751 if (!(c = resolve_classref_eager(cr))) {
757 /* patch back original code */
759 *((u8 *) ra) = mcode;
761 /* if we show disassembly, we have to skip the nop's */
763 if (opt_showdisassemble)
766 /* patch super class index */
768 *((s4 *) (ra + 7 + 3)) = (s4) c->index;
770 *((s4 *) (ra + 7 + 7 + 3 + 6 + 3)) =
771 (s4) (OFFSET(vftbl_t, interfacetable[0]) -
772 c->index * sizeof(methodptr*));
774 PATCHER_MARK_PATCHED_MONITOREXIT;
780 /* patcher_checkcast_class *****************************************************
784 <patched call position>
785 49 bb 00 00 00 00 00 00 00 00 mov $0x0,%r11
786 45 8b 92 20 00 00 00 mov 0x20(%r10),%r10d
787 45 8b 9b 20 00 00 00 mov 0x20(%r11),%r11d
788 4d 29 da sub %r11,%r10
789 49 bb 00 00 00 00 00 00 00 00 mov $0x0,%r11
791 *******************************************************************************/
793 bool patcher_checkcast_class(u1 *sp)
796 java_objectheader *o;
798 constant_classref *cr;
801 /* get stuff from the stack */
803 ra = (u1 *) *((ptrint *) (sp + 4 * 8));
804 o = (java_objectheader *) *((ptrint *) (sp + 3 * 8));
805 mcode = *((u8 *) (sp + 2 * 8));
806 cr = (constant_classref *) *((ptrint *) (sp + 1 * 8));
808 /* calculate and set the new return address */
811 *((ptrint *) (sp + 4 * 8)) = (ptrint) ra;
813 PATCHER_MONITORENTER;
815 /* get the fieldinfo */
817 if (!(c = resolve_classref_eager(cr))) {
823 /* patch back original code */
825 *((u8 *) ra) = mcode;
827 /* if we show disassembly, we have to skip the nop's */
829 if (opt_showdisassemble)
832 /* patch super class' vftbl */
834 *((ptrint *) (ra + 2)) = (ptrint) c->vftbl;
835 *((ptrint *) (ra + 10 + 7 + 7 + 3 + 2)) = (ptrint) c->vftbl;
837 PATCHER_MARK_PATCHED_MONITOREXIT;
843 /* patcher_instanceof_class ****************************************************
847 <patched call position>
848 49 ba 00 00 00 00 00 00 00 00 mov $0x0,%r10
850 *******************************************************************************/
852 bool patcher_instanceof_class(u1 *sp)
855 java_objectheader *o;
857 constant_classref *cr;
860 /* get stuff from the stack */
862 ra = (u1 *) *((ptrint *) (sp + 4 * 8));
863 o = (java_objectheader *) *((ptrint *) (sp + 3 * 8));
864 mcode = *((u8 *) (sp + 2 * 8));
865 cr = (constant_classref *) *((ptrint *) (sp + 1 * 8));
867 /* calculate and set the new return address */
870 *((ptrint *) (sp + 4 * 8)) = (ptrint) ra;
872 PATCHER_MONITORENTER;
874 /* get the fieldinfo */
876 if (!(c = resolve_classref_eager(cr))) {
882 /* patch back original code */
884 *((u8 *) ra) = mcode;
886 /* if we show disassembly, we have to skip the nop's */
888 if (opt_showdisassemble)
891 /* patch super class' vftbl */
893 *((ptrint *) (ra + 2)) = (ptrint) c->vftbl;
895 PATCHER_MARK_PATCHED_MONITOREXIT;
901 /* patcher_clinit **************************************************************
903 May be used for GET/PUTSTATIC and in native stub.
907 <patched call position>
908 4d 8b 15 92 ff ff ff mov -110(%rip),%r10
909 49 89 1a mov %rbx,(%r10)
911 *******************************************************************************/
913 bool patcher_clinit(u1 *sp)
916 java_objectheader *o;
920 /* get stuff from the stack */
922 ra = (u1 *) *((ptrint *) (sp + 4 * 8));
923 o = (java_objectheader *) *((ptrint *) (sp + 3 * 8));
924 mcode = *((u8 *) (sp + 2 * 8));
925 c = (classinfo *) *((ptrint *) (sp + 1 * 8));
927 /* calculate and set the new return address */
930 *((ptrint *) (sp + 4 * 8)) = (ptrint) ra;
932 PATCHER_MONITORENTER;
934 /* check if the class is initialized */
936 if (!(c->state & CLASS_INITIALIZED)) {
937 if (!initialize_class(c)) {
944 /* patch back original code */
946 *((u8 *) ra) = mcode;
948 PATCHER_MARK_PATCHED_MONITOREXIT;
954 /* patcher_athrow_areturn ******************************************************
958 <patched call position>
960 *******************************************************************************/
962 #ifdef ENABLE_VERIFIER
963 bool patcher_athrow_areturn(u1 *sp)
966 java_objectheader *o;
968 unresolved_class *uc;
971 /* get stuff from the stack */
973 ra = (u1 *) *((ptrint *) (sp + 4 * 8));
974 o = (java_objectheader *) *((ptrint *) (sp + 3 * 8));
975 mcode = *((u8 *) (sp + 2 * 8));
976 uc = (unresolved_class *) *((ptrint *) (sp + 1 * 8));
978 /* calculate and set the new return address */
981 *((ptrint *) (sp + 4 * 8)) = (ptrint) ra;
983 PATCHER_MONITORENTER;
985 /* resolve the class */
987 if (!resolve_class(uc, resolveEager, false, &c)) {
993 /* patch back original code */
995 *((u8 *) ra) = mcode;
997 PATCHER_MARK_PATCHED_MONITOREXIT;
1001 #endif /* ENABLE_VERIFIER */
1004 /* patcher_resolve_native ******************************************************
1008 <patched call position>
1009 48 b8 00 00 00 00 00 00 00 00 mov $0x0,%rax
1010 48 ff d0 callq *%rax
1012 *******************************************************************************/
1014 #if !defined(ENABLE_STATICVM)
1015 bool patcher_resolve_native(u1 *sp)
1018 java_objectheader *o;
1023 /* get stuff from the stack */
1025 ra = (u1 *) *((ptrint *) (sp + 4 * 8));
1026 o = (java_objectheader *) *((ptrint *) (sp + 3 * 8));
1027 mcode = *((u8 *) (sp + 2 * 8));
1028 m = (methodinfo *) *((ptrint *) (sp + 1 * 8));
1030 /* calculate and set the new return address */
1033 *((ptrint *) (sp + 4 * 8)) = (ptrint) ra;
1035 PATCHER_MONITORENTER;
1037 /* resolve native function */
1039 if (!(f = native_resolve_function(m))) {
1040 PATCHER_MONITOREXIT;
1045 /* patch back original code */
1047 *((u8 *) ra) = mcode;
1049 /* if we show disassembly, we have to skip the nop's */
1051 if (opt_showdisassemble)
1054 /* patch native function pointer */
1056 *((ptrint *) (ra + 2)) = (ptrint) f;
1058 PATCHER_MARK_PATCHED_MONITOREXIT;
1062 #endif /* !defined(ENABLE_STATICVM) */
1066 * These are local overrides for various environment variables in Emacs.
1067 * Please do not remove this and leave it at the end of the file, where
1068 * Emacs will automagically detect them.
1069 * ---------------------------------------------------------------------
1072 * indent-tabs-mode: t
1076 * vim:noexpandtab:sw=4:ts=4: