Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wasm library test using generic #4

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
// deal with import/export package
"import/no-extraneous-dependencies": ["error", { "optionalDependencies": false }],
"@typescript-eslint/no-this-alias": ["off"],
"@typescript-eslint/no-namespace": ["off"]
"@typescript-eslint/no-namespace": ["off"],
"@typescript-eslint/no-empty-interface": ["off"]

// eslint-plugin-no-null
// restricts using null as explicit values for variables or function arguments.
Expand Down
5 changes: 5 additions & 0 deletions lib/builtin/builtin_name.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ export namespace BuiltinNames {
export const DATAVIEW = 'DataView';
export const STRINGCONSTRCTOR = 'StringConstructor';

// wasm library type name
export const WASMARRAY = 'WASMArray';
export const WASMSTRUCT = 'WASMStruct';

// decorator name
export const decorator = 'binaryen';

Expand Down Expand Up @@ -269,6 +273,7 @@ export namespace BuiltinNames {
'ArrayConstructor',
'StringConstructor',
];
export const WASMLibraryTypes = [WASMARRAY, WASMSTRUCT];

export function getSpecializedFuncName(
mangledName: string,
Expand Down
209 changes: 209 additions & 0 deletions lib/builtin/wasm_lib_type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
interface PackedType {}
interface PackedType_Not_Packed extends PackedType {}
interface PackedType_I8 extends PackedType {}
interface PackedType_I16 extends PackedType {}

interface Mutability {}
interface Mutability_Immutable extends Mutability {}
interface Mutability_Mutable extends Mutability {}

interface Nullability {}
interface Nullability_NonNullable extends Nullability {}
interface Nullability_Nullable extends Nullability {}

interface HasBaseType {}
interface HasBaseType_True extends HasBaseType {}
interface HasBaseType_False extends HasBaseType {}

type i32 = number;

class WASMArray<
T,
P extends PackedType,
M extends Mutability,
N extends Nullability,
> {
elements: T[];
packedType: P;
mutable: M;
nullable: N;

constructor(elements: T[], packedType: P, mutable: M, nullable: N) {
this.elements = elements;
this.packedType = packedType;
this.mutable = mutable;
this.nullable = nullable;
}

static createWithDefaultValue<
T,
P extends PackedType,
M extends Mutability,
N extends Nullability,
>() {
return new WASMArray<T, P, M, N>([], {} as P, {} as M, {} as N);
}

getElem(index: i32): T {
return this.elements[index];
}

setElem(index: i32, elemValue: T) {
this.elements[index] = elemValue;
}

push(...items: T[]): number {
return this.elements.push(...items);
}

findIndex(
predicate: (value: T, index: number, obj: T[]) => boolean,
): number {
return this.elements.findIndex(predicate);
}
}

// eg.

const arr1 = WASMArray.createWithDefaultValue<
number,
PackedType_Not_Packed,
Mutability_Mutable,
Nullability_Nullable
>();
const arr2 = new WASMArray<
number,
PackedType_Not_Packed,
Mutability_Mutable,
Nullability_Nullable
>([1, 2], {}, {}, {});

arr1.push(1);
arr1.setElem(0, 10);
arr1.getElem(0);

class WASMStruct<
T extends any[],
P extends PackedType[],
M extends Mutability[],
N extends Nullability,
B extends HasBaseType,
T_B extends any[],
P_B extends PackedType[],
M_B extends Mutability[],
N_B extends Nullability,
> {
fields: T;
packedTypes: P;
mutables: M;
nullable: N;
hasBaseType: B;
baseFields: T_B;
basePackedTypes: P_B;
baseMutables: M_B;
baseNullable: N_B;

constructor(
fields: T,
packedTypes: P,
mutables: M,
nullable: N,
hasBaseType: B,
baseFields: T_B,
basePackedTypes: P_B,
baseMutables: M_B,
baseNullable: N_B,
) {
this.fields = fields;
this.packedTypes = packedTypes;
this.mutables = mutables;
this.nullable = nullable;
this.hasBaseType = hasBaseType;
this.baseFields = baseFields;
this.basePackedTypes = basePackedTypes;
this.baseMutables = baseMutables;
this.baseNullable = baseNullable;
}

static createWithDefaultValue() {
return new WASMStruct(
[],
[],
[],
{} as Nullability_Nullable,
{} as HasBaseType_False,
[],
[],
[],
[],
);
}

static createWithNoBaseType<
T extends any[],
P extends PackedType[],
M extends Mutability[],
N extends Nullability,
>(fields: T, packedTypes: P, mutables: M, nullable: N) {
return new WASMStruct(
fields,
packedTypes,
mutables,
nullable,
{} as HasBaseType_False,
[],
[],
[],
[],
);
}

getField<F>(index: i32): F {
return this.fields[index];
}

setField<F>(index: i32, fieldValue: F) {
this.fields[index] = fieldValue;
}
}

// eg.
const struct1 = WASMStruct.createWithDefaultValue();
const struct2 = WASMStruct.createWithNoBaseType<
[number, string],
[PackedType_Not_Packed, PackedType_Not_Packed],
[Mutability_Mutable, Mutability_Mutable],
Nullability_Nullable
>([1, 'hi'], [{}, {}], [{}, {}], {});
struct1.setField<number>(0, 20);
struct1.getField<number>(0);

// eg. Map
// ts code
// const map_instance = new Map<number, string>();
// map_instance.set(1, 'hi');
// const value = map_instance.get(1);
const keys_arr = WASMArray.createWithDefaultValue<
number,
PackedType_Not_Packed,
Mutability_Mutable,
Nullability_Nullable
>();
const values_arr = WASMArray.createWithDefaultValue<
string,
PackedType_Not_Packed,
Mutability_Mutable,
Nullability_Nullable
>();
const map_instance = WASMStruct.createWithNoBaseType<
[typeof keys_arr, typeof values_arr],
[PackedType_Not_Packed, PackedType_Not_Packed],
[Mutability_Mutable, Mutability_Mutable],
Nullability_Nullable
>([keys_arr, values_arr], [{}, {}], [{}, {}], {});

keys_arr.push(1);
values_arr.push('hi');

const index = keys_arr.findIndex((value) => value === 1);
const value = values_arr.getElem(index);
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
},
"lint-staged": {
"*.ts": [
"eslint --ignore-path .eslintignore --config .eslintrc.json --fix '**/*.ts'",
"eslint --ignore-path .eslintignore --config .eslintrc.json --fix --quiet '**/*.ts'",
"prettier --ignore-path .prettierignore --config .prettierrc.json --write '**/*.ts'"
]
},
Expand Down
32 changes: 32 additions & 0 deletions src/backend/binaryen/wasm_type_gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -470,8 +470,12 @@ export class WASMTypeGen {

createWASMObjectType(type: ObjectType) {
const metaInfo = type.meta;
const levelNames = metaInfo.name.split(BuiltinNames.moduleDelimiter);
const objectName = levelNames[levelNames.length - 1].split('<')[0];
if (BuiltinNames.builtInObjectTypes.includes(metaInfo.name)) {
this.createWASMBuiltinType(type);
} else if (BuiltinNames.WASMLibraryTypes.includes(objectName)) {
this.createWASMLibraryType(type, objectName);
} else {
if (metaInfo.isInterface) {
this.createWASMInfcType(type);
Expand All @@ -492,6 +496,34 @@ export class WASMTypeGen {
}
}

createWASMArrayLibraryType(type: ObjectType) {
this.typeMap.set(type, arrayBufferTypeInfo.typeRef);
this.heapTypeMap.set(type, arrayBufferTypeInfo.heapTypeRef);
}

createWASMStructLibraryType(type: ObjectType) {
this.typeMap.set(type, dataViewTypeInfo.typeRef);
this.heapTypeMap.set(type, dataViewTypeInfo.heapTypeRef);
}

createWASMLibraryType(type: ObjectType, libraryTypeName: string) {
switch (libraryTypeName) {
case BuiltinNames.WASMARRAY: {
this.createWASMArrayLibraryType(type);
break;
}
case BuiltinNames.WASMSTRUCT: {
this.createWASMStructLibraryType(type);
break;
}
default: {
throw new UnimplementError(
`${libraryTypeName} is not supported`,
);
}
}
}

createWASMInfcType(type: ObjectType) {
this.typeMap.set(type, infcTypeInfo.typeRef);
this.heapTypeMap.set(type, infcTypeInfo.heapTypeRef);
Expand Down
9 changes: 7 additions & 2 deletions src/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1621,7 +1621,8 @@ export class TypeResolver {
(this.isTypeReference(type) ||
this.isInterface(type) ||
this.isObjectLiteral(type) ||
this.isObjectType(type))
this.isObjectType(type)) &&
type.symbol
) {
const decls = type.symbol.declarations;
if (decls) {
Expand Down Expand Up @@ -1836,7 +1837,11 @@ export class TypeResolver {
}

private isArray(type: ts.Type): type is ts.TypeReference {
return this.isTypeReference(type) && type.symbol.name === 'Array';
return (
this.isTypeReference(type) &&
type.symbol &&
type.symbol.name === 'Array'
);
}

private isFunction(type: ts.Type): type is ts.ObjectType {
Expand Down
1 change: 1 addition & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,7 @@ export function isTypeGeneric(type: Type): boolean {
case TypeKind.STRING:
case TypeKind.UNKNOWN:
case TypeKind.NULL:
case TypeKind.ENUM:
case TypeKind.WASM_I32:
case TypeKind.WASM_I64:
case TypeKind.WASM_F32:
Expand Down