// PASS: COPY GRAPH // // Interface: // // #define ML(x) x##id e.g. _1 // #define ENTRY_LABEL copy_next_node * // #define ENTRY_LABEL_NODEP copy_next_node_in_nodeP * // #define EXIT_LABEL copy_done // #include "gts_copy.c" // #undef EXIT_LABEL // #ifdef UNFIXED_STACK # define PUSHL2 _pushl_gc # define RESERVE_STACK_BLOCK _reserve_stack_block_gc # define COPY_STACK_BLOCK _copy_stack_block_gc #else # define PUSHL2 _pushl_no_gc # define RESERVE_STACK_BLOCK _reserve_stack_block_no_gc # define COPY_STACK_BLOCK _copy_stack_block_no_gc #endif /* // pre-conditions: // - t1 contains to the encoded descP e.g. movl (stringP),t1 // - stringP points to the encoded descriptor // - t1 is not an indirection // // post condition: // - (stringP) is changed // - stringP is advanced with 4 // // identical code in: // adjust_offset_per_block */ .macro ML(_adapt_encoded_graph) t12 #define stringP source #define t0 descP // %ebx #define t2 nodeP // %eax pushl t2 movl t0,tijdelijk movl \t12,t2 andl $0x00ffffff,\t12 movl stackTop,t0 subl \t12,t0 // t0 = stackTop - offset movl 4(t0),\t12 // t12 = virtual base offset cmpl $0,\t12 jnz 9f // \virtual_base_offset_already_computed // The virtual base offset should already have been computed but it isn't if control // reaches this point. How come? int3 popl %eax movl tijdelijk,%ebx movl virtual_base_offset,\t12 // compute virtual base offset movl \t12,4(t0) // determine bitset size movl (t0),t2 // MAKE OFFSET DESCRIPTOR TABLE .. subl $1,free js undo_handler // gap between the string table and the intermediate data structure movl t2,(heapP) leal 4(heapP),heapP // .. MAKE OFFSET DESCRIPTOR TABLE andl $0xff000000,t2 shrl $24,t2 addl $n_bits,t2 movzbl (t2),t2 // t2 = #bitset leal (\t12,t2,4),t2 movl t2,virtual_base_offset // advance virtual base offset with #bitset * 4 movl (stringP),t2 9: // virtual base offset has already been computed andl $0xff000000,t2 shrl $29,t2 // t2 = prefix kind of encoded node addl $n_possible_prefixes_before_prefix,t2 movzbl (t2),t2 // t2 = set of prefixes which *can* occur before the desired prefix movl (t0),t0 andl $0xff000000,t0 shrl $24,t0 // t0 = set of needed prefixes andl t2,t0 // t0 = set of needed prefixes which *occur* before the desired prefix addl $n_bits,t0 movzbl (t0),t0 // t0 = #needed prefixes which *occur* before the desired prefix leal (\t12,t0,4),t0 // t0 = virtual_base_offset + (#needed prefixes * 4) andl $0x00ffffff,t0 movl (stringP),\t12 andl $0xff000000,\t12 // get prefix kind and arity orl t0,\t12 movl \t12,(stringP) // update encoded graph with just computed virtual offset for the prefix kind popl t2 #undef t0 #undef t2 /* // precondition: stringP always points at a descP in the encoded graph // // Adapt the lower 24 bits to hold the virtual offset in the descriptor address table. The descriptor address // table is generated by the linker at run-time. The order is important. Only the first four bytes of the // intermediate structure are stored. // */ leal 4(stringP),stringP // descriptor has been modified to point to the proper prefix // .. ADAPT ENCODED GRAPH .endm #define temp arity ML(_adapt_encoded_graph) temp #undef temp popl descP // mutally exclusive options #include "gts_shared_macros.c" // Code: testl $2,descP // test if in hnf (bit#1)? je ML(copy_closure) // no, copy closure // node in hnf movzwl -2(descP),arity // get arity (%cx) of descriptor testl arity,arity jne ML(copy_argument_pointers) // if not zero, the copy argument pointer cmpl $INT+2,descP je ML(copy_integer) cmpl $CHAR+2,descP je ML(copy_integer) cmpl $BOOL+2,descP je ML(copy_integer) cmpl $REAL+2,descP je ML(copy_real) cmpl $__STRING__+2,descP je ML(copy_string) cmpl $__ARRAY__+2,descP je ML(copy_array) jmp ENTRY_LABEL #define temp %ebx ML(copy_argument_pointers): cmpl $1,arity je ML(push_first_argument_pointer) cmpl $2,arity je ML(push_second_and_first) cmpl $256,arity jae ML(copy_record) // 2 < arity < 256 // (nodeP) descP // 4(nodeP) ptr to first arg // 8(nodeP) ptr to arg block pushl stringP // backup stringP movl 8(nodeP),source decl arity COPY_STACK_BLOCK temp popl stringP // restore stringP jmp ML(push_first_argument_pointer) #undef temp #define temp %ebx ML(push_second_and_first): movl 8(nodeP),temp PUSHL2 temp #undef temp ML(push_first_argument_pointer): movl 4(nodeP),nodeP jmp ENTRY_LABEL_NODEP // INT // (nodeP) descP to INT // 4(nodeP) integer value #define temp %ecx ML(copy_integer): leal 4(stringP),stringP jmp ENTRY_LABEL #undef temp // REAL // (nodeP) descP to REAL // 4(nodeP) least significant part of real // 8(nodeP) most significant part of real // encoding processor specific #define temp %ecx ML(copy_real): leal 8(stringP),stringP jmp ENTRY_LABEL #undef temp // CLOSURE // -8(descP) descP // -4(descP) arity of closure // descP text ptr to code #define temp %ebx ML(copy_closure): movl -4(descP),arity cmpl $0,arity jl ML(copy_closure1) je ENTRY_LABEL cmpl $256,arity // arity >= 256 jae ML(copy_unboxed_closure) cmpl $ CLEAN_nbuild_lazy_block,descP je ML(build_lazy_block) cmpl $ CLEAN_nbuild_block,descP jne ML(continue2) ML(build_lazy_block): addl $8,stringP #ifdef SHARING_ACROSS_CONVERSIONS movl BUILD_DYNAMIC_GDID__PTR(nodeP),nodeP testl $2,(nodeP) jnz ML(no_closure) movl 4(nodeP),nodeP // argument of closure is GlobalDynamicInfo ML(no_closure): movl 8(nodeP),nodeP movl GDI_GRAPH_POINTERS(nodeP),nodeP jmp ENTRY_LABEL_NODEP #endif jmp ENTRY_LABEL ML(continue2): pushl stringP // backup stringP leal 4(nodeP),source COPY_STACK_BLOCK temp popl stringP // restore stringP jmp ENTRY_LABEL ML(copy_closure1): movl 4(nodeP),nodeP jmp ENTRY_LABEL_NODEP # undef temp // UNBOXED CLOSURE // (descP) high byte, number of unboxed args // low_bytes, number of args // arity < 2: // 4(nodeP) 1st arg // 8(nodeP) 2nd arg if any // // arity > 2: // 4(nodeP) 1st arg // 8(nodeP) ptr to arg block // // Boxed args block if any precede unboxed args block #define nrUnboxed nodeP #define nrUnboxedL %al #define nrPointers arity #define nrPointersH %ch #define temp %ebx ML(copy_unboxed_closure): pushl stringP // backup stringP leal 4(nodeP),source // set source xorl nrUnboxed,nrUnboxed movb nrPointersH,nrUnboxedL andl $255,arity sub nrUnboxed,arity // arity = # boxed arguments COPY_STACK_BLOCK temp popl stringP // restore stringP leal (stringP,nrUnboxed,4),stringP // increase it with number of unboxed arguments jmp ENTRY_LABEL #undef nrUnboxed #undef nrUnboxedL #undef nrPointers #undef nrPointersH #undef temp // RECORD // -2(descP) arity // (descP) # boxed args (ptrs) ML(copy_record): // temporary register assignments #define nrPointers descP movzwl (descP),nrPointers // nrPointers (boxed arguments) subl $256,arity // arity -= 256 (real arity) cmpl $0,arity je ENTRY_LABEL // arity == 0 cmpl $1,arity je ML(record_with_one_cell) // arity == 1 cmpl $2,arity je ML(record_with_two_cells) // arity == 2 #define nrUnboxed arity subl nrPointers,nrUnboxed pushl nrPointers // arity contains total arity cmpl $0,nrPointers // nrPointers == 0 je ML(only_unboxed_args) decl nrPointers // 4(nodeP) is a boxed jmp ML(copy_args) // argument ML(only_unboxed_args): decl nrUnboxed // only unboxed, decrement // count ML(copy_args): xchgl nrPointers,nrUnboxed // %ecx = nrPointers cmpl $0,%ecx je ML(copy_first_arg) pushl source // backup stringP movl 8(nodeP),source // set source #define temp descP pushl temp COPY_STACK_BLOCK temp popl temp #undef temp popl source // restore stringP ML(copy_first_arg): leal (stringP,%ebx,4),stringP popl nrPointers jmp ML(record_with_one_cell) #undef nrUnboxed // RECORD with two elements ML(record_with_two_cells): cmpl $1,nrPointers ja ML(second_is_pointer) // nrPointers > 1 leal 4(stringP),stringP jmp ML(record_with_one_cell) // two boxed args ML(second_is_pointer): #define temp arity movl 8(nodeP),temp PUSHL2 temp #undef temp ML(record_with_one_cell): cmpl $0,nrPointers jne ML(first_arg_is_pointer) // one unboxed arg leal 4(stringP),stringP jmp ENTRY_LABEL ML(first_arg_is_pointer): movl 4(nodeP),nodeP jmp ENTRY_LABEL_NODEP #undef nrPointers // STRING // (nodeP) descP to STRING // 4(nodeP) length // 8(nodeP) string #define temp %ebx #define length arity ML(copy_string): movl 4(nodeP),length addl $7,length // length = 4 + 4(nodeP) + 3 shrl $2,length // length in longs leal (stringP,length,4),stringP jmp ENTRY_LABEL // ARRAY // (nodeP) descP to ARRAY // 4(nodeP) size // 8(nodeP) 0, boxed array // otherwise, element descP // 12(nodeP) element block ML(copy_array): movl 8(nodeP),descP // get element descP #define t1 arity cmpl $0,descP je ML(share_prefixes_in_array2) leal 4(stringP),stringP // advance stringP movl (stringP),t1 ML(_adapt_encoded_graph) t1 #undef t1 movl 8(nodeP),descP // restore element descP jmp ML(copy_array2) ML(share_prefixes_in_array2): leal 8(stringP),stringP // advance stringP #define size arity ML(copy_array2): movl 4(nodeP),size cmpl $0,size je ENTRY_LABEL // array size == 0 cmpl $0,descP je ML(copy_array_pointers) // copy boxed array elements cmpl $INT+2,descP je ML(copy_int_array) // copy unboxed array of integers/chars cmpl $BOOL+2,descP je ML(copy_bool_array) // copy unboxed array of booleans cmpl $CHAR+2,descP je ML(copy_bool_array) cmpl $REAL+2,descP je ML(copy_real_array) // copy unboxed array of reals jmp ML(copy_record_array) // copy array with records elements #define temp %ebx ML(copy_array_pointers): pushl stringP leal 12(nodeP),source COPY_STACK_BLOCK temp popl stringP jmp ENTRY_LABEL #undef temp ML(copy_int_array): leal (stringP,size,4),stringP jmp ENTRY_LABEL ML(copy_bool_array): addl $3,size // size = size + 3 shrl $2,size // size /= 4 (in longs) leal (stringP,size,4),stringP jmp ENTRY_LABEL ML(copy_real_array): leal (stringP,size,8),stringP jmp ENTRY_LABEL // RECORD ARRAY // (nodeP) descP to ARRAY // 4(nodeP) size // 8(nodeP) record element descP // 12(nodeP) record elements block // // -2(descP) #longs which is the recordsize // (descP) #a-fields in record (word,0) // // Purpose: // Copies an array containing records with at least one unboxed field. Other // records are handled by copy_record. If the record element type are unboxed // the copy_unboxed_record_array is called. .data .align 4 ML(t_stackP): .long 0 ML(unboxed_fields_size): .long 0 // copy indirection ML(old_heapP): .long 0 .text ML(copy_record_array): pushl stringP // backup stringP // compute boxed size part of the array and reserve stack memory movl stackP,ML(t_stackP) // backup stackP #define temp nodeP #define t_nodeP arity #define temp2 source // was: %esi movl nodeP,t_nodeP movzwl (descP),temp // #boxed fields per records cmpl $0,temp // any boxed arguments? je ML(copy_unboxed_record_array) // ok, copy only boxed mull 4(t_nodeP) // temp = size of boxed part of array (in longs) xchg nodeP,arity movl ML(t_stackP),stackP // restore stackP pushl stringP nop RESERVE_STACK_BLOCK temp2 popl stringP #undef temp #undef t_nodeP #undef temp2 // Copy the boxed part of the record array to stack leal 12(nodeP),source // set source pushl free #define nrPointers free movzwl (descP),nrPointers // boxed size of record #define s_unboxed_arguments descP movzwl -2(descP),s_unboxed_arguments // total record size subl $256,s_unboxed_arguments subl nrPointers,s_unboxed_arguments // s_unboxed_arguments = size of unboxed fields shll $2,s_unboxed_arguments // s_unboxed_arguments *= 4 (in bytes) #define count nodeP movl 4(nodeP),count // get array size pushl heapP movl stackP,heapP // set destination to stack start pushl count ML(share_prefixes_in_record_array2): movl nrPointers,arity // set arity to # boxed fields cld rep movsl addl s_unboxed_arguments,source decl count jne ML(share_prefixes_in_record_array2) popl count popl heapP popl free // %ebx = unboxed record size (s_unboxed_arguments) // %eax = #array elements (count) pushl %edx mull %ebx popl %edx popl stringP leal (stringP,%eax),stringP jmp ENTRY_LABEL //share_next_prefix #undef nrPointers #undef s_unboxed_arguments #undef count ML(copy_unboxed_record_array): popl stringP #define temp %edx pushl temp movl 4(arity),temp #define s_unboxed_arguments nodeP movzwl -2(descP),s_unboxed_arguments // total record size subl $256,s_unboxed_arguments shll $2,s_unboxed_arguments // s_unboxed_arguments *= 4 (in bytes) mull temp popl temp leal (stringP,%eax),stringP jmp ENTRY_LABEL #undef s_unboxed_arguments #undef temp #ifndef GTS_COPY_DEFINE_ONLY_ONCE # define GTS_COPY_DEFINE_ONLY_ONCE .data .align 4 // order r t c k d n // To compute the proper offset from the virtual base offset, it is necessary // to known what prefixes preceded the desired prefix e.g. suppose the offset // for k-prefix is desired, n_possible_prefixes_before_prefix: .byte 32+16+8+4+2 // n-prefix; 00|111110 .byte 32+16+8+4 // d-prefix; 00|111100 .byte 32+16+8 // k_prefix; 00|111000 .byte 32+16 // c_prefix; 00|110000 .byte 32 // t_prefix; 00|100000 .byte 0 // r_prefix; 00|000000 n_references_to_entry_nodes: .long 0 // kan weg #endif .text .align 4 #undef ML #undef ENTRY_LABEL #undef ENTRY_LABEL_NODEP #undef COPY_STACK_BLOCK #undef RESERVE_STACK_BLOCK #undef PUSHL2 #ifdef UNFIXED_STACK # undef UNFIXED_STACK #endif