Skip to content

Commit

Permalink
Integrate app framework (#79)
Browse files Browse the repository at this point in the history
* change arraybuffer's field type to wasmType
* parse comments information in frontend and semantic tree
* support declare pipeline
* add signature change ops

---------

Signed-off-by: Su Yihan <[email protected]>
  • Loading branch information
yviansu authored Dec 6, 2023
1 parent 041aa77 commit 987c7e4
Show file tree
Hide file tree
Showing 18 changed files with 947 additions and 131 deletions.
9 changes: 5 additions & 4 deletions lib/builtin/lib.type.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,20 +304,21 @@ declare function setTimeout(
declare function clearTimeout(timerid: number): void;

interface ArrayBuffer {
readonly byteLength: number;
readonly backing_store: anyref;
readonly byteLength: i32;

slice(begin?: number, end?: number): ArrayBuffer;
}
interface ArrayBufferConstructor {
new (byteLength: number): ArrayBuffer;
new (byteLength: i32): ArrayBuffer;
isView(arg: any): arg is ArrayBufferView;
}
declare var ArrayBuffer: ArrayBufferConstructor;

interface DataView {
readonly buffer: ArrayBuffer;
readonly byteLength: number;
readonly byteOffset: number;
readonly byteLength: i32;
readonly byteOffset: i32;

getFloat32(byteOffset: number, littleEndian?: boolean): number;
getFloat64(byteOffset: number, littleEndian?: boolean): number;
Expand Down
218 changes: 141 additions & 77 deletions src/backend/binaryen/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@
import binaryen from 'binaryen';
import * as binaryenCAPI from './glue/binaryen.js';
import { arrayToPtr, emptyStructType } from './glue/transform.js';
import { PredefinedTypeId, Stack } from '../../utils.js';
import {
PredefinedTypeId,
Stack,
isExportComment,
isImportComment,
isNativeSignatureComment,
} from '../../utils.js';
import {
importAnyLibAPI,
importInfcLibAPI,
Expand Down Expand Up @@ -38,6 +44,7 @@ import {
FunctionOwnKind,
IfNode,
ModuleNode,
NativeSignature,
SemanticsNode,
SwitchNode,
TryNode,
Expand All @@ -61,6 +68,7 @@ import {
SourceMapLoc,
BackendLocalVar,
UtilFuncs,
NativeSignatureConversion,
} from './utils.js';
import {
MemberDescription,
Expand Down Expand Up @@ -507,16 +515,20 @@ export class WASMGen extends Ts2wasmBackend {
const paramWASMTypes =
this.wasmTypeComp.getWASMFuncParamTypes(tsFuncType);
const returnType = tsFuncType.returnType;
const returnWASMType = this.wasmTypeComp.getWASMValueType(returnType);
let returnWASMType = this.wasmTypeComp.getWASMValueType(returnType);
const oriParamWasmTypes =
this.wasmTypeComp.getWASMFuncOriParamTypes(tsFuncType);

/* generate import function name */
const levelNames = func.name.split(BuiltinNames.moduleDelimiter);
let importName = levelNames[levelNames.length - 1];
let funcPureName = levelNames[levelNames.length - 1];
if ((func.ownKind & FunctionOwnKind.METHOD) !== 0) {
importName = `${levelNames[levelNames.length - 2]}_${importName}`;
funcPureName = `${
levelNames[levelNames.length - 2]
}_${funcPureName}`;
}
let importName = funcPureName;
let exportName = funcPureName;

/** declare functions */
if ((func.ownKind & FunctionOwnKind.DECLARE) !== 0) {
Expand All @@ -525,45 +537,75 @@ export class WASMGen extends Ts2wasmBackend {
/* For method, just skip the @context */
skipEnvParamLen = BuiltinNames.envParamLen - 1;
}
const importParamWASMTypes = paramWASMTypes.slice(skipEnvParamLen);
let calledParamValueRefs: binaryen.ExpressionRef[] = [];
for (let i = skipEnvParamLen; i < paramWASMTypes.length; i++) {
calledParamValueRefs.push(
this.module.local.get(i, paramWASMTypes[i]),
);
}
const internalFuncName = `${func.name}${BuiltinNames.declareSuffix}`;
let moduleName = BuiltinNames.externalModuleName;
let importParamTypeRefs = paramWASMTypes.slice(skipEnvParamLen);
const innerOpStmts: binaryen.ExpressionRef[] = [];
const vars: binaryen.Type[] = [];
for (let comment of func.comments) {
if (isImportComment(comment)) {
moduleName = comment.moduleName;
importName = comment.funcName;
} else if (isNativeSignatureComment(comment)) {
comment = comment as NativeSignature;
importParamTypeRefs = [];
calledParamValueRefs = [];
returnWASMType = this.wasmTypeComp.getWASMValueType(
comment.returnType,
);
for (const paramType of comment.paramTypes) {
const paramTypeRef =
this.wasmTypeComp.getWASMValueType(paramType);
importParamTypeRefs.push(paramTypeRef);
}
FunctionalFuncs.parseNativeSignature(
this.module,
innerOpStmts,
tsFuncType.argumentsType,
paramWASMTypes.slice(skipEnvParamLen),
comment.paramTypes,
skipEnvParamLen,
calledParamValueRefs,
vars,
true,
);
} else if (isExportComment(comment)) {
exportName = comment.exportName;
}
}
this.module.addFunctionImport(
internalFuncName,
BuiltinNames.externalModuleName,
moduleName,
importName,
binaryen.createType(importParamWASMTypes),
binaryen.createType(importParamTypeRefs),
returnWASMType,
);
/* use wrappered func to invoke the orignal func */
const oriParamWasmValues: binaryen.ExpressionRef[] = [];
for (let i = 0; i < importParamWASMTypes.length; i++) {
oriParamWasmValues.push(
this.module.local.get(
i + skipEnvParamLen,
importParamWASMTypes[i],
),
);
}
let innerOp: binaryen.ExpressionRef;
const callOp = this.module.call(
internalFuncName,
oriParamWasmValues,
calledParamValueRefs,
returnWASMType,
);
// TODO: ts's return type is not same with native signature's return type.
if (returnType.kind !== ValueTypeKind.VOID) {
innerOp = this.module.return(callOp);
innerOpStmts.push(this.module.return(callOp));
} else {
innerOp = callOp;
innerOpStmts.push(callOp);
}
this.module.addFunction(
func.name,
binaryen.createType(paramWASMTypes),
returnWASMType,
[],
this.module.block(null, [innerOp], returnWASMType),
vars,
this.module.block(null, innerOpStmts, returnWASMType),
);
if ((func.ownKind & FunctionOwnKind.EXPORT) !== 0) {
this.module.addFunctionExport(internalFuncName, importName);
this.module.addFunctionExport(internalFuncName, exportName);
}
return;
}
Expand Down Expand Up @@ -777,67 +819,89 @@ export class WASMGen extends Ts2wasmBackend {
}
this.currentFuncCtx.localVarIdxNameMap.clear();

/** wrapped functions */
/** wrapped export functions */
if (
(func.ownKind &
(FunctionOwnKind.EXPORT | FunctionOwnKind.DEFAULT)) ===
(FunctionOwnKind.EXPORT | FunctionOwnKind.DEFAULT) &&
func.isInEnterScope
(FunctionOwnKind.EXPORT | FunctionOwnKind.DEFAULT)
) {
const wrapperName = importName.concat(BuiltinNames.wrapperSuffix);
let idx = 0;
let oriParamWasmValues: binaryen.ExpressionRef[] = [];
if (func.parameters) {
oriParamWasmValues = func.parameters.map((param) => {
return this.module.local.get(
idx++,
this.wasmTypeComp.getWASMValueType(param.type),
if (
func.isInEnterScope ||
func.comments.some((comment) => {
return isExportComment(comment);
})
) {
const exportWrapperName = funcPureName.concat(
BuiltinNames.wrapperSuffix,
);
let exportName = funcPureName;
let exportParamTypeRefs = oriParamWasmTypes;
const calledParamValueRefs: binaryen.ExpressionRef[] = [];
for (let i = 0; i < tsFuncType.envParamLen; i++) {
calledParamValueRefs.push(this.emptyRef);
}
for (let i = 0; i < exportParamTypeRefs.length; i++) {
calledParamValueRefs.push(
this.module.local.get(i, exportParamTypeRefs[i]),
);
}) as unknown as binaryen.ExpressionRef[];
}
/* add init statements */
const functionStmts: binaryen.ExpressionRef[] = [];
/* call globalInitFunc */
functionStmts.push(
this.module.call(
BuiltinNames.globalInitFuncName,
[],
binaryen.none,
),
);
const wrapperCallArgs: binaryen.ExpressionRef[] = [];
for (let i = 0; i < tsFuncType.envParamLen; i++) {
wrapperCallArgs.push(this.emptyRef);
}
const targetCall = this.module.call(
func.name,
wrapperCallArgs.concat(oriParamWasmValues),
returnWASMType,
);
const isReturn = returnWASMType === binaryen.none ? false : true;
functionStmts.push(
isReturn ? this.module.local.set(idx, targetCall) : targetCall,
);

/* set return value */
const functionVars: binaryen.ExpressionRef[] = [];
if (isReturn) {
functionStmts.push(
this.module.return(
this.module.local.get(idx, returnWASMType),
}
const innerOpStmts: binaryen.ExpressionRef[] = [];
const vars: binaryen.Type[] = [];
for (let comment of func.comments) {
if (isExportComment(comment)) {
exportName = comment.exportName;
} else if (isNativeSignatureComment(comment)) {
comment = comment as NativeSignature;
exportParamTypeRefs = [];
calledParamValueRefs.splice(tsFuncType.envParamLen);
returnWASMType = this.wasmTypeComp.getWASMValueType(
comment.returnType,
);
for (const paramType of comment.paramTypes) {
const paramTypeRef =
this.wasmTypeComp.getWASMValueType(paramType);
exportParamTypeRefs.push(paramTypeRef);
}
FunctionalFuncs.parseNativeSignature(
this.module,
innerOpStmts,
comment.paramTypes,
exportParamTypeRefs,
tsFuncType.argumentsType,
tsFuncType.envParamLen,
calledParamValueRefs,
vars,
false,
);
}
}
innerOpStmts.push(
this.module.call(
BuiltinNames.globalInitFuncName,
[],
binaryen.none,
),
);
functionVars.push(returnWASMType);
const callOp = this.module.call(
func.name,
calledParamValueRefs,
returnWASMType,
);
// TODO: ts's return type is not same with native signature's return type.
if (returnType.kind !== ValueTypeKind.VOID) {
innerOpStmts.push(this.module.return(callOp));
} else {
innerOpStmts.push(callOp);
}
this.module.addFunction(
exportWrapperName,
binaryen.createType(exportParamTypeRefs),
returnWASMType,
vars,
this.module.block(null, innerOpStmts),
);
this.module.addFunctionExport(exportWrapperName, exportName);
}

this.module.addFunction(
wrapperName,
binaryen.createType(oriParamWasmTypes),
returnWASMType,
functionVars,
this.module.block(null, functionStmts),
);
this.module.addFunctionExport(wrapperName, importName);
}

this.generatedFuncNames.push(func.name);
Expand Down
35 changes: 9 additions & 26 deletions src/backend/binaryen/lib/init_builtin_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3794,32 +3794,17 @@ function arrayBufferConstructor(module: binaryen.Module) {
const this_Idx = 1;
const byteLength_Idx = 2;

/* values */
/* workaround: in type.d.ts, type is number, not wasmType i32 */
const byteLength_i32_Idx = 3;

const stmts: binaryen.ExpressionRef[] = [];
stmts.push(
module.local.set(
byteLength_i32_Idx,
FunctionalFuncs.convertTypeToI32(
module,
module.local.get(byteLength_Idx, binaryen.f64),
),
),
);
const i8Array = binaryenCAPI._BinaryenArrayNew(
module.ptr,
i8ArrayTypeInfo.heapTypeRef,
module.local.get(byteLength_i32_Idx, binaryen.i32),
module.local.get(byteLength_Idx, binaryen.i32),
module.i32.const(0),
);
const arrayBufferStruct = binaryenCAPI._BinaryenStructNew(
module.ptr,
arrayToPtr([
i8Array,
module.local.get(byteLength_i32_Idx, binaryen.i32),
]).ptr,
arrayToPtr([i8Array, module.local.get(byteLength_Idx, binaryen.i32)])
.ptr,
2,
arrayBufferTypeInfo.heapTypeRef,
);
Expand Down Expand Up @@ -3862,12 +3847,10 @@ function dataViewConstructor(module: binaryen.Module) {
anyref,
dyntype.dyntype_is_undefined,
);
const value = module.i32.trunc_s_sat.f64(
module.call(
dyntype.dyntype_to_number,
[FunctionalFuncs.getDynContextRef(module), anyref],
binaryen.f64,
),
const value = FunctionalFuncs.unboxAnyToBase(
module,
anyref,
ValueTypeKind.INT,
);
return module.if(
isUndefined,
Expand Down Expand Up @@ -5816,10 +5799,10 @@ export function callBuiltInAPIs(module: binaryen.Module) {
binaryen.createType([
emptyStructType.typeRef,
emptyStructType.typeRef,
binaryen.f64,
binaryen.i32,
]),
arrayBufferTypeInfo.typeRef,
[binaryen.i32],
[],
arrayBufferConstructor(module),
);
module.addFunctionImport(
Expand Down
Loading

0 comments on commit 987c7e4

Please sign in to comment.