Skip to content
This repository has been archived by the owner on Sep 14, 2023. It is now read-only.

Commit

Permalink
chore: compress wasm (and decompress on init) (#148)
Browse files Browse the repository at this point in the history
  • Loading branch information
harrysolovay authored Jun 30, 2022
1 parent 5c9e264 commit f19b58f
Show file tree
Hide file tree
Showing 12 changed files with 136 additions and 45 deletions.
1 change: 1 addition & 0 deletions _deps/lz4.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "https://deno.land/x/lz4@v0.1.2/mod.ts";
28 changes: 28 additions & 0 deletions _tasks/build_wasm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { assert, fail } from "../_deps/asserts.ts";
import { compress } from "../_deps/lz4.ts";
import * as path from "../_deps/path.ts";

await ["hashers", "sr25519", "ss58"].reduce(async (acc, cur) => {
await acc;
const destDir = path.join("bindings", cur);
const buildProcess = Deno.run({
cmd: [
"deno",
"task",
"run",
"https://deno.land/x/wasmbuild@0.8.2/main.ts",
"--js-ext",
"mjs",
"--out",
destDir,
"--features",
cur,
],
});
const status = await buildProcess.status();
assert(status.success);
const wasmPath = path.join(destDir, `mod_bg.wasm`);
const wasmBytes = await Deno.readFile(wasmPath);
const wasmCompressed = compress(wasmBytes);
Deno.writeFile(wasmPath, wasmCompressed);
}, Promise.resolve());
55 changes: 38 additions & 17 deletions bindings/hashers/mod.generated.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// @generated file from build script, do not edit
// @generated file from wasmbuild -- do not edit
// deno-lint-ignore-file
// source-hash: 1843d28d775dc4941c9f53705dfb80d6e7b59eda
// deno-fmt-ignore-file
// source-hash: 159285ce075cb9f0a0b1d5d306e765b19d3ebb81
let wasm;

const heap = new Array(32).fill(undefined);
Expand Down Expand Up @@ -234,12 +234,21 @@ const imports = {

const wasm_url = new URL("mod_bg.wasm", import.meta.url);

/**
* Decompression callback
*
* @callback decompressCallback
* @param {Uint8Array} compressed
* @return {Uint8Array} decompressed
*/

/** Instantiates an instance of the Wasm module returning its functions.
* @remarks It is safe to call this multiple times and once successfully
* loaded it will always return a reference to the same object.
* @param {decompressCallback=} transform
*/
export async function instantiate() {
return (await instantiateWithInstance()).exports;
export async function instantiate(transform) {
return (await instantiateWithInstance(transform)).exports;
}

let instanceWithExports;
Expand All @@ -248,32 +257,26 @@ let lastLoadPromise;
/** Instantiates an instance of the Wasm module along with its exports.
* @remarks It is safe to call this multiple times and once successfully
* loaded it will always return a reference to the same object.
* @param {decompressCallback=} transform
* @returns {Promise<{
* instance: WebAssembly.Instance;
* exports: { blake2_128: typeof blake2_128; blake2_256: typeof blake2_256; blake2_128Concat: typeof blake2_128Concat; twox128: typeof twox128; twox256: typeof twox256; twox64Concat: typeof twox64Concat }
* }>}
*/
export function instantiateWithInstance() {
export function instantiateWithInstance(transform) {
if (instanceWithExports != null) {
return Promise.resolve(instanceWithExports);
}
if (lastLoadPromise == null) {
lastLoadPromise = (async () => {
try {
const instance = (await instantiateModule()).instance;
const instance = (await instantiateModule(transform)).instance;
wasm = instance.exports;
cachedInt32Memory0 = new Int32Array(wasm.memory.buffer);
cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer);
instanceWithExports = {
instance,
exports: {
blake2_128,
blake2_256,
blake2_128Concat,
twox128,
twox256,
twox64Concat,
},
exports: getWasmInstanceExports(),
};
return instanceWithExports;
} finally {
Expand All @@ -284,12 +287,23 @@ export function instantiateWithInstance() {
return lastLoadPromise;
}

function getWasmInstanceExports() {
return {
blake2_128,
blake2_256,
blake2_128Concat,
twox128,
twox256,
twox64Concat,
};
}

/** Gets if the Wasm module has been instantiated. */
export function isInstantiated() {
return instanceWithExports != null;
}

async function instantiateModule() {
async function instantiateModule(transform) {
switch (wasm_url.protocol) {
case "file:": {
if (typeof Deno !== "object") {
Expand All @@ -300,14 +314,21 @@ async function instantiateModule() {
Deno.permissions.request({ name: "read", path: wasm_url });
}
const wasmCode = await Deno.readFile(wasm_url);
return WebAssembly.instantiate(wasmCode, imports);
return WebAssembly.instantiate(
!transform ? wasmCode : transform(wasmCode),
imports,
);
}
case "https:":
case "http:": {
if (typeof Deno === "object" && "permissions" in Deno) {
Deno.permissions.request({ name: "net", host: wasm_url.host });
}
const wasmResponse = await fetch(wasm_url);
if (transform) {
const wasmCode = new Uint8Array(await wasmResponse.arrayBuffer());
return WebAssembly.instantiate(transform(wasmCode), imports);
}
if (
wasmResponse.headers.get("content-type")?.toLowerCase().startsWith(
"application/wasm",
Expand Down
3 changes: 2 additions & 1 deletion bindings/hashers/mod.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { decompress } from "../../_deps/lz4.ts";
import * as M from "../../frame_metadata/mod.ts";
import { instantiate } from "./mod.generated.mjs";

export async function Hashers(): Promise<M.HasherLookup> {
const instance = await instantiate();
const instance = await instantiate(decompress);
return {
Blake2_128: instance.blake2_128,
Blake2_128Concat: instance.blake2_128Concat,
Expand Down
Binary file modified bindings/hashers/mod_bg.wasm
Binary file not shown.
41 changes: 31 additions & 10 deletions bindings/sr25519/mod.generated.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// @generated file from build script, do not edit
// @generated file from wasmbuild -- do not edit
// deno-lint-ignore-file
// source-hash: 1843d28d775dc4941c9f53705dfb80d6e7b59eda
// deno-fmt-ignore-file
// source-hash: 159285ce075cb9f0a0b1d5d306e765b19d3ebb81
let wasm;

const cachedTextDecoder = new TextDecoder("utf-8", {
Expand Down Expand Up @@ -521,12 +521,21 @@ const imports = {

const wasm_url = new URL("mod_bg.wasm", import.meta.url);

/**
* Decompression callback
*
* @callback decompressCallback
* @param {Uint8Array} compressed
* @return {Uint8Array} decompressed
*/

/** Instantiates an instance of the Wasm module returning its functions.
* @remarks It is safe to call this multiple times and once successfully
* loaded it will always return a reference to the same object.
* @param {decompressCallback=} transform
*/
export async function instantiate() {
return (await instantiateWithInstance()).exports;
export async function instantiate(transform) {
return (await instantiateWithInstance(transform)).exports;
}

let instanceWithExports;
Expand All @@ -535,25 +544,26 @@ let lastLoadPromise;
/** Instantiates an instance of the Wasm module along with its exports.
* @remarks It is safe to call this multiple times and once successfully
* loaded it will always return a reference to the same object.
* @param {decompressCallback=} transform
* @returns {Promise<{
* instance: WebAssembly.Instance;
* exports: { PublicKey : typeof PublicKey ; Signer : typeof Signer ; TestUser : typeof TestUser }
* }>}
*/
export function instantiateWithInstance() {
export function instantiateWithInstance(transform) {
if (instanceWithExports != null) {
return Promise.resolve(instanceWithExports);
}
if (lastLoadPromise == null) {
lastLoadPromise = (async () => {
try {
const instance = (await instantiateModule()).instance;
const instance = (await instantiateModule(transform)).instance;
wasm = instance.exports;
cachedInt32Memory0 = new Int32Array(wasm.memory.buffer);
cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer);
instanceWithExports = {
instance,
exports: { PublicKey, Signer, TestUser },
exports: getWasmInstanceExports(),
};
return instanceWithExports;
} finally {
Expand All @@ -564,12 +574,16 @@ export function instantiateWithInstance() {
return lastLoadPromise;
}

function getWasmInstanceExports() {
return { PublicKey, Signer, TestUser };
}

/** Gets if the Wasm module has been instantiated. */
export function isInstantiated() {
return instanceWithExports != null;
}

async function instantiateModule() {
async function instantiateModule(transform) {
switch (wasm_url.protocol) {
case "file:": {
if (typeof Deno !== "object") {
Expand All @@ -580,14 +594,21 @@ async function instantiateModule() {
Deno.permissions.request({ name: "read", path: wasm_url });
}
const wasmCode = await Deno.readFile(wasm_url);
return WebAssembly.instantiate(wasmCode, imports);
return WebAssembly.instantiate(
!transform ? wasmCode : transform(wasmCode),
imports,
);
}
case "https:":
case "http:": {
if (typeof Deno === "object" && "permissions" in Deno) {
Deno.permissions.request({ name: "net", host: wasm_url.host });
}
const wasmResponse = await fetch(wasm_url);
if (transform) {
const wasmCode = new Uint8Array(await wasmResponse.arrayBuffer());
return WebAssembly.instantiate(transform(wasmCode), imports);
}
if (
wasmResponse.headers.get("content-type")?.toLowerCase().startsWith(
"application/wasm",
Expand Down
3 changes: 2 additions & 1 deletion bindings/sr25519/mod.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// TODO: brands
// TODO: narrow error types
import { decompress } from "../../_deps/lz4.ts";
import { instantiate } from "./mod.generated.mjs";

export interface PublicKey {
Expand Down Expand Up @@ -35,7 +36,7 @@ export interface Sr25519 {
}

export async function Sr25519(): Promise<Sr25519> {
const instance = await instantiate();
const instance = await instantiate(decompress);
return {
PublicKey: instance.PublicKey,
TestUser: instance.TestUser,
Expand Down
Binary file modified bindings/sr25519/mod_bg.wasm
Binary file not shown.
41 changes: 31 additions & 10 deletions bindings/ss58/mod.generated.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// @generated file from build script, do not edit
// @generated file from wasmbuild -- do not edit
// deno-lint-ignore-file
// source-hash: 2bb4754084714a161d4275e4644a3fe07a13cd72
// deno-fmt-ignore-file
// source-hash: b58fa22ec45a318a5c2d20f7f7a249ac2e891efd
let wasm;

const cachedTextDecoder = new TextDecoder("utf-8", {
Expand Down Expand Up @@ -220,12 +220,21 @@ const imports = {

const wasm_url = new URL("mod_bg.wasm", import.meta.url);

/**
* Decompression callback
*
* @callback decompressCallback
* @param {Uint8Array} compressed
* @return {Uint8Array} decompressed
*/

/** Instantiates an instance of the Wasm module returning its functions.
* @remarks It is safe to call this multiple times and once successfully
* loaded it will always return a reference to the same object.
* @param {decompressCallback=} transform
*/
export async function instantiate() {
return (await instantiateWithInstance()).exports;
export async function instantiate(transform) {
return (await instantiateWithInstance(transform)).exports;
}

let instanceWithExports;
Expand All @@ -234,25 +243,26 @@ let lastLoadPromise;
/** Instantiates an instance of the Wasm module along with its exports.
* @remarks It is safe to call this multiple times and once successfully
* loaded it will always return a reference to the same object.
* @param {decompressCallback=} transform
* @returns {Promise<{
* instance: WebAssembly.Instance;
* exports: { decode: typeof decode; encode: typeof encode }
* }>}
*/
export function instantiateWithInstance() {
export function instantiateWithInstance(transform) {
if (instanceWithExports != null) {
return Promise.resolve(instanceWithExports);
}
if (lastLoadPromise == null) {
lastLoadPromise = (async () => {
try {
const instance = (await instantiateModule()).instance;
const instance = (await instantiateModule(transform)).instance;
wasm = instance.exports;
cachedInt32Memory0 = new Int32Array(wasm.memory.buffer);
cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer);
instanceWithExports = {
instance,
exports: { decode, encode },
exports: getWasmInstanceExports(),
};
return instanceWithExports;
} finally {
Expand All @@ -263,12 +273,16 @@ export function instantiateWithInstance() {
return lastLoadPromise;
}

function getWasmInstanceExports() {
return { decode, encode };
}

/** Gets if the Wasm module has been instantiated. */
export function isInstantiated() {
return instanceWithExports != null;
}

async function instantiateModule() {
async function instantiateModule(transform) {
switch (wasm_url.protocol) {
case "file:": {
if (typeof Deno !== "object") {
Expand All @@ -279,14 +293,21 @@ async function instantiateModule() {
Deno.permissions.request({ name: "read", path: wasm_url });
}
const wasmCode = await Deno.readFile(wasm_url);
return WebAssembly.instantiate(wasmCode, imports);
return WebAssembly.instantiate(
!transform ? wasmCode : transform(wasmCode),
imports,
);
}
case "https:":
case "http:": {
if (typeof Deno === "object" && "permissions" in Deno) {
Deno.permissions.request({ name: "net", host: wasm_url.host });
}
const wasmResponse = await fetch(wasm_url);
if (transform) {
const wasmCode = new Uint8Array(await wasmResponse.arrayBuffer());
return WebAssembly.instantiate(transform(wasmCode), imports);
}
if (
wasmResponse.headers.get("content-type")?.toLowerCase().startsWith(
"application/wasm",
Expand Down
Loading

0 comments on commit f19b58f

Please sign in to comment.