1 /*
2 Copyright (C) 2001-2015, Parrot Foundation.
3 
4 =head1 NAME
5 
6 src/packfile/pf_items.c - Fetch/store packfile data
7 
8 =head1 DESCRIPTION
9 
10 Low level packfile functions to fetch and store Parrot data, i.e.
11 C<INTVAL>, C<FLOATVAL>, C<STRING> ...
12 
13 C<< PF_fetch_<item>() >> functions retrieve the datatype item from the
14 opcode stream and convert byteordering or binary format on the fly,
15 depending on the packfile header.
16 
17 C<< PF_store_<item>() >> functions write the datatype item to the stream
18 as is. These functions don't check the available size.
19 
20 C<< PF_size_<item>() >> functions return the store size of item in
21 C<opcode_t> units.
22 
23 C<BE> and C<be> are short for "Big-endian", while C<LE> and C<le> are short
24 for "little endian".
25 
26 =head2 Functions
27 
28 =over 4
29 
30 =cut
31 
32 */
33 
34 #include "parrot/parrot.h"
35 #include "pf_items.str"
36 
37 /* HEADERIZER HFILE: include/parrot/packfile.h */
38 
39 /* HEADERIZER BEGIN: static */
40 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
41 
42 static void cvt_num12_num16(
43     ARGOUT(unsigned char *dest),
44     ARGIN(const unsigned char *src))
45         __attribute__nonnull__(1)
46         __attribute__nonnull__(2)
47         FUNC_MODIFIES(*dest);
48 
49 static void cvt_num12_num16_le(
50     ARGOUT(unsigned char *dest),
51     ARGIN(const unsigned char *src))
52         __attribute__nonnull__(1)
53         __attribute__nonnull__(2)
54         FUNC_MODIFIES(*dest);
55 
56 static void cvt_num12_num8(
57     ARGOUT(unsigned char *dest),
58     ARGIN(const unsigned char *src))
59         __attribute__nonnull__(1)
60         __attribute__nonnull__(2)
61         FUNC_MODIFIES(*dest);
62 
63 static void cvt_num12_num8_le(
64     ARGOUT(unsigned char *dest),
65     ARGIN(const unsigned char *src))
66         __attribute__nonnull__(1)
67         __attribute__nonnull__(2)
68         FUNC_MODIFIES(*dest);
69 
70 static void cvt_num16_num12(
71     ARGOUT(unsigned char *dest),
72     ARGIN(const unsigned char *src))
73         __attribute__nonnull__(1)
74         __attribute__nonnull__(2)
75         FUNC_MODIFIES(*dest);
76 
77 static void cvt_num16_num12_be(
78     ARGOUT(unsigned char *dest),
79     ARGIN(const unsigned char *src))
80         __attribute__nonnull__(1)
81         __attribute__nonnull__(2)
82         FUNC_MODIFIES(*dest);
83 
84 static void cvt_num16_num8(
85     ARGOUT(unsigned char *dest),
86     ARGIN(const unsigned char *src))
87         __attribute__nonnull__(1)
88         __attribute__nonnull__(2)
89         FUNC_MODIFIES(*dest);
90 
91 static void cvt_num16_num8_be(
92     ARGOUT(unsigned char *dest),
93     ARGIN(const unsigned char *src))
94         __attribute__nonnull__(1)
95         __attribute__nonnull__(2)
96         FUNC_MODIFIES(*dest);
97 
98 static void cvt_num16_num8_le(
99     ARGOUT(unsigned char *dest),
100     ARGIN(const unsigned char *src))
101         __attribute__nonnull__(1)
102         __attribute__nonnull__(2)
103         FUNC_MODIFIES(*dest);
104 
105 static void cvt_num8_num12(
106     ARGOUT(unsigned char *dest),
107     ARGIN(const unsigned char *src))
108         __attribute__nonnull__(1)
109         __attribute__nonnull__(2)
110         FUNC_MODIFIES(*dest);
111 
112 static void cvt_num8_num12_be(
113     ARGOUT(unsigned char *dest),
114     ARGIN(const unsigned char *src))
115         __attribute__nonnull__(1)
116         __attribute__nonnull__(2)
117         FUNC_MODIFIES(*dest);
118 
119 static void cvt_num8_num16(
120     ARGOUT(unsigned char *dest),
121     ARGIN(const unsigned char *src))
122         __attribute__nonnull__(1)
123         __attribute__nonnull__(2)
124         FUNC_MODIFIES(*dest);
125 
126 static void cvt_num8_num16_be(
127     ARGOUT(unsigned char *dest),
128     ARGIN(const unsigned char *src))
129         __attribute__nonnull__(1)
130         __attribute__nonnull__(2)
131         FUNC_MODIFIES(*dest);
132 
133 static void cvt_num8_num16_le(
134     ARGOUT(unsigned char *dest),
135     ARGIN(const unsigned char *src))
136         __attribute__nonnull__(1)
137         __attribute__nonnull__(2)
138         FUNC_MODIFIES(*dest);
139 
140 PARROT_INLINE
141 static void fetch_buf_be_12(
142     ARGOUT(unsigned char *rb),
143     ARGIN(const unsigned char *b))
144         __attribute__nonnull__(1)
145         __attribute__nonnull__(2)
146         FUNC_MODIFIES(*rb);
147 
148 PARROT_INLINE
149 static void fetch_buf_be_16(
150     ARGOUT(unsigned char *rb),
151     ARGIN(const unsigned char *b))
152         __attribute__nonnull__(1)
153         __attribute__nonnull__(2)
154         FUNC_MODIFIES(*rb);
155 
156 PARROT_INLINE
157 static void fetch_buf_be_32(
158     ARGOUT(unsigned char *rb),
159     ARGIN(const unsigned char *b))
160         __attribute__nonnull__(1)
161         __attribute__nonnull__(2)
162         FUNC_MODIFIES(*rb);
163 
164 PARROT_INLINE
165 static void fetch_buf_be_4(
166     ARGOUT(unsigned char *rb),
167     ARGIN(const unsigned char *b))
168         __attribute__nonnull__(1)
169         __attribute__nonnull__(2)
170         FUNC_MODIFIES(*rb);
171 
172 PARROT_INLINE
173 static void fetch_buf_be_8(
174     ARGOUT(unsigned char *rb),
175     ARGIN(const unsigned char *b))
176         __attribute__nonnull__(1)
177         __attribute__nonnull__(2)
178         FUNC_MODIFIES(*rb);
179 
180 PARROT_INLINE
181 static void fetch_buf_le_12(
182     ARGOUT(unsigned char *rb),
183     ARGIN(const unsigned char *b))
184         __attribute__nonnull__(1)
185         __attribute__nonnull__(2)
186         FUNC_MODIFIES(*rb);
187 
188 PARROT_INLINE
189 static void fetch_buf_le_16(
190     ARGOUT(unsigned char *rb),
191     ARGIN(const unsigned char *b))
192         __attribute__nonnull__(1)
193         __attribute__nonnull__(2)
194         FUNC_MODIFIES(*rb);
195 
196 PARROT_INLINE
197 static void fetch_buf_le_32(
198     ARGOUT(unsigned char *rb),
199     ARGIN(const unsigned char *b))
200         __attribute__nonnull__(1)
201         __attribute__nonnull__(2)
202         FUNC_MODIFIES(*rb);
203 
204 PARROT_INLINE
205 static void fetch_buf_le_4(
206     ARGOUT(unsigned char *rb),
207     ARGIN(const unsigned char *b))
208         __attribute__nonnull__(1)
209         __attribute__nonnull__(2)
210         FUNC_MODIFIES(*rb);
211 
212 PARROT_INLINE
213 static void fetch_buf_le_8(
214     ARGOUT(unsigned char *rb),
215     ARGIN(const unsigned char *b))
216         __attribute__nonnull__(1)
217         __attribute__nonnull__(2)
218         FUNC_MODIFIES(*rb);
219 
220 PARROT_INLINE
221 PARROT_WARN_UNUSED_RESULT
222 PARROT_CONST_FUNCTION
223 static INTVAL fetch_iv_be(INTVAL w);
224 
225 PARROT_INLINE
226 PARROT_WARN_UNUSED_RESULT
227 PARROT_CONST_FUNCTION
228 static INTVAL fetch_iv_le(INTVAL w);
229 
230 PARROT_INLINE
231 PARROT_WARN_UNUSED_RESULT
232 PARROT_CONST_FUNCTION
233 static opcode_t fetch_op_be(opcode_t w);
234 
235 PARROT_WARN_UNUSED_RESULT
236 static opcode_t fetch_op_be_4(ARGIN(const unsigned char *b))
237         __attribute__nonnull__(1);
238 
239 PARROT_WARN_UNUSED_RESULT
240 static opcode_t fetch_op_be_8(ARGIN(const unsigned char *b))
241         __attribute__nonnull__(1);
242 
243 PARROT_INLINE
244 PARROT_WARN_UNUSED_RESULT
245 PARROT_CONST_FUNCTION
246 static opcode_t fetch_op_le(opcode_t w);
247 
248 PARROT_WARN_UNUSED_RESULT
249 static opcode_t fetch_op_le_4(ARGIN(const unsigned char *b))
250         __attribute__nonnull__(1);
251 
252 PARROT_WARN_UNUSED_RESULT
253 static opcode_t fetch_op_le_8(ARGIN(const unsigned char *b))
254         __attribute__nonnull__(1);
255 
256 #define ASSERT_ARGS_cvt_num12_num16 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
257        PARROT_ASSERT_ARG(dest) \
258     , PARROT_ASSERT_ARG(src))
259 #define ASSERT_ARGS_cvt_num12_num16_le __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
260        PARROT_ASSERT_ARG(dest) \
261     , PARROT_ASSERT_ARG(src))
262 #define ASSERT_ARGS_cvt_num12_num8 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
263        PARROT_ASSERT_ARG(dest) \
264     , PARROT_ASSERT_ARG(src))
265 #define ASSERT_ARGS_cvt_num12_num8_le __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
266        PARROT_ASSERT_ARG(dest) \
267     , PARROT_ASSERT_ARG(src))
268 #define ASSERT_ARGS_cvt_num16_num12 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
269        PARROT_ASSERT_ARG(dest) \
270     , PARROT_ASSERT_ARG(src))
271 #define ASSERT_ARGS_cvt_num16_num12_be __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
272        PARROT_ASSERT_ARG(dest) \
273     , PARROT_ASSERT_ARG(src))
274 #define ASSERT_ARGS_cvt_num16_num8 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
275        PARROT_ASSERT_ARG(dest) \
276     , PARROT_ASSERT_ARG(src))
277 #define ASSERT_ARGS_cvt_num16_num8_be __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
278        PARROT_ASSERT_ARG(dest) \
279     , PARROT_ASSERT_ARG(src))
280 #define ASSERT_ARGS_cvt_num16_num8_le __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
281        PARROT_ASSERT_ARG(dest) \
282     , PARROT_ASSERT_ARG(src))
283 #define ASSERT_ARGS_cvt_num8_num12 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
284        PARROT_ASSERT_ARG(dest) \
285     , PARROT_ASSERT_ARG(src))
286 #define ASSERT_ARGS_cvt_num8_num12_be __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
287        PARROT_ASSERT_ARG(dest) \
288     , PARROT_ASSERT_ARG(src))
289 #define ASSERT_ARGS_cvt_num8_num16 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
290        PARROT_ASSERT_ARG(dest) \
291     , PARROT_ASSERT_ARG(src))
292 #define ASSERT_ARGS_cvt_num8_num16_be __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
293        PARROT_ASSERT_ARG(dest) \
294     , PARROT_ASSERT_ARG(src))
295 #define ASSERT_ARGS_cvt_num8_num16_le __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
296        PARROT_ASSERT_ARG(dest) \
297     , PARROT_ASSERT_ARG(src))
298 #define ASSERT_ARGS_fetch_buf_be_12 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
299        PARROT_ASSERT_ARG(rb) \
300     , PARROT_ASSERT_ARG(b))
301 #define ASSERT_ARGS_fetch_buf_be_16 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
302        PARROT_ASSERT_ARG(rb) \
303     , PARROT_ASSERT_ARG(b))
304 #define ASSERT_ARGS_fetch_buf_be_32 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
305        PARROT_ASSERT_ARG(rb) \
306     , PARROT_ASSERT_ARG(b))
307 #define ASSERT_ARGS_fetch_buf_be_4 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
308        PARROT_ASSERT_ARG(rb) \
309     , PARROT_ASSERT_ARG(b))
310 #define ASSERT_ARGS_fetch_buf_be_8 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
311        PARROT_ASSERT_ARG(rb) \
312     , PARROT_ASSERT_ARG(b))
313 #define ASSERT_ARGS_fetch_buf_le_12 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
314        PARROT_ASSERT_ARG(rb) \
315     , PARROT_ASSERT_ARG(b))
316 #define ASSERT_ARGS_fetch_buf_le_16 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
317        PARROT_ASSERT_ARG(rb) \
318     , PARROT_ASSERT_ARG(b))
319 #define ASSERT_ARGS_fetch_buf_le_32 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
320        PARROT_ASSERT_ARG(rb) \
321     , PARROT_ASSERT_ARG(b))
322 #define ASSERT_ARGS_fetch_buf_le_4 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
323        PARROT_ASSERT_ARG(rb) \
324     , PARROT_ASSERT_ARG(b))
325 #define ASSERT_ARGS_fetch_buf_le_8 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
326        PARROT_ASSERT_ARG(rb) \
327     , PARROT_ASSERT_ARG(b))
328 #define ASSERT_ARGS_fetch_iv_be __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
329 #define ASSERT_ARGS_fetch_iv_le __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
330 #define ASSERT_ARGS_fetch_op_be __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
331 #define ASSERT_ARGS_fetch_op_be_4 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
332        PARROT_ASSERT_ARG(b))
333 #define ASSERT_ARGS_fetch_op_be_8 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
334        PARROT_ASSERT_ARG(b))
335 #define ASSERT_ARGS_fetch_op_le __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
336 #define ASSERT_ARGS_fetch_op_le_4 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
337        PARROT_ASSERT_ARG(b))
338 #define ASSERT_ARGS_fetch_op_le_8 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
339        PARROT_ASSERT_ARG(b))
340 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
341 /* HEADERIZER END: static */
342 
343 /*
344  * round val up to whole size, return result in bytes
345  */
346 #define ROUND_UP_B(val, size) ((((val) + ((size) - 1))/(size)) * (size))
347 
348 /*
349  * round val up to whole opcode_t, return result in opcodes
350  */
351 #define ROUND_UP(val, size) (((val) + ((size) - 1))/(size))
352 
353 /*
354  * offset not in ptr diff, but in byte
355  */
356 #define OFFS(pf, cursor) ((pf) ? ((const char *)(cursor) - (const char *)((pf)->src)) : 0)
357 
358 /*
359  * low level FLOATVAL fetch and convert functions
360  *
361  * Floattype 0 = IEEE-754 8 byte double
362  * Floattype 1 = x86 little endian 12 byte long double
363  * Floattype 2 = IEEE-754 16 byte long double
364  *
365  */
366 
367 /*
368 
369 =item C<static void cvt_num12_num8(unsigned char *dest, const unsigned char
370 *src)>
371 
372 Converts i386 LE 12-byte long double to IEEE 754 8-byte double.
373 
374 Tested ok.
375 
376 =cut
377 
378 */
379 
380 #if (NUMVAL_SIZE == 8)
381 static void
cvt_num12_num8(ARGOUT (unsigned char * dest),ARGIN (const unsigned char * src))382 cvt_num12_num8(ARGOUT(unsigned char *dest), ARGIN(const unsigned char *src))
383 {
384     ASSERT_ARGS(cvt_num12_num8)
385     int expo, i, s;
386 #  ifdef __LCC__
387     int expo2;
388 #  endif
389 
390     /*
391        12-byte double (96 bits):
392        sign  1  bit 95
393        exp  15 bits 94-80
394        man  80 bits 79-0
395     to 8-byte double (64 bits):
396        sign  1  bit 63
397        exp  11 bits 62-52
398        man  52 bits 51-0
399 
400     +-------+-------+-------+-------+-------+-------+--...--+-------+
401     |src[11]|src[10]|src[9] |src[8] |src[7] |src[6] | ...   |src[0] |
402     S|     E        |                    F                          |
403     +-------+-------+-------+-------+-------+-------+--...--+-------+
404     1|<-----15----->|<----------------80 bits---------------------->|
405     <----------------------------96 bits---------------------------->
406 
407     +-------+-------+-------+-------+-------+-------+-------+-------+
408     |dest[7]|dest[6]|dest[5]|dest[4]|dest[3]|dest[2]|dest[1]|dest[0]|
409     S|    E    |                           F                        |
410     +-------+-------+-------+-------+-------+-------+-------+-------+
411     1|<---11-->|<---------------------52 bits---------------------->|
412     <----------------------------64 bits---------------------------->
413                        8-byte DOUBLE FLOATING-POINT
414     */
415 
416     memset(dest, 0, 8);
417     /* exponents 15 -> 11 bits */
418     s = src[9] & 0x80; /* sign */
419     expo = ((src[9] & 0x7f)<< 8 | src[8]);
420     if (expo == 0) {
421 nul:
422         if (s)
423             dest[7] |= 0x80;
424         return;
425     }
426 #  ifdef __LCC__
427     /* Yet again, LCC blows up mysteriously until a temporary variable is
428      * added. */
429     expo2 = expo - 16383;
430     expo  = expo2;
431 #  else
432     expo -= 16383;       /* - bias */
433 #  endif
434     expo += 1023;       /* + bias 8byte */
435     if (expo <= 0)       /* underflow */
436         goto nul;
437     if (expo > 0x7ff) {  /* inf/nan */
438         dest[7] = 0x7f;
439         dest[6] = src[7] == 0xc0 ? 0xf8 : 0xf0 ;
440         goto nul;
441     }
442     expo <<= 4;
443     dest[6] = (expo & 0xff);
444     dest[7] = (expo & 0x7f00) >> 8;
445     if (s)
446         dest[7] |= 0x80;
447     /* long double frac 63 bits => 52 bits
448        src[7] &= 0x7f; reset integer bit */
449     for (i = 0; i < 6; ++i) {
450         dest[i+1] |= (i==5 ? src[7]&0x7f : src[i+2]) >> 3;
451         dest[i] |= (src[i+2] & 0x1f) << 5;
452     }
453     dest[0] |= src[1] >> 3;
454 }
455 #endif
456 
457 /*
458 
459 =item C<static void cvt_num16_num12(unsigned char *dest, const unsigned char
460 *src)>
461 
462 Converts IEEE 754 LE 16-byte long double to i386 LE 12-byte long double.
463 See http://babbage.cs.qc.cuny.edu/IEEE-754/References.xhtml
464 
465 Tested ok.
466 
467 =cut
468 
469 */
470 
471 #if (NUMVAL_SIZE == 12)
472 static void
cvt_num16_num12(ARGOUT (unsigned char * dest),ARGIN (const unsigned char * src))473 cvt_num16_num12(ARGOUT(unsigned char *dest), ARGIN(const unsigned char *src))
474 {
475     ASSERT_ARGS(cvt_num16_num12)
476 
477     /*
478        16-byte double (128 bits):
479        sign  1  bit 127
480        exp  15 bits 126-112
481        man 112 bits 111-0
482     to 12-byte double (96 bits):
483        sign  1  bit 95
484        exp  15 bits 94-80
485        man  80 bits 79-0
486 
487     +-------+-------+-------+-------+-------+-------+--...--+-------+
488     |src[15]|src[14]|src[13]|src[12]|src[11]|src[10]| ...   |src[0] |
489     S|     E        |                    F                          |
490     +-------+-------+-------+-------+-------+-------+--...--+-------+
491     1|<-----15----->|<----------------112 bits--------------------->|
492     <---------------------------128 bits---------------------------->
493             16-byte LONG DOUBLE FLOATING-POINT (IA64 or BE 64-bit)
494 
495     +-------+-------+-------+-------+-------+-------+--...--+-------+
496     |dest[11]dest[10]dest[9]|dest[8]|dest[7]|dest[6]| ...   |dest[0]|
497     S|     E        |                    F                          |
498     +-------+-------+-------+-------+-------+-------+--...--+-------+
499     1|<-----15----->|<----------------80 bits---------------------->|
500     <----------------------------96 bits---------------------------->
501               12-byte LONG DOUBLE FLOATING-POINT (i386 special)
502 
503     */
504 
505     memset(dest, 0, 12);
506     /* simply copy over sign + exp */
507     dest[10] = src[15];
508     dest[11] = src[14];
509     /* and copy the rest */
510     memcpy(&dest[0], &src[0], 10);
511 }
512 #endif
513 
514 /*
515 
516 =item C<static void cvt_num12_num16(unsigned char *dest, const unsigned char
517 *src)>
518 
519 Converts i386 LE 12-byte long double to IEEE 754 LE 16-byte long double.
520 
521 Tested ok.
522 Fallback 12->8->16 disabled.
523 
524 =cut
525 
526 */
527 
528 #if (NUMVAL_SIZE == 16)
529 static void
cvt_num12_num16(ARGOUT (unsigned char * dest),ARGIN (const unsigned char * src))530 cvt_num12_num16(ARGOUT(unsigned char *dest), ARGIN(const unsigned char *src))
531 {
532     ASSERT_ARGS(cvt_num12_num16)
533 #  if 0
534     unsigned char b[8];
535     cvt_num12_num8(b, src);
536     cvt_num8_num16(dest, b);
537 #  endif
538     /*
539        12-byte double (96 bits):
540        sign  1  bit 95
541        exp  15 bits 94-80
542        man  80 bits 79-0
543     to 16-byte double (128 bits):
544        sign  1  bit 127
545        exp  15 bits 126-112
546        man 112 bits 111-0
547 
548     +-------+-------+-------+-------+-------+-------+--...--+-------+
549     |src[11]|src[10]| src[9]| src[8]| src[7]| src[6]| ...   | src[0]|
550     S|     E        |                    F                          |
551     +-------+-------+-------+-------+-------+-------+--...--+-------+
552     1|<-----15----->|<----------------80 bits---------------------->|
553     <----------------------------96 bits---------------------------->
554               12-byte LONG DOUBLE FLOATING-POINT (i386 special)
555 
556     +-------+-------+-------+-------+-------+-------+--...--+-------+
557     |dest[15]dest[14]dest[13]dest[12]dest[11]dest[10] ...   |dest[0]|
558     S|     E        |                    F                          |
559     +-------+-------+-------+-------+-------+-------+--...--+-------+
560     1|<-----15----->|<----------------112 bits--------------------->|
561     <---------------------------128 bits---------------------------->
562             16-byte LONG DOUBLE FLOATING-POINT (x86_64 or BE 64-bit)
563 
564     */
565 
566     memset(dest, 0, 16);
567     /* simply copy over sign + exp */
568     dest[15] = src[11];
569     dest[14] = src[10];
570     /* and copy the rest */
571     memcpy(&dest[0], &src[0], 10);
572 }
573 #endif
574 /*
575 
576 =item C<static void cvt_num16_num8(unsigned char *dest, const unsigned char
577 *src)>
578 
579 Converts IEEE 754 16-byte long double to IEEE 754 8 byte double.
580 
581 First variant ok, 2nd not ok.
582 
583 =cut
584 
585 */
586 
587 #if (NUMVAL_SIZE == 8)
588 static void
cvt_num16_num8(ARGOUT (unsigned char * dest),ARGIN (const unsigned char * src))589 cvt_num16_num8(ARGOUT(unsigned char *dest), ARGIN(const unsigned char *src))
590 {
591     ASSERT_ARGS(cvt_num16_num8)
592 
593     if ((sizeof (long double) == 16) && (sizeof (double) == 8)) {
594 
595         long double ld;
596         double d;
597 
598         memcpy(&ld, src, 16);
599         d = (double)ld; /* compiler cast */
600         memcpy(dest, &d, 8);
601 
602     }
603     else {
604 #  if !PARROT_BIGENDIAN
605         /* assume intel 10-byte padded to 16 byte, not a true __float128 */
606         cvt_num12_num8(dest, src);
607         return;
608 #  endif
609         Parrot_x_force_error_exit(NULL, 1, "cvt_num16_num8: long double conversion unsupported");
610     }
611 }
612 #endif
613 
614 /*
615 
616 =item C<static void cvt_num8_num16(unsigned char *dest, const unsigned char
617 *src)>
618 
619 Converts IEEE 754 8-byte double to IEEE 754 16 byte long double.
620 
621 Tested ok.
622 
623 =cut
624 
625 */
626 
627 #if (NUMVAL_SIZE == 16)
628 static void
cvt_num8_num16(ARGOUT (unsigned char * dest),ARGIN (const unsigned char * src))629 cvt_num8_num16(ARGOUT(unsigned char *dest), ARGIN(const unsigned char *src))
630 {
631     ASSERT_ARGS(cvt_num8_num16)
632     /* The compiler can do this for us */
633     long double ld;
634     double d;
635     memcpy(&d, src, 8);
636     ld = (long double)d; /* TODO: test compiler cast */
637     memcpy(dest, &ld, 16);
638 }
639 #endif
640 
641 /*
642 
643 =item C<static void cvt_num8_num12(unsigned char *dest, const unsigned char
644 *src)>
645 
646 Converts i386 8-byte double to i386 12 byte long double.
647 
648 Tested ok.
649 
650 =cut
651 
652 */
653 
654 #if (NUMVAL_SIZE == 12) && !PARROT_BIGENDIAN
655 static void
cvt_num8_num12(ARGOUT (unsigned char * dest),ARGIN (const unsigned char * src))656 cvt_num8_num12(ARGOUT(unsigned char *dest), ARGIN(const unsigned char *src))
657 {
658     ASSERT_ARGS(cvt_num8_num12)
659     long double ld;
660     double d;
661     memcpy(&d, src, 8);
662     ld = (long double)d; /* compiler cast */
663     memcpy(dest, &ld, 12);
664 }
665 #endif
666 
667 
668 /*
669 
670 =item C<static void cvt_num8_num12_be(unsigned char *dest, const unsigned char
671 *src)>
672 
673 Converts a big-endian IEEE 754 8-byte double to i386 LE 12-byte long double.
674 
675 Tested ok.
676 
677 =cut
678 
679 */
680 
681 #if (NUMVAL_SIZE == 12) && !PARROT_BIGENDIAN
682 static void
cvt_num8_num12_be(ARGOUT (unsigned char * dest),ARGIN (const unsigned char * src))683 cvt_num8_num12_be(ARGOUT(unsigned char *dest), ARGIN(const unsigned char *src))
684 {
685     ASSERT_ARGS(cvt_num8_num12_be)
686     unsigned char b[8];
687     fetch_buf_be_8(b, src);
688     cvt_num8_num12(dest, b);
689 }
690 #endif
691 
692 /*
693 
694 =item C<static void cvt_num8_num16_le(unsigned char *dest, const unsigned char
695 *src)>
696 
697 Converts a little-endian IEEE 754 8-byte double to big-endian 16-byte long double.
698 
699 Yet untested.
700 
701 =cut
702 
703 */
704 
705 #if (NUMVAL_SIZE == 16) && PARROT_BIGENDIAN
706 static void
cvt_num8_num16_le(ARGOUT (unsigned char * dest),ARGIN (const unsigned char * src))707 cvt_num8_num16_le(ARGOUT(unsigned char *dest), ARGIN(const unsigned char *src))
708 {
709     ASSERT_ARGS(cvt_num8_num16_le)
710     unsigned char b[8];
711     fetch_buf_be_8(b, src);  /* TODO test endianize */
712     cvt_num8_num16(dest, b);
713 }
714 #endif
715 
716 /*
717 
718 =item C<static void cvt_num12_num16_le(unsigned char *dest, const unsigned char
719 *src)>
720 
721 Converts a little-endian 12-byte double to big-endian 16-byte long double.
722 
723 Tested nok.
724 
725 =cut
726 
727 */
728 
729 #if (NUMVAL_SIZE == 16) && PARROT_BIGENDIAN
730 static void
cvt_num12_num16_le(ARGOUT (unsigned char * dest),ARGIN (const unsigned char * src))731 cvt_num12_num16_le(ARGOUT(unsigned char *dest), ARGIN(const unsigned char *src))
732 {
733     ASSERT_ARGS(cvt_num12_num16_le)
734     unsigned char b[12];
735     fetch_buf_be_12(b, src);  /* TODO test endianize */
736     cvt_num12_num16(dest, b);
737 }
738 #endif
739 
740 /*
741 
742 =item C<static void cvt_num12_num8_le(unsigned char *dest, const unsigned char
743 *src)>
744 
745 Converts a little-endian 12-byte i386 long double into a big-endian IEEE 754 8-byte double.
746 
747 =cut
748 
749 */
750 
751 #if (NUMVAL_SIZE == 8) && PARROT_BIGENDIAN
752 static void
cvt_num12_num8_le(ARGOUT (unsigned char * dest),ARGIN (const unsigned char * src))753 cvt_num12_num8_le(ARGOUT(unsigned char *dest), ARGIN(const unsigned char *src))
754 {
755     ASSERT_ARGS(cvt_num12_num8_le)
756     unsigned char b[12];
757     fetch_buf_le_12(b, src);  /* TODO test endianize */
758     cvt_num12_num8(dest, b);
759 }
760 #endif
761 
762 /*
763 
764 =item C<static void cvt_num16_num8_le(unsigned char *dest, const unsigned char
765 *src)>
766 
767 Converts a little-endian intel 16-byte long double (i.e. 10-byte)
768 into a big-endian IEEE 754 8-byte double.
769 
770 For a true little-endian __float128, see C<cvt_num16_num8_be()>.
771 
772 =cut
773 
774 */
775 
776 #if (NUMVAL_SIZE == 8) && PARROT_BIGENDIAN
777 static void
cvt_num16_num8_le(ARGOUT (unsigned char * dest),ARGIN (const unsigned char * src))778 cvt_num16_num8_le(ARGOUT(unsigned char *dest), ARGIN(const unsigned char *src))
779 {
780     ASSERT_ARGS(cvt_num16_num8_le)
781     unsigned char b[16];
782     fetch_buf_le_16(b, src);
783     cvt_num16_num8(dest, b);
784 }
785 #endif
786 
787 /*
788 
789 =item C<static void cvt_num16_num8_be(unsigned char *dest, const unsigned char
790 *src)>
791 
792 Converts a big-endian IEEE 754 16-byte __float128 (not a powerpc double-double)
793 into a little-endian IEEE 754 8-byte double.
794 
795 Untested.
796 
797 =cut
798 
799 */
800 
801 #if (NUMVAL_SIZE == 8) && !PARROT_BIGENDIAN
802 static void
cvt_num16_num8_be(ARGOUT (unsigned char * dest),ARGIN (const unsigned char * src))803 cvt_num16_num8_be(ARGOUT(unsigned char *dest), ARGIN(const unsigned char *src))
804 {
805     ASSERT_ARGS(cvt_num16_num8_be)
806     unsigned char b[16];
807     int expo, i, s;
808 #  ifdef __LCC__
809     int expo2;
810 #  endif
811 
812     fetch_buf_be_16(b, src);
813 
814     /*
815        16-byte double (128 bits):
816        sign  1  bit 127
817        exp  15 bits 126-112
818        man 112 bits 111-0
819     to 8-byte double (64 bits):
820        sign  1  bit 63
821        exp  11 bits 62-52
822        man  52 bits 51-0
823 
824     +-------+-------+-------+-------+-------+-------+--...--+-------+
825     |src[15]|src[14]|src[13]|src[12]|src[11]|src[10]| ...   |src[0] |
826     S|     E        |                    F                          |
827     +-------+-------+-------+-------+-------+-------+--...--+-------+
828     1|<-----15----->|<----------------112 bits--------------------->|
829     <---------------------------128 bits---------------------------->
830             16-byte __float128 (BE 64-bit)
831 
832     +-------+-------+-------+-------+-------+-------+-------+-------+
833     |dest[7]|dest[6]|dest[5]|dest[4]|dest[3]|dest[2]|dest[1]|dest[0]|
834     S|    E    |                           F                        |
835     +-------+-------+-------+-------+-------+-------+-------+-------+
836     1|<---11-->|<---------------------52 bits---------------------->|
837     <----------------------------64 bits---------------------------->
838                        8-byte DOUBLE FLOATING-POINT
839 
840    */
841 
842     memset(dest, 0, 8);
843     s = b[15] & 0x80; /* 10000000 */
844     /* 15->11 exponents bits */
845     expo = ((b[15] & 0x7f)<< 8 | b[14]);
846     if (expo == 0) {
847       nul:
848         if (s)
849             dest[7] |= 0x80;
850         return;
851     }
852 #  ifdef __LCC__
853     /* LCC blows up mysteriously until a temporary variable is
854      * added. */
855     expo2 = expo - 16383;
856     expo  = expo2;
857 #  else
858     expo -= 16383;       /* - same bias as with 12-byte */
859 #  endif
860     expo += 1023;       /* + bias 8byte */
861     if (expo <= 0)       /* underflow */
862         goto nul;
863     if (expo > 0x7ff) {  /* inf/nan */
864         dest[7] = 0x7f;
865         dest[6] = b[7] == 0xc0 ? 0xf8 : 0xf0 ;
866         goto nul;
867     }
868     expo <<= 4;
869     dest[6] = (expo & 0xff);
870     dest[7] = (expo & 0x7f00) >> 8;
871     if (s)
872         dest[7] |= 0x80;
873     /* long double frac 112 bits => 52 bits
874        b[13] &= 0x7f; reset integer bit */
875     for (i = 0; i < 6; ++i) {
876         dest[i+1] |= (i==5 ? b[13]&0x7f : b[i+7]) >> 3;
877         dest[i] |= (b[i+7] & 0x1f) << 5;
878     }
879     dest[0] |= b[1] >> 3;
880 }
881 #endif
882 
883 /*
884 
885 =item C<static void cvt_num16_num12_be(unsigned char *dest, const unsigned char
886 *src)>
887 
888 Converts a big-endian IEEE 754 16-byte long double into a 12-byte i386 long double.
889 
890 Untested.
891 
892 =cut
893 
894 */
895 
896 #if (NUMVAL_SIZE == 12) && !PARROT_BIGENDIAN
897 static void
cvt_num16_num12_be(ARGOUT (unsigned char * dest),ARGIN (const unsigned char * src))898 cvt_num16_num12_be(ARGOUT(unsigned char *dest), ARGIN(const unsigned char *src))
899 {
900     ASSERT_ARGS(cvt_num16_num12_be)
901     unsigned char b[16];
902     fetch_buf_be_16(b, src);
903     cvt_num16_num12(dest, b);
904 }
905 #endif
906 
907 /*
908 
909 =item C<static void cvt_num8_num16_be(unsigned char *dest, const unsigned char
910 *src)>
911 
912 Converts a big-endian IEEE 754 8-byte double to little-endian IEEE 754 16 byte
913 long double.
914 
915 Untested.
916 
917 =cut
918 
919 */
920 
921 #if (NUMVAL_SIZE == 16) && !PARROT_BIGENDIAN
922 static void
cvt_num8_num16_be(ARGOUT (unsigned char * dest),ARGIN (const unsigned char * src))923 cvt_num8_num16_be(ARGOUT(unsigned char *dest), ARGIN(const unsigned char *src))
924 {
925     ASSERT_ARGS(cvt_num8_num16_be)
926     unsigned char b[8];
927     fetch_buf_be_8(b, src);
928     cvt_num8_num16(dest, b);
929 }
930 #endif
931 
932 /*
933 
934 =item C<static opcode_t fetch_op_be_4(const unsigned char *b)>
935 
936 Fetches a 4-byte big-endian opcode.
937 
938 =cut
939 
940 */
941 
942 PARROT_WARN_UNUSED_RESULT
943 static opcode_t
fetch_op_be_4(ARGIN (const unsigned char * b))944 fetch_op_be_4(ARGIN(const unsigned char *b))
945 {
946     ASSERT_ARGS(fetch_op_be_4)
947     union {
948         unsigned char buf[4];
949         opcode_t o;
950     } u;
951     fetch_buf_be_4(u.buf, b);
952 #if PARROT_BIGENDIAN
953 #  if OPCODE_T_SIZE == 8
954     return (Parrot_Int4)(u.o >> 32);
955 #  else
956     return u.o;
957 #  endif
958 #else
959 #  if OPCODE_T_SIZE == 8
960     return (Parrot_Int4)(fetch_iv_le(u.o) & 0xffffffff);
961 #  else
962     return (opcode_t) fetch_iv_le(u.o);
963 #  endif
964 #endif
965 }
966 
967 /*
968 
969 =item C<static opcode_t fetch_op_be_8(const unsigned char *b)>
970 
971 Fetches an 8-byte big-endian opcode.
972 
973 =cut
974 
975 */
976 
977 PARROT_WARN_UNUSED_RESULT
978 static opcode_t
fetch_op_be_8(ARGIN (const unsigned char * b))979 fetch_op_be_8(ARGIN(const unsigned char *b))
980 {
981     ASSERT_ARGS(fetch_op_be_8)
982     union {
983         unsigned char buf[8];
984         opcode_t o[2];
985     } u;
986     fetch_buf_be_8(u.buf, b);
987 #if PARROT_BIGENDIAN
988 #  if OPCODE_T_SIZE == 8
989     return u.o[0];
990 #  else
991     return u.o[1];
992 #  endif
993 #else
994     return (opcode_t) fetch_iv_le((INTVAL)u.o[0]);
995 #endif
996 }
997 
998 /*
999 
1000 =item C<static opcode_t fetch_op_le_4(const unsigned char *b)>
1001 
1002 Fetches a 4-byte little-endian opcode
1003 
1004 =cut
1005 
1006 */
1007 
1008 PARROT_WARN_UNUSED_RESULT
1009 static opcode_t
fetch_op_le_4(ARGIN (const unsigned char * b))1010 fetch_op_le_4(ARGIN(const unsigned char *b))
1011 {
1012     ASSERT_ARGS(fetch_op_le_4)
1013     union {
1014         unsigned char buf[4];
1015         opcode_t o;
1016     } u;
1017     fetch_buf_le_4(u.buf, b);
1018 #if PARROT_BIGENDIAN
1019 #  if OPCODE_T_SIZE == 8
1020     return (Parrot_Int4)(u.o >> 32);
1021 #  else
1022     return (opcode_t) fetch_iv_be((INTVAL)u.o);
1023 #  endif
1024 #else
1025 #  if OPCODE_T_SIZE == 8
1026     /* without the cast we would not get a negative int, the vtable indices */
1027     return (Parrot_Int4)(u.o & 0xffffffff);
1028 #  else
1029     return u.o;
1030 #  endif
1031 #endif
1032 }
1033 
1034 /*
1035 
1036 =item C<static opcode_t fetch_op_le_8(const unsigned char *b)>
1037 
1038 Fetches an 8-byte little-endian opcode
1039 
1040 =cut
1041 
1042 */
1043 
1044 PARROT_WARN_UNUSED_RESULT
1045 static opcode_t
fetch_op_le_8(ARGIN (const unsigned char * b))1046 fetch_op_le_8(ARGIN(const unsigned char *b))
1047 {
1048     ASSERT_ARGS(fetch_op_le_8)
1049     union {
1050         unsigned char buf[8];
1051         opcode_t o[2];
1052     } u;
1053     fetch_buf_le_8(u.buf, b);
1054 #if PARROT_BIGENDIAN
1055 #  if OPCODE_T_SIZE == 8
1056     return u.o[0];
1057 #  else
1058     return (opcode_t) fetch_op_be((INTVAL)u.o[1]);
1059 #  endif
1060 #else
1061     return u.o[0];
1062 #endif
1063 }
1064 
1065 /*
1066 
1067 =item C<opcode_t PF_fetch_opcode(const PackFile *pf, const opcode_t **stream)>
1068 
1069 Fetches an C<opcode_t> from the stream, converting byteorder if needed.
1070 
1071 When used for freeze/thaw the C<pf> argument might be NULL.
1072 
1073 =cut
1074 
1075 */
1076 
1077 opcode_t
PF_fetch_opcode(ARGIN_NULLOK (const PackFile * pf),ARGMOD (const opcode_t ** stream))1078 PF_fetch_opcode(ARGIN_NULLOK(const PackFile *pf), ARGMOD(const opcode_t **stream))
1079 {
1080     ASSERT_ARGS(PF_fetch_opcode)
1081     if (!pf || !pf->fetch_op) {
1082         return *(*stream)++;
1083     }
1084     else {
1085         const unsigned char *ucstream = *(const unsigned char **)stream;
1086         opcode_t o  = (pf->fetch_op)(ucstream);
1087         ucstream   += pf->header->wordsize;
1088         /* XXX -Wcast-align Need to check alignment for RISC, or memcpy */
1089         *stream     = (const opcode_t *)ucstream;
1090         return o;
1091     }
1092 }
1093 
1094 /*
1095 
1096 =item C<opcode_t* PF_store_opcode(opcode_t *cursor, opcode_t val)>
1097 
1098 Stores an C<opcode_t> to stream as-is.
1099 
1100 =cut
1101 
1102 */
1103 
1104 PARROT_WARN_UNUSED_RESULT
1105 PARROT_CANNOT_RETURN_NULL
1106 opcode_t*
PF_store_opcode(ARGOUT (opcode_t * cursor),opcode_t val)1107 PF_store_opcode(ARGOUT(opcode_t *cursor), opcode_t val)
1108 {
1109     ASSERT_ARGS(PF_store_opcode)
1110     *cursor++ = val;
1111     return cursor;
1112 }
1113 
1114 /*
1115 
1116 =item C<size_t PF_size_opcode(void)>
1117 
1118 Returns the size of an item in C<opcode_t> units. The size of C<opcode_t>
1119 is 1 I<per definition>.
1120 
1121 =cut
1122 
1123 */
1124 
1125 PARROT_CONST_FUNCTION
1126 PARROT_WARN_UNUSED_RESULT
1127 size_t
PF_size_opcode(void)1128 PF_size_opcode(void)
1129 {
1130     ASSERT_ARGS(PF_size_opcode)
1131     return 1;
1132 }
1133 
1134 /*
1135 
1136 =item C<INTVAL PF_fetch_integer(PackFile *pf, const opcode_t **stream)>
1137 
1138 Fetches an C<INTVAL> from the stream, converting byteorder if needed.
1139 
1140 XXX assumes C<sizeof (INTVAL) == sizeof (opcode_t)> - we don't have
1141 C<INTVAL> size in the PackFile header.  See TT #1047 or RT #56810.
1142 
1143 =cut
1144 
1145 */
1146 
1147 PARROT_WARN_UNUSED_RESULT
1148 INTVAL
PF_fetch_integer(ARGIN (PackFile * pf),ARGIN (const opcode_t ** stream))1149 PF_fetch_integer(ARGIN(PackFile *pf), ARGIN(const opcode_t **stream))
1150 {
1151     ASSERT_ARGS(PF_fetch_integer)
1152     INTVAL i;
1153 
1154     if (!pf->fetch_iv)
1155         return *(*stream)++;
1156     i = (pf->fetch_iv)(*((const unsigned char **)stream));
1157 
1158     /* XXX assume sizeof (opcode_t) == sizeof (INTVAL) on the
1159      * machine producing this PBC.
1160      *
1161      * TODO GH #415 on Sparc 64bit: On pbc wordsize=4 but native ptrsize=8 and
1162      * ptr_alignment=8 the advance by 4 will signal BUS (invalid address alignment)
1163      * in PF_fetch_integer and elsewhere.
1164      */
1165     *((const unsigned char **) (stream)) += pf->header->wordsize;
1166     return i;
1167 }
1168 
1169 
1170 /*
1171 
1172 =item C<opcode_t* PF_store_integer(opcode_t *cursor, INTVAL val)>
1173 
1174 Stores an C<INTVAL> to stream as is.
1175 
1176 =cut
1177 
1178 */
1179 
1180 PARROT_WARN_UNUSED_RESULT
1181 PARROT_CANNOT_RETURN_NULL
1182 opcode_t*
PF_store_integer(ARGOUT (opcode_t * cursor),INTVAL val)1183 PF_store_integer(ARGOUT(opcode_t *cursor), INTVAL val)
1184 {
1185     ASSERT_ARGS(PF_store_integer)
1186     *cursor++ = (opcode_t)val; /* XXX */
1187     return cursor;
1188 }
1189 
1190 /*
1191 
1192 =item C<size_t PF_size_integer(void)>
1193 
1194 Returns stored size of C<INTVAL> in C<opcode_t> units.
1195 
1196 =cut
1197 
1198 */
1199 
1200 PARROT_CONST_FUNCTION
1201 size_t
PF_size_integer(void)1202 PF_size_integer(void)
1203 {
1204     ASSERT_ARGS(PF_size_integer)
1205     return sizeof (INTVAL) / sizeof (opcode_t);
1206 }
1207 
1208 /*
1209 
1210 =item C<FLOATVAL PF_fetch_number(PackFile *pf, const opcode_t **stream)>
1211 
1212 Fetches a C<FLOATVAL> from the stream, converting byteorder if needed.
1213 Then advances the stream pointer by the packfile float size.
1214 
1215 =cut
1216 
1217 */
1218 
1219 PARROT_WARN_UNUSED_RESULT
1220 FLOATVAL
PF_fetch_number(ARGIN_NULLOK (PackFile * pf),ARGIN (const opcode_t ** stream))1221 PF_fetch_number(ARGIN_NULLOK(PackFile *pf), ARGIN(const opcode_t **stream))
1222 {
1223     ASSERT_ARGS(PF_fetch_number)
1224     /* When we have alignment all squared away we don't need
1225      * to use memcpy() for native byteorder.  */
1226     FLOATVAL f;
1227     double d;
1228     if (!pf || !pf->fetch_nv) {
1229         memcpy(&f, (const char *)*stream, sizeof (FLOATVAL));
1230         (*stream) += (sizeof (FLOATVAL) + sizeof (opcode_t) - 1)/
1231             sizeof (opcode_t);
1232         return f;
1233     }
1234     f = (FLOATVAL) 0;
1235     /* 12->8 has a messy cast. */
1236     if (NUMVAL_SIZE == 8 && pf->header->floattype == FLOATTYPE_12) {
1237         (pf->fetch_nv)((unsigned char *)&d, (const unsigned char *) *stream);
1238         f = d;
1239     }
1240     else {
1241         (pf->fetch_nv)((unsigned char *)&f, (const unsigned char *) *stream);
1242     }
1243     if (pf->header->floattype == FLOATTYPE_8) {
1244         *((const unsigned char **) (stream)) += 8;
1245     }
1246     else if (pf->header->floattype == FLOATTYPE_12) {
1247         *((const unsigned char **) (stream)) += 12;
1248     }
1249     else if (pf->header->floattype == FLOATTYPE_16) {
1250         *((const unsigned char **) (stream)) += 16;
1251     }
1252     else if (pf->header->floattype == FLOATTYPE_16MIPS) {
1253         *((const unsigned char **) (stream)) += 16;
1254     }
1255     else if (pf->header->floattype == FLOATTYPE_16AIX) {
1256         *((const unsigned char **) (stream)) += 16;
1257     }
1258     else if (pf->header->floattype == FLOATTYPE_4) {
1259         *((const unsigned char **) (stream)) += 4;
1260     }
1261     return f;
1262 }
1263 
1264 /*
1265 
1266 =item C<opcode_t* PF_store_number(opcode_t *cursor, const FLOATVAL *val)>
1267 
1268 Writes a C<FLOATVAL> to the opcode stream as-is.
1269 
1270 =cut
1271 
1272 */
1273 
1274 PARROT_WARN_UNUSED_RESULT
1275 PARROT_CANNOT_RETURN_NULL
1276 opcode_t*
PF_store_number(ARGOUT (opcode_t * cursor),ARGIN (const FLOATVAL * val))1277 PF_store_number(ARGOUT(opcode_t *cursor), ARGIN(const FLOATVAL *val))
1278 {
1279     ASSERT_ARGS(PF_store_number)
1280     opcode_t padded_size  = (sizeof (FLOATVAL) + sizeof (opcode_t) - 1) /
1281         sizeof (opcode_t);
1282     memcpy(cursor, val, sizeof (FLOATVAL));
1283     cursor += padded_size;
1284     return cursor;
1285 }
1286 
1287 /*
1288 
1289 =item C<size_t PF_size_number(void)>
1290 
1291 Returns stored size of FLOATVAL in C<opcode_t> units.
1292 
1293 =cut
1294 
1295 */
1296 
1297 PARROT_CONST_FUNCTION
1298 size_t
PF_size_number(void)1299 PF_size_number(void)
1300 {
1301     ASSERT_ARGS(PF_size_number)
1302     return ROUND_UP(sizeof (FLOATVAL), sizeof (opcode_t));
1303 }
1304 
1305 /*
1306 
1307 =item C<STRING * PF_fetch_buf(PARROT_INTERP, PackFile *pf, const opcode_t
1308 **cursor)>
1309 
1310 Fetches a buffer (fixed_8 encoded temporary C<STRING>) from bytecode.
1311 
1312 Opcode format is:
1313 
1314     opcode_t size
1315     * data
1316 
1317 When used for freeze/thaw, the C<pf> argument might be C<NULL>.
1318 
1319 The returned buffer points to the underlying packfile. It should be used and
1320 discarded immediately to avoid things changing underneath you.
1321 
1322 =cut
1323 
1324 */
1325 
1326 
1327 PARROT_WARN_UNUSED_RESULT
1328 PARROT_CANNOT_RETURN_NULL
1329 STRING *
PF_fetch_buf(PARROT_INTERP,ARGIN_NULLOK (PackFile * pf),ARGIN (const opcode_t ** cursor))1330 PF_fetch_buf(PARROT_INTERP, ARGIN_NULLOK(PackFile *pf), ARGIN(const opcode_t **cursor))
1331 {
1332     ASSERT_ARGS(PF_fetch_buf)
1333     const int wordsize = pf ? pf->header->wordsize : sizeof (opcode_t);
1334     size_t  size       = PF_fetch_opcode(pf, cursor);
1335     STRING *s          = Parrot_str_new_init(interp, (const char *)*cursor, size,
1336                             Parrot_binary_encoding_ptr,
1337                             PObj_external_FLAG);
1338     *((const unsigned char **)(cursor)) += ROUND_UP_B(size, wordsize);
1339     return s;
1340 }
1341 
1342 
1343 /*
1344 
1345 =item C<opcode_t* PF_store_buf(opcode_t *cursor, const STRING *s)>
1346 
1347 Write a buffer (fixed_8 encoded, binary string) to the opcode stream. These
1348 are encoded more compactly and read more efficiently than normal strings, but
1349 have limitations (see C<PF_fetch_buf>).
1350 
1351 =cut
1352 
1353 */
1354 
1355 PARROT_WARN_UNUSED_RESULT
1356 PARROT_CANNOT_RETURN_NULL
1357 opcode_t*
PF_store_buf(ARGOUT (opcode_t * cursor),ARGIN (const STRING * s))1358 PF_store_buf(ARGOUT(opcode_t *cursor), ARGIN(const STRING *s))
1359 {
1360     ASSERT_ARGS(PF_store_buf)
1361     const int  wordsize = sizeof (opcode_t);
1362 
1363     PARROT_ASSERT(s->encoding == Parrot_binary_encoding_ptr);
1364 
1365     *cursor++ = s->bufused;
1366 
1367     if (s->strstart) {
1368         char *charcursor = (char *) cursor;
1369         memcpy(charcursor, s->strstart, s->bufused);
1370         charcursor += s->bufused;
1371 
1372         /* Pad up to wordsize boundary. */
1373         while ((charcursor - (char *)cursor) % wordsize)
1374             *charcursor++ = 0;
1375 
1376         cursor += (charcursor - (char *)cursor) / wordsize;
1377     }
1378 
1379     return cursor;
1380 }
1381 
1382 
1383 /*
1384 
1385 =item C<size_t PF_size_buf(const STRING *s)>
1386 
1387 Reports the stored size of a buffer in C<opcode_t> units.
1388 
1389 =cut
1390 
1391 */
1392 
1393 PARROT_PURE_FUNCTION
1394 size_t
PF_size_buf(ARGIN (const STRING * s))1395 PF_size_buf(ARGIN(const STRING *s))
1396 {
1397     ASSERT_ARGS(PF_size_buf)
1398     if (STRING_IS_NULL(s))
1399         return 1;
1400     else
1401         return PF_size_strlen(s->bufused) - 1;
1402 }
1403 
1404 
1405 /*
1406 
1407 =item C<STRING * PF_fetch_string(PARROT_INTERP, PackFile *pf, const opcode_t
1408 **cursor)>
1409 
1410 Fetches a C<STRING> from bytecode and return a new C<STRING>.
1411 
1412 Opcode format is:
1413 
1414     opcode_t flags8 | encoding
1415     opcode_t size
1416     * data
1417 
1418 When used for freeze/thaw the C<pf> argument might be NULL.
1419 
1420 =cut
1421 
1422 */
1423 
1424 PARROT_WARN_UNUSED_RESULT
1425 PARROT_CANNOT_RETURN_NULL
1426 STRING *
PF_fetch_string(PARROT_INTERP,ARGIN_NULLOK (PackFile * pf),ARGIN (const opcode_t ** cursor))1427 PF_fetch_string(PARROT_INTERP, ARGIN_NULLOK(PackFile *pf), ARGIN(const opcode_t **cursor))
1428 {
1429     ASSERT_ARGS(PF_fetch_string)
1430     STRING   *s;
1431     UINTVAL   flags;
1432     UINTVAL   encoding_nr;
1433     const STR_VTABLE *encoding;
1434     size_t    size;
1435     const int wordsize          = pf ? pf->header->wordsize : sizeof (opcode_t);
1436     opcode_t  flag_charset_word = PF_fetch_opcode(pf, cursor);
1437 
1438     if (flag_charset_word == -1)
1439         return STRINGNULL;
1440 
1441     /* decode flags, charset and encoding */
1442     flags       = (flag_charset_word & 0x1 ? PObj_constant_FLAG : 0) |
1443                   (flag_charset_word & 0x2 ? PObj_private7_FLAG : 0) ;
1444     encoding_nr = (flag_charset_word >> 8) & 0xFF;
1445 
1446     size = (size_t)PF_fetch_opcode(pf, cursor);
1447 
1448     encoding = Parrot_get_encoding(interp, encoding_nr);
1449     if (!encoding)
1450             Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_UNIMPLEMENTED,
1451                     "Invalid encoding number '%d' specified", encoding_nr);
1452 
1453     if (size || (encoding != CONST_STRING(interp, "")->encoding))
1454         s = Parrot_str_new_init(interp, (const char *)*cursor, size,
1455                 encoding, flags);
1456     else
1457         s = CONST_STRING(interp, "");
1458 
1459     size = ROUND_UP_B(size, wordsize);
1460     *((const unsigned char **) (cursor)) += size;
1461 
1462     return s;
1463 }
1464 
1465 
1466 /*
1467 
1468 =item C<opcode_t* PF_store_string(opcode_t *cursor, const STRING *s)>
1469 
1470 Writes a C<STRING> to the opcode stream.
1471 
1472 =cut
1473 
1474 */
1475 
1476 PARROT_WARN_UNUSED_RESULT
1477 PARROT_CANNOT_RETURN_NULL
1478 opcode_t*
PF_store_string(ARGOUT (opcode_t * cursor),ARGIN (const STRING * s))1479 PF_store_string(ARGOUT(opcode_t *cursor), ARGIN(const STRING *s))
1480 {
1481     ASSERT_ARGS(PF_store_string)
1482     opcode_t padded_size = s->bufused;
1483     char *charcursor;
1484 
1485     if (padded_size % sizeof (opcode_t)) {
1486         padded_size += sizeof (opcode_t) - (padded_size % sizeof (opcode_t));
1487     }
1488 
1489     if (STRING_IS_NULL(s)) {
1490         /* preserve NULL-ness of strings */
1491         *cursor++ = -1;
1492         return cursor;
1493     }
1494 
1495     /*
1496      * TODO as soon as we have dynamically loadable charsets
1497      *      we have to store the charset name, not the number
1498      *
1499      * TODO encoding
1500      *
1501      * see also PF_fetch_string
1502      */
1503 
1504     /* encode charset_nr, encoding_nr and flags into the same word */
1505     *cursor++ = (Parrot_encoding_number_of_str(NULL, s) << 8)         |
1506                 (PObj_get_FLAGS(s) & PObj_constant_FLAG ? 0x1 : 0x0) |
1507                 (PObj_get_FLAGS(s) & PObj_private7_FLAG ? 0x2 : 0x0) ;
1508     *cursor++ = s->bufused;
1509 
1510     /* Switch to char * since rest of string is addressed by
1511      * characters to ensure padding.  */
1512     charcursor = (char *)cursor;
1513 
1514     if (s->strstart) {
1515         memcpy(charcursor, s->strstart, s->bufused);
1516         charcursor += s->bufused;
1517         /* Pad up to sizeof (opcode_t) boundary. */
1518         while ((unsigned long) (charcursor - (char *) cursor) % sizeof (opcode_t)) {
1519             *charcursor++ = 0;
1520         }
1521     }
1522     PARROT_ASSERT(((unsigned long) (charcursor - (char *) cursor) % sizeof (opcode_t)) == 0);
1523     cursor += (charcursor - (char *) cursor) / sizeof (opcode_t);
1524 
1525     return cursor;
1526 }
1527 
1528 /*
1529 
1530 =item C<size_t PF_size_string(const STRING *s)>
1531 
1532 Reports stored size of C<STRING> in C<opcode_t> units.
1533 
1534 =cut
1535 
1536 */
1537 
1538 PARROT_PURE_FUNCTION
1539 size_t
PF_size_string(ARGIN (const STRING * s))1540 PF_size_string(ARGIN(const STRING *s))
1541 {
1542     ASSERT_ARGS(PF_size_string)
1543     /* TODO: don't break encapsulation on strings */
1544     const UINTVAL len = s->bufused;
1545     if (STRING_IS_NULL(s))
1546         return 1;
1547     else
1548         return PF_size_strlen(len);
1549 }
1550 
1551 /*
1552 
1553 =item C<size_t PF_size_strlen(const UINTVAL len)>
1554 
1555 Reports stored size of C<STRING> in C<opcode_t> units given its in-memory byte length.
1556 
1557 =cut
1558 
1559 */
1560 
1561 PARROT_CONST_FUNCTION
1562 PARROT_WARN_UNUSED_RESULT
1563 size_t
PF_size_strlen(const UINTVAL len)1564 PF_size_strlen(const UINTVAL len)
1565 {
1566     ASSERT_ARGS(PF_size_strlen)
1567     opcode_t padded_size = len;
1568 
1569     if (padded_size % sizeof (opcode_t)) {
1570         padded_size += sizeof (opcode_t) - (padded_size % sizeof (opcode_t));
1571     }
1572 
1573     /* Include space for flags, representation, and size fields.  */
1574     return 2 + (size_t)padded_size / sizeof (opcode_t);
1575 }
1576 
1577 /*
1578 
1579 =item C<char * PF_fetch_cstring(PARROT_INTERP, PackFile *pf, const opcode_t
1580 **cursor)>
1581 
1582 Fetches a cstring from bytecode and returns an allocated copy
1583 
1584 =cut
1585 
1586 */
1587 
1588 PARROT_MALLOC
1589 PARROT_CANNOT_RETURN_NULL
1590 char *
PF_fetch_cstring(PARROT_INTERP,ARGIN (PackFile * pf),ARGIN (const opcode_t ** cursor))1591 PF_fetch_cstring(PARROT_INTERP, ARGIN(PackFile *pf), ARGIN(const opcode_t **cursor))
1592 {
1593     ASSERT_ARGS(PF_fetch_cstring)
1594     const size_t str_len = strlen((const char *)(*cursor)) + 1;
1595     char * const p = mem_gc_allocate_n_typed(interp, str_len, char);
1596     const int wordsize = pf->header->wordsize;
1597 
1598     strcpy(p, (const char*) (*cursor));
1599     *((const unsigned char **) (cursor)) += ROUND_UP_B(str_len, wordsize);
1600     return p;
1601 }
1602 
1603 /*
1604 
1605 =item C<opcode_t* PF_store_cstring(opcode_t *cursor, const char *s)>
1606 
1607 Writes a C<NULL>-terminated string to the stream.
1608 
1609 =cut
1610 
1611 */
1612 
1613 PARROT_WARN_UNUSED_RESULT
1614 PARROT_CANNOT_RETURN_NULL
1615 opcode_t*
PF_store_cstring(ARGOUT (opcode_t * cursor),ARGIN (const char * s))1616 PF_store_cstring(ARGOUT(opcode_t *cursor), ARGIN(const char *s))
1617 {
1618     ASSERT_ARGS(PF_store_cstring)
1619     /*
1620      * This is not very efficient for filling padding with zeros.
1621      * But it's more efficient than calculate strlen twice.
1622      */
1623     size_t store_size = PF_size_cstring(s);
1624     memset((char *) cursor, 0, store_size * sizeof (opcode_t));
1625     strcpy((char *) cursor, s);
1626     return cursor + store_size;
1627 }
1628 
1629 /*
1630 
1631 =item C<size_t PF_size_cstring(const char *s)>
1632 
1633 Returns store size of a C-string in C<opcode_t> units.
1634 
1635 =cut
1636 
1637 */
1638 
1639 PARROT_PURE_FUNCTION
1640 size_t
PF_size_cstring(ARGIN (const char * s))1641 PF_size_cstring(ARGIN(const char *s))
1642 {
1643     ASSERT_ARGS(PF_size_cstring)
1644     size_t str_len;
1645 
1646     PARROT_ASSERT(s);
1647     str_len = strlen(s);
1648     return ROUND_UP(str_len + 1, sizeof (opcode_t));
1649 }
1650 
1651 /*
1652 
1653 =item C<void PackFile_assign_transforms(PackFile *pf)>
1654 
1655 Assigns transform functions to the vtable.
1656 
1657 =cut
1658 
1659 */
1660 
1661 void
PackFile_assign_transforms(ARGMOD (PackFile * pf))1662 PackFile_assign_transforms(ARGMOD(PackFile *pf))
1663 {
1664     ASSERT_ARGS(PackFile_assign_transforms)
1665     const int need_endianize = pf->header->byteorder != PARROT_BIGENDIAN;
1666     const int need_wordsize  = pf->header->wordsize  != sizeof (opcode_t);
1667 
1668     pf->need_endianize = need_endianize;
1669     pf->need_wordsize  = need_wordsize;
1670 
1671 #if PARROT_BIGENDIAN
1672     /* this Parrot is on a BIG ENDIAN machine */
1673     if (need_endianize) {
1674         if (pf->header->wordsize == 4)
1675             pf->fetch_op = fetch_op_le_4;
1676         else
1677             pf->fetch_op = fetch_op_le_8;
1678         pf->fetch_iv = pf->fetch_op;
1679 
1680         switch (pf->header->floattype) {
1681 #  if NUMVAL_SIZE == 8
1682           case FLOATTYPE_8:
1683             pf->fetch_nv = fetch_buf_le_8;
1684             break;
1685           case FLOATTYPE_12:
1686             pf->fetch_nv = cvt_num12_num8_le;
1687             break;
1688           case FLOATTYPE_16:
1689             pf->fetch_nv = cvt_num16_num8_le;
1690             break;
1691 #  endif
1692 #  if NUMVAL_SIZE == 16
1693           case FLOATTYPE_8:
1694             pf->fetch_nv = cvt_num8_num16_le;
1695             break;
1696           case FLOATTYPE_12:
1697             pf->fetch_nv = cvt_num12_num16_le;
1698             break;
1699           case FLOATTYPE_16:
1700             pf->fetch_nv = fetch_buf_le_16;
1701             break;
1702 #  endif
1703           default:
1704             Parrot_x_force_error_exit(NULL, 1,
1705               "PackFile_unpack: unsupported float conversion %d to %d, "
1706               "PARROT_BIGENDIAN=%d\n",
1707               NUMVAL_SIZE, pf->header->floattype, PARROT_BIGENDIAN);
1708             break;
1709         }
1710         return;
1711     }
1712     else {  /* no need_endianize */
1713         if (pf->header->wordsize == 4)
1714             pf->fetch_op = fetch_op_be_4;
1715         else
1716             pf->fetch_op = fetch_op_be_8;
1717         pf->fetch_iv = pf->fetch_op;
1718 
1719         switch (pf->header->floattype) {
1720 #  if NUMVAL_SIZE == 8
1721           case FLOATTYPE_8: /* native */
1722             break;
1723           case FLOATTYPE_12:
1724             pf->fetch_nv = cvt_num12_num8;
1725             break;
1726           case FLOATTYPE_16:
1727             pf->fetch_nv = cvt_num16_num8;
1728             break;
1729 #  endif
1730 #  if NUMVAL_SIZE == 16
1731           case FLOATTYPE_8:
1732             pf->fetch_nv = cvt_num8_num16;
1733             break;
1734           case FLOATTYPE_12:
1735             pf->fetch_nv = cvt_num12_num16;
1736             break;
1737           case FLOATTYPE_16: /* native */
1738             break;
1739 #  endif
1740           default:
1741             Parrot_x_force_error_exit(NULL, 1,
1742               "PackFile_unpack: unsupported float conversion %d to %d, "
1743               "PARROT_BIGENDIAN=%d\n",
1744               NUMVAL_SIZE, pf->header->floattype, PARROT_BIGENDIAN);
1745             break;
1746         }
1747         return;
1748     }
1749 
1750 #else  /* ENDIAN */
1751 
1752     /* this Parrot is on a LITTLE ENDIAN machine */
1753     if (need_endianize) {
1754         if (pf->header->wordsize == 4)
1755             pf->fetch_op = fetch_op_be_4;
1756         else
1757             pf->fetch_op = fetch_op_be_8;
1758         pf->fetch_iv = pf->fetch_op;
1759 
1760         switch (pf->header->floattype) {
1761 #  if NUMVAL_SIZE == 8
1762           case FLOATTYPE_8:
1763             pf->fetch_nv = fetch_buf_be_8;
1764             break;
1765           case FLOATTYPE_12:
1766             Parrot_x_force_error_exit(NULL, 1, "PackFile_unpack: invalid floattype 1 big-endian");
1767             break;
1768           case FLOATTYPE_16:
1769             pf->fetch_nv = cvt_num16_num8_be;
1770             break;
1771 #  endif
1772 #  if NUMVAL_SIZE == 12
1773           case FLOATTYPE_8:
1774             pf->fetch_nv = cvt_num8_num12_be;
1775             break;
1776           case FLOATTYPE_12:
1777             Parrot_x_force_error_exit(NULL, 1, "PackFile_unpack: invalid floattype 1 big-endian");
1778             break;
1779           case FLOATTYPE_16:
1780             pf->fetch_nv = cvt_num16_num12_be;
1781             break;
1782 #  endif
1783 #  if NUMVAL_SIZE == 16
1784           case FLOATTYPE_8:
1785             pf->fetch_nv = cvt_num8_num16_be;
1786             break;
1787           case FLOATTYPE_12:
1788             Parrot_x_force_error_exit(NULL, 1, "PackFile_unpack: invalid floattype 1 big-endian");
1789             break;
1790           case FLOATTYPE_16:
1791             pf->fetch_nv = fetch_buf_be_16;
1792             break;
1793 #  endif
1794           default:
1795             Parrot_x_force_error_exit(NULL, 1,
1796               "PackFile_unpack: unsupported float conversion %d to %d, "
1797               "PARROT_BIGENDIAN=%d\n",
1798               NUMVAL_SIZE, pf->header->floattype, PARROT_BIGENDIAN);
1799             break;
1800         }
1801         return;
1802     }
1803     else {
1804         if (pf->header->wordsize == 4)
1805             pf->fetch_op = fetch_op_le_4;
1806         else
1807             pf->fetch_op = fetch_op_le_8;
1808         pf->fetch_iv = pf->fetch_op;
1809 
1810         switch (pf->header->floattype) {
1811 #  if NUMVAL_SIZE == 8
1812           case FLOATTYPE_8: /* native */
1813             break;
1814           case FLOATTYPE_12:
1815             pf->fetch_nv = cvt_num12_num8;
1816             break;
1817           case FLOATTYPE_16:
1818             pf->fetch_nv = cvt_num16_num8;
1819             break;
1820 #  endif
1821 #  if NUMVAL_SIZE == 12
1822           case FLOATTYPE_8:
1823             pf->fetch_nv = cvt_num8_num12;
1824             break;
1825           case FLOATTYPE_12: /* native */
1826             break;
1827           case FLOATTYPE_16:
1828             pf->fetch_nv = cvt_num16_num12;
1829             break;
1830 #  endif
1831 #  if NUMVAL_SIZE == 16
1832           case FLOATTYPE_8:
1833             pf->fetch_nv = cvt_num8_num16;
1834             break;
1835           case FLOATTYPE_12:
1836             pf->fetch_nv = cvt_num12_num16;
1837             break;
1838           case FLOATTYPE_16: /* native */
1839             break;
1840 #  endif
1841           default:
1842             Parrot_x_force_error_exit(NULL, 1,
1843               "PackFile_unpack: unsupported float conversion %d to %d, "
1844               "PARROT_BIGENDIAN=%d\n",
1845               NUMVAL_SIZE, pf->header->floattype, PARROT_BIGENDIAN);
1846             break;
1847         }
1848         return;
1849     }
1850 #endif
1851 }
1852 
1853 
1854 /*
1855 
1856 =item C<static INTVAL fetch_iv_le(INTVAL w)>
1857 
1858 This function converts a 4 or 8 byte C<INTVAL> into little endian
1859 format. If the native format is already little endian, then no
1860 conversion is done.
1861 
1862 =cut
1863 
1864 */
1865 
1866 PARROT_INLINE
1867 PARROT_WARN_UNUSED_RESULT
1868 PARROT_CONST_FUNCTION
1869 static INTVAL
fetch_iv_le(INTVAL w)1870 fetch_iv_le(INTVAL w)
1871 {
1872     ASSERT_ARGS(fetch_iv_le)
1873 #if !PARROT_BIGENDIAN
1874     return w;
1875 #else
1876 #  if INTVAL_SIZE == 4
1877     return (w << 24) | ((w & 0xff00) << 8) | ((w & 0xff0000) >> 8) | (w >> 24);
1878 #  else
1879 #    if INTVAL_SIZE == 8
1880     INTVAL r;
1881 
1882     r = w << 56;
1883     r |= (w & 0xff00) << 40;
1884     r |= (w & 0xff0000) << 24;
1885     r |= (w & 0xff000000) << 8;
1886     r |= (w & 0xff00000000) >> 8;
1887     r |= (w & 0xff0000000000) >> 24;
1888     r |= (w & 0xff000000000000) >> 40;
1889     r |= (w & 0xff00000000000000) >> 56;
1890     return r;
1891 #    else
1892     Parrot_x_force_error_exit(NULL, 1, "Unsupported INTVAL_SIZE=%d\n",
1893                INTVAL_SIZE);
1894 #    endif
1895 #  endif
1896 #endif
1897 }
1898 
1899 /*
1900 
1901 =item C<static INTVAL fetch_iv_be(INTVAL w)>
1902 
1903 This function converts a 4 or 8 byte C<INTVAL> into big endian format.
1904 If the native format is already big endian, then no conversion is done.
1905 
1906 =cut
1907 
1908 */
1909 
1910 PARROT_INLINE
1911 PARROT_WARN_UNUSED_RESULT
1912 PARROT_CONST_FUNCTION
1913 static INTVAL
fetch_iv_be(INTVAL w)1914 fetch_iv_be(INTVAL w)
1915 {
1916     ASSERT_ARGS(fetch_iv_be)
1917 #if PARROT_BIGENDIAN
1918     return w;
1919 #else
1920 #  if INTVAL_SIZE == 4
1921     return (w << 24) | ((w & 0xff00) << 8) | ((w & 0xff0000) >> 8) | (w >> 24);
1922 #  else
1923 #    if INTVAL_SIZE == 8
1924     INTVAL r;
1925     r = w << 56;
1926     r |= (w & 0xff00) << 40;
1927     r |= (w & 0xff0000) << 24;
1928     r |= (w & 0xff000000) << 8;
1929     r |= (w & 0xff00000000) >> 8;
1930     r |= (w & 0xff0000000000) >> 24;
1931     r |= (w & 0xff000000000000) >> 40;
1932     r |= (w & 0xff00000000000000) >> 56;
1933     return r;
1934 #    else
1935     Parrot_x_force_error_exit(NULL, 1, "Unsupported INTVAL_SIZE=%d\n", INTVAL_SIZE);
1936 #    endif
1937 #  endif
1938 #endif
1939 }
1940 
1941 /*
1942 
1943 =item C<static opcode_t fetch_op_be(opcode_t w)>
1944 
1945 Same as C<fetch_iv_be> for opcode_t
1946 
1947 =cut
1948 
1949 */
1950 
1951 PARROT_INLINE
1952 PARROT_WARN_UNUSED_RESULT
1953 PARROT_CONST_FUNCTION
1954 static opcode_t
fetch_op_be(opcode_t w)1955 fetch_op_be(opcode_t w)
1956 {
1957     ASSERT_ARGS(fetch_op_be)
1958 #if PARROT_BIGENDIAN
1959     return w;
1960 #else
1961 #  if OPCODE_T_SIZE == 4
1962     return (w << 24) | ((w & 0x0000ff00) << 8) | ((w & 0x00ff0000) >> 8) |
1963         ((w & 0xff000000) >> 24);
1964 #  else
1965     opcode_t r;
1966 
1967     r = w << 56;
1968     r |= (w & 0xff00) << 40;
1969     r |= (w & 0xff0000) << 24;
1970     r |= (w & 0xff000000) << 8;
1971     r |= (w & 0xff00000000) >> 8;
1972     r |= (w & 0xff0000000000) >> 24;
1973     r |= (w & 0xff000000000000) >> 40;
1974     r |= (w & 0xff00000000000000) >> 56;
1975     return r;
1976 #  endif
1977 #endif
1978 }
1979 
1980 /*
1981 
1982 =item C<static opcode_t fetch_op_le(opcode_t w)>
1983 
1984 Same as C<fetch_iv_le> for opcode_t
1985 
1986 =cut
1987 
1988 */
1989 
1990 PARROT_INLINE
1991 PARROT_WARN_UNUSED_RESULT
1992 PARROT_CONST_FUNCTION
1993 static opcode_t
fetch_op_le(opcode_t w)1994 fetch_op_le(opcode_t w)
1995 {
1996     ASSERT_ARGS(fetch_op_le)
1997 #if !PARROT_BIGENDIAN
1998     return w;
1999 #else
2000 #  if OPCODE_T_SIZE == 4
2001     return (w << 24) | ((w & 0x0000ff00) << 8) | ((w & 0x00ff0000) >> 8) |
2002         ((w & 0xff000000) >> 24);
2003 #  else
2004     opcode_t r;
2005 
2006     r = w << 56;
2007     r |= (w & 0xff00) << 40;
2008     r |= (w & 0xff0000) << 24;
2009     r |= (w & 0xff000000) << 8;
2010     r |= (w & 0xff00000000) >> 8;
2011     r |= (w & 0xff0000000000) >> 24;
2012     r |= (w & 0xff000000000000) >> 40;
2013     r |= (w & 0xff00000000000000) >> 56;
2014     return r;
2015 #  endif
2016 #endif
2017 }
2018 
2019 /*
2020 
2021 =pod
2022 
2023 Unrolled routines for swapping various sizes from 32-128 bits. These
2024 should only be used if alignment is unknown or we are pulling something
2025 out of a padded buffer.
2026 
2027 =cut
2028 
2029 */
2030 
2031 /*
2032 
2033 =item C<static void fetch_buf_be_4(unsigned char *rb, const unsigned char *b)>
2034 
2035 Converts a 4-byte big-endian buffer C<b> into a little-endian C<rb>.
2036 
2037 =cut
2038 
2039 */
2040 
2041 PARROT_INLINE
2042 static void
fetch_buf_be_4(ARGOUT (unsigned char * rb),ARGIN (const unsigned char * b))2043 fetch_buf_be_4(ARGOUT(unsigned char *rb), ARGIN(const unsigned char *b))
2044 {
2045     ASSERT_ARGS(fetch_buf_be_4)
2046 #if PARROT_BIGENDIAN
2047     memcpy(rb, b, 4);
2048 #else
2049     rb[0] = b[3];
2050     rb[1] = b[2];
2051     rb[2] = b[1];
2052     rb[3] = b[0];
2053 #endif
2054 }
2055 
2056 /*
2057 
2058 =item C<static void fetch_buf_le_4(unsigned char *rb, const unsigned char *b)>
2059 
2060 Converts a 4-byte little-endian buffer C<b> into a big-endian buffer C<rb>.
2061 
2062 =cut
2063 
2064 */
2065 
2066 PARROT_INLINE
2067 static void
fetch_buf_le_4(ARGOUT (unsigned char * rb),ARGIN (const unsigned char * b))2068 fetch_buf_le_4(ARGOUT(unsigned char *rb), ARGIN(const unsigned char *b))
2069 {
2070     ASSERT_ARGS(fetch_buf_le_4)
2071 #if !PARROT_BIGENDIAN
2072     memcpy(rb, b, 4);
2073 #else
2074     rb[0] = b[3];
2075     rb[1] = b[2];
2076     rb[2] = b[1];
2077     rb[3] = b[0];
2078 #endif
2079 }
2080 
2081 /*
2082 
2083 =item C<static void fetch_buf_be_8(unsigned char *rb, const unsigned char *b)>
2084 
2085 Converts an 8-byte big-endian buffer C<b> into a little-endian buffer C<rb>
2086 
2087 =cut
2088 
2089 */
2090 
2091 PARROT_INLINE
2092 static void
fetch_buf_be_8(ARGOUT (unsigned char * rb),ARGIN (const unsigned char * b))2093 fetch_buf_be_8(ARGOUT(unsigned char *rb), ARGIN(const unsigned char *b))
2094 {
2095     ASSERT_ARGS(fetch_buf_be_8)
2096 #if PARROT_BIGENDIAN
2097     memcpy(rb, b, 8);
2098 #else
2099     rb[0] = b[7];
2100     rb[1] = b[6];
2101     rb[2] = b[5];
2102     rb[3] = b[4];
2103     rb[4] = b[3];
2104     rb[5] = b[2];
2105     rb[6] = b[1];
2106     rb[7] = b[0];
2107 #endif
2108 }
2109 
2110 /*
2111 
2112 =item C<static void fetch_buf_le_8(unsigned char *rb, const unsigned char *b)>
2113 
2114 Converts an 8-byte little-endian buffer C<b> into a big-endian buffer C<rb>.
2115 
2116 =cut
2117 
2118 */
2119 
2120 PARROT_INLINE
2121 static void
fetch_buf_le_8(ARGOUT (unsigned char * rb),ARGIN (const unsigned char * b))2122 fetch_buf_le_8(ARGOUT(unsigned char *rb), ARGIN(const unsigned char *b))
2123 {
2124     ASSERT_ARGS(fetch_buf_le_8)
2125 #if !PARROT_BIGENDIAN
2126     memcpy(rb, b, 8);
2127 #else
2128     rb[0] = b[7];
2129     rb[1] = b[6];
2130     rb[2] = b[5];
2131     rb[3] = b[4];
2132     rb[4] = b[3];
2133     rb[5] = b[2];
2134     rb[6] = b[1];
2135     rb[7] = b[0];
2136 #endif
2137 }
2138 
2139 /*
2140 
2141 =item C<static void fetch_buf_le_12(unsigned char *rb, const unsigned char *b)>
2142 
2143 Converts a 12-byte little-endian buffer C<b> into a big-endian buffer C<b>.
2144 
2145 =cut
2146 
2147 */
2148 
2149 PARROT_INLINE
2150 static void
fetch_buf_le_12(ARGOUT (unsigned char * rb),ARGIN (const unsigned char * b))2151 fetch_buf_le_12(ARGOUT(unsigned char *rb), ARGIN(const unsigned char *b))
2152 {
2153     ASSERT_ARGS(fetch_buf_le_12)
2154 #if !PARROT_BIGENDIAN
2155     memcpy(rb, b, 12);
2156 #else
2157     rb[0]  = b[11];
2158     rb[1]  = b[10];
2159     rb[2]  = b[9];
2160     rb[3]  = b[8];
2161     rb[4]  = b[7];
2162     rb[5]  = b[6];
2163     rb[6]  = b[5];
2164     rb[7]  = b[4];
2165     rb[8]  = b[3];
2166     rb[9]  = b[2];
2167     rb[10] = b[1];
2168     rb[11] = b[0];
2169 #endif
2170 }
2171 
2172 /*
2173 
2174 =item C<static void fetch_buf_be_12(unsigned char *rb, const unsigned char *b)>
2175 
2176 Converts a 12-byte big-endian buffer C<b> into a little-endian buffer C<b>.
2177 
2178 =cut
2179 
2180 */
2181 
2182 PARROT_INLINE
2183 static void
fetch_buf_be_12(ARGOUT (unsigned char * rb),ARGIN (const unsigned char * b))2184 fetch_buf_be_12(ARGOUT(unsigned char *rb), ARGIN(const unsigned char *b))
2185 {
2186     ASSERT_ARGS(fetch_buf_be_12)
2187 #if PARROT_BIGENDIAN
2188     memcpy(rb, b, 12);
2189 #else
2190     rb[0]  = b[11];
2191     rb[1]  = b[10];
2192     rb[2]  = b[9];
2193     rb[3]  = b[8];
2194     rb[4]  = b[7];
2195     rb[5]  = b[6];
2196     rb[6]  = b[5];
2197     rb[7]  = b[4];
2198     rb[8]  = b[3];
2199     rb[9]  = b[2];
2200     rb[10] = b[1];
2201     rb[11] = b[0];
2202 #endif
2203 }
2204 
2205 /*
2206 
2207 =item C<static void fetch_buf_le_16(unsigned char *rb, const unsigned char *b)>
2208 
2209 Converts a 16-byte little-endian buffer C<b> into a big-endian buffer C<b>.
2210 
2211 =cut
2212 
2213 */
2214 
2215 PARROT_INLINE
2216 static void
fetch_buf_le_16(ARGOUT (unsigned char * rb),ARGIN (const unsigned char * b))2217 fetch_buf_le_16(ARGOUT(unsigned char *rb), ARGIN(const unsigned char *b))
2218 {
2219     ASSERT_ARGS(fetch_buf_le_16)
2220 #if !PARROT_BIGENDIAN
2221     memcpy(rb, b, 16);
2222 #else
2223     rb[0]  = b[15];
2224     rb[1]  = b[14];
2225     rb[2]  = b[13];
2226     rb[3]  = b[12];
2227     rb[4]  = b[11];
2228     rb[5]  = b[10];
2229     rb[6]  = b[9];
2230     rb[7]  = b[8];
2231     rb[8]  = b[7];
2232     rb[9]  = b[6];
2233     rb[10] = b[5];
2234     rb[11] = b[4];
2235     rb[12] = b[3];
2236     rb[13] = b[2];
2237     rb[14] = b[1];
2238     rb[15] = b[0];
2239 #endif
2240 }
2241 
2242 /*
2243 
2244 =item C<static void fetch_buf_be_16(unsigned char *rb, const unsigned char *b)>
2245 
2246 Converts a 16-byte big-endian buffer C<b> into a little-endian buffer C<b>.
2247 
2248 =cut
2249 
2250 */
2251 
2252 PARROT_INLINE
2253 static void
fetch_buf_be_16(ARGOUT (unsigned char * rb),ARGIN (const unsigned char * b))2254 fetch_buf_be_16(ARGOUT(unsigned char *rb), ARGIN(const unsigned char *b))
2255 {
2256     ASSERT_ARGS(fetch_buf_be_16)
2257 #if PARROT_BIGENDIAN
2258     memcpy(rb, b, 16);
2259 #else
2260     rb[0]  = b[15];
2261     rb[1]  = b[14];
2262     rb[2]  = b[13];
2263     rb[3]  = b[12];
2264     rb[4]  = b[11];
2265     rb[5]  = b[10];
2266     rb[6]  = b[9];
2267     rb[7]  = b[8];
2268     rb[8]  = b[7];
2269     rb[9]  = b[6];
2270     rb[10] = b[5];
2271     rb[11] = b[4];
2272     rb[12] = b[3];
2273     rb[13] = b[2];
2274     rb[14] = b[1];
2275     rb[15] = b[0];
2276 #endif
2277 }
2278 
2279 /*
2280 
2281 =item C<static void fetch_buf_le_32(unsigned char *rb, const unsigned char *b)>
2282 
2283 Converts a 32-byte little-endian buffer C<b> into a big-endian buffer C<b>.
2284 
2285 =cut
2286 
2287 */
2288 
2289 PARROT_INLINE
2290 static void
fetch_buf_le_32(ARGOUT (unsigned char * rb),ARGIN (const unsigned char * b))2291 fetch_buf_le_32(ARGOUT(unsigned char *rb), ARGIN(const unsigned char *b))
2292 {
2293     ASSERT_ARGS(fetch_buf_le_32)
2294 #if !PARROT_BIGENDIAN
2295     memcpy(rb, b, 32);
2296 #else
2297     rb[0]  = b[31];
2298     rb[1]  = b[30];
2299     rb[2]  = b[29];
2300     rb[3]  = b[28];
2301     rb[4]  = b[27];
2302     rb[5]  = b[26];
2303     rb[6]  = b[25];
2304     rb[7]  = b[24];
2305     rb[8]  = b[23];
2306     rb[9]  = b[22];
2307     rb[10] = b[21];
2308     rb[11] = b[20];
2309     rb[12] = b[19];
2310     rb[13] = b[18];
2311     rb[14] = b[17];
2312     rb[15] = b[16];
2313     rb[16] = b[15];
2314     rb[17] = b[14];
2315     rb[18] = b[13];
2316     rb[19] = b[12];
2317     rb[20] = b[11];
2318     rb[21] = b[10];
2319     rb[22] = b[9];
2320     rb[23] = b[8];
2321     rb[24] = b[7];
2322     rb[25] = b[6];
2323     rb[26] = b[5];
2324     rb[27] = b[4];
2325     rb[28] = b[3];
2326     rb[29] = b[2];
2327     rb[30] = b[1];
2328     rb[31] = b[0];
2329 #endif
2330 }
2331 
2332 /*
2333 
2334 =item C<static void fetch_buf_be_32(unsigned char *rb, const unsigned char *b)>
2335 
2336 Converts a 32-byte big-endian buffer C<b> into a little-endian buffer C<b>.
2337 
2338 =cut
2339 
2340 */
2341 
2342 PARROT_INLINE
2343 static void
fetch_buf_be_32(ARGOUT (unsigned char * rb),ARGIN (const unsigned char * b))2344 fetch_buf_be_32(ARGOUT(unsigned char *rb), ARGIN(const unsigned char *b))
2345 {
2346     ASSERT_ARGS(fetch_buf_be_32)
2347 #if PARROT_BIGENDIAN
2348     memcpy(rb, b, 32);
2349 #else
2350     rb[0]  = b[31];
2351     rb[1]  = b[30];
2352     rb[2]  = b[29];
2353     rb[3]  = b[28];
2354     rb[4]  = b[27];
2355     rb[5]  = b[26];
2356     rb[6]  = b[25];
2357     rb[7]  = b[24];
2358     rb[8]  = b[23];
2359     rb[9]  = b[22];
2360     rb[10] = b[21];
2361     rb[11] = b[20];
2362     rb[12] = b[19];
2363     rb[13] = b[18];
2364     rb[14] = b[17];
2365     rb[15] = b[16];
2366     rb[16] = b[15];
2367     rb[17] = b[14];
2368     rb[18] = b[13];
2369     rb[19] = b[12];
2370     rb[20] = b[11];
2371     rb[21] = b[10];
2372     rb[22] = b[9];
2373     rb[23] = b[8];
2374     rb[24] = b[7];
2375     rb[25] = b[6];
2376     rb[26] = b[5];
2377     rb[27] = b[4];
2378     rb[28] = b[3];
2379     rb[29] = b[2];
2380     rb[30] = b[1];
2381     rb[31] = b[0];
2382 #endif
2383 }
2384 
2385 
2386 /*
2387 
2388 =back
2389 
2390 =head1 TODO
2391 
2392 C<<PF_store_<type>()>> - write an opcode_t stream to cursor in natural
2393 byte-ordering.
2394 
2395 C<<PF_fetch_<type>()>> - read items and possibly convert the foreign
2396 format.
2397 
2398 C<<PF_size_<type>()>> - return the needed size in C<opcode_t> units.
2399 
2400 =cut
2401 
2402 */
2403 
2404 /*
2405  * Local variables:
2406  *   c-file-style: "parrot"
2407  * End:
2408  * vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
2409  */
2410