fix codetest failure - ASSERT_ARGS does not have a ; after and
[parrot.git] / src / packout.c
blob64d3020c8059c1be00cf231c417fbf2473c37a1d
1 /*
2 Copyright (C) 2001-2010, Parrot Foundation.
3 This program is free software. It is subject to the same license as
4 Parrot itself.
5 $Id$
7 =head1 NAME
9 src/packout.c - Functions for writing out packfiles
11 =head1 DESCRIPTION
13 This file implements various functions for creating and writing packfiles.
15 =head2 Functions
17 =over 4
19 =cut
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
37 buffer.
39 =cut
43 PARROT_EXPORT
44 opcode_t
45 PackFile_pack_size(PARROT_INTERP, ARGMOD(PackFile *self))
47 ASSERT_ARGS(PackFile_pack_size)
48 size_t 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;
54 header_size +=
55 header_size % 16
56 ? 16 - header_size % 16
57 : 0;
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);
66 return size;
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
79 C<PackFile_pack()>
81 Other pack routines are in F<src/packfile.c>.
83 =cut
87 PARROT_EXPORT
88 void
89 PackFile_pack(PARROT_INTERP, ARGMOD(PackFile *self), ARGOUT(opcode_t *cursor))
91 ASSERT_ARGS(PackFile_pack)
92 opcode_t *ret;
94 size_t size;
95 PackFile_Directory * const dir = &self->directory;
96 PackFile_Segment *seg;
97 int padding_size;
98 char *byte_cursor = (char*)cursor;
100 self->src = 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;
106 /* Pack the UUID. */
107 if (self->header->uuid_size > 0)
108 mem_sys_memcopy(byte_cursor, self->header->uuid_data,
109 self->header->uuid_size);
111 /* Padding. */
112 padding_size = 16 - (PACKFILE_HEADER_BYTES + self->header->uuid_size) % 16;
113 if (padding_size < 16) {
114 int i;
115 for (i = 0; i < padding_size; ++i)
116 *byte_cursor++ = 0;
118 else {
119 padding_size = 0;
122 /* Set cursor. */
123 cursor += (PACKFILE_HEADER_BYTES + self->header->uuid_size + padding_size)
124 / sizeof (opcode_t);
126 /* Directory format and padding. */
127 *cursor++ = PF_DIR_FORMAT;
128 *cursor++ = 0;
129 *cursor++ = 0;
130 *cursor++ = 0;
132 /* pack the directory */
133 seg = (PackFile_Segment *) dir;
135 /* dir size */
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
147 *seg)>
149 Determine the size of the buffer needed in order to pack the PackFile
150 constant table into a contiguous region of memory.
152 =cut
156 PARROT_EXPORT
157 size_t
158 PackFile_ConstTable_pack_size(PARROT_INTERP, ARGIN(PackFile_Segment *seg))
160 ASSERT_ARGS(PackFile_ConstTable_pack_size)
161 opcode_t i;
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;
174 return size;
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()>
190 =cut
194 PARROT_EXPORT
195 PARROT_WARN_UNUSED_RESULT
196 PARROT_CANNOT_RETURN_NULL
197 opcode_t *
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;
204 opcode_t i;
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;
216 return cursor;
221 =item C<int PackFile_find_in_const(PARROT_INTERP, const PackFile_ConstTable *ct,
222 PMC *key, int type)>
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.
227 =cut
231 PARROT_EXPORT
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);
239 if (i < 0) {
240 Parrot_io_eprintf(NULL, "find_in_const: couldn't find const for key\n");
241 Parrot_exit(interp, 1);
244 return i;
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
256 =cut
260 PARROT_EXPORT
262 PackFile_ConstTable_rlookup(PARROT_INTERP,
263 ARGIN(const PackFile_ConstTable *ct), ARGIN(PMC *key), int type)
265 ASSERT_ARGS(PackFile_ConstTable_rlookup)
266 int i, strings;
267 FLOATVAL key_num;
268 STRING *key_str;
269 PMC *string_list;
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,
278 key_str);
279 if (bucket) {
280 i = (int)PTR2INTVAL(bucket->value);
281 if (i < ct->const_count) /* only consider constants that have already occured */
282 return i;
284 return -1;
287 for (i = 0; i < ct->const_count; ++i) {
288 PackFile_Constant *constant = &ct->constants[i];
290 switch (type) {
291 case PFC_STRING:
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) {
296 return i;
299 break;
301 case PFC_NUMBER:
302 if (constant->type == PFC_NUMBER)
303 if (constant->u.number == key_num)
304 return i;
305 break;
307 default:
308 PANIC(interp, "Universe imploded. Did you divide by zero?");
312 /* not found */
313 return -1;
318 =item C<opcode_t * PackFile_Constant_pack(PARROT_INTERP, const
319 PackFile_ConstTable *const_table, const PackFile_Constant *self, opcode_t
320 *cursor)>
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.)
333 =cut
337 PARROT_EXPORT
338 PARROT_CANNOT_RETURN_NULL
339 PARROT_WARN_UNUSED_RESULT
340 opcode_t *
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)
346 PMC *key;
347 size_t i;
349 *cursor++ = self->type;
351 switch (self->type) {
353 case PFC_NUMBER:
354 cursor = PF_store_number(cursor, &self->u.number);
355 break;
357 case PFC_STRING:
358 cursor = PF_store_string(cursor, self->u.string);
359 break;
361 case PFC_PMC:
362 cursor = Parrot_freeze_pbc(interp, self->u.key, const_table, cursor);
363 break;
365 case PFC_KEY:
366 for (i = 0, key = self->u.key; key; ++i){
367 GETATTR_Key_next_key(interp, key, key);
370 /* number of key components */
371 *cursor++ = i;
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++);
380 break;
381 case KEY_number_FLAG:
382 *cursor++ = PARROT_ARG_NC;
383 /* Argh */
384 *cursor++ = PackFile_find_in_const(interp, const_table, key, PFC_NUMBER);
385 break;
386 case KEY_string_FLAG:
387 *cursor++ = PARROT_ARG_SC;
388 /* Argh */
389 *cursor++ = PackFile_find_in_const(interp, const_table, key, PFC_STRING);
390 break;
392 case KEY_integer_FLAG | KEY_register_FLAG:
393 *cursor++ = PARROT_ARG_I;
394 GETATTR_Key_int_key(interp, key, *cursor++);
395 break;
396 case KEY_number_FLAG | KEY_register_FLAG:
397 *cursor++ = PARROT_ARG_N;
398 GETATTR_Key_int_key(interp, key, *cursor++);
399 break;
400 case KEY_string_FLAG | KEY_register_FLAG:
401 *cursor++ = PARROT_ARG_S;
402 GETATTR_Key_int_key(interp, key, *cursor++);
403 break;
404 case KEY_pmc_FLAG | KEY_register_FLAG:
405 *cursor++ = PARROT_ARG_P;
406 GETATTR_Key_int_key(interp, key, *cursor++);
407 break;
408 default:
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);
416 break;
418 default:
419 Parrot_io_eprintf(NULL, "PackFile_Constant_pack: unsupported constant\n");
420 Parrot_exit(interp, 1);
421 break;
423 return cursor;
428 =back
430 =head1 HISTORY
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.
437 =cut
443 * Local variables:
444 * c-file-style: "parrot"
445 * End:
446 * vim: expandtab shiftwidth=4: