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
&& ct
->string_hash
) {
277 HashBucket
*bucket
= parrot_hash_get_bucket(interp
, ct
->string_hash
,
280 i
= (int)PTR2INTVAL(bucket
->value
);
281 if (i
< ct
->const_count
) /* only consider constants that have already occured */
287 for (i
= 0; i
< ct
->const_count
; ++i
) {
288 PackFile_Constant
*constant
= &ct
->constants
[i
];
292 if (constant
->type
== PFC_STRING
) {
293 STRING
* const sc
= constant
->u
.string
;
294 if (Parrot_str_equal(interp
, key_str
, sc
)
295 && key_str
->encoding
== sc
->encoding
) {
302 if (constant
->type
== PFC_NUMBER
)
303 if (constant
->u
.number
== key_num
)
308 PANIC(interp
, "Universe imploded. Did you divide by zero?");
318 =item C<opcode_t * PackFile_Constant_pack(PARROT_INTERP, const
319 PackFile_ConstTable *const_table, const PackFile_Constant *self, opcode_t
322 Pack a PackFile Constant into a contiguous region of memory.
324 Note that the memory block had better have at least the amount of memory
325 indicated by C<PackFile_pack_size()>.
327 This means that you MUST call C<PackFile_pack_size()> before
328 C<PackFile_Constant_pack()>
330 The data is zero-padded to an opcode_t-boundary, so pad bytes may be added.
331 (Note this padding is not yet implemented for FLOATVALs.)
338 PARROT_CANNOT_RETURN_NULL
339 PARROT_WARN_UNUSED_RESULT
341 PackFile_Constant_pack(PARROT_INTERP
,
342 ARGIN(const PackFile_ConstTable
*const_table
),
343 ARGIN(const PackFile_Constant
*self
), ARGOUT(opcode_t
*cursor
))
345 ASSERT_ARGS(PackFile_Constant_pack
)
349 *cursor
++ = self
->type
;
351 switch (self
->type
) {
354 cursor
= PF_store_number(cursor
, &self
->u
.number
);
358 cursor
= PF_store_string(cursor
, self
->u
.string
);
362 cursor
= Parrot_freeze_pbc(interp
, self
->u
.key
, const_table
, cursor
);
366 for (i
= 0, key
= self
->u
.key
; key
; ++i
){
367 GETATTR_Key_next_key(interp
, key
, key
);
370 /* number of key components */
372 /* and now type / value per component */
373 for (key
= self
->u
.key
; key
;) {
374 const opcode_t type
= PObj_get_FLAGS(key
);
376 switch (type
& KEY_type_FLAGS
) {
377 case KEY_integer_FLAG
:
378 *cursor
++ = PARROT_ARG_IC
;
379 GETATTR_Key_int_key(interp
, key
, *cursor
++);
381 case KEY_number_FLAG
:
382 *cursor
++ = PARROT_ARG_NC
;
384 *cursor
++ = PackFile_find_in_const(interp
, const_table
, key
, PFC_NUMBER
);
386 case KEY_string_FLAG
:
387 *cursor
++ = PARROT_ARG_SC
;
389 *cursor
++ = PackFile_find_in_const(interp
, const_table
, key
, PFC_STRING
);
392 case KEY_integer_FLAG
| KEY_register_FLAG
:
393 *cursor
++ = PARROT_ARG_I
;
394 GETATTR_Key_int_key(interp
, key
, *cursor
++);
396 case KEY_number_FLAG
| KEY_register_FLAG
:
397 *cursor
++ = PARROT_ARG_N
;
398 GETATTR_Key_int_key(interp
, key
, *cursor
++);
400 case KEY_string_FLAG
| KEY_register_FLAG
:
401 *cursor
++ = PARROT_ARG_S
;
402 GETATTR_Key_int_key(interp
, key
, *cursor
++);
404 case KEY_pmc_FLAG
| KEY_register_FLAG
:
405 *cursor
++ = PARROT_ARG_P
;
406 GETATTR_Key_int_key(interp
, key
, *cursor
++);
409 Parrot_io_eprintf(NULL
, "PackFile_Constant_pack: "
410 "unsupported constant type\n");
411 Parrot_exit(interp
, 1);
413 GETATTR_Key_next_key(interp
, key
, key
);
419 Parrot_io_eprintf(NULL
, "PackFile_Constant_pack: unsupported constant\n");
420 Parrot_exit(interp
, 1);
432 Rework by Melvin; new bytecode format, make bytecode portable. (Do
433 endian conversion and wordsize transforms on the fly.)
435 leo: rewrite to use new directory-based format.
444 * c-file-style: "parrot"
446 * vim: expandtab shiftwidth=4: