diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js index 1743c97388e..d733ae25990 100644 --- a/src/js/binaryen.js-post.js +++ b/src/js/binaryen.js-post.js @@ -2465,6 +2465,18 @@ function wrapModule(module, self = {}) { } }; + self['call_ref'] = function(target, operands, type) { + return preserveStack(() => + Module['_BinaryenCallRef'](module, target, i32sToStack(operands), operands.length, type, false) + ); + }; + + self['return_call_ref'] = function(target, operands, type) { + return preserveStack(() => + Module['_BinaryenCallRef'](module, target, i32sToStack(operands), operands.length, type, true) + ); + } + self['any'] = { 'convert_extern'() { return Module['_BinaryenRefAsAnyConvertExtern'](); @@ -5146,6 +5158,39 @@ Module['I31Get'] = makeExpressionWrapper(Module['_BinaryenI31GetId'](), { } }); +Module['CallRef'] = makeExpressionWrapper(Module['_BinaryenCallRefId'](), { + 'getNumOperands'(expr) { + return Module['_BinaryenCallRefGetNumOperands'](expr); + }, + 'getOperandAt'(expr, index) { + return Module['_BinaryenCallRefGetOperandAt'](expr, index); + }, + 'setOperandAt'(expr, index, operandExpr) { + Module['_BinaryenCallRefSetOperandAt'](expr, index, operandExpr); + }, + 'appendOperand'(expr, operandExpr) { + return Module['_BinaryenCallRefAppendOperand'](expr, operandExpr); + }, + 'insertOperandAt'(expr, index, operandExpr) { + Module['_BinaryenCallRefInsertOperandAt'](expr, index, operandExpr); + }, + 'removeOperandAt'(expr, index) { + return Module['_BinaryenCallRefRemoveOperandAt'](expr, index); + }, + 'getTarget'(expr) { + return Module['_BinaryenCallRefGetTarget'](expr); + }, + 'setTarget'(expr, targetExpr) { + Module['_BinaryenCallRefSetTarget'](expr, targetExpr); + }, + 'isReturn'(expr) { + return Boolean(Module['_BinaryenCallRefIsReturn'](expr)); + }, + 'setReturn'(expr, isReturn) { + Module['_BinaryenCallRefSetReturn'](expr, isReturn); + } +}); + // Function wrapper Module['Function'] = (() => { diff --git a/test/binaryen.js/expressions.js b/test/binaryen.js/expressions.js index c750047c85e..ec7f866c535 100644 --- a/test/binaryen.js/expressions.js +++ b/test/binaryen.js/expressions.js @@ -3409,3 +3409,97 @@ console.log("# I31Get"); module.dispose(); })(); + +console.log("# CallRef"); +(function testCallRef() { + const module = new binaryen.Module(); + + const funcName = "tiny"; + module.addFunction(funcName, binaryen.createType([binaryen.i32, binaryen.i32]), binaryen.none, [], module.nop()); + const funcType = binaryen.Function(module.getFunction(funcName)).type; + const funcRef = binaryen.RefFunc(module.ref.func(funcName, funcType)); + + const operands = [ + module.i32.const(6), + module.i32.const(7) + ]; + + const theCallRef = binaryen.CallRef(module.call_ref(funcRef, operands, binaryen.none)); + assert(theCallRef instanceof binaryen.CallRef); + assert(theCallRef instanceof binaryen.Expression); + assert(theCallRef.numOperands === operands.length); + assert(theCallRef.type === binaryen.none); + assert(binaryen.RefFunc(theCallRef.target).func === funcName); + + const info = binaryen.getExpressionInfo(theCallRef); + assert(info.id === theCallRef.id); + assert(info.type === theCallRef.type); + assert(info.target === theCallRef.target); + assert(info.isReturn === theCallRef.isReturn()); + + assert(theCallRef.getNumOperands() === operands.length); + + assert(theCallRef.getOperandAt(0) === operands[0]); + assert(theCallRef.getOperandAt(1) === operands[1]); + + theCallRef.setOperandAt(0, operands[1]); + assert(theCallRef.getOperandAt(0), operands[1]); + theCallRef.setOperandAt(0, operands[0]); + assert(theCallRef.getOperandAt(0), operands[0]); + + const newOperand = module.i32.const(8); + theCallRef.appendOperand(newOperand); + assert(theCallRef.getNumOperands() == 3); + assert(theCallRef.getOperandAt(2) === newOperand); + + theCallRef.removeOperandAt(2); + assert(theCallRef.getNumOperands() == 2); + assert(theCallRef.getOperandAt(0) === operands[0]); + assert(theCallRef.getOperandAt(1) === operands[1]); + + theCallRef.insertOperandAt(1, newOperand); + assert(theCallRef.getNumOperands() == 3); + assert(theCallRef.getOperandAt(0) === operands[0]); + assert(theCallRef.getOperandAt(1) === newOperand); + assert(theCallRef.getOperandAt(2) === operands[1]); + + theCallRef.removeOperandAt(1); + assert(theCallRef.getNumOperands() == 2); + assert(theCallRef.getOperandAt(0) === operands[0]); + assert(theCallRef.getOperandAt(1) === operands[1]); + + assert(theCallRef.isReturn() === false); + theCallRef.setReturn(true); + assert(theCallRef.isReturn() === true); + theCallRef.setReturn(false); + assert(theCallRef.isReturn() === false); + + const theReturnCallRef = binaryen.CallRef(module.return_call_ref(funcRef, operands, binaryen.none)); + assert(theReturnCallRef instanceof binaryen.CallRef); + assert(theReturnCallRef instanceof binaryen.Expression); + assert(theReturnCallRef.numOperands === operands.length); + assert(binaryen.RefFunc(theReturnCallRef.target).func === funcName); + assert(theReturnCallRef.isReturn() === true); + + + const targetRef = binaryen.RefFunc(theCallRef.getTarget()); + assert(theCallRef.getTarget() == theCallRef.target); + assert(targetRef.func === funcName); + + const newTargetName = "newTarget"; + const newTargetRef = binaryen.RefFunc(module.ref.func(newTargetName, funcType)); + theCallRef.setTarget(newTargetRef); + assert(binaryen.RefFunc(theCallRef.getTarget()).func === newTargetName); + + theCallRef.setTarget(funcRef); + assert(binaryen.RefFunc(theCallRef.getTarget()).func === funcName); + + console.log(theCallRef.toText()); + assert( + theCallRef.toText() + == + "(call_ref $func.0\n (i32.const 6)\n (i32.const 7)\n (ref.func $tiny)\n)\n" + ); + + module.dispose(); +})(); \ No newline at end of file diff --git a/test/binaryen.js/expressions.js.txt b/test/binaryen.js/expressions.js.txt index 47d7cf43fb4..f060c0dd33c 100644 --- a/test/binaryen.js/expressions.js.txt +++ b/test/binaryen.js/expressions.js.txt @@ -453,3 +453,9 @@ (local.get $2) ) +# CallRef +(call_ref $func.0 + (i32.const 6) + (i32.const 7) + (ref.func $tiny) +)