Skip to content

Commit d568e82

Browse files
authored
Backport fixes made in #1559 (#1568)
1 parent 38f7705 commit d568e82

File tree

78 files changed

+3897
-1617
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+3897
-1617
lines changed

cli/shim/process.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ module.exports = {
66
umask() {
77
return 0;
88
},
9-
hrtime
9+
hrtime,
10+
argv: []
1011
};
1112

1213
// https://github.com/kumavis/browser-process-hrtime v1.0.0

src/builtins.ts

Lines changed: 149 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,6 @@ import {
6868
getConstValueI32,
6969
getConstValueF32,
7070
getConstValueF64,
71-
Relooper,
72-
RelooperBlockRef,
7371
SIMDLoadOp,
7472
getLocalGetIndex,
7573
createType,
@@ -82,7 +80,6 @@ import {
8280
Field,
8381
Global,
8482
DecoratorFlags,
85-
Element,
8683
ClassPrototype,
8784
Class
8885
} from "./program";
@@ -8691,134 +8688,184 @@ export function compileVisitGlobals(compiler: Compiler): void {
86918688
);
86928689
}
86938690

8694-
/** Compiles the `visit_members` function. */
8695-
export function compileVisitMembers(compiler: Compiler): void {
8691+
/** Ensures that the visitor function of the specified class is compiled. */
8692+
function ensureVisitMembersOf(compiler: Compiler, instance: Class): void {
8693+
assert(instance.type.isManaged);
8694+
if (instance.visitRef) return;
8695+
86968696
var program = compiler.program;
86978697
var module = compiler.module;
86988698
var usizeType = program.options.usizeType;
86998699
var nativeSizeType = usizeType.toNativeType();
87008700
var nativeSizeSize = usizeType.byteSize;
8701-
var managedClasses = program.managedClasses;
87028701
var visitInstance = assert(program.visitInstance);
8703-
var blocks = new Array<RelooperBlockRef>();
8704-
var relooper = Relooper.create(module);
8705-
8706-
// this function is @lazy: make sure it exists
8707-
compiler.compileFunction(visitInstance, true);
8708-
8709-
var outer = relooper.addBlockWithSwitch(
8710-
module.nop(),
8711-
module.load(nativeSizeSize, false,
8712-
nativeSizeType == NativeType.I64
8713-
? module.binary(BinaryOp.SubI64,
8714-
module.local_get(0, nativeSizeType),
8715-
module.i64(8)
8716-
)
8717-
: module.binary(BinaryOp.SubI32,
8718-
module.local_get(0, nativeSizeType),
8719-
module.i32(8) // rtId is at -8
8720-
),
8721-
NativeType.I32,
8722-
0
8723-
)
8724-
);
8725-
8726-
var lastId = 0;
8727-
// TODO: for (let [instanceId, instance] of managedClasses) {
8728-
for (let _keys = Map_keys(managedClasses), i = 0, k = _keys.length; i < k; ++i) {
8729-
let instanceId = _keys[i];
8730-
let instance = assert(managedClasses.get(instanceId));
8731-
assert(instance.type.isManaged);
8732-
assert(instanceId == lastId++);
8733-
8734-
let visitImpl: Element | null;
8735-
let code = new Array<ExpressionRef>();
8702+
var body = new Array<ExpressionRef>();
8703+
8704+
// If the class has a base class, call its visitor first
8705+
var base = instance.base;
8706+
if (base) {
8707+
body.push(
8708+
module.call(base.internalName + "~visit", [
8709+
module.local_get(0, nativeSizeType), // this
8710+
module.local_get(1, NativeType.I32) // cookie
8711+
], NativeType.None)
8712+
);
8713+
}
87368714

8737-
// if a library element, check if it implements a custom traversal function
8738-
if (instance.isDeclaredInLibrary && (visitImpl = instance.lookupInSelf("__visit_impl")) !== null) {
8739-
assert(visitImpl.kind == ElementKind.FUNCTION_PROTOTYPE);
8740-
let visitFunc = program.resolver.resolveFunction(<FunctionPrototype>visitImpl, null);
8741-
if (!visitFunc || !compiler.compileFunction(visitFunc)) {
8742-
code.push(
8715+
// Some standard library components provide a custom visitor implementation,
8716+
// for example to visit all members of a collection, e.g. arrays and maps.
8717+
var hasVisitImpl = false;
8718+
if (instance.isDeclaredInLibrary) {
8719+
let visitPrototype = instance.lookupInSelf("__visit");
8720+
if (visitPrototype) {
8721+
assert(visitPrototype.kind == ElementKind.FUNCTION_PROTOTYPE);
8722+
let visitInstance = program.resolver.resolveFunction(<FunctionPrototype>visitPrototype, null);
8723+
if (!visitInstance || !compiler.compileFunction(visitInstance)) {
8724+
body.push(
87438725
module.unreachable()
87448726
);
87458727
} else {
8746-
let visitSig = visitFunc.signature;
8747-
let visitThisType = assert(visitSig.thisType);
8728+
let visitSignature = visitInstance.signature;
8729+
let visitThisType = assert(visitSignature.thisType);
87488730
assert(
8749-
visitSig.parameterTypes.length == 1 &&
8750-
visitSig.parameterTypes[0] == Type.u32 &&
8751-
visitSig.returnType == Type.void &&
8731+
visitSignature.parameterTypes.length == 1 &&
8732+
visitSignature.parameterTypes[0] == Type.u32 &&
8733+
visitSignature.returnType == Type.void &&
87528734
instance.type.isStrictlyAssignableTo(visitThisType) // incl. implemented on super
87538735
);
8754-
code.push(
8755-
module.call(visitFunc.internalName, [
8756-
module.local_get(0, nativeSizeType), // ref
8736+
body.push(
8737+
module.call(visitInstance.internalName, [
8738+
module.local_get(0, nativeSizeType), // this
87578739
module.local_get(1, NativeType.I32) // cookie
87588740
], NativeType.None)
87598741
);
87608742
}
8743+
hasVisitImpl = true;
8744+
}
8745+
}
87618746

8762-
// otherwise generate traversal logic for own fields
8763-
} else {
8764-
let members = instance.members;
8765-
if (members) {
8766-
// TODO: for (let member of members.values()) {
8767-
for (let _values = Map_values(members), j = 0, l = _values.length; j < l; ++j) {
8768-
let member = unchecked(_values[j]);
8769-
if (member.kind == ElementKind.FIELD) {
8770-
if ((<Field>member).parent === instance) {
8771-
let fieldType = (<Field>member).type;
8772-
if (fieldType.isManaged) {
8773-
let fieldOffset = (<Field>member).memoryOffset;
8774-
assert(fieldOffset >= 0);
8775-
code.push(
8776-
// if ($2 = value) FIELDCLASS~traverse($2)
8777-
module.if(
8778-
module.local_tee(2,
8779-
module.load(nativeSizeSize, false,
8780-
module.local_get(0, nativeSizeType),
8781-
nativeSizeType, fieldOffset
8782-
)
8783-
),
8784-
module.call(visitInstance.internalName, [
8785-
module.local_get(2, nativeSizeType), // ref
8786-
module.local_get(1, NativeType.I32) // cookie
8787-
], NativeType.None)
8788-
)
8789-
);
8790-
}
8747+
// Otherwise, if there is no custom visitor, generate a visitor function
8748+
// according to class layout, visiting all _own_ managed members.
8749+
var needsTempValue = false;
8750+
if (!hasVisitImpl) {
8751+
let members = instance.members;
8752+
if (members) {
8753+
// TODO: for (let member of members.values()) {
8754+
for (let _values = Map_values(members), j = 0, l = _values.length; j < l; ++j) {
8755+
let member = unchecked(_values[j]);
8756+
if (member.kind == ElementKind.FIELD) {
8757+
if ((<Field>member).parent === instance) {
8758+
let fieldType = (<Field>member).type;
8759+
if (fieldType.isManaged) {
8760+
let fieldOffset = (<Field>member).memoryOffset;
8761+
assert(fieldOffset >= 0);
8762+
needsTempValue = true;
8763+
body.push(
8764+
// if ($2 = value) __visit($2, $1)
8765+
module.if(
8766+
module.local_tee(2,
8767+
module.load(nativeSizeSize, false,
8768+
module.local_get(0, nativeSizeType),
8769+
nativeSizeType, fieldOffset
8770+
)
8771+
),
8772+
module.call(visitInstance.internalName, [
8773+
module.local_get(2, nativeSizeType), // value
8774+
module.local_get(1, NativeType.I32) // cookie
8775+
], NativeType.None)
8776+
)
8777+
);
87918778
}
87928779
}
87938780
}
87948781
}
87958782
}
8796-
if (!instance.base) code.push(module.return());
8797-
let block = relooper.addBlock(
8798-
module.flatten(code)
8799-
);
8800-
relooper.addBranchForSwitch(outer, block, [ instanceId ]);
8801-
blocks.push(block);
88028783
}
8803-
// TODO: for (let [instanceId, instance] of managedClasses) {
8784+
8785+
// Create the visitor function
8786+
instance.visitRef = module.addFunction(instance.internalName + "~visit",
8787+
createType([nativeSizeType, NativeType.I32]),
8788+
NativeType.None,
8789+
needsTempValue ? [ nativeSizeType ] : null,
8790+
module.flatten(body, NativeType.None)
8791+
);
8792+
8793+
// And make sure the base visitor function exists
8794+
if (base) ensureVisitMembersOf(compiler, base);
8795+
}
8796+
8797+
/** Compiles the `__visit_members` function. */
8798+
export function compileVisitMembers(compiler: Compiler): void {
8799+
var program = compiler.program;
8800+
var module = compiler.module;
8801+
var usizeType = program.options.usizeType;
8802+
var nativeSizeType = usizeType.toNativeType();
8803+
var managedClasses = program.managedClasses;
8804+
var visitInstance = assert(program.visitInstance);
8805+
compiler.compileFunction(visitInstance, true); // is lazy, make sure it is compiled
8806+
8807+
// Prepare a mapping of class names to visitor calls. Each name corresponds to
8808+
// the respective sequential (0..N) class id.
8809+
var names = new Array<string>();
8810+
var cases = new Array<ExpressionRef>();
8811+
var nextId = 0;
88048812
for (let _keys = Map_keys(managedClasses), i = 0, k = _keys.length; i < k; ++i) {
8805-
let instanceId = unchecked(_keys[i]);
8813+
let instanceId = _keys[i];
8814+
assert(instanceId == nextId++);
88068815
let instance = assert(managedClasses.get(instanceId));
8807-
let base = instance.base;
8808-
if (base) relooper.addBranch(blocks[instanceId], blocks[base.id]);
8809-
}
8810-
blocks.push(
8811-
relooper.addBlock(
8812-
module.unreachable()
8816+
names[i] = instance.internalName;
8817+
cases[i] = module.block(null, [
8818+
module.call(instance.internalName + "~visit", [
8819+
module.local_get(0, nativeSizeType), // this
8820+
module.local_get(1, NativeType.I32) // cookie
8821+
], NativeType.None),
8822+
module.return()
8823+
], NativeType.None);
8824+
ensureVisitMembersOf(compiler, instance);
8825+
}
8826+
8827+
// Make a br_table of the mapping, calling visitor functions by unique class id
8828+
var current = module.block(names[0], [
8829+
module.switch(names, "invalid",
8830+
// load<u32>(changetype<usize>(this) - 8)
8831+
module.load(4, false,
8832+
nativeSizeType == NativeType.I64
8833+
? module.binary(BinaryOp.SubI64,
8834+
module.local_get(0, nativeSizeType),
8835+
module.i64(8)
8836+
)
8837+
: module.binary(BinaryOp.SubI32,
8838+
module.local_get(0, nativeSizeType),
8839+
module.i32(8) // rtId is at -8
8840+
),
8841+
NativeType.I32, 0
8842+
)
88138843
)
8814-
);
8815-
relooper.addBranchForSwitch(outer, blocks[blocks.length - 1], []); // default
8816-
compiler.compileFunction(visitInstance);
8844+
], NativeType.None);
8845+
8846+
// Wrap blocks in order
8847+
for (let i = 0, k = names.length - 1; i < k; ++i) {
8848+
current = module.block(names[i + 1], [
8849+
current,
8850+
cases[i]
8851+
], NativeType.None);
8852+
}
8853+
8854+
// Wrap the last id in an 'invalid' block to break out of on invalid ids
8855+
current = module.block("invalid", [
8856+
current,
8857+
cases[names.length - 1]
8858+
], NativeType.None);
8859+
8860+
// Add the function, executing an unreachable if breaking to 'invalid'
88178861
module.addFunction(BuiltinNames.visit_members,
8818-
createType([ usizeType.toNativeType(), NativeType.I32 ]), // ref, cookie
8862+
createType([ nativeSizeType, NativeType.I32 ]), // this, cookie
88198863
NativeType.None, // => void
8820-
[ nativeSizeType ],
8821-
relooper.renderAndDispose(outer, 2)
8864+
null,
8865+
module.flatten([
8866+
current,
8867+
module.unreachable()
8868+
])
88228869
);
88238870
}
88248871

src/compiler.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10508,8 +10508,12 @@ export class Compiler extends DiagnosticEmitter {
1050810508
}
1050910509
}
1051010510
var parameterTypes = signature.parameterTypes;
10511+
var parameterNodes = reportNode.parameters;
1051110512
for (let i = 0, k = parameterTypes.length; i < k; ++i) {
10512-
if (!this.checkTypeSupported(parameterTypes[i], reportNode.parameters[i])) {
10513+
let parameterReportNode: Node;
10514+
if (parameterNodes.length > i) parameterReportNode = parameterNodes[i];
10515+
else parameterReportNode = reportNode;
10516+
if (!this.checkTypeSupported(parameterTypes[i], parameterReportNode)) {
1051310517
supported = false;
1051410518
}
1051510519
}

src/flow.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,7 @@ export class Flow {
612612
/** Tests if the specified `this` field has the specified flag or flags. */
613613
isThisFieldFlag(field: Field, flag: FieldFlags): bool {
614614
var fieldFlags = this.thisFieldFlags;
615-
if (fieldFlags) {
615+
if (fieldFlags != null && fieldFlags.has(field)) {
616616
return (changetype<FieldFlags>(fieldFlags.get(field)) & flag) == flag;
617617
}
618618
return false;

src/glue/wasm/i64.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ function i64_is<T>(value: T): bool {
2323
// @ts-ignore: decorator
2424
@global @inline
2525
function i64_new(lo: i32, hi: i32 = 0): i64 {
26-
return lo | (hi << 32);
26+
return <i64><u32>lo | (<i64>hi << 32);
2727
}
2828

2929
// @ts-ignore: decorator

src/program.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4117,6 +4117,8 @@ export class Class extends TypedElement {
41174117
implementers: Set<Class> | null = null;
41184118
/** Whether the field initialization check has already been performed. */
41194119
didCheckFieldInitialization: bool = false;
4120+
/** Runtime visitor function reference. */
4121+
visitRef: FunctionRef = 0;
41204122

41214123
/** Gets the unique runtime id of this class. */
41224124
get id(): u32 {
@@ -4273,9 +4275,8 @@ export class Class extends TypedElement {
42734275
var instance: Class | null = this;
42744276
do {
42754277
let overloads = instance.overloads;
4276-
if (overloads) {
4277-
let overload = overloads.get(kind);
4278-
if (overload) return overload;
4278+
if (overloads != null && overloads.has(kind)) {
4279+
return assert(overloads.get(kind));
42794280
}
42804281
instance = instance.base;
42814282
} while (instance);

std/assembly/array.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,7 @@ export class Array<T> {
563563

564564
// RT integration
565565

566-
@unsafe private __visit_impl(cookie: u32): void {
566+
@unsafe private __visit(cookie: u32): void {
567567
if (isManaged<T>()) {
568568
let cur = this.dataStart;
569569
let end = cur + (<usize>this.length_ << alignof<T>());

std/assembly/function.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ type auto = i32;
3131

3232
// RT integration
3333

34-
@unsafe private __visit_impl(cookie: u32): void {
34+
@unsafe private __visit(cookie: u32): void {
3535
// Env is either `null` (nop) or compiler-generated
3636
__visit(this._env, cookie);
3737
}

std/assembly/map.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ export class Map<K,V> {
233233

234234
// RT integration
235235

236-
@unsafe private __visit_impl(cookie: u32): void {
236+
@unsafe private __visit(cookie: u32): void {
237237
__visit(changetype<usize>(this.buckets), cookie);
238238
var entries = changetype<usize>(this.entries);
239239
if (isManaged<K>() || isManaged<V>()) {

std/assembly/set.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ export class Set<T> {
196196

197197
// RT integration
198198

199-
@unsafe private __visit_impl(cookie: u32): void {
199+
@unsafe private __visit(cookie: u32): void {
200200
__visit(changetype<usize>(this.buckets), cookie);
201201
var entries = changetype<usize>(this.entries);
202202
if (isManaged<T>()) {

0 commit comments

Comments
 (0)