[t][TT#1507] Add tests for VTABLE_init_int with a key constant
[parrot.git] / src / packout.c
blob196f10685cef4ae38096a8197cbb635a6d358d30
1 /*
2 Copyright (C) 2001-2009, 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 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]);
167 return size;
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()>
183 =cut
187 PARROT_EXPORT
188 PARROT_WARN_UNUSED_RESULT
189 PARROT_CANNOT_RETURN_NULL
190 opcode_t *
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;
196 opcode_t i;
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);
203 return cursor;
208 =item C<int PackFile_find_in_const(PARROT_INTERP, const PackFile_ConstTable *ct,
209 PMC *key, int type)>
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.
214 =cut
218 PARROT_EXPORT
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)
224 int i;
225 FLOATVAL key_num;
226 STRING *key_str;
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)
233 return i;
234 if (type == PFC_NUMBER && ct->constants[i]->u.number == key_num)
235 return i;
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
245 *cursor)>
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.)
258 =cut
262 PARROT_EXPORT
263 PARROT_CANNOT_RETURN_NULL
264 PARROT_WARN_UNUSED_RESULT
265 opcode_t *
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)
271 PMC *key;
272 size_t i;
273 STRING *image;
275 *cursor++ = self->type;
277 switch (self->type) {
279 case PFC_NUMBER:
280 cursor = PF_store_number(cursor, &self->u.number);
281 break;
283 case PFC_STRING:
284 cursor = PF_store_string(cursor, self->u.string);
285 break;
287 case PFC_PMC:
288 key = self->u.key; /* the (Sub) PMC */
289 image = Parrot_freeze(interp, key);
290 cursor = PF_store_string(cursor, image);
291 break;
293 case PFC_KEY:
294 for (i = 0, key = self->u.key; key; i++){
295 GETATTR_Key_next_key(interp, key, key);
298 /* number of key components */
299 *cursor++ = i;
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++);
308 break;
309 case KEY_number_FLAG:
310 *cursor++ = PARROT_ARG_NC;
311 /* Argh */
312 *cursor++ = PackFile_find_in_const(interp, const_table, key, PFC_NUMBER);
313 break;
314 case KEY_string_FLAG:
315 *cursor++ = PARROT_ARG_SC;
316 /* Argh */
317 *cursor++ = PackFile_find_in_const(interp, const_table, key, PFC_STRING);
318 break;
320 case KEY_integer_FLAG | KEY_register_FLAG:
321 *cursor++ = PARROT_ARG_I;
322 GETATTR_Key_int_key(interp, key, *cursor++);
323 break;
324 case KEY_number_FLAG | KEY_register_FLAG:
325 *cursor++ = PARROT_ARG_N;
326 GETATTR_Key_int_key(interp, key, *cursor++);
327 break;
328 case KEY_string_FLAG | KEY_register_FLAG:
329 *cursor++ = PARROT_ARG_S;
330 GETATTR_Key_int_key(interp, key, *cursor++);
331 break;
332 case KEY_pmc_FLAG | KEY_register_FLAG:
333 *cursor++ = PARROT_ARG_P;
334 GETATTR_Key_int_key(interp, key, *cursor++);
335 break;
336 default:
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);
344 break;
346 default:
347 Parrot_io_eprintf(NULL, "PackFile_Constant_pack: unsupported constant\n");
348 Parrot_exit(interp, 1);
349 break;
351 return cursor;
356 =back
358 =head1 HISTORY
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.
365 =cut
371 * Local variables:
372 * c-file-style: "parrot"
373 * End:
374 * vim: expandtab shiftwidth=4: