History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/appl/java/classloader.b (1 of 18352 files). Show all

Unified · Split

java/appl/java/classloader.b+3452−0
@@ -0,0 +1,3452 @@
1implement JavaClassLoader;
2
3#
4# Java Class Loader.
5#
6
7include "sys.m";
8 sys: Sys;
9
10stderr: ref Sys->FD;
11
12include "keyring.m";
13 kr: Keyring;
14
15include "string.m";
16 str: String;
17
18include "math.m";
19 math: Math;
20
21include "hash.m";
22 hash: Hash;
23
24include "loader.m";
25include "classloader.m";
26 ld: Loader;
27 Niladt: import Loader;
28 jassist: JavaAssist;
29 jtrace: JavaTrace;
30
31 JDEBUG, JVERBOSE: import JavaTrace;
32
33 getint, getintarray, getptr: import jassist;
34 getreloc, getrtreloc, getstring: import jassist;
35 getclassadt, getabsint, getadtstring: import jassist;
36 getbytearray, getstrarray, arrayof: import jassist;
37 getmd, putclass, putint, putmod: import jassist;
38 putobj, putptr, putstring, makeadt: import jassist;
39 bytearraytoJS, intarraytoJS: import jassist;
40 bigarraytoJS, realarraytoJS: import jassist;
41 ArraytoJS, JStoObject: import jassist;
42
43this: JavaClassLoader;
44thisnil: Nilmod;
45sysnil: Nilmod;
46loadlinks: array of Loader->Link;
47syslinks: array of Loader->Link;
48relocs: list of ref Class;
49relocd: list of ref Class;
50interf: list of ref Class;
51interfx: list of ref Class;
52initcl: list of ref Class;
53main: ref Class;
54arrayclass: ref Class;
55arraymd: ref Loader->Niladt;
56stringclass: ref Class;
57fsindir: int;
58cur: string;
59
60interfaces: array of ref Class;
61ninterfaces: int = 0;
62linterfaces: int = 0;
63
64INITINTER: con 32;
65
66acqchan: chan of int;
67relchan: chan of int;
68exitchan: chan of int;
69
70MSHUTDOWN, MENTER, MEXIT, MWAIT, MNOTIFY, MSLEEP, MINTERRUPT, MTIMER, MSYNC:
71 con iota;
72
73monitorctl: chan of (int, ref ThreadData, ref Object, int);
74threadctl: chan of (ref ThreadData, int);
75
76threadcount: int = 0;
77daemoncount: int = 0;
78stopped: int = 0;
79
80ident: con "ClassLoader";
81warn: int = 1;
82debug: int = 0;
83verbose: int = 0;
84errors: int = 0;
85
86# for generating ClassLoader exceptions use
87# the following con's. They will be turned
88# into a corresponding Java Exception by
89# sysexcetion
90# when thrown the format is:
91# raise( ex +":"+detail );
92# see loaderror();
93#
94# NOTE: the "raise" string has limited size
95# hence the "e"+<int>
96#
97JCLDREX : con "JLD:"; #prefix
98noclassdeffound,
99classcircularity,
100classformat,
101nosuchmethod,
102nosuchfield,
103unsatisfiedlink,
104linkageerr,
105exceptionininitializer
106 : con "e" + (string iota);
107
108badcallindex : con "call index";
109nocloneindex : con "clone index";
110
111encoding := array[] of
112{
113 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
114 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
115 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
116 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
117 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
118 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
119 'w', 'x', 'y', 'z', '0', '1', '2', '3',
120 '4', '5', '6', '7', '8', '9', '+', '-',
121};
122
123bits := array[] of { 16r80, 16r40, 16r20, 16r10, 16r08, 16r04, 16r02, 16r01 };
124mbits := array[] of { 16r80, 16r20, 16r08, 16r02 };
125
126#
127# Diagnostics.
128#
129
130mesg(s: string)
131{
132 sys->fprint(stderr, "%s: %s\n", ident, s);
133}
134
135diag(s: string)
136{
137 if (cur != nil)
138 s = cur + ": " + s;
139 mesg(s);
140 errors++;
141}
142
143loaderror( ex : string, msg : string )
144{
145 s := msg;
146
147 # if prefix exists then just rethrow msg
148 if ( str->prefix( JCLDREX+ex, msg ) == 0 )
149 {
150 if ( cur != nil )
151 s = cur +": " + s;
152
153 s = sys->sprint( "%s%s:%s", JCLDREX, ex, s );
154 }
155
156 trace(JDEBUG,s);
157
158 raise s;
159}
160
161error(s: string)
162{
163 if ( s == nil )
164 s = JCLDREX + "fatal error";
165 else
166 {
167 # if prefix exists then just re-throw s
168 if ( str->prefix(JCLDREX,s) == 0 )
169 {
170 # add prefix to tag as a Loader ex
171 s = sys->sprint( "%s%s:%s", JCLDREX, s, cur );
172 }
173 }
174
175 trace(JDEBUG,s);
176
177 raise s;
178}
179
180warning(s: string)
181{
182 if (!warn)
183 return;
184 if (cur != nil)
185 s = cur + ": " + s;
186 sys->fprint(stderr, "%s: warning: %s\n", ident, s);
187}
188
189trace(c: int, s: string)
190{
191 if (jtrace != nil)
192 jtrace->trace(c, s);
193}
194
195loadtrace()
196{
197 if (jtrace != nil)
198 return;
199 jtrace = load JavaTrace JavaTrace->PATH;
200 if (jtrace == nil)
201 error(sys->sprint("could not load %s: %r", JavaTrace->PATH));
202 jtrace->init(jassist);
203}
204
205#
206# Load synchronization. Allow only one thread to be loading at a time.
207#
208
209loadsync()
210{
211 for (;;) {
212 alt {
213 <- acqchan =>
214 ;
215 <- exitchan =>
216 return;
217 }
218 alt {
219 <- relchan =>
220 ;
221 <- exitchan =>
222 return;
223 }
224 }
225}
226
227acquire()
228{
229 acqchan <-= 0;
230}
231
232release()
233{
234 relchan <-= 0;
235}
236
237context: ref Draw->Context;
238
239#
240# Initialize loader. Entry.
241#
242init(j: JavaClassLoader, ctxt: ref Draw->Context)
243{
244 sys = load Sys Sys->PATH;
245 stderr = sys->fildes(2);
246 context = ctxt;
247 kr = load Keyring Keyring->PATH;
248 if (kr == nil)
249 error(sys->sprint("could not load %s: %r", Keyring->PATH));
250 str = load String String->PATH;
251 if (str == nil)
252 error(sys->sprint("could not load %s: %r", String->PATH));
253 math = load Math Math->PATH;
254 if (math == nil)
255 error(sys->sprint("could not load %s: %r", Math->PATH));
256 math->FPcontrol(0, Math->INVAL|Math->ZDIV|Math->OVFL|Math->UNFL|Math->INEX);
257 hash = load Hash Hash->PATH;
258 if (hash == nil)
259 error(sys->sprint("could not load %s: %r", Hash->PATH));
260 ld = load Loader Loader->PATH;
261 if (ld == nil)
262 error(sys->sprint("could not load %s: %r", Loader->PATH));
263 jassist = load JavaAssist JavaAssist->PATH;
264 if (jassist == nil)
265 error(sys->sprint("could not load %s: %r", JavaAssist->PATH));
266 if (verbose) {
267 loadtrace();
268 if (debug)
269 jtrace->level = JDEBUG;
270 else
271 jtrace->level = JVERBOSE;
272 }
273 fsindir = jassist->little_endian();
274 this = j;
275 thisnil = jassist->jclnilmod(j);
276 sysnil = jassist->sysnilmod(sys);
277 loadlinks = ld->link(thisnil);
278 syslinks = ld->link(sysnil);
279 if (loadlinks == nil || syslinks == nil)
280 error(sys->sprint("Loader->link failed: %r"));
281 initloadhash();
282 acqchan = chan of int;
283 relchan = chan of int;
284 exitchan = chan of int;
285 spawn loadsync();
286 monitorctl = chan of (int, ref ThreadData, ref Object, int);
287 spawn monitor();
288 threadctl = chan of (ref ThreadData, int);
289 spawn threadmanager();
290 jniinit();
291}
292
293loadarrayclass()
294{
295 arrayclass = loader(ARRAYCLASS);
296 arraymd = arrayclass.moddata;
297}
298
299loadstringclass()
300{
301 stringclass = loader(STRINGCLASS);
302}
303
304#
305# Native interface initialization.
306#
307jniinit()
308{
309 j := load JavaNative JavaNative->PATH;
310 if (j == nil)
311 error(sys->sprint("could not load %s: %r", JavaNative->PATH));
312 e := j->init(sys, ld, this, jassist);
313 if (e != nil)
314 error(sys->sprint("JavaNative->init failed: %s", e));
315}
316
317#
318# Shutdown loader. Entry.
319#
320shutdown()
321{
322 if (exitchan != nil) {
323 exitchan <-= 0;
324 exitchan = nil;
325 }
326 if (monitorctl != nil) {
327 monitorctl <-= (MSHUTDOWN, nil, nil, 0);
328 monitorctl = nil;
329 }
330 if (threadctl != nil) {
331 threadctl <-= (nil, ThreadData.SHUTDOWN);
332 threadctl = nil;
333 }
334}
335
336#
337# Load a class and print information about it.
338# Does not resolve the class and should not be
339# called in the execution environment. Entry.
340#
341info(name: string)
342{
343 c := getclass(name);
344 if (c.state == NEW)
345 c.loadclass();
346 loadtrace();
347 jtrace->info(c);
348}
349
350#
351# Perform outstanding relocation on loaded classes.
352#
353doreloc()
354{
355 #
356 # Load classes we need for relocation.
357 #
358 while (relocs != nil) {
359 r: list of ref Class;
360 r = nil;
361 reloc := hd relocs;
362 relocs = tl relocs;
363 trace(JDEBUG, sys->sprint("reloc %s", reloc.name));
364 i := CLASSREF;
365 while ((s := getstring(reloc.mod, i)) != nil) {
366 if (s != LOADER)
367 r = loadhierarchy(s) :: r;
368 else
369 r = nil :: r;
370 i += 2 * WORDZ;
371 }
372 reloc.refs = mkclarray(r);
373 reloc.relocate();
374 relocd = reloc :: relocd;
375 }
376 #
377 # Patch the module data of the relocated classes.
378 #
379 while (relocd != nil) {
380 patch := hd relocd;
381 relocd = tl relocd;
382 trace(JDEBUG, sys->sprint("modpatch %s", patch.name));
383 patch.modpatch();
384 if (patch.native != nil || patch.classinit != nil) {
385 initcl = patch :: initcl;
386 patch.state = LOADED;
387 } else
388 patch.state = INITED;
389 }
390 #
391 # Extend interfaces.
392 #
393 while (interfx != nil) {
394 extend := hd interfx;
395 interfx = tl interfx;
396 extend.interdirect = extend.interextends;
397 extend.extinterfaces();
398 }
399 #
400 # Make interface linkage tables for classes that implement interfaces.
401 #
402 while (interf != nil) {
403 inter := hd interf;
404 interf = tl interf;
405 inter.interdirect = inter.interextends;
406 inter.linkinterfaces();
407 }
408 #
409 # Call class initializers.
410 #
411 initc : ref Class;
412 t : ref ThreadData;
413
414 {
415 while (initcl != nil) {
416 initc = hd initcl;
417 initcl = tl initcl;
418 initc.state = INITED;
419 trace(JVERBOSE, sys->sprint("Switching class %s state to INITED", initc.name));
420 t = getthreaddata();
421 release();
422 unblock(t);
423 if (initc.native != nil)
424 initc.initjni();
425 if (initc.classinit != nil) {
426 trace(JVERBOSE, sys->sprint("%s-><clinit>()", initc.name));
427 jassist->mcall0(initc.mod, initc.classinit.value);
428 trace(JDEBUG, sys->sprint("clinit done"));
429 }
430 block(t);
431 acquire();
432 }
433 }
434 exception e
435 {
436 "*" =>
437 #NOTE: a raise is only expected from the init calls therefore
438 # when we reach here we need to block and acquire
439 block(t);
440 acquire();
441 trace(JVERBOSE, sys->sprint("Some exception: %s", e));
442 if ( str->prefix(JCLDREX+exceptionininitializer, e ) == 1 )
443 loaderror(exceptionininitializer, e ); #rethrow
444 else
445 {
446 # clear any java exception; we are replacing it
447 t.culprit = nil;
448 loaderror(exceptionininitializer, sys->sprint("%s[unk]", initc.name));
449 }
450 }
451}
452
453#
454# Main "load class" routine. Load a class hierarchy and
455# its dependencies and prepare it for use. Entry.
456# No return on error.
457#
458loader(name: string): ref Class
459{
460 released := 0;
461 t := getthreaddata();
462 {
463 trace(JDEBUG, sys->sprint("load class %s", name));
464 block(t);
465 acquire();
466 c := loadhierarchy(name);
467 if (relocs != nil)
468 doreloc();
469 release();
470 unblock(t);
471 released = 1;
472 trace(JDEBUG, sys->sprint("loader() exit"));
473# if (errors)
474# error(nil);
475 return c;
476 }
477 exception e
478 {
479 "*" =>
480 if(released == 0) {
481 release();
482 unblock(t);
483 }
484 if (e == nil)
485 e = "exit";
486
487 if ( str->prefix(JCLDREX, e) == 1 )
488 error(e);
489
490 error( sys->sprint( "%s", e) );
491
492 #else if (e.name == noclassdeffound)
493 #{
494 # error(nil);
495 #}
496 #else
497 # error(sys->sprint("loader exception: %s: %s: %d", e.mod, e.name, e.pc));
498 }
499 return nil;
500}
501
502#
503# Recursively load a hierarchy.
504#
505loadhierarchy(name: string): ref Class
506{
507 c := getclass(name);
508 case c.state {
509 NEW =>
510 trace(JVERBOSE, sys->sprint("[%s]", name));
511 c.loadclass();
512 relocs = c :: relocs;
513 if ((s := getstring(c.mod, SUPER)) != nil) {
514 c.state = HIER;
515 trace(JVERBOSE, sys->sprint("Switching class %s state to HIER", name));
516 c.super = loadhierarchy(s);
517 } else
518 c.super = nil;
519 c.state = RESOLVE;
520 trace(JVERBOSE, sys->sprint("Switching class %s state to RESOLVE", name));
521 c.resolve();
522 c.loadinterfaces();
523 HIER =>
524 loaderror( classcircularity, name );
525 }
526 return c;
527}
528
529#
530# Check if a string matches exception,
531# right aligned in string
532#
533matches(str, e: string): int
534{
535 if (len str >= len e && str[len str - len e:] == e)
536 return 1;
537 return 0;
538}
539
540#
541# Encode a class name path if its final component
542# will be too long. Entry.
543#
544encodename(name: string): string
545{
546 (dir, base) := str->splitr(name, "/");
547 b := array of byte base;
548 if (len b <= MAXUNENCODED)
549 return name;
550 d := array[kr->MD5dlen] of byte;
551 if (kr->md5(b, len b, d, nil) == nil)
552 error(sys->sprint("md5 failed: %r"));
553 e := array[ENCODEDLEN] of byte;
554 v := 0;
555 n := 0;
556 r := 0;
557 for (i := 0; i < ENCODEDLEN; i++) {
558 if (r < 6) {
559 v |= int d[n++] << r;
560 r += 8;
561 }
562 e[i] = byte encoding[v & 16r3F];
563 v >>= 6;
564 r -= 6;
565 }
566 return dir + string e;
567}
568
569##
570## Runtime entries.
571##
572
573#
574# Runtime load. Passed a pointer into a module's data of a rtload table.
575#
576rtload(addr: int)
577{
578 o := getabsint(addr + RTTHISOFFSET);
579 r := getabsint(addr - (o + WORDZ));
580 l := o + r;
581 d := makeadt(addr - l);
582 s := getadtstring(d, l + RTCLASSOFFSET);
583 a := getrtreloc(d, l + RTRELOCOFFSET);
584 t := getclassadt(d, CLASSADTOFFSET);
585 trace(JVERBOSE, sys->sprint("rtload %s [%d -> %d] for %s", s, o, r, t.name));
586 if (t.state != INITED)
587 error("this not loaded");
588 c := loader(s);
589 cur = c.name;
590 putmod(d, l, c.mod);
591 putmod(d, l + RTCLASSOFFSET, c.native);
592 putclass(d, l + RTRELOCOFFSET, c);
593 putint(d, l + RTTHISOFFSET, c.objtype);
594 o = l + RTFIRSTRELOC;
595 n := len a;
596 for (i := 0; i < n; i++) {
597 if ((a[i].flags & Rmask) == Rinvokespecial) {
598 (w, m, x) := t.special(a[i].field, a[i].signature, a[i].flags, c);
599 if (a[i].flags & Rspecialmp) {
600 if (w == CMP)
601 putmod(d, o, m.mod);
602 else if (w == CNP)
603 putmod(d, o, m.native);
604 else
605 error("bad special");
606 } else
607 putint(d, o, x);
608 } else {
609 (w, v) := c.resolvereloc(a[i].field, a[i].signature, a[i].flags);
610 case w {
611 VVAL =>
612 putint(d, o, v);
613 VMP =>
614 putmod(d, o, c.mod);
615 VNP =>
616 putmod(d, o, c.native);
617 VOBJ =>
618 putobj(d, o, c.this);
619 * =>
620 error("bad resolve");
621 }
622 }
623 o += WORDZ;
624 }
625 cur = nil;
626# if (errors)
627# error("rtload failed");
628}
629
630#
631# Get a Class adt by name. Used internally and made visible.
632# It does no loading so should only be called if you know
633# the class is loaded (or are loading it).
634#
635
636CHSZ: con 31;
637classhash := array[CHSZ] of list of ref Class;
638
639getclass(name: string): ref Class
640{
641 h := classhash[hash->fun1(name, CHSZ):];
642 for (l := h[0]; l != nil; l = tl l) {
643 c := hd l;
644 if (c.name == name)
645 return c;
646 }
647 c := ref Class;
648 c.state = NEW;
649 trace(JVERBOSE, sys->sprint("Switching class %s state to NEW", name));
650 c.name = name;
651 c.flags = 0;
652 c.info = ref Ldinfo;
653 h[0] = c :: h[0];
654 return c;
655}
656
657#
658# Map a module to its class. This works for native modules too.
659#
660
661MHSZ: con 31;
662modhash := array[MHSZ] of list of (Nilmod, ref Class);
663
664addmodclass(m: Nilmod, c: ref Class)
665{
666 h := modhash[jassist->modhash(m) % MHSZ:];
667 h[0] = (m, c) :: h[0];
668}
669
670getmodclass(m: Nilmod): ref Class
671{
672 for (l := modhash[jassist->modhash(m) % MHSZ]; l != nil; l = tl l) {
673 (t, c) := hd l;
674 if (t == m)
675 return c;
676 }
677 return nil;
678}
679
680#
681# Thread data.
682#
683
684THSZ: con 31;
685threadhash := array[THSZ] of list of ref ThreadData;
686
687getpid(): int
688{
689 return sys->pctl(0, nil);
690}
691
692getcontext(): ref Draw->Context
693{
694 return context;
695}
696
697getthreaddata(): ref ThreadData
698{
699 p := getpid();
700 for (l := threadhash[p % THSZ]; l != nil; l = tl l) {
701 t := hd l;
702 if (t.pid == p)
703 return t;
704 }
705 acquire();
706 h := threadhash[p % THSZ:];
707 d := ref ThreadData;
708 d.pid = p;
709 d.wchan = chan of int;
710 d.flags = 0;
711 h[0] = d :: h[0];
712 threadcount++;
713 trace(JVERBOSE, sys->sprint("count = %d + %d", threadcount, daemoncount));
714 release();
715 return d;
716}
717
718delthreaddata()
719{
720 n: list of ref ThreadData;
721 acquire();
722 p := getpid();
723 h := threadhash[p % THSZ:];
724 for (l := h[0]; l != nil; l = tl l) {
725 t := hd l;
726 if (t.pid == p) {
727 if (t.flags & ThreadData.DAEMON)
728 daemoncount--;
729 else
730 threadcount--;
731 } else
732 n = t :: n;
733 }
734 h[0] = n;
735 trace(JVERBOSE, sys->sprint("count = %d + %d", threadcount, daemoncount));
736 if (threadcount == 0)
737 nothreads(nil);
738 else
739 release();
740}
741
742#
743# Mark current thread a daemon. Entry.
744#
745daemonize()
746{
747 t := getthreaddata();
748 acquire();
749 if ((t.flags & ThreadData.DAEMON) == 0) {
750 t.flags |= ThreadData.DAEMON;
751 daemoncount++;
752 threadcount--;
753 }
754 trace(JVERBOSE, sys->sprint("count = %d + %d", threadcount, daemoncount));
755 if (threadcount == 0)
756 nothreads(t);
757 else
758 release();
759}
760
761#
762# Stop all threads. When all are dead we will shutdown.
763#
764stopthreads(t: ref ThreadData)
765{
766 for (i := 0; i < THSZ; i++)
767 for (l := threadhash[i]; l != nil; l = tl l) {
768 s := hd l;
769 if (s != t)
770 stop(s, nil);
771 }
772 stopped = 1;
773}
774
775#
776# No non-daemon threads. Maybe clean up, maybe shutdown.
777#
778nothreads(t: ref ThreadData)
779{
780 if (!stopped)
781 stopthreads(t);
782 if (daemoncount != 0) {
783 release();
784 if (t != nil) {
785 t.culprit = threaddeath().new();
786 raise JAVAEXCEPTION;
787 }
788 return;
789 }
790 release();
791 shutdown();
792}
793
794#
795# Entry for system.exit().
796#
797system_exit()
798{
799 t := getthreaddata();
800 acquire();
801 stopthreads(t);
802 release();
803 t.culprit = threaddeath().new();
804 raise JAVAEXCEPTION;
805}
806
807cmd_start: array of byte;
808cmd_stop: array of byte;
809cmd_kill: array of byte;
810cmd_failed: int = 0;
811tdclass: ref Class;
812
813ctlfile(t: ref ThreadData)
814{
815 if (t.ctlfile == nil)
816 t.ctlfile = PROG + "/" + string t.pid + "/dbgctl";
817}
818
819threaddeath(): ref Class
820{
821 if (tdclass == nil)
822 tdclass = loader(EXCEPTIONPATH + "ThreadDeath");
823 return tdclass;
824}
825
826dosuspend(t: ref ThreadData)
827{
828 ctlfile(t);
829 f := sys->open(t.ctlfile, Sys->ORDWR);
830 monsync();
831 t.flags |= ThreadData.SUSPENDED;
832 if (f == nil) {
833 if (!cmd_failed) {
834 warning(sys->sprint("could not open %s: %r", t.ctlfile));
835 cmd_failed = 1;
836 }
837 } else {
838 sys->write(f, cmd_stop, len cmd_stop);
839 t.control = f;
840 }
841}
842
843doresume(t: ref ThreadData)
844{
845 if (t.control != nil) {
846 sys->write(t.control, cmd_start, len cmd_start);
847 t.control = nil;
848 }
849 monsync();
850 t.flags &= ~ThreadData.SUSPENDED;
851 if (t.flags & ThreadData.ACKSUSP) {
852 t.wchan <-= MONOK;
853 t.flags &= ~ThreadData.ACKSUSP;
854 }
855}
856
857dostop(t: ref ThreadData)
858{
859 ctlfile(t);
860 f := sys->open(t.ctlfile, Sys->ORDWR);
861 if (f == nil) {
862 if (!cmd_failed) {
863 warning(sys->sprint("could not open %s: %r", t.ctlfile));
864 cmd_failed = 1;
865 }
866 } else
867 sys->write(f, cmd_kill, len cmd_kill);
868}
869
870#
871# The thread manager looks after suspend and resume.
872# A thread that cannot be suspended enters a block()/unblock()
873# pair for the duration of its critical region.
874#
875
876threadmanager()
877{
878 cmd_start = array of byte "start";
879 cmd_stop = array of byte "stop";
880 cmd_kill = array of byte "maim";
881 for (;;) {
882 (t, c) := <- threadctl;
883 if (t != nil && (t.flags & ThreadData.EXITED)) {
884 t = nil;
885 continue;
886 }
887 case c {
888 ThreadData.SHUTDOWN =>
889 return;
890 ThreadData.BLOCK =>
891 t.flags |= ThreadData.BLOCKED;
892 ThreadData.UNBLOCK =>
893 if (t.flags & ThreadData.WAITSTOP)
894 dostop(t);
895 else if (t.flags & ThreadData.WAITSUSP)
896 dosuspend(t);
897 t.flags &= ~(ThreadData.BLOCKED | ThreadData.WAITSTOP | ThreadData.WAITSUSP);
898 ThreadData.SUSPEND =>
899 if ((t.flags & ThreadData.SUSPENDED) == 0) {
900 if (t.flags & ThreadData.BLOCKED)
901 t.flags |= ThreadData.WAITSUSP;
902 else
903 dosuspend(t);
904 }
905 ThreadData.RESUME =>
906 if (t.flags & ThreadData.SUSPENDED)
907 doresume(t);
908 else
909 t.flags &= ~ThreadData.WAITSUSP;
910 ThreadData.STOP =>
911 if (t.flags & ThreadData.BLOCKED)
912 t.flags |= ThreadData.WAITSTOP;
913 else
914 dostop(t);
915 * =>
916 threadctl = nil;
917 raise "bad threadctl command"; #error("bad threadctl command");
918 }
919 t = nil;
920 }
921}
922
923block(t: ref ThreadData)
924{
925 threadctl <-= (t, ThreadData.BLOCK);
926}
927
928unblock(t: ref ThreadData)
929{
930 threadctl <-= (t, ThreadData.UNBLOCK);
931}
932
933suspend(t: ref ThreadData)
934{
935 threadctl <-= (t, ThreadData.SUSPEND);
936}
937
938resume(t: ref ThreadData)
939{
940 threadctl <-= (t, ThreadData.RESUME);
941}
942
943stop(t: ref ThreadData, o: ref Object)
944{
945 if (o == nil)
946 o = threaddeath().new();
947 t.culprit = o;
948 threadctl <-= (t, ThreadData.STOP);
949}
950
951#
952# Exceptions.
953#
954
955mkexception( name : string ) : ref Object
956{
957 return(loader(EXCEPTIONPATH + name).new());
958}
959
960# convert an Inferno exception into a Java Exception
961sysexception( e : string ) : ref Object
962{
963 s : string;
964 msg : string;
965
966
967 if ( e == nil )
968 {
969 s = "InternalError";
970 msg = "unknown";
971 }
972 else if ( str->prefix(JCLDREX,e) == 1 )
973 {
974 trace(JDEBUG, sys->sprint("sysexception: / %s /", e));
975 # try to convert JavaClassLoader exceptions first
976 rest := e[len JCLDREX:]; #strip off prefix
977
978 # pull the possible java ex name; save the rest as a message
979 ex : string;
980 (ex,msg) = str->splitl(rest, ":");
981
982 # convert to coresponding Java Exception, if any
983 case ex
984 {
985 noclassdeffound => s = "NoClassDefFoundError";
986 nosuchmethod => s = "NoSuchMethodError";
987 classcircularity => s = "ClassCircularityError";
988 classformat => s = "ClassFormatError";
989 unsatisfiedlink => s = "UnsatisfiedLinkError";
990 exceptionininitializer => s = "ExceptionInInitializerError";
991 linkageerr => s = "LinkageError"; #different then '*'
992
993 # if none found then make into a generic LinkageError
994 * => s = "LinkageError";
995 msg = rest;
996 }
997 }
998 else
999 {
1000 trace(JDEBUG, sys->sprint("sysexception: / %s /", e));
1001 case e
1002 {
1003 #
1004 # inferno system exceptions
1005 #
1006 "zero divide" or
1007 "invalid math argument" or
1008 "Floating point exception" or
1009 "Integer Overflow" or
1010 "Divide by Zero" or
1011 "Floating Point Divide by Zero" or
1012 "Inexact Floating Point" or
1013 "Invalid Floating Operation" or
1014 "Floating Point Result Overflow" or
1015 "Floating Point Stack Check" or
1016 "Floating Point Result Underflow" =>
1017 s = "ArithmeticException";
1018 "heap full" or
1019 "no memory" =>
1020 s = "OutOfMemoryError";
1021 "array bounds error" or
1022 "Array Bounds Check" =>
1023 s = "ArrayIndexOutOfBoundsException";
1024 "negative array size" =>
1025 s = "NegativeArraySizeException";
1026 "dereference of nil" or
1027 "Segmentation violation" or
1028 "Bus error" =>
1029 s = "NullPointerException";
1030 "Stack Overflow" =>
1031 s = "StackOverflowError";
1032 * =>
1033 s = "InternalError";
1034 }
1035
1036 # fill throwable object with information from inferno ex
1037 #msg = sys->sprint( "%s[%d]:%s", e.mod, e.pc, e.name );
1038 }
1039
1040 obj := mkexception(s); #create Java Ex object
1041
1042
1043 # set the detailed message
1044 throwable := jassist->ObjecttoJT(obj);
1045 if (stringclass == nil)
1046 loadstringclass();
1047 throwable.msg = ref JavaString(stringclass.moddata, msg);
1048
1049 return( obj );
1050}
1051
1052culprit(e: string): ref Object
1053{
1054 thd := getthreaddata();
1055
1056 if ( thd.culprit == nil || e != JAVAEXCEPTION )
1057 {
1058 # no java exception -- turn an inferno
1059 # exception into a Java Exception
1060 thd.culprit = sysexception(e);
1061 }
1062
1063 return( thd.culprit );
1064}
1065
1066throw(c: ref Object)
1067{
1068 getthreaddata().culprit = c;
1069 raise JAVAEXCEPTION;
1070}
1071
1072sthrow(s: string)
1073{
1074 throw(mkexception(s));
1075}
1076
1077#
1078# Monitors.
1079#
1080
1081MONOK, MONILL, MONINT:
1082 con iota;
1083
1084Synch: adt
1085{
1086 thread: ref ThreadData;
1087 count: int;
1088 status: int;
1089 next: cyclic ref Synch;
1090};
1091
1092Monitor: adt
1093{
1094 thread: ref ThreadData;
1095 object: ref Object;
1096 count: int;
1097 head: ref Synch;
1098 tail: ref Synch;
1099};
1100
1101Waiter: adt
1102{
1103 thread: ref ThreadData;
1104 object: ref Object;
1105 count: int;
1106 time: int;
1107 next: cyclic ref Waiter;
1108};
1109
1110sleepers: ref Waiter;
1111waiters: ref Waiter;
1112timeout: int;
1113
1114MAXSLEEP: con 1000;
1115SLEEPTOL: con 50;
1116
1117MONHSZ: con 31;
1118monhash := array[MONHSZ] of list of ref Monitor;
1119
1120getmonitor(o: ref Object): ref Monitor
1121{
1122 z: ref Monitor;
1123 h := monhash[jassist->objhash(o) % MONHSZ:];
1124 for (l := h[0]; l != nil; l = tl l) {
1125 m := hd l;
1126 if (m.object == o)
1127 return m;
1128 if (m.count == 0)
1129 z = m;
1130 }
1131 if (z == nil) {
1132 z = ref Monitor;
1133 z.count = 0;
1134 h[0] = z :: h[0];
1135 }
1136 z.object = o;
1137 return z;
1138}
1139
1140#
1141# Timer thread.
1142#
1143timer(t: int)
1144{
1145 s := t - sys->millisec();
1146 if (s > 0)
1147 sys->sleep(s);
1148 if(monitorctl != nil)
1149 monitorctl <-= (MTIMER, nil, nil, t);
1150}
1151
1152#
1153# Wait to be interrupted, notified or for timeout to expire.
1154#
1155waiter(w: ref Waiter)
1156{
1157 w.thread.flags &= ~ThreadData.INTERRUPTED;
1158 s := w.time;
1159 if (s == 0) {
1160 w.next = waiters.next;
1161 waiters.next = w;
1162 } else {
1163 t := sys->millisec();
1164 w.time += t;
1165 if (sleepers.next == nil) {
1166 sleepers.next = w;
1167 if (s > MAXSLEEP)
1168 s = MAXSLEEP;
1169 timeout = t + s;
1170 spawn timer(timeout);
1171 } else if (w.time >= sleepers.next.time) {
1172 h := sleepers.next;
1173 while (h.next != nil && w.time > h.next.time)
1174 h = h.next;
1175 w.next = h.next;
1176 h.next = w;
1177 } else {
1178 w.next = sleepers.next;
1179 sleepers.next = w;
1180 if (w.time < timeout - SLEEPTOL) {
1181 timeout = w.time;
1182 spawn timer(timeout);
1183 }
1184 }
1185 }
1186}
1187
1188#
1189# Respond to timer.
1190#
1191dotimer(t: int)
1192{
1193 c := sys->millisec();
1194 n := t;
1195 if (t < c)
1196 n = c;
1197 n += SLEEPTOL;
1198 w := sleepers;
1199 while ((l := w.next) != nil && l.time <= n) {
1200 w.next = l.next;
1201 mondone(l, MONOK);
1202 }
1203 if (t == timeout && l != nil) {
1204 timeout = l.time;
1205 if (timeout - c > MAXSLEEP)
1206 timeout = c + MAXSLEEP;
1207 spawn timer(timeout);
1208 }
1209}
1210
1211#
1212# Notify.
1213#
1214
1215donotifyl(w: ref Waiter, o: ref Object): ref Waiter
1216{
1217 while ((l := w.next) != nil) {
1218 if (l.object == o) {
1219 w.next = l.next;
1220 return l;
1221 }
1222 else
1223 w = l;
1224 }
1225 return nil;
1226}
1227
1228donotify(o: ref Object)
1229{
1230 if ((l := donotifyl(waiters, o)) != nil || (l = donotifyl(sleepers, o)) != nil)
1231 mondone(l, MONOK);
1232}
1233
1234#
1235# Notify all.
1236#
1237
1238donotifyalll(w: ref Waiter, o: ref Object)
1239{
1240 while ((t := w.next) != nil) {
1241 if (t.object == o) {
1242 w.next = t.next;
1243 mondone(t, MONOK);
1244 } else
1245 w = t;
1246 }
1247}
1248
1249donotifyall(o: ref Object)
1250{
1251 donotifyalll(waiters, o);
1252 donotifyalll(sleepers, o);
1253}
1254
1255#
1256# Interrupt.
1257#
1258
1259dointerruptl(w: ref Waiter, t: ref ThreadData): ref Waiter
1260{
1261 while ((l := w.next) != nil) {
1262 if (l.thread == t) {
1263 w.next = l.next;
1264 return l;
1265 }
1266 else
1267 w = l;
1268 }
1269 return nil;
1270}
1271
1272dointerrupt(t: ref ThreadData)
1273{
1274 if ((l := dointerruptl(waiters, t)) != nil || (l = dointerruptl(sleepers, t)) != nil) {
1275 l.thread.flags |= ThreadData.INTERRUPTED;
1276 mondone(l, MONINT);
1277 }
1278}
1279
1280#
1281# Enter or reenter a monitor.
1282#
1283doenter(t: ref ThreadData, o: ref Object, n: int, s: int)
1284{
1285 m := getmonitor(o);
1286 if (m.count == 0) {
1287 m.thread = t;
1288 m.count = n;
1289 } else if (m.thread == t)
1290 m.count += n;
1291 else {
1292 w := ref Synch;
1293 w.thread = t;
1294 w.count = n;
1295 w.status = s;
1296 if (m.tail == nil) {
1297 m.head = w;
1298 m.tail = w;
1299 } else {
1300 m.tail.next = w;
1301 m.tail = w;
1302 }
1303 return ;
1304 }
1305 for (;;) {
1306 alt {
1307 t.wchan <-= s =>
1308 return;
1309 * =>
1310 if (t.flags & ThreadData.SUSPENDED) {
1311 t.flags |= ThreadData.ACKSUSP;
1312 return;
1313 }
1314 sys->sleep(0);
1315 }
1316 }
1317}
1318
1319#
1320# A sleeper or waiter is done.
1321#
1322mondone(w: ref Waiter, s: int)
1323{
1324 if (w.object != nil)
1325 doenter(w.thread, w.object, w.count, s);
1326 else
1327 w.thread.wchan <-= s;
1328}
1329
1330#
1331# Concede monitor to next synchronizer.
1332#
1333monitornext(m: ref Monitor)
1334{
1335 h := m.head;
1336 if (h != nil) {
1337 x := h.next;
1338 m.head = x;
1339 if (x == nil)
1340 m.tail = nil;
1341 m.thread = h.thread;
1342 m.count = h.count;
1343 m.thread.wchan <-= h.status;
1344 } else {
1345 m.thread = nil;
1346 m.object = nil;
1347 m.count = 0;
1348 }
1349}
1350
1351#
1352# Monitor thread.
1353#
1354monitor()
1355{
1356 m: ref Monitor;
1357 sleepers = ref Waiter;
1358 waiters = ref Waiter;
1359 for (;;) {
1360 (c, t, o, n) := <- monitorctl;
1361 case c {
1362 MSHUTDOWN =>
1363 return;
1364 MSYNC =>
1365 sys->sleep(0);
1366 MENTER =>
1367 doenter(t, o, n, MONOK);
1368 MEXIT =>
1369 m = getmonitor(o);
1370 if (m.count == 0)
1371 raise "mexit inbalance"; #error("mexit inbalance");
1372 if (m.thread != t)
1373 raise "mexit mismatch"; #error("mexit mismatch");
1374 m.count--;
1375 if (m.count == 0)
1376 monitornext(m);
1377 MWAIT =>
1378 m = getmonitor(o);
1379 if (m.count == 0 || m.thread != t) {
1380 t.wchan <-= MONILL;
1381 break;
1382 }
1383 waiter(ref Waiter(t, o, m.count, n, nil));
1384 monitornext(m);
1385 MNOTIFY =>
1386 m = getmonitor(o);
1387 if (m.count == 0 || m.thread != t) {
1388 t.wchan <-= MONILL;
1389 break;
1390 }
1391 if (n)
1392 donotifyall(o);
1393 else
1394 donotify(o);
1395 t.wchan <-= MONOK;
1396 MSLEEP =>
1397 waiter(ref Waiter(t, nil, 0, n, nil));
1398 MINTERRUPT =>
1399 dointerrupt(t);
1400 MTIMER =>
1401 dotimer(n);
1402 * =>
1403 monitorctl = nil;
1404 raise "bad monitorctl command"; #error("bad monitorctl command");
1405 }
1406 t = nil;
1407 o = nil;
1408 m = nil;
1409 }
1410}
1411
1412#
1413# Common resume code.
1414#
1415monitorresume(d: ref ThreadData)
1416{
1417 case <- d.wchan {
1418 MONILL =>
1419 unblock(d);
1420 sthrow("IllegalMonitorStateException");
1421 MONINT =>
1422 unblock(d);
1423 sthrow("InterruptedException");
1424 }
1425 unblock(d);
1426}
1427
1428#
1429# Monitor / thread control entries.
1430#
1431
1432monitorenter(o: ref Object)
1433{
1434 if ( o == nil )
1435 sthrow("NullPointerException");
1436 d := getthreaddata();
1437 if (monitorctl != nil) {
1438 monitorctl <-= (MENTER, d, o, 1);
1439 <- d.wchan;
1440 }
1441}
1442
1443monitorexit(o: ref Object)
1444{
1445 if ( o == nil )
1446 sthrow("NullPointerException");
1447 d := getthreaddata();
1448 if (monitorctl != nil)
1449 monitorctl <-= (MEXIT, d, o, 0);
1450}
1451
1452monitorwait(o: ref Object, l: int)
1453{
1454 if ( o == nil )
1455 sthrow("NullPointerException");
1456 d := getthreaddata();
1457 if (monitorctl != nil) {
1458 block(d);
1459 monitorctl <-= (MWAIT, d, o, l);
1460 monitorresume(d);
1461 }
1462}
1463
1464monitornotify(o: ref Object, f: int)
1465{
1466 if ( o == nil )
1467 sthrow("NullPointerException");
1468 d := getthreaddata();
1469 if (monitorctl != nil) {
1470 block(d);
1471 monitorctl <-= (MNOTIFY, d, o, f);
1472 monitorresume(d);
1473 }
1474}
1475
1476monsync()
1477{
1478 monitorctl <-= (MSYNC, nil, nil, 0);
1479}
1480
1481sleep(l: int)
1482{
1483 if (l <= 100) {
1484 sys->sleep(l);
1485 return;
1486 }
1487 d := getthreaddata();
1488 if (monitorctl != nil) {
1489 block(d);
1490 monitorctl <-= (MSLEEP, d, nil, l);
1491 monitorresume(d);
1492 }
1493}
1494
1495interrupt(t: ref ThreadData)
1496{
1497 d := getthreaddata();
1498 if (monitorctl != nil) {
1499 block(d);
1500 monitorctl <-= (MINTERRUPT, t, nil, 0);
1501 unblock(d);
1502 }
1503}
1504
1505#
1506# Runtime hierarchy/type check routines.
1507#
1508
1509compatclass(who, what: ref Class): int
1510{
1511 if ((what.flags & ACC_INTERFACE) && (who.flags & ACC_INTERFACE) == 0)
1512 return who.getinterface(what) != nil;
1513 do {
1514 if (who == what)
1515 return 1;
1516 who = who.super;
1517 } while (who != nil);
1518 return 0;
1519}
1520
1521checkcast(who: ref Object, what: ref Class)
1522{
1523 if (who != nil && !instanceof(who, what))
1524 sthrow("ClassCastException");
1525}
1526
1527instanceof(who: ref Object, what: ref Class): int
1528{
1529 if (who == nil)
1530 return 0;
1531 return compatclass(who.class(), what);
1532}
1533
1534acheckcast(who: ref Array, what: ref Class, dims: int)
1535{
1536 if (who != nil && !ainstanceof(who, what, dims))
1537 sthrow("ClassCastException");
1538}
1539
1540ainstanceof(who: ref Array, what: ref Class, dims: int): int
1541{
1542 if (who == nil)
1543 return 0;
1544 if (arrayclass == nil)
1545 loadarrayclass();
1546 if (who.mod != arraymd)
1547 return 0;
1548 # is 'what' Object[]... ?
1549 if (who.dims > dims && what.super == nil && (what.flags & ACC_INTERFACE) == 0)
1550 return 1;
1551 if (who.dims != dims || who.class == nil)
1552 return 0;
1553 return compatclass(who.class, what);
1554}
1555
1556pcheckcast(who: ref Array, what, dims: int)
1557{
1558 if (who != nil && !pinstanceof(who, what, dims))
1559 sthrow("ClassCastException");
1560}
1561
1562pinstanceof(who: ref Array, what, dims: int): int
1563{
1564 if (who == nil)
1565 return 0;
1566 if (arrayclass == nil)
1567 loadarrayclass();
1568 if (who.mod != arraymd || who.dims != dims || who.class != nil)
1569 return 0;
1570 return who.primitive == what;
1571}
1572
1573aastoreinstanceof(who: ref Object, what: ref Array): int
1574{
1575 if (arrayclass == nil)
1576 loadarrayclass();
1577 if (what.mod != arraymd)
1578 return 0;
1579 if (what.dims == 1) {
1580 if (what.class == nil)
1581 return 0;
1582 if (who == nil)
1583 return 1;
1584 return compatclass(who.class(), what.class);
1585 } else {
1586 if (who == nil)
1587 return 1;
1588 if (who.class() != arrayclass)
1589 return 0;
1590 a := arrayof(who);
1591 if (a.dims != what.dims - 1)
1592 return 0;
1593 if (a.class == nil)
1594 return what.class == nil && a.primitive == what.primitive;
1595 if (what.class == nil)
1596 return 0;
1597 return compatclass(a.class, what.class);
1598 }
1599}
1600
1601aastorecheck(who: ref Object, what: ref Array)
1602{
1603 if (what == nil)
1604 sthrow("NullPointerException");
1605 if (!aastoreinstanceof(who, what))
1606 sthrow("ArrayStoreException");
1607}
1608
1609multianewarray(ndim: int, c: ref Class, etype: int, bounds: array of int): ref Array
1610{
1611 n := bounds[0];
1612 if (n < 0)
1613 sthrow("NegativeArraySizeException");
1614 if (arrayclass == nil)
1615 loadarrayclass();
1616 a := ref Array(arraymd, nil, ndim, c, etype);
1617 if (etype == 0 || ndim > 1)
1618 a.holder = array[n] of ref JavaString;
1619 else {
1620 case etype {
1621 T_BOOLEAN or T_BYTE =>
1622 a.holder = bytearraytoJS(array[n] of byte);
1623 T_CHAR or T_SHORT or T_INT =>
1624 a.holder = intarraytoJS(array[n] of int);
1625 T_LONG =>
1626 a.holder = bigarraytoJS(array[n] of big);
1627 T_FLOAT or T_DOUBLE =>
1628 a.holder = realarraytoJS(array[n] of real);
1629 }
1630 }
1631 if (len bounds > 1) {
1632 for (i := 0; i < n; i++)
1633 a.holder[i] = ArraytoJS(multianewarray(ndim - 1, c, etype, bounds[1:]));
1634 }
1635 return a;
1636}
1637
1638arraycopy(src: ref Array, sx: int, dst: ref Array, dx: int, n: int)
1639{
1640 if (arrayclass == nil)
1641 loadarrayclass();
1642 if (src == nil || dst == nil)
1643 sthrow("NullPointerException");
1644 if (src.mod != arraymd || dst.mod != arraymd)
1645 sthrow("ArrayStoreException");
1646 sa := src.holder;
1647 if (src.dims == dst.dims) {
1648 if (src.class == nil) {
1649 if (dst.class != nil || src.primitive != dst.primitive)
1650 sthrow("ArrayStoreException");
1651 } else {
1652 if (dst.class == nil)
1653 sthrow("ArrayStoreException");
1654 if (src.class != dst.class && !compatclass(src.class, dst.class))
1655 for (i := 0; i < n; i++)
1656 if (!aastoreinstanceof(JStoObject(sa[sx + i]), dst))
1657 sthrow("ArrayStoreException");
1658 }
1659 } else if (dst.class == nil || dst.class.super != nil || dst.dims > src.dims)
1660 sthrow("ArrayStoreException");
1661 if (sx < 0 || dx < 0 || n < 0 || sx + n > len src.holder || dx + n > len dst.holder || sx > 2147483647 - n || dx > 2147483647 - n)
1662 sthrow("ArrayIndexOutOfBoundsException");
1663 dst.holder[dx:] = sa[sx:sx + n];
1664}
1665
1666#
1667# Map a class and a interface cookie to a methodtable entry.
1668#
1669getinterface(c: ref Class, cookie: int) : int
1670{
1671 x := cookie >> 16;
1672 t := cookie & 16rFFFF;
1673 if (x >= ninterfaces)
1674 error("bad interface number");
1675 k := interfaces[x];
1676 m := c.getinterface(k);
1677 if (m == nil)
1678 error(sys->sprint("class %s does not implement interface %s", c.name, k.name));
1679 if (t >= len m)
1680 error("bad interface index");
1681 return m[t];
1682}
1683
1684#
1685# Math.
1686#
1687
1688lcmp(x, y: big): int
1689{
1690 if(x < y)
1691 return -1;
1692 if(x == y)
1693 return 0;
1694 return 1;
1695}
1696
1697truncate(x: real): real
1698{
1699 if (x < 0.0)
1700 x = math->ceil(x);
1701 else
1702 x = math->floor(x);
1703 return x;
1704}
1705
1706d2i(x: real): int
1707{
1708 return int truncate(x);
1709}
1710
1711d2l(x: real): big
1712{
1713 return big truncate(x);
1714}
1715
1716dcmpg(x, y: real): int
1717{
1718 if (math->isnan(x) || math->isnan(y) || x > y)
1719 return 1;
1720 if (x == y)
1721 return 0;
1722 return -1;
1723}
1724
1725dcmpl(x, y: real): int
1726{
1727 if (math->isnan(x) || math->isnan(y) || x < y)
1728 return -1;
1729 if (x == y)
1730 return 0;
1731 return 1;
1732}
1733
1734drem(x, y: real): real
1735{
1736 if (math->isnan(x) || math->isnan(y) || !math->finite(x) || y == 0.0)
1737 return math->NaN;
1738 if ((math->finite(x) && !math->finite(y)) || (x == 0.0 && math->finite(y)))
1739 return x;
1740 return math->fmod(x, y);
1741}
1742
1743#
1744# Class entries.
1745#
1746
1747Class.run(c: self ref Class, args: list of string)
1748{
1749 m := c.findsmethod(MAINFIELD, MAINSIGNATURE);
1750 if (m == nil)
1751 loaderror( nosuchmethod, sys->sprint("%s: missing static method main", c.name));
1752 main = c;
1753 if (arrayclass == nil)
1754 loadarrayclass();
1755 if (stringclass == nil)
1756 loadstringclass();
1757 n := len args;
1758 h := array[n] of ref JavaString;
1759 d := stringclass.moddata;
1760 for (i := 0; i < n; i++) {
1761 h[i] = ref JavaString(d, hd args);
1762 args = tl args;
1763 }
1764 #c.xeq(m.value, ref Array(arraymd, h, 1, stringclass, 0));
1765 getthreaddata();
1766 r := jassist->mcalla(c.mod, m.value, ref Array(arraymd, h, 1, stringclass, 0));
1767 delthreaddata();
1768}
1769
1770
1771Class.new(c: self ref Class): ref Object
1772{
1773 o := jassist->new(c.mod, c.objtype);
1774 o.mod = c.moddata;
1775 f := findasig(c.initmethods, VOIDSIGNATURE);
1776 if (f == nil)
1777 error(sys->sprint("%s: %s: missing constructor", nosuchmethod, c.name));
1778 c.call(f.value, o);
1779 return o;
1780}
1781
1782Class.call(c: self ref Class, x: int, a: ref Object): ref Object
1783{
1784 if (x < 0 || x >= c.mlinks)
1785 raise badcallindex;
1786 return jassist->mcall1(c.mod, x, a);
1787}
1788
1789Class.clone(c: self ref Class, o: ref Object): ref Object
1790{
1791 if (c.cloneindex < 0)
1792 raise nocloneindex;
1793 return jassist->mcall1(c.mod, c.cloneindex, o);
1794}
1795
1796#
1797# Class private methods.
1798#
1799
1800#
1801# Load a class file.
1802#
1803Class.loadclass(c: self ref Class)
1804{
1805 c.encoding = encodename(c.name);
1806 f := c.encoding + ".dis";
1807 m := load Nilmod f;
1808 if (m == nil) {
1809 e := sys->sprint("%r");
1810 if (!matches(e, EXIST))
1811 error(f + ": " + e);
1812 f = ROOT + f;
1813 m = load Nilmod f;
1814 if (m == nil) {
1815 e = sys->sprint("%r");
1816 m : string;
1817 if (!matches(e, EXIST))
1818 m = f + ": " + e;
1819 else
1820 m = c.name + ": class not found";
1821 loaderror(noclassdeffound, m);
1822 }
1823 }
1824 trace(JDEBUG, sys->sprint("\"%s\"", f));
1825 c.file = f;
1826 c.mod = m;
1827 if (getint(m, MAGIC) != JAVA)
1828 loaderror(classformat, f + ": bad magic number");
1829 c.version = getint(m, VERSION) & 16rFF;
1830 if (c.version != SUXV)
1831 loaderror(classformat, f + ": incompatible version (rerun j2d)");
1832 c.ownname = getstring(m, NAME);
1833 if (c.ownname != c.name && encodename(c.ownname) != c.name)
1834 warning("class file " + f + ": inconsistent classname: " + c.ownname);
1835}
1836
1837#
1838# The bulk of the work for loading a class is done here.
1839# This is the essentially the first (resolution) pass.
1840#
1841Class.resolve(c: self ref Class)
1842{
1843 od, vm, pm, sd, sm, im: list of ref Field;
1844 oz, vz, sz: int;
1845 cur = c.name;
1846 c.info.links = ld->link(c.mod);
1847 if (c.info.links == nil)
1848 error(sys->sprint("link failed: %r"));
1849 c.mlinks = len c.info.links;
1850 c.info.types = ld->tdesc(c.mod);
1851 if (c.info.types == nil)
1852 error(sys->sprint("tdesc failed: %r"));
1853 c.objtype = len c.info.types;
1854 c.cloneindex = -1;
1855 if (c.super != nil) {
1856 od = c.super.objectdata;
1857 vz = len c.super.virtualmethods;
1858 oz = c.super.objectsize;
1859 } else {
1860 od = nil;
1861 vz = 0;
1862 oz = WORDZ;
1863 }
1864 vm = nil;
1865 pm = nil;
1866 sd = nil;
1867 sm = nil;
1868 im = nil;
1869 sz = 0;
1870 r := getreloc(c.mod, RELOC);
1871 n := len r;
1872 p := array[n] of Patch;
1873 e := 0;
1874 for (i := 0; i < n; i++) {
1875 s := r[i].field;
1876 if (s[0] != '@')
1877 break;
1878 case s {
1879 CLASS =>
1880 p[i].what = PVALUE;
1881 p[i].value = c.objtype;
1882 c.flags = r[i].flags;
1883 MP or NP or ADT or OBJ =>
1884 p[i].what = PEXTRA;
1885 p[i].value = e++;
1886 JEX =>
1887 error("@jex not in @Loader");
1888 SYS =>
1889 error("@sys not in @Loader");
1890 }
1891 }
1892 for (; i < n; i++) {
1893 t := r[i];
1894 if (isdata(t.signature)) {
1895 if (isspecial(t.field))
1896 error(sys->sprint("unknown special data: %s", t.field));
1897 else if (isstatic(t.flags)) {
1898 trace(JDEBUG, sys->sprint("%s: static data", t.field));
1899 sz = alignto(sz, t.signature);
1900 p[i].what = PSTATIC;
1901 p[i].value = sz;
1902 f := ref Field(t.field, t.signature, t.flags, sz);
1903 sz += sizeof(t.signature);
1904 sd = f :: sd;
1905 } else {
1906 trace(JDEBUG, sys->sprint("%s: new data", t.field));
1907 oz = alignto(oz, t.signature);
1908 p[i].what = PVALUE;
1909 p[i].value = oz;
1910 f := ref Field(t.field, t.signature, t.flags, oz);
1911 od = f :: od;
1912 oz += sizeof(t.signature);
1913 }
1914 } else {
1915 if (isspecial(t.field)) {
1916 s := t.field;
1917 case s {
1918 SPECIALINIT =>
1919 if (isstatic(t.flags))
1920 error("<init> static");
1921 x := c.getmethod(s, t.signature, t.flags);
1922 if (t.flags & Rspecialmp) {
1923 p[i].what = PEXTRA;
1924 p[i].value = e++;
1925 } else {
1926 p[i].what = PVALUE;
1927 p[i].value = x;
1928 }
1929 if (findsig(im, t.signature) == nil)
1930 im = ref Field(s, t.signature, t.flags, x) :: im;
1931 SPECIALCLINIT or SPECIALCLONE =>
1932 if (!isstatic(t.flags))
1933 error(s + " not static");
1934 if (t.patch != nil)
1935 error(s + " patches");
1936 if (t.signature != VOIDSIGNATURE)
1937 error(s + " bad signature");
1938 if (isnative(t.flags))
1939 error(s + " is native");
1940 x := c.getmethod(s, t.signature, t.flags);
1941 if (s == SPECIALCLINIT)
1942 c.classinit = ref Field(s, t.signature, t.flags, x);
1943 else
1944 c.cloneindex = x;
1945 p[i].what = PVALUE;
1946 p[i].value = x;
1947 * =>
1948 error(sys->sprint("unknown special: %s", s));
1949 }
1950 } else if (isvirtual(t.flags)) {
1951 f := findfs(vm, t.field, t.signature);
1952 if (f == nil) {
1953 x := c.override(t.field, t.signature);
1954 if (x < 0) {
1955 trace(JDEBUG, sys->sprint("%s: new method", t.field));
1956 x = vz++;
1957 } else {
1958 trace(JDEBUG, sys->sprint("%s: overriden method", t.field));
1959 }
1960 f = ref Field(t.field, t.signature, t.flags, x);
1961 vm = f :: vm;
1962 }
1963 if (t.flags & Rspecialmp) {
1964 p[i].what = PVALUE;
1965 p[i].value = e++;
1966 } else {
1967 p[i].what = PMETHOD;
1968 p[i].value = f.value;
1969 }
1970 } else {
1971 trace(JDEBUG, sys->sprint("%s: static method", t.field));
1972 x := c.getmethod(t.field, t.signature, t.flags);
1973 f := ref Field(t.field, t.signature, t.flags, x);
1974 p[i].what = PVALUE;
1975 p[i].value = x;
1976 if (isstatic(t.flags)) {
1977 trace(JDEBUG, sys->sprint("%s: static method", t.field));
1978 sm = f :: sm;
1979 } else {
1980 trace(JDEBUG, sys->sprint("%s: private method", t.field));
1981 pm = f :: pm;
1982 }
1983 }
1984 }
1985 }
1986 if (c.flags & ACC_INTERFACE)
1987 c.addinterface();
1988 c.info.reloc = p;
1989 c.objectdata = od;
1990 c.virtualmethods = c.makevmtable(vm, vz);
1991 c.staticdata = mkfdarray(sd);
1992 c.staticmethods = mkfdarray(sm);
1993 c.privatemethods = mkfdarray(pm);
1994 c.initmethods = mkfdarray(im);
1995 c.objectsize = alignto(oz, nil);
1996 c.staticsize = alignto(sz, nil);
1997 c.info.extrabase = e;
1998 cur = nil;
1999}
2000
2001#
2002# Make a type for a class object.
2003#
2004Class.makeobjtype(c: self ref Class)
2005{
2006 z := ((c.objectsize / WORDZ) + 7) / 8;
2007 m := array[z] of byte;
2008 m[0] = byte 16r80;
2009 for (i := 1; i < z; i++)
2010 m[i] = byte 0;
2011 for (l := c.objectdata; l != nil; l = tl l) {
2012 f := hd l;
2013 if (ispointer(f.signature)) {
2014 v := f.value / WORDZ;
2015 x := v / 8;
2016 m[x] = byte ((int m[x]) | bits[v & 7]);
2017 }
2018 }
2019 c.objmap = m;
2020 if (ld->tnew(c.mod, c.objectsize, c.objmap) != c.objtype)
2021 error("objtype mismatch");
2022}
2023
2024#
2025# Make a virtual method table from that of the superclass
2026# and the overriden and new entries.
2027#
2028Class.makevmtable(c: self ref Class, m: list of ref Field, z: int): array of Method
2029{
2030 t := array[z] of Method;
2031 if (c.super != nil) {
2032 s := c.super.virtualmethods;
2033 n := len s;
2034 for (i := 0; i < n; i++)
2035 t[i] = s[i];
2036 }
2037 while (m != nil) {
2038 f := hd m;
2039 n := f.value;
2040 # TODO: check if we don't have this method in links, so just use parent class's one
2041 trace(JDEBUG, sys->sprint("Makevmtable for %s, %d", c.name, z));
2042 {
2043 f.value = c.getmethod(f.field, f.signature, f.flags);
2044 }
2045 exception e {
2046 JCLDREX + nosuchmethod + "*" =>
2047 ; # silently ignore
2048 }
2049 t[n].field = f;
2050 t[n].class = c;
2051 m = tl m;
2052 }
2053 return t;
2054}
2055
2056#
2057# Load the interfaces implemented by a class.
2058#
2059Class.loadinterfaces(c: self ref Class)
2060{
2061 s := getstrarray(c.mod, INTERFACES);
2062 if (s == nil)
2063 return;
2064 n := len s;
2065 trace(JDEBUG, sys->sprint("inter %s %d", c.name, n));
2066 l: list of ref Class;
2067 for (i := 0; i < n; i++)
2068 l = loadhierarchy(s[i]) :: l;
2069 c.interextends = l;
2070 if (c.flags & ACC_INTERFACE) {
2071 c.flags |= JCL_INTEREXT;
2072 interfx = c :: interfx;
2073 } else
2074 interf = c :: interf;
2075}
2076
2077#
2078# Add a class to a list.
2079#
2080addclass(c: ref Class, n: list of ref Class): list of ref Class
2081{
2082 for (l := n; l != nil; l = tl l)
2083 if (hd l == c)
2084 return n;
2085 return c :: n;
2086}
2087
2088#
2089# Extend list of interfaces.
2090#
2091interext(l: list of ref Class): list of ref Class
2092{
2093 n: list of ref Class;
2094 while (l != nil) {
2095 c := hd l;
2096 n = addclass(c, n);
2097 for (x := c.interextends; x != nil; x = tl x)
2098 n = addclass(hd x, n);
2099 l = tl l;
2100 }
2101 return n;
2102}
2103
2104#
2105# Extend (transitively) an interface.
2106#
2107intertrans(c: ref Class, n: list of ref Class): list of ref Class
2108{
2109 if (c.flags & JCL_INTERWORK)
2110 error("circular interface extension"); #ClassCircularityError ??
2111 n = addclass(c, n);
2112 c.extinterfaces();
2113 for (l := c.interextends; l != nil; l = tl l)
2114 n = addclass(hd l, n);
2115 return n;
2116}
2117
2118#
2119# Extend interfaces.
2120#
2121Class.extinterfaces(c: self ref Class)
2122{
2123 if ((c.flags & JCL_INTEREXT) == 0)
2124 return;
2125 c.flags |= JCL_INTERWORK;
2126 n: list of ref Class;
2127 for (l := c.interextends; l != nil; l = tl l)
2128 n = intertrans(hd l, n);
2129 c.interextends = n;
2130 c.flags &= ~(JCL_INTEREXT | JCL_INTERWORK);
2131}
2132
2133#
2134# Resolve the implementation of a class' interfaces.
2135#
2136Class.linkinterfaces(c: self ref Class)
2137{
2138 cur = c.name;
2139 l := interext(c.interextends);
2140 n := len l;
2141 a := array[n] of Interface;
2142 c.interfaces = a;
2143 for (i := 0; i < n; i++) {
2144 s := hd l;
2145 l = tl l;
2146 a[i].class = s;
2147 if ((s.flags & ACC_INTERFACE) == 0)
2148 loaderror(linkageerr, sys->sprint("%s not an interface", s.name));
2149 v := s.virtualmethods;
2150 m := len v;
2151 o := array[m] of int;
2152 a[i].methods = o;
2153 for (j := 0; j < m; j++) {
2154 f := v[j].field;
2155 x := findmfsx(c.virtualmethods, f.field, f.signature);
2156 if (x < 0)
2157 loaderror( nosuchmethod, sys->sprint("method %s'%s' of interface %s not implemented",
2158 f.field, f.signature, s.name));
2159 else
2160 o[j] = (METHODOFFSET + x * 2) * WORDZ;
2161 }
2162 }
2163 cur = nil;
2164}
2165
2166#
2167# This is the second pass of class loading. All classes needed for
2168# relocation have been resolved.
2169#
2170Class.relocate(c: self ref Class)
2171{
2172 cur = c.name;
2173 trace(JDEBUG, sys->sprint("relocate(%s) enter", c.name));
2174 #
2175 # Count extra entries (e.g. @mp and @adt).
2176 #
2177 n := nextra(getreloc(c.mod, RELOC));
2178 i := CLASSREF;
2179 while ((s := getstring(c.mod, i)) != nil) {
2180 n += nextra(getreloc(c.mod, i + WORDZ));
2181 i += 2 * WORDZ;
2182 }
2183 c.dataoffset = (i + 4 + 31) & ~31;
2184 c.nextra = n;
2185 #
2186 # Record extras.
2187 #
2188 c.info.extras = array[n] of Extra;
2189 n = c.extras(getreloc(c.mod, RELOC), 0, c);
2190 j := 0;
2191 i = CLASSREF;
2192 while ((s = getstring(c.mod, i)) != nil) {
2193 n = c.extras(getreloc(c.mod, i + WORDZ), n, c.refs[j]);
2194 i += 2 * WORDZ;
2195 j++;
2196 }
2197 #
2198 # Determine size of new module data.
2199 #
2200 v := len c.virtualmethods;
2201 z := METHODOFFSET * WORDZ + v * 2 * WORDZ + c.staticsize + c.nextra * WORDZ + WORDZ;
2202 c.datareloc = (z + 31) & ~31;
2203 c.datasize = getint(c.mod, DSIZE);
2204 c.modsize = c.datareloc + c.datasize;
2205 z = ((c.modsize / WORDZ) + 7) / 8;
2206 m := array[z] of byte;
2207 #
2208 # Create type map for module.
2209 #
2210 c.modmap = m;
2211 #
2212 # First two entries are nil and ref Class adt.
2213 #
2214 m[0] = byte 16rC0;
2215 for (i = 1; i < z; i++)
2216 m[i] = byte 0;
2217 #
2218 # Method table.
2219 #
2220 for (i = 1; i <= v; i++) {
2221 x := i / 4;
2222 m[x] = byte ((int m[x]) | mbits[i & 3]);
2223 }
2224 o := METHODOFFSET + v * 2;
2225 #
2226 # Static data.
2227 #
2228 c.staticoffset = o * WORDZ;
2229 d := c.staticdata;
2230 for (i = 0; i < len d; i++) {
2231 f := d[i];
2232 if (ispointer(f.signature)) {
2233 w := o + (f.value / WORDZ);
2234 x := w / 8;
2235 m[x] = byte ((int m[x]) | bits[w & 7]);
2236 }
2237 }
2238 o += c.staticsize / WORDZ;
2239 #
2240 # Extra data.
2241 #
2242 c.info.extraoffset = o * WORDZ;
2243 for (i = 0; i < c.nextra; i++) {
2244 x := o / 8;
2245 m[x] = byte ((int m[x]) | bits[o & 7]);
2246 o++;
2247 }
2248 #
2249 # Copy class module data and its map.
2250 #
2251 if (c.datasize > 0) {
2252 if (c.datasize + c.dataoffset > c.info.types[0].size) {
2253 error("bad data size/offset");
2254 c.datasize = 0;
2255 } else
2256 c.copymap(c.info.types[0].map, c.dataoffset);
2257 }
2258 trace(JDEBUG, sys->sprint("%s data %d reloc %d", c.name, c.modsize, c.datareloc));
2259 trace(JDEBUG, sys->sprint("\t%d bytes at %d", c.datasize, c.dataoffset));
2260 md := ld->dnew(c.modsize, c.modmap);
2261 if (md == nil)
2262 error(sys->sprint("dnew failed: %r"));
2263 c.moddata = md;
2264 c.this = ref ClassObject(nil, c, nil);
2265 #
2266 # Fetch the instruction stream and patch it.
2267 #
2268 instructions := ld->ifetch(c.mod);
2269 if (instructions == nil)
2270 error(sys->sprint("ifetch failed: %r"));
2271 c.instrpatch(instructions);
2272 trace(JDEBUG, sys->sprint("\t%d instrs", len instructions));
2273 #
2274 # Make the new module.
2275 #
2276 links := c.info.links;
2277 oldmod := c.mod;
2278 c.mod = ld->newmod(c.name, STACKSIZE, len links, instructions, md);
2279 if (c.mod == nil)
2280 error(sys->sprint("newmod failed: %r"));
2281 addmodclass(c.mod, c);
2282 #
2283 # Install the new types.
2284 #
2285 types := c.info.types;
2286 for (i = 1; i < len types; i++) {
2287 if (ld->tnew(c.mod, types[i].size, types[i].map) != i)
2288 error(sys->sprint("tnew failed: %r"));
2289 }
2290 #
2291 # Install the links.
2292 #
2293 for (i = 0; i < len links; i++) {
2294 if (ld->ext(c.mod, i, links[i].pc, links[i].tdesc) < 0)
2295 error(sys->sprint("ext failed: %r"));
2296 }
2297 #
2298 # This word is used by rtload.
2299 #
2300 putint(md, c.datareloc - WORDZ, c.datareloc);
2301 if (c.datasize > 0)
2302 c.copymd(md, c.dataoffset, oldmod);
2303 c.makeobjtype();
2304 trace(JDEBUG, sys->sprint("relocate(%s) exit", c.name));
2305 cur = nil;
2306}
2307
2308#
2309# Instruction patching.
2310#
2311Class.instrpatch(c: self ref Class, inst: array of Loader->Inst)
2312{
2313 #
2314 # A class' own relocations were determined in resolve.
2315 #
2316 r := getreloc(c.mod, RELOC);
2317 p := c.info.reloc;
2318 x := c.info.extraoffset;
2319 n := len r;
2320 for (i := 0; i < n; i++) {
2321 v: int;
2322 case p[i].what {
2323 PVALUE =>
2324 v = p[i].value;
2325 PEXTRA =>
2326 v = x + p[i].value * WORDZ;
2327 PMETHOD =>
2328 v = (METHODOFFSET + p[i].value * 2) * WORDZ;
2329 PSTATIC =>
2330 v = c.staticoffset + p[i].value;
2331 * =>
2332 error("bad Patch");
2333 }
2334 ipatch(inst, r[i].patch, v);
2335 }
2336 x += c.info.extrabase * WORDZ;
2337 #
2338 # Data relocation.
2339 #
2340 ipatch(inst, getbytearray(c.mod, DRELOC), c.datareloc);
2341 #
2342 # Patching for referenced classes (and @Loader).
2343 #
2344 j := 0;
2345 i = CLASSREF;
2346 while ((s := getstring(c.mod, i)) != nil) {
2347 k := c.refs[j];
2348 if (k != nil)
2349 x = k.relocref(c, inst, getreloc(c.mod, i + WORDZ), x);
2350 else
2351 x = relocloader(inst, getreloc(c.mod, i + WORDZ), x);
2352 i += 2 * WORDZ;
2353 j++;
2354 }
2355}
2356
2357#
2358# Third pass of class loader. All referenced classes
2359# have had new modules allocated.
2360#
2361Class.modpatch(c: self ref Class)
2362{
2363 cur = c.name;
2364 d := c.moddata;
2365 putclass(d, CLASSADTOFFSET, c);
2366 v := c.virtualmethods;
2367 n := len v;
2368 o := METHODOFFSET * WORDZ;
2369 for (i := 0; i < n; i++) {
2370 m := v[i];
2371 if (isnative(m.field.flags))
2372 putmod(d, o, m.class.native);
2373 else
2374 putmod(d, o, m.class.mod);
2375 putint(d, o + WORDZ, m.field.value);
2376 o += 2 * WORDZ;
2377 }
2378 x := c.info.extras;
2379 n = len x;
2380 o = c.info.extraoffset;
2381 for (i = 0; i < n; i++) {
2382 e := x[i];
2383 case e.what {
2384 CMP =>
2385 if (e.class == nil)
2386 putmod(d, o, thisnil);
2387 else
2388 putmod(d, o, e.class.mod);
2389 CADT =>
2390 putclass(d, o, e.class);
2391 CNP =>
2392 putmod(d, o, e.class.native);
2393 COBJ =>
2394 putobj(d, o, e.class.this);
2395 CJEX =>
2396 putstring(d, o, JAVAEXCEPTION);
2397 CSYS =>
2398 putmod(d, o, sysnil);
2399 * =>
2400 error("bad extra what");
2401 }
2402 o += WORDZ;
2403 }
2404 trace(JDEBUG, sys->sprint("compile %s", c.name));
2405 if ((c.flags & DONTCOMPILE) == 0) {
2406 if (ld->compile(c.mod, c.flags & MUSTCOMPILE) < 0)
2407 error(sys->sprint("compile %s failed: %r", c.name));
2408 if (c.native != nil) {
2409 trace(JDEBUG, sys->sprint("compile native %s", c.name));
2410 if (ld->compile(c.native, c.flags & MUSTCOMPILE) < 0)
2411 error(sys->sprint("compile native %s failed: %r", c.name));
2412 }
2413 }
2414 cur = nil;
2415}
2416
2417#
2418# Resolution routines.
2419#
2420
2421#
2422# Check for method override.
2423#
2424Class.override(c: self ref Class, f, s: string): int
2425{
2426 if (c.super == nil)
2427 return -1;
2428 m := c.super.virtualmethods;
2429 n := len m;
2430 for (i := 0; i < n; i++) {
2431 t := m[i].field;
2432 if (t.field == f && t.signature == s)
2433 return i;
2434 }
2435 return -1;
2436}
2437
2438#
2439# Find init method.
2440#
2441Class.findimethod(c: self ref Class, s: string): ref Field
2442{
2443 return findasig(c.initmethods, s);
2444}
2445
2446#
2447# Find private method.
2448#
2449Class.findpmethod(c: self ref Class, f, s: string): ref Field
2450{
2451 return findafs(c.privatemethods, f, s);
2452}
2453
2454#
2455# Find static field.
2456#
2457Class.findsfield(c: self ref Class, f: string): ref Field
2458{
2459 return findafield(c.staticdata, f);
2460}
2461
2462#
2463# Find static method.
2464#
2465Class.findsmethod(c: self ref Class, f, s: string): ref Field
2466{
2467 return findafs(c.staticmethods, f, s);
2468}
2469
2470#
2471# Find object field.
2472#
2473Class.findofield(c: self ref Class, f: string): ref Field
2474{
2475 return findfield(c.objectdata, f);
2476}
2477
2478#
2479# Find virtual method.
2480#
2481Class.findvmethod(c: self ref Class, f, s: string): int
2482{
2483 a := c.virtualmethods;
2484 n := len a;
2485 if (c.name == "java/lang/StringBuffer") {
2486 trace(JDEBUG, sys->sprint("Class: %s, virtual methods: %d", c.name, n));
2487 trace(JDEBUG, sys->sprint("Started looking for method: %s, %s", f, s));
2488 statenames := array [] of {"NEW", "HIER", "RESOLVE", "LOADED", "INITED"};
2489 trace(JDEBUG, sys->sprint("Class state: %s", statenames[c.state]));
2490 }
2491 for (i := 0; i < n; i++) {
2492 t := a[i].field;
2493 if (t.field == f && t.signature == s)
2494 return i;
2495 }
2496 trace(JDEBUG, "returned fail");
2497 return -1;
2498}
2499
2500Class.loadnative(c: self ref Class)
2501{
2502 native := ROOT + c.encoding + "_L.dis";
2503 mod := load Nilmod native;
2504 if (mod == nil) {
2505 trace(JVERBOSE, sys->sprint("Load native failed: %r"));
2506 return;
2507 }
2508 trace(JDEBUG, sys->sprint("\"%s\"", native));
2509 links := ld->link(mod);
2510 if (links == nil)
2511 error(sys->sprint("%s: native Loader->link failed: %r", unsatisfiedlink));
2512 c.info.nlinks = links;
2513 types := ld->tdesc(mod);
2514 if (types == nil)
2515 error(sys->sprint("%s: native tdesc failed: %r",unsatisfiedlink));
2516 instrs := ld->ifetch(mod);
2517 if (instrs == nil)
2518 error(sys->sprint("%s: native ifetch failed: %r",unsatisfiedlink));
2519 nm := ld->newmod("N-" + c.name, STACKSIZE, len links, instrs, getmd(mod));
2520 if (nm == nil)
2521 error(sys->sprint("%s: native newmod failed: %r",unsatisfiedlink));
2522 n := len types;
2523 for (i := 1; i < n; i++) {
2524 if (ld->tnew(nm, types[i].size, types[i].map) != i)
2525 error(sys->sprint("%s: native tnew failed: %r",unsatisfiedlink));
2526 }
2527 n = len links;
2528 for (i = 0; i < n; i++) {
2529 if (ld->ext(nm, i, links[i].pc, links[i].tdesc) < 0)
2530 error(sys->sprint("%s: native ext failed: %r",unsatisfiedlink));
2531 }
2532 addmodclass(nm, c);
2533 c.native = nm;
2534}
2535
2536#
2537# Search the links for a method. Maybe load the native module.
2538#
2539Class.getmethod(c: self ref Class, f, s: string, flags: int): int
2540{
2541 trace(JDEBUG, sys->sprint("Getmethod of %s: %s, %s, %d", c.name, f, s, flags));
2542 l: array of Loader->Link;
2543 m: string;
2544 if (isnative(flags)) {
2545 if (c.native == nil)
2546 c.loadnative();
2547 l = c.info.nlinks;
2548 m = mangle(f, s);
2549 } else {
2550 l = c.info.links;
2551 m = f + s;
2552 }
2553 n := len l;
2554 for (i := 0; i < n; i++) {
2555 if (l[i].name == m)
2556 return i;
2557 }
2558 if (!(flags & (ACC_ABSTRACT | ACC_NATIVE)))
2559 {
2560 loaderror( nosuchmethod, sys->sprint("method %x %s '%s' %s not found", flags, f, s, m) );
2561 }
2562 return -1;
2563}
2564
2565#
2566# Find method called with invokespecial.
2567#
2568Class.special(c: self ref Class, f, s: string, flags: int, r: ref Class): (int, ref Class, int)
2569{
2570 if (f == SPECIALINIT) {
2571 i := findasig(r.initmethods, s);
2572 if (i == nil)
2573 error(sys->sprint("%s: <init> '%s' not found in class %s", nosuchmethod, s, r.name));
2574 return (CMP, r, i.value);
2575 } else if (isprivate(flags)) {
2576 p := findafs(r.privatemethods, f, s);
2577 if (p == nil)
2578 error("invokespecial private botch");
2579 if (isnative(p.flags))
2580 return (CNP, r, p.value);
2581 else
2582 return (CMP, r, p.value);
2583 } else {
2584 r = c.super;
2585 if (r == nil)
2586 error("invokespecial super botch");
2587 i := r.findvmethod(f, s);
2588 if (i < 0)
2589 error("invokespecial botch");
2590 m := r.virtualmethods[i];
2591 if (isnative(m.field.flags))
2592 return (CNP, m.class, m.field.value);
2593 else
2594 return (CMP, m.class, m.field.value);
2595 }
2596}
2597
2598#
2599# Record info for an extra.
2600#
2601Class.extra(c: self ref Class, w, n: int, r: ref Class)
2602{
2603 c.info.extras[n].what = w;
2604 c.info.extras[n].class = r;
2605}
2606
2607#
2608# Record info for extras.
2609#
2610Class.extras(c: self ref Class, a: array of Reloc, n: int, r: ref Class): int
2611{
2612 l := len a;
2613 for (i := 0; i < l; i++) {
2614 f := a[i].field;
2615 if (f[0] != '@')
2616 break;
2617 case f {
2618 MP =>
2619 c.extra(CMP, n, r);
2620 ADT =>
2621 c.extra(CADT, n, r);
2622 NP =>
2623 c.extra(CNP, n, r);
2624 OBJ =>
2625 c.extra(COBJ, n, r);
2626 JEX =>
2627 if (r != nil)
2628 error("@jex not in @Loader");
2629 c.extra(CJEX, n, nil);
2630 SYS =>
2631 if (r != nil)
2632 error("@sys not in @Loader");
2633 c.extra(CSYS, n, nil);
2634 CLASS =>
2635 n--;
2636 * =>
2637 error(sys->sprint("unknown reloc: %s", f));
2638 }
2639 n++;
2640 }
2641 for (; i < l; i++) {
2642 if (a[i].flags & Rspecialmp) {
2643 if ((a[i].flags & Rmask) != Rinvokespecial)
2644 error("bad Rspecialmp");
2645 (v, s, nil) := c.special(a[i].field, a[i].signature, a[i].flags, r);
2646 c.extra(v, n, s);
2647 n++;
2648 }
2649 }
2650 return n;
2651}
2652
2653#
2654# Count the extra data fields need for a Reloc.
2655#
2656nextra(a: array of Reloc): int
2657{
2658 n := 0;
2659 l := len a;
2660 for (i := 0; i < l; i++) {
2661 f := a[i].field;
2662 if (f[0] != '@')
2663 break;
2664 case f {
2665 MP or NP or ADT or OBJ or JEX or SYS =>
2666 n++;
2667 }
2668 }
2669 for (; i < l; i++) {
2670 if (a[i].flags & Rspecialmp)
2671 n++;
2672 }
2673 return n;
2674}
2675
2676#
2677# Copy old module map corresponding to module data to new map.
2678#
2679Class.copymap(c: self ref Class, om: array of byte, dr: int)
2680{
2681 nm := c.modmap;
2682 s := dr / MAPZ;
2683 d := c.datareloc / MAPZ;
2684 while (d < len nm) {
2685 if (s < len om)
2686 nm[d] = om[s];
2687 else
2688 nm[d] = byte 0;
2689 s++;
2690 d++;
2691 }
2692}
2693
2694#
2695# Copy old module data to new module data.
2696#
2697Class.copymd(c: self ref Class, md: ref Niladt, dr: int, om: Nilmod)
2698{
2699 m := c.modmap;
2700 s := dr;
2701 d := c.datareloc;
2702 for (i := 0; i < c.datasize; i+= WORDZ) {
2703 w := d / WORDZ;
2704 if ((int m[w / 8] & bits[w & 7]) != 0)
2705 putptr(md, d, getptr(om, s));
2706 else
2707 putint(md, d, getint(om, s));
2708 d += WORDZ;
2709 s += WORDZ;
2710 }
2711}
2712
2713#
2714# Resolve a relocation for a referenced class.
2715#
2716Class.resolvereloc(c: self ref Class, r, s: string, flags: int): (int, int)
2717{
2718 v: int;
2719 f: ref Field;
2720 case flags & Rmask {
2721 Rgetputfield =>
2722 f = findfield(c.objectdata, r);
2723 if (f == nil)
2724 loaderror(nosuchfield, sys->sprint("%s not resolved in class %s", r, c.name));
2725 else {
2726 if (f.signature != s) {
2727 loaderror(nosuchfield, sys->sprint("%s type mismatch in class %s:%s vs %s", r, c.name, f.signature, s));
2728 }
2729 v = f.value;
2730 }
2731 Rgetputstatic =>
2732 f = c.findsfield(r);
2733 if (f == nil)
2734 loaderror( nosuchfield, sys->sprint("static %s not found in class %s", r, c.name));
2735 else {
2736 if (f.signature != s) {
2737 loaderror(nosuchfield, sys->sprint("%s static type mismatch in class %s:%s vs %s", r, c.name, f.signature, s));
2738 }
2739 v = c.staticoffset + f.value;
2740 }
2741 Rinvokeinterface =>
2742 if ((c.flags & ACC_INTERFACE) == 0) {
2743 loaderror(linkageerr, sys->sprint("%s is not an interface", c.name));
2744 break;
2745 }
2746 v = findmfsx(c.virtualmethods, r, s);
2747 if (v < 0)
2748 loaderror( nosuchmethod, sys->sprint("interface method %s '%s' not found in class %s", r, s, c.name));
2749 v |= c.interindex << 16;
2750 Rinvokespecial =>
2751 error("Rinvokespecial botch");
2752 Rinvokestatic =>
2753 f = c.findsmethod(r, s);
2754 if (f == nil)
2755 loaderror( nosuchmethod, sys->sprint("static method %s '%s' not found in class %s", r, s, c.name));
2756 else if (flags & Rstaticmp) {
2757 if (f.flags & ACC_NATIVE)
2758 return (VNP, 0);
2759 else
2760 return (VMP, 0);
2761 } else
2762 v = f.value;
2763 Rinvokevirtual =>
2764 v = c.findvmethod(r, s);
2765 if (v < 0)
2766 loaderror( nosuchmethod, sys->sprint("method %s '%s' not resolved in class %s", r, s, c.name));
2767 v = (METHODOFFSET + v * 2) * WORDZ;
2768 * =>
2769 if (r == OBJ)
2770 return (VOBJ, 0);
2771 error(sys->sprint("%s: bad Rmask", c.name));
2772 }
2773 return (VVAL, v);
2774}
2775
2776#
2777# Perform relocation for a referenced class.
2778#
2779Class.relocref(c: self ref Class, t: ref Class, inst: array of Loader->Inst, a: array of Reloc, x: int): int
2780{
2781 v, w: int;
2782 mp := -1;
2783 np := -1;
2784 n := len a;
2785 for (i := 0; i < n; i++) {
2786 f := a[i].field;
2787 if (f[0] != '@')
2788 break;
2789 case f {
2790 MP =>
2791 if (mp >= 0)
2792 error("repeat @mp");
2793 mp = x;
2794 v = x;
2795 x += WORDZ;
2796 NP =>
2797 if (np >= 0)
2798 error("repeat @np");
2799 np = x;
2800 v = x;
2801 x += WORDZ;
2802 ADT =>
2803 v = x;
2804 x += WORDZ;
2805 OBJ =>
2806 v = x;
2807 x += WORDZ;
2808 JEX =>
2809 error("@jex not in @Loader");
2810 SYS =>
2811 error("@sys not in @Loader");
2812 CLASS =>
2813 v = c.objtype;
2814 * =>
2815 error("@botch");
2816 }
2817 ipatch(inst, a[i].patch, v);
2818 }
2819 for (; i < n; i++) {
2820 if ((a[i].flags & Rmask) == Rinvokespecial) {
2821 if (a[i].flags & Rspecialmp) {
2822 v = x;
2823 x += WORDZ;
2824 } else
2825 (nil, nil, v) = t.special(a[i].field, a[i].signature, a[i].flags, c);
2826 } else {
2827 (w, v) = c.resolvereloc(a[i].field, a[i].signature, a[i].flags);
2828 if (w == VMP) {
2829 if (mp < 0)
2830 error("no @mp for Rstaticmp");
2831 v = mp;
2832 } else if (w == VNP) {
2833 if (np < 0)
2834 error("no @np for Rstaticmp");
2835 v = np;
2836 }
2837 }
2838 ipatch(inst, a[i].patch, v);
2839 }
2840 return x;
2841}
2842
2843#
2844# Record an interface and assign it an ordinal.
2845#
2846Class.addinterface(c: self ref Class)
2847{
2848 if (ninterfaces == linterfaces) {
2849 if (ninterfaces == 0) {
2850 linterfaces = INITINTER;
2851 interfaces = array[INITINTER] of ref Class;
2852 } else {
2853 n := linterfaces * 3 / 2;
2854 a := array[n] of ref Class;
2855 for (i := 0; i < linterfaces; i++)
2856 a[i] = interfaces[i];
2857 linterfaces = n;
2858 interfaces = a;
2859 }
2860 }
2861 c.interindex = ninterfaces;
2862 interfaces[ninterfaces++] = c;
2863}
2864
2865#
2866# Search for an interface implementation.
2867#
2868Class.interlook(c: self ref Class, a: array of Interface): array of int
2869{
2870 if (a == nil)
2871 return nil;
2872 n := len a;
2873 for (i := 0; i < n; i++) {
2874 d := a[i].class;
2875 do {
2876 if (d == c)
2877 return a[i].methods;
2878 d = d.super;
2879 } while (d != nil);
2880 }
2881 return nil;
2882}
2883
2884#
2885# Fetch interface table, possibly cached.
2886#
2887Class.getinterface(c: self ref Class, k: ref Class): array of int
2888{
2889 for (l := c.intercache; l != nil; l = tl l) {
2890 (d, m) := hd l;
2891 if (d == k)
2892 return m;
2893 }
2894 m: array of int;
2895 d := c;
2896 do {
2897 m = k.interlook(d.interfaces);
2898 d = d.super;
2899 } while (m == nil && d != nil);
2900 if (m != nil) {
2901 c.intercache = (k, m) :: c.intercache;
2902 return m;
2903 }
2904 return nil;
2905}
2906
2907#
2908# Call native module init function.
2909#
2910Class.initjni(c: self ref Class)
2911{
2912 trace(JVERBOSE, sys->sprint("%s->init()", c.name));
2913 l := c.info.nlinks;
2914 n := len l;
2915 for (i := 0; i < n; i++) {
2916 if (l[i].name == "init") {
2917 if (l[i].sig != jnisig)
2918 error(sys->sprint("init typecheck in class %s native", c.name));
2919 jassist->mcallm(c.native, i, jninil);
2920 trace(JDEBUG, "done");
2921 return;
2922 }
2923 }
2924 error(sys->sprint("no init function in class %s native", c.name));
2925}
2926
2927#
2928# @Loader relocation.
2929#
2930relocloader(inst: array of Loader->Inst, a: array of Reloc, x: int): int
2931{
2932 v: int;
2933 n := len a;
2934 for (i := 0; i < n; i++) {
2935 r := a[i].field;
2936 case r {
2937 MP or JEX or SYS =>
2938 v = x;
2939 x += WORDZ;
2940 CLASS =>
2941 error("@Loader @Class");
2942 ADT =>
2943 error("@Loader @adt");
2944 NP =>
2945 error("@Loader @np");
2946 OBJ =>
2947 error("@Loader @obj");
2948 * =>
2949 v = getloader(r);
2950 if (v < 0)
2951 error(sys->sprint("no ClassLoader/Sys entry %s", r));
2952 }
2953 ipatch(inst, a[i].patch, v);
2954 }
2955 return x;
2956}
2957
2958#
2959# @Loader and @Sys entries.
2960# This uses a magic hash which maps each loadkey to a unique index.
2961# If you add a loadkey you will need new magic.
2962#
2963
2964LDHASH: con 38;
2965
2966LoadMap: adt
2967{
2968 name: string;
2969 value: int;
2970};
2971
2972loadtable := array[LDHASH] of LoadMap;
2973
2974loadkeys := array[] of
2975{
2976 "aastorecheck",
2977 "acheckcast",
2978 "ainstanceof",
2979 "checkcast",
2980 "culprit",
2981 "d2i",
2982 "d2l",
2983 "dcmpg",
2984 "dcmpl",
2985 "drem",
2986 "getinterface",
2987 "instanceof",
2988 "lcmp",
2989 "monitorenter",
2990 "monitorexit",
2991 "multianewarray",
2992 "pcheckcast",
2993 "pinstanceof",
2994 "raise",
2995 "rescue",
2996 "rtload",
2997 "throw",
2998 "unrescue",
2999};
3000
3001#
3002# This function maps the above 23 strings to unique integers from 0 to 37.
3003#
3004loadhash(s: string): int
3005{
3006 return ((s[len s - 1] + 49) * len s + 19 * s[0]) % LDHASH;
3007}
3008
3009loadenter(s: string, x: int)
3010{
3011 n := loadhash(s);
3012 if (loadtable[n].name == s)
3013 loadtable[n].value = x;
3014}
3015
3016initloadhash()
3017{
3018 n := len loadkeys;
3019 for (i := 0; i < n; i++) {
3020 s := loadkeys[i];
3021 loadtable[loadhash(s)].name = s;
3022 }
3023 a := loadlinks;
3024 n = len a;
3025 for (i = 0; i < n; i++)
3026 loadenter(a[i].name, i);
3027 a = syslinks;
3028 n = len a;
3029 for (i = 0; i < n; i++)
3030 loadenter(a[i].name, i);
3031}
3032
3033#
3034# Map a string to a @Loader or @Sys index.
3035#
3036getloader(s: string): int
3037{
3038 n := loadhash(s);
3039 if (loadtable[n].name != s)
3040 error("getloader botch");
3041 return loadtable[n].value;
3042}
3043
3044#
3045# Get Class adt from an object.
3046#
3047Object.class(o: self ref Object): ref Class
3048{
3049 return getclassadt(o.mod, CLASSADTOFFSET);
3050}
3051
3052#
3053# Categorizers.
3054#
3055isdata(sig: string): int
3056{
3057 return sig[0] != '(';
3058}
3059
3060isspecial(field: string): int
3061{
3062 return field[0] == '<';
3063}
3064
3065ispointer(sig: string): int
3066{
3067 case sig[0] {
3068 'L' or '[' =>
3069 return 1;
3070 }
3071 return 0;
3072}
3073
3074isprivate(flags: int): int
3075{
3076 return flags & ACC_PRIVATE;
3077}
3078
3079isstatic(flags: int): int
3080{
3081 return flags & ACC_STATIC;
3082}
3083
3084isnative(flags: int): int
3085{
3086 return flags & ACC_NATIVE;
3087}
3088
3089isvirtual(flags: int): int
3090{
3091 return (flags & (ACC_PRIVATE | ACC_STATIC)) == 0;
3092}
3093
3094isabstract(flags: int): int
3095{
3096 return flags & ACC_ABSTRACT;
3097}
3098
3099#
3100# Type alignment.
3101#
3102alignto(sz: int, sig: string): int
3103{
3104 a: int;
3105 if (sig == nil)
3106 a = WORDZ;
3107 else {
3108 a = sizeof(sig);
3109 if (a == 1)
3110 return sz;
3111 }
3112 a--;
3113 return (sz + a) & ~a;
3114}
3115
3116#
3117# Type size.
3118#
3119sizeof(sig: string): int
3120{
3121 case sig[0] {
3122 'Z' or 'B' =>
3123 return 1;
3124 'D' or 'J' or 'F' =>
3125 return 2 * WORDZ;
3126 'C' or 'S' or 'I' or 'L' or '[' =>
3127 return WORDZ;
3128 }
3129 warning("unknown size: " + sig);
3130 return WORDZ;
3131}
3132
3133#
3134# Utilities.
3135#
3136
3137mkclarray(l: list of ref Class): array of ref Class
3138{
3139 n := len l;
3140 a := array[n] of ref Class;
3141 while (--n >= 0) {
3142 a[n] = hd l;
3143 l = tl l;
3144 }
3145 return a;
3146}
3147
3148mkfdarray(l: list of ref Field): array of ref Field
3149{
3150 n := len l;
3151 a := array[n] of ref Field;
3152 while (--n >= 0) {
3153 a[n] = hd l;
3154 l = tl l;
3155 }
3156 return a;
3157}
3158
3159findfield(l: list of ref Field, f: string): ref Field
3160{
3161 while (l != nil) {
3162 h := hd l;
3163 if (h.field == f)
3164 return h;
3165 l = tl l;
3166 }
3167 return nil;
3168}
3169
3170findsig(l: list of ref Field, s: string): ref Field
3171{
3172 while (l != nil) {
3173 h := hd l;
3174 if (h.signature == s)
3175 return h;
3176 l = tl l;
3177 }
3178 return nil;
3179}
3180
3181findfs(l: list of ref Field, f, s: string): ref Field
3182{
3183 while (l != nil) {
3184 h := hd l;
3185 if (h.field == f && h.signature == s)
3186 return h;
3187 l = tl l;
3188 }
3189 return nil;
3190}
3191
3192findafield(a: array of ref Field, f: string): ref Field
3193{
3194 n := len a;
3195 for (i := 0; i < n; i++) {
3196 if (a[i].field == f)
3197 return a[i];
3198 }
3199 return nil;
3200}
3201
3202findasig(a: array of ref Field, s: string): ref Field
3203{
3204 n := len a;
3205 for (i := 0; i < n; i++) {
3206 if (a[i].signature == s)
3207 return a[i];
3208 }
3209 return nil;
3210}
3211
3212findafs(a: array of ref Field, f, s: string): ref Field
3213{
3214 n := len a;
3215 for (i := 0; i < n; i++) {
3216 if (a[i].field == f && a[i].signature == s)
3217 return a[i];
3218 }
3219 return nil;
3220}
3221
3222findmfsx(a: array of Method, f, s: string): int
3223{
3224 n := len a;
3225 for (i := 0; i < n; i++) {
3226 t := a[i].field;
3227 if (t.field == f && t.signature == s)
3228 return i;
3229 }
3230 return -1;
3231}
3232
3233#
3234# Patch an instruction.
3235#
3236ipatch(inst: array of Loader->Inst, p: array of byte, d: int)
3237{
3238 v: int;
3239 l := len inst;
3240 n := len p;
3241 x := 0;
3242 if (fsindir) {
3243 for (i := 0; i < n; i++) {
3244 t := int p[i];
3245 if (t & RDELTA) {
3246 x += (256 - t) << 3;
3247 continue;
3248 }
3249 x += t >> ISHIFT;
3250 if (x < 0 || x >= l)
3251 error("bad inst index");
3252 if (inst[x].op == byte 57 && inst[x].mid == 0) {
3253 trace(JVERBOSE, sys->sprint("Skipping instruction %d", x));
3254 continue;
3255 }
3256 case t & (POP | PTYPE) {
3257 PSRC | PIMM or PSRC | PSIND =>
3258 inst[x].src += d;
3259 PSRC | PDIND1 =>
3260 v = inst[x].src;
3261 inst[x].src = (v & int 16rFFFF0000) | ((v & 16rFFFF) + d);
3262 PSRC | PDIND2 =>
3263 v = inst[x].src;
3264 inst[x].src = (v & 16rFFFF) | ((v & int 16rFFFF0000) + (d << 16));
3265 PMID | PIMM or PMID | PSIND =>
3266 inst[x].mid += d;
3267 PDST | PIMM or PDST | PSIND =>
3268 inst[x].dst += d;
3269 PDST | PDIND1 =>
3270 v = inst[x].dst;
3271 inst[x].dst = (v & int 16rFFFF0000) | ((v & 16rFFFF) + d);
3272 PDST | PDIND2 =>
3273 v = inst[x].dst;
3274 inst[x].dst = (v & 16rFFFF) | ((v & int 16rFFFF0000) + (d << 16));
3275 * =>
3276 error("bad reloc");
3277 }
3278 }
3279 } else {
3280 for (i := 0; i < n; i++) {
3281 t := int p[i];
3282 if (t & RDELTA) {
3283 x += (256 - t) << 3;
3284 continue;
3285 }
3286 x += t >> ISHIFT;
3287 if (x < 0 || x >= l)
3288 error("bad inst index");
3289 case t & (POP | PTYPE) {
3290 PSRC | PIMM or PSRC | PSIND =>
3291 inst[x].src += d;
3292 PSRC | PDIND1 =>
3293 v = inst[x].src;
3294 inst[x].src = (v & 16rFFFF) | ((v & int 16rFFFF0000) + (d << 16));
3295 PSRC | PDIND2 =>
3296 v = inst[x].src;
3297 inst[x].src = (v & int 16rFFFF0000) | ((v & 16rFFFF) + d);
3298 PMID | PIMM or PMID | PSIND =>
3299 inst[x].mid += d;
3300 PDST | PIMM or PDST | PSIND =>
3301 inst[x].dst += d;
3302 PDST | PDIND1 =>
3303 v = inst[x].dst;
3304 inst[x].dst = (v & 16rFFFF) | ((v & int 16rFFFF0000) + (d << 16));
3305 PDST | PDIND2 =>
3306 v = inst[x].dst;
3307 inst[x].dst = (v & int 16rFFFF0000) | ((v & 16rFFFF) + d);
3308 * =>
3309 error("bad POP");
3310 }
3311 }
3312 }
3313}
3314
3315#
3316# String concatenation.
3317#
3318concat(l: list of string, r: int): string
3319{
3320 n := len l;
3321 do {
3322 t: list of string;
3323 t = nil;
3324 do {
3325 if (n > 1) {
3326 s0, s1: string;
3327 if (r) {
3328 s1 = hd l;
3329 l = tl l;
3330 s0 = hd l;
3331 l = tl l;
3332 } else {
3333 s0 = hd l;
3334 l = tl l;
3335 s1 = hd l;
3336 l = tl l;
3337 }
3338 t = (s0 + s1) :: t;
3339 n -= 2;
3340 } else {
3341 t = (hd l) :: t;
3342 break;
3343 }
3344 } while (l != nil);
3345 l = t;
3346 n = len l;
3347 r = 1 - r;
3348 } while (n > 1);
3349 return hd l;
3350}
3351
3352#
3353# Native name mangling.
3354#
3355mangle(f, s: string): string
3356{
3357 l := f :: nil;
3358 _ := 1;
3359 a := 0;
3360 while (s != nil) {
3361 n := len s;
3362 i := 0;
3363 scan: for (;;) {
3364 if (i == n) {
3365 s = nil;
3366 break;
3367 }
3368 if (_)
3369 l = "_" :: l;
3370 case s[i] {
3371 '(' or ')' =>
3372 _ = 0;
3373 '[' =>
3374 l = "a" :: l;
3375 _ = 0;
3376 a = 1;
3377 'L' =>
3378 (c, r) := str->splitl(s[i + 1:], ";)");
3379 (nil, b) := str->splitr(c, "/");
3380 if (a)
3381 l = b :: l;
3382 else
3383 l = b :: "r" :: l;
3384 if (r == nil)
3385 s = nil;
3386 else
3387 s = r[1:];
3388 _ = 1;
3389 a = 0;
3390 break scan;
3391 * =>
3392 l = s[i:i + 1] :: l;
3393 _ = 1;
3394 a = 0;
3395 }
3396 i++;
3397 }
3398 }
3399 return concat(l, 1);
3400}
3401
3402handlejavaex(nil: string, obj: ref Object)
3403{
3404 class := obj.class();
3405 if (class != tdclass) {
3406 throwable := jassist->ObjecttoJT(obj);
3407 msg : string = nil;
3408 if ( throwable.msg != nil )
3409 msg = throwable.msg.str;
3410 sys->fprint(stderr, "%s: %s\n", class.name, msg);
3411 if (throwable.trace != nil)
3412 sys->fprint(stderr, "%s\n", string throwable.trace);
3413 }
3414 delthreaddata();
3415 exit;
3416}
3417
3418setflags( flags : list of (string,int) )
3419{
3420 if ( flags == nil ) return;
3421
3422 for((f,v):=hd flags; flags != nil; flags = tl flags )
3423 {
3424 case (f)
3425 {
3426 "debug" => loadtrace();
3427 jtrace->level = JDEBUG;
3428 "verbose" => loadtrace();
3429 jtrace->level = JVERBOSE;
3430 "warn" => warn = v;
3431 }
3432 }
3433}
3434
3435runmain( classloader : JavaClassLoader, classname : string, argv : list of string )
3436{
3437 {
3438 classloader->loader(classname).run(tl tl argv);
3439 }
3440 exception e
3441 {
3442 "*" =>
3443 m := sys->sprint("uncaught exception: %s", e);
3444 mesg(m);
3445 if ( (obj := culprit(e)) != nil)
3446 handlejavaex(e, obj);
3447 else {
3448 raise m; #just giveup
3449 }
3450 classloader->shutdown();
3451 }
3452}