| Differences between
and this patch
- a/Source/JavaScriptCore/ChangeLog +41 lines
Lines 1-3 a/Source/JavaScriptCore/ChangeLog_sec1
1
2016-09-26  Keith Miller  <keith_miller@apple.com>
2
3
        Add support for WASM Memory.
4
        https://bugs.webkit.org/show_bug.cgi?id=161710
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        This patch add initial support for WASM memory operations. First,
9
        it adds the concept of a WASM Module memory management object.
10
        This object currently mmaps a 32-bit address space for WASM use,
11
        although it marks all the memory outside the current breakpoint as
12
        PROT_NONE. For now, we do a range check on each store and load. In
13
        the future, we should change this to be an signal handler that
14
        checks what module the program trapped in.
15
16
        * testWASM.cpp:
17
        (runWASMTests):
18
        * wasm/WASMB3IRGenerator.cpp:
19
        (JSC::WASM::parseAndCompile):
20
        * wasm/WASMB3IRGenerator.h:
21
        * wasm/WASMFormat.h:
22
        (JSC::WASM::Memory::Memory):
23
        (JSC::WASM::Memory::~Memory):
24
        (JSC::WASM::Memory::memory):
25
        (JSC::WASM::Memory::size):
26
        (JSC::WASM::Memory::growMemory):
27
        (JSC::WASM::Memory::offsetOfSize):
28
        * wasm/WASMFunctionParser.h:
29
        (JSC::WASM::FunctionParser<Context>::parseExpression):
30
        * wasm/WASMModuleParser.cpp:
31
        (JSC::WASM::ModuleParser::parse):
32
        (JSC::WASM::ModuleParser::parseMemory):
33
        * wasm/WASMModuleParser.h:
34
        (JSC::WASM::ModuleParser::functionInformation):
35
        (JSC::WASM::ModuleParser::memory):
36
        * wasm/WASMOps.h:
37
        * wasm/WASMPlan.cpp:
38
        (JSC::WASM::Plan::Plan):
39
        * wasm/WASMPlan.h:
40
        * wasm/WASMSections.h:
41
1
2016-09-26  Don Olmstead  <don.olmstead@am.sony.com>
42
2016-09-26  Don Olmstead  <don.olmstead@am.sony.com>
2
43
3
        [JSC] Allow fixedExecutableMemoryPoolSize to be set during build
44
        [JSC] Allow fixedExecutableMemoryPoolSize to be set during build
- a/Source/JavaScriptCore/Configurations/ToolExecutable.xcconfig +1 lines
Lines 31-36 CODE_SIGN_ENTITLEMENTS_ios_minidom = entitlements.plist; a/Source/JavaScriptCore/Configurations/ToolExecutable.xcconfig_sec1
31
CODE_SIGN_ENTITLEMENTS_ios_testair = entitlements.plist;
31
CODE_SIGN_ENTITLEMENTS_ios_testair = entitlements.plist;
32
CODE_SIGN_ENTITLEMENTS_ios_testapi = entitlements.plist;
32
CODE_SIGN_ENTITLEMENTS_ios_testapi = entitlements.plist;
33
CODE_SIGN_ENTITLEMENTS_ios_testb3 = entitlements.plist;
33
CODE_SIGN_ENTITLEMENTS_ios_testb3 = entitlements.plist;
34
CODE_SIGN_ENTITLEMENTS_ios_testWASM = entitlements.plist;
34
CODE_SIGN_ENTITLEMENTS_ios_testRegExp = entitlements.plist;
35
CODE_SIGN_ENTITLEMENTS_ios_testRegExp = entitlements.plist;
35
36
36
SKIP_INSTALL = $(SKIP_INSTALL_$(FORCE_TOOL_INSTALL));
37
SKIP_INSTALL = $(SKIP_INSTALL_$(FORCE_TOOL_INSTALL));
- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj +8 lines
Lines 1204-1209 a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj_sec1
1204
		534C457C1BC72411007476A7 /* JSTypedArrayViewConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 534C457B1BC72411007476A7 /* JSTypedArrayViewConstructor.h */; };
1204
		534C457C1BC72411007476A7 /* JSTypedArrayViewConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 534C457B1BC72411007476A7 /* JSTypedArrayViewConstructor.h */; };
1205
		534C457E1BC72549007476A7 /* JSTypedArrayViewConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 534C457D1BC72549007476A7 /* JSTypedArrayViewConstructor.cpp */; };
1205
		534C457E1BC72549007476A7 /* JSTypedArrayViewConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 534C457D1BC72549007476A7 /* JSTypedArrayViewConstructor.cpp */; };
1206
		53529A4C1C457B75000B49C6 /* APIUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 53529A4B1C457B75000B49C6 /* APIUtils.h */; };
1206
		53529A4C1C457B75000B49C6 /* APIUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 53529A4B1C457B75000B49C6 /* APIUtils.h */; };
1207
		535557141D9D9EA5006D583B /* WASMMemory.h in Headers */ = {isa = PBXBuildFile; fileRef = 535557131D9D9EA5006D583B /* WASMMemory.h */; };
1208
		535557161D9DFA32006D583B /* WASMMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 535557151D9DFA32006D583B /* WASMMemory.cpp */; };
1207
		5370B4F51BF26202005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5370B4F31BF25EA2005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.cpp */; };
1209
		5370B4F51BF26202005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5370B4F31BF25EA2005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.cpp */; };
1208
		5370B4F61BF26205005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 5370B4F41BF25EA2005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.h */; };
1210
		5370B4F61BF26205005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 5370B4F41BF25EA2005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.h */; };
1209
		53917E7B1B7906FA000EBD33 /* JSGenericTypedArrayViewPrototypeFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = 53917E7A1B7906E4000EBD33 /* JSGenericTypedArrayViewPrototypeFunctions.h */; };
1211
		53917E7B1B7906FA000EBD33 /* JSGenericTypedArrayViewPrototypeFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = 53917E7A1B7906E4000EBD33 /* JSGenericTypedArrayViewPrototypeFunctions.h */; };
Lines 3418-3423 a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj_sec2
3418
		534C457B1BC72411007476A7 /* JSTypedArrayViewConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSTypedArrayViewConstructor.h; sourceTree = "<group>"; };
3420
		534C457B1BC72411007476A7 /* JSTypedArrayViewConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSTypedArrayViewConstructor.h; sourceTree = "<group>"; };
3419
		534C457D1BC72549007476A7 /* JSTypedArrayViewConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSTypedArrayViewConstructor.cpp; sourceTree = "<group>"; };
3421
		534C457D1BC72549007476A7 /* JSTypedArrayViewConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSTypedArrayViewConstructor.cpp; sourceTree = "<group>"; };
3420
		53529A4B1C457B75000B49C6 /* APIUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APIUtils.h; sourceTree = "<group>"; };
3422
		53529A4B1C457B75000B49C6 /* APIUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APIUtils.h; sourceTree = "<group>"; };
3423
		535557131D9D9EA5006D583B /* WASMMemory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WASMMemory.h; sourceTree = "<group>"; };
3424
		535557151D9DFA32006D583B /* WASMMemory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WASMMemory.cpp; sourceTree = "<group>"; };
3421
		5370B4F31BF25EA2005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AdaptiveInferredPropertyValueWatchpointBase.cpp; sourceTree = "<group>"; };
3425
		5370B4F31BF25EA2005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AdaptiveInferredPropertyValueWatchpointBase.cpp; sourceTree = "<group>"; };
3422
		5370B4F41BF25EA2005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AdaptiveInferredPropertyValueWatchpointBase.h; sourceTree = "<group>"; };
3426
		5370B4F41BF25EA2005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AdaptiveInferredPropertyValueWatchpointBase.h; sourceTree = "<group>"; };
3423
		53917E7A1B7906E4000EBD33 /* JSGenericTypedArrayViewPrototypeFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGenericTypedArrayViewPrototypeFunctions.h; sourceTree = "<group>"; };
3427
		53917E7A1B7906E4000EBD33 /* JSGenericTypedArrayViewPrototypeFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGenericTypedArrayViewPrototypeFunctions.h; sourceTree = "<group>"; };
Lines 5619-5624 a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj_sec3
5619
				53F40E901D5903020099A1B6 /* WASMOps.h */,
5623
				53F40E901D5903020099A1B6 /* WASMOps.h */,
5620
				7BC547D21B69599B00959B58 /* WASMFormat.h */,
5624
				7BC547D21B69599B00959B58 /* WASMFormat.h */,
5621
				53F40E8A1D5901BB0099A1B6 /* WASMFunctionParser.h */,
5625
				53F40E8A1D5901BB0099A1B6 /* WASMFunctionParser.h */,
5626
				535557151D9DFA32006D583B /* WASMMemory.cpp */,
5627
				535557131D9D9EA5006D583B /* WASMMemory.h */,
5622
				53F40E961D5A7BEC0099A1B6 /* WASMModuleParser.cpp */,
5628
				53F40E961D5A7BEC0099A1B6 /* WASMModuleParser.cpp */,
5623
				53F40E941D5A7AEF0099A1B6 /* WASMModuleParser.h */,
5629
				53F40E941D5A7AEF0099A1B6 /* WASMModuleParser.h */,
5624
				531374BE1D5CE95000AF7A0B /* WASMPlan.cpp */,
5630
				531374BE1D5CE95000AF7A0B /* WASMPlan.cpp */,
Lines 7759-7764 a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj_sec4
7759
				142E3138134FF0A600AFADB5 /* HandleStack.h in Headers */,
7765
				142E3138134FF0A600AFADB5 /* HandleStack.h in Headers */,
7760
				1478297B1379E8A800A7C2A3 /* HandleTypes.h in Headers */,
7766
				1478297B1379E8A800A7C2A3 /* HandleTypes.h in Headers */,
7761
				0F10F1A31C420BF0001C07D2 /* AirCustom.h in Headers */,
7767
				0F10F1A31C420BF0001C07D2 /* AirCustom.h in Headers */,
7768
				535557141D9D9EA5006D583B /* WASMMemory.h in Headers */,
7762
				14BA7A9813AADFF8005B7C2C /* Heap.h in Headers */,
7769
				14BA7A9813AADFF8005B7C2C /* Heap.h in Headers */,
7763
				0F32BD111BB34F190093A57F /* HeapHelperPool.h in Headers */,
7770
				0F32BD111BB34F190093A57F /* HeapHelperPool.h in Headers */,
7764
				C2DA778318E259990066FCB6 /* HeapInlines.h in Headers */,
7771
				C2DA778318E259990066FCB6 /* HeapInlines.h in Headers */,
Lines 9088-9093 a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj_sec5
9088
				0F5A1273192D9FDF008764A3 /* DFGDoesGC.cpp in Sources */,
9095
				0F5A1273192D9FDF008764A3 /* DFGDoesGC.cpp in Sources */,
9089
				0FD3C82614115D4000FD81CB /* DFGDriver.cpp in Sources */,
9096
				0FD3C82614115D4000FD81CB /* DFGDriver.cpp in Sources */,
9090
				0FF0F19E16B72A0B005DF95B /* DFGEdge.cpp in Sources */,
9097
				0FF0F19E16B72A0B005DF95B /* DFGEdge.cpp in Sources */,
9098
				535557161D9DFA32006D583B /* WASMMemory.cpp in Sources */,
9091
				0F8F14331ADF090100ED792C /* DFGEpoch.cpp in Sources */,
9099
				0F8F14331ADF090100ED792C /* DFGEpoch.cpp in Sources */,
9092
				0FBC0AE71496C7C400D4FBDD /* DFGExitProfile.cpp in Sources */,
9100
				0FBC0AE71496C7C400D4FBDD /* DFGExitProfile.cpp in Sources */,
9093
				A78A9774179738B8009DF744 /* DFGFailedFinalizer.cpp in Sources */,
9101
				A78A9774179738B8009DF744 /* DFGFailedFinalizer.cpp in Sources */,
- a/Source/JavaScriptCore/testWASM.cpp -48 / +510 lines
Lines 32-38 a/Source/JavaScriptCore/testWASM.cpp_sec1
32
#include "LLIntThunks.h"
32
#include "LLIntThunks.h"
33
#include "ProtoCallFrame.h"
33
#include "ProtoCallFrame.h"
34
#include "VM.h"
34
#include "VM.h"
35
#include "WASMMemory.h"
35
#include "WASMPlan.h"
36
#include "WASMPlan.h"
37
36
#include <wtf/DataLog.h>
38
#include <wtf/DataLog.h>
37
#include <wtf/LEBDecoder.h>
39
#include <wtf/LEBDecoder.h>
38
40
Lines 242-249 static void runWASMTests() a/Source/JavaScriptCore/testWASM.cpp_sec2
242
{
244
{
243
    {
245
    {
244
        // Generated from:
246
        // Generated from:
247
        // (module
248
        //  (memory 1)
249
        //  (func (export "i32_load8_s") (param $i i32) (param $ptr i32) (result i32)
250
        //   (i32.store (get_local $ptr) (get_local $i))
251
        //   (return (i32.load (get_local $ptr)))
252
        //   )
253
        //  )
254
        Vector<uint8_t> vector = {
255
            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
256
            0x02, 0x02, 0x01, 0x01, 0x02, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
257
            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x69, 0x33,
258
            0x32, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x38, 0x5f, 0x73, 0x00, 0x00, 0x0a, 0x95, 0x80, 0x80, 0x80,
259
            0x00, 0x01, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14, 0x01, 0x14, 0x00, 0x34, 0x03, 0x00, 0x14,
260
            0x01, 0x2b, 0x03, 0x00, 0x09, 0x0f
261
        };
262
263
        Plan plan(*vm, vector);
264
        if (plan.result.size() != 1 || !plan.result[0]) {
265
            dataLogLn("Module failed to compile correctly.");
266
            CRASH();
267
        }
268
269
        // Test this doesn't crash.
270
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(10) }), 0);
271
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(2) }), 100);
272
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(100) }), 1);
273
    }
274
275
    {
276
        // Generated from:
277
        // (module
278
        //  (memory 1)
279
        //  (func (export "i32_load8_s") (param $i i32) (param $ptr i32) (result i32)
280
        //   (i32.store (get_local $ptr) (get_local $i))
281
        //   (return (i32.load (get_local $ptr)))
282
        //   )
283
        //  )
284
        Vector<uint8_t> vector = {
285
            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
286
            0x02, 0x01, 0x01, 0x01, 0x01, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
287
            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x69, 0x33,
288
            0x32, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x38, 0x5f, 0x73, 0x00, 0x00, 0x0a, 0x95, 0x80, 0x80, 0x80,
289
            0x00, 0x01, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14, 0x01, 0x14, 0x00, 0x33, 0x02, 0x00, 0x14,
290
            0x01, 0x2a, 0x02, 0x00, 0x09, 0x0f
291
        };
292
293
        Plan plan(*vm, vector);
294
        if (plan.result.size() != 1 || !plan.result[0]) {
295
            dataLogLn("Module failed to compile correctly.");
296
            CRASH();
297
        }
298
299
        // Test this doesn't crash.
300
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(10) }), 0);
301
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(2) }), 100);
302
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(100) }), 1);
303
    }
304
305
    {
306
        // Generated from:
307
        //    (module
308
        //     (memory 1)
309
        //     (func (export "write_array") (param $x i32) (param $p i32) (param $length i32) (local $i i32)
310
        //      (set_local $i (i32.const 0))
311
        //      (block
312
        //       (loop
313
        //        (br_if 1 (i32.ge_u (get_local $i) (get_local $length)))
314
        //        (i32.store (i32.add (get_local $p) (i32.mul (get_local $i) (i32.const 4))) (get_local $x))
315
        //        (set_local $i (i32.add (i32.const 1) (get_local $i)))
316
        //        (br 0)
317
        //        )
318
        //       )
319
        //      (return)
320
        //      )
321
        //     )
322
        Vector<uint8_t> vector = {
323
            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
324
            0x03, 0x01, 0x01, 0x01, 0x00, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
325
            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x77, 0x72,
326
            0x69, 0x74, 0x65, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x00, 0x00, 0x0a, 0xb2, 0x80, 0x80, 0x80,
327
            0x00, 0x01, 0xac, 0x80, 0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x10, 0x00, 0x15, 0x03, 0x01, 0x00,
328
            0x02, 0x00, 0x14, 0x03, 0x14, 0x02, 0x56, 0x07, 0x01, 0x14, 0x01, 0x14, 0x03, 0x10, 0x04, 0x42,
329
            0x40, 0x14, 0x00, 0x33, 0x02, 0x00, 0x10, 0x01, 0x14, 0x03, 0x40, 0x15, 0x03, 0x06, 0x00, 0x0f,
330
            0x0f, 0x09, 0x0f
331
        };
332
333
        Plan plan(*vm, vector);
334
        if (plan.result.size() != 1 || !plan.result[0]) {
335
            dataLogLn("Module failed to compile correctly.");
336
            CRASH();
337
        }
338
        ASSERT(plan.memory->size());
339
340
        // Test this doesn't crash.
341
        unsigned length = 5;
342
        unsigned offset = sizeof(uint32_t);
343
        uint32_t* memory = static_cast<uint32_t*>(plan.memory->memory());
344
        invoke<void>(*plan.result[0]->jsEntryPoint, { box(100), box(offset), box(length) });
345
        offset /= sizeof(uint32_t);
346
        CHECK_EQ(memory[offset - 1], 0u);
347
        CHECK_EQ(memory[offset + length], 0u);
348
        for (unsigned i = 0; i < length; ++i)
349
            CHECK_EQ(memory[i + offset], 100u);
350
351
        length = 10;
352
        offset = 5 * sizeof(uint32_t);
353
        invoke<void>(*plan.result[0]->jsEntryPoint, { box(5), box(offset), box(length) });
354
        offset /= sizeof(uint32_t);
355
        CHECK_EQ(memory[offset - 1], 100u);
356
        CHECK_EQ(memory[offset + length], 0u);
357
        for (unsigned i = 0; i < length; ++i)
358
            CHECK_EQ(memory[i + offset], 5u);
359
    }
360
361
    {
362
        // Generated from:
363
        //    (module
364
        //     (memory 1)
365
        //     (func (export "write_array") (param $x i32) (param $p i32) (param $length i32) (local $i i32)
366
        //      (set_local $i (i32.const 0))
367
        //      (block
368
        //       (loop
369
        //        (br_if 1 (i32.ge_u (get_local $i) (get_local $length)))
370
        //        (i32.store8 (i32.add (get_local $p) (get_local $i)) (get_local $x))
371
        //        (set_local $i (i32.add (i32.const 1) (get_local $i)))
372
        //        (br 0)
373
        //        )
374
        //       )
375
        //      (return)
376
        //      )
377
        //     )
378
        Vector<uint8_t> vector = {
379
            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
380
            0x03, 0x01, 0x01, 0x01, 0x00, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
381
            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x77, 0x72,
382
            0x69, 0x74, 0x65, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x00, 0x00, 0x0a, 0xaf, 0x80, 0x80, 0x80,
383
            0x00, 0x01, 0xa9, 0x80, 0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x10, 0x00, 0x15, 0x03, 0x01, 0x00,
384
            0x02, 0x00, 0x14, 0x03, 0x14, 0x02, 0x56, 0x07, 0x01, 0x14, 0x01, 0x14, 0x03, 0x40, 0x14, 0x00,
385
            0x2e, 0x00, 0x00, 0x10, 0x01, 0x14, 0x03, 0x40, 0x15, 0x03, 0x06, 0x00, 0x0f, 0x0f, 0x09, 0x0f
386
        };
387
388
        Plan plan(*vm, vector);
389
        if (plan.result.size() != 1 || !plan.result[0]) {
390
            dataLogLn("Module failed to compile correctly.");
391
            CRASH();
392
        }
393
        ASSERT(plan.memory->size());
394
395
        // Test this doesn't crash.
396
        unsigned length = 5;
397
        unsigned offset = 1;
398
        uint8_t* memory = static_cast<uint8_t*>(plan.memory->memory());
399
        invoke<void>(*plan.result[0]->jsEntryPoint, { box(100), box(offset), box(length) });
400
        CHECK_EQ(memory[offset - 1], 0u);
401
        CHECK_EQ(memory[offset + length], 0u);
402
        for (unsigned i = 0; i < length; ++i)
403
            CHECK_EQ(memory[i + offset], 100u);
404
405
        length = 10;
406
        offset = 5;
407
        invoke<void>(*plan.result[0]->jsEntryPoint, { box(5), box(offset), box(length) });
408
        CHECK_EQ(memory[offset - 1], 100u);
409
        CHECK_EQ(memory[offset + length], 0u);
410
        for (unsigned i = 0; i < length; ++i)
411
            CHECK_EQ(memory[i + offset], 5u);
412
    }
413
414
    {
415
        // Generated from:
416
        //    (module
417
        //     (memory 1)
418
        //     (func (export "i32_load8_s") (param $i i32) (param $ptr i32) (result i32)
419
        //      (i32.store8 (get_local $ptr) (get_local $i))
420
        //      (return (i32.load8_s (get_local $ptr)))
421
        //      )
422
        //     )
423
        Vector<uint8_t> vector = {
424
            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
425
            0x02, 0x01, 0x01, 0x01, 0x01, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
426
            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x69, 0x33,
427
            0x32, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x38, 0x5f, 0x73, 0x00, 0x00, 0x0a, 0x95, 0x80, 0x80, 0x80,
428
            0x00, 0x01, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14, 0x01, 0x14, 0x00, 0x2e, 0x00, 0x00, 0x14,
429
            0x01, 0x20, 0x00, 0x00, 0x09, 0x0f
430
        };
431
432
        Plan plan(*vm, vector);
433
        if (plan.result.size() != 1 || !plan.result[0]) {
434
            dataLogLn("Module failed to compile correctly.");
435
            CRASH();
436
        }
437
        ASSERT(plan.memory->size());
438
439
        // Test this doesn't crash.
440
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(10) }), 0);
441
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(2) }), 100);
442
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(100) }), 1);
443
    }
444
445
    {
446
        // Generated from:
447
        //    (module
448
        //     (memory 1)
449
        //     (func (export "i32_load8_s") (param $i i32) (result i32)
450
        //      (i32.store8 (i32.const 8) (get_local $i))
451
        //      (return (i32.load8_s (i32.const 8)))
452
        //      )
453
        //     )
454
        Vector<uint8_t> vector = {
455
            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x86, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
456
            0x01, 0x01, 0x01, 0x01, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80, 0x80,
457
            0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x69, 0x33, 0x32,
458
            0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x38, 0x5f, 0x73, 0x00, 0x00, 0x0a, 0x95, 0x80, 0x80, 0x80, 0x00,
459
            0x01, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x00, 0x10, 0x08, 0x14, 0x00, 0x2e, 0x00, 0x00, 0x10, 0x08,
460
            0x20, 0x00, 0x00, 0x09, 0x0f
461
        };
462
463
        Plan plan(*vm, vector);
464
        if (plan.result.size() != 1 || !plan.result[0]) {
465
            dataLogLn("Module failed to compile correctly.");
466
            CRASH();
467
        }
468
469
        // Test this doesn't crash.
470
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0) }), 0);
471
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100) }), 100);
472
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1) }), 1);
473
    }
474
475
    {
476
        // Generated from:
477
        // (module
478
        //  (memory 1)
479
        //  (func (export "i32_load8_s") (param $i i32) (param $ptr i32) (result i32)
480
        //   (i32.store (get_local $ptr) (get_local $i))
481
        //   (return (i32.load (get_local $ptr)))
482
        //   )
483
        //  )
484
        Vector<uint8_t> vector = {
485
            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
486
            0x02, 0x02, 0x01, 0x01, 0x02, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
487
            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x69, 0x33,
488
            0x32, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x38, 0x5f, 0x73, 0x00, 0x00, 0x0a, 0x95, 0x80, 0x80, 0x80,
489
            0x00, 0x01, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14, 0x01, 0x14, 0x00, 0x34, 0x03, 0x00, 0x14,
490
            0x01, 0x2b, 0x03, 0x00, 0x09, 0x0f
491
        };
492
493
        Plan plan(*vm, vector);
494
        if (plan.result.size() != 1 || !plan.result[0]) {
495
            dataLogLn("Module failed to compile correctly.");
496
            CRASH();
497
        }
498
499
        // Test this doesn't crash.
500
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(10) }), 0);
501
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(2) }), 100);
502
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(100) }), 1);
503
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(-12), box(plan.memory->size() - sizeof(uint64_t)) }), -12);
504
    }
505
506
    {
507
        // Generated from:
508
        // (module
509
        //  (memory 1)
510
        //  (func (export "i32_load8_s") (param $i i32) (param $ptr i32) (result i32)
511
        //   (i32.store (get_local $ptr) (get_local $i))
512
        //   (return (i32.load (get_local $ptr)))
513
        //   )
514
        //  )
515
        Vector<uint8_t> vector = {
516
            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
517
            0x02, 0x01, 0x01, 0x01, 0x01, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
518
            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x69, 0x33,
519
            0x32, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x38, 0x5f, 0x73, 0x00, 0x00, 0x0a, 0x95, 0x80, 0x80, 0x80,
520
            0x00, 0x01, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14, 0x01, 0x14, 0x00, 0x33, 0x02, 0x00, 0x14,
521
            0x01, 0x2a, 0x02, 0x00, 0x09, 0x0f
522
        };
523
524
        Plan plan(*vm, vector);
525
        if (plan.result.size() != 1 || !plan.result[0]) {
526
            dataLogLn("Module failed to compile correctly.");
527
            CRASH();
528
        }
529
530
        // Test this doesn't crash.
531
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(10) }), 0);
532
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(2) }), 100);
533
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(100) }), 1);
534
    }
535
536
    {
537
        // Generated from:
245
        //    (module
538
        //    (module
246
        //     (func (export "dumb-eq") (param $x i32) (param $y i32) (result i32)
539
        //     (memory 1)
540
        //     (func (export "write_array") (param $x i32) (param $p i32) (param $length i32) (local $i i32)
541
        //      (set_local $i (i32.const 0))
542
        //      (block
543
        //       (loop
544
        //        (br_if 1 (i32.ge_u (get_local $i) (get_local $length)))
545
        //        (i32.store (i32.add (get_local $p) (i32.mul (get_local $i) (i32.const 4))) (get_local $x))
546
        //        (set_local $i (i32.add (i32.const 1) (get_local $i)))
547
        //        (br 0)
548
        //        )
549
        //       )
550
        //      (return)
551
        //      )
552
        //     )
553
        Vector<uint8_t> vector = {
554
            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
555
            0x03, 0x01, 0x01, 0x01, 0x00, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
556
            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x77, 0x72,
557
            0x69, 0x74, 0x65, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x00, 0x00, 0x0a, 0xb2, 0x80, 0x80, 0x80,
558
            0x00, 0x01, 0xac, 0x80, 0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x10, 0x00, 0x15, 0x03, 0x01, 0x00,
559
            0x02, 0x00, 0x14, 0x03, 0x14, 0x02, 0x56, 0x07, 0x01, 0x14, 0x01, 0x14, 0x03, 0x10, 0x04, 0x42,
560
            0x40, 0x14, 0x00, 0x33, 0x02, 0x00, 0x10, 0x01, 0x14, 0x03, 0x40, 0x15, 0x03, 0x06, 0x00, 0x0f,
561
            0x0f, 0x09, 0x0f
562
        };
563
564
        Plan plan(*vm, vector);
565
        if (plan.result.size() != 1 || !plan.result[0]) {
566
            dataLogLn("Module failed to compile correctly.");
567
            CRASH();
568
        }
569
        ASSERT(plan.memory->size());
570
571
        // Test this doesn't crash.
572
        unsigned length = 5;
573
        unsigned offset = sizeof(uint32_t);
574
        uint32_t* memory = static_cast<uint32_t*>(plan.memory->memory());
575
        invoke<void>(*plan.result[0]->jsEntryPoint, { box(100), box(offset), box(length) });
576
        offset /= sizeof(uint32_t);
577
        CHECK_EQ(memory[offset - 1], 0u);
578
        CHECK_EQ(memory[offset + length], 0u);
579
        for (unsigned i = 0; i < length; ++i)
580
            CHECK_EQ(memory[i + offset], 100u);
581
582
        length = 10;
583
        offset = 5 * sizeof(uint32_t);
584
        invoke<void>(*plan.result[0]->jsEntryPoint, { box(5), box(offset), box(length) });
585
        offset /= sizeof(uint32_t);
586
        CHECK_EQ(memory[offset - 1], 100u);
587
        CHECK_EQ(memory[offset + length], 0u);
588
        for (unsigned i = 0; i < length; ++i)
589
            CHECK_EQ(memory[i + offset], 5u);
590
    }
591
592
    {
593
        // Generated from:
594
        //    (module
595
        //     (memory 1)
596
        //     (func (export "write_array") (param $x i32) (param $p i32) (param $length i32) (local $i i32)
597
        //      (set_local $i (i32.const 0))
598
        //      (block
599
        //       (loop
600
        //        (br_if 1 (i32.ge_u (get_local $i) (get_local $length)))
601
        //        (i32.store8 (i32.add (get_local $p) (get_local $i)) (get_local $x))
602
        //        (set_local $i (i32.add (i32.const 1) (get_local $i)))
603
        //        (br 0)
604
        //        )
605
        //       )
606
        //      (return)
607
        //      )
608
        //     )
609
        Vector<uint8_t> vector = {
610
            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
611
            0x03, 0x01, 0x01, 0x01, 0x00, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
612
            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x77, 0x72,
613
            0x69, 0x74, 0x65, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x00, 0x00, 0x0a, 0xaf, 0x80, 0x80, 0x80,
614
            0x00, 0x01, 0xa9, 0x80, 0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x10, 0x00, 0x15, 0x03, 0x01, 0x00,
615
            0x02, 0x00, 0x14, 0x03, 0x14, 0x02, 0x56, 0x07, 0x01, 0x14, 0x01, 0x14, 0x03, 0x40, 0x14, 0x00,
616
            0x2e, 0x00, 0x00, 0x10, 0x01, 0x14, 0x03, 0x40, 0x15, 0x03, 0x06, 0x00, 0x0f, 0x0f, 0x09, 0x0f
617
        };
618
619
        Plan plan(*vm, vector);
620
        if (plan.result.size() != 1 || !plan.result[0]) {
621
            dataLogLn("Module failed to compile correctly.");
622
            CRASH();
623
        }
624
        ASSERT(plan.memory->size());
625
626
        // Test this doesn't crash.
627
        unsigned length = 5;
628
        unsigned offset = 1;
629
        uint8_t* memory = static_cast<uint8_t*>(plan.memory->memory());
630
        invoke<void>(*plan.result[0]->jsEntryPoint, { box(100), box(offset), box(length) });
631
        CHECK_EQ(memory[offset - 1], 0u);
632
        CHECK_EQ(memory[offset + length], 0u);
633
        for (unsigned i = 0; i < length; ++i)
634
            CHECK_EQ(memory[i + offset], 100u);
635
636
        length = 10;
637
        offset = 5;
638
        invoke<void>(*plan.result[0]->jsEntryPoint, { box(5), box(offset), box(length) });
639
        CHECK_EQ(memory[offset - 1], 100u);
640
        CHECK_EQ(memory[offset + length], 0u);
641
        for (unsigned i = 0; i < length; ++i)
642
            CHECK_EQ(memory[i + offset], 5u);
643
    }
644
645
    {
646
        // Generated from:
647
        //    (module
648
        //     (memory 1)
649
        //     (func (export "i32_load8_s") (param $i i32) (param $ptr i32) (result i32)
650
        //      (i32.store8 (get_local $ptr) (get_local $i))
651
        //      (return (i32.load8_s (get_local $ptr)))
652
        //      )
653
        //     )
654
        Vector<uint8_t> vector = {
655
            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
656
            0x02, 0x01, 0x01, 0x01, 0x01, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
657
            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x69, 0x33,
658
            0x32, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x38, 0x5f, 0x73, 0x00, 0x00, 0x0a, 0x95, 0x80, 0x80, 0x80,
659
            0x00, 0x01, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14, 0x01, 0x14, 0x00, 0x2e, 0x00, 0x00, 0x14,
660
            0x01, 0x20, 0x00, 0x00, 0x09, 0x0f
661
        };
662
663
        Plan plan(*vm, vector);
664
        if (plan.result.size() != 1 || !plan.result[0]) {
665
            dataLogLn("Module failed to compile correctly.");
666
            CRASH();
667
        }
668
        ASSERT(plan.memory->size());
669
670
        // Test this doesn't crash.
671
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(10) }), 0);
672
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(2) }), 100);
673
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(100) }), 1);
674
    }
675
676
    {
677
        // Generated from:
678
        //    (module
679
        //     (memory 1)
680
        //     (func (export "i32_load8_s") (param $i i32) (result i32)
681
        //      (i32.store8 (i32.const 8) (get_local $i))
682
        //      (return (i32.load8_s (i32.const 8)))
683
        //      )
684
        //     )
685
        Vector<uint8_t> vector = {
686
            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x86, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
687
            0x01, 0x01, 0x01, 0x01, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80, 0x80,
688
            0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x69, 0x33, 0x32,
689
            0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x38, 0x5f, 0x73, 0x00, 0x00, 0x0a, 0x95, 0x80, 0x80, 0x80, 0x00,
690
            0x01, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x00, 0x10, 0x08, 0x14, 0x00, 0x2e, 0x00, 0x00, 0x10, 0x08,
691
            0x20, 0x00, 0x00, 0x09, 0x0f
692
        };
693
694
        Plan plan(*vm, vector);
695
        if (plan.result.size() != 1 || !plan.result[0]) {
696
            dataLogLn("Module failed to compile correctly.");
697
            CRASH();
698
        }
699
700
        // Test this doesn't crash.
701
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0) }), 0);
702
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100) }), 100);
703
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1) }), 1);
704
    }
705
706
    {
707
        // Generated from:
708
        //    (module
709
        //     (func "dumb-eq" (param $x i32) (param $y i32) (result i32)
247
        //      (if (i32.eq (get_local $x) (get_local $y))
710
        //      (if (i32.eq (get_local $x) (get_local $y))
248
        //       (then (br 0))
711
        //       (then (br 0))
249
        //       (else (return (i32.const 1))))
712
        //       (else (return (i32.const 1))))
Lines 265-278 static void runWASMTests() a/Source/JavaScriptCore/testWASM.cpp_sec3
265
        }
728
        }
266
729
267
        // Test this doesn't crash.
730
        // Test this doesn't crash.
268
        CHECK_EQ(invoke<int>(*plan.result[0], { box(0), box(1) }), 1);
731
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(1) }), 1);
269
        CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(0) }), 1);
732
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(0) }), 1);
270
        CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(1) }), 1);
733
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(1) }), 1);
271
        CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(2) }), 1);
734
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(2) }), 1);
272
        CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(2) }), 0);
735
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(2) }), 0);
273
        CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(1) }), 0);
736
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(1) }), 0);
274
        CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(6) }), 1);
737
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(6) }), 1);
275
        CHECK_EQ(invoke<int>(*plan.result[0], { box(100), box(6) }), 1);
738
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(6) }), 1);
276
    }
739
    }
277
740
278
    {
741
    {
Lines 306-319 static void runWASMTests() a/Source/JavaScriptCore/testWASM.cpp_sec4
306
        }
769
        }
307
770
308
        // Test this doesn't crash.
771
        // Test this doesn't crash.
309
        CHECK_EQ(invoke<int>(*plan.result[0], { box(0), box(1) }), 1);
772
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(1) }), 1);
310
        CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(0) }), 0);
773
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(0) }), 0);
311
        CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(1) }), 0);
774
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(1) }), 0);
312
        CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(2) }), 1);
775
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(2) }), 1);
313
        CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(2) }), 0);
776
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(2) }), 0);
314
        CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(1) }), 0);
777
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(1) }), 0);
315
        CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(6) }), 1);
778
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(6) }), 1);
316
        CHECK_EQ(invoke<int>(*plan.result[0], { box(100), box(6) }), 0);
779
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(6) }), 0);
317
    }
780
    }
318
781
319
782
Lines 333-339 static void runWASMTests() a/Source/JavaScriptCore/testWASM.cpp_sec5
333
        }
796
        }
334
797
335
        // Test this doesn't crash.
798
        // Test this doesn't crash.
336
        CHECK_EQ(invoke<int>(*plan.result[0], { }), 5);
799
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { }), 5);
337
    }
800
    }
338
801
339
802
Lines 354-360 static void runWASMTests() a/Source/JavaScriptCore/testWASM.cpp_sec6
354
        }
817
        }
355
818
356
        // Test this doesn't crash.
819
        // Test this doesn't crash.
357
        CHECK_EQ(invoke<int>(*plan.result[0], { }), 11);
820
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { }), 11);
358
    }
821
    }
359
822
360
    {
823
    {
Lines 374-380 static void runWASMTests() a/Source/JavaScriptCore/testWASM.cpp_sec7
374
        }
837
        }
375
838
376
        // Test this doesn't crash.
839
        // Test this doesn't crash.
377
        CHECK_EQ(invoke<int>(*plan.result[0], { }), 11);
840
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { }), 11);
378
    }
841
    }
379
842
380
    {
843
    {
Lines 394-400 static void runWASMTests() a/Source/JavaScriptCore/testWASM.cpp_sec8
394
        }
857
        }
395
858
396
        // Test this doesn't crash.
859
        // Test this doesn't crash.
397
        CHECK_EQ(invoke<int>(*plan.result[0], { }), 11);
860
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { }), 11);
398
    }
861
    }
399
862
400
    {
863
    {
Lines 413-422 static void runWASMTests() a/Source/JavaScriptCore/testWASM.cpp_sec9
413
        }
876
        }
414
877
415
        // Test this doesn't crash.
878
        // Test this doesn't crash.
416
        CHECK_EQ(invoke<int>(*plan.result[0], { box(0), box(1) }), 1);
879
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(1) }), 1);
417
        CHECK_EQ(invoke<int>(*plan.result[0], { box(100), box(1) }), 101);
880
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(1) }), 101);
418
        CHECK_EQ(invoke<int>(*plan.result[0], { box(-1), box(1)}), 0);
881
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(-1), box(1)}), 0);
419
        CHECK_EQ(invoke<int>(*plan.result[0], { box(std::numeric_limits<int>::max()), box(1) }), std::numeric_limits<int>::min());
882
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(std::numeric_limits<int>::max()), box(1) }), std::numeric_limits<int>::min());
420
    }
883
    }
421
884
422
    {
885
    {
Lines 442-449 static void runWASMTests() a/Source/JavaScriptCore/testWASM.cpp_sec10
442
        }
905
        }
443
906
444
        // Test this doesn't crash.
907
        // Test this doesn't crash.
445
        CHECK_EQ(invoke<int>(*plan.result[0], { box(0) }), 0);
908
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0) }), 0);
446
        CHECK_EQ(invoke<int>(*plan.result[0], { box(10) }), 10);
909
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(10) }), 10);
447
    }
910
    }
448
911
449
    {
912
    {
Lines 478-487 static void runWASMTests() a/Source/JavaScriptCore/testWASM.cpp_sec11
478
        }
941
        }
479
942
480
        // Test this doesn't crash.
943
        // Test this doesn't crash.
481
        CHECK_EQ(invoke<int>(*plan.result[0], { box(0) }), 0);
944
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0) }), 0);
482
        CHECK_EQ(invoke<int>(*plan.result[0], { box(1) }), 1);
945
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1) }), 1);
483
        CHECK_EQ(invoke<int>(*plan.result[0], { box(2)}), 3);
946
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2)}), 3);
484
        CHECK_EQ(invoke<int>(*plan.result[0], { box(100) }), 5050);
947
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100) }), 5050);
485
    }
948
    }
486
949
487
    {
950
    {
Lines 522-535 static void runWASMTests() a/Source/JavaScriptCore/testWASM.cpp_sec12
522
        }
985
        }
523
986
524
        // Test this doesn't crash.
987
        // Test this doesn't crash.
525
        CHECK_EQ(invoke<int>(*plan.result[0], { box(0), box(1) }), 0);
988
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(1) }), 0);
526
        CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(0) }), 0);
989
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(0) }), 0);
527
        CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(1) }), 2);
990
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(1) }), 2);
528
        CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(2) }), 2);
991
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(2) }), 2);
529
        CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(2) }), 4);
992
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(2) }), 4);
530
        CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(6) }), 12);
993
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(6) }), 12);
531
        CHECK_EQ(invoke<int>(*plan.result[0], { box(100), box(6) }), 600);
994
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(6) }), 600);
532
        CHECK_EQ(invoke<int>(*plan.result[0], { box(100), box(100) }), 10000);
995
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(100) }), 10000);
533
    }
996
    }
534
997
535
    {
998
    {
Lines 575-588 static void runWASMTests() a/Source/JavaScriptCore/testWASM.cpp_sec13
575
        }
1038
        }
576
1039
577
        // Test this doesn't crash.
1040
        // Test this doesn't crash.
578
        CHECK_EQ(invoke<int>(*plan.result[0], { box(0), box(1) }), 1);
1041
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(1) }), 1);
579
        CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(0) }), 0);
1042
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(0) }), 0);
580
        CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(1) }), 0);
1043
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(1) }), 0);
581
        CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(2) }), 1);
1044
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(2) }), 1);
582
        CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(2) }), 0);
1045
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(2) }), 0);
583
        CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(1) }), 0);
1046
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(1) }), 0);
584
        CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(6) }), 1);
1047
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(6) }), 1);
585
        CHECK_EQ(invoke<int>(*plan.result[0], { box(100), box(6) }), 0);
1048
        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(6) }), 0);
586
    }
1049
    }
587
1050
588
}
1051
}
Lines 596-602 int main(int argc, char** argv) a/Source/JavaScriptCore/testWASM.cpp_sec14
596
    if (options.m_runLEBTests)
1059
    if (options.m_runLEBTests)
597
        runLEBTests();
1060
        runLEBTests();
598
1061
599
600
    if (options.m_runWASMTests) {
1062
    if (options.m_runWASMTests) {
601
#if ENABLE(WEBASSEMBLY)
1063
#if ENABLE(WEBASSEMBLY)
602
        JSC::initializeThreading();
1064
        JSC::initializeThreading();
- a/Source/JavaScriptCore/wasm/WASMB3IRGenerator.cpp -8 / +263 lines
Lines 29-35 a/Source/JavaScriptCore/wasm/WASMB3IRGenerator.cpp_sec1
29
#if ENABLE(WEBASSEMBLY)
29
#if ENABLE(WEBASSEMBLY)
30
30
31
#include "B3BasicBlockInlines.h"
31
#include "B3BasicBlockInlines.h"
32
#include "B3ConstPtrValue.h"
32
#include "B3FixSSA.h"
33
#include "B3FixSSA.h"
34
#include "B3StackmapGenerationParams.h"
33
#include "B3Validate.h"
35
#include "B3Validate.h"
34
#include "B3ValueInlines.h"
36
#include "B3ValueInlines.h"
35
#include "B3Variable.h"
37
#include "B3Variable.h"
Lines 37-42 a/Source/JavaScriptCore/wasm/WASMB3IRGenerator.cpp_sec2
37
#include "VirtualRegister.h"
39
#include "VirtualRegister.h"
38
#include "WASMCallingConvention.h"
40
#include "WASMCallingConvention.h"
39
#include "WASMFunctionParser.h"
41
#include "WASMFunctionParser.h"
42
#include "WASMMemory.h"
40
#include <wtf/Optional.h>
43
#include <wtf/Optional.h>
41
44
42
void dumpProcedure(void* ptr)
45
void dumpProcedure(void* ptr)
Lines 165-182 public: a/Source/JavaScriptCore/wasm/WASMB3IRGenerator.cpp_sec3
165
    typedef Vector<Variable*, 1> ResultList;
168
    typedef Vector<Variable*, 1> ResultList;
166
    static constexpr ExpressionType emptyExpression = nullptr;
169
    static constexpr ExpressionType emptyExpression = nullptr;
167
170
168
    B3IRGenerator(Procedure&);
171
    B3IRGenerator(Memory*, Procedure&);
169
172
170
    void addArguments(const Vector<Type>&);
173
    void addArguments(const Vector<Type>&);
171
    void addLocal(Type, uint32_t);
174
    void addLocal(Type, uint32_t);
172
    ExpressionType addConstant(Type, uint64_t);
175
    ExpressionType addConstant(Type, uint64_t);
173
176
177
    // Locals
174
    bool WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
178
    bool WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
175
    bool WARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value);
179
    bool WARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value);
176
180
181
    // Memory
182
    bool WARN_UNUSED_RETURN load(LoadOpType, uint32_t offset, ExpressionType pointer, ExpressionType& result);
183
    bool WARN_UNUSED_RETURN store(StoreOpType, uint32_t offset, ExpressionType pointer, ExpressionType value);
184
185
    // Basic operators
177
    bool WARN_UNUSED_RETURN binaryOp(BinaryOpType, ExpressionType left, ExpressionType right, ExpressionType& result);
186
    bool WARN_UNUSED_RETURN binaryOp(BinaryOpType, ExpressionType left, ExpressionType right, ExpressionType& result);
178
    bool WARN_UNUSED_RETURN unaryOp(UnaryOpType, ExpressionType arg, ExpressionType& result);
187
    bool WARN_UNUSED_RETURN unaryOp(UnaryOpType, ExpressionType arg, ExpressionType& result);
179
188
189
    // Control flow
180
    ControlData WARN_UNUSED_RETURN addBlock(Type signature);
190
    ControlData WARN_UNUSED_RETURN addBlock(Type signature);
181
    ControlData WARN_UNUSED_RETURN addLoop(Type signature);
191
    ControlData WARN_UNUSED_RETURN addLoop(Type signature);
182
    ControlData WARN_UNUSED_RETURN addIf(ExpressionType condition, Type signature);
192
    ControlData WARN_UNUSED_RETURN addIf(ExpressionType condition, Type signature);
Lines 191-206 public: a/Source/JavaScriptCore/wasm/WASMB3IRGenerator.cpp_sec4
191
    void dump(const Vector<ControlType>& controlStack, const ExpressionList& expressionStack);
201
    void dump(const Vector<ControlType>& controlStack, const ExpressionList& expressionStack);
192
202
193
private:
203
private:
204
    ExpressionType emitCheckAndPreparePointer(uint32_t offset, ExpressionType pointer, uint32_t sizeOfOp);
205
    ExpressionType emitLoadOp(LoadOpType, Origin, ExpressionType pointer);
206
    void emitStoreOp(StoreOpType, Origin, ExpressionType pointer, ExpressionType value);
207
194
    void unify(Variable* target, const ExpressionType source);
208
    void unify(Variable* target, const ExpressionType source);
195
    void unifyValuesWithBlock(const ExpressionList& resultStack, ResultList& stack);
209
    void unifyValuesWithBlock(const ExpressionList& resultStack, ResultList& stack);
196
210
211
    Memory* m_memory;
197
    Procedure& m_proc;
212
    Procedure& m_proc;
198
    BasicBlock* m_currentBlock;
213
    BasicBlock* m_currentBlock;
199
    Vector<Variable*> m_locals;
214
    Vector<Variable*> m_locals;
215
    Value* m_memoryBase { nullptr };
216
    Value* m_memorySize { nullptr };
200
};
217
};
201
218
202
B3IRGenerator::B3IRGenerator(Procedure& procedure)
219
B3IRGenerator::B3IRGenerator(Memory* memory, Procedure& procedure)
203
    : m_proc(procedure)
220
    : m_memory(memory)
221
    , m_proc(procedure)
204
{
222
{
205
    m_currentBlock = m_proc.addBlock();
223
    m_currentBlock = m_proc.addBlock();
206
}
224
}
Lines 222-243 void B3IRGenerator::addArguments(const Vector<Type>& types) a/Source/JavaScriptCore/wasm/WASMB3IRGenerator.cpp_sec5
222
            m_locals[i] = argumentVariable;
240
            m_locals[i] = argumentVariable;
223
            m_currentBlock->appendNew<VariableValue>(m_proc, Set, Origin(), argumentVariable, argument);
241
            m_currentBlock->appendNew<VariableValue>(m_proc, Set, Origin(), argumentVariable, argument);
224
        });
242
        });
243
244
    if (m_memory) {
245
        // FIXME: When we add the calling convention we should have two entrypoints and we should change these to register arguments.
246
        m_memoryBase = m_currentBlock->appendNew<ConstPtrValue>(m_proc, Origin(), m_memory->memory());
247
        Value* memorySizeAddress = m_currentBlock->appendNew<ConstPtrValue>(m_proc, Origin(), bitwise_cast<char*>(m_memory) + Memory::offsetOfSize());
248
        m_memorySize = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int64, Origin(), memorySizeAddress);
249
    }
225
}
250
}
226
251
227
bool WARN_UNUSED_RETURN B3IRGenerator::getLocal(uint32_t index, ExpressionType& result)
252
bool B3IRGenerator::getLocal(uint32_t index, ExpressionType& result)
228
{
253
{
229
    ASSERT(m_locals[index]);
254
    ASSERT(m_locals[index]);
230
    result = m_currentBlock->appendNew<VariableValue>(m_proc, B3::Get, Origin(), m_locals[index]);
255
    result = m_currentBlock->appendNew<VariableValue>(m_proc, B3::Get, Origin(), m_locals[index]);
231
    return true;
256
    return true;
232
}
257
}
233
258
234
bool WARN_UNUSED_RETURN B3IRGenerator::setLocal(uint32_t index, ExpressionType value)
259
bool B3IRGenerator::setLocal(uint32_t index, ExpressionType value)
235
{
260
{
236
    ASSERT(m_locals[index]);
261
    ASSERT(m_locals[index]);
237
    m_currentBlock->appendNew<VariableValue>(m_proc, B3::Set, Origin(), m_locals[index], value);
262
    m_currentBlock->appendNew<VariableValue>(m_proc, B3::Set, Origin(), m_locals[index], value);
238
    return true;
263
    return true;
239
}
264
}
240
265
266
inline Value* B3IRGenerator::emitCheckAndPreparePointer(uint32_t offset, ExpressionType pointer, uint32_t sizeOfOperation)
267
{
268
    ASSERT(m_memoryBase && m_memorySize);
269
    // We need to make sure that we add the memoryOffset to the pointer with a 32bit add
270
    // so if it overflows we stay within our mapped memory.
271
    Value* memoryOffset = m_currentBlock->appendIntConstant(m_proc, Origin(), Int32, offset);
272
    pointer = m_currentBlock->appendNew<Value>(m_proc, Add, Origin(), pointer, memoryOffset);
273
    pointer = m_currentBlock->appendNew<Value>(m_proc, ZExt32, Origin(), pointer);
274
275
    Value* sizeOfValue = m_currentBlock->appendIntConstant(m_proc, Origin(), Int64, sizeOfOperation);
276
    Value* lastByte = m_currentBlock->appendNew<Value>(m_proc, Add, Origin(), sizeOfValue, pointer);
277
    Value* outOfBounds = m_currentBlock->appendNew<Value>(m_proc, Above, Origin(), lastByte, m_memorySize);
278
    CheckValue* boundsCheck = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(), outOfBounds);
279
    boundsCheck->setGenerator([] (CCallHelpers& jit, const StackmapGenerationParams&) {
280
        jit.breakpoint();
281
    });
282
283
    pointer = m_currentBlock->appendNew<Value>(m_proc, Add, Origin(), m_memoryBase, pointer);
284
    return pointer;
285
}
286
287
inline uint32_t sizeOfLoadOp(LoadOpType op)
288
{
289
    switch (op) {
290
    case LoadOpType::I32Load8S:
291
    case LoadOpType::I32Load8U:
292
    case LoadOpType::I64Load8S:
293
    case LoadOpType::I64Load8U:
294
        return 1;
295
    case LoadOpType::I32Load16S:
296
    case LoadOpType::I64Load16S:
297
        return 2;
298
    case LoadOpType::I32Load:
299
    case LoadOpType::I64Load32S:
300
    case LoadOpType::I64Load32U:
301
        return 4;
302
    case LoadOpType::I64Load:
303
        return 8;
304
    }
305
    RELEASE_ASSERT_NOT_REACHED();
306
}
307
308
// FIXME: B3 should support Int64 small loads and 16-bit unsigned loads.
309
inline Value* B3IRGenerator::emitLoadOp(LoadOpType op, Origin origin, ExpressionType pointer)
310
{
311
    switch (op) {
312
    case LoadOpType::I32Load8S: {
313
        return m_currentBlock->appendNew<MemoryValue>(m_proc, Load8S, origin, pointer, 0);
314
    }
315
316
    case LoadOpType::I64Load8S: {
317
        Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, Load8S, origin, pointer, 0);
318
        return m_currentBlock->appendNew<Value>(m_proc, SExt32, origin, value);
319
    }
320
321
    case LoadOpType::I32Load8U: {
322
        return m_currentBlock->appendNew<MemoryValue>(m_proc, Load8Z, origin, pointer, 0);
323
    }
324
325
    case LoadOpType::I64Load8U: {
326
        Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, Load8Z, origin, pointer, 0);
327
        return m_currentBlock->appendNew<Value>(m_proc, ZExt32, origin, value);
328
    }
329
330
    case LoadOpType::I32Load16S: {
331
        return m_currentBlock->appendNew<MemoryValue>(m_proc, Load16S, origin, pointer, 0);
332
    }
333
    case LoadOpType::I64Load16S: {
334
        Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, Load16S, origin, pointer, 0);
335
        return m_currentBlock->appendNew<Value>(m_proc, SExt32, origin, value);
336
    }
337
338
    case LoadOpType::I32Load: {
339
        return m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, origin, pointer);
340
    }
341
342
    case LoadOpType::I64Load32U: {
343
        Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, origin, pointer);
344
        return m_currentBlock->appendNew<Value>(m_proc, ZExt32, origin, value);
345
    }
346
347
    case LoadOpType::I64Load32S: {
348
        Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, origin, pointer);
349
        return m_currentBlock->appendNew<Value>(m_proc, SExt32, origin, value);
350
    }
351
352
    case LoadOpType::I64Load: {
353
        return m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int64, origin, pointer);
354
    }
355
    }
356
    RELEASE_ASSERT_NOT_REACHED();
357
}
358
359
bool B3IRGenerator::load(LoadOpType op, uint32_t offset, ExpressionType pointer, ExpressionType& result)
360
{
361
    ASSERT(pointer->type() == Int32);
362
363
    result = emitLoadOp(op, Origin(), emitCheckAndPreparePointer(offset, pointer, sizeOfLoadOp(op)));
364
    return true;
365
}
366
367
inline uint32_t sizeOfStoreOp(StoreOpType op)
368
{
369
    switch (op) {
370
    case StoreOpType::I32Store8:
371
    case StoreOpType::I64Store8:
372
        return 1;
373
    case StoreOpType::I32Store16:
374
    case StoreOpType::I64Store16:
375
        return 2;
376
    case StoreOpType::I32Store:
377
    case StoreOpType::I64Store32:
378
        return 4;
379
    case StoreOpType::I64Store:
380
        return 8;
381
    }
382
    RELEASE_ASSERT_NOT_REACHED();
383
}
384
385
386
// FIXME: We should just support an Int64 store8.
387
inline void B3IRGenerator::emitStoreOp(StoreOpType op, Origin origin, ExpressionType pointer, ExpressionType value)
388
{
389
    switch (op) {
390
    case StoreOpType::I64Store8:
391
        value = m_currentBlock->appendNew<Value>(m_proc, Trunc, origin, value);
392
        FALLTHROUGH;
393
394
    case StoreOpType::I32Store8:
395
        m_currentBlock->appendNew<MemoryValue>(m_proc, Store8, origin, value, pointer);
396
        return;
397
398
    case StoreOpType::I64Store16:
399
        value = m_currentBlock->appendNew<Value>(m_proc, Trunc, origin, value);
400
        FALLTHROUGH;
401
402
    case StoreOpType::I32Store16:
403
        m_currentBlock->appendNew<MemoryValue>(m_proc, Store16, origin, value, pointer);
404
        return;
405
406
    case StoreOpType::I64Store32:
407
        value = m_currentBlock->appendNew<Value>(m_proc, Trunc, origin, value);
408
        FALLTHROUGH;
409
410
    case StoreOpType::I64Store:
411
    case StoreOpType::I32Store:
412
        m_currentBlock->appendNew<MemoryValue>(m_proc, Store, origin, value, pointer);
413
        return;
414
    }
415
    RELEASE_ASSERT_NOT_REACHED();
416
}
417
418
bool B3IRGenerator::store(StoreOpType op, uint32_t offset, ExpressionType pointer, ExpressionType value)
419
{
420
    ASSERT(pointer->type() == Int32);
421
422
    emitStoreOp(op, Origin(), emitCheckAndPreparePointer(offset, pointer, sizeOfStoreOp(op)), value);
423
    return true;
424
}
425
241
bool B3IRGenerator::unaryOp(UnaryOpType op, ExpressionType arg, ExpressionType& result)
426
bool B3IRGenerator::unaryOp(UnaryOpType op, ExpressionType arg, ExpressionType& result)
242
{
427
{
243
    result = m_currentBlock->appendNew<Value>(m_proc, toB3Op(op), Origin(), arg);
428
    result = m_currentBlock->appendNew<Value>(m_proc, toB3Op(op), Origin(), arg);
Lines 403-412 void B3IRGenerator::dump(const Vector<ControlType>& controlStack, const Expressi a/Source/JavaScriptCore/wasm/WASMB3IRGenerator.cpp_sec6
403
588
404
} // anonymous namespace
589
} // anonymous namespace
405
590
406
std::unique_ptr<Compilation> parseAndCompile(VM& vm, Vector<uint8_t>& source, FunctionInformation info, unsigned optLevel)
591
592
    static std::unique_ptr<Compilation> createWrapper(VM& vm, const Signature* signature, MacroAssemblerCodePtr mainFunction, Memory* memory)
593
    {
594
        Procedure proc;
595
        BasicBlock* block = proc.addBlock();
596
597
//        prologue;
598
//        if (argCount < expected)
599
//            trap;
600
//
601
//        for (i = 0; i < argCount; ++i)
602
//            moveArgument[i];
603
//
604
//        pin things;
605
//        result = call mainFunction;
606
//        epilogue result;
607
608
        // FIXME: is this supposed to trap if less than expected number of arguments?
609
        Value* framePointer = block->appendNew<B3::Value>(proc, B3::FramePointer, Origin());
610
        Value* offSetOfArgumentCount = block->appendNew<Const64Value>(proc, Origin(), CallFrameSlot::argumentCount * sizeof(Register));
611
        Value* argumentCount = block->appendNew<MemoryValue>(proc, Load, Int32, Origin(),
612
            block->appendNew<Value>(proc, Add, Origin(), framePointer, offSetOfArgumentCount));
613
614
        Value* expectedArgumentCount = block->appendNew<Const32Value>(proc, Origin(), signature->arguments.size());
615
616
        CheckValue* argumentCountCheck = block->appendNew<CheckValue>(proc, Check, Origin(),
617
            block->appendNew<Value>(proc, Above, Origin(), expectedArgumentCount, argumentCount));
618
        argumentCountCheck->setGenerator([] (CCallHelpers& jit, const StackmapGenerationParams&) {
619
            jit.breakpoint();
620
        });
621
622
        Value* baseMemory = nullptr;
623
        Vector<Value*> sizes;
624
        if (memory) {
625
            baseMemory = block->appendNew<ConstPtrValue>(proc, Origin(), memory->memory());
626
            Value* size = block->appendNew<MemoryValue>(proc, Load, Int32, Origin(),
627
                block->appendNew<ConstPtrValue>(proc, Origin(), memory));
628
            sizes.reserveCapacity(memory->pinnedRegisters().sizeRegisters.size());
629
            for (auto info : memory->pinnedRegisters().sizeRegisters)
630
                sizes.append(block->appendNew<Value>(proc, Sub, Origin(), size,
631
                    block->appendNew<Const32Value>(proc, Origin(), info.sizeOffset)));
632
        }
633
634
        Vector<Value*> arguments;
635
        jscCallingConvention().iterate(signature->arguments, proc, block, Origin(),
636
            [&] (Value* argument, unsigned) {
637
                arguments.append(argument);
638
            });
639
640
        Value* result = jscCallingConvention().setupCall(proc, block, Origin(), mainFunction, arguments, toB3Type(signature->returnType), [&] (PatchpointValue* patchpoint) {
641
            if (memory) {
642
                ASSERT(sizes.size() == memory->pinnedRegisters().sizeRegisters.size());
643
                patchpoint->append(ConstrainedValue(baseMemory, ValueRep::reg(memory->pinnedRegisters().baseMemoryPointer)));
644
                for (unsigned i = 0; i < sizes.size(); ++i)
645
                    patchpoint->append(ConstrainedValue(sizes[i], ValueRep::reg(memory->pinnedRegisters().sizeRegisters[i].sizeRegister)));
646
            }
647
        });
648
649
        if (signature->returnType != Void)
650
            block->appendNewControlValue(proc, B3::Return, Origin(), result);
651
        else
652
            block->appendNewControlValue(proc, B3::Return, Origin());
653
654
        return std::make_unique<Compilation>(vm, proc);
655
    }
656
657
std::unique_ptr<FunctionCompilation> parseAndCompile(VM& vm, Vector<uint8_t>& source, Memory* memory, FunctionInformation info, unsigned optLevel)
407
{
658
{
408
    Procedure procedure;
659
    Procedure procedure;
409
    B3IRGenerator context(procedure);
660
    B3IRGenerator context(memory, procedure);
410
    FunctionParser<B3IRGenerator> parser(context, source, info);
661
    FunctionParser<B3IRGenerator> parser(context, source, info);
411
    if (!parser.parse())
662
    if (!parser.parse())
412
        RELEASE_ASSERT_NOT_REACHED();
663
        RELEASE_ASSERT_NOT_REACHED();
Lines 417-423 std::unique_ptr<Compilation> parseAndCompile(VM& vm, Vector<uint8_t>& source, Fu a/Source/JavaScriptCore/wasm/WASMB3IRGenerator.cpp_sec7
417
    fixSSA(procedure);
668
    fixSSA(procedure);
418
    if (verbose)
669
    if (verbose)
419
        dataLog("Post SSA: ", procedure);
670
        dataLog("Post SSA: ", procedure);
420
    return std::make_unique<Compilation>(vm, procedure, optLevel);
671
    std::unique_ptr<FunctionCompilation> result = std::make_unique<FunctionCompilation>();
672
673
    result->code = std::make_unique<Compilation>(vm, procedure, optLevel);
674
    result->jsEntryPoint = createWrapper(vm, info.signature, result->code->code(), memory);
675
    return result;
421
}
676
}
422
677
423
} } // namespace JSC::WASM
678
} } // namespace JSC::WASM
- a/Source/JavaScriptCore/wasm/WASMB3IRGenerator.h -1 / +3 lines
Lines 35-41 extern "C" void dumpProcedure(void*); a/Source/JavaScriptCore/wasm/WASMB3IRGenerator.h_sec1
35
35
36
namespace JSC { namespace WASM {
36
namespace JSC { namespace WASM {
37
37
38
std::unique_ptr<B3::Compilation> parseAndCompile(VM&, Vector<uint8_t>&, FunctionInformation, unsigned optLevel = 1);
38
class Memory;
39
40
std::unique_ptr<FunctionCompilation> parseAndCompile(VM&, Vector<uint8_t>&, Memory*, FunctionInformation, unsigned optLevel = 1);
39
41
40
} } // namespace JSC::WASM
42
} } // namespace JSC::WASM
41
43
- a/Source/JavaScriptCore/wasm/WASMCallingConvention.h -6 / +50 lines
Lines 27-49 a/Source/JavaScriptCore/wasm/WASMCallingConvention.h_sec1
27
27
28
#if ENABLE(WEBASSEMBLY)
28
#if ENABLE(WEBASSEMBLY)
29
29
30
#include "AllowMacroScratchRegisterUsage.h"
30
#include "B3ArgumentRegValue.h"
31
#include "B3ArgumentRegValue.h"
31
#include "B3BasicBlock.h"
32
#include "B3BasicBlock.h"
33
#include "B3ConstrainedValue.h"
32
#include "B3Const64Value.h"
34
#include "B3Const64Value.h"
33
#include "B3MemoryValue.h"
35
#include "B3MemoryValue.h"
36
#include "B3PatchpointValue.h"
37
#include "B3Procedure.h"
38
#include "B3StackmapGenerationParams.h"
34
#include "CallFrame.h"
39
#include "CallFrame.h"
40
#include "LinkBuffer.h"
35
#include "RegisterSet.h"
41
#include "RegisterSet.h"
36
#include "WASMFormat.h"
42
#include "WASMFormat.h"
37
43
38
namespace JSC { namespace WASM {
44
namespace JSC { namespace WASM {
39
45
40
typedef unsigned (*NextOffset)(unsigned currentOffset, Type type);
46
typedef unsigned (*NextOffset)(unsigned currentOffset, B3::Type type);
41
47
42
template<unsigned offset, NextOffset updateOffset>
48
template<unsigned headerSize, NextOffset updateOffset>
43
class CallingConvention {
49
class CallingConvention {
44
public:
50
public:
45
    static const unsigned headerSize = offset;
46
47
    CallingConvention(Vector<GPRReg>&& registerArguments, RegisterSet&& calleeSaveRegisters)
51
    CallingConvention(Vector<GPRReg>&& registerArguments, RegisterSet&& calleeSaveRegisters)
48
        : m_registerArguments(registerArguments)
52
        : m_registerArguments(registerArguments)
49
        , m_calleeSaveRegisters(calleeSaveRegisters)
53
        , m_calleeSaveRegisters(calleeSaveRegisters)
Lines 64-81 public: a/Source/JavaScriptCore/wasm/WASMCallingConvention.h_sec2
64
                B3::Value* address = block->appendNew<B3::Value>(proc, B3::Add, origin, framePointer,
68
                B3::Value* address = block->appendNew<B3::Value>(proc, B3::Add, origin, framePointer,
65
                    block->appendNew<B3::Const64Value>(proc, origin, currentOffset));
69
                    block->appendNew<B3::Const64Value>(proc, origin, currentOffset));
66
                argument = block->appendNew<B3::MemoryValue>(proc, B3::Load, toB3Type(argumentTypes[i]), origin, address);
70
                argument = block->appendNew<B3::MemoryValue>(proc, B3::Load, toB3Type(argumentTypes[i]), origin, address);
67
                currentOffset = updateOffset(currentOffset, argumentTypes[i]);
71
                currentOffset = updateOffset(currentOffset, toB3Type(argumentTypes[i]));
68
            }
72
            }
69
            functor(argument, i);
73
            functor(argument, i);
70
        }
74
        }
71
    }
75
    }
72
76
77
    template<typename Functor>
78
    B3::Value* setupCall(B3::Procedure& proc, B3::BasicBlock* block, B3::Origin origin, MacroAssemblerCodePtr target, const Vector<B3::Value*>& arguments, B3::Type returnType, const Functor& patchpointFunctor) const
79
    {
80
        unsigned stackArgumentCount = arguments.size() < m_registerArguments.size() ? 0 : arguments.size() - m_registerArguments.size();
81
        proc.requestCallArgAreaSizeInBytes(WTF::roundUpToMultipleOf(stackAlignmentBytes(), headerSize + (stackArgumentCount * sizeof(Register))));
82
83
        unsigned offset = headerSize;
84
        Vector<B3::ConstrainedValue> constrainedArguments;
85
        for (unsigned i = 0; i < arguments.size(); ++i) {
86
            B3::ValueRep rep;
87
            if (i < m_registerArguments.size())
88
                rep = B3::ValueRep::reg(m_registerArguments[i]);
89
            else
90
                rep = B3::ValueRep::stackArgument(offset);
91
            constrainedArguments.append(B3::ConstrainedValue(arguments[i], rep));
92
            offset = updateOffset(offset, arguments[i]->type());
93
        }
94
95
        B3::PatchpointValue* patchpoint = block->appendNew<B3::PatchpointValue>(proc, returnType, origin);
96
        patchpoint->appendVector(constrainedArguments);
97
        patchpointFunctor(patchpoint);
98
        patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) {
99
            AllowMacroScratchRegisterUsage allowScratch(jit);
100
101
            CCallHelpers::Call call = jit.call();
102
            jit.addPtr(
103
                CCallHelpers::TrustedImm32(-params.proc().frameSize()),
104
                GPRInfo::callFrameRegister, CCallHelpers::stackPointerRegister);
105
            jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
106
                    linkBuffer.link(call, FunctionPtr(target.executableAddress()));
107
            });
108
109
110
        });
111
112
        if (returnType != B3::Void)
113
            return patchpoint;
114
        return nullptr;
115
    }
116
73
    const Vector<GPRReg> m_registerArguments;
117
    const Vector<GPRReg> m_registerArguments;
74
    const RegisterSet m_calleeSaveRegisters;
118
    const RegisterSet m_calleeSaveRegisters;
75
    const RegisterSet m_callerSaveRegisters;
119
    const RegisterSet m_callerSaveRegisters;
76
};
120
};
77
121
78
inline unsigned nextJSCOffset(unsigned currentOffset, Type)
122
inline unsigned nextJSCOffset(unsigned currentOffset, B3::Type)
79
{
123
{
80
    return currentOffset + sizeof(Register);
124
    return currentOffset + sizeof(Register);
81
}
125
}
- a/Source/JavaScriptCore/wasm/WASMFormat.h +6 lines
Lines 45-50 a/Source/JavaScriptCore/wasm/WASMFormat.h_sec1
45
#if ENABLE(WEBASSEMBLY)
45
#if ENABLE(WEBASSEMBLY)
46
46
47
#include "B3Type.h"
47
#include "B3Type.h"
48
#include "B3Compilation.h"
48
#include <wtf/Vector.h>
49
#include <wtf/Vector.h>
49
#include <wtf/text/WTFString.h>
50
#include <wtf/text/WTFString.h>
50
51
Lines 126-131 struct FunctionInformation { a/Source/JavaScriptCore/wasm/WASMFormat.h_sec2
126
    size_t end;
127
    size_t end;
127
};
128
};
128
129
130
struct FunctionCompilation {
131
    std::unique_ptr<B3::Compilation> code;
132
    std::unique_ptr<B3::Compilation> jsEntryPoint;
133
};
134
129
} } // namespace JSC::WASM
135
} } // namespace JSC::WASM
130
136
131
#endif // ENABLE(WEBASSEMBLY)
137
#endif // ENABLE(WEBASSEMBLY)
- a/Source/JavaScriptCore/wasm/WASMFunctionParser.h +33 lines
Lines 154-159 bool FunctionParser<Context>::parseExpression(OpType op) a/Source/JavaScriptCore/wasm/WASMFunctionParser.h_sec1
154
        return true;
154
        return true;
155
    }
155
    }
156
156
157
    FOR_EACH_WASM_MEMORY_LOAD_OP(CREATE_CASE) {
158
        // TODO: What do I do with this?
159
        uint32_t alignment;
160
        if (!parseVarUInt32(alignment))
161
            return false;
162
163
        uint32_t offset;
164
        if (!parseVarUInt32(offset))
165
            return false;
166
167
        ExpressionType pointer = m_expressionStack.takeLast();
168
        ExpressionType result;
169
        if (!m_context.load(static_cast<LoadOpType>(op), offset, pointer, result))
170
            return false;
171
        m_expressionStack.append(result);
172
        return true;
173
    }
174
175
    FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_CASE) {
176
        // TODO: What do I do with this?
177
        uint32_t alignment;
178
        if (!parseVarUInt32(alignment))
179
            return false;
180
181
        uint32_t offset;
182
        if (!parseVarUInt32(offset))
183
            return false;
184
185
        ExpressionType value = m_expressionStack.takeLast();
186
        ExpressionType pointer = m_expressionStack.takeLast();
187
        return m_context.store(static_cast<StoreOpType>(op), offset, pointer, value);
188
    }
189
157
    case OpType::I32Const: {
190
    case OpType::I32Const: {
158
        uint32_t constant;
191
        uint32_t constant;
159
        if (!parseVarUInt32(constant))
192
        if (!parseVarUInt32(constant))
- a/Source/JavaScriptCore/wasm/WASMMemory.cpp +70 lines
Line 0 a/Source/JavaScriptCore/wasm/WASMMemory.cpp_sec1
1
/*
2
 * Copyright (C) 2016 Apple Inc. All rights reserved.
3
 *
4
 * Redistribution and use in source and binary forms, with or without
5
 * modification, are permitted provided that the following conditions
6
 * are met:
7
 * 1. Redistributions of source code must retain the above copyright
8
 *    notice, this list of conditions and the following disclaimer.
9
 * 2. Redistributions in binary form must reproduce the above copyright
10
 *    notice, this list of conditions and the following disclaimer in the
11
 *    documentation and/or other materials provided with the distribution.
12
 *
13
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
 */
25
26
#include "config.h"
27
#include "WASMMemory.h"
28
29
#if ENABLE(WEBASSEMBLY)
30
31
namespace JSC { namespace WASM {
32
33
Memory::Memory(uint32_t startingSize, uint32_t maxSize, const Vector<unsigned>& pinnedSizeRegisters)
34
: m_size(startingSize)
35
, m_maxSize(maxSize)
36
{
37
    ASSERT(pinnedSizeRegisters.size() > 0);
38
    // Perhaps we should try MAP_32BIT on X86-64 since that might allow B3 to emit better Loads/Stores.
39
    void* result = mmap(nullptr, maxSize, PROT_NONE, MAP_PRIVATE | MAP_ANON, 0, 0);
40
    if (!result)
41
        return;
42
43
    if (mprotect(result, startingSize, PROT_READ | PROT_WRITE)) {
44
        munmap(result, maxSize);
45
        return;
46
    }
47
48
    unsigned remainingPinnedRegisters = pinnedSizeRegisters.size() + 1;
49
    jscCallingConvention().m_calleeSaveRegisters.forEach([&] (Reg reg) {
50
        GPRReg gpr = reg.gpr();
51
        if (gpr == CCallHelpers::framePointerRegister || gpr == CCallHelpers::stackPointerRegister)
52
            return;
53
        if (!remainingPinnedRegisters)
54
            return;
55
        if (remainingPinnedRegisters == 1) {
56
            m_pinnedRegisters.baseMemoryPointer = gpr;
57
            remainingPinnedRegisters--;
58
        } else
59
            m_pinnedRegisters.sizeRegisters.append({ gpr, pinnedSizeRegisters[--remainingPinnedRegisters - 1] });
60
    });
61
62
    ASSERT(!remainingPinnedRegisters);
63
    m_memory = result;
64
}
65
66
} // namespace JSC
67
68
} // namespace WASM
69
70
#endif // ENABLE(WEBASSEMBLY)
- a/Source/JavaScriptCore/wasm/WASMMemory.h +84 lines
Line 0 a/Source/JavaScriptCore/wasm/WASMMemory.h_sec1
1
/*
2
 * Copyright (C) 2016 Apple Inc. All rights reserved.
3
 *
4
 * Redistribution and use in source and binary forms, with or without
5
 * modification, are permitted provided that the following conditions
6
 * are met:
7
 * 1. Redistributions of source code must retain the above copyright
8
 *    notice, this list of conditions and the following disclaimer.
9
 * 2. Redistributions in binary form must reproduce the above copyright
10
 *    notice, this list of conditions and the following disclaimer in the
11
 *    documentation and/or other materials provided with the distribution.
12
 *
13
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
 */
25
26
#pragma once
27
28
#if ENABLE(WEBASSEMBLY)
29
30
#include "WASMCallingConvention.h"
31
32
#include <wtf/Vector.h>
33
34
namespace JSC { namespace WASM {
35
36
struct PinnedSizeRegisterInfo {
37
    GPRReg sizeRegister;
38
    unsigned sizeOffset;
39
};
40
41
struct PinnedRegisterInfo {
42
    Vector<PinnedSizeRegisterInfo> sizeRegisters;
43
    GPRReg baseMemoryPointer;
44
};
45
46
class Memory {
47
    WTF_MAKE_NONCOPYABLE(Memory);
48
    WTF_MAKE_FAST_ALLOCATED;
49
public:
50
51
    Memory() = default;
52
    Memory(uint32_t startingSize, uint32_t maxSize, const Vector<unsigned>& pinnedSizeRegisters);
53
54
    ~Memory()
55
    {
56
        if (m_memory)
57
            munmap(m_memory, m_maxSize);
58
    }
59
60
    void* memory() const { return m_memory; }
61
    uint32_t size() const { return m_size; }
62
    const PinnedRegisterInfo& pinnedRegisters() const { return m_pinnedRegisters; }
63
64
    bool growMemory(uint32_t newSize)
65
    {
66
        ASSERT(m_memory);
67
        if (newSize > m_maxSize)
68
            return false;
69
70
        return !mprotect(m_memory, newSize, PROT_READ | PROT_WRITE);
71
    }
72
73
    static ptrdiff_t offsetOfSize() { return OBJECT_OFFSETOF(Memory, m_size); }
74
    
75
private:
76
    void* m_memory { nullptr };
77
    PinnedRegisterInfo m_pinnedRegisters;
78
    uint32_t m_size { 0 };
79
    uint32_t m_maxSize { 0 };
80
};
81
82
} } // namespace JSC::WASM
83
84
#endif // ENABLE(WEBASSEMLY)
- a/Source/JavaScriptCore/wasm/WASMModuleParser.cpp -4 / +46 lines
Lines 28-37 a/Source/JavaScriptCore/wasm/WASMModuleParser.cpp_sec1
28
28
29
#if ENABLE(WEBASSEMBLY)
29
#if ENABLE(WEBASSEMBLY)
30
30
31
#include "JSWASMModule.h"
31
#include "WASMFormat.h"
32
#include "WASMFormat.h"
32
#include "WASMOps.h"
33
#include "WASMOps.h"
33
#include "WASMSections.h"
34
#include "WASMSections.h"
34
35
36
#include <sys/mman.h>
37
35
namespace JSC { namespace WASM {
38
namespace JSC { namespace WASM {
36
39
37
static const bool verbose = false;
40
static const bool verbose = false;
Lines 62-76 bool ModuleParser::parse() a/Source/JavaScriptCore/wasm/WASMModuleParser.cpp_sec2
62
        if (verbose)
65
        if (verbose)
63
            dataLogLn("Starting to parse next section at offset: ", m_offset);
66
            dataLogLn("Starting to parse next section at offset: ", m_offset);
64
67
65
        Sections::Section section = Sections::Unknown;
66
        uint8_t sectionByte;
68
        uint8_t sectionByte;
67
        if (!parseUInt7(sectionByte))
69
        if (!parseUInt7(sectionByte))
68
            return false;
70
            return false;
69
71
72
        if (verbose)
73
            dataLogLn("Section byte: ", sectionByte);
74
75
        Sections::Section section = Sections::Unknown;
70
        if (sectionByte) {
76
        if (sectionByte) {
71
            if (sectionByte >= Sections::Unknown)
77
            if (sectionByte < Sections::Unknown)
72
                section = Sections::Unknown;
73
            else
74
                section = static_cast<Sections::Section>(sectionByte);
78
                section = static_cast<Sections::Section>(sectionByte);
75
        } else {
79
        } else {
76
            uint32_t sectionNameLength;
80
            uint32_t sectionNameLength;
Lines 96-101 bool ModuleParser::parse() a/Source/JavaScriptCore/wasm/WASMModuleParser.cpp_sec3
96
        unsigned end = m_offset + sectionLength;
100
        unsigned end = m_offset + sectionLength;
97
101
98
        switch (section) {
102
        switch (section) {
103
104
        case Sections::Memory: {
105
            if (verbose)
106
                dataLogLn("Parsing Memory.");
107
            if (!parseMemory())
108
                return false;
109
            break;
110
        }
111
99
        case Sections::FunctionTypes: {
112
        case Sections::FunctionTypes: {
100
            if (verbose)
113
            if (verbose)
101
                dataLogLn("Parsing types.");
114
                dataLogLn("Parsing types.");
Lines 143-148 bool ModuleParser::parse() a/Source/JavaScriptCore/wasm/WASMModuleParser.cpp_sec4
143
    return true;
156
    return true;
144
}
157
}
145
158
159
bool ModuleParser::parseMemory()
160
{
161
    uint32_t maxPageNum = std::numeric_limits<uint32_t>::max() / 64 / KB;
162
    uint8_t flags;
163
    if (!parseVarUInt1(flags))
164
        return false;
165
166
    uint32_t size;
167
    if (!parseVarUInt32(size))
168
        return false;
169
    if (size > maxPageNum)
170
        return false;
171
172
    uint32_t max = maxPageNum;
173
    if (flags) {
174
        if (!parseVarUInt32(max))
175
            return false;
176
        if (size > max || max > maxPageNum)
177
            return false;
178
    }
179
180
    max *= 64 * KB;
181
    size *= 64 * KB;
182
183
    Vector<unsigned> pinnedSizes = { 0 };
184
    m_memory = std::make_unique<Memory>(maxPageNum * 64 * KB, maxPageNum * 64 * KB, pinnedSizes);
185
    return m_memory->memory();
186
}
187
146
bool ModuleParser::parseFunctionTypes()
188
bool ModuleParser::parseFunctionTypes()
147
{
189
{
148
    uint32_t count;
190
    uint32_t count;
- a/Source/JavaScriptCore/wasm/WASMModuleParser.h -3 / +5 lines
Lines 28-33 a/Source/JavaScriptCore/wasm/WASMModuleParser.h_sec1
28
#if ENABLE(WEBASSEMBLY)
28
#if ENABLE(WEBASSEMBLY)
29
29
30
#include "WASMOps.h"
30
#include "WASMOps.h"
31
#include "WASMMemory.h"
31
#include "WASMParser.h"
32
#include "WASMParser.h"
32
#include <wtf/Vector.h>
33
#include <wtf/Vector.h>
33
34
Lines 45-62 public: a/Source/JavaScriptCore/wasm/WASMModuleParser.h_sec2
45
46
46
    bool WARN_UNUSED_RETURN parse();
47
    bool WARN_UNUSED_RETURN parse();
47
48
48
    const Vector<FunctionInformation>& functionInformation() { return m_functions; }
49
    const Vector<FunctionInformation>& functionInformation() const { return m_functions; }
50
    std::unique_ptr<Memory>& memory() { return m_memory; }
49
51
50
private:
52
private:
53
    bool WARN_UNUSED_RETURN parseMemory();
51
    bool WARN_UNUSED_RETURN parseFunctionTypes();
54
    bool WARN_UNUSED_RETURN parseFunctionTypes();
52
    bool WARN_UNUSED_RETURN parseFunctionSignatures();
55
    bool WARN_UNUSED_RETURN parseFunctionSignatures();
53
    bool WARN_UNUSED_RETURN parseFunctionDefinitions();
56
    bool WARN_UNUSED_RETURN parseFunctionDefinitions();
54
    bool WARN_UNUSED_RETURN parseFunctionDefinition(uint32_t number);
57
    bool WARN_UNUSED_RETURN parseFunctionDefinition(uint32_t number);
55
    bool WARN_UNUSED_RETURN parseBlock();
56
    bool WARN_UNUSED_RETURN parseExpression(OpType);
57
58
58
    Vector<FunctionInformation> m_functions;
59
    Vector<FunctionInformation> m_functions;
59
    Vector<Signature> m_signatures;
60
    Vector<Signature> m_signatures;
61
    std::unique_ptr<Memory> m_memory;
60
};
62
};
61
63
62
} } // namespace JSC::WASM
64
} } // namespace JSC::WASM
- a/Source/JavaScriptCore/wasm/WASMOps.h -1 / +36 lines
Lines 103-113 namespace JSC { namespace WASM { a/Source/JavaScriptCore/wasm/WASMOps.h_sec1
103
    macro(I64LeU, 0x6d, BelowEqual) \
103
    macro(I64LeU, 0x6d, BelowEqual) \
104
104
105
105
106
#define FOR_EACH_WASM_MEMORY_LOAD_OP(macro) \
107
    macro(I32Load8S, 0x20, NA) \
108
    macro(I32Load8U, 0x21, NA) \
109
    macro(I32Load16S, 0x22, NA) \
110
    /* macro(I32Load16U, 0x23, NA) */ \
111
    macro(I64Load8S, 0x24, NA) \
112
    macro(I64Load8U, 0x25, NA) \
113
    macro(I64Load16S, 0x26, NA) \
114
    /* macro(I64Load16U, 0x27, NA) */ \
115
    macro(I64Load32S, 0x28, NA) \
116
    macro(I64Load32U, 0x29, NA) \
117
    macro(I32Load, 0x2a, NA) \
118
    macro(I64Load, 0x2b, NA) \
119
120
121
#define FOR_EACH_WASM_MEMORY_STORE_OP(macro) \
122
    macro(I32Store8, 0x2e, NA) \
123
    macro(I32Store16, 0x2f, NA) \
124
    macro(I64Store8, 0x30, NA) \
125
    macro(I64Store16, 0x31, NA) \
126
    macro(I64Store32, 0x32, NA) \
127
    macro(I32Store, 0x33, NA) \
128
    macro(I64Store, 0x34, NA) \
129
130
106
#define FOR_EACH_WASM_OP(macro) \
131
#define FOR_EACH_WASM_OP(macro) \
107
    FOR_EACH_WASM_SPECIAL_OP(macro) \
132
    FOR_EACH_WASM_SPECIAL_OP(macro) \
108
    FOR_EACH_WASM_CONTROL_FLOW_OP(macro) \
133
    FOR_EACH_WASM_CONTROL_FLOW_OP(macro) \
109
    FOR_EACH_WASM_UNARY_OP(macro) \
134
    FOR_EACH_WASM_UNARY_OP(macro) \
110
    FOR_EACH_WASM_BINARY_OP(macro)
135
    FOR_EACH_WASM_BINARY_OP(macro) \
136
    FOR_EACH_WASM_MEMORY_LOAD_OP(macro) \
137
    FOR_EACH_WASM_MEMORY_STORE_OP(macro)
111
138
112
#define CREATE_ENUM_VALUE(name, id, b3op) name = id,
139
#define CREATE_ENUM_VALUE(name, id, b3op) name = id,
113
140
Lines 123-128 enum class UnaryOpType : uint8_t { a/Source/JavaScriptCore/wasm/WASMOps.h_sec2
123
    FOR_EACH_WASM_UNARY_OP(CREATE_ENUM_VALUE)
150
    FOR_EACH_WASM_UNARY_OP(CREATE_ENUM_VALUE)
124
};
151
};
125
152
153
enum class LoadOpType : uint8_t {
154
    FOR_EACH_WASM_MEMORY_LOAD_OP(CREATE_ENUM_VALUE)
155
};
156
157
enum class StoreOpType : uint8_t {
158
    FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_ENUM_VALUE)
159
};
160
126
#undef CREATE_ENUM_VALUE
161
#undef CREATE_ENUM_VALUE
127
162
128
inline bool isControlOp(OpType op)
163
inline bool isControlOp(OpType op)
- a/Source/JavaScriptCore/wasm/WASMPlan.cpp -1 / +3 lines
Lines 30-35 a/Source/JavaScriptCore/wasm/WASMPlan.cpp_sec1
30
30
31
#include "B3Compilation.h"
31
#include "B3Compilation.h"
32
#include "WASMB3IRGenerator.h"
32
#include "WASMB3IRGenerator.h"
33
#include "WASMCallingConvention.h"
33
#include "WASMModuleParser.h"
34
#include "WASMModuleParser.h"
34
#include <wtf/DataLog.h>
35
#include <wtf/DataLog.h>
35
36
Lines 53-60 Plan::Plan(VM& vm, Vector<uint8_t> source) a/Source/JavaScriptCore/wasm/WASMPlan.cpp_sec2
53
    for (const FunctionInformation& info : moduleParser.functionInformation()) {
54
    for (const FunctionInformation& info : moduleParser.functionInformation()) {
54
        if (verbose)
55
        if (verbose)
55
            dataLogLn("Processing funcion starting at: ", info.start, " and ending at: ", info.end);
56
            dataLogLn("Processing funcion starting at: ", info.start, " and ending at: ", info.end);
56
        result.append(parseAndCompile(vm, source, info));
57
        result.append(parseAndCompile(vm, source, moduleParser.memory().get(), info));
57
    }
58
    }
59
    memory = WTFMove(moduleParser.memory());
58
}
60
}
59
61
60
} } // namespace JSC::WASM
62
} } // namespace JSC::WASM
- a/Source/JavaScriptCore/wasm/WASMPlan.h -8 / +5 lines
Lines 29-51 a/Source/JavaScriptCore/wasm/WASMPlan.h_sec1
29
29
30
#include "CompilationResult.h"
30
#include "CompilationResult.h"
31
#include "VM.h"
31
#include "VM.h"
32
#include "WASMFormat.h"
32
#include <wtf/ThreadSafeRefCounted.h>
33
#include <wtf/ThreadSafeRefCounted.h>
33
#include <wtf/Vector.h>
34
#include <wtf/Vector.h>
34
35
35
namespace JSC {
36
namespace JSC { namespace WASM {
36
37
class Memory;
37
namespace B3 {
38
class Compilation;
39
} // namespace B3
40
41
namespace WASM {
42
38
43
// TODO: This should create a WASM Module not a list of functions.
39
// TODO: This should create a WASM Module not a list of functions.
44
class Plan {
40
class Plan {
45
public:
41
public:
46
    JS_EXPORT_PRIVATE Plan(VM&, Vector<uint8_t> source);
42
    JS_EXPORT_PRIVATE Plan(VM&, Vector<uint8_t> source);
47
43
48
    Vector<std::unique_ptr<B3::Compilation>> result;
44
    Vector<std::unique_ptr<FunctionCompilation>> result;
45
    std::unique_ptr<Memory> memory;
49
};
46
};
50
47
51
} } // namespace JSC::WASM
48
} } // namespace JSC::WASM
- a/Source/JavaScriptCore/wasm/WASMSections.h +1 lines
Lines 33-38 struct Sections { a/Source/JavaScriptCore/wasm/WASMSections.h_sec1
33
    enum Section : uint8_t {
33
    enum Section : uint8_t {
34
        FunctionTypes = 1,
34
        FunctionTypes = 1,
35
        Signatures = 3,
35
        Signatures = 3,
36
        Memory = 5,
36
        Definitions = 10,
37
        Definitions = 10,
37
        Unknown
38
        Unknown
38
    };
39
    };

Return to Bug 161710