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 @@
1+implement JavaClassLoader;
2+
3+#
4+# Java Class Loader.
5+#
6+
7+include "sys.m";
8+ sys: Sys;
9+
10+stderr: ref Sys->FD;
11+
12+include "keyring.m";
13+ kr: Keyring;
14+
15+include "string.m";
16+ str: String;
17+
18+include "math.m";
19+ math: Math;
20+
21+include "hash.m";
22+ hash: Hash;
23+
24+include "loader.m";
25+include "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+
43+this: JavaClassLoader;
44+thisnil: Nilmod;
45+sysnil: Nilmod;
46+loadlinks: array of Loader->Link;
47+syslinks: array of Loader->Link;
48+relocs: list of ref Class;
49+relocd: list of ref Class;
50+interf: list of ref Class;
51+interfx: list of ref Class;
52+initcl: list of ref Class;
53+main: ref Class;
54+arrayclass: ref Class;
55+arraymd: ref Loader->Niladt;
56+stringclass: ref Class;
57+fsindir: int;
58+cur: string;
59+
60+interfaces: array of ref Class;
61+ninterfaces: int = 0;
62+linterfaces: int = 0;
63+
64+INITINTER: con 32;
65+
66+acqchan: chan of int;
67+relchan: chan of int;
68+exitchan: chan of int;
69+
70+MSHUTDOWN, MENTER, MEXIT, MWAIT, MNOTIFY, MSLEEP, MINTERRUPT, MTIMER, MSYNC:
71+ con iota;
72+
73+monitorctl: chan of (int, ref ThreadData, ref Object, int);
74+threadctl: chan of (ref ThreadData, int);
75+
76+threadcount: int = 0;
77+daemoncount: int = 0;
78+stopped: int = 0;
79+
80+ident: con "ClassLoader";
81+warn: int = 1;
82+debug: int = 0;
83+verbose: int = 0;
84+errors: 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+#
97+JCLDREX : con "JLD:"; #prefix
98+noclassdeffound,
99+classcircularity,
100+classformat,
101+nosuchmethod,
102+nosuchfield,
103+unsatisfiedlink,
104+linkageerr,
105+exceptionininitializer
106+ : con "e" + (string iota);
107+
108+badcallindex : con "call index";
109+nocloneindex : con "clone index";
110+
111+encoding := 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+
123+bits := array[] of { 16r80, 16r40, 16r20, 16r10, 16r08, 16r04, 16r02, 16r01 };
124+mbits := array[] of { 16r80, 16r20, 16r08, 16r02 };
125+
126+#
127+# Diagnostics.
128+#
129+
130+mesg(s: string)
131+{
132+ sys->fprint(stderr, "%s: %s\n", ident, s);
133+}
134+
135+diag(s: string)
136+{
137+ if (cur != nil)
138+ s = cur + ": " + s;
139+ mesg(s);
140+ errors++;
141+}
142+
143+loaderror( 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+
161+error(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+
180+warning(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+
189+trace(c: int, s: string)
190+{
191+ if (jtrace != nil)
192+ jtrace->trace(c, s);
193+}
194+
195+loadtrace()
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+
209+loadsync()
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+
227+acquire()
228+{
229+ acqchan <-= 0;
230+}
231+
232+release()
233+{
234+ relchan <-= 0;
235+}
236+
237+context: ref Draw->Context;
238+
239+#
240+# Initialize loader. Entry.
241+#
242+init(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+
293+loadarrayclass()
294+{
295+ arrayclass = loader(ARRAYCLASS);
296+ arraymd = arrayclass.moddata;
297+}
298+
299+loadstringclass()
300+{
301+ stringclass = loader(STRINGCLASS);
302+}
303+
304+#
305+# Native interface initialization.
306+#
307+jniinit()
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+#
320+shutdown()
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+#
341+info(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+#
353+doreloc()
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+#
458+loader(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+#
505+loadhierarchy(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+#
533+matches(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+#
544+encodename(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+#
576+rtload(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+
636+CHSZ: con 31;
637+classhash := array[CHSZ] of list of ref Class;
638+
639+getclass(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+
661+MHSZ: con 31;
662+modhash := array[MHSZ] of list of (Nilmod, ref Class);
663+
664+addmodclass(m: Nilmod, c: ref Class)
665+{
666+ h := modhash[jassist->modhash(m) % MHSZ:];
667+ h[0] = (m, c) :: h[0];
668+}
669+
670+getmodclass(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+
684+THSZ: con 31;
685+threadhash := array[THSZ] of list of ref ThreadData;
686+
687+getpid(): int
688+{
689+ return sys->pctl(0, nil);
690+}
691+
692+getcontext(): ref Draw->Context
693+{
694+ return context;
695+}
696+
697+getthreaddata(): 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+
718+delthreaddata()
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+#
745+daemonize()
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+#
764+stopthreads(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+#
778+nothreads(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+#
797+system_exit()
798+{
799+ t := getthreaddata();
800+ acquire();
801+ stopthreads(t);
802+ release();
803+ t.culprit = threaddeath().new();
804+ raise JAVAEXCEPTION;
805+}
806+
807+cmd_start: array of byte;
808+cmd_stop: array of byte;
809+cmd_kill: array of byte;
810+cmd_failed: int = 0;
811+tdclass: ref Class;
812+
813+ctlfile(t: ref ThreadData)
814+{
815+ if (t.ctlfile == nil)
816+ t.ctlfile = PROG + "/" + string t.pid + "/dbgctl";
817+}
818+
819+threaddeath(): ref Class
820+{
821+ if (tdclass == nil)
822+ tdclass = loader(EXCEPTIONPATH + "ThreadDeath");
823+ return tdclass;
824+}
825+
826+dosuspend(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+
843+doresume(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+
857+dostop(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+
876+threadmanager()
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+
923+block(t: ref ThreadData)
924+{
925+ threadctl <-= (t, ThreadData.BLOCK);
926+}
927+
928+unblock(t: ref ThreadData)
929+{
930+ threadctl <-= (t, ThreadData.UNBLOCK);
931+}
932+
933+suspend(t: ref ThreadData)
934+{
935+ threadctl <-= (t, ThreadData.SUSPEND);
936+}
937+
938+resume(t: ref ThreadData)
939+{
940+ threadctl <-= (t, ThreadData.RESUME);
941+}
942+
943+stop(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+
955+mkexception( name : string ) : ref Object
956+{
957+ return(loader(EXCEPTIONPATH + name).new());
958+}
959+
960+# convert an Inferno exception into a Java Exception
961+sysexception( 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+
1052+culprit(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+
1066+throw(c: ref Object)
1067+{
1068+ getthreaddata().culprit = c;
1069+ raise JAVAEXCEPTION;
1070+}
1071+
1072+sthrow(s: string)
1073+{
1074+ throw(mkexception(s));
1075+}
1076+
1077+#
1078+# Monitors.
1079+#
1080+
1081+MONOK, MONILL, MONINT:
1082+ con iota;
1083+
1084+Synch: adt
1085+{
1086+ thread: ref ThreadData;
1087+ count: int;
1088+ status: int;
1089+ next: cyclic ref Synch;
1090+};
1091+
1092+Monitor: adt
1093+{
1094+ thread: ref ThreadData;
1095+ object: ref Object;
1096+ count: int;
1097+ head: ref Synch;
1098+ tail: ref Synch;
1099+};
1100+
1101+Waiter: adt
1102+{
1103+ thread: ref ThreadData;
1104+ object: ref Object;
1105+ count: int;
1106+ time: int;
1107+ next: cyclic ref Waiter;
1108+};
1109+
1110+sleepers: ref Waiter;
1111+waiters: ref Waiter;
1112+timeout: int;
1113+
1114+MAXSLEEP: con 1000;
1115+SLEEPTOL: con 50;
1116+
1117+MONHSZ: con 31;
1118+monhash := array[MONHSZ] of list of ref Monitor;
1119+
1120+getmonitor(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+#
1143+timer(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+#
1155+waiter(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+#
1191+dotimer(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+
1215+donotifyl(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+
1228+donotify(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+
1238+donotifyalll(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+
1249+donotifyall(o: ref Object)
1250+{
1251+ donotifyalll(waiters, o);
1252+ donotifyalll(sleepers, o);
1253+}
1254+
1255+#
1256+# Interrupt.
1257+#
1258+
1259+dointerruptl(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+
1272+dointerrupt(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+#
1283+doenter(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+#
1322+mondone(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+#
1333+monitornext(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+#
1354+monitor()
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+#
1415+monitorresume(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+
1432+monitorenter(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+
1443+monitorexit(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+
1452+monitorwait(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+
1464+monitornotify(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+
1476+monsync()
1477+{
1478+ monitorctl <-= (MSYNC, nil, nil, 0);
1479+}
1480+
1481+sleep(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+
1495+interrupt(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+
1509+compatclass(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+
1521+checkcast(who: ref Object, what: ref Class)
1522+{
1523+ if (who != nil && !instanceof(who, what))
1524+ sthrow("ClassCastException");
1525+}
1526+
1527+instanceof(who: ref Object, what: ref Class): int
1528+{
1529+ if (who == nil)
1530+ return 0;
1531+ return compatclass(who.class(), what);
1532+}
1533+
1534+acheckcast(who: ref Array, what: ref Class, dims: int)
1535+{
1536+ if (who != nil && !ainstanceof(who, what, dims))
1537+ sthrow("ClassCastException");
1538+}
1539+
1540+ainstanceof(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+
1556+pcheckcast(who: ref Array, what, dims: int)
1557+{
1558+ if (who != nil && !pinstanceof(who, what, dims))
1559+ sthrow("ClassCastException");
1560+}
1561+
1562+pinstanceof(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+
1573+aastoreinstanceof(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+
1601+aastorecheck(who: ref Object, what: ref Array)
1602+{
1603+ if (what == nil)
1604+ sthrow("NullPointerException");
1605+ if (!aastoreinstanceof(who, what))
1606+ sthrow("ArrayStoreException");
1607+}
1608+
1609+multianewarray(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+
1638+arraycopy(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+#
1669+getinterface(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+
1688+lcmp(x, y: big): int
1689+{
1690+ if(x < y)
1691+ return -1;
1692+ if(x == y)
1693+ return 0;
1694+ return 1;
1695+}
1696+
1697+truncate(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+
1706+d2i(x: real): int
1707+{
1708+ return int truncate(x);
1709+}
1710+
1711+d2l(x: real): big
1712+{
1713+ return big truncate(x);
1714+}
1715+
1716+dcmpg(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+
1725+dcmpl(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+
1734+drem(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+
1747+Class.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+
1771+Class.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+
1782+Class.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+
1789+Class.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+#
1803+Class.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+#
1841+Class.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+#
2004+Class.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+#
2028+Class.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+#
2059+Class.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+#
2080+addclass(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+#
2091+interext(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+#
2107+intertrans(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+#
2121+Class.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+#
2136+Class.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+#
2170+Class.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+#
2311+Class.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+#
2361+Class.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+#
2424+Class.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+#
2441+Class.findimethod(c: self ref Class, s: string): ref Field
2442+{
2443+ return findasig(c.initmethods, s);
2444+}
2445+
2446+#
2447+# Find private method.
2448+#
2449+Class.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+#
2457+Class.findsfield(c: self ref Class, f: string): ref Field
2458+{
2459+ return findafield(c.staticdata, f);
2460+}
2461+
2462+#
2463+# Find static method.
2464+#
2465+Class.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+#
2473+Class.findofield(c: self ref Class, f: string): ref Field
2474+{
2475+ return findfield(c.objectdata, f);
2476+}
2477+
2478+#
2479+# Find virtual method.
2480+#
2481+Class.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+
2500+Class.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+#
2539+Class.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+#
2568+Class.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+#
2601+Class.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+#
2610+Class.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+#
2656+nextra(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+#
2679+Class.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+#
2697+Class.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+#
2716+Class.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+#
2779+Class.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+#
2846+Class.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+#
2868+Class.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+#
2887+Class.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+#
2910+Class.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+#
2930+relocloader(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+
2964+LDHASH: con 38;
2965+
2966+LoadMap: adt
2967+{
2968+ name: string;
2969+ value: int;
2970+};
2971+
2972+loadtable := array[LDHASH] of LoadMap;
2973+
2974+loadkeys := 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+#
3004+loadhash(s: string): int
3005+{
3006+ return ((s[len s - 1] + 49) * len s + 19 * s[0]) % LDHASH;
3007+}
3008+
3009+loadenter(s: string, x: int)
3010+{
3011+ n := loadhash(s);
3012+ if (loadtable[n].name == s)
3013+ loadtable[n].value = x;
3014+}
3015+
3016+initloadhash()
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+#
3036+getloader(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+#
3047+Object.class(o: self ref Object): ref Class
3048+{
3049+ return getclassadt(o.mod, CLASSADTOFFSET);
3050+}
3051+
3052+#
3053+# Categorizers.
3054+#
3055+isdata(sig: string): int
3056+{
3057+ return sig[0] != '(';
3058+}
3059+
3060+isspecial(field: string): int
3061+{
3062+ return field[0] == '<';
3063+}
3064+
3065+ispointer(sig: string): int
3066+{
3067+ case sig[0] {
3068+ 'L' or '[' =>
3069+ return 1;
3070+ }
3071+ return 0;
3072+}
3073+
3074+isprivate(flags: int): int
3075+{
3076+ return flags & ACC_PRIVATE;
3077+}
3078+
3079+isstatic(flags: int): int
3080+{
3081+ return flags & ACC_STATIC;
3082+}
3083+
3084+isnative(flags: int): int
3085+{
3086+ return flags & ACC_NATIVE;
3087+}
3088+
3089+isvirtual(flags: int): int
3090+{
3091+ return (flags & (ACC_PRIVATE | ACC_STATIC)) == 0;
3092+}
3093+
3094+isabstract(flags: int): int
3095+{
3096+ return flags & ACC_ABSTRACT;
3097+}
3098+
3099+#
3100+# Type alignment.
3101+#
3102+alignto(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+#
3119+sizeof(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+
3137+mkclarray(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+
3148+mkfdarray(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+
3159+findfield(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+
3170+findsig(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+
3181+findfs(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+
3192+findafield(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+
3202+findasig(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+
3212+findafs(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+
3222+findmfsx(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+#
3236+ipatch(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+#
3318+concat(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+#
3355+mangle(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+
3402+handlejavaex(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+
3418+setflags( 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+
3435+runmain( 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+}