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

chore(loader): introduced an argument to determine if metering is applied #1041

Merged
merged 1 commit into from
Oct 16, 2024
Merged
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
49 changes: 31 additions & 18 deletions loader/src/index.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,6 @@ const metering = require('@permaweb/wasm-metering')
*/

/*
* Custom WebAssembly.compileStreaming Implementation with WASM Metering
*
* This implementation overrides WebAssembly.compileStreaming to add metering
* to WebAssembly binaries. Metering enables tracking of resource usage (e.g.,
* CPU or memory) within the WebAssembly runtime, which is critical for monitoring
Expand All @@ -106,28 +104,43 @@ const metering = require('@permaweb/wasm-metering')
* instead of within each CU instance. By integrating metering directly into the
* loader, we ensure that all WebAssembly binaries are metered consistently across
* different CUs, reducing redundancy and enhancing modularity.
*/
*/
// Save the original WebAssembly.compile and compileStreaming functions
const originalCompileStreaming = WebAssembly.compileStreaming
const originalCompile = WebAssembly.compile

// Override WebAssembly.compileStreaming to apply metering
WebAssembly.compileStreaming = async function (source, importObject = {}) {
// Read the response and convert it to an ArrayBuffer
const arrayBuffer = await source.arrayBuffer();
const shouldApplyMetering = (importObject = {}) => {
return importObject.applyMetering && ['wasm32-unknown-emscripten4', 'wasm64-unknown-emscripten-draft_2024_02_15'].includes(importObject.format);
}

// Convert ArrayBuffer to Uint8Array for metering compatibility
const nodeBuffer = Buffer.from(arrayBuffer);
const applyMetering = (arrayBuffer, importObject) => {
const { format } = importObject

if(importObject.format === "wasm32-unknown-emscripten" || importObject.format === "wasm32-unknown-emscripten2" || importObject.format === "wasm32-unknown-emscripten3") {
return WebAssembly.compile(nodeBuffer);
}
const view = ArrayBuffer.isView(arrayBuffer)
? arrayBuffer
: Buffer.from(arrayBuffer)

// Determine meter type and apply metering
const meterType = format.startsWith('wasm32') ? 'i32' : 'i64'
const meteredView = metering.meterWASM(view, { meterType })

let meterType = importObject.format.startsWith("wasm32") ? "i32" : "i64";
return originalCompile(meteredView.buffer)
}

// Override WebAssembly.compileStreaming to apply metering
WebAssembly.compileStreaming = async function (source, importObject = { applyMetering: false }) {
if (!shouldApplyMetering(importObject)) return originalCompileStreaming(source)

// Apply metering with the Uint8Array buffer
const meteredView = metering.meterWASM(nodeBuffer, { meterType });
const arrayBuffer = await source.arrayBuffer()
return applyMetering(arrayBuffer, importObject)
}

// Override WebAssembly.compile to apply metering
WebAssembly.compile = async function (source, importObject = { applyMetering: false }) {
if (!shouldApplyMetering(importObject)) return originalCompile(source)

// const meteredResponse = new Response(meteredBuffer, { headers: { 'Content-Type': 'application/wasm' } });
return WebAssembly.compile(meteredView.buffer);
};
return applyMetering(source, importObject)
}

module.exports = async function (binary, options) {
let instance = null
Expand Down
2 changes: 1 addition & 1 deletion loader/test/emscripten2.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ describe('loader', async () => {
Readable.toWeb(createReadStream('./test/process/process.wasm')),
{ headers: { 'Content-Type': 'application/wasm' } }
),
{ format: 'wasm32-unknown-emscripten2' }
{ format: 'wasm32-unknown-emscripten2', applyMetering: false }
)

const handle = await AoLoader((info, receiveInstance) => {
Expand Down
2 changes: 1 addition & 1 deletion loader/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ describe('loader', async () => {
Readable.toWeb(createReadStream('./test/legacy/process.wasm')),
{ headers: { 'Content-Type': 'application/wasm' } }
),
{ format: 'wasm32-unknown-emscripten' }
{ format: 'wasm32-unknown-emscripten', applyMetering: false }
)

const handle = await AoLoader((info, receiveInstance) => {
Expand Down
Loading