Skip to content

Commit b6b7d0b

Browse files
authored
Merge pull request #1 from openwebf/feat/0.2.11_kbc1_ic
Feat/0.2.11 kbc1 ic
2 parents 4a4c505 + ee106bc commit b6b7d0b

File tree

313 files changed

+126917
-61280
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

313 files changed

+126917
-61280
lines changed
+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
2+
# For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages
3+
4+
name: Publish Node.js Package Beta
5+
6+
on:
7+
release:
8+
types: [created]
9+
workflow_dispatch:
10+
jobs:
11+
prebuild:
12+
strategy:
13+
matrix:
14+
os: [windows-2022, ubuntu-latest, macos-12, macos-14]
15+
node: [14]
16+
runs-on: ${{ matrix.os }}
17+
env:
18+
VCINSTALLDIR: 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC'
19+
steps:
20+
- uses: actions/checkout@v2
21+
- uses: actions/setup-python@v4
22+
with:
23+
python-version: '3.x'
24+
- run: pip install setuptools
25+
- uses: actions/setup-node@v3
26+
with:
27+
node-version: ${{ matrix.node }}
28+
- if: ${{ matrix.os == 'windows' }}
29+
shell: powershell
30+
run: |
31+
npm config set msvs_version 2022 -g
32+
- run: npm install --ignore-scripts
33+
- run: npm run build -- --msvs_version=2022
34+
- uses: actions/upload-artifact@v3
35+
with:
36+
name: qjsc-prebuild-${{ matrix.os }}-node${{ matrix.node }}
37+
path: build/Release/node.napi.node
38+
publish-npm:
39+
needs: build
40+
runs-on: ubuntu-latest
41+
steps:
42+
- uses: actions/checkout@v2
43+
- uses: actions/setup-node@v2
44+
with:
45+
node-version: 16
46+
registry-url: https://registry.npmjs.org/
47+
- uses: actions/setup-python@v4
48+
with:
49+
python-version: '3.x'
50+
- uses: actions/download-artifact@v2
51+
with:
52+
name: qjsc-prebuild-windows-2022-node14
53+
path: prebuilds/win32-x64/
54+
- uses: actions/download-artifact@v2
55+
with:
56+
name: qjsc-prebuild-ubuntu-latest-node14
57+
path: prebuilds/linux-x64/
58+
- uses: actions/download-artifact@v2
59+
with:
60+
name: qjsc-prebuild-macos-12-node14
61+
path: prebuilds/darwin-x64/
62+
- uses: actions/download-artifact@v2
63+
with:
64+
name: qjsc-prebuild-macos-14-node14
65+
path: prebuilds/darwin-arm64/
66+
- run: npm publish --tag beta
67+
env:
68+
NODE_AUTH_TOKEN: ${{secrets.npm_token}}

.github/workflows/npm-publish.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
- uses: actions/checkout@v2
1515
- uses: actions/setup-node@v2
1616
with:
17-
node-version: 14
17+
node-version: 16
1818
- run: npm ci
1919
- run: npm test
2020

@@ -25,7 +25,7 @@ jobs:
2525
- uses: actions/checkout@v2
2626
- uses: actions/setup-node@v2
2727
with:
28-
node-version: 14
28+
node-version: 16
2929
registry-url: https://registry.npmjs.org/
3030
- run: npm publish
3131
env:

.github/workflows/prebuild.yml

+1-23
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,4 @@ on:
44
workflow_dispatch:
55

66
jobs:
7-
prebuild:
8-
strategy:
9-
matrix:
10-
os: [windows, linux, macos]
11-
node: [16]
12-
runs-on: ${{ matrix.os }}-latest
13-
env:
14-
VCINSTALLDIR: 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC'
15-
steps:
16-
- uses: actions/checkout@v2
17-
- uses: actions/setup-node@v3
18-
with:
19-
node-version: ${{ matrix.node }}
20-
- if: ${{ matrix.os == 'windows' }}
21-
shell: powershell
22-
run: |
23-
npm config set msvs_version 2022 -g
24-
- run: npm install --ignore-scripts
25-
- run: npm run build -- --msvs_version=2022
26-
- uses: actions/upload-artifact@v3
27-
with:
28-
name: qjsc-prebuild-${{ matrix.os }}-node${{ matrix.node }}
29-
path: build/Release/qjsc_20210327.node
7+

.github/workflows/test.yml

+6-1
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,17 @@ jobs:
1111
strategy:
1212
matrix:
1313
os: [ubuntu-latest, windows-latest, macos-latest]
14-
node: [14]
14+
node: [16]
1515
runs-on: ${{ matrix.os }}
1616
steps:
1717
- uses: actions/checkout@v2
18+
- uses: actions/setup-python@v4
19+
with:
20+
python-version: '3.x'
21+
- run: pip install setuptools
1822
- uses: actions/setup-node@v2
1923
with:
2024
node-version: ${{ matrix.node }}
25+
- run: npm install
2126
- run: npm ci
2227
- run: npm test

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ pids
1515
*.seed
1616
*.pid.lock
1717

18+
package-lock.json
19+
1820
# Directory for instrumented libs generated by jscoverage/JSCover
1921
lib-cov
2022

README.md

+8-14
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,23 @@
1-
# node-qjsc
2-
> Node.js addon for the [QuickJS](https://github.com/bellard/quickjs) compiler.
1+
# WBC
32

4-
Current supported version:
5-
+ 20210327
3+
The [WBC](https://github.com/openwebf/rfc/blob/main/working/wbc1.en-US.md)(WebF bytecode file) file generator.
4+
5+
The WBC file is a specially designed binary file that contains pre-compiled JavaScript bytecodes and other assets, which could speed up the loading of WebF's application.
66

77
## Install
88

99
```
10-
npm install qjsc --save
10+
npm install wbc --save
1111
```
1212

1313
## Usage
1414

1515
```javascript
16-
const Qjsc = require('qjsc');
17-
const qjsc = new Qjsc();
16+
const WBC = require('wbc');
17+
const wbc = new WBC();
1818

1919
// Dump bytecode from javascript source;
20-
qjsc.compile('function hello() { return 1 + 1};'); // <Buffer ...>
21-
22-
// Use specified quickjs version
23-
qjsc = new Qjsc({version: '20210327'});
24-
25-
// Get all supported versions.
26-
qjsc.getSupportedVersions();
20+
wbc.compile('function hello() { return 1 + 1};'); // <Buffer ...>
2721
```
2822

2923
## Contribute

bin/qjsc.js bin/wbc.js

+20-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#!/usr/bin/env node
2+
const Wbc = require('./wbc_lib').Wbc;
23
const path = require('path');
34
const fs = require('fs');
45
const { program } = require('commander');
@@ -7,15 +8,21 @@ const Qjsc = require('../index');
78

89
program
910
.version(packageConfig.version)
10-
.description('QuickJS Compiler')
11+
.description('The WBC file generator')
1112
.requiredOption('-s, --source <source>', 'the Javascript source file path')
1213
.requiredOption('-d, --dist <dist>', 'the generated bytecode file path')
14+
.option('--legacy_kbc1', 'generate legacy kbc1 file, (compact with openkraken project)')
1315
.parse(process.argv);
1416

1517
let options = program.opts();
1618
let source = options.source;
1719
let dist = options.dist;
1820

21+
let type = "wbc";
22+
if (options.legacy_kbc1) {
23+
type = 'kbc1';
24+
}
25+
1926
if (!path.isAbsolute(source)) {
2027
source = path.join(process.cwd(), source);
2128
}
@@ -29,6 +36,15 @@ const sourceFileName = source.split('/').slice(-1)[0].split('.')[0];
2936
const sourceCode = fs.readFileSync(source, {encoding: 'utf-8'});
3037

3138
let buffer = qjsc.compile(sourceCode);
32-
let distPath = path.join(dist, sourceFileName + '.kbc1');
33-
fs.writeFileSync(distPath, buffer);
34-
console.log('Quickjs bytecode generated at: \n' + distPath);
39+
40+
if (type == 'kbc1') {
41+
let distPath = path.join(dist, sourceFileName + '.kbc1');
42+
fs.writeFileSync(distPath, buffer);
43+
console.log('Quickjs bytecode generated kbc1 at: \n' + distPath);
44+
} else if (type == 'wbc') {
45+
const wbc = new Wbc();
46+
let wbcBytecode = wbc.generateWbcBytecode(buffer);
47+
let distPath = path.join(dist, sourceFileName + '.wbc1');
48+
fs.writeFileSync(distPath, wbcBytecode);
49+
console.log('Quickjs bytecode generated wbc1 at: \n' + distPath);
50+
}

bin/wbc_lib.js

+150
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
var lz4 = require('lz4');
2+
const path = require('path');
3+
4+
//each part of header length
5+
const HEADER_LENGTH = 4;
6+
const HEADER_CHUNK_TYPE = 4;
7+
const HEADER_COMPRESSION_METHOD = 1;
8+
const HEADER_COMPILE_LEVEL = 1;
9+
const HEADER_BYTECODE_VERSION = 1;
10+
const HEADER_ADDITIONAL_DATA = 3;
11+
const HEADER_CRC32 = 4;
12+
13+
//each part of body length
14+
const BODY_LENGTH = 4;
15+
const BODY_CHUNK_TYPE = 4;
16+
const BODY_CRC32 = 4;
17+
18+
//each part of end length
19+
const END_LENGTH = 4;
20+
const END_CHUNK_TYPE = 4;
21+
22+
const HEADER_FIELDS = [
23+
HEADER_LENGTH,
24+
HEADER_CHUNK_TYPE,
25+
HEADER_COMPRESSION_METHOD,
26+
HEADER_COMPILE_LEVEL,
27+
HEADER_BYTECODE_VERSION,
28+
HEADER_ADDITIONAL_DATA,
29+
HEADER_CRC32
30+
];
31+
32+
class Wbc {
33+
constructor(options = {}) {
34+
const rootDir = path.resolve(__dirname, '..');
35+
this._bindings = require('node-gyp-build')(rootDir);
36+
}
37+
38+
getAdler32(buffer) {
39+
return this._bindings.getAdler32(buffer);
40+
}
41+
42+
generateWbcBytecode(oriBody) {
43+
let signatureBuffer = this.generateSignature();
44+
let headerBuffer = this.generateHeader();
45+
let bodyBuffer = this.generateBody(oriBody);
46+
let endBuffer = this.generateEnd();
47+
48+
let totalLength = signatureBuffer.length + headerBuffer.length + bodyBuffer.length + endBuffer.length;
49+
let bytecodeBuffer = Buffer.concat([signatureBuffer, headerBuffer, bodyBuffer, endBuffer], totalLength);
50+
return bytecodeBuffer;
51+
}
52+
53+
//0x89 0x57 0x42 0x43 0x31 0x0D 0x0A 0x1A 0x0A
54+
generateSignature() {
55+
const buffer = Buffer.alloc(9);
56+
buffer.writeUInt8(0x89, 0);
57+
buffer.writeUInt8(0x57, 1);
58+
buffer.writeUInt8(0x42, 2);
59+
buffer.writeUInt8(0x43, 3);
60+
buffer.writeUInt8(0x31, 4);
61+
buffer.writeUInt8(0x0D, 5);
62+
buffer.writeUInt8(0x0A, 6);
63+
buffer.writeUInt8(0x1A, 7);
64+
buffer.writeUInt8(0x0A, 8);
65+
return buffer;
66+
}
67+
68+
generateHeader() {
69+
let pointer = 0;
70+
let length = this.calculateHeaderLength();
71+
const headerBuffer = Buffer.alloc(length);
72+
73+
//length
74+
headerBuffer.writeUInt32BE(length, 0);
75+
76+
//ASCII value for the letter WBHD (0x57 0x42 0x48 0x44 in hexadecimal)
77+
pointer += HEADER_LENGTH;
78+
headerBuffer.writeUInt32BE(0x57424844, pointer);
79+
80+
//compressionMethod
81+
pointer += HEADER_CHUNK_TYPE;
82+
headerBuffer.writeUInt8(0, pointer);
83+
84+
//compileLevel
85+
pointer += HEADER_COMPRESSION_METHOD;
86+
headerBuffer.writeUInt8(0, pointer);
87+
88+
//bytecodeVersion
89+
pointer += HEADER_COMPILE_LEVEL;
90+
headerBuffer.writeUInt8(0, pointer);
91+
92+
//additionalData 3bytes
93+
pointer += HEADER_BYTECODE_VERSION;
94+
95+
//Only the CRC32 value of the first 14 bytes is calculated because the last CRC32 field is reserved
96+
pointer += HEADER_ADDITIONAL_DATA;
97+
const adler32Value = this.getAdler32(headerBuffer.slice(0, pointer));
98+
99+
// Write the calculated CRC32 value to the last 4 bytes of the Buffer
100+
headerBuffer.writeUInt32BE(adler32Value, pointer);
101+
return headerBuffer;
102+
}
103+
104+
calculateHeaderLength() {
105+
return HEADER_FIELDS.reduce((sum, value) => sum + value, 0);
106+
}
107+
108+
generateBody(oriBody) {
109+
let pointer = 0;
110+
//use lz4 to compress quickJs bytecode
111+
var bodyChunk = lz4.encode(oriBody);
112+
let length = BODY_LENGTH + BODY_CHUNK_TYPE + bodyChunk.length + BODY_CRC32;
113+
const bodyBuffer = Buffer.alloc(length);
114+
115+
//length
116+
bodyBuffer.writeUInt32BE(length, 0);
117+
118+
//ASCII value for the letter WBDY (0x57 0x42 0x44 0x59 in hexadecimal)
119+
pointer += BODY_LENGTH;
120+
bodyBuffer.writeUInt32BE(0x57424459, pointer);
121+
122+
//body chunk
123+
pointer += BODY_CHUNK_TYPE;
124+
bodyChunk.copy(bodyBuffer, pointer);
125+
126+
//crc32
127+
pointer += bodyChunk.length;
128+
const adler32Value = this.getAdler32(bodyBuffer.slice(0, pointer));
129+
130+
// Write the calculated CRC32 value to the last 4 bytes of the Buffer
131+
bodyBuffer.writeUInt32BE(adler32Value, pointer);
132+
return bodyBuffer;
133+
}
134+
135+
generateEnd() {
136+
let pointer = 0;
137+
let length = END_LENGTH + END_CHUNK_TYPE;
138+
const endBuffer = Buffer.alloc(length);
139+
140+
//length
141+
endBuffer.writeUInt32BE(length, 0);
142+
143+
//The ASCII values for the letters 'WEND' (0x57 0x45 0x4e 0x44 in hexadecimal).
144+
pointer += END_LENGTH;
145+
endBuffer.writeUInt32BE(0x57454e44, pointer);
146+
return endBuffer;
147+
}
148+
}
149+
150+
exports.Wbc = Wbc

0 commit comments

Comments
 (0)