├── .editorconfig ├── .eslintignore ├── .eslintrc.json ├── .github └── workflows │ └── gatsby.yml ├── .gitignore ├── .prettierrc ├── LICENSE ├── README.md ├── csv.js ├── gatsby-config.js ├── gatsby-node.js ├── lessons ├── assembly-script │ ├── assembly-script.md │ ├── exercises │ │ ├── 1 │ │ │ └── iwasm │ │ │ │ ├── asconfig.json │ │ │ │ ├── assembly │ │ │ │ ├── index.ts │ │ │ │ └── tsconfig.json │ │ │ │ ├── build │ │ │ │ ├── .gitignore │ │ │ │ ├── optimized.wat │ │ │ │ └── untouched.wat │ │ │ │ ├── index.js │ │ │ │ ├── package-lock.json │ │ │ │ ├── package.json │ │ │ │ └── tests │ │ │ │ └── index.js │ │ ├── 2 │ │ │ └── iwasm │ │ │ │ ├── asconfig.json │ │ │ │ ├── assembly │ │ │ │ ├── index.ts │ │ │ │ └── tsconfig.json │ │ │ │ ├── build │ │ │ │ ├── .gitignore │ │ │ │ ├── optimized.wat │ │ │ │ └── untouched.wat │ │ │ │ ├── index.html │ │ │ │ ├── index.js │ │ │ │ ├── js │ │ │ │ └── loader.js │ │ │ │ ├── package-lock.json │ │ │ │ ├── package.json │ │ │ │ ├── server.js │ │ │ │ └── tests │ │ │ │ └── index.js │ │ ├── 3 │ │ │ └── iwasm │ │ │ │ ├── asconfig.json │ │ │ │ ├── assembly │ │ │ │ ├── index.ts │ │ │ │ └── tsconfig.json │ │ │ │ ├── build │ │ │ │ ├── .gitignore │ │ │ │ ├── optimized.wat │ │ │ │ └── untouched.wat │ │ │ │ ├── index.html │ │ │ │ ├── index.js │ │ │ │ ├── js │ │ │ │ └── loader.js │ │ │ │ ├── package-lock.json │ │ │ │ ├── package.json │ │ │ │ ├── server.js │ │ │ │ └── tests │ │ │ │ └── index.js │ │ ├── 4 │ │ │ └── iwasm │ │ │ │ ├── asconfig.json │ │ │ │ ├── assembly │ │ │ │ ├── index.ts │ │ │ │ └── tsconfig.json │ │ │ │ ├── build │ │ │ │ ├── .gitignore │ │ │ │ ├── optimized.wat │ │ │ │ └── untouched.wat │ │ │ │ ├── index.html │ │ │ │ ├── index.js │ │ │ │ ├── js │ │ │ │ └── loader.js │ │ │ │ ├── package-lock.json │ │ │ │ ├── package.json │ │ │ │ ├── server.js │ │ │ │ └── tests │ │ │ │ └── index.js │ │ ├── 5 │ │ │ └── iwasm │ │ │ │ ├── asconfig.json │ │ │ │ ├── assembly │ │ │ │ ├── index.ts │ │ │ │ └── tsconfig.json │ │ │ │ ├── build │ │ │ │ ├── .gitignore │ │ │ │ ├── optimized.wat │ │ │ │ └── untouched.wat │ │ │ │ ├── index.html │ │ │ │ ├── index.js │ │ │ │ ├── js │ │ │ │ └── loader.js │ │ │ │ ├── package-lock.json │ │ │ │ ├── package.json │ │ │ │ ├── server.js │ │ │ │ └── tests │ │ │ │ └── index.js │ │ ├── 6 │ │ │ └── iwasm │ │ │ │ ├── asconfig.json │ │ │ │ ├── assembly │ │ │ │ ├── index.ts │ │ │ │ └── tsconfig.json │ │ │ │ ├── build │ │ │ │ ├── .gitignore │ │ │ │ ├── optimized.wat │ │ │ │ └── untouched.wat │ │ │ │ ├── index.html │ │ │ │ ├── index.js │ │ │ │ ├── js │ │ │ │ └── loader.js │ │ │ │ ├── package-lock.json │ │ │ │ ├── package.json │ │ │ │ ├── server.js │ │ │ │ └── tests │ │ │ │ └── index.js │ │ └── 7 │ │ │ └── iwasm │ │ │ ├── asconfig.json │ │ │ ├── assembly │ │ │ ├── index.ts │ │ │ └── tsconfig.json │ │ │ ├── build │ │ │ ├── .gitignore │ │ │ ├── optimized.wat │ │ │ └── untouched.wat │ │ │ ├── index.html │ │ │ ├── index.js │ │ │ ├── js │ │ │ └── loader.js │ │ │ ├── package-lock.json │ │ │ ├── package.json │ │ │ ├── server.js │ │ │ └── tests │ │ │ └── index.js │ ├── images │ │ ├── as.png │ │ └── memory.png │ ├── imports.md │ ├── js-vs-wasm.md │ ├── loader.md │ ├── loading-browser.md │ ├── loading-node.md │ ├── memory.md │ ├── setup.md │ ├── using-loader.md │ └── writing.md ├── closing.md ├── images │ ├── course.png │ ├── lasercat.png │ ├── lowhigh.png │ └── title.png ├── intro-to-wasm.md ├── intro.md ├── low-level │ ├── binary-contd.md │ ├── binary.md │ ├── hex.md │ ├── images │ │ ├── 0and1.png │ │ ├── 32bits.png │ │ ├── bit.png │ │ ├── byte.png │ │ ├── counting.png │ │ ├── endian.png │ │ ├── hex.png │ │ └── pointer.png │ ├── memory.md │ ├── tostring.md │ └── types.md └── wasm │ ├── images │ ├── intro.png │ ├── opcode-table.png │ ├── opcodes.png │ ├── wasm-v-wat.png │ └── wasmmodule.png │ ├── stack-and-opcode.md │ ├── wasm-intro-contd.md │ ├── wasm-intro.md │ └── writing-wasm.md ├── package-lock.json ├── package.json ├── postcss.config.js ├── src ├── components │ └── TOCCard.js ├── layouts │ └── index.js ├── pages │ ├── 404.js │ └── index.js ├── styles │ └── global.css ├── templates │ └── lessonTemplate.js └── util │ └── helpers.js ├── tailwind.config.js └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 2 -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | lessons/**/** 2 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": [ 4 | "eslint:recommended", 5 | "plugin:import/errors", 6 | "plugin:react/recommended", 7 | "plugin:jsx-a11y/recommended", 8 | "prettier", 9 | "prettier/react" 10 | ], 11 | "rules": { 12 | "react/prop-types": 0, 13 | "jsx-a11y/label-has-for": 0, 14 | "no-console": 1 15 | }, 16 | "plugins": ["react", "import", "jsx-a11y", "@typescript-eslint"], 17 | "parser": "@typescript-eslint/parser", 18 | "parserOptions": { 19 | "ecmaVersion": 2018, 20 | "sourceType": "module", 21 | "ecmaFeatures": { 22 | "jsx": true 23 | } 24 | }, 25 | "env": { 26 | "es6": true, 27 | "browser": true, 28 | "node": true 29 | }, 30 | "settings": { 31 | "react": { 32 | "version": "16.5.2" 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /.github/workflows/gatsby.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Gatsby Site to GitHub Pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@master 13 | - name: npm install, build, and csv 14 | run: | 15 | npm install 16 | npm run build 17 | npm run csv 18 | - name: Deploy site to gh-pages branch 19 | uses: alex-page/blazing-fast-gh-pages-deploy@v1.1.0 20 | with: 21 | repo-token: ${{ secrets.ACCESS_TOKEN }} 22 | site-directory: public 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Project dependencies 2 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 3 | node_modules 4 | .cache/ 5 | # Build directory 6 | public/ 7 | .DS_Store 8 | yarn-error.log 9 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Intro to Web Assembly


2 | 3 |

4 | Introduction to Web Assembly 5 |

6 | -------------------------------------------------------------------------------- /csv.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs").promises; 2 | const path = require("path"); 3 | const fm = require("front-matter"); 4 | const isUrl = require("is-url-superb"); 5 | const parseLinks = require("parse-markdown-links"); 6 | const { sorter } = require("./src/util/helpers"); 7 | const mdDir = process.env.MARKDOWN_DIR || path.join(__dirname, "lessons/"); 8 | const outputPath = 9 | process.env.OUTPUT_CSV_PATH || path.join(__dirname, "public/lessons.csv"); 10 | const linksOutputPath = 11 | process.env.LINKS_CSV_PATH || path.join(__dirname, "public/links.csv"); 12 | 13 | async function createCsv() { 14 | console.log(`making the markdown files into a CSV from ${mdDir}`); 15 | 16 | // get paths 17 | const allFiles = await fs.readdir(mdDir); 18 | const files = allFiles.filter(filePath => filePath.endsWith(".md")); 19 | 20 | // read paths, get buffers 21 | const buffers = await Promise.all( 22 | files.map(filePath => fs.readFile(path.join(mdDir, filePath))) 23 | ); 24 | 25 | // make buffers strings 26 | const contents = buffers.map(content => content.toString()); 27 | 28 | // make strings objects 29 | let frontmatters = contents.map(fm); 30 | 31 | // find all attribute keys 32 | const seenAttributes = new Set(); 33 | frontmatters.forEach(item => { 34 | Object.keys(item.attributes).forEach(attr => seenAttributes.add(attr)); 35 | }); 36 | const attributes = Array.from(seenAttributes.values()); 37 | 38 | if (attributes.includes("order")) { 39 | frontmatters = frontmatters.sort(sorter); 40 | } 41 | 42 | // get all data into an array 43 | let rows = frontmatters.map(item => { 44 | const row = attributes.map(attr => 45 | item.attributes[attr] ? JSON.stringify(item.attributes[attr]) : "" 46 | ); 47 | return row; 48 | }); 49 | 50 | // header row must be first row 51 | rows.unshift(attributes); 52 | 53 | // join into CSV string 54 | const csv = rows.map(row => row.join(",")).join("\n"); 55 | 56 | // write file out 57 | await fs.writeFile(outputPath, csv); 58 | 59 | console.log(`Wrote ${rows.length} rows to ${outputPath}`); 60 | 61 | // make links csv 62 | let longestLength = 0; 63 | let linksArray = frontmatters.map(row => { 64 | const links = parseLinks(row.body).filter(isUrl); 65 | longestLength = longestLength > links.length ? longestLength : links.length; 66 | const newRow = [row.attributes.order, row.attributes.title, ...links]; 67 | return newRow; 68 | }); 69 | 70 | if (longestLength) { 71 | // add title row 72 | linksArray = linksArray.map(array => { 73 | const lengthToFill = longestLength + 2 - array.length; 74 | return array.concat(Array.from({ length: lengthToFill }).fill("")); 75 | }); 76 | 77 | linksArray.unshift( 78 | ["order", "title"].concat( 79 | Array.from({ length: longestLength }).map((_, index) => `link${index}`) 80 | ) 81 | ); 82 | 83 | // join into CSV string 84 | const linksCsv = linksArray.map(row => row.join(",")).join("\n"); 85 | 86 | // write file out 87 | await fs.writeFile(linksOutputPath, linksCsv); 88 | 89 | console.log(`Wrote ${linksArray.length} rows to ${linksOutputPath}`); 90 | } 91 | } 92 | 93 | createCsv(); 94 | -------------------------------------------------------------------------------- /gatsby-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | siteMetadata: { 3 | title: "Introduction to Web Assembly", 4 | subtitle: "Jem Young", 5 | description: 6 | "Jem Young - Introduction to Web Assembly - Frontend Masters", 7 | keywords: [ 8 | "web assembly", 9 | "frontend masters", 10 | "wasm", 11 | "jem young" 12 | ] 13 | }, 14 | pathPrefix: "/intro-to-web-assembly", 15 | plugins: [ 16 | `gatsby-plugin-layout`, 17 | { 18 | resolve: `gatsby-source-filesystem`, 19 | options: { 20 | path: `${__dirname}/lessons`, 21 | name: "markdown-pages" 22 | } 23 | }, 24 | `gatsby-plugin-react-helmet`, 25 | `gatsby-plugin-postcss`, 26 | { 27 | resolve: `gatsby-transformer-remark`, 28 | options: { 29 | plugins: [ 30 | `gatsby-remark-autolink-headers`, 31 | `gatsby-remark-copy-linked-files`, 32 | `gatsby-remark-prismjs`, 33 | { 34 | resolve: `gatsby-remark-images`, 35 | options: { 36 | maxWidth: 800, 37 | linkImagesToOriginal: true, 38 | sizeByPixelDensity: false 39 | } 40 | } 41 | ] 42 | } 43 | }, 44 | { 45 | resolve: `gatsby-plugin-sharp`, 46 | options: { 47 | // Available options and their defaults: 48 | base64Width: 20, 49 | forceBase64Format: `png`, // valid formats: png,jpg,webp 50 | useMozJpeg: process.env.GATSBY_JPEG_ENCODER === `MOZJPEG`, 51 | stripMetadata: true, 52 | defaultQuality: 50, 53 | failOnError: true, 54 | }, 55 | }, 56 | ] 57 | }; 58 | -------------------------------------------------------------------------------- /gatsby-node.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | exports.createPages = ({ actions, graphql }) => { 4 | const { createPage } = actions; 5 | 6 | const lessonTemplate = path.resolve(`src/templates/lessonTemplate.js`); 7 | 8 | return graphql(` 9 | { 10 | allMarkdownRemark( 11 | sort: { order: DESC, fields: [frontmatter___order] } 12 | limit: 1000 13 | ) { 14 | edges { 15 | node { 16 | excerpt(pruneLength: 250) 17 | html 18 | id 19 | frontmatter { 20 | order 21 | path 22 | title 23 | } 24 | } 25 | } 26 | } 27 | } 28 | `).then(result => { 29 | if (result.errors) { 30 | return Promise.reject(result.errors); 31 | } 32 | 33 | result.data.allMarkdownRemark.edges.forEach(({ node }) => { 34 | createPage({ 35 | path: node.frontmatter.path, 36 | component: lessonTemplate 37 | }); 38 | }); 39 | }); 40 | }; 41 | -------------------------------------------------------------------------------- /lessons/assembly-script/assembly-script.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/assembly-script" 3 | section: "AssemblyScript" 4 | order: "3A" 5 | title: "What is AssemblyScript" 6 | description: "" 7 | 8 | --- 9 | ![AssemblyScript](./images/as.png) 10 | 11 | [AssemblyScript](https://www.assemblyscript.org/introduction.html) at high level is a TypeScript to WebAssembly compiler. It provides both high-level language features such as loops but also allows for low-level memory access. 12 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/1/iwasm/asconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "targets": { 3 | "debug": { 4 | "binaryFile": "build/untouched.wasm", 5 | "textFile": "build/untouched.wat", 6 | "sourceMap": true, 7 | "debug": true 8 | }, 9 | "release": { 10 | "binaryFile": "build/optimized.wasm", 11 | "textFile": "build/optimized.wat", 12 | "sourceMap": true, 13 | "optimizeLevel": 3, 14 | "shrinkLevel": 1, 15 | "converge": false, 16 | "noAssert": false 17 | } 18 | }, 19 | "options": {} 20 | } -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/1/iwasm/assembly/index.ts: -------------------------------------------------------------------------------- 1 | export function minusOne(n: i32): i32 { 2 | return n - 1 3 | } 4 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/1/iwasm/assembly/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "assemblyscript/std/assembly.json", 3 | "include": [ 4 | "./**/*.ts" 5 | ] 6 | } -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/1/iwasm/build/.gitignore: -------------------------------------------------------------------------------- 1 | *.wasm 2 | *.wasm.map 3 | *.asm.js 4 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/1/iwasm/build/optimized.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (type $i32_=>_i32 (func (param i32) (result i32))) 3 | (memory $0 0) 4 | (export "minusOne" (func $assembly/index/minusOne)) 5 | (export "memory" (memory $0)) 6 | (func $assembly/index/minusOne (param $0 i32) (result i32) 7 | local.get $0 8 | i32.const 1 9 | i32.sub 10 | ) 11 | ) 12 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/1/iwasm/build/untouched.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (type $i32_=>_i32 (func (param i32) (result i32))) 3 | (memory $0 0) 4 | (table $0 1 funcref) 5 | (global $~lib/memory/__data_end i32 (i32.const 8)) 6 | (global $~lib/memory/__stack_pointer (mut i32) (i32.const 16392)) 7 | (global $~lib/memory/__heap_base i32 (i32.const 16392)) 8 | (export "minusOne" (func $assembly/index/minusOne)) 9 | (export "memory" (memory $0)) 10 | (func $assembly/index/minusOne (param $0 i32) (result i32) 11 | local.get $0 12 | i32.const 1 13 | i32.sub 14 | ) 15 | ) 16 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/1/iwasm/index.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const loader = require("@assemblyscript/loader"); 3 | const imports = { /* imports go here */ }; 4 | const wasmModule = loader.instantiateSync(fs.readFileSync(__dirname + "/build/optimized.wasm"), imports); 5 | module.exports = wasmModule.exports; 6 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/1/iwasm/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "requires": true, 3 | "lockfileVersion": 1, 4 | "dependencies": { 5 | "@assemblyscript/loader": { 6 | "version": "0.18.7", 7 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/@assemblyscript/loader/-/loader-0.18.7.tgz", 8 | "integrity": "sha1-o7r6YudH3cjXdUnFKIzXbql2xqA=" 9 | }, 10 | "assemblyscript": { 11 | "version": "0.18.7", 12 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/assemblyscript/-/assemblyscript-0.18.7.tgz", 13 | "integrity": "sha1-tV9EKf82J88xL0c1Uht9xSQ5nMU=", 14 | "dev": true, 15 | "requires": { 16 | "binaryen": "98.0.0-nightly.20210106", 17 | "long": "^4.0.0" 18 | } 19 | }, 20 | "binaryen": { 21 | "version": "98.0.0-nightly.20210106", 22 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/binaryen/-/binaryen-98.0.0-nightly.20210106.tgz", 23 | "integrity": "sha1-x7xjfiIjqDvzyunZiWn1ae+rQGI=", 24 | "dev": true 25 | }, 26 | "long": { 27 | "version": "4.0.0", 28 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/long/-/long-4.0.0.tgz", 29 | "integrity": "sha1-mntxz7fTYaGU6lVSQckvdGjVvyg=", 30 | "dev": true 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/1/iwasm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "asbuild:untouched": "asc assembly/index.ts --target debug", 4 | "asbuild:optimized": "asc assembly/index.ts --target release", 5 | "asbuild": "npm run asbuild:untouched && npm run asbuild:optimized", 6 | "test": "node tests" 7 | }, 8 | "dependencies": { 9 | "@assemblyscript/loader": "^0.18.7" 10 | }, 11 | "devDependencies": { 12 | "assemblyscript": "^0.18.7" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/1/iwasm/tests/index.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | const myModule = require(".."); 3 | assert.equal(myModule.minusOne(2), 1); 4 | console.log("ok"); 5 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/2/iwasm/asconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "targets": { 3 | "debug": { 4 | "binaryFile": "build/untouched.wasm", 5 | "textFile": "build/untouched.wat", 6 | "sourceMap": true, 7 | "debug": true 8 | }, 9 | "release": { 10 | "binaryFile": "build/optimized.wasm", 11 | "textFile": "build/optimized.wat", 12 | "sourceMap": true, 13 | "optimizeLevel": 3, 14 | "shrinkLevel": 1, 15 | "converge": false, 16 | "noAssert": false 17 | } 18 | }, 19 | "options": {} 20 | } -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/2/iwasm/assembly/index.ts: -------------------------------------------------------------------------------- 1 | export function minusOne(n: i32): i32 { 2 | return n - 1; 3 | } 4 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/2/iwasm/assembly/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "assemblyscript/std/assembly.json", 3 | "include": [ 4 | "./**/*.ts" 5 | ] 6 | } -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/2/iwasm/build/.gitignore: -------------------------------------------------------------------------------- 1 | *.wasm 2 | *.wasm.map 3 | *.asm.js 4 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/2/iwasm/build/optimized.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (type $i32_=>_i32 (func (param i32) (result i32))) 3 | (memory $0 0) 4 | (export "minusOne" (func $assembly/index/minusOne)) 5 | (export "memory" (memory $0)) 6 | (func $assembly/index/minusOne (param $0 i32) (result i32) 7 | local.get $0 8 | i32.const 1 9 | i32.sub 10 | ) 11 | ) 12 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/2/iwasm/build/untouched.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (type $i32_=>_i32 (func (param i32) (result i32))) 3 | (memory $0 0) 4 | (table $0 1 funcref) 5 | (global $~lib/memory/__data_end i32 (i32.const 8)) 6 | (global $~lib/memory/__stack_pointer (mut i32) (i32.const 16392)) 7 | (global $~lib/memory/__heap_base i32 (i32.const 16392)) 8 | (export "minusOne" (func $assembly/index/minusOne)) 9 | (export "memory" (memory $0)) 10 | (func $assembly/index/minusOne (param $0 i32) (result i32) 11 | local.get $0 12 | i32.const 1 13 | i32.sub 14 | ) 15 | ) 16 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/2/iwasm/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/2/iwasm/index.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const loader = require("@assemblyscript/loader"); 3 | const imports = { /* imports go here */ }; 4 | const wasmModule = loader.instantiateSync(fs.readFileSync(__dirname + "/build/optimized.wasm"), imports); 5 | module.exports = wasmModule.exports; 6 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/2/iwasm/js/loader.js: -------------------------------------------------------------------------------- 1 | class WasmLoader { 2 | constructor() { 3 | } 4 | 5 | async wasm(path) { 6 | console.log(`fetching ${path}`); 7 | 8 | if (!WebAssembly.instantiateStreaming) { 9 | return this.wasmFallback(path); 10 | } 11 | 12 | const { instance } = await WebAssembly.instantiateStreaming(fetch(path)); 13 | 14 | return instance?.exports; 15 | } 16 | 17 | async wasmFallback(path) { 18 | console.log('using fallback'); 19 | const response = await fetch(path); 20 | const bytes = await response?.arrayBuffer(); 21 | const { instance } = await WebAssembly.instantiate(bytes); 22 | 23 | return instance?.exports; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/2/iwasm/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "requires": true, 3 | "lockfileVersion": 1, 4 | "dependencies": { 5 | "@assemblyscript/loader": { 6 | "version": "0.18.7", 7 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/@assemblyscript/loader/-/loader-0.18.7.tgz", 8 | "integrity": "sha1-o7r6YudH3cjXdUnFKIzXbql2xqA=" 9 | }, 10 | "accepts": { 11 | "version": "1.3.7", 12 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/accepts/-/accepts-1.3.7.tgz", 13 | "integrity": "sha1-UxvHJlF6OytB+FACHGzBXqq1B80=", 14 | "requires": { 15 | "mime-types": "~2.1.24", 16 | "negotiator": "0.6.2" 17 | } 18 | }, 19 | "array-flatten": { 20 | "version": "1.1.1", 21 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/array-flatten/-/array-flatten-1.1.1.tgz", 22 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 23 | }, 24 | "assemblyscript": { 25 | "version": "0.18.7", 26 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/assemblyscript/-/assemblyscript-0.18.7.tgz", 27 | "integrity": "sha1-tV9EKf82J88xL0c1Uht9xSQ5nMU=", 28 | "dev": true, 29 | "requires": { 30 | "binaryen": "98.0.0-nightly.20210106", 31 | "long": "^4.0.0" 32 | } 33 | }, 34 | "binaryen": { 35 | "version": "98.0.0-nightly.20210106", 36 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/binaryen/-/binaryen-98.0.0-nightly.20210106.tgz", 37 | "integrity": "sha1-x7xjfiIjqDvzyunZiWn1ae+rQGI=", 38 | "dev": true 39 | }, 40 | "body-parser": { 41 | "version": "1.19.0", 42 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/body-parser/-/body-parser-1.19.0.tgz", 43 | "integrity": "sha1-lrJwnlfJxOCab9Zqj9l5hE9p8Io=", 44 | "requires": { 45 | "bytes": "3.1.0", 46 | "content-type": "~1.0.4", 47 | "debug": "2.6.9", 48 | "depd": "~1.1.2", 49 | "http-errors": "1.7.2", 50 | "iconv-lite": "0.4.24", 51 | "on-finished": "~2.3.0", 52 | "qs": "6.7.0", 53 | "raw-body": "2.4.0", 54 | "type-is": "~1.6.17" 55 | } 56 | }, 57 | "bytes": { 58 | "version": "3.1.0", 59 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/bytes/-/bytes-3.1.0.tgz", 60 | "integrity": "sha1-9s95M6Ng4FiPqf3oVlHNx/gF0fY=" 61 | }, 62 | "content-disposition": { 63 | "version": "0.5.3", 64 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/content-disposition/-/content-disposition-0.5.3.tgz", 65 | "integrity": "sha1-4TDK9+cnkIfFYWwgB9BIVpiYT70=", 66 | "requires": { 67 | "safe-buffer": "5.1.2" 68 | } 69 | }, 70 | "content-type": { 71 | "version": "1.0.4", 72 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/content-type/-/content-type-1.0.4.tgz", 73 | "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=" 74 | }, 75 | "cookie": { 76 | "version": "0.4.0", 77 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/cookie/-/cookie-0.4.0.tgz", 78 | "integrity": "sha1-vrQ35wIrO21JAZ0IhmUwPr6cFLo=" 79 | }, 80 | "cookie-signature": { 81 | "version": "1.0.6", 82 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/cookie-signature/-/cookie-signature-1.0.6.tgz", 83 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 84 | }, 85 | "debug": { 86 | "version": "2.6.9", 87 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/debug/-/debug-2.6.9.tgz", 88 | "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", 89 | "requires": { 90 | "ms": "2.0.0" 91 | } 92 | }, 93 | "depd": { 94 | "version": "1.1.2", 95 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/depd/-/depd-1.1.2.tgz", 96 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 97 | }, 98 | "destroy": { 99 | "version": "1.0.4", 100 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/destroy/-/destroy-1.0.4.tgz", 101 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 102 | }, 103 | "ee-first": { 104 | "version": "1.1.1", 105 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/ee-first/-/ee-first-1.1.1.tgz", 106 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 107 | }, 108 | "encodeurl": { 109 | "version": "1.0.2", 110 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/encodeurl/-/encodeurl-1.0.2.tgz", 111 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 112 | }, 113 | "escape-html": { 114 | "version": "1.0.3", 115 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/escape-html/-/escape-html-1.0.3.tgz", 116 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 117 | }, 118 | "etag": { 119 | "version": "1.8.1", 120 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/etag/-/etag-1.8.1.tgz", 121 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 122 | }, 123 | "express": { 124 | "version": "4.17.1", 125 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/express/-/express-4.17.1.tgz", 126 | "integrity": "sha1-RJH8OGBc9R+GKdOcK10Cb5ikwTQ=", 127 | "requires": { 128 | "accepts": "~1.3.7", 129 | "array-flatten": "1.1.1", 130 | "body-parser": "1.19.0", 131 | "content-disposition": "0.5.3", 132 | "content-type": "~1.0.4", 133 | "cookie": "0.4.0", 134 | "cookie-signature": "1.0.6", 135 | "debug": "2.6.9", 136 | "depd": "~1.1.2", 137 | "encodeurl": "~1.0.2", 138 | "escape-html": "~1.0.3", 139 | "etag": "~1.8.1", 140 | "finalhandler": "~1.1.2", 141 | "fresh": "0.5.2", 142 | "merge-descriptors": "1.0.1", 143 | "methods": "~1.1.2", 144 | "on-finished": "~2.3.0", 145 | "parseurl": "~1.3.3", 146 | "path-to-regexp": "0.1.7", 147 | "proxy-addr": "~2.0.5", 148 | "qs": "6.7.0", 149 | "range-parser": "~1.2.1", 150 | "safe-buffer": "5.1.2", 151 | "send": "0.17.1", 152 | "serve-static": "1.14.1", 153 | "setprototypeof": "1.1.1", 154 | "statuses": "~1.5.0", 155 | "type-is": "~1.6.18", 156 | "utils-merge": "1.0.1", 157 | "vary": "~1.1.2" 158 | } 159 | }, 160 | "finalhandler": { 161 | "version": "1.1.2", 162 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/finalhandler/-/finalhandler-1.1.2.tgz", 163 | "integrity": "sha1-t+fQAP/RGTjQ/bBTUG9uur6fWH0=", 164 | "requires": { 165 | "debug": "2.6.9", 166 | "encodeurl": "~1.0.2", 167 | "escape-html": "~1.0.3", 168 | "on-finished": "~2.3.0", 169 | "parseurl": "~1.3.3", 170 | "statuses": "~1.5.0", 171 | "unpipe": "~1.0.0" 172 | } 173 | }, 174 | "forwarded": { 175 | "version": "0.1.2", 176 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/forwarded/-/forwarded-0.1.2.tgz", 177 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 178 | }, 179 | "fresh": { 180 | "version": "0.5.2", 181 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/fresh/-/fresh-0.5.2.tgz", 182 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 183 | }, 184 | "http-errors": { 185 | "version": "1.7.2", 186 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/http-errors/-/http-errors-1.7.2.tgz", 187 | "integrity": "sha1-T1ApzxMjnzEDblsuVSkrz7zIXI8=", 188 | "requires": { 189 | "depd": "~1.1.2", 190 | "inherits": "2.0.3", 191 | "setprototypeof": "1.1.1", 192 | "statuses": ">= 1.5.0 < 2", 193 | "toidentifier": "1.0.0" 194 | } 195 | }, 196 | "iconv-lite": { 197 | "version": "0.4.24", 198 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/iconv-lite/-/iconv-lite-0.4.24.tgz", 199 | "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=", 200 | "requires": { 201 | "safer-buffer": ">= 2.1.2 < 3" 202 | } 203 | }, 204 | "inherits": { 205 | "version": "2.0.3", 206 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/inherits/-/inherits-2.0.3.tgz", 207 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 208 | }, 209 | "ipaddr.js": { 210 | "version": "1.9.1", 211 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 212 | "integrity": "sha1-v/OFQ+64mEglB5/zoqjmy9RngbM=" 213 | }, 214 | "long": { 215 | "version": "4.0.0", 216 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/long/-/long-4.0.0.tgz", 217 | "integrity": "sha1-mntxz7fTYaGU6lVSQckvdGjVvyg=", 218 | "dev": true 219 | }, 220 | "media-typer": { 221 | "version": "0.3.0", 222 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/media-typer/-/media-typer-0.3.0.tgz", 223 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 224 | }, 225 | "merge-descriptors": { 226 | "version": "1.0.1", 227 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 228 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 229 | }, 230 | "methods": { 231 | "version": "1.1.2", 232 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/methods/-/methods-1.1.2.tgz", 233 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 234 | }, 235 | "mime": { 236 | "version": "1.6.0", 237 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/mime/-/mime-1.6.0.tgz", 238 | "integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE=" 239 | }, 240 | "mime-db": { 241 | "version": "1.45.0", 242 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/mime-db/-/mime-db-1.45.0.tgz", 243 | "integrity": "sha1-zO7aIczXw6dF66LezVXUtz54eeo=" 244 | }, 245 | "mime-types": { 246 | "version": "2.1.28", 247 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/mime-types/-/mime-types-2.1.28.tgz", 248 | "integrity": "sha1-EWDEdX6rLFNjiI4AUnPs950qDs0=", 249 | "requires": { 250 | "mime-db": "1.45.0" 251 | } 252 | }, 253 | "ms": { 254 | "version": "2.0.0", 255 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/ms/-/ms-2.0.0.tgz", 256 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 257 | }, 258 | "negotiator": { 259 | "version": "0.6.2", 260 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/negotiator/-/negotiator-0.6.2.tgz", 261 | "integrity": "sha1-/qz3zPUlp3rpY0Q2pkiD/+yjRvs=" 262 | }, 263 | "on-finished": { 264 | "version": "2.3.0", 265 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/on-finished/-/on-finished-2.3.0.tgz", 266 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 267 | "requires": { 268 | "ee-first": "1.1.1" 269 | } 270 | }, 271 | "parseurl": { 272 | "version": "1.3.3", 273 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/parseurl/-/parseurl-1.3.3.tgz", 274 | "integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ=" 275 | }, 276 | "path-to-regexp": { 277 | "version": "0.1.7", 278 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 279 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 280 | }, 281 | "proxy-addr": { 282 | "version": "2.0.6", 283 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/proxy-addr/-/proxy-addr-2.0.6.tgz", 284 | "integrity": "sha1-/cIzZQVEfT8vLGOO0nLK9hS7sr8=", 285 | "requires": { 286 | "forwarded": "~0.1.2", 287 | "ipaddr.js": "1.9.1" 288 | } 289 | }, 290 | "qs": { 291 | "version": "6.7.0", 292 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/qs/-/qs-6.7.0.tgz", 293 | "integrity": "sha1-QdwaAV49WB8WIXdr4xr7KHapsbw=" 294 | }, 295 | "range-parser": { 296 | "version": "1.2.1", 297 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/range-parser/-/range-parser-1.2.1.tgz", 298 | "integrity": "sha1-PPNwI9GZ4cJNGlW4SADC8+ZGgDE=" 299 | }, 300 | "raw-body": { 301 | "version": "2.4.0", 302 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/raw-body/-/raw-body-2.4.0.tgz", 303 | "integrity": "sha1-oc5vucm8NWylLoklarWQWeE9AzI=", 304 | "requires": { 305 | "bytes": "3.1.0", 306 | "http-errors": "1.7.2", 307 | "iconv-lite": "0.4.24", 308 | "unpipe": "1.0.0" 309 | } 310 | }, 311 | "safe-buffer": { 312 | "version": "5.1.2", 313 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/safe-buffer/-/safe-buffer-5.1.2.tgz", 314 | "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" 315 | }, 316 | "safer-buffer": { 317 | "version": "2.1.2", 318 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/safer-buffer/-/safer-buffer-2.1.2.tgz", 319 | "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=" 320 | }, 321 | "send": { 322 | "version": "0.17.1", 323 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/send/-/send-0.17.1.tgz", 324 | "integrity": "sha1-wdiwWfeQD3Rm3Uk4vcROEd2zdsg=", 325 | "requires": { 326 | "debug": "2.6.9", 327 | "depd": "~1.1.2", 328 | "destroy": "~1.0.4", 329 | "encodeurl": "~1.0.2", 330 | "escape-html": "~1.0.3", 331 | "etag": "~1.8.1", 332 | "fresh": "0.5.2", 333 | "http-errors": "~1.7.2", 334 | "mime": "1.6.0", 335 | "ms": "2.1.1", 336 | "on-finished": "~2.3.0", 337 | "range-parser": "~1.2.1", 338 | "statuses": "~1.5.0" 339 | }, 340 | "dependencies": { 341 | "ms": { 342 | "version": "2.1.1", 343 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/ms/-/ms-2.1.1.tgz", 344 | "integrity": "sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo=" 345 | } 346 | } 347 | }, 348 | "serve-static": { 349 | "version": "1.14.1", 350 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/serve-static/-/serve-static-1.14.1.tgz", 351 | "integrity": "sha1-Zm5jbcTwEPfvKZcKiKZ0MgiYsvk=", 352 | "requires": { 353 | "encodeurl": "~1.0.2", 354 | "escape-html": "~1.0.3", 355 | "parseurl": "~1.3.3", 356 | "send": "0.17.1" 357 | } 358 | }, 359 | "setprototypeof": { 360 | "version": "1.1.1", 361 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/setprototypeof/-/setprototypeof-1.1.1.tgz", 362 | "integrity": "sha1-fpWsskqpL1iF4KvvW6ExMw1K5oM=" 363 | }, 364 | "statuses": { 365 | "version": "1.5.0", 366 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/statuses/-/statuses-1.5.0.tgz", 367 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 368 | }, 369 | "toidentifier": { 370 | "version": "1.0.0", 371 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/toidentifier/-/toidentifier-1.0.0.tgz", 372 | "integrity": "sha1-fhvjRw8ed5SLxD2Uo8j013UrpVM=" 373 | }, 374 | "type-is": { 375 | "version": "1.6.18", 376 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/type-is/-/type-is-1.6.18.tgz", 377 | "integrity": "sha1-TlUs0F3wlGfcvE73Od6J8s83wTE=", 378 | "requires": { 379 | "media-typer": "0.3.0", 380 | "mime-types": "~2.1.24" 381 | } 382 | }, 383 | "unpipe": { 384 | "version": "1.0.0", 385 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/unpipe/-/unpipe-1.0.0.tgz", 386 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 387 | }, 388 | "utils-merge": { 389 | "version": "1.0.1", 390 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/utils-merge/-/utils-merge-1.0.1.tgz", 391 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 392 | }, 393 | "vary": { 394 | "version": "1.1.2", 395 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/vary/-/vary-1.1.2.tgz", 396 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 397 | } 398 | } 399 | } 400 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/2/iwasm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "asbuild:untouched": "asc assembly/index.ts --target debug", 4 | "asbuild:optimized": "asc assembly/index.ts --target release", 5 | "asbuild": "npm run asbuild:untouched && npm run asbuild:optimized", 6 | "test": "node tests", 7 | "server": "node server.js" 8 | }, 9 | "dependencies": { 10 | "@assemblyscript/loader": "^0.18.7", 11 | "express": "^4.17.1" 12 | }, 13 | "devDependencies": { 14 | "assemblyscript": "^0.18.7" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/2/iwasm/server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express(); 3 | 4 | app.use(express.static('./')) 5 | 6 | app.listen(3000, () => console.log('Server up on port 3000!')); 7 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/2/iwasm/tests/index.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | const myModule = require(".."); 3 | assert.equal(myModule.minusOne(2), 1); 4 | console.log("ok"); 5 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/3/iwasm/asconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "targets": { 3 | "debug": { 4 | "binaryFile": "build/untouched.wasm", 5 | "textFile": "build/untouched.wat", 6 | "sourceMap": true, 7 | "debug": true 8 | }, 9 | "release": { 10 | "binaryFile": "build/optimized.wasm", 11 | "textFile": "build/optimized.wat", 12 | "sourceMap": true, 13 | "optimizeLevel": 3, 14 | "shrinkLevel": 1, 15 | "converge": false, 16 | "noAssert": false 17 | } 18 | }, 19 | "options": {} 20 | } -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/3/iwasm/assembly/index.ts: -------------------------------------------------------------------------------- 1 | export function minusOne(n: i32): i32 { 2 | return n - 1; 3 | } 4 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/3/iwasm/assembly/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "assemblyscript/std/assembly.json", 3 | "include": [ 4 | "./**/*.ts" 5 | ] 6 | } -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/3/iwasm/build/.gitignore: -------------------------------------------------------------------------------- 1 | *.wasm 2 | *.wasm.map 3 | *.asm.js 4 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/3/iwasm/build/optimized.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32))) 3 | (type $i32_=>_i32 (func (param i32) (result i32))) 4 | (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) 5 | (memory $0 0) 6 | (export "minusOne" (func $assembly/index/minusOne)) 7 | (export "memory" (memory $0)) 8 | (func $assembly/index/minusOne (param $0 i32) (result i32) 9 | local.get $0 10 | i32.const 44 11 | i32.eq 12 | if 13 | i32.const 0 14 | i32.const 0 15 | i32.const 0 16 | i32.const 0 17 | call $~lib/builtins/abort 18 | end 19 | local.get $0 20 | i32.const 1 21 | i32.sub 22 | ) 23 | ) 24 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/3/iwasm/build/untouched.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32))) 3 | (type $i32_=>_i32 (func (param i32) (result i32))) 4 | (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) 5 | (memory $0 0) 6 | (table $0 1 funcref) 7 | (global $~lib/memory/__data_end i32 (i32.const 8)) 8 | (global $~lib/memory/__stack_pointer (mut i32) (i32.const 16392)) 9 | (global $~lib/memory/__heap_base i32 (i32.const 16392)) 10 | (export "minusOne" (func $assembly/index/minusOne)) 11 | (export "memory" (memory $0)) 12 | (func $assembly/index/minusOne (param $0 i32) (result i32) 13 | local.get $0 14 | i32.const 44 15 | i32.eq 16 | if 17 | i32.const 0 18 | i32.const 0 19 | i32.const 0 20 | i32.const 0 21 | call $~lib/builtins/abort 22 | end 23 | local.get $0 24 | i32.const 1 25 | i32.sub 26 | ) 27 | ) 28 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/3/iwasm/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/3/iwasm/index.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const loader = require("@assemblyscript/loader"); 3 | const imports = { /* imports go here */ }; 4 | const wasmModule = loader.instantiateSync(fs.readFileSync(__dirname + "/build/optimized.wasm"), imports); 5 | module.exports = wasmModule.exports; 6 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/3/iwasm/js/loader.js: -------------------------------------------------------------------------------- 1 | class WasmLoader { 2 | constructor() { 3 | this._imports = { 4 | env: { 5 | abort() { 6 | throw new Error('Abort called from wasm file'); 7 | } 8 | } 9 | }; 10 | } 11 | 12 | async wasm(path, imports = this._imports) { 13 | console.log(`fetching ${path}`); 14 | 15 | if (!WebAssembly.instantiateStreaming) { 16 | return this.wasmFallback(path, imports); 17 | } 18 | 19 | const { instance } = await WebAssembly.instantiateStreaming(fetch(path), imports); 20 | 21 | return instance?.exports; 22 | } 23 | 24 | async wasmFallback(path, imports) { 25 | console.log('using fallback'); 26 | const response = await fetch(path); 27 | const bytes = await response?.arrayBuffer(); 28 | const { instance } = await WebAssembly.instantiate(bytes, imports); 29 | 30 | return instance?.exports; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/3/iwasm/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "requires": true, 3 | "lockfileVersion": 1, 4 | "dependencies": { 5 | "@assemblyscript/loader": { 6 | "version": "0.18.7", 7 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/@assemblyscript/loader/-/loader-0.18.7.tgz", 8 | "integrity": "sha1-o7r6YudH3cjXdUnFKIzXbql2xqA=" 9 | }, 10 | "accepts": { 11 | "version": "1.3.7", 12 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/accepts/-/accepts-1.3.7.tgz", 13 | "integrity": "sha1-UxvHJlF6OytB+FACHGzBXqq1B80=", 14 | "requires": { 15 | "mime-types": "~2.1.24", 16 | "negotiator": "0.6.2" 17 | } 18 | }, 19 | "array-flatten": { 20 | "version": "1.1.1", 21 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/array-flatten/-/array-flatten-1.1.1.tgz", 22 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 23 | }, 24 | "assemblyscript": { 25 | "version": "0.18.7", 26 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/assemblyscript/-/assemblyscript-0.18.7.tgz", 27 | "integrity": "sha1-tV9EKf82J88xL0c1Uht9xSQ5nMU=", 28 | "dev": true, 29 | "requires": { 30 | "binaryen": "98.0.0-nightly.20210106", 31 | "long": "^4.0.0" 32 | } 33 | }, 34 | "binaryen": { 35 | "version": "98.0.0-nightly.20210106", 36 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/binaryen/-/binaryen-98.0.0-nightly.20210106.tgz", 37 | "integrity": "sha1-x7xjfiIjqDvzyunZiWn1ae+rQGI=", 38 | "dev": true 39 | }, 40 | "body-parser": { 41 | "version": "1.19.0", 42 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/body-parser/-/body-parser-1.19.0.tgz", 43 | "integrity": "sha1-lrJwnlfJxOCab9Zqj9l5hE9p8Io=", 44 | "requires": { 45 | "bytes": "3.1.0", 46 | "content-type": "~1.0.4", 47 | "debug": "2.6.9", 48 | "depd": "~1.1.2", 49 | "http-errors": "1.7.2", 50 | "iconv-lite": "0.4.24", 51 | "on-finished": "~2.3.0", 52 | "qs": "6.7.0", 53 | "raw-body": "2.4.0", 54 | "type-is": "~1.6.17" 55 | } 56 | }, 57 | "bytes": { 58 | "version": "3.1.0", 59 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/bytes/-/bytes-3.1.0.tgz", 60 | "integrity": "sha1-9s95M6Ng4FiPqf3oVlHNx/gF0fY=" 61 | }, 62 | "content-disposition": { 63 | "version": "0.5.3", 64 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/content-disposition/-/content-disposition-0.5.3.tgz", 65 | "integrity": "sha1-4TDK9+cnkIfFYWwgB9BIVpiYT70=", 66 | "requires": { 67 | "safe-buffer": "5.1.2" 68 | } 69 | }, 70 | "content-type": { 71 | "version": "1.0.4", 72 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/content-type/-/content-type-1.0.4.tgz", 73 | "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=" 74 | }, 75 | "cookie": { 76 | "version": "0.4.0", 77 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/cookie/-/cookie-0.4.0.tgz", 78 | "integrity": "sha1-vrQ35wIrO21JAZ0IhmUwPr6cFLo=" 79 | }, 80 | "cookie-signature": { 81 | "version": "1.0.6", 82 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/cookie-signature/-/cookie-signature-1.0.6.tgz", 83 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 84 | }, 85 | "debug": { 86 | "version": "2.6.9", 87 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/debug/-/debug-2.6.9.tgz", 88 | "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", 89 | "requires": { 90 | "ms": "2.0.0" 91 | } 92 | }, 93 | "depd": { 94 | "version": "1.1.2", 95 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/depd/-/depd-1.1.2.tgz", 96 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 97 | }, 98 | "destroy": { 99 | "version": "1.0.4", 100 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/destroy/-/destroy-1.0.4.tgz", 101 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 102 | }, 103 | "ee-first": { 104 | "version": "1.1.1", 105 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/ee-first/-/ee-first-1.1.1.tgz", 106 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 107 | }, 108 | "encodeurl": { 109 | "version": "1.0.2", 110 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/encodeurl/-/encodeurl-1.0.2.tgz", 111 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 112 | }, 113 | "escape-html": { 114 | "version": "1.0.3", 115 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/escape-html/-/escape-html-1.0.3.tgz", 116 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 117 | }, 118 | "etag": { 119 | "version": "1.8.1", 120 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/etag/-/etag-1.8.1.tgz", 121 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 122 | }, 123 | "express": { 124 | "version": "4.17.1", 125 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/express/-/express-4.17.1.tgz", 126 | "integrity": "sha1-RJH8OGBc9R+GKdOcK10Cb5ikwTQ=", 127 | "requires": { 128 | "accepts": "~1.3.7", 129 | "array-flatten": "1.1.1", 130 | "body-parser": "1.19.0", 131 | "content-disposition": "0.5.3", 132 | "content-type": "~1.0.4", 133 | "cookie": "0.4.0", 134 | "cookie-signature": "1.0.6", 135 | "debug": "2.6.9", 136 | "depd": "~1.1.2", 137 | "encodeurl": "~1.0.2", 138 | "escape-html": "~1.0.3", 139 | "etag": "~1.8.1", 140 | "finalhandler": "~1.1.2", 141 | "fresh": "0.5.2", 142 | "merge-descriptors": "1.0.1", 143 | "methods": "~1.1.2", 144 | "on-finished": "~2.3.0", 145 | "parseurl": "~1.3.3", 146 | "path-to-regexp": "0.1.7", 147 | "proxy-addr": "~2.0.5", 148 | "qs": "6.7.0", 149 | "range-parser": "~1.2.1", 150 | "safe-buffer": "5.1.2", 151 | "send": "0.17.1", 152 | "serve-static": "1.14.1", 153 | "setprototypeof": "1.1.1", 154 | "statuses": "~1.5.0", 155 | "type-is": "~1.6.18", 156 | "utils-merge": "1.0.1", 157 | "vary": "~1.1.2" 158 | } 159 | }, 160 | "finalhandler": { 161 | "version": "1.1.2", 162 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/finalhandler/-/finalhandler-1.1.2.tgz", 163 | "integrity": "sha1-t+fQAP/RGTjQ/bBTUG9uur6fWH0=", 164 | "requires": { 165 | "debug": "2.6.9", 166 | "encodeurl": "~1.0.2", 167 | "escape-html": "~1.0.3", 168 | "on-finished": "~2.3.0", 169 | "parseurl": "~1.3.3", 170 | "statuses": "~1.5.0", 171 | "unpipe": "~1.0.0" 172 | } 173 | }, 174 | "forwarded": { 175 | "version": "0.1.2", 176 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/forwarded/-/forwarded-0.1.2.tgz", 177 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 178 | }, 179 | "fresh": { 180 | "version": "0.5.2", 181 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/fresh/-/fresh-0.5.2.tgz", 182 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 183 | }, 184 | "http-errors": { 185 | "version": "1.7.2", 186 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/http-errors/-/http-errors-1.7.2.tgz", 187 | "integrity": "sha1-T1ApzxMjnzEDblsuVSkrz7zIXI8=", 188 | "requires": { 189 | "depd": "~1.1.2", 190 | "inherits": "2.0.3", 191 | "setprototypeof": "1.1.1", 192 | "statuses": ">= 1.5.0 < 2", 193 | "toidentifier": "1.0.0" 194 | } 195 | }, 196 | "iconv-lite": { 197 | "version": "0.4.24", 198 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/iconv-lite/-/iconv-lite-0.4.24.tgz", 199 | "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=", 200 | "requires": { 201 | "safer-buffer": ">= 2.1.2 < 3" 202 | } 203 | }, 204 | "inherits": { 205 | "version": "2.0.3", 206 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/inherits/-/inherits-2.0.3.tgz", 207 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 208 | }, 209 | "ipaddr.js": { 210 | "version": "1.9.1", 211 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 212 | "integrity": "sha1-v/OFQ+64mEglB5/zoqjmy9RngbM=" 213 | }, 214 | "long": { 215 | "version": "4.0.0", 216 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/long/-/long-4.0.0.tgz", 217 | "integrity": "sha1-mntxz7fTYaGU6lVSQckvdGjVvyg=", 218 | "dev": true 219 | }, 220 | "media-typer": { 221 | "version": "0.3.0", 222 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/media-typer/-/media-typer-0.3.0.tgz", 223 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 224 | }, 225 | "merge-descriptors": { 226 | "version": "1.0.1", 227 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 228 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 229 | }, 230 | "methods": { 231 | "version": "1.1.2", 232 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/methods/-/methods-1.1.2.tgz", 233 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 234 | }, 235 | "mime": { 236 | "version": "1.6.0", 237 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/mime/-/mime-1.6.0.tgz", 238 | "integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE=" 239 | }, 240 | "mime-db": { 241 | "version": "1.45.0", 242 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/mime-db/-/mime-db-1.45.0.tgz", 243 | "integrity": "sha1-zO7aIczXw6dF66LezVXUtz54eeo=" 244 | }, 245 | "mime-types": { 246 | "version": "2.1.28", 247 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/mime-types/-/mime-types-2.1.28.tgz", 248 | "integrity": "sha1-EWDEdX6rLFNjiI4AUnPs950qDs0=", 249 | "requires": { 250 | "mime-db": "1.45.0" 251 | } 252 | }, 253 | "ms": { 254 | "version": "2.0.0", 255 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/ms/-/ms-2.0.0.tgz", 256 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 257 | }, 258 | "negotiator": { 259 | "version": "0.6.2", 260 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/negotiator/-/negotiator-0.6.2.tgz", 261 | "integrity": "sha1-/qz3zPUlp3rpY0Q2pkiD/+yjRvs=" 262 | }, 263 | "on-finished": { 264 | "version": "2.3.0", 265 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/on-finished/-/on-finished-2.3.0.tgz", 266 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 267 | "requires": { 268 | "ee-first": "1.1.1" 269 | } 270 | }, 271 | "parseurl": { 272 | "version": "1.3.3", 273 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/parseurl/-/parseurl-1.3.3.tgz", 274 | "integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ=" 275 | }, 276 | "path-to-regexp": { 277 | "version": "0.1.7", 278 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 279 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 280 | }, 281 | "proxy-addr": { 282 | "version": "2.0.6", 283 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/proxy-addr/-/proxy-addr-2.0.6.tgz", 284 | "integrity": "sha1-/cIzZQVEfT8vLGOO0nLK9hS7sr8=", 285 | "requires": { 286 | "forwarded": "~0.1.2", 287 | "ipaddr.js": "1.9.1" 288 | } 289 | }, 290 | "qs": { 291 | "version": "6.7.0", 292 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/qs/-/qs-6.7.0.tgz", 293 | "integrity": "sha1-QdwaAV49WB8WIXdr4xr7KHapsbw=" 294 | }, 295 | "range-parser": { 296 | "version": "1.2.1", 297 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/range-parser/-/range-parser-1.2.1.tgz", 298 | "integrity": "sha1-PPNwI9GZ4cJNGlW4SADC8+ZGgDE=" 299 | }, 300 | "raw-body": { 301 | "version": "2.4.0", 302 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/raw-body/-/raw-body-2.4.0.tgz", 303 | "integrity": "sha1-oc5vucm8NWylLoklarWQWeE9AzI=", 304 | "requires": { 305 | "bytes": "3.1.0", 306 | "http-errors": "1.7.2", 307 | "iconv-lite": "0.4.24", 308 | "unpipe": "1.0.0" 309 | } 310 | }, 311 | "safe-buffer": { 312 | "version": "5.1.2", 313 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/safe-buffer/-/safe-buffer-5.1.2.tgz", 314 | "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" 315 | }, 316 | "safer-buffer": { 317 | "version": "2.1.2", 318 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/safer-buffer/-/safer-buffer-2.1.2.tgz", 319 | "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=" 320 | }, 321 | "send": { 322 | "version": "0.17.1", 323 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/send/-/send-0.17.1.tgz", 324 | "integrity": "sha1-wdiwWfeQD3Rm3Uk4vcROEd2zdsg=", 325 | "requires": { 326 | "debug": "2.6.9", 327 | "depd": "~1.1.2", 328 | "destroy": "~1.0.4", 329 | "encodeurl": "~1.0.2", 330 | "escape-html": "~1.0.3", 331 | "etag": "~1.8.1", 332 | "fresh": "0.5.2", 333 | "http-errors": "~1.7.2", 334 | "mime": "1.6.0", 335 | "ms": "2.1.1", 336 | "on-finished": "~2.3.0", 337 | "range-parser": "~1.2.1", 338 | "statuses": "~1.5.0" 339 | }, 340 | "dependencies": { 341 | "ms": { 342 | "version": "2.1.1", 343 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/ms/-/ms-2.1.1.tgz", 344 | "integrity": "sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo=" 345 | } 346 | } 347 | }, 348 | "serve-static": { 349 | "version": "1.14.1", 350 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/serve-static/-/serve-static-1.14.1.tgz", 351 | "integrity": "sha1-Zm5jbcTwEPfvKZcKiKZ0MgiYsvk=", 352 | "requires": { 353 | "encodeurl": "~1.0.2", 354 | "escape-html": "~1.0.3", 355 | "parseurl": "~1.3.3", 356 | "send": "0.17.1" 357 | } 358 | }, 359 | "setprototypeof": { 360 | "version": "1.1.1", 361 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/setprototypeof/-/setprototypeof-1.1.1.tgz", 362 | "integrity": "sha1-fpWsskqpL1iF4KvvW6ExMw1K5oM=" 363 | }, 364 | "statuses": { 365 | "version": "1.5.0", 366 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/statuses/-/statuses-1.5.0.tgz", 367 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 368 | }, 369 | "toidentifier": { 370 | "version": "1.0.0", 371 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/toidentifier/-/toidentifier-1.0.0.tgz", 372 | "integrity": "sha1-fhvjRw8ed5SLxD2Uo8j013UrpVM=" 373 | }, 374 | "type-is": { 375 | "version": "1.6.18", 376 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/type-is/-/type-is-1.6.18.tgz", 377 | "integrity": "sha1-TlUs0F3wlGfcvE73Od6J8s83wTE=", 378 | "requires": { 379 | "media-typer": "0.3.0", 380 | "mime-types": "~2.1.24" 381 | } 382 | }, 383 | "unpipe": { 384 | "version": "1.0.0", 385 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/unpipe/-/unpipe-1.0.0.tgz", 386 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 387 | }, 388 | "utils-merge": { 389 | "version": "1.0.1", 390 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/utils-merge/-/utils-merge-1.0.1.tgz", 391 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 392 | }, 393 | "vary": { 394 | "version": "1.1.2", 395 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/vary/-/vary-1.1.2.tgz", 396 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 397 | } 398 | } 399 | } 400 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/3/iwasm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "asbuild:untouched": "asc assembly/index.ts --target debug", 4 | "asbuild:optimized": "asc assembly/index.ts --target release", 5 | "asbuild": "npm run asbuild:untouched && npm run asbuild:optimized", 6 | "test": "node tests", 7 | "server": "node server.js" 8 | }, 9 | "dependencies": { 10 | "@assemblyscript/loader": "^0.18.7", 11 | "express": "^4.17.1" 12 | }, 13 | "devDependencies": { 14 | "assemblyscript": "^0.18.7" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/3/iwasm/server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express(); 3 | 4 | app.use(express.static('./')) 5 | 6 | app.listen(3000, () => console.log('Server up on port 3000!')); 7 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/3/iwasm/tests/index.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | const myModule = require(".."); 3 | assert.equal(myModule.minusOne(2), 1); 4 | console.log("ok"); 5 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/4/iwasm/asconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "targets": { 3 | "debug": { 4 | "binaryFile": "build/untouched.wasm", 5 | "textFile": "build/untouched.wat", 6 | "sourceMap": true, 7 | "debug": true 8 | }, 9 | "release": { 10 | "binaryFile": "build/optimized.wasm", 11 | "textFile": "build/optimized.wat", 12 | "sourceMap": true, 13 | "optimizeLevel": 3, 14 | "shrinkLevel": 1, 15 | "converge": false, 16 | "noAssert": false 17 | } 18 | }, 19 | "options": {} 20 | } -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/4/iwasm/assembly/index.ts: -------------------------------------------------------------------------------- 1 | declare function log(n: i32): void 2 | 3 | export function minusOne(n: i32): i32 { 4 | log(n); 5 | return n - 1; 6 | } 7 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/4/iwasm/assembly/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "assemblyscript/std/assembly.json", 3 | "include": [ 4 | "./**/*.ts" 5 | ] 6 | } -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/4/iwasm/build/.gitignore: -------------------------------------------------------------------------------- 1 | *.wasm 2 | *.wasm.map 3 | *.asm.js 4 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/4/iwasm/build/optimized.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (type $i32_=>_none (func (param i32))) 3 | (type $i32_=>_i32 (func (param i32) (result i32))) 4 | (import "index" "log" (func $assembly/index/log (param i32))) 5 | (memory $0 0) 6 | (export "minusOne" (func $assembly/index/minusOne)) 7 | (export "memory" (memory $0)) 8 | (func $assembly/index/minusOne (param $0 i32) (result i32) 9 | local.get $0 10 | call $assembly/index/log 11 | local.get $0 12 | i32.const 1 13 | i32.sub 14 | ) 15 | ) 16 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/4/iwasm/build/untouched.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (type $i32_=>_none (func (param i32))) 3 | (type $i32_=>_i32 (func (param i32) (result i32))) 4 | (import "index" "log" (func $assembly/index/log (param i32))) 5 | (memory $0 0) 6 | (table $0 1 funcref) 7 | (global $~lib/memory/__data_end i32 (i32.const 8)) 8 | (global $~lib/memory/__stack_pointer (mut i32) (i32.const 16392)) 9 | (global $~lib/memory/__heap_base i32 (i32.const 16392)) 10 | (export "minusOne" (func $assembly/index/minusOne)) 11 | (export "memory" (memory $0)) 12 | (func $assembly/index/minusOne (param $0 i32) (result i32) 13 | local.get $0 14 | call $assembly/index/log 15 | local.get $0 16 | i32.const 1 17 | i32.sub 18 | ) 19 | ) 20 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/4/iwasm/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/4/iwasm/index.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const loader = require("@assemblyscript/loader"); 3 | const imports = { /* imports go here */ }; 4 | const wasmModule = loader.instantiateSync(fs.readFileSync(__dirname + "/build/optimized.wasm"), imports); 5 | module.exports = wasmModule.exports; 6 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/4/iwasm/js/loader.js: -------------------------------------------------------------------------------- 1 | class WasmLoader { 2 | constructor() { 3 | this._imports = { 4 | env: { 5 | abort() { 6 | throw new Error('Abort called from wasm file'); 7 | } 8 | }, 9 | index: { 10 | log(n) { 11 | console.log(n); 12 | } 13 | } 14 | }; 15 | } 16 | 17 | async wasm(path, imports = this._imports) { 18 | console.log(`fetching ${path}`); 19 | 20 | if (!WebAssembly.instantiateStreaming) { 21 | return this.wasmFallback(path, imports); 22 | } 23 | 24 | const { instance } = await WebAssembly.instantiateStreaming(fetch(path), imports); 25 | 26 | return instance?.exports; 27 | } 28 | 29 | async wasmFallback(path, imports) { 30 | console.log('using fallback'); 31 | const response = await fetch(path); 32 | const bytes = await response?.arrayBuffer(); 33 | const { instance } = await WebAssembly.instantiate(bytes, imports); 34 | 35 | return instance?.exports; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/4/iwasm/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "requires": true, 3 | "lockfileVersion": 1, 4 | "dependencies": { 5 | "@assemblyscript/loader": { 6 | "version": "0.18.7", 7 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/@assemblyscript/loader/-/loader-0.18.7.tgz", 8 | "integrity": "sha1-o7r6YudH3cjXdUnFKIzXbql2xqA=" 9 | }, 10 | "accepts": { 11 | "version": "1.3.7", 12 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/accepts/-/accepts-1.3.7.tgz", 13 | "integrity": "sha1-UxvHJlF6OytB+FACHGzBXqq1B80=", 14 | "requires": { 15 | "mime-types": "~2.1.24", 16 | "negotiator": "0.6.2" 17 | } 18 | }, 19 | "array-flatten": { 20 | "version": "1.1.1", 21 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/array-flatten/-/array-flatten-1.1.1.tgz", 22 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 23 | }, 24 | "assemblyscript": { 25 | "version": "0.18.7", 26 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/assemblyscript/-/assemblyscript-0.18.7.tgz", 27 | "integrity": "sha1-tV9EKf82J88xL0c1Uht9xSQ5nMU=", 28 | "dev": true, 29 | "requires": { 30 | "binaryen": "98.0.0-nightly.20210106", 31 | "long": "^4.0.0" 32 | } 33 | }, 34 | "binaryen": { 35 | "version": "98.0.0-nightly.20210106", 36 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/binaryen/-/binaryen-98.0.0-nightly.20210106.tgz", 37 | "integrity": "sha1-x7xjfiIjqDvzyunZiWn1ae+rQGI=", 38 | "dev": true 39 | }, 40 | "body-parser": { 41 | "version": "1.19.0", 42 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/body-parser/-/body-parser-1.19.0.tgz", 43 | "integrity": "sha1-lrJwnlfJxOCab9Zqj9l5hE9p8Io=", 44 | "requires": { 45 | "bytes": "3.1.0", 46 | "content-type": "~1.0.4", 47 | "debug": "2.6.9", 48 | "depd": "~1.1.2", 49 | "http-errors": "1.7.2", 50 | "iconv-lite": "0.4.24", 51 | "on-finished": "~2.3.0", 52 | "qs": "6.7.0", 53 | "raw-body": "2.4.0", 54 | "type-is": "~1.6.17" 55 | } 56 | }, 57 | "bytes": { 58 | "version": "3.1.0", 59 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/bytes/-/bytes-3.1.0.tgz", 60 | "integrity": "sha1-9s95M6Ng4FiPqf3oVlHNx/gF0fY=" 61 | }, 62 | "content-disposition": { 63 | "version": "0.5.3", 64 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/content-disposition/-/content-disposition-0.5.3.tgz", 65 | "integrity": "sha1-4TDK9+cnkIfFYWwgB9BIVpiYT70=", 66 | "requires": { 67 | "safe-buffer": "5.1.2" 68 | } 69 | }, 70 | "content-type": { 71 | "version": "1.0.4", 72 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/content-type/-/content-type-1.0.4.tgz", 73 | "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=" 74 | }, 75 | "cookie": { 76 | "version": "0.4.0", 77 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/cookie/-/cookie-0.4.0.tgz", 78 | "integrity": "sha1-vrQ35wIrO21JAZ0IhmUwPr6cFLo=" 79 | }, 80 | "cookie-signature": { 81 | "version": "1.0.6", 82 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/cookie-signature/-/cookie-signature-1.0.6.tgz", 83 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 84 | }, 85 | "debug": { 86 | "version": "2.6.9", 87 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/debug/-/debug-2.6.9.tgz", 88 | "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", 89 | "requires": { 90 | "ms": "2.0.0" 91 | } 92 | }, 93 | "depd": { 94 | "version": "1.1.2", 95 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/depd/-/depd-1.1.2.tgz", 96 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 97 | }, 98 | "destroy": { 99 | "version": "1.0.4", 100 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/destroy/-/destroy-1.0.4.tgz", 101 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 102 | }, 103 | "ee-first": { 104 | "version": "1.1.1", 105 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/ee-first/-/ee-first-1.1.1.tgz", 106 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 107 | }, 108 | "encodeurl": { 109 | "version": "1.0.2", 110 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/encodeurl/-/encodeurl-1.0.2.tgz", 111 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 112 | }, 113 | "escape-html": { 114 | "version": "1.0.3", 115 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/escape-html/-/escape-html-1.0.3.tgz", 116 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 117 | }, 118 | "etag": { 119 | "version": "1.8.1", 120 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/etag/-/etag-1.8.1.tgz", 121 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 122 | }, 123 | "express": { 124 | "version": "4.17.1", 125 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/express/-/express-4.17.1.tgz", 126 | "integrity": "sha1-RJH8OGBc9R+GKdOcK10Cb5ikwTQ=", 127 | "requires": { 128 | "accepts": "~1.3.7", 129 | "array-flatten": "1.1.1", 130 | "body-parser": "1.19.0", 131 | "content-disposition": "0.5.3", 132 | "content-type": "~1.0.4", 133 | "cookie": "0.4.0", 134 | "cookie-signature": "1.0.6", 135 | "debug": "2.6.9", 136 | "depd": "~1.1.2", 137 | "encodeurl": "~1.0.2", 138 | "escape-html": "~1.0.3", 139 | "etag": "~1.8.1", 140 | "finalhandler": "~1.1.2", 141 | "fresh": "0.5.2", 142 | "merge-descriptors": "1.0.1", 143 | "methods": "~1.1.2", 144 | "on-finished": "~2.3.0", 145 | "parseurl": "~1.3.3", 146 | "path-to-regexp": "0.1.7", 147 | "proxy-addr": "~2.0.5", 148 | "qs": "6.7.0", 149 | "range-parser": "~1.2.1", 150 | "safe-buffer": "5.1.2", 151 | "send": "0.17.1", 152 | "serve-static": "1.14.1", 153 | "setprototypeof": "1.1.1", 154 | "statuses": "~1.5.0", 155 | "type-is": "~1.6.18", 156 | "utils-merge": "1.0.1", 157 | "vary": "~1.1.2" 158 | } 159 | }, 160 | "finalhandler": { 161 | "version": "1.1.2", 162 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/finalhandler/-/finalhandler-1.1.2.tgz", 163 | "integrity": "sha1-t+fQAP/RGTjQ/bBTUG9uur6fWH0=", 164 | "requires": { 165 | "debug": "2.6.9", 166 | "encodeurl": "~1.0.2", 167 | "escape-html": "~1.0.3", 168 | "on-finished": "~2.3.0", 169 | "parseurl": "~1.3.3", 170 | "statuses": "~1.5.0", 171 | "unpipe": "~1.0.0" 172 | } 173 | }, 174 | "forwarded": { 175 | "version": "0.1.2", 176 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/forwarded/-/forwarded-0.1.2.tgz", 177 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 178 | }, 179 | "fresh": { 180 | "version": "0.5.2", 181 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/fresh/-/fresh-0.5.2.tgz", 182 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 183 | }, 184 | "http-errors": { 185 | "version": "1.7.2", 186 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/http-errors/-/http-errors-1.7.2.tgz", 187 | "integrity": "sha1-T1ApzxMjnzEDblsuVSkrz7zIXI8=", 188 | "requires": { 189 | "depd": "~1.1.2", 190 | "inherits": "2.0.3", 191 | "setprototypeof": "1.1.1", 192 | "statuses": ">= 1.5.0 < 2", 193 | "toidentifier": "1.0.0" 194 | } 195 | }, 196 | "iconv-lite": { 197 | "version": "0.4.24", 198 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/iconv-lite/-/iconv-lite-0.4.24.tgz", 199 | "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=", 200 | "requires": { 201 | "safer-buffer": ">= 2.1.2 < 3" 202 | } 203 | }, 204 | "inherits": { 205 | "version": "2.0.3", 206 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/inherits/-/inherits-2.0.3.tgz", 207 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 208 | }, 209 | "ipaddr.js": { 210 | "version": "1.9.1", 211 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 212 | "integrity": "sha1-v/OFQ+64mEglB5/zoqjmy9RngbM=" 213 | }, 214 | "long": { 215 | "version": "4.0.0", 216 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/long/-/long-4.0.0.tgz", 217 | "integrity": "sha1-mntxz7fTYaGU6lVSQckvdGjVvyg=", 218 | "dev": true 219 | }, 220 | "media-typer": { 221 | "version": "0.3.0", 222 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/media-typer/-/media-typer-0.3.0.tgz", 223 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 224 | }, 225 | "merge-descriptors": { 226 | "version": "1.0.1", 227 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 228 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 229 | }, 230 | "methods": { 231 | "version": "1.1.2", 232 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/methods/-/methods-1.1.2.tgz", 233 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 234 | }, 235 | "mime": { 236 | "version": "1.6.0", 237 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/mime/-/mime-1.6.0.tgz", 238 | "integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE=" 239 | }, 240 | "mime-db": { 241 | "version": "1.45.0", 242 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/mime-db/-/mime-db-1.45.0.tgz", 243 | "integrity": "sha1-zO7aIczXw6dF66LezVXUtz54eeo=" 244 | }, 245 | "mime-types": { 246 | "version": "2.1.28", 247 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/mime-types/-/mime-types-2.1.28.tgz", 248 | "integrity": "sha1-EWDEdX6rLFNjiI4AUnPs950qDs0=", 249 | "requires": { 250 | "mime-db": "1.45.0" 251 | } 252 | }, 253 | "ms": { 254 | "version": "2.0.0", 255 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/ms/-/ms-2.0.0.tgz", 256 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 257 | }, 258 | "negotiator": { 259 | "version": "0.6.2", 260 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/negotiator/-/negotiator-0.6.2.tgz", 261 | "integrity": "sha1-/qz3zPUlp3rpY0Q2pkiD/+yjRvs=" 262 | }, 263 | "on-finished": { 264 | "version": "2.3.0", 265 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/on-finished/-/on-finished-2.3.0.tgz", 266 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 267 | "requires": { 268 | "ee-first": "1.1.1" 269 | } 270 | }, 271 | "parseurl": { 272 | "version": "1.3.3", 273 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/parseurl/-/parseurl-1.3.3.tgz", 274 | "integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ=" 275 | }, 276 | "path-to-regexp": { 277 | "version": "0.1.7", 278 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 279 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 280 | }, 281 | "proxy-addr": { 282 | "version": "2.0.6", 283 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/proxy-addr/-/proxy-addr-2.0.6.tgz", 284 | "integrity": "sha1-/cIzZQVEfT8vLGOO0nLK9hS7sr8=", 285 | "requires": { 286 | "forwarded": "~0.1.2", 287 | "ipaddr.js": "1.9.1" 288 | } 289 | }, 290 | "qs": { 291 | "version": "6.7.0", 292 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/qs/-/qs-6.7.0.tgz", 293 | "integrity": "sha1-QdwaAV49WB8WIXdr4xr7KHapsbw=" 294 | }, 295 | "range-parser": { 296 | "version": "1.2.1", 297 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/range-parser/-/range-parser-1.2.1.tgz", 298 | "integrity": "sha1-PPNwI9GZ4cJNGlW4SADC8+ZGgDE=" 299 | }, 300 | "raw-body": { 301 | "version": "2.4.0", 302 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/raw-body/-/raw-body-2.4.0.tgz", 303 | "integrity": "sha1-oc5vucm8NWylLoklarWQWeE9AzI=", 304 | "requires": { 305 | "bytes": "3.1.0", 306 | "http-errors": "1.7.2", 307 | "iconv-lite": "0.4.24", 308 | "unpipe": "1.0.0" 309 | } 310 | }, 311 | "safe-buffer": { 312 | "version": "5.1.2", 313 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/safe-buffer/-/safe-buffer-5.1.2.tgz", 314 | "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" 315 | }, 316 | "safer-buffer": { 317 | "version": "2.1.2", 318 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/safer-buffer/-/safer-buffer-2.1.2.tgz", 319 | "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=" 320 | }, 321 | "send": { 322 | "version": "0.17.1", 323 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/send/-/send-0.17.1.tgz", 324 | "integrity": "sha1-wdiwWfeQD3Rm3Uk4vcROEd2zdsg=", 325 | "requires": { 326 | "debug": "2.6.9", 327 | "depd": "~1.1.2", 328 | "destroy": "~1.0.4", 329 | "encodeurl": "~1.0.2", 330 | "escape-html": "~1.0.3", 331 | "etag": "~1.8.1", 332 | "fresh": "0.5.2", 333 | "http-errors": "~1.7.2", 334 | "mime": "1.6.0", 335 | "ms": "2.1.1", 336 | "on-finished": "~2.3.0", 337 | "range-parser": "~1.2.1", 338 | "statuses": "~1.5.0" 339 | }, 340 | "dependencies": { 341 | "ms": { 342 | "version": "2.1.1", 343 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/ms/-/ms-2.1.1.tgz", 344 | "integrity": "sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo=" 345 | } 346 | } 347 | }, 348 | "serve-static": { 349 | "version": "1.14.1", 350 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/serve-static/-/serve-static-1.14.1.tgz", 351 | "integrity": "sha1-Zm5jbcTwEPfvKZcKiKZ0MgiYsvk=", 352 | "requires": { 353 | "encodeurl": "~1.0.2", 354 | "escape-html": "~1.0.3", 355 | "parseurl": "~1.3.3", 356 | "send": "0.17.1" 357 | } 358 | }, 359 | "setprototypeof": { 360 | "version": "1.1.1", 361 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/setprototypeof/-/setprototypeof-1.1.1.tgz", 362 | "integrity": "sha1-fpWsskqpL1iF4KvvW6ExMw1K5oM=" 363 | }, 364 | "statuses": { 365 | "version": "1.5.0", 366 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/statuses/-/statuses-1.5.0.tgz", 367 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 368 | }, 369 | "toidentifier": { 370 | "version": "1.0.0", 371 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/toidentifier/-/toidentifier-1.0.0.tgz", 372 | "integrity": "sha1-fhvjRw8ed5SLxD2Uo8j013UrpVM=" 373 | }, 374 | "type-is": { 375 | "version": "1.6.18", 376 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/type-is/-/type-is-1.6.18.tgz", 377 | "integrity": "sha1-TlUs0F3wlGfcvE73Od6J8s83wTE=", 378 | "requires": { 379 | "media-typer": "0.3.0", 380 | "mime-types": "~2.1.24" 381 | } 382 | }, 383 | "unpipe": { 384 | "version": "1.0.0", 385 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/unpipe/-/unpipe-1.0.0.tgz", 386 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 387 | }, 388 | "utils-merge": { 389 | "version": "1.0.1", 390 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/utils-merge/-/utils-merge-1.0.1.tgz", 391 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 392 | }, 393 | "vary": { 394 | "version": "1.1.2", 395 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/vary/-/vary-1.1.2.tgz", 396 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 397 | } 398 | } 399 | } 400 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/4/iwasm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "asbuild:untouched": "asc assembly/index.ts --target debug", 4 | "asbuild:optimized": "asc assembly/index.ts --target release", 5 | "asbuild": "npm run asbuild:untouched && npm run asbuild:optimized", 6 | "test": "node tests", 7 | "server": "node server.js" 8 | }, 9 | "dependencies": { 10 | "@assemblyscript/loader": "^0.18.7", 11 | "express": "^4.17.1" 12 | }, 13 | "devDependencies": { 14 | "assemblyscript": "^0.18.7" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/4/iwasm/server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express(); 3 | 4 | app.use(express.static('./')) 5 | 6 | app.listen(3000, () => console.log('Server up on port 3000!')); 7 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/4/iwasm/tests/index.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | const myModule = require(".."); 3 | assert.equal(myModule.minusOne(2), 1); 4 | console.log("ok"); 5 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/5/iwasm/asconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "targets": { 3 | "debug": { 4 | "binaryFile": "build/untouched.wasm", 5 | "textFile": "build/untouched.wat", 6 | "sourceMap": true, 7 | "debug": true 8 | }, 9 | "release": { 10 | "binaryFile": "build/optimized.wasm", 11 | "textFile": "build/optimized.wat", 12 | "sourceMap": true, 13 | "optimizeLevel": 3, 14 | "shrinkLevel": 1, 15 | "converge": false, 16 | "noAssert": false 17 | } 18 | }, 19 | "options": {} 20 | } -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/5/iwasm/assembly/index.ts: -------------------------------------------------------------------------------- 1 | declare function log(n: i32): void 2 | 3 | export function minusOne(n: i32): i32 { 4 | log(n); 5 | return n - 1; 6 | } 7 | 8 | export function fizzbuzz(n: i32): String | null { 9 | 10 | if (n % 15 === 0) { 11 | return 'fizzbuzz'; 12 | } 13 | 14 | if (n % 3 === 0) { 15 | return 'fizz'; 16 | } 17 | 18 | if (n % 5 === 0) { 19 | return 'buzz'; 20 | } 21 | 22 | return null; 23 | } 24 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/5/iwasm/assembly/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "assemblyscript/std/assembly.json", 3 | "include": [ 4 | "./**/*.ts" 5 | ] 6 | } -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/5/iwasm/build/.gitignore: -------------------------------------------------------------------------------- 1 | *.wasm 2 | *.wasm.map 3 | *.asm.js 4 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/5/iwasm/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/5/iwasm/index.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const loader = require("@assemblyscript/loader"); 3 | const imports = { /* imports go here */ }; 4 | const wasmModule = loader.instantiateSync(fs.readFileSync(__dirname + "/build/optimized.wasm"), imports); 5 | module.exports = wasmModule.exports; 6 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/5/iwasm/js/loader.js: -------------------------------------------------------------------------------- 1 | class WasmLoader { 2 | constructor() { 3 | this._imports = { 4 | env: { 5 | abort() { 6 | throw new Error('Abort called from wasm file'); 7 | } 8 | }, 9 | index: { 10 | log(n) { 11 | console.log(n); 12 | } 13 | } 14 | }; 15 | } 16 | 17 | async wasm(path, imports = this._imports) { 18 | console.log(`fetching ${path}`); 19 | 20 | if (!loader.instantiateStreaming) { 21 | return this.wasmFallback(path, imports); 22 | } 23 | 24 | const instance = await loader.instantiateStreaming(fetch(path), imports); 25 | 26 | return instance?.exports; 27 | } 28 | 29 | async wasmFallback(path, imports) { 30 | console.log('using fallback'); 31 | const response = await fetch(path); 32 | const bytes = await response?.arrayBuffer(); 33 | const instance = await loader.instantiate(bytes, imports); 34 | 35 | return instance?.exports; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/5/iwasm/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "requires": true, 3 | "lockfileVersion": 1, 4 | "dependencies": { 5 | "@assemblyscript/loader": { 6 | "version": "0.18.7", 7 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/@assemblyscript/loader/-/loader-0.18.7.tgz", 8 | "integrity": "sha1-o7r6YudH3cjXdUnFKIzXbql2xqA=" 9 | }, 10 | "accepts": { 11 | "version": "1.3.7", 12 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/accepts/-/accepts-1.3.7.tgz", 13 | "integrity": "sha1-UxvHJlF6OytB+FACHGzBXqq1B80=", 14 | "requires": { 15 | "mime-types": "~2.1.24", 16 | "negotiator": "0.6.2" 17 | } 18 | }, 19 | "array-flatten": { 20 | "version": "1.1.1", 21 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/array-flatten/-/array-flatten-1.1.1.tgz", 22 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 23 | }, 24 | "assemblyscript": { 25 | "version": "0.18.7", 26 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/assemblyscript/-/assemblyscript-0.18.7.tgz", 27 | "integrity": "sha1-tV9EKf82J88xL0c1Uht9xSQ5nMU=", 28 | "dev": true, 29 | "requires": { 30 | "binaryen": "98.0.0-nightly.20210106", 31 | "long": "^4.0.0" 32 | } 33 | }, 34 | "binaryen": { 35 | "version": "98.0.0-nightly.20210106", 36 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/binaryen/-/binaryen-98.0.0-nightly.20210106.tgz", 37 | "integrity": "sha1-x7xjfiIjqDvzyunZiWn1ae+rQGI=", 38 | "dev": true 39 | }, 40 | "body-parser": { 41 | "version": "1.19.0", 42 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/body-parser/-/body-parser-1.19.0.tgz", 43 | "integrity": "sha1-lrJwnlfJxOCab9Zqj9l5hE9p8Io=", 44 | "requires": { 45 | "bytes": "3.1.0", 46 | "content-type": "~1.0.4", 47 | "debug": "2.6.9", 48 | "depd": "~1.1.2", 49 | "http-errors": "1.7.2", 50 | "iconv-lite": "0.4.24", 51 | "on-finished": "~2.3.0", 52 | "qs": "6.7.0", 53 | "raw-body": "2.4.0", 54 | "type-is": "~1.6.17" 55 | } 56 | }, 57 | "bytes": { 58 | "version": "3.1.0", 59 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/bytes/-/bytes-3.1.0.tgz", 60 | "integrity": "sha1-9s95M6Ng4FiPqf3oVlHNx/gF0fY=" 61 | }, 62 | "content-disposition": { 63 | "version": "0.5.3", 64 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/content-disposition/-/content-disposition-0.5.3.tgz", 65 | "integrity": "sha1-4TDK9+cnkIfFYWwgB9BIVpiYT70=", 66 | "requires": { 67 | "safe-buffer": "5.1.2" 68 | } 69 | }, 70 | "content-type": { 71 | "version": "1.0.4", 72 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/content-type/-/content-type-1.0.4.tgz", 73 | "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=" 74 | }, 75 | "cookie": { 76 | "version": "0.4.0", 77 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/cookie/-/cookie-0.4.0.tgz", 78 | "integrity": "sha1-vrQ35wIrO21JAZ0IhmUwPr6cFLo=" 79 | }, 80 | "cookie-signature": { 81 | "version": "1.0.6", 82 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/cookie-signature/-/cookie-signature-1.0.6.tgz", 83 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 84 | }, 85 | "debug": { 86 | "version": "2.6.9", 87 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/debug/-/debug-2.6.9.tgz", 88 | "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", 89 | "requires": { 90 | "ms": "2.0.0" 91 | } 92 | }, 93 | "depd": { 94 | "version": "1.1.2", 95 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/depd/-/depd-1.1.2.tgz", 96 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 97 | }, 98 | "destroy": { 99 | "version": "1.0.4", 100 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/destroy/-/destroy-1.0.4.tgz", 101 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 102 | }, 103 | "ee-first": { 104 | "version": "1.1.1", 105 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/ee-first/-/ee-first-1.1.1.tgz", 106 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 107 | }, 108 | "encodeurl": { 109 | "version": "1.0.2", 110 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/encodeurl/-/encodeurl-1.0.2.tgz", 111 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 112 | }, 113 | "escape-html": { 114 | "version": "1.0.3", 115 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/escape-html/-/escape-html-1.0.3.tgz", 116 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 117 | }, 118 | "etag": { 119 | "version": "1.8.1", 120 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/etag/-/etag-1.8.1.tgz", 121 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 122 | }, 123 | "express": { 124 | "version": "4.17.1", 125 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/express/-/express-4.17.1.tgz", 126 | "integrity": "sha1-RJH8OGBc9R+GKdOcK10Cb5ikwTQ=", 127 | "requires": { 128 | "accepts": "~1.3.7", 129 | "array-flatten": "1.1.1", 130 | "body-parser": "1.19.0", 131 | "content-disposition": "0.5.3", 132 | "content-type": "~1.0.4", 133 | "cookie": "0.4.0", 134 | "cookie-signature": "1.0.6", 135 | "debug": "2.6.9", 136 | "depd": "~1.1.2", 137 | "encodeurl": "~1.0.2", 138 | "escape-html": "~1.0.3", 139 | "etag": "~1.8.1", 140 | "finalhandler": "~1.1.2", 141 | "fresh": "0.5.2", 142 | "merge-descriptors": "1.0.1", 143 | "methods": "~1.1.2", 144 | "on-finished": "~2.3.0", 145 | "parseurl": "~1.3.3", 146 | "path-to-regexp": "0.1.7", 147 | "proxy-addr": "~2.0.5", 148 | "qs": "6.7.0", 149 | "range-parser": "~1.2.1", 150 | "safe-buffer": "5.1.2", 151 | "send": "0.17.1", 152 | "serve-static": "1.14.1", 153 | "setprototypeof": "1.1.1", 154 | "statuses": "~1.5.0", 155 | "type-is": "~1.6.18", 156 | "utils-merge": "1.0.1", 157 | "vary": "~1.1.2" 158 | } 159 | }, 160 | "finalhandler": { 161 | "version": "1.1.2", 162 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/finalhandler/-/finalhandler-1.1.2.tgz", 163 | "integrity": "sha1-t+fQAP/RGTjQ/bBTUG9uur6fWH0=", 164 | "requires": { 165 | "debug": "2.6.9", 166 | "encodeurl": "~1.0.2", 167 | "escape-html": "~1.0.3", 168 | "on-finished": "~2.3.0", 169 | "parseurl": "~1.3.3", 170 | "statuses": "~1.5.0", 171 | "unpipe": "~1.0.0" 172 | } 173 | }, 174 | "forwarded": { 175 | "version": "0.1.2", 176 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/forwarded/-/forwarded-0.1.2.tgz", 177 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 178 | }, 179 | "fresh": { 180 | "version": "0.5.2", 181 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/fresh/-/fresh-0.5.2.tgz", 182 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 183 | }, 184 | "http-errors": { 185 | "version": "1.7.2", 186 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/http-errors/-/http-errors-1.7.2.tgz", 187 | "integrity": "sha1-T1ApzxMjnzEDblsuVSkrz7zIXI8=", 188 | "requires": { 189 | "depd": "~1.1.2", 190 | "inherits": "2.0.3", 191 | "setprototypeof": "1.1.1", 192 | "statuses": ">= 1.5.0 < 2", 193 | "toidentifier": "1.0.0" 194 | } 195 | }, 196 | "iconv-lite": { 197 | "version": "0.4.24", 198 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/iconv-lite/-/iconv-lite-0.4.24.tgz", 199 | "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=", 200 | "requires": { 201 | "safer-buffer": ">= 2.1.2 < 3" 202 | } 203 | }, 204 | "inherits": { 205 | "version": "2.0.3", 206 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/inherits/-/inherits-2.0.3.tgz", 207 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 208 | }, 209 | "ipaddr.js": { 210 | "version": "1.9.1", 211 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 212 | "integrity": "sha1-v/OFQ+64mEglB5/zoqjmy9RngbM=" 213 | }, 214 | "long": { 215 | "version": "4.0.0", 216 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/long/-/long-4.0.0.tgz", 217 | "integrity": "sha1-mntxz7fTYaGU6lVSQckvdGjVvyg=", 218 | "dev": true 219 | }, 220 | "media-typer": { 221 | "version": "0.3.0", 222 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/media-typer/-/media-typer-0.3.0.tgz", 223 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 224 | }, 225 | "merge-descriptors": { 226 | "version": "1.0.1", 227 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 228 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 229 | }, 230 | "methods": { 231 | "version": "1.1.2", 232 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/methods/-/methods-1.1.2.tgz", 233 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 234 | }, 235 | "mime": { 236 | "version": "1.6.0", 237 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/mime/-/mime-1.6.0.tgz", 238 | "integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE=" 239 | }, 240 | "mime-db": { 241 | "version": "1.45.0", 242 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/mime-db/-/mime-db-1.45.0.tgz", 243 | "integrity": "sha1-zO7aIczXw6dF66LezVXUtz54eeo=" 244 | }, 245 | "mime-types": { 246 | "version": "2.1.28", 247 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/mime-types/-/mime-types-2.1.28.tgz", 248 | "integrity": "sha1-EWDEdX6rLFNjiI4AUnPs950qDs0=", 249 | "requires": { 250 | "mime-db": "1.45.0" 251 | } 252 | }, 253 | "ms": { 254 | "version": "2.0.0", 255 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/ms/-/ms-2.0.0.tgz", 256 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 257 | }, 258 | "negotiator": { 259 | "version": "0.6.2", 260 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/negotiator/-/negotiator-0.6.2.tgz", 261 | "integrity": "sha1-/qz3zPUlp3rpY0Q2pkiD/+yjRvs=" 262 | }, 263 | "on-finished": { 264 | "version": "2.3.0", 265 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/on-finished/-/on-finished-2.3.0.tgz", 266 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 267 | "requires": { 268 | "ee-first": "1.1.1" 269 | } 270 | }, 271 | "parseurl": { 272 | "version": "1.3.3", 273 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/parseurl/-/parseurl-1.3.3.tgz", 274 | "integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ=" 275 | }, 276 | "path-to-regexp": { 277 | "version": "0.1.7", 278 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 279 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 280 | }, 281 | "proxy-addr": { 282 | "version": "2.0.6", 283 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/proxy-addr/-/proxy-addr-2.0.6.tgz", 284 | "integrity": "sha1-/cIzZQVEfT8vLGOO0nLK9hS7sr8=", 285 | "requires": { 286 | "forwarded": "~0.1.2", 287 | "ipaddr.js": "1.9.1" 288 | } 289 | }, 290 | "qs": { 291 | "version": "6.7.0", 292 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/qs/-/qs-6.7.0.tgz", 293 | "integrity": "sha1-QdwaAV49WB8WIXdr4xr7KHapsbw=" 294 | }, 295 | "range-parser": { 296 | "version": "1.2.1", 297 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/range-parser/-/range-parser-1.2.1.tgz", 298 | "integrity": "sha1-PPNwI9GZ4cJNGlW4SADC8+ZGgDE=" 299 | }, 300 | "raw-body": { 301 | "version": "2.4.0", 302 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/raw-body/-/raw-body-2.4.0.tgz", 303 | "integrity": "sha1-oc5vucm8NWylLoklarWQWeE9AzI=", 304 | "requires": { 305 | "bytes": "3.1.0", 306 | "http-errors": "1.7.2", 307 | "iconv-lite": "0.4.24", 308 | "unpipe": "1.0.0" 309 | } 310 | }, 311 | "safe-buffer": { 312 | "version": "5.1.2", 313 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/safe-buffer/-/safe-buffer-5.1.2.tgz", 314 | "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" 315 | }, 316 | "safer-buffer": { 317 | "version": "2.1.2", 318 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/safer-buffer/-/safer-buffer-2.1.2.tgz", 319 | "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=" 320 | }, 321 | "send": { 322 | "version": "0.17.1", 323 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/send/-/send-0.17.1.tgz", 324 | "integrity": "sha1-wdiwWfeQD3Rm3Uk4vcROEd2zdsg=", 325 | "requires": { 326 | "debug": "2.6.9", 327 | "depd": "~1.1.2", 328 | "destroy": "~1.0.4", 329 | "encodeurl": "~1.0.2", 330 | "escape-html": "~1.0.3", 331 | "etag": "~1.8.1", 332 | "fresh": "0.5.2", 333 | "http-errors": "~1.7.2", 334 | "mime": "1.6.0", 335 | "ms": "2.1.1", 336 | "on-finished": "~2.3.0", 337 | "range-parser": "~1.2.1", 338 | "statuses": "~1.5.0" 339 | }, 340 | "dependencies": { 341 | "ms": { 342 | "version": "2.1.1", 343 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/ms/-/ms-2.1.1.tgz", 344 | "integrity": "sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo=" 345 | } 346 | } 347 | }, 348 | "serve-static": { 349 | "version": "1.14.1", 350 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/serve-static/-/serve-static-1.14.1.tgz", 351 | "integrity": "sha1-Zm5jbcTwEPfvKZcKiKZ0MgiYsvk=", 352 | "requires": { 353 | "encodeurl": "~1.0.2", 354 | "escape-html": "~1.0.3", 355 | "parseurl": "~1.3.3", 356 | "send": "0.17.1" 357 | } 358 | }, 359 | "setprototypeof": { 360 | "version": "1.1.1", 361 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/setprototypeof/-/setprototypeof-1.1.1.tgz", 362 | "integrity": "sha1-fpWsskqpL1iF4KvvW6ExMw1K5oM=" 363 | }, 364 | "statuses": { 365 | "version": "1.5.0", 366 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/statuses/-/statuses-1.5.0.tgz", 367 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 368 | }, 369 | "toidentifier": { 370 | "version": "1.0.0", 371 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/toidentifier/-/toidentifier-1.0.0.tgz", 372 | "integrity": "sha1-fhvjRw8ed5SLxD2Uo8j013UrpVM=" 373 | }, 374 | "type-is": { 375 | "version": "1.6.18", 376 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/type-is/-/type-is-1.6.18.tgz", 377 | "integrity": "sha1-TlUs0F3wlGfcvE73Od6J8s83wTE=", 378 | "requires": { 379 | "media-typer": "0.3.0", 380 | "mime-types": "~2.1.24" 381 | } 382 | }, 383 | "unpipe": { 384 | "version": "1.0.0", 385 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/unpipe/-/unpipe-1.0.0.tgz", 386 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 387 | }, 388 | "utils-merge": { 389 | "version": "1.0.1", 390 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/utils-merge/-/utils-merge-1.0.1.tgz", 391 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 392 | }, 393 | "vary": { 394 | "version": "1.1.2", 395 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/vary/-/vary-1.1.2.tgz", 396 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 397 | } 398 | } 399 | } 400 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/5/iwasm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "asbuild:untouched": "asc assembly/index.ts --target debug --exportRuntime", 4 | "asbuild:optimized": "asc assembly/index.ts --target release --exportRuntime", 5 | "asbuild": "npm run asbuild:untouched && npm run asbuild:optimized", 6 | "test": "node tests", 7 | "server": "node server.js" 8 | }, 9 | "dependencies": { 10 | "@assemblyscript/loader": "^0.18.7", 11 | "express": "^4.17.1" 12 | }, 13 | "devDependencies": { 14 | "assemblyscript": "^0.18.7" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/5/iwasm/server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express(); 3 | 4 | app.use(express.static('./')) 5 | 6 | app.listen(3000, () => console.log('Server up on port 3000!')); 7 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/5/iwasm/tests/index.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | const myModule = require(".."); 3 | assert.equal(myModule.minusOne(2), 1); 4 | console.log("ok"); 5 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/6/iwasm/asconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "targets": { 3 | "debug": { 4 | "binaryFile": "build/untouched.wasm", 5 | "textFile": "build/untouched.wat", 6 | "sourceMap": true, 7 | "debug": true 8 | }, 9 | "release": { 10 | "binaryFile": "build/optimized.wasm", 11 | "textFile": "build/optimized.wat", 12 | "sourceMap": true, 13 | "optimizeLevel": 3, 14 | "shrinkLevel": 1, 15 | "converge": false, 16 | "noAssert": false 17 | } 18 | }, 19 | "options": {} 20 | } -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/6/iwasm/assembly/index.ts: -------------------------------------------------------------------------------- 1 | declare function log(n: i32): void 2 | 3 | memory.grow(2); 4 | store(0, 21); 5 | store(1, 99); 6 | 7 | export function readMemory(n: i32): i32 { 8 | const valueAtIndexOne = load(n); 9 | return valueAtIndexOne; 10 | } 11 | 12 | 13 | 14 | export function minusOne(n: i32): i32 { 15 | log(n); 16 | return n - 1; 17 | } 18 | 19 | export function fizzbuzz(n: i32): String | null { 20 | 21 | if (n % 15 === 0) { 22 | return 'fizzbuzz'; 23 | } 24 | 25 | if (n % 3 === 0) { 26 | return 'fizz'; 27 | } 28 | 29 | if (n % 5 === 0) { 30 | return 'buzz'; 31 | } 32 | 33 | return null; 34 | } 35 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/6/iwasm/assembly/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "assemblyscript/std/assembly.json", 3 | "include": [ 4 | "./**/*.ts" 5 | ] 6 | } -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/6/iwasm/build/.gitignore: -------------------------------------------------------------------------------- 1 | *.wasm 2 | *.wasm.map 3 | *.asm.js 4 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/6/iwasm/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/6/iwasm/index.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const loader = require("@assemblyscript/loader"); 3 | const imports = { /* imports go here */ }; 4 | const wasmModule = loader.instantiateSync(fs.readFileSync(__dirname + "/build/optimized.wasm"), imports); 5 | module.exports = wasmModule.exports; 6 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/6/iwasm/js/loader.js: -------------------------------------------------------------------------------- 1 | class WasmLoader { 2 | constructor() { 3 | this._imports = { 4 | env: { 5 | abort() { 6 | throw new Error('Abort called from wasm file'); 7 | } 8 | }, 9 | index: { 10 | log(n) { 11 | console.log(n); 12 | } 13 | } 14 | }; 15 | } 16 | 17 | async wasm(path, imports = this._imports) { 18 | console.log(`fetching ${path}`); 19 | 20 | if (!loader.instantiateStreaming) { 21 | return this.wasmFallback(path, imports); 22 | } 23 | 24 | const instance = await loader.instantiateStreaming(fetch(path), imports); 25 | 26 | return instance?.exports; 27 | } 28 | 29 | async wasmFallback(path, imports) { 30 | console.log('using fallback'); 31 | const response = await fetch(path); 32 | const bytes = await response?.arrayBuffer(); 33 | const instance = await loader.instantiate(bytes, imports); 34 | 35 | return instance?.exports; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/6/iwasm/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "requires": true, 3 | "lockfileVersion": 1, 4 | "dependencies": { 5 | "@assemblyscript/loader": { 6 | "version": "0.18.7", 7 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/@assemblyscript/loader/-/loader-0.18.7.tgz", 8 | "integrity": "sha1-o7r6YudH3cjXdUnFKIzXbql2xqA=" 9 | }, 10 | "accepts": { 11 | "version": "1.3.7", 12 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/accepts/-/accepts-1.3.7.tgz", 13 | "integrity": "sha1-UxvHJlF6OytB+FACHGzBXqq1B80=", 14 | "requires": { 15 | "mime-types": "~2.1.24", 16 | "negotiator": "0.6.2" 17 | } 18 | }, 19 | "array-flatten": { 20 | "version": "1.1.1", 21 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/array-flatten/-/array-flatten-1.1.1.tgz", 22 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 23 | }, 24 | "assemblyscript": { 25 | "version": "0.18.7", 26 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/assemblyscript/-/assemblyscript-0.18.7.tgz", 27 | "integrity": "sha1-tV9EKf82J88xL0c1Uht9xSQ5nMU=", 28 | "dev": true, 29 | "requires": { 30 | "binaryen": "98.0.0-nightly.20210106", 31 | "long": "^4.0.0" 32 | } 33 | }, 34 | "binaryen": { 35 | "version": "98.0.0-nightly.20210106", 36 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/binaryen/-/binaryen-98.0.0-nightly.20210106.tgz", 37 | "integrity": "sha1-x7xjfiIjqDvzyunZiWn1ae+rQGI=", 38 | "dev": true 39 | }, 40 | "body-parser": { 41 | "version": "1.19.0", 42 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/body-parser/-/body-parser-1.19.0.tgz", 43 | "integrity": "sha1-lrJwnlfJxOCab9Zqj9l5hE9p8Io=", 44 | "requires": { 45 | "bytes": "3.1.0", 46 | "content-type": "~1.0.4", 47 | "debug": "2.6.9", 48 | "depd": "~1.1.2", 49 | "http-errors": "1.7.2", 50 | "iconv-lite": "0.4.24", 51 | "on-finished": "~2.3.0", 52 | "qs": "6.7.0", 53 | "raw-body": "2.4.0", 54 | "type-is": "~1.6.17" 55 | } 56 | }, 57 | "bytes": { 58 | "version": "3.1.0", 59 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/bytes/-/bytes-3.1.0.tgz", 60 | "integrity": "sha1-9s95M6Ng4FiPqf3oVlHNx/gF0fY=" 61 | }, 62 | "content-disposition": { 63 | "version": "0.5.3", 64 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/content-disposition/-/content-disposition-0.5.3.tgz", 65 | "integrity": "sha1-4TDK9+cnkIfFYWwgB9BIVpiYT70=", 66 | "requires": { 67 | "safe-buffer": "5.1.2" 68 | } 69 | }, 70 | "content-type": { 71 | "version": "1.0.4", 72 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/content-type/-/content-type-1.0.4.tgz", 73 | "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=" 74 | }, 75 | "cookie": { 76 | "version": "0.4.0", 77 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/cookie/-/cookie-0.4.0.tgz", 78 | "integrity": "sha1-vrQ35wIrO21JAZ0IhmUwPr6cFLo=" 79 | }, 80 | "cookie-signature": { 81 | "version": "1.0.6", 82 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/cookie-signature/-/cookie-signature-1.0.6.tgz", 83 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 84 | }, 85 | "debug": { 86 | "version": "2.6.9", 87 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/debug/-/debug-2.6.9.tgz", 88 | "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", 89 | "requires": { 90 | "ms": "2.0.0" 91 | } 92 | }, 93 | "depd": { 94 | "version": "1.1.2", 95 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/depd/-/depd-1.1.2.tgz", 96 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 97 | }, 98 | "destroy": { 99 | "version": "1.0.4", 100 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/destroy/-/destroy-1.0.4.tgz", 101 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 102 | }, 103 | "ee-first": { 104 | "version": "1.1.1", 105 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/ee-first/-/ee-first-1.1.1.tgz", 106 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 107 | }, 108 | "encodeurl": { 109 | "version": "1.0.2", 110 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/encodeurl/-/encodeurl-1.0.2.tgz", 111 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 112 | }, 113 | "escape-html": { 114 | "version": "1.0.3", 115 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/escape-html/-/escape-html-1.0.3.tgz", 116 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 117 | }, 118 | "etag": { 119 | "version": "1.8.1", 120 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/etag/-/etag-1.8.1.tgz", 121 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 122 | }, 123 | "express": { 124 | "version": "4.17.1", 125 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/express/-/express-4.17.1.tgz", 126 | "integrity": "sha1-RJH8OGBc9R+GKdOcK10Cb5ikwTQ=", 127 | "requires": { 128 | "accepts": "~1.3.7", 129 | "array-flatten": "1.1.1", 130 | "body-parser": "1.19.0", 131 | "content-disposition": "0.5.3", 132 | "content-type": "~1.0.4", 133 | "cookie": "0.4.0", 134 | "cookie-signature": "1.0.6", 135 | "debug": "2.6.9", 136 | "depd": "~1.1.2", 137 | "encodeurl": "~1.0.2", 138 | "escape-html": "~1.0.3", 139 | "etag": "~1.8.1", 140 | "finalhandler": "~1.1.2", 141 | "fresh": "0.5.2", 142 | "merge-descriptors": "1.0.1", 143 | "methods": "~1.1.2", 144 | "on-finished": "~2.3.0", 145 | "parseurl": "~1.3.3", 146 | "path-to-regexp": "0.1.7", 147 | "proxy-addr": "~2.0.5", 148 | "qs": "6.7.0", 149 | "range-parser": "~1.2.1", 150 | "safe-buffer": "5.1.2", 151 | "send": "0.17.1", 152 | "serve-static": "1.14.1", 153 | "setprototypeof": "1.1.1", 154 | "statuses": "~1.5.0", 155 | "type-is": "~1.6.18", 156 | "utils-merge": "1.0.1", 157 | "vary": "~1.1.2" 158 | } 159 | }, 160 | "finalhandler": { 161 | "version": "1.1.2", 162 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/finalhandler/-/finalhandler-1.1.2.tgz", 163 | "integrity": "sha1-t+fQAP/RGTjQ/bBTUG9uur6fWH0=", 164 | "requires": { 165 | "debug": "2.6.9", 166 | "encodeurl": "~1.0.2", 167 | "escape-html": "~1.0.3", 168 | "on-finished": "~2.3.0", 169 | "parseurl": "~1.3.3", 170 | "statuses": "~1.5.0", 171 | "unpipe": "~1.0.0" 172 | } 173 | }, 174 | "forwarded": { 175 | "version": "0.1.2", 176 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/forwarded/-/forwarded-0.1.2.tgz", 177 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 178 | }, 179 | "fresh": { 180 | "version": "0.5.2", 181 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/fresh/-/fresh-0.5.2.tgz", 182 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 183 | }, 184 | "http-errors": { 185 | "version": "1.7.2", 186 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/http-errors/-/http-errors-1.7.2.tgz", 187 | "integrity": "sha1-T1ApzxMjnzEDblsuVSkrz7zIXI8=", 188 | "requires": { 189 | "depd": "~1.1.2", 190 | "inherits": "2.0.3", 191 | "setprototypeof": "1.1.1", 192 | "statuses": ">= 1.5.0 < 2", 193 | "toidentifier": "1.0.0" 194 | } 195 | }, 196 | "iconv-lite": { 197 | "version": "0.4.24", 198 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/iconv-lite/-/iconv-lite-0.4.24.tgz", 199 | "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=", 200 | "requires": { 201 | "safer-buffer": ">= 2.1.2 < 3" 202 | } 203 | }, 204 | "inherits": { 205 | "version": "2.0.3", 206 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/inherits/-/inherits-2.0.3.tgz", 207 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 208 | }, 209 | "ipaddr.js": { 210 | "version": "1.9.1", 211 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 212 | "integrity": "sha1-v/OFQ+64mEglB5/zoqjmy9RngbM=" 213 | }, 214 | "long": { 215 | "version": "4.0.0", 216 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/long/-/long-4.0.0.tgz", 217 | "integrity": "sha1-mntxz7fTYaGU6lVSQckvdGjVvyg=", 218 | "dev": true 219 | }, 220 | "media-typer": { 221 | "version": "0.3.0", 222 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/media-typer/-/media-typer-0.3.0.tgz", 223 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 224 | }, 225 | "merge-descriptors": { 226 | "version": "1.0.1", 227 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 228 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 229 | }, 230 | "methods": { 231 | "version": "1.1.2", 232 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/methods/-/methods-1.1.2.tgz", 233 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 234 | }, 235 | "mime": { 236 | "version": "1.6.0", 237 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/mime/-/mime-1.6.0.tgz", 238 | "integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE=" 239 | }, 240 | "mime-db": { 241 | "version": "1.45.0", 242 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/mime-db/-/mime-db-1.45.0.tgz", 243 | "integrity": "sha1-zO7aIczXw6dF66LezVXUtz54eeo=" 244 | }, 245 | "mime-types": { 246 | "version": "2.1.28", 247 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/mime-types/-/mime-types-2.1.28.tgz", 248 | "integrity": "sha1-EWDEdX6rLFNjiI4AUnPs950qDs0=", 249 | "requires": { 250 | "mime-db": "1.45.0" 251 | } 252 | }, 253 | "ms": { 254 | "version": "2.0.0", 255 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/ms/-/ms-2.0.0.tgz", 256 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 257 | }, 258 | "negotiator": { 259 | "version": "0.6.2", 260 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/negotiator/-/negotiator-0.6.2.tgz", 261 | "integrity": "sha1-/qz3zPUlp3rpY0Q2pkiD/+yjRvs=" 262 | }, 263 | "on-finished": { 264 | "version": "2.3.0", 265 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/on-finished/-/on-finished-2.3.0.tgz", 266 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 267 | "requires": { 268 | "ee-first": "1.1.1" 269 | } 270 | }, 271 | "parseurl": { 272 | "version": "1.3.3", 273 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/parseurl/-/parseurl-1.3.3.tgz", 274 | "integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ=" 275 | }, 276 | "path-to-regexp": { 277 | "version": "0.1.7", 278 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 279 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 280 | }, 281 | "proxy-addr": { 282 | "version": "2.0.6", 283 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/proxy-addr/-/proxy-addr-2.0.6.tgz", 284 | "integrity": "sha1-/cIzZQVEfT8vLGOO0nLK9hS7sr8=", 285 | "requires": { 286 | "forwarded": "~0.1.2", 287 | "ipaddr.js": "1.9.1" 288 | } 289 | }, 290 | "qs": { 291 | "version": "6.7.0", 292 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/qs/-/qs-6.7.0.tgz", 293 | "integrity": "sha1-QdwaAV49WB8WIXdr4xr7KHapsbw=" 294 | }, 295 | "range-parser": { 296 | "version": "1.2.1", 297 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/range-parser/-/range-parser-1.2.1.tgz", 298 | "integrity": "sha1-PPNwI9GZ4cJNGlW4SADC8+ZGgDE=" 299 | }, 300 | "raw-body": { 301 | "version": "2.4.0", 302 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/raw-body/-/raw-body-2.4.0.tgz", 303 | "integrity": "sha1-oc5vucm8NWylLoklarWQWeE9AzI=", 304 | "requires": { 305 | "bytes": "3.1.0", 306 | "http-errors": "1.7.2", 307 | "iconv-lite": "0.4.24", 308 | "unpipe": "1.0.0" 309 | } 310 | }, 311 | "safe-buffer": { 312 | "version": "5.1.2", 313 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/safe-buffer/-/safe-buffer-5.1.2.tgz", 314 | "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" 315 | }, 316 | "safer-buffer": { 317 | "version": "2.1.2", 318 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/safer-buffer/-/safer-buffer-2.1.2.tgz", 319 | "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=" 320 | }, 321 | "send": { 322 | "version": "0.17.1", 323 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/send/-/send-0.17.1.tgz", 324 | "integrity": "sha1-wdiwWfeQD3Rm3Uk4vcROEd2zdsg=", 325 | "requires": { 326 | "debug": "2.6.9", 327 | "depd": "~1.1.2", 328 | "destroy": "~1.0.4", 329 | "encodeurl": "~1.0.2", 330 | "escape-html": "~1.0.3", 331 | "etag": "~1.8.1", 332 | "fresh": "0.5.2", 333 | "http-errors": "~1.7.2", 334 | "mime": "1.6.0", 335 | "ms": "2.1.1", 336 | "on-finished": "~2.3.0", 337 | "range-parser": "~1.2.1", 338 | "statuses": "~1.5.0" 339 | }, 340 | "dependencies": { 341 | "ms": { 342 | "version": "2.1.1", 343 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/ms/-/ms-2.1.1.tgz", 344 | "integrity": "sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo=" 345 | } 346 | } 347 | }, 348 | "serve-static": { 349 | "version": "1.14.1", 350 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/serve-static/-/serve-static-1.14.1.tgz", 351 | "integrity": "sha1-Zm5jbcTwEPfvKZcKiKZ0MgiYsvk=", 352 | "requires": { 353 | "encodeurl": "~1.0.2", 354 | "escape-html": "~1.0.3", 355 | "parseurl": "~1.3.3", 356 | "send": "0.17.1" 357 | } 358 | }, 359 | "setprototypeof": { 360 | "version": "1.1.1", 361 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/setprototypeof/-/setprototypeof-1.1.1.tgz", 362 | "integrity": "sha1-fpWsskqpL1iF4KvvW6ExMw1K5oM=" 363 | }, 364 | "statuses": { 365 | "version": "1.5.0", 366 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/statuses/-/statuses-1.5.0.tgz", 367 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 368 | }, 369 | "toidentifier": { 370 | "version": "1.0.0", 371 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/toidentifier/-/toidentifier-1.0.0.tgz", 372 | "integrity": "sha1-fhvjRw8ed5SLxD2Uo8j013UrpVM=" 373 | }, 374 | "type-is": { 375 | "version": "1.6.18", 376 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/type-is/-/type-is-1.6.18.tgz", 377 | "integrity": "sha1-TlUs0F3wlGfcvE73Od6J8s83wTE=", 378 | "requires": { 379 | "media-typer": "0.3.0", 380 | "mime-types": "~2.1.24" 381 | } 382 | }, 383 | "unpipe": { 384 | "version": "1.0.0", 385 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/unpipe/-/unpipe-1.0.0.tgz", 386 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 387 | }, 388 | "utils-merge": { 389 | "version": "1.0.1", 390 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/utils-merge/-/utils-merge-1.0.1.tgz", 391 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 392 | }, 393 | "vary": { 394 | "version": "1.1.2", 395 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/vary/-/vary-1.1.2.tgz", 396 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 397 | } 398 | } 399 | } 400 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/6/iwasm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "asbuild:untouched": "asc assembly/index.ts --target debug --exportRuntime", 4 | "asbuild:optimized": "asc assembly/index.ts --target release --exportRuntime", 5 | "asbuild": "npm run asbuild:untouched && npm run asbuild:optimized", 6 | "test": "node tests", 7 | "server": "node server.js" 8 | }, 9 | "dependencies": { 10 | "@assemblyscript/loader": "^0.18.7", 11 | "express": "^4.17.1" 12 | }, 13 | "devDependencies": { 14 | "assemblyscript": "^0.18.7" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/6/iwasm/server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express(); 3 | 4 | app.use(express.static('./')) 5 | 6 | app.listen(3000, () => console.log('Server up on port 3000!')); 7 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/6/iwasm/tests/index.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | const myModule = require(".."); 3 | assert.equal(myModule.minusOne(2), 1); 4 | console.log("ok"); 5 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/7/iwasm/asconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "targets": { 3 | "debug": { 4 | "binaryFile": "build/untouched.wasm", 5 | "textFile": "build/untouched.wat", 6 | "sourceMap": true, 7 | "debug": true 8 | }, 9 | "release": { 10 | "binaryFile": "build/optimized.wasm", 11 | "textFile": "build/optimized.wat", 12 | "sourceMap": true, 13 | "optimizeLevel": 3, 14 | "shrinkLevel": 1, 15 | "converge": false, 16 | "noAssert": false 17 | } 18 | }, 19 | "options": {} 20 | } -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/7/iwasm/assembly/index.ts: -------------------------------------------------------------------------------- 1 | export function isPrimeWasm(x: u32): bool { 2 | if (x < 2) { 3 | return false; 4 | } 5 | 6 | for (let i: u32 = 2; i < x; i++) { 7 | if (x % i === 0) { 8 | return false; 9 | } 10 | } 11 | 12 | return true; 13 | } 14 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/7/iwasm/assembly/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "assemblyscript/std/assembly.json", 3 | "include": [ 4 | "./**/*.ts" 5 | ] 6 | } -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/7/iwasm/build/.gitignore: -------------------------------------------------------------------------------- 1 | *.wasm 2 | *.wasm.map 3 | *.asm.js 4 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/7/iwasm/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/7/iwasm/index.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const loader = require("@assemblyscript/loader"); 3 | const imports = { /* imports go here */ }; 4 | const wasmModule = loader.instantiateSync(fs.readFileSync(__dirname + "/build/optimized.wasm"), imports); 5 | module.exports = wasmModule.exports; 6 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/7/iwasm/js/loader.js: -------------------------------------------------------------------------------- 1 | class WasmLoader { 2 | constructor() { 3 | this._imports = { 4 | env: { 5 | abort() { 6 | throw new Error('Abort called from wasm file'); 7 | } 8 | }, 9 | index: { 10 | log(n) { 11 | console.log(n); 12 | } 13 | } 14 | }; 15 | } 16 | 17 | async wasm(path, imports = this._imports) { 18 | console.log(`fetching ${path}`); 19 | 20 | if (!loader.instantiateStreaming) { 21 | return this.wasmFallback(path, imports); 22 | } 23 | 24 | const instance = await loader.instantiateStreaming(fetch(path), imports); 25 | 26 | return instance?.exports; 27 | } 28 | 29 | async wasmFallback(path, imports) { 30 | console.log('using fallback'); 31 | const response = await fetch(path); 32 | const bytes = await response?.arrayBuffer(); 33 | const instance = await loader.instantiate(bytes, imports); 34 | 35 | return instance?.exports; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/7/iwasm/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "requires": true, 3 | "lockfileVersion": 1, 4 | "dependencies": { 5 | "@assemblyscript/loader": { 6 | "version": "0.18.7", 7 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/@assemblyscript/loader/-/loader-0.18.7.tgz", 8 | "integrity": "sha1-o7r6YudH3cjXdUnFKIzXbql2xqA=" 9 | }, 10 | "accepts": { 11 | "version": "1.3.7", 12 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/accepts/-/accepts-1.3.7.tgz", 13 | "integrity": "sha1-UxvHJlF6OytB+FACHGzBXqq1B80=", 14 | "requires": { 15 | "mime-types": "~2.1.24", 16 | "negotiator": "0.6.2" 17 | } 18 | }, 19 | "array-flatten": { 20 | "version": "1.1.1", 21 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/array-flatten/-/array-flatten-1.1.1.tgz", 22 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 23 | }, 24 | "assemblyscript": { 25 | "version": "0.18.7", 26 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/assemblyscript/-/assemblyscript-0.18.7.tgz", 27 | "integrity": "sha1-tV9EKf82J88xL0c1Uht9xSQ5nMU=", 28 | "dev": true, 29 | "requires": { 30 | "binaryen": "98.0.0-nightly.20210106", 31 | "long": "^4.0.0" 32 | } 33 | }, 34 | "binaryen": { 35 | "version": "98.0.0-nightly.20210106", 36 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/binaryen/-/binaryen-98.0.0-nightly.20210106.tgz", 37 | "integrity": "sha1-x7xjfiIjqDvzyunZiWn1ae+rQGI=", 38 | "dev": true 39 | }, 40 | "body-parser": { 41 | "version": "1.19.0", 42 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/body-parser/-/body-parser-1.19.0.tgz", 43 | "integrity": "sha1-lrJwnlfJxOCab9Zqj9l5hE9p8Io=", 44 | "requires": { 45 | "bytes": "3.1.0", 46 | "content-type": "~1.0.4", 47 | "debug": "2.6.9", 48 | "depd": "~1.1.2", 49 | "http-errors": "1.7.2", 50 | "iconv-lite": "0.4.24", 51 | "on-finished": "~2.3.0", 52 | "qs": "6.7.0", 53 | "raw-body": "2.4.0", 54 | "type-is": "~1.6.17" 55 | } 56 | }, 57 | "bytes": { 58 | "version": "3.1.0", 59 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/bytes/-/bytes-3.1.0.tgz", 60 | "integrity": "sha1-9s95M6Ng4FiPqf3oVlHNx/gF0fY=" 61 | }, 62 | "content-disposition": { 63 | "version": "0.5.3", 64 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/content-disposition/-/content-disposition-0.5.3.tgz", 65 | "integrity": "sha1-4TDK9+cnkIfFYWwgB9BIVpiYT70=", 66 | "requires": { 67 | "safe-buffer": "5.1.2" 68 | } 69 | }, 70 | "content-type": { 71 | "version": "1.0.4", 72 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/content-type/-/content-type-1.0.4.tgz", 73 | "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=" 74 | }, 75 | "cookie": { 76 | "version": "0.4.0", 77 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/cookie/-/cookie-0.4.0.tgz", 78 | "integrity": "sha1-vrQ35wIrO21JAZ0IhmUwPr6cFLo=" 79 | }, 80 | "cookie-signature": { 81 | "version": "1.0.6", 82 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/cookie-signature/-/cookie-signature-1.0.6.tgz", 83 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 84 | }, 85 | "debug": { 86 | "version": "2.6.9", 87 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/debug/-/debug-2.6.9.tgz", 88 | "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", 89 | "requires": { 90 | "ms": "2.0.0" 91 | } 92 | }, 93 | "depd": { 94 | "version": "1.1.2", 95 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/depd/-/depd-1.1.2.tgz", 96 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 97 | }, 98 | "destroy": { 99 | "version": "1.0.4", 100 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/destroy/-/destroy-1.0.4.tgz", 101 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 102 | }, 103 | "ee-first": { 104 | "version": "1.1.1", 105 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/ee-first/-/ee-first-1.1.1.tgz", 106 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 107 | }, 108 | "encodeurl": { 109 | "version": "1.0.2", 110 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/encodeurl/-/encodeurl-1.0.2.tgz", 111 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 112 | }, 113 | "escape-html": { 114 | "version": "1.0.3", 115 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/escape-html/-/escape-html-1.0.3.tgz", 116 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 117 | }, 118 | "etag": { 119 | "version": "1.8.1", 120 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/etag/-/etag-1.8.1.tgz", 121 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 122 | }, 123 | "express": { 124 | "version": "4.17.1", 125 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/express/-/express-4.17.1.tgz", 126 | "integrity": "sha1-RJH8OGBc9R+GKdOcK10Cb5ikwTQ=", 127 | "requires": { 128 | "accepts": "~1.3.7", 129 | "array-flatten": "1.1.1", 130 | "body-parser": "1.19.0", 131 | "content-disposition": "0.5.3", 132 | "content-type": "~1.0.4", 133 | "cookie": "0.4.0", 134 | "cookie-signature": "1.0.6", 135 | "debug": "2.6.9", 136 | "depd": "~1.1.2", 137 | "encodeurl": "~1.0.2", 138 | "escape-html": "~1.0.3", 139 | "etag": "~1.8.1", 140 | "finalhandler": "~1.1.2", 141 | "fresh": "0.5.2", 142 | "merge-descriptors": "1.0.1", 143 | "methods": "~1.1.2", 144 | "on-finished": "~2.3.0", 145 | "parseurl": "~1.3.3", 146 | "path-to-regexp": "0.1.7", 147 | "proxy-addr": "~2.0.5", 148 | "qs": "6.7.0", 149 | "range-parser": "~1.2.1", 150 | "safe-buffer": "5.1.2", 151 | "send": "0.17.1", 152 | "serve-static": "1.14.1", 153 | "setprototypeof": "1.1.1", 154 | "statuses": "~1.5.0", 155 | "type-is": "~1.6.18", 156 | "utils-merge": "1.0.1", 157 | "vary": "~1.1.2" 158 | } 159 | }, 160 | "finalhandler": { 161 | "version": "1.1.2", 162 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/finalhandler/-/finalhandler-1.1.2.tgz", 163 | "integrity": "sha1-t+fQAP/RGTjQ/bBTUG9uur6fWH0=", 164 | "requires": { 165 | "debug": "2.6.9", 166 | "encodeurl": "~1.0.2", 167 | "escape-html": "~1.0.3", 168 | "on-finished": "~2.3.0", 169 | "parseurl": "~1.3.3", 170 | "statuses": "~1.5.0", 171 | "unpipe": "~1.0.0" 172 | } 173 | }, 174 | "forwarded": { 175 | "version": "0.1.2", 176 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/forwarded/-/forwarded-0.1.2.tgz", 177 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 178 | }, 179 | "fresh": { 180 | "version": "0.5.2", 181 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/fresh/-/fresh-0.5.2.tgz", 182 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 183 | }, 184 | "http-errors": { 185 | "version": "1.7.2", 186 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/http-errors/-/http-errors-1.7.2.tgz", 187 | "integrity": "sha1-T1ApzxMjnzEDblsuVSkrz7zIXI8=", 188 | "requires": { 189 | "depd": "~1.1.2", 190 | "inherits": "2.0.3", 191 | "setprototypeof": "1.1.1", 192 | "statuses": ">= 1.5.0 < 2", 193 | "toidentifier": "1.0.0" 194 | } 195 | }, 196 | "iconv-lite": { 197 | "version": "0.4.24", 198 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/iconv-lite/-/iconv-lite-0.4.24.tgz", 199 | "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=", 200 | "requires": { 201 | "safer-buffer": ">= 2.1.2 < 3" 202 | } 203 | }, 204 | "inherits": { 205 | "version": "2.0.3", 206 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/inherits/-/inherits-2.0.3.tgz", 207 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 208 | }, 209 | "ipaddr.js": { 210 | "version": "1.9.1", 211 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 212 | "integrity": "sha1-v/OFQ+64mEglB5/zoqjmy9RngbM=" 213 | }, 214 | "long": { 215 | "version": "4.0.0", 216 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/long/-/long-4.0.0.tgz", 217 | "integrity": "sha1-mntxz7fTYaGU6lVSQckvdGjVvyg=", 218 | "dev": true 219 | }, 220 | "media-typer": { 221 | "version": "0.3.0", 222 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/media-typer/-/media-typer-0.3.0.tgz", 223 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 224 | }, 225 | "merge-descriptors": { 226 | "version": "1.0.1", 227 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 228 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 229 | }, 230 | "methods": { 231 | "version": "1.1.2", 232 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/methods/-/methods-1.1.2.tgz", 233 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 234 | }, 235 | "mime": { 236 | "version": "1.6.0", 237 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/mime/-/mime-1.6.0.tgz", 238 | "integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE=" 239 | }, 240 | "mime-db": { 241 | "version": "1.45.0", 242 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/mime-db/-/mime-db-1.45.0.tgz", 243 | "integrity": "sha1-zO7aIczXw6dF66LezVXUtz54eeo=" 244 | }, 245 | "mime-types": { 246 | "version": "2.1.28", 247 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/mime-types/-/mime-types-2.1.28.tgz", 248 | "integrity": "sha1-EWDEdX6rLFNjiI4AUnPs950qDs0=", 249 | "requires": { 250 | "mime-db": "1.45.0" 251 | } 252 | }, 253 | "ms": { 254 | "version": "2.0.0", 255 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/ms/-/ms-2.0.0.tgz", 256 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 257 | }, 258 | "negotiator": { 259 | "version": "0.6.2", 260 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/negotiator/-/negotiator-0.6.2.tgz", 261 | "integrity": "sha1-/qz3zPUlp3rpY0Q2pkiD/+yjRvs=" 262 | }, 263 | "on-finished": { 264 | "version": "2.3.0", 265 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/on-finished/-/on-finished-2.3.0.tgz", 266 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 267 | "requires": { 268 | "ee-first": "1.1.1" 269 | } 270 | }, 271 | "parseurl": { 272 | "version": "1.3.3", 273 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/parseurl/-/parseurl-1.3.3.tgz", 274 | "integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ=" 275 | }, 276 | "path-to-regexp": { 277 | "version": "0.1.7", 278 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 279 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 280 | }, 281 | "proxy-addr": { 282 | "version": "2.0.6", 283 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/proxy-addr/-/proxy-addr-2.0.6.tgz", 284 | "integrity": "sha1-/cIzZQVEfT8vLGOO0nLK9hS7sr8=", 285 | "requires": { 286 | "forwarded": "~0.1.2", 287 | "ipaddr.js": "1.9.1" 288 | } 289 | }, 290 | "qs": { 291 | "version": "6.7.0", 292 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/qs/-/qs-6.7.0.tgz", 293 | "integrity": "sha1-QdwaAV49WB8WIXdr4xr7KHapsbw=" 294 | }, 295 | "range-parser": { 296 | "version": "1.2.1", 297 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/range-parser/-/range-parser-1.2.1.tgz", 298 | "integrity": "sha1-PPNwI9GZ4cJNGlW4SADC8+ZGgDE=" 299 | }, 300 | "raw-body": { 301 | "version": "2.4.0", 302 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/raw-body/-/raw-body-2.4.0.tgz", 303 | "integrity": "sha1-oc5vucm8NWylLoklarWQWeE9AzI=", 304 | "requires": { 305 | "bytes": "3.1.0", 306 | "http-errors": "1.7.2", 307 | "iconv-lite": "0.4.24", 308 | "unpipe": "1.0.0" 309 | } 310 | }, 311 | "safe-buffer": { 312 | "version": "5.1.2", 313 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/safe-buffer/-/safe-buffer-5.1.2.tgz", 314 | "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" 315 | }, 316 | "safer-buffer": { 317 | "version": "2.1.2", 318 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/safer-buffer/-/safer-buffer-2.1.2.tgz", 319 | "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=" 320 | }, 321 | "send": { 322 | "version": "0.17.1", 323 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/send/-/send-0.17.1.tgz", 324 | "integrity": "sha1-wdiwWfeQD3Rm3Uk4vcROEd2zdsg=", 325 | "requires": { 326 | "debug": "2.6.9", 327 | "depd": "~1.1.2", 328 | "destroy": "~1.0.4", 329 | "encodeurl": "~1.0.2", 330 | "escape-html": "~1.0.3", 331 | "etag": "~1.8.1", 332 | "fresh": "0.5.2", 333 | "http-errors": "~1.7.2", 334 | "mime": "1.6.0", 335 | "ms": "2.1.1", 336 | "on-finished": "~2.3.0", 337 | "range-parser": "~1.2.1", 338 | "statuses": "~1.5.0" 339 | }, 340 | "dependencies": { 341 | "ms": { 342 | "version": "2.1.1", 343 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/ms/-/ms-2.1.1.tgz", 344 | "integrity": "sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo=" 345 | } 346 | } 347 | }, 348 | "serve-static": { 349 | "version": "1.14.1", 350 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/serve-static/-/serve-static-1.14.1.tgz", 351 | "integrity": "sha1-Zm5jbcTwEPfvKZcKiKZ0MgiYsvk=", 352 | "requires": { 353 | "encodeurl": "~1.0.2", 354 | "escape-html": "~1.0.3", 355 | "parseurl": "~1.3.3", 356 | "send": "0.17.1" 357 | } 358 | }, 359 | "setprototypeof": { 360 | "version": "1.1.1", 361 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/setprototypeof/-/setprototypeof-1.1.1.tgz", 362 | "integrity": "sha1-fpWsskqpL1iF4KvvW6ExMw1K5oM=" 363 | }, 364 | "statuses": { 365 | "version": "1.5.0", 366 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/statuses/-/statuses-1.5.0.tgz", 367 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 368 | }, 369 | "toidentifier": { 370 | "version": "1.0.0", 371 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/toidentifier/-/toidentifier-1.0.0.tgz", 372 | "integrity": "sha1-fhvjRw8ed5SLxD2Uo8j013UrpVM=" 373 | }, 374 | "type-is": { 375 | "version": "1.6.18", 376 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/type-is/-/type-is-1.6.18.tgz", 377 | "integrity": "sha1-TlUs0F3wlGfcvE73Od6J8s83wTE=", 378 | "requires": { 379 | "media-typer": "0.3.0", 380 | "mime-types": "~2.1.24" 381 | } 382 | }, 383 | "unpipe": { 384 | "version": "1.0.0", 385 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/unpipe/-/unpipe-1.0.0.tgz", 386 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 387 | }, 388 | "utils-merge": { 389 | "version": "1.0.1", 390 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/utils-merge/-/utils-merge-1.0.1.tgz", 391 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 392 | }, 393 | "vary": { 394 | "version": "1.1.2", 395 | "resolved": "https://artifacts.netflix.com/api/npm/npm-netflix/vary/-/vary-1.1.2.tgz", 396 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 397 | } 398 | } 399 | } 400 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/7/iwasm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "asbuild:untouched": "asc assembly/index.ts --target debug --exportRuntime", 4 | "asbuild:optimized": "asc assembly/index.ts --target release --exportRuntime", 5 | "asbuild": "npm run asbuild:untouched && npm run asbuild:optimized", 6 | "test": "node tests", 7 | "server": "node server.js" 8 | }, 9 | "dependencies": { 10 | "@assemblyscript/loader": "^0.18.7", 11 | "express": "^4.17.1" 12 | }, 13 | "devDependencies": { 14 | "assemblyscript": "^0.18.7" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/7/iwasm/server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express(); 3 | 4 | app.use(express.static('./')) 5 | 6 | app.listen(3000, () => console.log('Server up on port 3000!')); 7 | -------------------------------------------------------------------------------- /lessons/assembly-script/exercises/7/iwasm/tests/index.js: -------------------------------------------------------------------------------- 1 | const assert = require("assert"); 2 | const myModule = require(".."); 3 | assert.equal(myModule.minusOne(2), 1); 4 | console.log("ok"); 5 | -------------------------------------------------------------------------------- /lessons/assembly-script/images/as.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/young/intro-to-web-assembly/ce655c73cc207412155090f9ea9a0989ede6684a/lessons/assembly-script/images/as.png -------------------------------------------------------------------------------- /lessons/assembly-script/images/memory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/young/intro-to-web-assembly/ce655c73cc207412155090f9ea9a0989ede6684a/lessons/assembly-script/images/memory.png -------------------------------------------------------------------------------- /lessons/assembly-script/imports.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/assembly-script/imports" 3 | section: "AssemblyScript" 4 | order: "3G" 5 | title: "Imports" 6 | description: "" 7 | --- 8 | ###### [Working repo](https://github.com/young/intro-to-web-assembly/tree/main/lessons/assembly-script/exercises/3/iwasm) 9 | 10 | Just as we can export wasm functions, we can import JS functions into our code. One useful import is the `abort()` function which we call if we want terminate execution of wasm a function. 11 | 12 | Call `abort()` if the function input is 44. 13 | ```js 14 | // assembly/index.ts 15 | export function minusOne(n: i32): i32 { 16 | 17 | if (n == 44) { 18 | abort(); 19 | } 20 | 21 | return n - 1; 22 | } 23 | ``` 24 | Compile our wasm 25 | ```bash 26 | $ npm run asbuild 27 | ``` 28 | 29 | Loading the browser we see an error: 30 | `Imports argument must be present and must be an object` 31 | 32 | This is because `abort()` isn't currently defined in the context of our wasm yet. The import object is defined in the second argument of `instantiateStreaming()` and `instantiate()`. 33 | 34 | 35 | Create an import object with an `abort()` function. 36 | 37 | ```js 38 | // js/loader.js 39 | constructor() { 40 | this._imports = { 41 | env: { 42 | abort() { 43 | throw new Error('Abort called from wasm file'); 44 | } 45 | } 46 | }; 47 | } 48 | } 49 | ``` 50 | 51 | Add the import object to both methods 52 | ```js 53 | // js/loader.js 54 | async wasm(path, imports = this._imports) { 55 | console.log(`fetching ${path}`); 56 | 57 | if (!WebAssembly.instantiateStreaming) { 58 | return this.wasmFallback(path, imports); 59 | } 60 | 61 | const { instance } = await WebAssembly.instantiateStreaming(fetch(path), imports); 62 | 63 | return instance?.exports; 64 | } 65 | 66 | async wasmFallback(path, imports) { 67 | console.log('using fallback'); 68 | const response = await fetch(path); 69 | const bytes = await response?.arrayBuffer(); 70 | const { instance } = await WebAssembly.instantiate(bytes, imports); 71 | 72 | return instance?.exports; 73 | } 74 | ``` 75 | Loading the page now throws an exception. Remove the `abort()` call for now and rebuild the wasm code. 76 | 77 | #### Defining imports 78 | ###### [Working repo](https://github.com/young/intro-to-web-assembly/tree/main/lessons/assembly-script/exercises/3/iwasm) 79 | 80 | AssemblyScript has several [imports built into its loader](https://www.assemblyscript.org/exports-and-imports.html#imports-2) (which we'll cover a bit later) so we didn't have to manually declare `abort()`. For other JavaScript functions imported into AssemblyScript we need to define them before they can be imported. 81 | 82 | To define a custom import in AssemblyScript we declare it's function signature. Here we're defining a log function that will allow us to call `console.log()` from Web Assembly code. 83 | 84 | ```js 85 | // assembly/index.ts 86 | declare function log(n: i32): void 87 | 88 | export function minusOne(n: i32): i32 { 89 | log(n); 90 | return n - 1; 91 | } 92 | ``` 93 | 94 | Add the function to the import object. 95 | ```js 96 | // js/loader.js 97 | constructor() { 98 | this._imports = { 99 | env: { 100 | abort() { 101 | throw new Error('Abort called from wasm file'); 102 | } 103 | }, 104 | index: { 105 | log(n) { 106 | console.log(n); 107 | } 108 | } 109 | }; 110 | } 111 | ``` 112 | -------------------------------------------------------------------------------- /lessons/assembly-script/js-vs-wasm.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/assembly-script/jsvwasm" 3 | section: "AssemblyScript" 4 | order: "3K" 5 | title: "JS vs Wasm" 6 | description: "" 7 | 8 | --- 9 | 10 | 11 | ###### [Working repo](https://github.com/young/intro-to-web-assembly/tree/main/lessons/assembly-script/exercises/7/iwasm) 12 | Let's do simple experiment to see which is faster: JavaScript or Web Assembly? 13 | 14 | > prime function from this excellent [logrocket post](https://blog.logrocket.com/the-introductory-guide-to-assemblyscript/) 15 | 16 | ```js 17 | export function isPrimeWasm(x: u32): bool { 18 | if (x < 2) { 19 | return false; 20 | } 21 | 22 | for (let i: u32 = 2; i < x; i++) { 23 | if (x % i === 0) { 24 | return false; 25 | } 26 | } 27 | 28 | return true; 29 | } 30 | ``` 31 | 32 | ```html 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 96 | 97 | 98 | 99 | ``` 100 | 101 | So which is faster? 102 | -------------------------------------------------------------------------------- /lessons/assembly-script/loader.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/assembly-script/loader" 3 | section: "AssemblyScript" 4 | order: "3H" 5 | title: "AssemblyScript Loader" 6 | description: "" 7 | 8 | --- 9 | 10 | ###### [Working repo](https://github.com/young/intro-to-web-assembly/tree/main/lessons/assembly-script/exercises/5/iwasm) 11 | 12 | 13 | #### Exercise 14 | 15 | Implement fizzbuzz in AssemblyScript. 16 | 17 | Hint: 18 | 19 | ``` 20 | if (number is divisible by 15) then 21 | "fizzbuzz" 22 | if (number is divisible by 3) then 23 | "fizz" 24 | if (number is divisible by 5) then 25 | "buzz" 26 | ``` 27 | 28 |
29 | Solution 30 | 31 | ```js 32 | // assembly/index.ts 33 | export function fizzbuzz(n: i32): String | null { 34 | if (n % 15 === 0) { 35 | return 'fizzbuzz'; 36 | } 37 | 38 | if (n % 3 === 0) { 39 | return 'fizz'; 40 | } 41 | 42 | if (n % 5 === 0) { 43 | return 'buzz'; 44 | } 45 | 46 | return null; 47 | } 48 | ``` 49 |
50 | 51 | #### Strings 52 | Update `index.html` to call `fizzbuzz()` 53 | ```html 54 | // index.html 55 | 64 | ``` 65 | 66 | Running `fizzbuzz(3)` outputs a number and not a string. Remember that Web Assembly only deals in numbers so AssemblyScript allocates space for the strings (see: untouched.wat) and passes them into memory. The number being returned is a pointer to the memory address of the string being returned. Fortunately AssemblyScript includes a [loader](https://www.assemblyscript.org/loader.html#loader) that lets us allocate and read from memory. 67 | 68 | 69 | Let's import the loader into the page: 70 | ```html 71 | // index.html 72 | 73 | ``` 74 | 75 | 76 | In `loader.js` file, replace the `WebAssembly` method calls with `loader`. 77 | 78 | 79 | ```js 80 | // js/loader.js 81 | class WasmLoader { 82 | constructor() {...} 83 | 84 | async wasm(path, imports = this._imports) { 85 | console.log(`fetching ${path}`); 86 | 87 | if (!loader.instantiateStreaming) { 88 | return this.wasmFallback(path, imports); 89 | } 90 | 91 | const { instance } = await loader.instantiateStreaming(fetch(path), imports); 92 | 93 | return instance?.exports; 94 | } 95 | 96 | async wasmFallback(path, imports) { 97 | console.log('using fallback'); 98 | const response = await fetch(path); 99 | const bytes = await response?.arrayBuffer(); 100 | const { instance } = await loader.instantiate(bytes, imports); 101 | 102 | return instance?.exports; 103 | } 104 | } 105 | ``` 106 | 107 | The AssemblyScript loader will require internal glue code to be sent with our wasm. Adding the `--exportRuntime` flag will compile our wasm with these helper functions. 108 | 109 | ```js 110 | // package.json 111 | "asbuild:untouched": "asc assembly/index.ts --target debug --exportRuntime", 112 | "asbuild:optimized": "asc assembly/index.ts --target release --exportRuntime" 113 | ``` 114 | -------------------------------------------------------------------------------- /lessons/assembly-script/loading-browser.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/assembly-script/loading-browser" 3 | section: "AssemblyScript" 4 | order: "3F" 5 | title: "Loading AssemblyScript - Browser" 6 | description: "" 7 | --- 8 | ###### [Working repo](https://github.com/young/intro-to-web-assembly/tree/main/lessons/assembly-script/exercises/2/iwasm) 9 | 10 | Now we get to the good stuff: using our Web Assembly in the browser just as nature intended. 11 | 12 | All modern browsers have the `WebAssembly` global object that acts the primary API into Web Assembly. `WebAssembly` has five static methods: 13 | 14 | - `WebAssembly.compile()` - Compile wasm 15 | - `WebAssembly.compileStreaming()` - Compile wasm from a streamed source 16 | - `WebAssembly.instantiate()` - Compile and instantiate wasm 17 | - `WebAssembly.instantiateStreaming()` - Compile and instantiate wasm from a streamed source 18 | - `WebAssembly.validate()` - Checks if wasm code is valid 19 | 20 | 21 | #### Fetching wasm 22 | We're fetching wasm from our server so let's use `instantiate()` and `instantiateStreaming()` to make a utility class for fetching and compiling our wasm. 23 | 24 | ```js 25 | // js/loader.js 26 | 27 | class WasmLoader { 28 | constructor(){} 29 | 30 | async wasm(path){} 31 | 32 | async wasmFallback(path){} 33 | } 34 | ``` 35 | 36 | Our `wasm()` method takes a path to the wasm file and will return the exported wasm functions. The `wasmFallback()` method is for browsers that don't support `instantiateStreaming()`. 37 | 38 | ```js 39 | // js/loader.js 40 | 41 | class WasmLoader { 42 | constructor(){} 43 | 44 | async wasm(path) { 45 | console.log(`fetching ${path}`); 46 | 47 | if (!WebAssembly.instantiateStreaming) { 48 | return this.wasmFallback(path); 49 | } 50 | 51 | const { instance } = await WebAssembly.instantiateStreaming(fetch(path)); 52 | 53 | return instance?.exports; 54 | } 55 | 56 | async wasmFallback(path){} 57 | } 58 | ``` 59 | 60 | `wasmFallback()` works the same as `wasm()` with the exeception that we need to create an intermediate array buffer before instantiating our module. 61 | 62 | ```js 63 | // js/loader.js 64 | 65 | class WasmLoader { 66 | constructor(){} 67 | 68 | async wasm(path) { 69 | console.log(`fetching ${path}`); 70 | 71 | if (!WebAssembly.instantiateStreaming) { 72 | return this.wasmFallback(path); 73 | } 74 | 75 | const { instance } = await WebAssembly.instantiateStreaming(fetch(path)); 76 | 77 | return instance?.exports; 78 | } 79 | 80 | async wasmFallback(path){ 81 | console.log('using fallback'); 82 | const response = await fetch(path); 83 | const bytes = await response?.arrayBuffer(); 84 | const { instance } = await WebAssembly.instantiate(bytes); 85 | 86 | return instance?.exports; 87 | } 88 | } 89 | ``` 90 | #### Creating a server 91 | 92 | `instantiateStreaming()` requires the wasm being fetched to have an `Content-Type: application/wasm` response header. Fortunately, [Express](https://expressjs.com/) will automatically add this header when serving requests for wasm files. 93 | 94 | Install Express 95 | ```bash 96 | $ npm i express --save 97 | ``` 98 | 99 | Create a simple server 100 | ```js 101 | // server.js 102 | const express = require('express'); 103 | const app = express(); 104 | // Serve static files from root (note: do not this in production code) 105 | app.use(express.static('./')) 106 | 107 | app.listen(3000, () => console.log('Server up on port 3000!')); 108 | ``` 109 | Add a run script to start the server 110 | ```js 111 | // package.json 112 | "server": "node server.js" 113 | ``` 114 | 115 | #### Loading in the browser 116 | 117 | Let's import our `WasmLoader` and use it to access our `minusone()` function. 118 | 119 | ```html 120 | 121 | 122 | 123 | 124 |
125 | 126 | 135 | 136 | 137 | ``` 138 | 139 | Navigate to `localhost:3000` and you will see _43_ on the page. Congratulations! We've written Web Assembly, loaded and compiled the module, and executed a wasm function 🎉. Now that we understand how to _export_ and run wasm functions in JavaScript, let's learn how to _import_ JS functions into Web Assembly. 140 | -------------------------------------------------------------------------------- /lessons/assembly-script/loading-node.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/assembly-script/loading-node" 3 | section: "AssemblyScript" 4 | order: "3E" 5 | title: "Loading AssemblyScript - NodeJS" 6 | description: "" 7 | --- 8 | AssemblyScript automatically loads and imports your built wasm files into `index.js`. 9 | 10 | ```js 11 | // index.js 12 | const fs = require("fs"); 13 | const loader = require("@assemblyscript/loader"); 14 | const imports = { /* imports go here */ }; 15 | const wasmModule = loader.instantiateSync(fs.readFileSync(__dirname + "/build/optimized.wasm"), imports); 16 | module.exports = wasmModule.exports; 17 | ``` 18 | 19 | 20 | To run our compiled module we require `index.js` and call our exported wasm function. 21 | 22 | 23 | ```bash 24 | $ node 25 | ``` 26 | 27 | ```js 28 | > const { minusOne } = require('./index.js'); 29 | > minusOne(2); 30 | // 1 31 | ``` 32 | -------------------------------------------------------------------------------- /lessons/assembly-script/memory.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/assembly-script/memory" 3 | section: "AssemblyScript" 4 | order: "3J" 5 | title: "Memory" 6 | description: "" 7 | 8 | --- 9 | ![memory as ones and zeros](./images/memory.png) 10 | 11 | Memory in Web Assembly is linear. The easiest way to visualize it is to think of a long unbroken chain of 0's and 1's. When we instantiate a wasm module, a fixed portion of memory is allocated to the process and all data passed between wasm and JavaScript takes place in this fixed portion of space. This contrasts with JavaScript memory which utilizes both a stack and heap. 12 | 13 | > A heap is dynamic, non-linear memory used by a program to arbitrarily read and store data. 14 | 15 | #### ArrayBuffers 16 | 17 | Naturally we need a way to read and write to this fixed memory space. Other languages have pointers, addresses to specifc locations in memory, whereas in JavaScript we have to use an `ArrayBuffer` object. An `ArrayBuffer` is an object that represents raw binary data. A `SharedArrayBuffer` is an ArrayBuffer that represents a fixed-length portion of memory that can be shared by multiple processes. `WebAssembly.Memory` is the name of the memory shared by JavaScript and WebAssembly that is used to pass data back and forth. 18 | 19 | Because `ArrayBuffer` `SharedArrayBuffer` are merely representations of raw binary data, we need to use a `TypedArray` to properly coerce the raw data into something useable by our processes. 20 | 21 | #### Memory and TypedArrays 22 | 23 | Create an ArrayBuffer and allocate 1 page (64Kb) of memory 24 | ```js 25 | const memory = new WebAssembly.Memory({ initial: 1, shared: true }); 26 | ``` 27 | 28 | Create an array-like object where each index is a pointer to a 16-bit unsigned integer 29 | ```js 30 | const u16Array = new Uint16Array(memory.buffer); 31 | ``` 32 | 33 | We can now directly write into memory and the number 42 will be accessible by both JavaScript and Web Assembly 34 | ```js 35 | u16Array[0] = 42; 36 | ``` 37 | 38 | #### Memory in AssemblyScript 39 | ###### [Working repo](https://github.com/young/intro-to-web-assembly/tree/main/lessons/assembly-script/exercises/6/iwasm) 40 | 41 | ```js 42 | // assembly/index.ts 43 | // Grow memory by 2 pages (128Kb) 44 | memory.grow(2); 45 | // Save 21 at index 0 46 | store(0, 21); 47 | // Save 99 at index 1 48 | store(1, 99); 49 | 50 | export function readMemory(n: i32): i32 { 51 | return load(n); 52 | } 53 | ``` 54 | 55 | 56 | ```js 57 | // index.html 58 | const { readMemory, memory } = instance; 59 | 60 | const memoryArray = new Uint8Array(memory.buffer); 61 | // Read from memory at index 1 62 | // Returns 99 63 | document.write(memoryArray[1]); 64 | document.write('
'); 65 | // Write to memory at index 2 66 | memoryArray[2] = 42; 67 | // Returns 42 68 | document.write(readMemory(2)); 69 | ``` 70 | -------------------------------------------------------------------------------- /lessons/assembly-script/setup.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/assembly-script/setup" 3 | section: "AssemblyScript" 4 | order: "3C" 5 | title: "AssemblyScript Setup" 6 | description: "" 7 | --- 8 | 9 | ###### [Working repo](https://github.com/young/intro-to-web-assembly/tree/main/lessons/assembly-script/exercises/1/iwasm) 10 | 11 | Let's get our environment set up. 12 | 13 | 14 | 15 | #### Setup 16 | 17 | Make sure we’re on latest version of node 18 | > We need to be version 14 or above. 19 | 20 | ```bash 21 | $ nvm install --lts 22 | ``` 23 | 24 | Install npx 25 | ```bash 26 | $ npm i -g npx 27 | ``` 28 | 29 | Create working directory 30 | ```bash 31 | $ mkdir iwasm && cd iwasm 32 | ``` 33 | 34 | Install the loader 35 | ```bash 36 | $ npm i --save @assemblyscript/loader 37 | ``` 38 | 39 | Install AssemblyScript 40 | ```bash 41 | $ npm i --save-dev assemblyscript 42 | ``` 43 | 44 | 45 | Scaffold and build an empty project 46 | ```bash 47 | $ npx asinit . 48 | $ npm run asbuild 49 | ``` 50 | 51 | ##### Note 52 | We're following the official AssemblyScript [quick start guide](https://www.assemblyscript.org/quick-start.html) 53 | -------------------------------------------------------------------------------- /lessons/assembly-script/using-loader.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/assembly-script/loader-usage" 3 | section: "AssemblyScript" 4 | order: "3I" 5 | title: "Using the AssemblyScript loader" 6 | description: "" 7 | 8 | --- 9 | ###### [Working repo](https://github.com/young/intro-to-web-assembly/tree/main/lessons/assembly-script/exercises/5/iwasm) 10 | 11 | Using the loader to fetch and instantiate our wasm lets us access some useful utility functions but we need to update our `WasmLoader` class to export them. 12 | 13 | ```js 14 | // js/loader.js 15 | // WasmLoader::wasm() 16 | const instance = await loader.instantiateStreaming(fetch(path), imports); 17 | return instance; 18 | ``` 19 | 20 | ```js 21 | // WasmLoader::wasmFallback() 22 | const instance = await loader.instantiate(bytes, imports); 23 | ``` 24 | 25 | The instance methods include our exported wasm functions along with AssemblyScript utilities. We're reading a string from memory so we're going to use [__getString()](https://www.assemblyscript.org/loader.html#module-instance-utility). 26 | 27 | ```js 28 | // index.html 29 | const { fizzbuzz, __getString } = instance; 30 | const str = __getString(fizzbuzz(3)); 31 | document.write(str); 32 | ``` 33 | 34 | ### BONUS 35 | 36 | Let's check out the source code of `__getString` 37 | 38 | ```js 39 | // Take a pointer as only argument 40 | function __getString(ptr) { 41 | ``` 42 | ```js 43 | // Return null if there's no pointer 44 | if (!ptr) return null; 45 | ``` 46 | ```js 47 | // Get reference to wasm memory 48 | const buffer = memory.buffer; 49 | ``` 50 | ```js 51 | // Load wasm memory buffer into a 32 bit unsigned integer array 52 | const id = new Uint32Array(buffer) 53 | ``` 54 | ```js 55 | // The memory location of the string is at pointer + the runtime header offset 56 | // The location is then zero fill right shifted 57 | [ptr + ID_OFFSET >>> 2]; 58 | ``` 59 | 60 | ```js 61 | /** Reads a string from the module's memory by its pointer. */ 62 | function __getString(ptr) { 63 | if (!ptr) return null; 64 | const buffer = memory.buffer; 65 | const id = new Uint32Array(buffer)[ptr + ID_OFFSET >>> 2]; 66 | if (id !== STRING_ID) throw Error(`not a string: ${ptr}`); 67 | return getStringImpl(buffer, ptr); 68 | } 69 | ``` 70 | -------------------------------------------------------------------------------- /lessons/assembly-script/writing.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/assembly-script/writing" 3 | section: "AssemblyScript" 4 | order: "3D" 5 | title: "Writing AssemblyScript" 6 | description: "" 7 | --- 8 | ###### [Working repo](https://github.com/young/intro-to-web-assembly/tree/main/lessons/assembly-script/exercises/1/iwasm) 9 | 10 | Let's start off with our minusOne example. 11 | 12 | ```js 13 | export function minusOne(n) { 14 | return n - 1; 15 | } 16 | ``` 17 | 18 | 19 | Converting this function to AssemblyScript is straightforward. We just need to add types for the function argument and return value. AssemblyScript automatically looks in the `/assembly` directory for files to compile. 20 | 21 | ```js 22 | // /assembly/index.ts 23 | export function minusOne(n: i32): i32 { 24 | return n - 1; 25 | } 26 | ``` 27 | 28 | Let's convert our AssemblyScript to Web Assembly. The converted files are located in `/build/`. 29 | 30 | ```bash 31 | npm run asbuild 32 | ``` 33 | -------------------------------------------------------------------------------- /lessons/closing.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/closing" 3 | title: "In closing" 4 | order: "5A" 5 | section: "Conclusion" 6 | description: "Introduction to Web Assembly by Jem Young" 7 | --- 8 | We did it! We've written Web Assembly, AssemblyScript, and learned how it all works together. The next step is to deep dive and make more complex, beautiful creations using wasm. Go forth and build! 9 | 10 | #### Issues/Comments/Corrections 11 | See a spelling/grammar mistake or feel that information is missing? [File an issue](https://github.com/young/intro-to-web-assembly/issues) and pull requests are always welcome. 12 | 13 | 14 | #### Further resources 15 | - [Wasi](https://wasi.dev/) - WebAssembly System Interface. A common API to operating-system-like features. 16 | - [Made with Web Assembly](https://madewithwebassembly.com/) - An open source showcase of awesome production applications, side projects, and use cases made with WebAssembly. 17 | - [ASBind](https://github.com/torch2424/as-bind) - Library to handle passing high-level data structures between AssemblyScript and JavaScript 18 | - [Binaryen](https://github.com/WebAssembly/binaryen) - Binaryen is a compiler and toolchain infrastructure library for WebAssembly. 19 | - [Emscripten](https://emscripten.org/) - A complete compiler toolchain to WebAssembly. 20 | - [Built With AssemblyScript](https://www.assemblyscript.org/built-with-assemblyscript.html#built-with-assemblyscript) - A collection of AssemblyScript projects 21 | - [Interference AssemblyScript](https://www.assemblyscript.org/examples/interference.html#example) - Advanced example of using AssemblyScript 22 | 23 | 24 | #### Thanks 25 | Special thanks to [Brian Holt](https://twitter.com/holtbt) for creating this course starter kit. 26 | 27 | The **entire** team at Frontend Masters. They make producing content painless and I'm eternally grateful for all their work. 28 | 29 | [Luna Yu](https://twitter.com/lunaceee) and [Justine Benoit](https://twitter.com/justinechlorine) for helping with site design. 30 | 31 | And of course my wife and son who put up with my rants about CPU instructions and Fast and Furious trivia. 32 | -------------------------------------------------------------------------------- /lessons/images/course.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/young/intro-to-web-assembly/ce655c73cc207412155090f9ea9a0989ede6684a/lessons/images/course.png -------------------------------------------------------------------------------- /lessons/images/lasercat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/young/intro-to-web-assembly/ce655c73cc207412155090f9ea9a0989ede6684a/lessons/images/lasercat.png -------------------------------------------------------------------------------- /lessons/images/lowhigh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/young/intro-to-web-assembly/ce655c73cc207412155090f9ea9a0989ede6684a/lessons/images/lowhigh.png -------------------------------------------------------------------------------- /lessons/images/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/young/intro-to-web-assembly/ce655c73cc207412155090f9ea9a0989ede6684a/lessons/images/title.png -------------------------------------------------------------------------------- /lessons/intro-to-wasm.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/intro-to-wasm" 3 | title: "Introduction to Web Assembly" 4 | order: "0B" 5 | section: "Introduction" 6 | description: "Introduction to Web Assembly by Jem Young" 7 | --- 8 | ![low to high](./images/lowhigh.png) 9 | 10 | ## Why web assembly 11 | With the rise of the internet almost every personal computer has a web browser and with it, a powerful standardized platform which Frontend Engineers use to build and create using JavaScript, HTML, and CSS. Over the past few years, non-frontend engineers have increasingly wanted to utilize the browser to build and create but were limited because to work on the frontend you have to know JavaScript. 12 | 13 | Web Assembly bridges that gap and allows languages like C and Rust to be compiled into a language that the browser understands and works in _tandem_ with JavaScript. 14 | 15 | -- Runs at near native speed\ 16 | -- Is memory safe\ 17 | -- Designed to run on many platforms, not just the browser 18 | -------------------------------------------------------------------------------- /lessons/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/intro" 3 | title: "Hello" 4 | order: "0A" 5 | section: "Introduction" 6 | description: "Introduction to Web Assembly by Jem Young" 7 | --- 8 | 9 | ![jem and his laser cat](./images/lasercat.png) 10 | 11 | Hello! My name is Jem Young and I'm very excited to go on a journey with you with Introduction to Web Assembly. By the day I'm a Senior Software Engineer at [Netflix](https://www.netflix.com) where I work on growth infrastructure. At night I'm a father, husband, co-host on the [Frontend Happy Hour](https://frontendhappyhour.com/) podcast, instructor on [Frontend Masters](https://frontendmasters.com/teachers/jem-young/) and in my "free time" I really enjoy [giving talks](https://www.youtube.com/watch?v=qouPzSryggk) on engineering and code. 12 | 13 | 14 | [Twitter: @jemyoung](https://twitter.com/jemyoung) 15 | 16 | [LinkedIn](https://www.linkedin.com/in/jemyoung/) 17 | 18 | 19 | ### Other courses on Frontend Masters 20 | [Fullstack for Frontend](https://frontendmasters.com/courses/fullstack-v2/) 21 | 22 | [Interviewing for Front-End Engineers](https://frontendmasters.com/courses/interviewing-frontend/) 23 | -------------------------------------------------------------------------------- /lessons/low-level/binary-contd.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/low-level/binary-contd" 3 | title: "Binary continued" 4 | order: "1C" 5 | description: "" 6 | section: "Low Level Stuff" 7 | --- 8 | 9 | A bit (binary digit) is the smallest unit of information in computing. 10 | ![two bits](./images/bit.png) 11 | 12 | 13 | A group of of 8 bits is called a byte. 14 | ![a byte](./images/byte.png) 15 | 16 | Using only 1 and 0 means that we use a Base 2 (**bi**nary) counting system in computing. That is, in any given position there are only two options: 0 or 1. Compare this with our everyday Base 10 (**deci**mal) system where any given position can be 0-9. 17 | 18 | 19 | #### Counting 20 | In Base 2,\ 21 | 20 = 1,\ 22 | 21 = 2,\ 23 | 22 = 4... 24 | ![counting](./images/counting.png) 25 | 26 | `00000001` = 1\ 27 | `00000011` = 3\ 28 | `10100001` = 161 29 | 30 | #### Endianness 31 | When computers interpret instructions they need to know the byte order known as endianness. When the leftmost bit represents the largest value this is known as _little endian_. When the rightmost bit is the largest value is known as _big endian_. 32 | 33 | ![endian](./images/endian.png) 34 | 35 | Web Assembly reads and writes instructions in [little endian](https://webassembly.github.io/spec/core/syntax/instructions.html#memory-instructions) byte order. 36 | -------------------------------------------------------------------------------- /lessons/low-level/binary.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/low-level/binary" 3 | title: "Binary" 4 | order: "1B" 5 | description: "" 6 | section: "Low Level Stuff" 7 | --- 8 | 9 | In the beginning... 10 | 11 | ![zero and one](./images/0and1.png) 12 | 13 | Computers only have the concept of one and zero, on or off. Everything else we can do with computers is merely manipulating ones and zeroes. 14 | 15 | (unless we're talking about quantum computing where a one and zero can exist at the same time 🤯 ) 16 | -------------------------------------------------------------------------------- /lessons/low-level/hex.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/low-level/hex" 3 | title: "Hexadecimal" 4 | order: "1D" 5 | description: "" 6 | section: "Low Level Stuff" 7 | --- 8 | 9 | The phrase _machine code_ is often used when describing low-level programming and it conjours images of engineers reading pages of ones and zeroes. In reality, most humans would be unable to follow endless blocks of ones and zeroes thus _hexadecimal_ serves as an intermediate step: concise enough for machines but readable enough for humans and is the lowest level programming language. 10 | 11 | > Note: I don't expect you to memorize how to read hexadecimal. This is more of an FYI because Web Assembly error and opcodes are often presented in hex. 12 | 13 | Hexadecimal uses Base 16 for calculating byte values and the letters A through F represent the numbers 10 through 15 respectively. 14 | 15 | | Decimal | Hexadecimal | 16 | | ----------- | ----------- | 17 | | 0 | 00 | 18 | | 1 | 01 | 19 | | 2 | 02 | 20 | | .. | .. | 21 | | 9 | 09 | 22 | | 10 | 0A | 23 | | 11 | 0B | 24 | | 12 | 0C | 25 | | 13 | 0D | 26 | | 14 | 0E | 27 | | 15 | 0F | 28 | | 16 | 10 | 29 | | 17 | 11 | 30 | | 18 | 12 | 31 | ![hex](./images/hex.png) 32 | 33 | `2E7` = 743\ 34 | (**256** * 2) + (**16** * 14) + (**1** * 7) = 743 35 | 36 | Confused? Totally ok! The first time coming across hex may seem a bit daunting but it's easy to see the advantage of hex when it comes to brevity and readabilty as compared with binary. 37 | 38 | `1A7` = 423\ 39 | `110100111` = 423 40 | 41 | I've found this [site](https://www.bbc.co.uk/bitesize/guides/z3fgcdm/revision/2) by the BBC useful for understanding hexadecimal. 42 | 43 | #### Exercise 44 |
45 | What number does 1F7 represent? 46 | 47 | `503`\ 48 | (**256** * 1) + (**16** * 15) + (**1** * 7) = 503 49 | 50 |
51 | 52 | > Note on the origins of Hexadecimal:\ 53 | An 8 bit byte can be split into 2 * 4 bit "nibbles".\ 54 | \ 55 | For example: 56 | `11001011` can be split into 57 | `1100` and `1011` 58 | \ 59 | Each 4 bit nibble is a number between 0 & 15 (a single hex digit). 60 | \ 61 | \ 62 | So a byte of 8 bits (that are difficult to remember and prone to errors if copying from a book) can be represented in 2 hex digits (easier to remember when copying from a book). 63 | \ 64 | \ 65 | It came about when early computer engineers had to write down binary codes (before printers even) and so many errors crept in that they realised they had to come up with a method that would reduce the number of errors that would occur. 66 | \ 67 | \ 68 | So 2 hexadecimal digits are just a convenient way (or shorthand even) to represent an 8 bit binary byte. 69 | \ 70 | via [Simon Cobb](https://www.simoncobb.co.uk) 71 | -------------------------------------------------------------------------------- /lessons/low-level/images/0and1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/young/intro-to-web-assembly/ce655c73cc207412155090f9ea9a0989ede6684a/lessons/low-level/images/0and1.png -------------------------------------------------------------------------------- /lessons/low-level/images/32bits.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/young/intro-to-web-assembly/ce655c73cc207412155090f9ea9a0989ede6684a/lessons/low-level/images/32bits.png -------------------------------------------------------------------------------- /lessons/low-level/images/bit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/young/intro-to-web-assembly/ce655c73cc207412155090f9ea9a0989ede6684a/lessons/low-level/images/bit.png -------------------------------------------------------------------------------- /lessons/low-level/images/byte.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/young/intro-to-web-assembly/ce655c73cc207412155090f9ea9a0989ede6684a/lessons/low-level/images/byte.png -------------------------------------------------------------------------------- /lessons/low-level/images/counting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/young/intro-to-web-assembly/ce655c73cc207412155090f9ea9a0989ede6684a/lessons/low-level/images/counting.png -------------------------------------------------------------------------------- /lessons/low-level/images/endian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/young/intro-to-web-assembly/ce655c73cc207412155090f9ea9a0989ede6684a/lessons/low-level/images/endian.png -------------------------------------------------------------------------------- /lessons/low-level/images/hex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/young/intro-to-web-assembly/ce655c73cc207412155090f9ea9a0989ede6684a/lessons/low-level/images/hex.png -------------------------------------------------------------------------------- /lessons/low-level/images/pointer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/young/intro-to-web-assembly/ce655c73cc207412155090f9ea9a0989ede6684a/lessons/low-level/images/pointer.png -------------------------------------------------------------------------------- /lessons/low-level/memory.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/low-level/memory" 3 | title: "Memory" 4 | order: "1G" 5 | description: "" 6 | section: "Low Level Stuff" 7 | --- 8 | 9 | Computer processes are inherently stateless. That is, all those 1's and 0's flying around are lost once the power is turned off so all computers use some form of memory in order to save information and keep track running processes. There are many forms of memory from L1 caches on processors to solid state drives (SSD) for long-term data storage to random access memory (RAM) used by the operating system to store and access short-term data. 10 | 11 | For a high-level language like JavaScript we generally don't spend too many calories thinking about memory since JavaScript has garbage collection meaning that when we need to create a string or an object, the engine automatically allocates and deallocates memory for us. In a lower level language like Web Assembly we have to be explict about where in memory we're reading and writing data to. 12 | 13 | #### Structure 14 | Think of memory as a giant warehouse full of storage bins. Each bin has an address and can have anything inside it so long as it fits within the bin. Processes can request bins for any purpose and it's up to the operating system to allocate the bins, remember which bins are in use, and make sure others processess can't peek into other bins. 15 | 16 | Generally speaking, only the process itself knows the contents and ordering of the data in the bin so we can't access the contents directly. We only know the address and size of the data. In programming we use the concept of _pointers_ (the address of the bin) to read and write from memory. 17 | 18 | ![pointer](./images/pointer.png) 19 | -------------------------------------------------------------------------------- /lessons/low-level/tostring.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/low-level/tostring" 3 | title: "The underrated .toString() method" 4 | order: "1E" 5 | description: "" 6 | section: "Low Level Stuff" 7 | --- 8 | 9 | All of this value conversion is a lot of mental overhead. Fortunately we can utilize JavaScript to make our lives easier. 10 | 11 | #### `Object.prototype.toString(radix)` 12 | 13 | [toString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString) returns a string representation of an object. It takes an optional `radix` parameter. 14 | 15 | > _radix_ is the number of unique digits. It is also known as _base_ 16 | 17 | | Radix/Base | Type | 18 | | ----------- | ----------- | 19 | | 2 | binary | 20 | | 10 | decimal | 21 | | 16 | hexadecimal | 22 | 23 | 24 | #### Exercise 25 | 26 |
27 | Write a function that converts from hexadecimal to decimal 28 | 29 | ```js 30 | function hexToDecimal(hex) { 31 | return (hex).toString(10); 32 | } 33 | ``` 34 |
35 | 36 |
37 | Write a function that converts from decimal to binary 38 | 39 | ```js 40 | function decimalToBinary(num) { 41 | return (num).toString(2); 42 | } 43 | ``` 44 |
45 | -------------------------------------------------------------------------------- /lessons/low-level/types.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/low-level/types" 3 | title: "Numeric types" 4 | order: "1G" 5 | description: "" 6 | section: "Low Level Stuff" 7 | --- 8 | 9 | The two main types of numbers we care about are floating points and integers. 10 | 11 | ###### Floating Point 12 | `142.24` 13 | 14 | ###### Integer 15 | `142` 16 | 17 | JavaScript only has floating point numbers but most environments don't display the dot after a number. 18 | 19 | ``` js 20 | 21.000 21 | // 21 22 | ``` 23 | 24 | > Note: [Number.MAX\_SAFE\_INTEGER](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER) shows the largest integer that can be safely used in JavaScript. 25 | 26 | 27 | Under the hood, numbers in JavaScript are 64-bit floating points whereas in Web Assembly all memory pointers are 32-bits. 28 | 29 | 30 | ![32 bits](./images/32bits.png) 31 | 32 | This is important because understanding memory is fundemental to working with Web Assembly. 33 | -------------------------------------------------------------------------------- /lessons/wasm/images/intro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/young/intro-to-web-assembly/ce655c73cc207412155090f9ea9a0989ede6684a/lessons/wasm/images/intro.png -------------------------------------------------------------------------------- /lessons/wasm/images/opcode-table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/young/intro-to-web-assembly/ce655c73cc207412155090f9ea9a0989ede6684a/lessons/wasm/images/opcode-table.png -------------------------------------------------------------------------------- /lessons/wasm/images/opcodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/young/intro-to-web-assembly/ce655c73cc207412155090f9ea9a0989ede6684a/lessons/wasm/images/opcodes.png -------------------------------------------------------------------------------- /lessons/wasm/images/wasm-v-wat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/young/intro-to-web-assembly/ce655c73cc207412155090f9ea9a0989ede6684a/lessons/wasm/images/wasm-v-wat.png -------------------------------------------------------------------------------- /lessons/wasm/images/wasmmodule.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/young/intro-to-web-assembly/ce655c73cc207412155090f9ea9a0989ede6684a/lessons/wasm/images/wasmmodule.png -------------------------------------------------------------------------------- /lessons/wasm/stack-and-opcode.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/wasm/stack" 3 | section: "Web Assembly" 4 | title: "Stack and OpCode" 5 | order: "2C" 6 | description: "" 7 | --- 8 | 9 | #### Stacks 10 | 11 | A stack is memory region where variables are stored and accessed by the running program. Once execution is complete the stack is cleared. 12 | 13 | > While similar in concept, a Stack is data structure that stores information in Last In First Order (LIFO) and is not the as an execution stack. 14 | 15 | Web Assembly is stack based language so all operations read and write to the stack in a linear fashion. 16 | 17 | > You've probably heard of the call stack in JavaScript which is a reserved portion of memory the interpreter uses to keep track of running functions. 18 | 19 | #### OpCodes 20 | 21 | Opcodes (Operation Code) are readable computer instructions representing machine language instructions. 22 | 23 | ![example of opcodes with corresponding hex](./images/opcodes.png) 24 | 25 | [Here is an interactive table](https://pengowray.github.io/wasm-ops/) of current Web Assembly OpCodes. 26 | 27 | ![table of wasm opcodes](./images/opcode-table.png) 28 | 29 | OpCodes are specific to the data type. We're going to stick with 32-bit integers for this course. 30 | 31 | | Type | Name | 32 | | ----------- | ----------- | 33 | | i32 | 32-bit integer | 34 | | i64 | 64-bit integer | 35 | | f32 | 32-bit float | 36 | | f64 | 64-bit float | 37 | ----------- 38 | #### Instruction stack 39 | All Web Assembly instructions read and write from the stack. Think of the stack like a JavaScript array where values are pushed and popped to and from the stack. For example, `i32.mul` pops two `i32` values from the stack and multiplies them together. 40 | 41 | ```wasm 42 | get_local 0 ;; push first parameter onto the stack 43 | get_local 1 ;; push second parameter onto the stack 44 | i32.mul ;; pop both values and execute operation 45 | ``` 46 | 47 | To push a value onto the stack use the `i32.const` instruction 48 | ```wasm 49 | i32.const 99 ;; push 99 onto the stack 50 | ``` 51 | 52 | #### Exercise 53 |
54 | Create a "minusone" function that takes an i32 and substracts 1 55 | 56 | ```wasm 57 | (module 58 | (export "minusone" (func $minusone)) 59 | (func $minusone (param $x i32) (result i32) 60 | get_local $x 61 | i32.const 1 62 | i32.sub 63 | ) 64 | ) 65 | ``` 66 | 67 | 68 | 69 |
70 | -------------------------------------------------------------------------------- /lessons/wasm/wasm-intro-contd.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/wasm/intro-contd" 3 | section: "Web Assembly" 4 | 5 | title: "Modules" 6 | order: "2B" 7 | description: "" 8 | --- 9 | 10 | The fundamental unit of code is a module. Within the module, we create functions to export which can be called by JavaScript. Function parameters are known as _locals_ and we access them with either `get_local` or `local.get`. 11 | 12 | ![a wasm module](./images/wasmmodule.png) 13 | 14 | > A Web Assembly module is a tree-based structure known as an [S-expression](https://developer.mozilla.org/en-US/docs/WebAssembly/Understanding_the_text_format#s-expressions). Just thought you'd like to know. 15 | 16 | #### Web Assembly Studio 17 | We're going use [Web Assembly Studio](https://wasm-studio.surge.sh/) to write our first hello world. 18 | 19 | Our function will take a 32-bit integer as input and return the input unmodified. 20 | ```wasm 21 | ;; main.wat 22 | (module 23 | (func $helloWorld (param $num1 i32) (result i32) 24 | get_local $num1 25 | ) 26 | (export "helloWorld" (func $helloWorld)) 27 | ) 28 | ``` 29 | 30 | Notice that a function implicitly returns the last item in the stack. To execute our wasm, click "build and run" to see the output of our hello world function. 31 | 32 | Before we can build anything more complex there's two concepts we need to learn: stack and OpCodes. 33 | -------------------------------------------------------------------------------- /lessons/wasm/wasm-intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/wasm/intro" 3 | section: "Web Assembly" 4 | 5 | title: "What is Web Assembly?" 6 | order: "2A" 7 | description: "" 8 | --- 9 | 10 | ![intro](./images/intro.png) 11 | 12 | Web Assembly (wasm) is a powerful low-level language that is meant to be a compile target for high-level languages. It is designed to be portable and ran in many different environments. It is designed to _compliment_ JavaScript, not replace it. 13 | 14 | 15 | Web Assembly runs in its own environment at near native speed, can be cached, and runs much faster than JavaScript can be parsed. 16 | 17 | #### File types 18 | Web Assembly has two file types: 19 | - `.wasm` is the actual assembly code in binary format 20 | - `.wat` is the human readable textual representation of the code 21 | 22 | 23 | ![wasm-v-wat](./images/wasm-v-wat.png) 24 | -------------------------------------------------------------------------------- /lessons/wasm/writing-wasm.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/wasm/writing" 3 | section: "Web Assembly" 4 | title: "Writing Web Assembly" 5 | order: "2D" 6 | description: "" 7 | --- 8 | 9 | Let's write something a bit more complicated. Create an equivalent function in Web Assembly: 10 | 11 | ```js 12 | function example(n) { 13 | if (n === 2) { 14 | return n * 2; 15 | } 16 | 17 | if (n === 3) { 18 | return n * 3; 19 | } 20 | 21 | return n * n; 22 | } 23 | ``` 24 | 25 | The equivalent Web Assembly function is a bit more...verbose 26 | 27 | ```wasm 28 | 29 | (func $example (param $0 i32) (result i32) 30 | get_local $0 31 | i32.const 2 32 | i32.eq 33 | if 34 | get_local $0 35 | i32.const 2 36 | i32.mul 37 | return 38 | end 39 | get_local $0 40 | i32.const 3 41 | i32.eq 42 | if 43 | get_local $0 44 | i32.const 3 45 | i32.mul 46 | return 47 | end 48 | get_local $0 49 | get_local $0 50 | i32.mul 51 | ) 52 | ``` 53 | 54 | As we can see writing Web Assembly by hand isn't terribly practical. Fortunately we have AssemblyScript. 55 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gatsby-course-starter", 3 | "description": "a gatsby seed project to get your education site started", 4 | "version": "1.0.0", 5 | "author": "Brian Holt ", 6 | "dependencies": { 7 | "bootstrap": "^4.5.3", 8 | "code-mirror-themes": "^1.0.0", 9 | "front-matter": "^4.0.2", 10 | "gatsby": "^2.30.1", 11 | "gatsby-cli": "^2.17.0", 12 | "gatsby-link": "^2.9.0", 13 | "gatsby-plugin-layout": "^1.8.0", 14 | "gatsby-plugin-react-helmet": "^3.8.0", 15 | "gatsby-plugin-sharp": "^2.12.0", 16 | "gatsby-remark-autolink-headers": "^2.9.0", 17 | "gatsby-remark-copy-linked-files": "^2.8.0", 18 | "gatsby-remark-images": "^3.9.0", 19 | "gatsby-remark-prismjs": "^3.11.0", 20 | "gatsby-source-filesystem": "^2.9.0", 21 | "gatsby-transformer-remark": "^2.14.0", 22 | "is-url-superb": "^5.0.0", 23 | "parse-markdown-links": "^1.0.4", 24 | "prismjs": "^1.23.0", 25 | "react": "^17.0.1", 26 | "react-dom": "^17.0.1", 27 | "react-helmet": "^6.1.0" 28 | }, 29 | "keywords": [ 30 | "gatsby", 31 | "gatsby-starter", 32 | "course", 33 | "education" 34 | ], 35 | "license": "(CC-BY-NC-4.0 OR Apache-2.0)", 36 | "main": "n/a", 37 | "scripts": { 38 | "build": "gatsby build --prefix-paths", 39 | "csv": "node csv.js", 40 | "dev": "gatsby develop", 41 | "format": "prettier --write \"src/**/*.{js,jsx,md,css}\"", 42 | "lint": "eslint \"src/**/*.{js,jsx}\"" 43 | }, 44 | "devDependencies": { 45 | "@babel/polyfill": "^7.12.1", 46 | "@typescript-eslint/eslint-plugin": "^4.15.1", 47 | "@typescript-eslint/parser": "^4.15.1", 48 | "babel-eslint": "^10.1.0", 49 | "core-js": "^3.8.2", 50 | "eslint": "^7.20.0", 51 | "eslint-config-prettier": "^7.1.0", 52 | "eslint-plugin-import": "^2.22.1", 53 | "eslint-plugin-jsx-a11y": "^6.4.1", 54 | "eslint-plugin-react": "^7.22.0", 55 | "gatsby-plugin-postcss": "^3.7.0", 56 | "postcss": "^8.2.6", 57 | "prettier": "^2.2.1", 58 | "tailwindcss": "^2.0.3", 59 | "typescript": "^4.1.5" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {} 4 | }, 5 | } 6 | -------------------------------------------------------------------------------- /src/components/TOCCard.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Link from "gatsby-link"; 3 | import * as helpers from "../util/helpers"; 4 | 5 | const sortFn = helpers.sorter; 6 | 7 | const LessonCard = ({ content, title }) => { 8 | console.log(sortFn); 9 | 10 | const sections = content 11 | .map(lesson => lesson.node.frontmatter) 12 | .sort(sortFn) 13 | .reduce((acc, lesson) => { 14 | if (!acc.length) { 15 | acc.push([lesson]); 16 | return acc; 17 | } 18 | 19 | const lastSection = acc[acc.length - 1][0].section.split(",")[0]; 20 | if (lastSection === lesson.section.split(",")[0]) { 21 | acc[acc.length - 1].push(lesson); 22 | } else { 23 | acc.push([lesson]); 24 | } 25 | 26 | return acc; 27 | }, []); 28 | 29 | return ( 30 |
31 |
32 |

{title}

33 |
34 |
35 |
    36 | {sections.map(section => ( 37 |
  1. 38 |

    {section[0].section}

    39 |
      40 | {section.map(lesson => ( 41 |
    1. 42 | {lesson.title} 43 |
    2. 44 | ))} 45 |
    46 |
  2. 47 | ))} 48 |
49 |
50 | ); 51 | }; 52 | 53 | export default LessonCard; 54 | -------------------------------------------------------------------------------- /src/layouts/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Link from "gatsby-link"; 3 | import Helmet from "react-helmet"; 4 | import { graphql, StaticQuery } from "gatsby"; 5 | 6 | import "../styles/global.css"; 7 | import "prismjs/themes/prism-solarizedlight.css"; 8 | import "code-mirror-themes/themes/monokai.css"; 9 | 10 | // import jpg from "../../static/posterframe.jpg"; 11 | 12 | const TemplateWrapper = props => { 13 | return ( 14 | { 16 | const frontmatter = 17 | props.data && props.data.markdownRemark 18 | ? props.data.markdownRemark.frontmatter 19 | : null; 20 | 21 | return ( 22 |
23 | 59 |
60 |
61 |
62 |
63 | 64 |

{data.site.siteMetadata.title}

65 |

By Jem Young

66 | 67 | {/* {!frontmatter ? null : ( 68 |

{`${frontmatter.section} – ${frontmatter.title}`}

69 | )} */} 70 |
71 |
{props.children}
72 |
73 | ); 74 | }} 75 | query={graphql` 76 | query HomePage($path: String!) { 77 | markdownRemark(frontmatter: { path: { eq: $path } }) { 78 | html 79 | frontmatter { 80 | path 81 | title 82 | order 83 | section 84 | description 85 | } 86 | } 87 | site { 88 | pathPrefix 89 | siteMetadata { 90 | title 91 | subtitle 92 | description 93 | keywords 94 | } 95 | } 96 | } 97 | `} 98 | /> 99 | ); 100 | }; 101 | 102 | export default TemplateWrapper; 103 | -------------------------------------------------------------------------------- /src/pages/404.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const NotFoundPage = () => ( 4 |
5 |

NOT FOUND

6 |

You just hit a route that doesn't exist... the sadness.

7 |
8 | ); 9 | 10 | export default NotFoundPage; 11 | -------------------------------------------------------------------------------- /src/pages/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { StaticQuery, graphql } from "gatsby"; 3 | import Card from "../components/TOCCard"; 4 | 5 | import "../styles/global.css"; 6 | 7 | 8 | const IndexPage = () => ( 9 | ( 37 | 41 | )} 42 | /> 43 | ); 44 | 45 | export default IndexPage; 46 | -------------------------------------------------------------------------------- /src/styles/global.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | @import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap'); 5 | 6 | 7 | @layer base { 8 | h1 { 9 | @apply text-4xl text-white 10 | } 11 | 12 | h2 { 13 | @apply text-2xl text-white 14 | } 15 | 16 | h3 { 17 | @apply text-xl 18 | } 19 | 20 | h4 { 21 | @apply text-lg py-4 font-bold 22 | } 23 | 24 | body { 25 | @apply bg-gray 26 | } 27 | } 28 | 29 | 30 | .lesson-content td { 31 | @apply border-2 border-black p-2 32 | } 33 | 34 | .lesson-content p { 35 | @apply mb-4 leading-7; 36 | } 37 | 38 | .lesson-content td input { 39 | min-width: 300px; 40 | } 41 | 42 | 43 | .lesson { 44 | @apply w-full max-w-4xl md:w-4/5 mx-auto p-10 m-8 border-2 border-gray rounded-xl bg-white z-10 shadow-md; 45 | } 46 | 47 | .lesson h1, .lesson h2 { 48 | @apply text-black text-center m-10 text-4xl font-semibold; 49 | } 50 | 51 | .lesson-title { 52 | color: white; 53 | text-transform: uppercase; 54 | font-weight: bold; 55 | } 56 | 57 | .lesson p { 58 | clear: both; 59 | } 60 | 61 | .lesson a { 62 | @apply text-purple-light hover:underline hover:text-purple-dark 63 | } 64 | 65 | .lesson-links { 66 | @apply mt-10 mb-20; 67 | } 68 | 69 | .next { 70 | float: right; 71 | } 72 | 73 | .prev { 74 | float: left; 75 | } 76 | 77 | .lesson-title { 78 | color: white; 79 | text-transform: uppercase; 80 | font-weight: bold; 81 | } 82 | 83 | blockquote { 84 | background: #cecccc; 85 | padding-left: 9px; 86 | border-left: 4px solid #ff9800; 87 | } 88 | -------------------------------------------------------------------------------- /src/templates/lessonTemplate.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Link from "gatsby-link"; 3 | import { graphql } from "gatsby"; 4 | import * as helpers from "../util/helpers"; 5 | 6 | const sortFn = helpers.sorter; 7 | 8 | export default function Template(props) { 9 | let { markdownRemark, allMarkdownRemark } = props.data; // data.markdownRemark holds our post data 10 | 11 | const sections = allMarkdownRemark.edges 12 | .map(lesson => lesson.node.frontmatter) 13 | .sort(sortFn); 14 | 15 | const { frontmatter, html } = markdownRemark; 16 | 17 | const index = sections.findIndex(el => el.path === frontmatter.path); 18 | 19 | const prevLink = 20 | index > 0 ? ( 21 | 22 | {"← " + sections[index - 1].title} 23 | 24 | ) : null; 25 | const nextLink = 26 | index < sections.length - 1 ? ( 27 | 28 | {sections[index + 1].title + " →"} 29 | 30 | ) : null; 31 | return ( 32 |
33 |
34 |

{frontmatter.title}

35 |

{frontmatter.date}

36 |
40 |
41 | {prevLink} 42 | {nextLink} 43 |
44 |
45 |
46 | ); 47 | } 48 | 49 | export const pageQuery = graphql` 50 | query LessonByPath($path: String!) { 51 | markdownRemark(frontmatter: { path: { eq: $path } }) { 52 | html 53 | frontmatter { 54 | path 55 | title 56 | order 57 | section 58 | description 59 | } 60 | } 61 | allMarkdownRemark(limit: 1000) { 62 | edges { 63 | node { 64 | frontmatter { 65 | order 66 | path 67 | title 68 | } 69 | } 70 | } 71 | } 72 | } 73 | `; 74 | -------------------------------------------------------------------------------- /src/util/helpers.js: -------------------------------------------------------------------------------- 1 | function splitSections(str) { 2 | const validSectionTest = /^\d+[A-Z]+$/; 3 | const numbersRegex = /^\d+/; 4 | const lettersRegex = /[A-Z]+$/; 5 | if (!validSectionTest.test(str)) { 6 | throw new Error( 7 | `${str} does not match the section format. It must be , like 16A or 5F (case sensitive)` 8 | ); 9 | } 10 | 11 | return [numbersRegex.exec(str)[0], lettersRegex.exec(str)[0]]; 12 | } 13 | 14 | const getCharScore = str => 15 | str 16 | .split("") 17 | .map((char, index) => char.charCodeAt(0) * 10 ** index) 18 | .reduce((acc, score) => acc + score); 19 | 20 | function sorter(a, b) { 21 | let aOrder, bOrder; 22 | 23 | if (a.attributes && a.attributes.order) { 24 | aOrder = a.attributes.order; 25 | bOrder = b.attributes.order; 26 | } else { 27 | aOrder = a.order; 28 | bOrder = b.order; 29 | } 30 | 31 | const [aSec, aSub] = splitSections(aOrder); 32 | const [bSec, bSub] = splitSections(bOrder); 33 | 34 | // sections first 35 | if (aSec !== bSec) { 36 | return aSec - bSec; 37 | } 38 | 39 | // subsections next 40 | return getCharScore(aSub) - getCharScore(bSub); 41 | } 42 | 43 | module.exports.splitSections = splitSections; 44 | module.exports.sorter = sorter; 45 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | purge: ['./src/**/*.{js,jsx,ts,tsx}'], 3 | darkMode: false, // or 'media' or 'class' 4 | theme: { 5 | extend: {}, 6 | fontFamily: { 7 | 'sans': ['Poppins'] 8 | }, 9 | colors: { 10 | purple: { 11 | light: "#654FF0", 12 | dark: "#5a47d6" 13 | }, 14 | black: "#171123", 15 | yellow: "#ffc857", 16 | gray: "#e8ebf7", 17 | white: "#ffffff" 18 | } 19 | }, 20 | variants: { 21 | extend: {}, 22 | }, 23 | plugins: [], 24 | } 25 | --------------------------------------------------------------------------------