MBLoaderExtra.mesa
Edited by Sandman on 5-Aug-81 11:56:04
Edited by Lewis on 25-Sep-81 15:03:08
Edited by Levin on May 24, 1983 10:26 am
DIRECTORY
BcdDefs USING [
Base, BcdBase, EVIndex, EVNull, EXPHandle, EXPIndex, EXPNull, FTHandle, FTIndex, FTSelf, IMPHandle, IMPIndex, Link, MTHandle, MTIndex, MTNull, NameRecord, NameString, PackedString, ProcLimit, TMHandle, TMIndex, TMNull, TMRecord, UnboundLink, VarLimit, VersionStamp],
BcdOps USING [ProcessExports, ProcessImports, ProcessModules],
MB USING [BHandle, Error, Handle, MT],
MBLoaderOps USING [
AcquireBcd, BcdExports, BcdExportsTypes, BcdUnresolved, Binding, BindLink, CloseLinkSpace, ConfigIndex, EnterModule, GetModule, GetVirtualLinks, InitBinding, ModuleInfo, OpenLinkSpace, ReadLink, UpdateLoadState, VirtualLinks, WriteLink],
PrincOps USING [
ControlLink, GFTIndex, GFTNull, GlobalFrame, GlobalFrameHandle, NullGlobalFrame, NullLink, UnboundLink],
Rope USING [Concat, FromProc];
MBLoaderExtra: PROGRAM
IMPORTS BcdOps, MB, MBLoaderOps, Rope
EXPORTS MBLoaderOps =
BEGIN
OPEN BcdDefs, BcdOps;
data: MB.Handle ← NIL;
InitLoaderExtra: PUBLIC PROC [h: MB.Handle] = {data ← h};
FinishLoaderExtra: PUBLIC PROC = {data ← NIL};
Bind: PUBLIC PROC [loadee: MB.BHandle, config: MBLoaderOps.ConfigIndex] = {
bcd: BcdBase = loadee.bcd;
bindings for loadee's imports
binding: MBLoaderOps.Binding ← MBLoaderOps.InitBinding[bcd];
bindingsFound, resolved: BOOL;
resolved ← (bcd.nImports = 0);
bind (relocate) imports within loadee itself
[] ← BindImports[bcd: loadee.bcd, system: loadee.bcd, binding: binding];
resolved ← ProcessLinks[
loadee: loadee, system: loadee, binding: binding, config: config, initLinkSpace: TRUE];
bind into existing system
FOR i: CARDINAL DECREASING IN [0..config) DO
system: MB.BHandle ← MBLoaderOps.AcquireBcd[i];
bind loadee's imports exported by existing Bcd i
IF ~resolved AND MBLoaderOps.BcdExports[i] THEN {
binding ← MBLoaderOps.InitBinding[bcd];
bindingsFound ← BindImports[bcd: loadee.bcd, system: system.bcd, binding: binding];
IF bindingsFound THEN
resolved ← ProcessLinks[
loadee: loadee, system: system, binding: binding, config: i, initLinkSpace: FALSE]
ELSE resolved ← FALSE;
};
bind imports of existing Bcd i exported by loadee
IF MBLoaderOps.BcdUnresolved[i] AND (bcd.nExports ~= 0 OR bcd.nModules = 1) THEN {
binding ← MBLoaderOps.InitBinding[system.bcd];
bindingsFound ← BindImports[bcd: system.bcd, system: loadee.bcd, binding: binding];
IF bindingsFound THEN
[] ← ProcessLinks[
loadee: system, system: loadee, binding: binding, config: config, initLinkSpace: FALSE
];
};
check exported types
IF bcd.typeExported AND MBLoaderOps.BcdExportsTypes[i] THEN
CheckTypes[bcd, system.bcd];
ENDLOOP;
MBLoaderOps.UpdateLoadState[config: config, handle: loadee];
};
BindImports: PROC [bcd, system: BcdBase, binding: MBLoaderOps.Binding]
RETURNS [bindingsFound: BOOL] = {
bcdSsb: NameString = LOOPHOLE[bcd + bcd.ssOffset];
systemSsb: NameString = LOOPHOLE[system + system.ssOffset];
BindOneImport: PROC [ith: IMPHandle, iti: IMPIndex] RETURNS [BOOL] = {
ExpMatch: PROC [eth: EXPHandle, eti: EXPIndex] RETURNS [BOOL] = {
RETURN[
eth.port = ith.port AND
EqualNames[bcdSsb, systemSsb, ith.name, eth.name] AND
EqualVersions[bcd, system, ith.file, eth.file]]
};
ModuleMatch: PROC [mth: MTHandle, mti: MTIndex] RETURNS [BOOL] = {
RETURN[
EqualNames[bcdSsb, systemSsb, ith.name, mth.name] AND
EqualVersions[bcd, system, ith.file, mth.file]]
};
IF ith.port = interface THEN {
eti: EXPIndex = ProcessExports[system, ExpMatch].eti;
FOR i: CARDINAL IN [0..ith.ngfi) DO
IF eti = EXPNull THEN
binding.b[ith.gfi + i - binding.bias] ← [whichgfi: i, body: notbound[]]
ELSE {
bindingsFound ← TRUE;
binding.b[ith.gfi + i - binding.bias] ← [whichgfi: i, body: interface[eti: eti]];
};
ENDLOOP;
}
ELSE {
mti: MTIndex = ProcessModules[system, ModuleMatch].mti;
FOR i: CARDINAL IN [0..ith.ngfi) DO
IF mti = MTNull THEN
binding.b[ith.gfi + i - binding.bias] ← [whichgfi: i, body: notbound[]]
ELSE {
bindingsFound ← TRUE;
binding.b[ith.gfi + i - binding.bias] ← [whichgfi: i, body: module[mti: mti]];
};
ENDLOOP;
};
RETURN[FALSE]
};
bindingsFound ← FALSE;
[] ← ProcessImports[bcd, BindOneImport];
};
EqualNames: PROC [ss1, ss2: NameString, n1, n2: NameRecord]
RETURNS [BOOL] = {
IF ss1.size[n1] ~= ss2.size[n2] THEN RETURN[FALSE];
FOR i: CARDINAL IN [0..ss1.size[n1]) DO
IF ss1.string.text[n1 + i] ~= ss2.string.text[n2 + i] THEN RETURN[FALSE];
ENDLOOP;
RETURN[TRUE]
};
EqualVersions: PROC [bcd1, bcd2: BcdBase, fti1, fti2: FTIndex]
RETURNS [BOOL] = {
v1, v2: LONG POINTER TO VersionStamp;
f1: FTHandle ← @LOOPHOLE[bcd1 + bcd1.ftOffset, Base][fti1];
f2: FTHandle ← @LOOPHOLE[bcd2 + bcd2.ftOffset, Base][fti2];
v1 ← (IF fti1 = FTSelf THEN @bcd1.version ELSE @f1.version);
v2 ← (IF fti2 = FTSelf THEN @bcd2.version ELSE @f2.version);
IF v1^ = v2^ THEN RETURN[TRUE];
BadVersion[
ssb: LOOPHOLE[bcd1 + bcd1.ssOffset],
name: (IF fti1 = FTSelf THEN bcd1.source ELSE f1.name)
];
RETURN[FALSE]
};
BadVersion: PROC [ssb: NameString, name: NameRecord] = {
i: INT ← name;
GetFromNameString: SAFE PROC RETURNS [char: CHARACTER] = TRUSTED {
char ← ssb.string[i]; i ← i + 1};
MB.Error[
Rope.Concat[Rope.FromProc[ssb.size[name], GetFromNameString], " has incorrect version!"]];
};
ProcessLinks: PROC [
loadee, system: MB.BHandle, binding: MBLoaderOps.Binding,
config: MBLoaderOps.ConfigIndex, initLinkSpace: BOOL]
RETURNS [completelyBound: BOOL] = {
bcd: BcdBase = loadee.bcd;
mt: MB.MT = loadee.mt;
smtb: Base = LOOPHOLE[system.bcd + system.bcd.mtOffset];
setb: Base = LOOPHOLE[system.bcd + system.bcd.expOffset];
ProcessModulesLinks: PROC [mth: MTHandle, mti: MTIndex] RETURNS [BOOL] = {
gfi: PrincOps.GFTIndex = (mth.gfi + loadee.gfiOffset); -- biased
frame: PrincOps.GlobalFrameHandle = mt[mth.gfi].frame;
info: MBLoaderOps.ModuleInfo ← MBLoaderOps.GetModule[gfi];
linkBound, linkJustBound, modulesLinksAllBound: BOOL;
old, new: PrincOps.ControlLink;
i: CARDINAL;
virtualLinks: MBLoaderOps.VirtualLinks;
IF frame = PrincOps.NullGlobalFrame OR info.resolved THEN RETURN[FALSE];
MBLoaderOps.OpenLinkSpace[loadee, mth];
virtualLinks ← MBLoaderOps.GetVirtualLinks[loadee, mth];
IF initLinkSpace THEN
FOR i IN [0..LENGTH[virtualLinks]) DO
MBLoaderOps.WriteLink[
offset: i,
link: SELECT virtualLinks[i].vtag FROM
var, type => PrincOps.NullLink,
ENDCASE => PrincOps.UnboundLink];
ENDLOOP;
modulesLinksAllBound ← TRUE;
FOR i IN [0..LENGTH[virtualLinks]) DO -- bind each external link
old ← MBLoaderOps.ReadLink[i];
[new: new, linkBound: linkBound, linkJustBound: linkJustBound] ← NewLink[
link: virtualLinks[i], old: old];
IF linkJustBound THEN MBLoaderOps.WriteLink[offset: i, link: new];
modulesLinksAllBound ← (modulesLinksAllBound AND linkBound);
ENDLOOP;
FOR i IN [gfi..gfi + mth.ngfi) DO
info ← MBLoaderOps.GetModule[i];
info.resolved ← modulesLinksAllBound;
MBLoaderOps.EnterModule[i, info];
ENDLOOP;
completelyBound ← (completelyBound AND modulesLinksAllBound);
MBLoaderOps.CloseLinkSpace[];
RETURN[FALSE]
};
NewLink: PROC [link: Link, old: PrincOps.ControlLink]
RETURNS [new: PrincOps.ControlLink, linkBound, linkJustBound: BOOL] = {
ConvertProcOrVarLink: PROC [link: Link]
RETURNS [new: PrincOps.ControlLink, resolved: BOOL] = {
insideLoadee: BOOL = (link.gfi < loadee.bcd.firstdummy);
rgfi: PrincOps.GFTIndex ← PrincOps.GFTNull;
new ← PrincOps.UnboundLink;
IF insideLoadee THEN {
new ← ConvertLink[link];
IF link.gfi ~= PrincOps.GFTNull THEN rgfi ← link.gfi + loadee.gfiOffset;
}
ELSE {
bindLink: MBLoaderOps.BindLink = binding.b[link.gfi - binding.bias];
WITH b: bindLink SELECT FROM
interface => {
e: EXPHandle = @setb[b.eti];
SELECT e.port FROM
interface => {
link ← e.links[link.ep + (b.whichgfi * ProcLimit)]; -- matching exported link
IF link.gfi ~= PrincOps.GFTNull THEN
rgfi ← link.gfi + system.gfiOffset};
ENDCASE;
};
module => {
m: MTHandle = @smtb[b.mti];
link ← [variable[vgfi: m.gfi, var: 0, vtag: var]];
IF link.gfi ~= PrincOps.GFTNull THEN rgfi ← m.gfi + system.gfiOffset;
};
ENDCASE;
};
SELECT link.vtag FROM
proc0, proc1 => {
new ← ConvertLink[link];
new.gfi ← rgfi; -- relocate link's gfi
};
var => new ← FindVariableLink[insideLoadee, link, rgfi];
ENDCASE;
RETURN[new: new, resolved: (rgfi ~= PrincOps.GFTNull)]
};
FindVariableLink: PROC [
insideLoadee: BOOL, varLink: Link, rgfi: PrincOps.GFTIndex]
RETURNS [link: PrincOps.ControlLink] = INLINE {
mth: MTHandle;
frame: PrincOps.GlobalFrameHandle;
gfi: PrincOps.GFTIndex = varLink.vgfi;
evb: Base;
vp: CARDINAL;
FindModule: PROC [mth: MTHandle, mti: MTIndex] RETURNS [BOOL] = {
mgfi: PrincOps.GFTIndex = mth.gfi;
IF gfi IN [mth.gfi..mgfi + mth.ngfi) THEN
{vp ← VarLimit*(gfi - mgfi); RETURN[TRUE]};
RETURN[FALSE]
};
IF rgfi = PrincOps.GFTNull THEN RETURN[PrincOps.NullLink];
mth ← ProcessModules[
(IF insideLoadee THEN loadee.bcd ELSE system.bcd), FindModule].mth;
IF mth = NIL THEN RETURN[PrincOps.NullLink];
IF insideLoadee THEN {
evb ← LOOPHOLE[(loadee.bcd + loadee.bcd.evOffset), Base];
frame ← loadee.mt[rgfi - loadee.gfiOffset].frame;
}
ELSE {
evb ← LOOPHOLE[(system.bcd + system.bcd.evOffset), Base];
frame ← system.mt[rgfi - system.gfiOffset].frame;
};
vp ← vp + varLink.var;
IF vp = 0 THEN RETURN[LOOPHOLE[frame]];
IF mth.variables = EVNull THEN RETURN[PrincOps.NullLink];
RETURN[LOOPHOLE[frame + evb[mth.variables].offsets[vp]]]
};
new ← old;
linkBound ← linkJustBound ← FALSE;
SELECT link.vtag FROM
proc0, proc1 =>
IF old = PrincOps.UnboundLink THEN {
[new: new, resolved: linkJustBound] ← ConvertProcOrVarLink[link];
linkBound ← linkJustBound;
}
ELSE linkBound ← TRUE;
var =>
IF old = PrincOps.NullLink THEN {
[new: new, resolved: linkJustBound] ← ConvertProcOrVarLink[link];
linkBound ← linkJustBound;
}
ELSE linkBound ← TRUE;
ENDCASE => --type-- new ← LOOPHOLE[link.typeID];
IF ~linkJustBound THEN new ← old; -- end of NewLink
};
completelyBound ← TRUE;
[] ← ProcessModules[loadee.bcd, ProcessModulesLinks];
RETURN[completelyBound]; -- all modules completely resolved
};
ConvertLink: PROC [bl: Link] RETURNS [cl: PrincOps.ControlLink] = {
IF bl = UnboundLink THEN RETURN[PrincOps.UnboundLink];
SELECT bl.vtag FROM
proc0, proc1 => cl ← [procedure[gfi: bl.gfi, ep: bl.ep, tag: TRUE]];
var => cl ← [procedure[gfi: bl.vgfi, ep: bl.var, tag: FALSE]];
type => cl ← LOOPHOLE[bl.typeID];
ENDCASE;
};
CheckTypes: PROC [bcd1, bcd2: BcdBase] = {
typb1: Base = LOOPHOLE[bcd1 + bcd1.typOffset];
typb2: Base = LOOPHOLE[bcd2 + bcd2.typOffset];
TypeMap1: PROC [tmh1: TMHandle, tmi1: TMIndex] RETURNS [BOOL] = {
TypeMap2: PROC [tmh2: TMHandle, tmi2: TMIndex] RETURNS [BOOL] = {
IF tmh2.offset = tmh1.offset AND tmh2.version = tmh1.version THEN {
IF typb1[tmh1.map] ~= typb2[tmh2.map] THEN MB.Error["Exported Type Clash"];
RETURN[TRUE]
}
ELSE RETURN[FALSE]
};
[] ← EnumerateTypeMap[bcd2, TypeMap2];
RETURN[FALSE]
};
[] ← EnumerateTypeMap[bcd1, TypeMap1];
};
EnumerateTypeMap: PROC [
bcd: BcdBase, proc: PROC [TMHandle, TMIndex] RETURNS [BOOL]]
RETURNS [tmh: TMHandle, tmi: TMIndex] = {
tmb: Base = LOOPHOLE[bcd + bcd.tmOffset];
FOR tmi ← FIRST[TMIndex], tmi + SIZE[TMRecord]
UNTIL tmi = bcd.tmLimit DO
IF proc[(tmh ← @tmb[tmi]), tmi] THEN RETURN;
ENDLOOP;
RETURN[NIL, TMNull]
};
END.