Diff
Modified: branches/safari-603-branch/JSTests/ChangeLog (210421 => 210422)
--- branches/safari-603-branch/JSTests/ChangeLog 2017-01-06 01:49:36 UTC (rev 210421)
+++ branches/safari-603-branch/JSTests/ChangeLog 2017-01-06 01:49:39 UTC (rev 210422)
@@ -1,5 +1,24 @@
2017-01-05 Matthew Hanson <matthew_han...@apple.com>
+ Merge r210282. rdar://problem/29760326
+
+ 2017-01-04 JF Bastien <jfbast...@apple.com>
+
+ WebAssembly JS API: add Module.sections
+ https://bugs.webkit.org/show_bug.cgi?id=165159
+ <rdar://problem/29760326>
+
+ Reviewed by Mark Lam.
+
+ As described here: https://github.com/WebAssembly/design/blob/master/JS.md#webassemblymodulecustomsections
+
+ * wasm/Builder.js: allow custom sections to be duplicated
+ * wasm/js-api/Module.customSection.js: Added.
+ (assert.throws.WebAssembly.Module.prototype.customSections):
+ (assert.eq):
+
+2017-01-05 Matthew Hanson <matthew_han...@apple.com>
+
Merge r210229. rdar://problem/29760322
2017-01-02 JF Bastien <jfbast...@apple.com>
Modified: branches/safari-603-branch/JSTests/wasm/Builder.js (210421 => 210422)
--- branches/safari-603-branch/JSTests/wasm/Builder.js 2017-01-06 01:49:36 UTC (rev 210421)
+++ branches/safari-603-branch/JSTests/wasm/Builder.js 2017-01-06 01:49:39 UTC (rev 210422)
@@ -713,7 +713,8 @@
if (this._checked) {
// Check uniqueness.
for (const s of this._sections)
- assert.falsy(s.name === name && s.id === number, `Cannot have two sections with the same name "${name}" and ID ${number}`);
+ if (number !== _unknownSectionId)
+ assert.falsy(s.name === name && s.id === number, `Cannot have two sections with the same name "${name}" and ID ${number}`);
// Check ordering.
if ((number !== _unknownSectionId) && (this._sections.length !== 0)) {
for (let i = this._sections.length - 1; i >= 0; --i) {
Added: branches/safari-603-branch/JSTests/wasm/js-api/Module.customSection.js (0 => 210422)
--- branches/safari-603-branch/JSTests/wasm/js-api/Module.customSection.js (rev 0)
+++ branches/safari-603-branch/JSTests/wasm/js-api/Module.customSection.js 2017-01-06 01:49:39 UTC (rev 210422)
@@ -0,0 +1,76 @@
+import Builder from '../Builder.js';
+import * as assert from '../assert.js';
+
+assert.throws(() => WebAssembly.Module.prototype.customSections(undefined, ""), TypeError, `WebAssembly.Module.prototype.customSections called with non WebAssembly.Module |this| value`);
+
+{
+ const empty = new WebAssembly.Module((new Builder()).WebAssembly().get());
+ assert.isArray(empty.customSections(""));
+ assert.eq(empty.customSections("").length, 0);
+}
+
+{
+ const single = new WebAssembly.Module((new Builder())
+ .Unknown("hello").Byte(0x00).Byte(0x42).Byte(0xFF).End()
+ .WebAssembly().get());
+ assert.eq(single.customSections("").length, 0);
+ const hello = single.customSections("hello");
+ assert.eq(hello.length, 1);
+ assert.eq(hello[0].byteLength, 3);
+ const helloI8 = new Int8Array(hello[0]);
+ assert.eq(helloI8[0], 0x00);
+ assert.eq(helloI8[1], 0x42);
+ assert.eq(helloI8[2], -1);
+}
+
+{
+ const unicode = new WebAssembly.Module((new Builder())
+ .Unknown("👨❤️💋👨").Byte(42).End()
+ .WebAssembly().get());
+ const family = unicode.customSections("👨❤️💋👨");
+ assert.eq(family.length, 1);
+ assert.eq(family[0].byteLength, 1);
+ const familyI8 = new Int8Array(family[0]);
+ assert.eq(familyI8[0], 42);
+}
+
+{
+ const many = new WebAssembly.Module((new Builder())
+ .Unknown("zero").Byte(0).End()
+ .Unknown("one").Byte(1).Byte(1).End()
+ .Unknown("one").Byte(2).Byte(2).Byte(2).End()
+ .Unknown("two").Byte(3).Byte(3).Byte(3).Byte(3).End()
+ .Unknown("one").Byte(4).Byte(4).Byte(4).Byte(4).Byte(4).End()
+ .WebAssembly().get());
+
+ const zero = many.customSections("zero");
+ assert.eq(zero.length, 1);
+ assert.eq(zero[0].byteLength, 1);
+ const zeroI8 = new Int8Array(zero[0]);
+ assert.eq(zeroI8[0], 0);
+
+ const two = many.customSections("two");
+ assert.eq(two.length, 1);
+ assert.eq(two[0].byteLength, 4);
+ const twoI8 = new Int8Array(two[0]);
+ assert.eq(twoI8[0], 3);
+ assert.eq(twoI8[1], 3);
+ assert.eq(twoI8[2], 3);
+ assert.eq(twoI8[3], 3);
+
+ const _one_ = many.customSections("one");
+ assert.eq(one.length, 3);
+ let seen = 0;
+ const expect = [
+ [1, 1],
+ [2, 2, 2],
+ [4, 4, 4, 4, 4],
+ ];
+ for (const section of one) {
+ assert.eq(section.byteLength, expect[seen].length);
+ const I8 = new Int8Array(section);
+ for (let i = 0; i < expect[seen].length; ++i)
+ assert.eq(I8[i], expect[seen][i]);
+ ++seen;
+ }
+}
Modified: branches/safari-603-branch/Source/_javascript_Core/ChangeLog (210421 => 210422)
--- branches/safari-603-branch/Source/_javascript_Core/ChangeLog 2017-01-06 01:49:36 UTC (rev 210421)
+++ branches/safari-603-branch/Source/_javascript_Core/ChangeLog 2017-01-06 01:49:39 UTC (rev 210422)
@@ -1,5 +1,28 @@
2017-01-05 Matthew Hanson <matthew_han...@apple.com>
+ Merge r210282. rdar://problem/29760326
+
+ 2017-01-04 JF Bastien <jfbast...@apple.com>
+
+ WebAssembly JS API: add Module.sections
+ https://bugs.webkit.org/show_bug.cgi?id=165159
+ <rdar://problem/29760326>
+
+ Reviewed by Mark Lam.
+
+ As described in: https://github.com/WebAssembly/design/blob/master/JS.md#webassemblymodulecustomsections
+
+ This was added for Emscripten, and is likely to be used soon.
+
+ * wasm/WasmFormat.h: custom sections are just name + bytes
+ * wasm/WasmModuleParser.cpp: parse them, instead of skipping over
+ * wasm/WasmModuleParser.h:
+ * wasm/js/WebAssemblyModulePrototype.cpp: construct the Array of
+ ArrayBuffer as described in the spec
+ (JSC::webAssemblyModuleProtoCustomSections):
+
+2017-01-05 Matthew Hanson <matthew_han...@apple.com>
+
Merge r210229. rdar://problem/29760322
2017-01-02 JF Bastien <jfbast...@apple.com>
Modified: branches/safari-603-branch/Source/_javascript_Core/wasm/WasmFormat.h (210421 => 210422)
--- branches/safari-603-branch/Source/_javascript_Core/wasm/WasmFormat.h 2017-01-06 01:49:36 UTC (rev 210421)
+++ branches/safari-603-branch/Source/_javascript_Core/wasm/WasmFormat.h 2017-01-06 01:49:39 UTC (rev 210422)
@@ -220,6 +220,11 @@
bool m_isImport { false };
bool m_isValid { false };
};
+
+struct CustomSection {
+ String name;
+ Vector<uint8_t> payload;
+};
struct ModuleInformation {
Vector<Import> imports;
@@ -235,6 +240,8 @@
TableInformation tableInformation;
Vector<Global> globals;
unsigned firstInternalGlobal { 0 };
+ Vector<CustomSection> customSections;
+
size_t functionIndexSpaceSize() const { return importFunctionSignatureIndices.size() + internalFunctionSignatureIndices.size(); }
bool isImportedFunctionFromFunctionIndexSpace(size_t functionIndex) const
{
Modified: branches/safari-603-branch/Source/_javascript_Core/wasm/WasmModuleParser.cpp (210421 => 210422)
--- branches/safari-603-branch/Source/_javascript_Core/wasm/WasmModuleParser.cpp 2017-01-06 01:49:36 UTC (rev 210421)
+++ branches/safari-603-branch/Source/_javascript_Core/wasm/WasmModuleParser.cpp 2017-01-06 01:49:39 UTC (rev 210422)
@@ -87,8 +87,7 @@
#undef WASM_SECTION_PARSE
case Section::Unknown: {
- // Ignore section's name LEB and bytes: they're already included in sectionLength.
- m_offset += sectionLength;
+ WASM_FAIL_IF_HELPER_FAILS(parseCustom(sectionLength));
break;
}
}
@@ -600,7 +599,31 @@
}
return { };
}
+
+auto ModuleParser::parseCustom(uint32_t sectionLength) -> PartialResult
+{
+ const uint32_t customSectionStartOffset = m_offset;
+ CustomSection section;
+ uint32_t customSectionNumber = m_result.module->customSections.size() + 1;
+ uint32_t nameLen;
+ WASM_PARSER_FAIL_IF(!m_result.module->customSections.tryReserveCapacity(customSectionNumber), "can't allocate enough memory for ", customSectionNumber, "th custom section");
+ WASM_PARSER_FAIL_IF(!parseVarUInt32(nameLen), "can't get ", customSectionNumber, "th custom section's name length");
+ WASM_PARSER_FAIL_IF(!consumeUTF8String(section.name, nameLen), "nameLen get ", customSectionNumber, "th custom section's name of length ", nameLen);
+
+ uint32_t payloadBytes = sectionLength - (m_offset - customSectionStartOffset);
+ WASM_PARSER_FAIL_IF(!section.payload.tryReserveCapacity(payloadBytes), "can't allocate enough memory for ", customSectionNumber, "th custom section's ", payloadBytes, " bytes");
+ for (uint32_t byteNumber = 0; byteNumber < payloadBytes; ++byteNumber) {
+ uint8_t byte;
+ WASM_PARSER_FAIL_IF(!parseUInt8(byte), "can't get ", byteNumber, "th data byte from ", customSectionNumber, "th custom section");
+ section.payload.uncheckedAppend(byte);
+ }
+
+ m_result.module->customSections.uncheckedAppend(WTFMove(section));
+
+ return { };
+}
+
} } // namespace JSC::Wasm
#endif // ENABLE(WEBASSEMBLY)
Modified: branches/safari-603-branch/Source/_javascript_Core/wasm/WasmModuleParser.h (210421 => 210422)
--- branches/safari-603-branch/Source/_javascript_Core/wasm/WasmModuleParser.h 2017-01-06 01:49:36 UTC (rev 210421)
+++ branches/safari-603-branch/Source/_javascript_Core/wasm/WasmModuleParser.h 2017-01-06 01:49:39 UTC (rev 210422)
@@ -60,6 +60,7 @@
FOR_EACH_WASM_SECTION(WASM_SECTION_DECLARE_PARSER)
#undef WASM_SECTION_DECLARE_PARSER
+ PartialResult WARN_UNUSED_RETURN parseCustom(uint32_t);
PartialResult WARN_UNUSED_RETURN parseGlobalType(Global&);
PartialResult WARN_UNUSED_RETURN parseMemoryHelper(bool isImport);
PartialResult WARN_UNUSED_RETURN parseTableHelper(bool isImport);
Modified: branches/safari-603-branch/Source/_javascript_Core/wasm/js/WebAssemblyModulePrototype.cpp (210421 => 210422)
--- branches/safari-603-branch/Source/_javascript_Core/wasm/js/WebAssemblyModulePrototype.cpp 2017-01-06 01:49:36 UTC (rev 210421)
+++ branches/safari-603-branch/Source/_javascript_Core/wasm/js/WebAssemblyModulePrototype.cpp 2017-01-06 01:49:39 UTC (rev 210422)
@@ -28,9 +28,16 @@
#if ENABLE(WEBASSEMBLY)
+#include "ArrayBuffer.h"
#include "FunctionPrototype.h"
+#include "JSArrayBuffer.h"
#include "JSCInlines.h"
+#include "JSWebAssemblyModule.h"
+namespace JSC {
+static EncodedJSValue JSC_HOST_CALL webAssemblyModuleProtoCustomSections(ExecState*);
+}
+
#include "WebAssemblyModulePrototype.lut.h"
namespace JSC {
@@ -39,9 +46,45 @@
/* Source for WebAssemblyModulePrototype.lut.h
@begin prototypeTableWebAssemblyModule
+ customSections webAssemblyModuleProtoCustomSections DontEnum|Function 1
@end
*/
+EncodedJSValue JSC_HOST_CALL webAssemblyModuleProtoCustomSections(ExecState* exec)
+{
+ VM& vm = exec->vm();
+ auto* globalObject = exec->lexicalGlobalObject();
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+
+ JSWebAssemblyModule* module = jsDynamicCast<JSWebAssemblyModule*>(exec->thisValue());
+ if (!module)
+ throwException(exec, throwScope, createTypeError(exec, ASCIILiteral("WebAssembly.Module.prototype.customSections called with non WebAssembly.Module |this| value")));
+ RETURN_IF_EXCEPTION(throwScope, { });
+
+ const String sectionNameString = exec->argument(0).getString(exec);
+ RETURN_IF_EXCEPTION(throwScope, { });
+
+ JSArray* result = constructEmptyArray(exec, nullptr, globalObject);
+ RETURN_IF_EXCEPTION(throwScope, { });
+
+ const auto& customSections = module->moduleInformation().customSections;
+ for (const Wasm::CustomSection& section : customSections) {
+ if (section.name == sectionNameString) {
+ auto buffer = ArrayBuffer::tryCreate(section.payload.data(), section.payload.size());
+ if (!buffer)
+ throwException(exec, throwScope, createOutOfMemoryError(exec));
+
+ Structure* arrayBufferStructure = InternalFunction::createSubclassStructure(exec, JSValue(), globalObject->arrayBufferStructure(ArrayBufferSharingMode::Default));
+ RETURN_IF_EXCEPTION(throwScope, { });
+
+ result->push(exec, JSArrayBuffer::create(vm, arrayBufferStructure, WTFMove(buffer)));
+ RETURN_IF_EXCEPTION(throwScope, { });
+ }
+ }
+
+ return JSValue::encode(result);
+}
+
WebAssemblyModulePrototype* WebAssemblyModulePrototype::create(VM& vm, JSGlobalObject*, Structure* structure)
{
auto* object = new (NotNull, allocateCell<WebAssemblyModulePrototype>(vm.heap)) WebAssemblyModulePrototype(vm, structure);