summaryrefslogtreecommitdiffstats
path: root/byterun/fix_code.c
blob: 6496ee4dbf120f781e48facc6bdf2ab121f268d5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/***********************************************************************/
/*                                                                     */
/*                           Objective Caml                            */
/*                                                                     */
/*            Xavier Leroy, projet Cristal, INRIA Rocquencourt         */
/*                                                                     */
/*  Copyright 1996 Institut National de Recherche en Informatique et   */
/*  en Automatique.  All rights reserved.  This file is distributed    */
/*  under the terms of the GNU Library General Public License.         */
/*                                                                     */
/***********************************************************************/

/* $Id$ */

/* Handling of blocks of bytecode (endianness switch, threading). */

#include "config.h"
#include "debugger.h"
#include "fix_code.h"
#include "instruct.h"
#include "md5.h"
#include "memory.h"
#include "misc.h"
#include "mlvalues.h"
#include "reverse.h"
#ifdef HAS_UNISTD
#include <unistd.h>
#endif

code_t start_code;
asize_t code_size;
unsigned char * saved_code;
unsigned char code_md5[16];

/* Read the main bytecode block from a file */

void load_code(int fd, asize_t len)
{
  int i;
  struct MD5Context ctx;

  code_size = len;
  start_code = (code_t) stat_alloc(code_size);
  if (read(fd, (char *) start_code, code_size) != code_size)
    fatal_error("Fatal error: truncated bytecode file.\n");
  MD5Init(&ctx);
  MD5Update(&ctx, (unsigned char *) start_code, code_size);
  MD5Final(code_md5, &ctx);
#ifdef ARCH_BIG_ENDIAN
  fixup_endianness(start_code, code_size);
#endif
  if (debugger_in_use) {
    len /= sizeof(opcode_t);
    saved_code = (unsigned char *) stat_alloc(len);
    for (i = 0; i < len; i++) saved_code[i] = start_code[i];
  }
#ifdef THREADED_CODE
  /* Better to thread now than at the beginning of interprete(),
     since the debugger interface needs to perform SET_EVENT requests
     on the code. */
  thread_code(start_code, code_size);
#endif
}

/* This code is needed only if the processor is big endian */

#ifdef ARCH_BIG_ENDIAN

void fixup_endianness(code_t code, asize_t len)
{
  code_t p;
  len /= sizeof(opcode_t);
  for (p = code; p < code + len; p++) {
    Reverse_32(p, p);
  }
}

#endif

/* This code is needed only if we're using threaded code */

#ifdef THREADED_CODE

char ** instr_table;
char * instr_base;

void thread_code (code_t code, asize_t len)
{
  code_t p;
  int l [STOP + 1];
  int i;
  
  for (i = 0; i <= STOP; i++) {
    l [i] = 0;
  }
  /* Instructions with one operand */
  l[PUSHACC] = l[ACC] = l[POP] = l[ASSIGN] =
  l[PUSHENVACC] = l[ENVACC] = l[PUSH_RETADDR] = l[APPLY] =
  l[APPTERM1] = l[APPTERM2] = l[APPTERM3] = l[RETURN] =
  l[GRAB] = l[PUSHGETGLOBAL] = l[GETGLOBAL] = l[SETGLOBAL] =
  l[PUSHATOM] = l[ATOM] = l[MAKEBLOCK1] = l[MAKEBLOCK2] =
  l[MAKEBLOCK3] = l[MAKEFLOATBLOCK] = l[GETFIELD] =
  l[GETFLOATFIELD] = l[SETFIELD] = l[SETFLOATFIELD] =
  l[BRANCH] = l[BRANCHIF] = l[BRANCHIFNOT] = l[PUSHTRAP] =
  l[C_CALL1] = l[C_CALL2] = l[C_CALL3] = l[C_CALL4] = l[C_CALL5] =
  l[CONSTINT] = l[PUSHCONSTINT] = l[OFFSETINT] =
  l[OFFSETREF] = l[OFFSETCLOSURE] = l[PUSHOFFSETCLOSURE] = 1;

  /* Instructions with two operands */
  l[APPTERM] = l[CLOSURE] = l[PUSHGETGLOBALFIELD] =
  l[GETGLOBALFIELD] = l[MAKEBLOCK] = l[C_CALLN] = 2;

  len /= sizeof(opcode_t);
  for (p = code; p < code + len; /*nothing*/) {
    opcode_t instr = *p;
    if (instr < 0 || instr > STOP){
      fatal_error_arg ("Fatal error in fix_code: bad opcode (%lx)\n",
                       (char *)(long)instr);
    }
    *p++ = (opcode_t)(instr_table[instr] - instr_base);
    if (instr == SWITCH) {
      uint32 sizes = *p++;
      uint32 const_size = sizes & 0xFFFF;
      uint32 block_size = sizes >> 16;
      p += const_size + block_size;
    } else if (instr == CLOSUREREC) {
      uint32 nfuncs = *p++;
      p++;                      /* skip nvars */
      p += nfuncs;
    } else {
      p += l[instr];
    }
  }
  Assert(p == code + len);
}

#endif /* THREADED_CODE */

void set_instruction(code_t pos, opcode_t instr)
{
#ifdef THREADED_CODE
  *pos = (opcode_t)(instr_table[instr] - instr_base);
#else
  *pos = instr;
#endif
}