2 Copyright (C) 2001-2009, Parrot Foundation.
3 This program is free software. It is subject to the same license as
9 src/packout.c - Functions for writing out packfiles
13 This file implements various functions for creating and writing packfiles.
23 #include "parrot/parrot.h"
24 #include "parrot/packfile.h"
25 #include "pmc/pmc_key.h"
27 /* HEADERIZER HFILE: include/parrot/packfile.h */
31 =item C<opcode_t PackFile_pack_size(PARROT_INTERP, PackFile *self)>
33 Determine the size of the buffer needed in order to pack the PackFile
34 into a contiguous region of memory.
36 Must be run before C<PackFile_pack()>, so it will allocate an adequate
45 PackFile_pack_size(PARROT_INTERP
, ARGMOD(PackFile
*self
))
47 ASSERT_ARGS(PackFile_pack_size
)
49 size_t header_size
= 0;
50 PackFile_Directory
* const dir
= &self
->directory
;
52 header_size
= PACKFILE_HEADER_BYTES
;
53 header_size
+= self
->header
->uuid_size
;
56 ? 16 - header_size
% 16
59 size
= header_size
/ sizeof (opcode_t
);
61 size
+= 4; /* directory type + 3 padding zeros */
63 dir
->base
.file_offset
= size
;
64 size
+= PackFile_Segment_packed_size(interp
, (PackFile_Segment
*) dir
);
71 =item C<void PackFile_pack(PARROT_INTERP, PackFile *self, opcode_t *cursor)>
73 Pack the PackFile into a contiguous region of memory.
75 Note that the memory block had better have at least the amount of memory
76 indicated by C<PackFile_pack_size()>.
78 This means that you MUST call C<PackFile_pack_size()> before
81 Other pack routines are in F<src/packfile.c>.
89 PackFile_pack(PARROT_INTERP
, ARGMOD(PackFile
*self
), ARGOUT(opcode_t
*cursor
))
91 ASSERT_ARGS(PackFile_pack
)
95 PackFile_Directory
* const dir
= &self
->directory
;
96 PackFile_Segment
*seg
;
98 char *byte_cursor
= (char*)cursor
;
102 /* Pack the fixed part of the header */
103 mem_sys_memcopy(cursor
, self
->header
, PACKFILE_HEADER_BYTES
);
104 byte_cursor
+= PACKFILE_HEADER_BYTES
;
107 if (self
->header
->uuid_size
> 0)
108 mem_sys_memcopy(byte_cursor
, self
->header
->uuid_data
,
109 self
->header
->uuid_size
);
112 padding_size
= 16 - (PACKFILE_HEADER_BYTES
+ self
->header
->uuid_size
) % 16;
113 if (padding_size
< 16) {
115 for (i
= 0; i
< padding_size
; i
++)
123 cursor
+= (PACKFILE_HEADER_BYTES
+ self
->header
->uuid_size
+ padding_size
)
126 /* Directory format and padding. */
127 *cursor
++ = PF_DIR_FORMAT
;
132 /* pack the directory */
133 seg
= (PackFile_Segment
*) dir
;
136 size
= seg
->op_count
;
137 ret
= PackFile_Segment_pack(interp
, seg
, cursor
);
138 if ((size_t)(ret
- cursor
) != size
) {
139 Parrot_io_eprintf(interp
, "PackFile_pack segment '%Ss' used size %d "
140 "but reported %d\n", seg
->name
, (int)(ret
-cursor
), (int)size
);
146 =item C<size_t PackFile_ConstTable_pack_size(PARROT_INTERP, PackFile_Segment
149 Determine the size of the buffer needed in order to pack the PackFile
150 constant table into a contiguous region of memory.
158 PackFile_ConstTable_pack_size(PARROT_INTERP
, ARGIN(PackFile_Segment
*seg
))
160 ASSERT_ARGS(PackFile_ConstTable_pack_size
)
162 const PackFile_ConstTable
* const self
= (const PackFile_ConstTable
*) seg
;
163 size_t size
= 1; /* const_count */
165 for (i
= 0; i
< self
->const_count
; i
++)
166 size
+= PackFile_Constant_pack_size(interp
, self
->constants
[i
]);
172 =item C<opcode_t * PackFile_ConstTable_pack(PARROT_INTERP, PackFile_Segment
173 *seg, opcode_t *cursor)>
175 Pack the PackFile ConstTable into a contiguous region of memory.
177 Note that the memory block had better have at least the amount of memory
178 indicated by C<PackFile_pack_size()>.
180 This means that you MUST call C<PackFile_pack_size()> before
181 C<PackFile_ConstTable_pack()>
188 PARROT_WARN_UNUSED_RESULT
189 PARROT_CANNOT_RETURN_NULL
191 PackFile_ConstTable_pack(PARROT_INTERP
,
192 ARGIN(PackFile_Segment
*seg
), ARGMOD(opcode_t
*cursor
))
194 ASSERT_ARGS(PackFile_ConstTable_pack
)
195 const PackFile_ConstTable
* const self
= (const PackFile_ConstTable
*)seg
;
198 *cursor
++ = self
->const_count
;
200 for (i
= 0; i
< self
->const_count
; i
++)
201 cursor
= PackFile_Constant_pack(interp
, self
, self
->constants
[i
], cursor
);
208 =item C<int PackFile_find_in_const(PARROT_INTERP, const PackFile_ConstTable *ct,
211 This is really ugly, we don't know where our C<PARROT_ARG_SC> key
212 constant is in constant table, so we have to search for it.
220 PackFile_find_in_const(PARROT_INTERP
,
221 ARGIN(const PackFile_ConstTable
*ct
), ARGIN(PMC
*key
), int type
)
223 ASSERT_ARGS(PackFile_find_in_const
)
228 GETATTR_Key_str_key(interp
, key
, key_str
);
229 GETATTR_Key_num_key(interp
, key
, key_num
);
231 for (i
= 0; i
< ct
->const_count
; i
++) {
232 if (type
== PFC_STRING
&& ct
->constants
[i
]->u
.string
== key_str
)
234 if (type
== PFC_NUMBER
&& ct
->constants
[i
]->u
.number
== key_num
)
237 Parrot_io_eprintf(NULL
, "find_in_const: couldn't find const for key\n");
238 Parrot_exit(interp
, 1);
243 =item C<opcode_t * PackFile_Constant_pack(PARROT_INTERP, const
244 PackFile_ConstTable *const_table, const PackFile_Constant *self, opcode_t
247 Pack a PackFile Constant into a contiguous region of memory.
249 Note that the memory block had better have at least the amount of memory
250 indicated by C<PackFile_pack_size()>.
252 This means that you MUST call C<PackFile_pack_size()> before
253 C<PackFile_Constant_pack()>
255 The data is zero-padded to an opcode_t-boundary, so pad bytes may be added.
256 (Note this padding is not yet implemented for FLOATVALs.)
263 PARROT_CANNOT_RETURN_NULL
264 PARROT_WARN_UNUSED_RESULT
266 PackFile_Constant_pack(PARROT_INTERP
,
267 ARGIN(const PackFile_ConstTable
*const_table
),
268 ARGIN(const PackFile_Constant
*self
), ARGOUT(opcode_t
*cursor
))
270 ASSERT_ARGS(PackFile_Constant_pack
)
275 *cursor
++ = self
->type
;
277 switch (self
->type
) {
280 cursor
= PF_store_number(cursor
, &self
->u
.number
);
284 cursor
= PF_store_string(cursor
, self
->u
.string
);
288 key
= self
->u
.key
; /* the (Sub) PMC */
289 image
= Parrot_freeze(interp
, key
);
290 cursor
= PF_store_string(cursor
, image
);
294 for (i
= 0, key
= self
->u
.key
; key
; i
++){
295 GETATTR_Key_next_key(interp
, key
, key
);
298 /* number of key components */
300 /* and now type / value per component */
301 for (key
= self
->u
.key
; key
;) {
302 const opcode_t type
= PObj_get_FLAGS(key
);
304 switch (type
& KEY_type_FLAGS
) {
305 case KEY_integer_FLAG
:
306 *cursor
++ = PARROT_ARG_IC
;
307 GETATTR_Key_int_key(interp
, key
, *cursor
++);
309 case KEY_number_FLAG
:
310 *cursor
++ = PARROT_ARG_NC
;
312 *cursor
++ = PackFile_find_in_const(interp
, const_table
, key
, PFC_NUMBER
);
314 case KEY_string_FLAG
:
315 *cursor
++ = PARROT_ARG_SC
;
317 *cursor
++ = PackFile_find_in_const(interp
, const_table
, key
, PFC_STRING
);
320 case KEY_integer_FLAG
| KEY_register_FLAG
:
321 *cursor
++ = PARROT_ARG_I
;
322 GETATTR_Key_int_key(interp
, key
, *cursor
++);
324 case KEY_number_FLAG
| KEY_register_FLAG
:
325 *cursor
++ = PARROT_ARG_N
;
326 GETATTR_Key_int_key(interp
, key
, *cursor
++);
328 case KEY_string_FLAG
| KEY_register_FLAG
:
329 *cursor
++ = PARROT_ARG_S
;
330 GETATTR_Key_int_key(interp
, key
, *cursor
++);
332 case KEY_pmc_FLAG
| KEY_register_FLAG
:
333 *cursor
++ = PARROT_ARG_P
;
334 GETATTR_Key_int_key(interp
, key
, *cursor
++);
337 Parrot_io_eprintf(NULL
, "PackFile_Constant_pack: "
338 "unsupported constant type\n");
339 Parrot_exit(interp
, 1);
341 GETATTR_Key_next_key(interp
, key
, key
);
347 Parrot_io_eprintf(NULL
, "PackFile_Constant_pack: unsupported constant\n");
348 Parrot_exit(interp
, 1);
360 Rework by Melvin; new bytecode format, make bytecode portable. (Do
361 endian conversion and wordsize transforms on the fly.)
363 leo: rewrite to use new directory-based format.
372 * c-file-style: "parrot"
374 * vim: expandtab shiftwidth=4: