Skip to content

Commit 7c0ac95

Browse files
authored
Merge pull request #12265 from ethereum/packedSoljson
Packed soljson.js
2 parents d29709e + 3a201ec commit 7c0ac95

File tree

7 files changed

+235
-6
lines changed

7 files changed

+235
-6
lines changed

.circleci/config.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -982,10 +982,10 @@ jobs:
982982
command: |
983983
scripts/ci/build_emscripten.sh
984984
- store_artifacts:
985-
path: emscripten_build/libsolc/soljson.js
985+
path: upload/soljson.js
986986
destination: soljson.js
987987
- run: mkdir -p workspace
988-
- run: cp emscripten_build/libsolc/soljson.js workspace/soljson.js
988+
- run: cp upload/soljson.js workspace/soljson.js
989989
- run: scripts/get_version.sh > workspace/version.txt
990990
- persist_to_workspace:
991991
root: workspace

cmake/EthCompilerSettings.cmake

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,6 @@ if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MA
142142
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s WASM=1")
143143
# Set webassembly build to synchronous loading.
144144
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s WASM_ASYNC_COMPILATION=0")
145-
# Output a single js file with the wasm binary embedded as base64 string.
146-
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s SINGLE_FILE=1")
147145
# Allow new functions to be added to the wasm module via addFunction.
148146
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s ALLOW_TABLE_GROWTH=1")
149147
# Disable warnings about not being pure asm.js due to memory growth.

cmake/templates/license.h.in

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,36 @@ evmc:
137137
See the License for the specific language governing permissions and
138138
limitations under the License.
139139

140+
mini-lz4:
141+
The file scripts/ci/mini-lz4.js is derived from the emscripten adaptation of
142+
node-lz4 and licensed under the following terms:
143+
144+
Copyright (c) 2012 Pierre Curto
145+
146+
Permission is hereby granted, free of charge, to any person obtaining a copy
147+
of this software and associated documentation files (the "Software"), to deal
148+
in the Software without restriction, including without limitation the rights
149+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
150+
copies of the Software, and to permit persons to whom the Software is
151+
furnished to do so, subject to the following conditions:
152+
153+
The above copyright notice and this permission notice shall be included in
154+
all copies or substantial portions of the Software.
155+
156+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
157+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
158+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
159+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
160+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
161+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
162+
THE SOFTWARE.
163+
164+
base64:
165+
The file scripts/ci/base64DecToArr.js is derived from a code example
166+
in the MDN Web Docs, which permits use under CC0 terms:
167+
168+
Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/
169+
140170

141171
All other code is licensed under GPL version 3:
142172

scripts/ci/base64DecToArr.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
function base64DecToArr (sBase64) {
2+
/*\
3+
|*|
4+
|*| Base64 / binary data / UTF-8 strings utilities
5+
|*|
6+
|*| https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding
7+
|*|
8+
\*/
9+
10+
/* Array of bytes to Base64 string decoding */
11+
12+
function b64ToUint6 (nChr) {
13+
14+
return nChr > 64 && nChr < 91 ?
15+
nChr - 65
16+
: nChr > 96 && nChr < 123 ?
17+
nChr - 71
18+
: nChr > 47 && nChr < 58 ?
19+
nChr + 4
20+
: nChr === 43 ?
21+
62
22+
: nChr === 47 ?
23+
63
24+
:
25+
0;
26+
27+
}
28+
29+
var
30+
nInLen = sBase64.length,
31+
nOutLen = nInLen * 3 + 1 >> 2, taBytes = new Uint8Array(nOutLen);
32+
33+
for (var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) {
34+
nMod4 = nInIdx & 3;
35+
nUint24 |= b64ToUint6(sBase64.charCodeAt(nInIdx)) << 6 * (3 - nMod4);
36+
if (nMod4 === 3 || nInLen - nInIdx === 1) {
37+
for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) {
38+
taBytes[nOutIdx] = nUint24 >>> (16 >>> nMod3 & 24) & 255;
39+
}
40+
nUint24 = 0;
41+
42+
}
43+
}
44+
45+
return taBytes;
46+
}

scripts/ci/build_emscripten.sh

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ else
4040
BUILD_DIR="$1"
4141
fi
4242

43+
apt-get update && apt-get install lz4
44+
4345
WORKSPACE=/root/project
4446

4547
cd $WORKSPACE
@@ -71,8 +73,8 @@ make soljson
7173

7274
cd ..
7375
mkdir -p upload
74-
cp "$BUILD_DIR/libsolc/soljson.js" upload/
75-
cp "$BUILD_DIR/libsolc/soljson.js" ./
76+
scripts/ci/pack_soljson.sh "$BUILD_DIR/libsolc/soljson.js" "$BUILD_DIR/libsolc/soljson.wasm" upload/soljson.js
77+
cp upload/soljson.js ./
7678

7779
OUTPUT_SIZE=$(ls -la soljson.js)
7880

scripts/ci/mini-lz4.js

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
function uncompress(source, uncompressedSize) {
2+
/*
3+
based off https://github.com/emscripten-core/emscripten/blob/main/third_party/mini-lz4.js
4+
The license only applies to the body of this function (``uncompress``).
5+
====
6+
MiniLZ4: Minimal LZ4 block decoding and encoding.
7+
8+
based off of node-lz4, https://github.com/pierrec/node-lz4
9+
10+
====
11+
Copyright (c) 2012 Pierre Curto
12+
13+
Permission is hereby granted, free of charge, to any person obtaining a copy
14+
of this software and associated documentation files (the "Software"), to deal
15+
in the Software without restriction, including without limitation the rights
16+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17+
copies of the Software, and to permit persons to whom the Software is
18+
furnished to do so, subject to the following conditions:
19+
20+
The above copyright notice and this permission notice shall be included in
21+
all copies or substantial portions of the Software.
22+
23+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29+
THE SOFTWARE.
30+
====
31+
32+
changes have the same license
33+
*/
34+
/**
35+
* Decode a block. Assumptions: input contains all sequences of a
36+
* chunk, output is large enough to receive the decoded data.
37+
* If the output buffer is too small, an error will be thrown.
38+
* If the returned value is negative, an error occurred at the returned offset.
39+
*
40+
* @param {ArrayBufferView} input input data
41+
* @param {ArrayBufferView} output output data
42+
* @param {number=} sIdx
43+
* @param {number=} eIdx
44+
* @return {number} number of decoded bytes
45+
* @private
46+
*/
47+
function uncompressBlock (input, output, sIdx, eIdx) {
48+
sIdx = sIdx || 0
49+
eIdx = eIdx || (input.length - sIdx)
50+
// Process each sequence in the incoming data
51+
for (var i = sIdx, n = eIdx, j = 0; i < n;) {
52+
var token = input[i++]
53+
54+
// Literals
55+
var literals_length = (token >> 4)
56+
if (literals_length > 0) {
57+
// length of literals
58+
var l = literals_length + 240
59+
while (l === 255) {
60+
l = input[i++]
61+
literals_length += l
62+
}
63+
64+
// Copy the literals
65+
var end = i + literals_length
66+
while (i < end) output[j++] = input[i++]
67+
68+
// End of buffer?
69+
if (i === n) return j
70+
}
71+
72+
// Match copy
73+
// 2 bytes offset (little endian)
74+
var offset = input[i++] | (input[i++] << 8)
75+
76+
// XXX 0 is an invalid offset value
77+
if (offset === 0) return j
78+
if (offset > j) return -(i-2)
79+
80+
// length of match copy
81+
var match_length = (token & 0xf)
82+
var l = match_length + 240
83+
while (l === 255) {
84+
l = input[i++]
85+
match_length += l
86+
}
87+
// Copy the match
88+
var pos = j - offset // position of the match copy in the current output
89+
var end = j + match_length + 4 // minmatch = 4
90+
while (j < end) output[j++] = output[pos++]
91+
}
92+
93+
return j
94+
}
95+
var result = new ArrayBuffer(uncompressedSize);
96+
var sourceIndex = 0;
97+
var destIndex = 0;
98+
var blockSize;
99+
while((blockSize = (source[sourceIndex] | (source[sourceIndex + 1] << 8) | (source[sourceIndex + 2] << 16) | (source[sourceIndex + 3] << 24))) > 0)
100+
{
101+
sourceIndex += 4;
102+
if (blockSize & 0x80000000)
103+
{
104+
blockSize &= 0x7FFFFFFFF;
105+
for (var i = 0; i < blockSize; i++) {
106+
result[destIndex++] = source[sourceIndex++];
107+
}
108+
}
109+
else
110+
{
111+
destIndex += uncompressBlock(source, new Uint8Array(result, destIndex, uncompressedSize - destIndex), sourceIndex, sourceIndex + blockSize);
112+
sourceIndex += blockSize;
113+
}
114+
}
115+
return new Uint8Array(result, 0, uncompressedSize);
116+
}

scripts/ci/pack_soljson.sh

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
script_dir="$(realpath "$(dirname "$0")")"
5+
soljson_js="$1"
6+
soljson_wasm="$2"
7+
soljson_wasm_size=$(wc -c "${soljson_wasm}" | cut -d ' ' -f 1)
8+
output="$3"
9+
10+
(( $# == 3 )) || { >&2 echo "Usage: $0 soljson.js soljson.wasm packed_soljson.js"; exit 1; }
11+
12+
# If this changes in an emscripten update, it's probably nothing to worry about,
13+
# but we should double-check when it happens and adjust the tail command below.
14+
[[ $(head -c 5 "${soljson_js}") == "null;" ]] || { >&2 echo 'Expected soljson.js to start with "null;"'; exit 1; }
15+
16+
echo "Packing $soljson_js and $soljson_wasm to $output."
17+
(
18+
echo -n 'var Module = Module || {}; Module["wasmBinary"] = '
19+
echo -n '(function(source, uncompressedSize) {'
20+
# Note that base64DecToArr assumes no trailing equals signs.
21+
cpp "${script_dir}/base64DecToArr.js" | grep -v "^#.*"
22+
# Note that mini-lz4.js assumes no file header and no frame crc checksums.
23+
cpp "${script_dir}/mini-lz4.js" | grep -v "^#.*"
24+
echo 'return uncompress(base64DecToArr(source), uncompressedSize);})('
25+
echo -n '"'
26+
# We fix lz4 format settings, remove the 8 bytes file header and remove the trailing equals signs of the base64 encoding.
27+
lz4c --no-frame-crc --best --favor-decSpeed "${soljson_wasm}" - | tail -c +8 | base64 -w 0 | sed 's/[^A-Za-z0-9\+\/]//g'
28+
echo '",'
29+
echo -n "${soljson_wasm_size});"
30+
# Remove "null;" from the js wrapper.
31+
tail -c +6 "${soljson_js}"
32+
) > "$output"
33+
34+
echo "Testing $output."
35+
echo "process.stdout.write(require('$(realpath "${output}")').wasmBinary)" | node | cmp "${soljson_wasm}" && echo "Binaries match."
36+
# Allow the wasm binary to be garbage collected after compilation.
37+
echo 'Module["wasmBinary"] = undefined;' >> "${output}"

0 commit comments

Comments
 (0)