Skip to content

Commit 5d0c5ea

Browse files
committed
Merge remote-tracking branch 'origin/master' into release
2 parents eabf490 + ab964b4 commit 5d0c5ea

File tree

9 files changed

+257
-109
lines changed

9 files changed

+257
-109
lines changed

cli/asc.d.ts

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,92 @@ export interface MemoryStream extends OutputStream {
5050
toString(): string;
5151
}
5252

53-
/** Compiler API options. */
53+
/** Compiler options. */
5454
interface CompilerOptions {
55+
/** Prints just the compiler's version and exits. */
56+
version?: boolean;
57+
/** Prints the help message and exits. */
58+
help?: boolean;
59+
/** Optimizes the module. */
60+
optimize?: boolean;
61+
/** How much to focus on optimizing code. */
62+
optimizeLevel?: number;
63+
/** How much to focus on shrinking code size. */
64+
shrinkLevel?: number;
65+
/** Re-optimizes until no further improvements can be made. */
66+
converge?: boolean;
67+
/** Validates the module using Binaryen. Exits if invalid. */
68+
validate?: boolean;
69+
/** Specifies the base directory of input and output files. */
70+
baseDir?: string;
71+
/** Specifies the output file. File extension indicates format. */
72+
outFile?: string;
73+
/** Specifies the binary output file (.wasm). */
74+
binaryFile?: string;
75+
/** Specifies the text output file (.wat). */
76+
textFile?: string;
77+
/** Specifies the asm.js output file (.js). */
78+
asmjsFile?: string;
79+
/** Specifies the WebIDL output file (.webidl). */
80+
idlFile?: string;
81+
/** Specifies the TypeScript definition output file (.d.ts). */
82+
tsdFile?: string;
83+
/** Enables source map generation. Optionally takes the URL. */
84+
sourceMap?: boolean | string;
85+
/** Specifies the runtime variant to include in the program. */
86+
runtime?: string;
87+
/** Disallows the use of unsafe features in user code. */
88+
noUnsafe?: boolean;
89+
/** Enables debug information in emitted binaries. */
90+
debug?: boolean;
91+
/** Replaces assertions with just their value without trapping. */
92+
noAssert?: boolean;
93+
/** Performs compilation as usual but does not emit code. */
94+
noEmit?: boolean;
95+
/** Imports the memory provided as 'env.memory'. */
96+
importMemory?: boolean;
97+
/** Declare memory as shared by settings the max shared memory. */
98+
sharedMemory?: number;
99+
/** Sets the start offset of compiler-generated static memory. */
100+
memoryBase?: number;
101+
/** Imports the function table provided as 'env.table'. */
102+
importTable?: boolean;
103+
/** Exports the function table as 'table'. */
104+
exportTable?: boolean;
105+
/** Exports an explicit start function to be called manually. */
106+
explicitStart?: boolean;
107+
/** "Adds one or multiple paths to custom library components. */
108+
lib?: string | string[];
109+
/** Adds one or multiple paths to package resolution. */
110+
path?: string | string[];
111+
/** Aliases a global object under another name. */
112+
use?: string | string[];
113+
/** Sets the trap mode to use. */
114+
trapMode?: "allow" | "clamp" | "js";
115+
/** Specifies additional Binaryen passes to run. */
116+
runPasses?: string | string[];
117+
/** Enables WebAssembly features that are disabled by default. */
118+
enable?: string | string[];
119+
/** Disables WebAssembly features that are enabled by default. */
120+
disable?: string | string[];
121+
/** Specifies the path to a custom transform to 'require'. */
122+
transform?: string | string[];
123+
/** Make yourself sad for no good reason. */
124+
pedantic?: boolean;
125+
/** Enables tracing of package resolution. */
126+
traceResolution?: boolean;
127+
/** Lists files to be compiled and exits. */
128+
listFiles?: boolean;
129+
/** Prints measuring information on I/O and compile times. */
130+
measure?: boolean;
131+
/** Prints the module's runtime type information to stderr. */
132+
printrtti?: boolean;
133+
/** Disables terminal colors. */
134+
noColors?: boolean;
135+
}
136+
137+
/** Compiler API options. */
138+
interface APIOptions {
55139
/** Standard output stream to use. */
56140
stdout?: OutputStream;
57141
/** Standard error stream to use. */
@@ -77,7 +161,7 @@ export function compileString(sources: { [key: string]: string } | string, optio
77161
}
78162

79163
/** Runs the command line utility using the specified arguments array. */
80-
export function main(argv: string[], options: CompilerOptions, callback?: (err: Error | null) => number): number;
164+
export function main(argv: string[], options: APIOptions, callback?: (err: Error | null) => number): number;
81165
export function main(argv: string[], callback?: (err: Error | null) => number): number;
82166

83167
/** Checks diagnostics emitted so far for errors. */

cli/asc.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,13 @@ exports.compileString = (sources, options) => {
110110
];
111111
Object.keys(options || {}).forEach(key => {
112112
var val = options[key];
113-
if (Array.isArray(val)) val.forEach(val => argv.push("--" + key, String(val)));
114-
else argv.push("--" + key, String(val));
113+
var opt = exports.options[key];
114+
if (opt && opt.type === "b") {
115+
if (val) argv.push("--" + key);
116+
} else {
117+
if (Array.isArray(val)) val.forEach(val => argv.push("--" + key, String(val)));
118+
else argv.push("--" + key, String(val));
119+
}
115120
});
116121
exports.main(argv.concat(Object.keys(sources)), {
117122
stdout: output.stdout,

src/compiler.ts

Lines changed: 97 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -623,9 +623,12 @@ export class Compiler extends DiagnosticEmitter {
623623
break;
624624
}
625625
case ElementKind.FIELD: {
626-
this.makeExportedFieldGetter(prefix + GETTER_PREFIX + name, <Field>element);
627-
if (!element.is(CommonFlags.READONLY)) {
628-
this.makeExportedFieldSetter(prefix + SETTER_PREFIX + name, <Field>element);
626+
if (element.is(CommonFlags.COMPILED)) {
627+
let module = this.module;
628+
module.addFunctionExport((<Field>element).internalGetterName, prefix + GETTER_PREFIX + name);
629+
if (!element.is(CommonFlags.READONLY)) {
630+
module.addFunctionExport((<Field>element).internalSetterName, prefix + SETTER_PREFIX + name);
631+
}
629632
}
630633
break;
631634
}
@@ -674,48 +677,6 @@ export class Compiler extends DiagnosticEmitter {
674677
}
675678
}
676679

677-
/** Makes an exported function to get the value of an instance field. */
678-
private makeExportedFieldGetter(name: string, field: Field): void {
679-
var type = field.type;
680-
var nativeThisType = this.options.nativeSizeType;
681-
var nativeValueType = type.toNativeType();
682-
var module = this.module;
683-
var returnExpr = module.load(type.byteSize, type.is(TypeFlags.SIGNED),
684-
module.local_get(0, nativeThisType),
685-
nativeValueType, field.memoryOffset
686-
);
687-
// functions retain the return value for the caller
688-
if (type.isManaged) returnExpr = this.makeRetain(returnExpr);
689-
module.addFunction(name, nativeThisType, nativeValueType, null, returnExpr);
690-
module.addFunctionExport(name, name);
691-
}
692-
693-
/** Makes an exported function to set the value of an instance field. */
694-
private makeExportedFieldSetter(name: string, field: Field): void {
695-
var type = field.type;
696-
var nativeThisType = this.options.nativeSizeType;
697-
var nativeValueType = type.toNativeType();
698-
var module = this.module;
699-
var valueExpr = module.local_get(1, nativeValueType);
700-
if (type.isManaged) {
701-
valueExpr = this.makeReplace(
702-
module.load(type.byteSize, false,
703-
module.local_get(0, nativeThisType),
704-
nativeValueType, field.memoryOffset
705-
),
706-
valueExpr
707-
);
708-
}
709-
module.addFunction(name, createType([ nativeThisType, nativeValueType ]), NativeType.None, null,
710-
module.store(type.byteSize,
711-
module.local_get(0, nativeThisType),
712-
valueExpr,
713-
nativeValueType, field.memoryOffset
714-
)
715-
);
716-
module.addFunctionExport(name, name);
717-
}
718-
719680
// === Elements =================================================================================
720681

721682
/** Compiles any element. */
@@ -1423,15 +1384,12 @@ export class Compiler extends DiagnosticEmitter {
14231384
}
14241385
break;
14251386
}
1426-
case ElementKind.FIELD_PROTOTYPE: {
1427-
element.set(CommonFlags.COMPILED);
1387+
case ElementKind.FIELD: {
1388+
this.compileField(<Field>element);
14281389
break;
14291390
}
14301391
case ElementKind.PROPERTY: {
1431-
let getterInstance = (<Property>element).getterInstance;
1432-
if (getterInstance) this.compileFunction(getterInstance);
1433-
let setterInstance = (<Property>element).setterInstance;
1434-
if (setterInstance) this.compileFunction(setterInstance);
1392+
this.compileProperty(<Property>element);
14351393
break;
14361394
}
14371395
}
@@ -1440,6 +1398,94 @@ export class Compiler extends DiagnosticEmitter {
14401398
return true;
14411399
}
14421400

1401+
/** Compiles an instance field to a getter and a setter. */
1402+
compileField(instance: Field): bool {
1403+
this.compileFieldGetter(instance);
1404+
this.compileFieldSetter(instance);
1405+
return instance.is(CommonFlags.COMPILED);
1406+
}
1407+
1408+
/** Compiles the getter of the specified instance field. */
1409+
compileFieldGetter(instance: Field): bool {
1410+
// A getter retains, while a load, as of a field access, does not.
1411+
if (instance.getterRef) return true;
1412+
var type = instance.type;
1413+
var nativeThisType = this.options.nativeSizeType;
1414+
var nativeValueType = type.toNativeType();
1415+
var module = this.module;
1416+
var valueExpr = module.load(type.byteSize, type.is(TypeFlags.SIGNED),
1417+
module.local_get(0, nativeThisType),
1418+
nativeValueType, instance.memoryOffset
1419+
);
1420+
if (type.isManaged) valueExpr = this.makeRetain(valueExpr);
1421+
instance.getterRef = module.addFunction(instance.internalGetterName, nativeThisType, nativeValueType, null, valueExpr);
1422+
if (instance.setterRef) instance.set(CommonFlags.COMPILED);
1423+
return true;
1424+
}
1425+
1426+
/** Compiles the setter of the specified instance field. */
1427+
compileFieldSetter(instance: Field): bool {
1428+
if (instance.setterRef) return true;
1429+
var type = instance.type;
1430+
var nativeThisType = this.options.nativeSizeType;
1431+
var nativeValueType = type.toNativeType();
1432+
var module = this.module;
1433+
var valueExpr = module.local_get(1, nativeValueType);
1434+
if (type.isManaged) {
1435+
valueExpr = this.makeReplace(
1436+
module.load(type.byteSize, false,
1437+
module.local_get(0, nativeThisType),
1438+
nativeValueType, instance.memoryOffset
1439+
),
1440+
valueExpr
1441+
);
1442+
}
1443+
instance.setterRef = module.addFunction(instance.internalSetterName, createType([ nativeThisType, nativeValueType ]), NativeType.None, null,
1444+
module.store(type.byteSize,
1445+
module.local_get(0, nativeThisType),
1446+
valueExpr,
1447+
nativeValueType, instance.memoryOffset
1448+
)
1449+
);
1450+
if (instance.getterRef) instance.set(CommonFlags.COMPILED);
1451+
return true;
1452+
}
1453+
1454+
/** Compiles a property to a getter and potentially a setter. */
1455+
compileProperty(instance: Property): bool {
1456+
this.compilePropertyGetter(instance);
1457+
this.compilePropertySetter(instance);
1458+
return instance.is(CommonFlags.COMPILED);
1459+
}
1460+
1461+
/* Compiles the getter of the specified property. */
1462+
compilePropertyGetter(instance: Property): bool {
1463+
var getterInstance = instance.getterInstance;
1464+
if (getterInstance) {
1465+
let ret = this.compileFunction(getterInstance);
1466+
let setterInstance = instance.setterInstance;
1467+
if (getterInstance.is(CommonFlags.COMPILED) && (!setterInstance || setterInstance.is(CommonFlags.COMPILED))) {
1468+
instance.set(CommonFlags.COMPILED);
1469+
}
1470+
return ret;
1471+
}
1472+
return false;
1473+
}
1474+
1475+
/** Compiles the setter of the specified property. */
1476+
compilePropertySetter(instance: Property): bool {
1477+
var setterInstance = instance.setterInstance;
1478+
if (setterInstance) {
1479+
let ret = this.compileFunction(setterInstance);
1480+
let getterInstance = instance.getterInstance;
1481+
if (getterInstance !== null && getterInstance.is(CommonFlags.COMPILED) && setterInstance.is(CommonFlags.COMPILED)) {
1482+
instance.set(CommonFlags.COMPILED);
1483+
}
1484+
return ret;
1485+
}
1486+
return false;
1487+
}
1488+
14431489
// === Memory ===================================================================================
14441490

14451491
/** Adds a static memory segment with the specified data. */
@@ -8290,7 +8336,6 @@ export class Compiler extends DiagnosticEmitter {
82908336
assert((<Field>target).memoryOffset >= 0);
82918337
let thisExpression = assert(this.resolver.currentThisExpression);
82928338
let thisExpr = this.compileExpression(thisExpression, this.options.usizeType);
8293-
// FIXME
82948339
let thisType = this.currentType;
82958340
if (thisType.is(TypeFlags.NULLABLE)) {
82968341
if (!flow.isNonnull(thisExpr, thisType)) {

src/program.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3048,6 +3048,10 @@ export class Field extends VariableLikeElement {
30483048
prototype: FieldPrototype;
30493049
/** Field memory offset, if an instance field. */
30503050
memoryOffset: i32 = -1;
3051+
/** Getter function reference, if compiled. */
3052+
getterRef: FunctionRef = 0;
3053+
/** Setter function reference, if compiled. */
3054+
setterRef: FunctionRef = 0;
30513055

30523056
/** Constructs a new field. */
30533057
constructor(
@@ -3071,6 +3075,16 @@ export class Field extends VariableLikeElement {
30713075
this.setType(type);
30723076
registerConcreteElement(this.program, this);
30733077
}
3078+
3079+
/** Gets the internal name of the respective getter function. */
3080+
get internalGetterName(): string {
3081+
return this.parent.internalName + INSTANCE_DELIMITER + GETTER_PREFIX + this.name;
3082+
}
3083+
3084+
/** Gets the internal name of the respective setter function. */
3085+
get internalSetterName(): string {
3086+
return this.parent.internalName + INSTANCE_DELIMITER + SETTER_PREFIX + this.name;
3087+
}
30743088
}
30753089

30763090
/** A property comprised of a getter and a setter function. */

tests/browser-asc.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ if (typeof asc.definitionFiles.portable !== "string") throw Error("missing bundl
55

66
const stdout = asc.createMemoryStream();
77
const stderr = asc.createMemoryStream();
8-
const files = { "module.ts": `import "allocator/arena";` };
8+
const files = { "module.ts": `export function test(): void {}` };
99

1010
console.log("# asc --version");
1111

@@ -73,7 +73,7 @@ process.stdout.write(stderr.toString());
7373

7474
console.log("\n# asc.compileString");
7575

76-
const output = asc.compileString(`import "allocator/arena";`, { optimizeLevel: 2 });
76+
const output = asc.compileString(`export function test(): void {}`, { optimizeLevel: 3, runtime: "none", exportTable: true, measure: true });
7777
console.log(">>> .stdout >>>");
7878
process.stdout.write(output.stdout.toString());
7979
console.log(">>> .stderr >>>");

tests/compiler/exports.optimized.wat

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,20 @@
2828
(export "animals.Animal.CAT" (global $exports/animals.Animal.CAT))
2929
(export "animals.Animal.DOG" (global $exports/animals.Animal.DOG))
3030
(export "Car" (global $exports/Car))
31-
(export "Car#get:doors" (func $exports/Car#get:numDoors))
32-
(export "Car#set:doors" (func $exports/Car#set:numDoors))
31+
(export "Car#get:doors" (func $exports/Car#get:doors))
32+
(export "Car#set:doors" (func $exports/Car#set:doors))
3333
(export "Car#constructor" (func $exports/Car#constructor|trampoline))
34-
(export "Car#get:numDoors" (func $exports/Car#get:numDoors))
35-
(export "Car#set:numDoors" (func $exports/Car#set:numDoors))
34+
(export "Car#get:numDoors" (func $exports/Car#get:doors))
35+
(export "Car#set:numDoors" (func $exports/Car#set:doors))
3636
(export "Car#openDoors" (func $exports/Car#openDoors))
3737
(export "Car.TIRES" (global $exports/Car.TIRES))
3838
(export "Car.getNumTires" (func $exports/Car.getNumTires))
3939
(export "vehicles.Car" (global $exports/vehicles.Car))
40-
(export "vehicles.Car#get:doors" (func $exports/Car#get:numDoors))
41-
(export "vehicles.Car#set:doors" (func $exports/Car#set:numDoors))
40+
(export "vehicles.Car#get:doors" (func $exports/Car#get:doors))
41+
(export "vehicles.Car#set:doors" (func $exports/Car#set:doors))
4242
(export "vehicles.Car#constructor" (func $exports/vehicles.Car#constructor|trampoline))
43-
(export "vehicles.Car#get:numDoors" (func $exports/Car#get:numDoors))
44-
(export "vehicles.Car#set:numDoors" (func $exports/Car#set:numDoors))
43+
(export "vehicles.Car#get:numDoors" (func $exports/Car#get:doors))
44+
(export "vehicles.Car#set:numDoors" (func $exports/Car#set:doors))
4545
(export "vehicles.Car#openDoors" (func $exports/Car#openDoors))
4646
(export "vehicles.Car.TIRES" (global $exports/vehicles.Car.TIRES))
4747
(export "vehicles.Car.getNumTires" (func $exports/Car.getNumTires))
@@ -129,11 +129,11 @@
129129
i32.store offset=12
130130
local.get $2
131131
)
132-
(func $exports/Car#get:numDoors (; 5 ;) (param $0 i32) (result i32)
132+
(func $exports/Car#get:doors (; 5 ;) (param $0 i32) (result i32)
133133
local.get $0
134134
i32.load
135135
)
136-
(func $exports/Car#set:numDoors (; 6 ;) (param $0 i32) (param $1 i32)
136+
(func $exports/Car#set:doors (; 6 ;) (param $0 i32) (param $1 i32)
137137
local.get $0
138138
local.get $1
139139
i32.store

0 commit comments

Comments
 (0)