Skip to content

Commit 2b30501

Browse files
committed
Relocatable module experiment
1 parent 024d9de commit 2b30501

5 files changed

Lines changed: 84 additions & 11 deletions

File tree

cli/asc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,7 @@ exports.main = function main(argv, options, callback) {
472472
assemblyscript.setSourceMap(compilerOptions, args.sourceMap != null);
473473
assemblyscript.setOptimizeLevelHints(compilerOptions, optimizeLevel, shrinkLevel);
474474
assemblyscript.setNoUnsafe(compilerOptions, args.noUnsafe);
475+
assemblyscript.setRelocatable(compilerOptions, args.relocatable);
475476

476477
// Initialize default aliases
477478
assemblyscript.setGlobalAlias(compilerOptions, "Math", "NativeMath");

cli/asc.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,14 @@
107107
"type": "b",
108108
"default": false
109109
},
110+
"relocatable": {
111+
"description": [
112+
"Emits a relocatable module. Imports a __memory_base and a",
113+
"__table_base constant indicating where the module lives."
114+
],
115+
"type": "b",
116+
"default": false
117+
},
110118
"noAssert": {
111119
"description": "Replaces assertions with just their value without trapping.",
112120
"type": "b",

src/compiler.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,8 @@ export class Options {
206206
features: Feature = Feature.MUTABLE_GLOBALS;
207207
/** If true, disallows unsafe features in user code. */
208208
noUnsafe: bool = false;
209+
/** If true, emits a relocatable module. */
210+
relocatable: bool = false;
209211

210212
/** Hinted optimize level. Not applied by the compiler itself. */
211213
optimizeLevelHint: i32 = 0;
@@ -363,6 +365,15 @@ export class Compiler extends DiagnosticEmitter {
363365
module.addGlobal(BuiltinSymbols.rtti_base, NativeType.I32, true, module.i32(0));
364366
}
365367

368+
// add relocation globals
369+
if (options.relocatable) {
370+
let nativeSizeType = options.nativeSizeType;
371+
module.addGlobalImport("__memory_base", "env", "memory_base", nativeSizeType, false);
372+
module.setMemoryBase("__memory_base");
373+
module.addGlobalImport("__table_base", "env", "table_base", nativeSizeType, false);
374+
module.setTableBase("__table_base");
375+
}
376+
366377
// compile entry file(s) while traversing reachable elements
367378
var files = program.filesByName;
368379
for (let file of files.values()) {
@@ -459,6 +470,20 @@ export class Compiler extends DiagnosticEmitter {
459470
for (let file of this.program.filesByName.values()) {
460471
if (file.source.sourceKind == SourceKind.USER_ENTRY) this.ensureModuleExports(file);
461472
}
473+
474+
// set up relocation hints
475+
if (options.relocatable) {
476+
let memorySize = i64_align(memoryOffset, 16);
477+
if (options.isWasm64) {
478+
module.addGlobal("__memory_size", NativeType.I64, false, module.i64(i64_low(memorySize), i64_high(memorySize)));
479+
} else {
480+
module.addGlobal("__memory_size", NativeType.I32, false, module.i32(i64_low(memorySize)));
481+
}
482+
module.addGlobalExport("__memory_size", "__memory_size");
483+
module.addGlobal("__table_size", NativeType.I32, false, module.i32(functionTable.length));
484+
module.addGlobalExport("__table_size", "__table_size");
485+
}
486+
462487
return module;
463488
}
464489

src/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,11 @@ export function setNoUnsafe(options: Options, noUnsafe: bool): void {
121121
options.noUnsafe = noUnsafe;
122122
}
123123

124+
/** Sets the `relocatable` option. */
125+
export function setRelocatable(options: Options, relocatable: bool): void {
126+
options.relocatable = relocatable;
127+
}
128+
124129
/** Sign extension operations. */
125130
export const FEATURE_SIGN_EXTENSION = Feature.SIGN_EXTENSION;
126131
/** Mutable global imports and exports. */

src/module.ts

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,37 @@ export class Module {
459459

460460
private constructor() { }
461461

462+
// relocation
463+
464+
private mbase: usize = 0;
465+
private tbase: usize = 0;
466+
467+
setMemoryBase(globalName: string | null): void {
468+
this.mbase = globalName ? this.allocStringCached(globalName) : 0;
469+
}
470+
471+
setTableBase(globalName: string | null): void {
472+
this.tbase = globalName ? this.allocStringCached(globalName) : 0;
473+
}
474+
475+
private relocMem(ptr: ExpressionRef): ExpressionRef {
476+
var mbase = this.mbase;
477+
if (!mbase) return ptr;
478+
var ref = this.ref;
479+
switch (_BinaryenExpressionGetType(ptr)) {
480+
default: assert(false);
481+
case NativeType.I32: return _BinaryenBinary(ref, BinaryOp.AddI32, _BinaryenGlobalGet(ref, mbase, NativeType.I32), ptr);
482+
case NativeType.I64: return _BinaryenBinary(ref, BinaryOp.AddI64, _BinaryenGlobalGet(ref, mbase, NativeType.I64), ptr);
483+
}
484+
}
485+
486+
private relocTbl(idx: ExpressionRef): ExpressionRef {
487+
var tbase = this.tbase;
488+
if (!tbase) return idx;
489+
var ref = this.ref;
490+
return _BinaryenBinary(ref, BinaryOp.AddI32, _BinaryenGlobalGet(ref, tbase, NativeType.I32), idx);
491+
}
492+
462493
// types
463494

464495
addFunctionType(
@@ -587,7 +618,7 @@ export class Module {
587618
offset: Index = 0,
588619
align: Index = bytes // naturally aligned by default
589620
): ExpressionRef {
590-
return _BinaryenLoad(this.ref, bytes, signed ? 1 : 0, offset, align, type, ptr);
621+
return _BinaryenLoad(this.ref, bytes, signed ? 1 : 0, offset, align, type, this.relocMem(ptr));
591622
}
592623

593624
store(
@@ -598,8 +629,7 @@ export class Module {
598629
offset: Index = 0,
599630
align: Index = bytes // naturally aligned by default
600631
): ExpressionRef {
601-
if (type < NativeType.None || type > NativeType.V128) throw new Error("here: " + type);
602-
return _BinaryenStore(this.ref, bytes, offset, align, ptr, value, type);
632+
return _BinaryenStore(this.ref, bytes, offset, align, this.relocMem(ptr), value, type);
603633
}
604634

605635
atomic_load(
@@ -608,7 +638,7 @@ export class Module {
608638
type: NativeType,
609639
offset: Index = 0
610640
): ExpressionRef {
611-
return _BinaryenAtomicLoad(this.ref, bytes, offset, type, ptr);
641+
return _BinaryenAtomicLoad(this.ref, bytes, offset, type, this.relocMem(ptr));
612642
}
613643

614644
atomic_store(
@@ -618,7 +648,7 @@ export class Module {
618648
type: NativeType,
619649
offset: Index = 0
620650
): ExpressionRef {
621-
return _BinaryenAtomicStore(this.ref, bytes, offset, ptr, value, type);
651+
return _BinaryenAtomicStore(this.ref, bytes, offset, this.relocMem(ptr), value, type);
622652
}
623653

624654
atomic_rmw(
@@ -629,7 +659,7 @@ export class Module {
629659
value: ExpressionRef,
630660
type: NativeType
631661
): ExpressionRef {
632-
return _BinaryenAtomicRMW(this.ref, op, bytes, offset, ptr, value, type);
662+
return _BinaryenAtomicRMW(this.ref, op, bytes, offset, this.relocMem(ptr), value, type);
633663
}
634664

635665
atomic_cmpxchg(
@@ -640,7 +670,7 @@ export class Module {
640670
replacement: ExpressionRef,
641671
type: NativeType
642672
): ExpressionRef {
643-
return _BinaryenAtomicCmpxchg(this.ref, bytes, offset, ptr, expected, replacement, type);
673+
return _BinaryenAtomicCmpxchg(this.ref, bytes, offset, this.relocMem(ptr), expected, replacement, type);
644674
}
645675

646676
atomic_wait(
@@ -649,14 +679,14 @@ export class Module {
649679
timeout: ExpressionRef,
650680
expectedType: NativeType
651681
): ExpressionRef {
652-
return _BinaryenAtomicWait(this.ref, ptr, expected, timeout, expectedType);
682+
return _BinaryenAtomicWait(this.ref, this.relocMem(ptr), expected, timeout, expectedType);
653683
}
654684

655685
atomic_notify(
656686
ptr: ExpressionRef,
657687
notifyCount: ExpressionRef
658688
): ExpressionRef {
659-
return _BinaryenAtomicNotify(this.ref, ptr, notifyCount);
689+
return _BinaryenAtomicNotify(this.ref, this.relocMem(ptr), notifyCount);
660690
}
661691

662692
atomic_fence(): ExpressionRef {
@@ -798,8 +828,8 @@ export class Module {
798828
var cArr = allocPtrArray(operands);
799829
try {
800830
return isReturn
801-
? _BinaryenReturnCallIndirect(this.ref, index, cArr, operands && operands.length || 0, cStr)
802-
: _BinaryenCallIndirect(this.ref, index, cArr, operands && operands.length || 0, cStr);
831+
? _BinaryenReturnCallIndirect(this.ref, this.relocTbl(index), cArr, operands && operands.length || 0, cStr)
832+
: _BinaryenCallIndirect(this.ref, this.relocTbl(index), cArr, operands && operands.length || 0, cStr);
803833
} finally {
804834
memory.free(cArr);
805835
}
@@ -1151,6 +1181,8 @@ export class Module {
11511181
: this.i32(i64_low(offset));
11521182
sizs[i] = buffer.length;
11531183
}
1184+
var mbase = this.mbase;
1185+
if (mbase) for (let i = 0; i < k; ++i) offs[i] = this.relocMem(offs[i]);
11541186
var cArr1 = allocI32Array(segs);
11551187
var cArr2 = allocU8Array(psvs);
11561188
var cArr3 = allocI32Array(offs);
@@ -1176,6 +1208,8 @@ export class Module {
11761208
for (let i = 0; i < numNames; ++i) {
11771209
names[i] = this.allocStringCached(funcs[i]);
11781210
}
1211+
// FIXME: Relocating the function table is not possible currently due to
1212+
// the C-API only accepting an array of names, but no offsets.
11791213
var cArr = allocI32Array(names);
11801214
try {
11811215
_BinaryenSetFunctionTable(this.ref, initial, maximum, cArr, numNames);

0 commit comments

Comments
 (0)