added Number>>log2
[k8lst.git] / src / lstcore / lst_dpname.c
blob62f2d4c532f9c6c26ad0d6603c83139bd14d7732
1 /*
2 * Little Smalltalk, Version 5
4 * Copyright (C) 1987-2005 by Timothy A. Budd
5 * Copyright (C) 2007 by Charles R. Childers
6 * Copyright (C) 2005-2007 by Danny Reinhold
7 * Copyright (C) 2010 by Ketmar // Vampire Avalon
9 * ============================================================================
10 * This license applies to the virtual machine and to the initial image of
11 * the Little Smalltalk system and to all files in the Little Smalltalk
12 * packages except the files explicitly licensed with another license(s).
13 * ============================================================================
14 * Permission is hereby granted, free of charge, to any person obtaining a copy
15 * of this software and associated documentation files (the "Software"), to deal
16 * in the Software without restriction, including without limitation the rights
17 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18 * copies of the Software, and to permit persons to whom the Software is
19 * furnished to do so, subject to the following conditions:
21 * The above copyright notice and this permission notice shall be included in
22 * all copies or substantial portions of the Software.
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 * DEALINGS IN THE SOFTWARE.
32 typedef struct EPInfo {
33 const char *name;
34 lstObject **eptr;
35 } EPInfo;
38 static const EPInfo clInfo[] = {
39 {"Boolean", &lstBooleanClass},
40 {"SmallInt", &lstSmallIntClass},
41 {"Integer", &lstIntegerClass},
42 {"Char", &lstCharClass},
43 {"Float", &lstFloatClass},
44 {"Array", &lstArrayClass},
45 {"Block", &lstBlockClass},
46 {"Context", &lstContextClass},
47 {"Process", &lstProcessClass},
48 {"String", &lstStringClass},
49 {"Symbol", &lstSymbolClass},
50 {"ByteArray", &lstByteArrayClass},
51 {"ByteCode", &lstByteCodeClass},
52 {"Method", &lstMethodClass},
53 {"Number", &lstNumberClass},
54 {0}
57 static const EPInfo epInfo[] = {
58 {"initialize", &lstInitMethod},
59 {"loadFile:", &lstLoadMethod},
60 {"doString:", &lstDoStrMethod},
61 {"runREPL", &lstReplMethod},
62 {"newSymbol:", &lstNewSymMethod},
63 {"setGlobal:", &lstSetGlobMethod},
64 {0}
68 typedef struct {
69 int idx;
70 const char *name;
71 } LSTPrimDef;
73 static const LSTPrimDef lstPrimList[] = {
75 { 1, "NewObject"},
76 { 2, "NewByteArray"},
77 { 3, "ObjectIdentity"}, /* are two args represents the same object? (address compare) */
78 { 4, "ObjectClass"},
79 { 5, "ObjectSize"},
80 { 6, "Array#at:"},
81 { 7, "Array#at:put:"},
82 { 8, "String#at:"},
83 { 9, "String#at:put:"},
84 { 10, "String#clone:"},
85 { 11, "String#Position:from:"},
86 { 12, "String#LastPosition:from:"},
87 { 13, "String#CopyFromTo"},
89 { 14, "BulkObjectExchange"}, /*???*/
90 { 15, "replaceFrom:to:with:startingAt:"},
92 { 16, "BlockInvocation"},
94 { 17, "FlushMethodCache"},
96 { 18, "SmallIntToInteger"},
97 { 19, "NumberToFloat"},
98 { 20, "FloatToInteger"},
99 { 21, "IntegerToSmallInt"},
100 { 22, "IntegerToSmallIntTrunc"},
102 { 23, "bit2op:"},
103 { 24, "bitNot"},
104 { 25, "bitShift:"},
106 { 26, "SmallIntAdd"},
107 { 27, "SmallIntSub"},
108 { 28, "SmallIntMul"},
109 { 29, "SmallIntDiv"},
110 { 30, "SmallIntMod"},
111 { 31, "SmallIntLess"},
112 { 32, "SmallIntLessEqu"},
113 { 33, "SmallIntGreat"},
114 { 34, "SmallIntGreatEqu"},
115 { 35, "SmallIntEqu"},
116 { 36, "SmallIntNotEqu"},
118 { 37, "IntegerAdd"},
119 { 38, "IntegerSub"},
120 { 39, "IntegerMul"},
121 { 40, "IntegerDiv"},
122 { 41, "IntegerMod"},
123 { 42, "IntegerLess"},
124 { 43, "IntegerLessEqu"},
125 { 44, "IntegerGreat"},
126 { 45, "IntegerGreatEqu"},
127 { 46, "IntegerEqu"},
128 { 47, "IntegerNotEqu"},
130 { 48, "FloatAdd"},
131 { 49, "FloatSub"},
132 { 50, "FloatMul"},
133 { 51, "FloatDiv"},
134 { 52, "FloatLess"},
135 { 53, "FloatLessEqu"},
136 { 54, "FloatGreat"},
137 { 55, "FloatGreatEqu"},
138 { 56, "FloatEqu"},
139 { 57, "FloatNotEqu"},
141 { 58, "FloatToString"},
142 { 59, "FloatNegate"},
144 { 60, "PrimIdxName"},
146 { 61, "GetCurrentProcess"},
147 { 62, "ErrorOrYield"},
148 { 63, "ExecuteNewProcessAndWait"},
150 { 64, "LockUnlockSheduler"},
151 { 65, "TicksGetSet"},
152 { 66, "RunGC" },
153 { 67, "UserBreakSignal" },
154 { 68, "EventHandlerCtl" },
155 { 69, "ProcessGroupCtl" },
157 { 70, "PrintObject"},
158 { 71, "ReadCharacter"}, /* returns nil or int */
160 { 72, "FloatBAIO"},
161 { 73, "IntegerBAIO"},
163 { 74, "ExecuteContext"},
165 { 75, "StFinalizeCtl"},
166 { 76, "StWeakCtl"},
168 { 77, "FloatFunc"},
172 #define LST_FIRST_UNUSED_PRIM 80
175 static const LSTPrimDef *lstPDefByIdx (int idx) {
176 const LSTPrimDef *pd;
177 for (pd = lstPrimList; pd->name; pd++) if (pd->idx == idx) return pd;
178 return NULL;
182 static const LSTPrimDef *lstPDefByName (const char *name) {
183 const LSTPrimDef *pd;
184 for (pd = lstPrimList; pd->name; pd++) if (!strcmp(pd->name, name)) return pd;
185 return NULL;
189 static int lstPDGetInstr (const void *bcode, int pc, int *op, int *arg) {
190 const uint8_t *bc = (const uint8_t *)bcode;
191 uint8_t h, l;
192 l = (h = bc[pc++])&0x0f;
193 h = (h>>4)&0x0f;
194 if (h == 0) {
195 h = l;
196 l = bc[pc++];
198 *op = h;
199 *arg = l;
200 return pc;
204 #define VALSIZE 2
205 static int lstPDGetInstrSize (const void *bcode, int pc) {
206 int res = pc;
207 const uint8_t *bc = (const uint8_t *)bcode;
208 uint8_t high, low;
209 low = (high = bc[pc++])&0x0f;
210 high = (high>>4)&0x0f;
211 if (high == 0) { high = low; low = bc[pc++]; }
212 res = pc-res;
213 switch (high) {
214 case lstBCPushBlock:
215 res += VALSIZE;
216 ++res;
217 break;
218 case lstBCDoPrimitive:
219 /* low is argument count; next byte is primitive number */
220 ++res;
221 break;
222 case lstBCDoSpecial:
223 switch (low) {
224 case lstBXBranch:
225 case lstBXBranchIfTrue:
226 case lstBXBranchIfFalse:
227 case lstBXBranchIfNil:
228 case lstBXBranchIfNotNil:
229 res += VALSIZE;
230 break;
231 case lstBXSendToSuper:
232 /* next byte has literal selector number */
233 ++res;
234 break;
236 break;
238 return res;
242 #define GETVAL(pc) (bc[pc] | (bc[(pc)+1] << 8))
243 static __attribute((unused)) int lstPDGetHighestJump (const void *bcode, int bcsize) {
244 const uint8_t *bc = (const uint8_t *)bcode;
245 int zjmp = -1, pc = 0, jdst;
246 while (pc < bcsize) {
247 uint8_t high, low;
248 low = (high = bc[pc++])&0x0f;
249 high = (high>>4)&0x0f;
250 if (high == 0) { high = low; low = bc[pc++]; }
251 jdst = -1;
252 switch (high) {
253 case lstBCPushBlock:
254 jdst = GETVAL(pc);
255 pc += VALSIZE;
256 ++pc;
257 break;
258 case lstBCDoPrimitive:
259 /* low is argument count; next byte is primitive number */
260 ++pc;
261 break;
262 case lstBCDoSpecial:
263 switch (low) {
264 case lstBXBranch:
265 case lstBXBranchIfTrue:
266 case lstBXBranchIfFalse:
267 case lstBXBranchIfNil:
268 case lstBXBranchIfNotNil:
269 jdst = GETVAL(pc);
270 pc += VALSIZE;
271 break;
272 case lstBXSendToSuper:
273 /* next byte has literal selector number */
274 ++pc;
275 break;
277 break;
279 if (jdst > zjmp) zjmp = jdst;
281 return zjmp;
285 static void lstWritePrimPatches (FILE *fp, lstByteObject *bobj) {
286 static struct {
287 int pccount;
288 int pc[256];
289 } primPatch[256];
290 int size = LST_SIZE(bobj);
291 memset(primPatch, 0, sizeof(primPatch));
292 int pc = 0, primRC = 0;
293 while (pc < size) {
294 int op, arg;
295 int apc = lstPDGetInstr(bobj->bytes, pc, &op, &arg);
296 if (op == lstBCDoPrimitive) {
297 int idx = bobj->bytes[apc];
298 if (lstFindPrimitiveName(idx)) {
299 if (primPatch[idx].pccount == 0) primRC++;
300 if (primPatch[idx].pccount >= 255) lstFatal("too many primitive calls in bytecode", (intptr_t)bobj);
301 primPatch[idx].pc[primPatch[idx].pccount++] = apc;
302 } else {
303 lstFatal("unknown primitive in image writer", idx);
306 int len = lstPDGetInstrSize(bobj->bytes, pc);
307 if (len < 1) lstFatal("internal error in bytecode tracer", (intptr_t)bobj);
308 pc += len;
310 lstImgWriteWord(fp, primRC);
311 if (primRC) {
312 int f, c;
313 for (f = 0; f <= 255; f++) {
314 if (primPatch[f].pccount) {
315 const char *pname = lstFindPrimitiveName(f);
316 if (pname) {
317 uint8_t len = strlen(pname);
318 if (fwrite(&len, 1, 1, fp) != 1) lstFatal("can't write str8", (intptr_t)bobj);
319 if (len > 0) {
320 if (fwrite(pname, len, 1, fp) != 1) lstFatal("can't write str8", (intptr_t)bobj);
322 lstImgWriteWord(fp, primPatch[f].pccount);
323 for (c = 0; c < primPatch[f].pccount; c++) lstImgWriteWord(fp, primPatch[f].pc[c]);
331 typedef struct {
332 char *name;
333 LSTPrimitiveFn pfn;
334 LSTPrimitiveClearFn cfn;
335 } LSTExtPrimDef;
338 static LSTExtPrimDef lstExtPrimList[256];
339 static int lstExtPrimFree = LST_FIRST_UNUSED_PRIM;
342 int lstFindExtPrimitiveByName (const char *name) {
343 int f;
344 for (f = LST_FIRST_UNUSED_PRIM; f < lstExtPrimFree; ++f) {
345 if (lstExtPrimList[f].name && !strcmp(lstExtPrimList[f].name, name)) return f;
347 return -1;
351 int lstFindPrimitiveIdx (const char *name) {
352 const LSTPrimDef *pd = lstPDefByName(name);
353 if (pd) return pd->idx;
354 return lstFindExtPrimitiveByName(name);
358 LSTPrimitiveFn lstFindExtPrimitiveFn (int idx) {
359 if (idx < LST_FIRST_UNUSED_PRIM || idx >= lstExtPrimFree) return NULL;
360 if (!lstExtPrimList[idx].name) return NULL;
361 return lstExtPrimList[idx].pfn;
365 const char *lstFindPrimitiveName (int idx) {
366 if (idx < 0 || idx >= lstExtPrimFree) return NULL;
367 if (idx < LST_FIRST_UNUSED_PRIM) {
368 const LSTPrimDef *pd = lstPDefByIdx(idx);
369 return pd ? pd->name : NULL;
371 return lstExtPrimList[idx].name;
375 int lstRegisterExtPrimitive (const char *name, LSTPrimitiveFn pfn, LSTPrimitiveClearFn cfn) {
376 /*fprintf(stderr, "registering: [%s]\n", name);*/
377 if (!name || !name[0] || strlen(name) > 255) return -1; /* invalid name */
378 int idx = lstFindExtPrimitiveByName(name);
379 if (idx < 0) {
380 if (lstExtPrimFree > 255) return -1; /* out of space for primitives */
381 idx = lstExtPrimFree++;
382 lstExtPrimList[idx].name = strdup(name);
384 lstExtPrimList[idx].pfn = pfn;
385 lstExtPrimList[idx].cfn = cfn;
386 return idx;
390 void lstClearExtPrimitives (void) {
391 int f;
392 for (f = LST_FIRST_UNUSED_PRIM; f < lstExtPrimFree; ++f) {
393 if (lstExtPrimList[f].name) {
394 if (lstExtPrimList[f].cfn) lstExtPrimList[f].cfn(f);
395 free(lstExtPrimList[f].name);
396 lstExtPrimList[f].name = NULL;
399 lstExtPrimFree = LST_FIRST_UNUSED_PRIM;
403 void lstPrimitivesClear (void) {
404 lstClearExtPrimitives();
408 int lstRegisterExtPrimitiveTable (const LSTExtPrimitiveTable *tbl) {
409 while (tbl->name) {
410 int px = lstRegisterExtPrimitive(tbl->name, tbl->pfn, tbl->cfn);
411 if (px < 0) return 0;
412 tbl++;
414 return 1;