Bug 1612534 - Use 'wat' crate for wasmTextToBinary. r=lth

This commit removes the old WasmTextToBinary implementation and replaces
it with a stub that calls into the rust wat implementation.

The old wasmTextToBinary function took an optional boolean parameter to
indicate that additional metadata was desired. This extra metadata was
a list of offsets of instructions in the code section. I'm not sure if
this was intentional or not, but it looks like it only includes root
expressions of nested s-exprs.

These offsets were used in two tests, debug/wasm-breakpoints.js and a
wasm/regress test. Adding this functionality into 'wat' proved to be a large
change for a function that didn't seem to have much use cases. A new
wasmCodeOffsets function was added to replicate this feature. It's implemented
in rust using the 'wasmparser' crate that cranelift uses. When cranelift is
compiled, this shouldn't result in an increased binary size. If the compile
time or binary size proves to be an issue in non-cranelift builds, I think
we can make this a conditional feature for JS-shells only.

Differential Revision: https://phabricator.services.mozilla.com/D67245

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Ryan Hunt 2020-03-18 20:37:52 +00:00
Родитель 84f6c5cca3
Коммит f237c01fda
12 изменённых файлов: 268 добавлений и 9181 удалений

37
Cargo.lock сгенерированный
Просмотреть файл

@ -2127,6 +2127,7 @@ dependencies = [
"mozglue-static",
"mozilla-central-workspace-hack",
"smoosh",
"wasm-rust",
]
[[package]]
@ -2178,6 +2179,12 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
[[package]]
name = "leb128"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a"
[[package]]
name = "libc"
version = "0.2.59"
@ -4668,9 +4675,9 @@ checksum = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1"
[[package]]
name = "unicode-width"
version = "0.1.4"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
[[package]]
name = "unicode-xid"
@ -4793,12 +4800,38 @@ dependencies = [
"urlencoding",
]
[[package]]
name = "wasm-rust"
version = "0.1.0"
dependencies = [
"wasmparser",
"wat",
]
[[package]]
name = "wasmparser"
version = "0.48.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "073da89bf1c84db000dd68ce660c1b4a08e3a2d28fd1e3394ab9e7abdde4a0f8"
[[package]]
name = "wast"
version = "11.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df4d67ba9266f4fcaf2e8a1afadc5e2a959e51aecc07b1ecbdf85a6ddaf08bde"
dependencies = [
"leb128",
]
[[package]]
name = "wat"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a9400dc1c8512087b2d974b1b9b0a6c4e6e26e7e8acf629e3e351165a1ed301"
dependencies = [
"wast",
]
[[package]]
name = "webdriver"
version = "0.40.2"

Просмотреть файл

@ -91,7 +91,7 @@
#include "wasm/WasmJS.h"
#include "wasm/WasmModule.h"
#include "wasm/WasmSignalHandlers.h"
#include "wasm/WasmTextToBinary.h"
#include "wasm/WasmTesting.h"
#include "wasm/WasmTypes.h"
#include "debugger/DebugAPI-inl.h"
@ -917,26 +917,12 @@ static bool WasmTextToBinary(JSContext* cx, unsigned argc, Value* vp) {
return false;
}
bool withOffsets = false;
if (args.hasDefined(1)) {
if (!args[1].isBoolean()) {
ReportUsageErrorASCII(cx, callee,
"Second argument, if present, must be a boolean");
return false;
}
withOffsets = ToBoolean(args[1]);
}
uintptr_t stackLimit = GetNativeStackLimit(cx);
wasm::Bytes bytes;
UniqueChars error;
wasm::Uint32Vector offsets;
if (!wasm::TextToBinary(twoByteChars.twoByteChars(), textLen, stackLimit,
&bytes, &offsets, &error)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_WASM_TEXT_FAIL,
error.get() ? error.get() : "out of memory");
if (!wasm::TextToBinary(twoByteChars.twoByteChars(), textLen, &bytes,
&error)) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_WASM_TEXT_FAIL,
error.get() ? error.get() : "out of memory");
return false;
}
@ -948,21 +934,38 @@ static bool WasmTextToBinary(JSContext* cx, unsigned argc, Value* vp) {
memcpy(binary->as<TypedArrayObject>().dataPointerUnshared(), bytes.begin(),
bytes.length());
if (!withOffsets) {
args.rval().setObject(*binary);
return true;
}
args.rval().setObject(*binary);
return true;
}
RootedObject obj(cx, JS_NewPlainObject(cx));
if (!obj) {
static bool WasmCodeOffsets(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
RootedObject callee(cx, &args.callee());
if (!args.requireAtLeast(cx, "wasmCodeOffsets", 1)) {
return false;
}
constexpr unsigned propAttrs = JSPROP_ENUMERATE;
if (!JS_DefineProperty(cx, obj, "binary", binary, propAttrs)) {
if (!args.get(0).isObject()) {
JS_ReportErrorASCII(cx, "argument is not an object");
return false;
}
SharedMem<uint8_t*> bytes;
size_t byteLength;
JSObject* bufferObject = &args[0].toObject();
JSObject* unwrappedBufferObject = CheckedUnwrapStatic(bufferObject);
if (!unwrappedBufferObject ||
!IsBufferSource(unwrappedBufferObject, &bytes, &byteLength)) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_BAD_BUF_ARG);
return false;
}
wasm::Uint32Vector offsets;
wasm::CodeOffsets(bytes.unwrap(), byteLength, &offsets);
RootedObject jsOffsets(cx, JS::NewArrayObject(cx, offsets.length()));
if (!jsOffsets) {
return false;
@ -974,11 +977,7 @@ static bool WasmTextToBinary(JSContext* cx, unsigned argc, Value* vp) {
return false;
}
}
if (!JS_DefineProperty(cx, obj, "offsets", jsOffsets, propAttrs)) {
return false;
}
args.rval().setObject(*obj);
args.rval().setObject(*jsOffsets);
return true;
}
@ -6715,6 +6714,11 @@ gc::ZealModeHelpText),
"wasmTextToBinary(str)",
" Translates the given text wasm module into its binary encoding."),
JS_FN_HELP("wasmCodeOffsets", WasmCodeOffsets, 1, 0,
"wasmCodeOffsets(binary)",
" Decodes the given wasm binary to find the offsets of every instruction in the"
" code section."),
JS_FN_HELP("wasmExtractCode", WasmExtractCode, 1, 0,
"wasmExtractCode(module[, tier])",
" Extracts generated machine code from WebAssembly.Module. The tier is a string,\n"

Просмотреть файл

@ -65,9 +65,9 @@ const unusedValuesError = /unused values not explicitly dropped by end of block/
function jsify(wasmVal) {
if (wasmVal === 'nan')
return NaN;
if (wasmVal === 'infinity')
if (wasmVal === 'inf')
return Infinity;
if (wasmVal === '-infinity')
if (wasmVal === '-inf')
return Infinity;
if (wasmVal === '-0')
return -0;

Просмотреть файл

@ -13,6 +13,7 @@ baldrdash = { path = "../../wasm/cranelift", optional = true }
encoding_c = "0.9.5"
encoding_c_mem = "0.2.4"
smoosh = { path = "../../frontend/smoosh", optional = true }
wasm-rust = { path = "../../wasm/rust" }
mozilla-central-workspace-hack = { path = "../../../../build/workspace-hack" }
mozglue-static = { path = "../../../../mozglue/static/rust" }

Просмотреть файл

@ -21,3 +21,5 @@ extern crate mozglue_static;
#[cfg(feature = "smoosh")]
extern crate smoosh;
extern crate wasm_rust;

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,72 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=2 et sw=2 tw=80:
*
* Copyright 2015 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "wasm/WasmTesting.h"
#include <inttypes.h>
#include <stdbool.h>
#include <stddef.h>
#include "wasm/WasmTypes.h"
extern "C" {
bool wasm_text_to_binary(const char16_t* text, size_t text_len,
uint8_t** out_bytes, size_t* out_bytes_len,
uint8_t** out_error, size_t* out_error_len);
void wasm_code_offsets(const uint8_t* bytes, size_t bytes_len,
uint32_t** out_offsets, size_t* out_offset_len);
} // extern "C"
bool wasm::TextToBinary(const char16_t* text, size_t textLen, Bytes* bytes,
UniqueChars* error) {
uint8_t* outBytes = nullptr;
size_t outBytesLength = 0;
uint8_t* outError = nullptr;
size_t outErrorLength = 0;
bool result = wasm_text_to_binary(text, textLen, &outBytes, &outBytesLength,
&outError, &outErrorLength);
if (result) {
MOZ_ASSERT(outBytes);
MOZ_ASSERT(outBytesLength > 0);
bytes->replaceRawBuffer(outBytes, outBytesLength);
return true;
}
MOZ_ASSERT(outError);
MOZ_ASSERT(outErrorLength > 0);
*error = UniqueChars{(char*)outError};
return false;
}
void wasm::CodeOffsets(const uint8_t* bytes, size_t bytesLen,
Uint32Vector* offsets) {
uint32_t* outOffsets = nullptr;
size_t outOffsetsLength = 0;
wasm_code_offsets(bytes, bytesLen, &outOffsets, &outOffsetsLength);
if (outOffsets) {
MOZ_ASSERT(outOffsetsLength > 0);
offsets->replaceRawBuffer(outOffsets, outOffsetsLength);
} else {
offsets->clear();
}
}

Просмотреть файл

@ -1,7 +1,7 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=2 et sw=2 tw=80:
*
* Copyright 2015 Mozilla Foundation
* Copyright 2020 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,10 +16,8 @@
* limitations under the License.
*/
#ifndef wasm_text_to_binary_h
#define wasm_text_to_binary_h
#include "wasm/WasmTypes.h"
#ifndef wasm_testing_h
#define wasm_testing_h
namespace js {
namespace wasm {
@ -29,11 +27,18 @@ namespace wasm {
// other than out-of-memory an error message string will be stored in 'error'.
extern MOZ_MUST_USE bool TextToBinary(const char16_t* text, size_t textLen,
uintptr_t stackLimit, Bytes* bytes,
Uint32Vector* offsets,
UniqueChars* error);
Bytes* bytes, UniqueChars* error);
// Decode the binary wasm module given and return the offsets of all
// instructions inside of the the code section.
//
// This function is used exclusively for testing and handles errors by
// returning an empty offset array.
extern void CodeOffsets(const uint8_t* bytes, size_t bytesLen,
Uint32Vector* offsets);
} // namespace wasm
} // namespace js
#endif // wasm_text_to_binary_h
#endif // wasm_testing_h

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -40,7 +40,7 @@ UNIFIED_SOURCES += [
'WasmSignalHandlers.cpp',
'WasmStubs.cpp',
'WasmTable.cpp',
'WasmTextToBinary.cpp',
'WasmTesting.cpp',
'WasmTypes.cpp',
'WasmValidate.cpp'
]

Просмотреть файл

@ -0,0 +1,13 @@
[package]
name = "wasm-rust"
version = "0.1.0"
authors = ["The Spidermonkey developers"]
edition = "2018"
[lib]
crate-type = ["rlib"]
name = "wasm_rust"
[dependencies]
wat = { version = "1.0.12" }
wasmparser = { version = "0.48.2" }

Просмотреть файл

@ -0,0 +1,91 @@
/* Copyright 2020 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#[no_mangle]
pub unsafe extern "C" fn wasm_text_to_binary(
text: *const u16,
text_len: usize,
out_bytes: *mut *mut u8,
out_bytes_len: *mut usize,
out_error: *mut *mut u8,
out_error_len: *mut usize,
) -> bool {
let text_slice = std::slice::from_raw_parts(text, text_len);
let text = String::from_utf16_lossy(text_slice);
match wat::parse_str(&text) {
Ok(bytes) => {
let bytes_box = bytes.into_boxed_slice();
let bytes_slice = Box::leak(bytes_box);
out_bytes.write(bytes_slice.as_mut_ptr());
out_bytes_len.write(bytes_slice.len());
true
}
Err(error) => {
let error = Box::leak(format!("{}\0", error).into_boxed_str());
out_error.write(error.as_mut_ptr());
out_error_len.write(error.len());
false
}
}
}
#[no_mangle]
pub unsafe extern "C" fn wasm_code_offsets(
bytes: *const u8,
bytes_len: usize,
out_offsets: *mut *mut u32,
out_offsets_len: *mut usize,
) {
fn code_offsets(bytes: &[u8]) -> Vec<u32> {
use wasmparser::*;
if bytes.is_empty() {
return Vec::new();
}
let mut offsets = Vec::new();
let mut parser = Parser::new(bytes);
let mut next_input = ParserInput::Default;
while !parser.eof() {
let offset = parser.current_position();
match parser.read_with_input(next_input) {
ParserState::BeginSection { code, .. } if *code != SectionCode::Code => {
next_input = ParserInput::SkipSection;
}
ParserState::CodeOperator(..) => {
offsets.push(offset as u32);
next_input = ParserInput::Default
}
_ => next_input = ParserInput::Default,
}
}
offsets
}
let bytes = std::slice::from_raw_parts(bytes, bytes_len);
let offsets = code_offsets(bytes);
if offsets.len() == 0 {
out_offsets.write(std::ptr::null_mut());
out_offsets_len.write(0);
} else {
let offsets_box = offsets.into_boxed_slice();
let offsets_slice = Box::leak(offsets_box);
out_offsets.write(offsets_slice.as_mut_ptr());
out_offsets_len.write(offsets_slice.len());
}
}