2 Copyright (C) 2001-2010, 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 PackFile_ConstTable
* const self
= (PackFile_ConstTable
*) seg
;
163 const opcode_t n_constants
= self
->const_count
;
164 size_t size
= 1; /* const_count */
166 for (i
= 0; i
< n_constants
; ++i
) {
167 /* only constants up to the current one will be valid on unpack */
168 self
->const_count
= i
;
169 size
+= PackFile_Constant_pack_size(interp
, self
->constants
[i
], self
);
172 self
->const_count
= i
;
179 =item C<opcode_t * PackFile_ConstTable_pack(PARROT_INTERP, PackFile_Segment
180 *seg, opcode_t *cursor)>
182 Pack the PackFile ConstTable into a contiguous region of memory.
184 Note that the memory block had better have at least the amount of memory
185 indicated by C<PackFile_pack_size()>.
187 This means that you MUST call C<PackFile_pack_size()> before
188 C<PackFile_ConstTable_pack()>
195 PARROT_WARN_UNUSED_RESULT
196 PARROT_CANNOT_RETURN_NULL
198 PackFile_ConstTable_pack(PARROT_INTERP
,
199 ARGIN(PackFile_Segment
*seg
), ARGMOD(opcode_t
*cursor
))
201 ASSERT_ARGS(PackFile_ConstTable_pack
)
202 PackFile_ConstTable
* const self
= (PackFile_ConstTable
*)seg
;
203 const opcode_t n_constants
= self
->const_count
;
206 *cursor
++ = self
->const_count
;
208 for (i
= 0; i
< n_constants
; ++i
) {
209 /* only constants up to the current one will be valid on unpack */
210 self
->const_count
= i
;
211 cursor
= PackFile_Constant_pack(interp
, self
, self
->constants
[i
], cursor
);
214 self
->const_count
= n_constants
;
221 =item C<int PackFile_find_in_const(PARROT_INTERP, const PackFile_ConstTable *ct,
224 This is really ugly, we don't know where our C<PARROT_ARG_SC> key
225 constant is in constant table, so we have to search for it.
233 PackFile_find_in_const(PARROT_INTERP
,
234 ARGIN(const PackFile_ConstTable
*ct
), ARGIN(PMC
*key
), int type
)
236 ASSERT_ARGS(PackFile_find_in_const
)
237 int i
= PackFile_ConstTable_rlookup(interp
, ct
, key
, type
);
240 Parrot_io_eprintf(NULL
, "find_in_const: couldn't find const for key\n");
241 Parrot_exit(interp
, 1);
249 =item C<int PackFile_ConstTable_rlookup(PARROT_INTERP, const PackFile_ConstTable
250 *ct, PMC *key, int type)>
252 Reverse lookup a constant in the constant table.
254 TODO: use a hash to make these O(1) for strings
262 PackFile_ConstTable_rlookup(PARROT_INTERP
,
263 ARGIN(const PackFile_ConstTable
*ct
), ARGIN(PMC
*key
), int type
)
265 ASSERT_ARGS(PackFile_ConstTable_rlookup
)
271 PARROT_ASSERT(type
== PFC_STRING
|| type
== PFC_NUMBER
);
273 GETATTR_Key_str_key(interp
, key
, key_str
);
274 GETATTR_Key_num_key(interp
, key
, key_num
);
276 if (type
== PFC_STRING
&& !PMC_IS_NULL(ct
->string_hash
)) {
277 if (VTABLE_exists_keyed_str(interp
, ct
->string_hash
, key_str
)) {
278 i
= VTABLE_get_integer_keyed_str(interp
, ct
->string_hash
, key_str
);
279 if (i
< ct
->const_count
) /* only consider constants that have already occured */
285 for (i
= 0; i
< ct
->const_count
; ++i
) {
286 PackFile_Constant
*constant
= ct
->constants
[i
];
290 if (constant
->type
== PFC_STRING
) {
291 STRING
* const sc
= constant
->u
.string
;
292 if (Parrot_str_equal(interp
, key_str
, sc
)
293 && Parrot_charset_number_of_str(interp
, key_str
)
294 == Parrot_charset_number_of_str(interp
, sc
)
295 && Parrot_encoding_number_of_str(interp
, key_str
)
296 == Parrot_encoding_number_of_str(interp
, sc
)) {
303 if (constant
->type
== PFC_NUMBER
)
304 if (constant
->u
.number
== key_num
)
309 PANIC(interp
, "Universe imploded. Did you divide by zero?");
319 =item C<opcode_t * PackFile_Constant_pack(PARROT_INTERP, const
320 PackFile_ConstTable *const_table, const PackFile_Constant *self, opcode_t
323 Pack a PackFile Constant into a contiguous region of memory.
325 Note that the memory block had better have at least the amount of memory
326 indicated by C<PackFile_pack_size()>.
328 This means that you MUST call C<PackFile_pack_size()> before
329 C<PackFile_Constant_pack()>
331 The data is zero-padded to an opcode_t-boundary, so pad bytes may be added.
332 (Note this padding is not yet implemented for FLOATVALs.)
339 PARROT_CANNOT_RETURN_NULL
340 PARROT_WARN_UNUSED_RESULT
342 PackFile_Constant_pack(PARROT_INTERP
,
343 ARGIN(const PackFile_ConstTable
*const_table
),
344 ARGIN(const PackFile_Constant
*self
), ARGOUT(opcode_t
*cursor
))
346 ASSERT_ARGS(PackFile_Constant_pack
)
351 *cursor
++ = self
->type
;
353 switch (self
->type
) {
356 cursor
= PF_store_number(cursor
, &self
->u
.number
);
360 cursor
= PF_store_string(cursor
, self
->u
.string
);
364 key
= self
->u
.key
; /* the (Sub) PMC */
365 image
= Parrot_freeze_pbc(interp
, key
, const_table
);
366 cursor
= PF_store_string(cursor
, image
);
370 for (i
= 0, key
= self
->u
.key
; key
; ++i
){
371 GETATTR_Key_next_key(interp
, key
, key
);
374 /* number of key components */
376 /* and now type / value per component */
377 for (key
= self
->u
.key
; key
;) {
378 const opcode_t type
= PObj_get_FLAGS(key
);
380 switch (type
& KEY_type_FLAGS
) {
381 case KEY_integer_FLAG
:
382 *cursor
++ = PARROT_ARG_IC
;
383 GETATTR_Key_int_key(interp
, key
, *cursor
++);
385 case KEY_number_FLAG
:
386 *cursor
++ = PARROT_ARG_NC
;
388 *cursor
++ = PackFile_find_in_const(interp
, const_table
, key
, PFC_NUMBER
);
390 case KEY_string_FLAG
:
391 *cursor
++ = PARROT_ARG_SC
;
393 *cursor
++ = PackFile_find_in_const(interp
, const_table
, key
, PFC_STRING
);
396 case KEY_integer_FLAG
| KEY_register_FLAG
:
397 *cursor
++ = PARROT_ARG_I
;
398 GETATTR_Key_int_key(interp
, key
, *cursor
++);
400 case KEY_number_FLAG
| KEY_register_FLAG
:
401 *cursor
++ = PARROT_ARG_N
;
402 GETATTR_Key_int_key(interp
, key
, *cursor
++);
404 case KEY_string_FLAG
| KEY_register_FLAG
:
405 *cursor
++ = PARROT_ARG_S
;
406 GETATTR_Key_int_key(interp
, key
, *cursor
++);
408 case KEY_pmc_FLAG
| KEY_register_FLAG
:
409 *cursor
++ = PARROT_ARG_P
;
410 GETATTR_Key_int_key(interp
, key
, *cursor
++);
413 Parrot_io_eprintf(NULL
, "PackFile_Constant_pack: "
414 "unsupported constant type\n");
415 Parrot_exit(interp
, 1);
417 GETATTR_Key_next_key(interp
, key
, key
);
423 Parrot_io_eprintf(NULL
, "PackFile_Constant_pack: unsupported constant\n");
424 Parrot_exit(interp
, 1);
436 Rework by Melvin; new bytecode format, make bytecode portable. (Do
437 endian conversion and wordsize transforms on the fly.)
439 leo: rewrite to use new directory-based format.
448 * c-file-style: "parrot"
450 * vim: expandtab shiftwidth=4: