Source/JavaScriptCore/ChangeLog

112016-10-31 Keith Miller <keith_miller@apple.com>
22
 3 Add a WASM function validator.
 4 https://bugs.webkit.org/show_bug.cgi?id=161707
 5
 6 Reviewed by Saam Barati.
 7
 8 This is a new template specialization of the Wasm FunctionParser class. Instead of having
 9 the FunctionParser track what B3 values each stack entry refers to the validator has each
 10 entry refer to the type of the stack entry. Additionally, the control stack tracks what type
 11 of block the object is and what the result type of the block is. The validation functions
 12 for unary, binary, and memory operations are autogenerated by the
 13 generateWasmValidateInlinesHeader.py script.
 14
 15 There are still a couple issue with validating that will be addressed in follow-up patches.
 16 1) We need to handle result types from basic blocks. https://bugs.webkit.org/show_bug.cgi?id=164100
 17 2) We need to handle popping things from stacks when they don't exist. https://bugs.webkit.org/show_bug.cgi?id=164275
 18
 19 * CMakeLists.txt:
 20 * DerivedSources.make:
 21 * JavaScriptCore.xcodeproj/project.pbxproj:
 22 * testWasm.cpp:
 23 (runWasmTests):
 24 * wasm/WasmB3IRGenerator.cpp:
 25 * wasm/WasmFormat.cpp: Added.
 26 (JSC::Wasm::toString):
 27 * wasm/WasmFormat.h:
 28 * wasm/WasmFunctionParser.h:
 29 (JSC::Wasm::FunctionParser<Context>::parseExpression):
 30 (JSC::Wasm::FunctionParser<Context>::parseUnreachableExpression):
 31 * wasm/WasmPlan.cpp:
 32 (JSC::Wasm::Plan::Plan):
 33 * wasm/WasmValidate.cpp: Added.
 34 (JSC::Wasm::Validate::ControlData::ControlData):
 35 (JSC::Wasm::Validate::ControlData::dump):
 36 (JSC::Wasm::Validate::ControlData::type):
 37 (JSC::Wasm::Validate::ControlData::signature):
 38 (JSC::Wasm::Validate::addConstant):
 39 (JSC::Wasm::Validate::isContinuationReachable):
 40 (JSC::Wasm::Validate::errorMessage):
 41 (JSC::Wasm::Validate::Validate):
 42 (JSC::Wasm::Validate::addArguments):
 43 (JSC::Wasm::Validate::addLocal):
 44 (JSC::Wasm::Validate::getLocal):
 45 (JSC::Wasm::Validate::setLocal):
 46 (JSC::Wasm::Validate::addBlock):
 47 (JSC::Wasm::Validate::addLoop):
 48 (JSC::Wasm::Validate::addIf):
 49 (JSC::Wasm::Validate::addElse):
 50 (JSC::Wasm::Validate::addReturn):
 51 (JSC::Wasm::Validate::addBranch):
 52 (JSC::Wasm::Validate::endBlock):
 53 (JSC::Wasm::Validate::addCall):
 54 (JSC::Wasm::Validate::unify):
 55 (JSC::Wasm::Validate::dump):
 56 (JSC::Wasm::validateFunction):
 57 * wasm/WasmValidate.h: Added.
 58 * wasm/generateWasmValidateInlinesHeader.py: Added.
 59 (cppType):
 60 (toCpp):
 61 (unaryMacro):
 62 (binaryMacro):
 63 (loadMacro):
 64 (storeMacro):
 65
 662016-10-31 Keith Miller <keith_miller@apple.com>
 67
368 autogenerated files from wasm.json should be in derived sources.
469 https://bugs.webkit.org/show_bug.cgi?id=164152
570

10711136
10721137 Async functions generate bytecode equivalent to the following, which is
10731138 highly dependent on the Generator implementation:
1074 
 1139
10751140 ```
10761141 // Before translation:
10771142 async function asyncfn() {}

10931158 Await Expressions are equivalent to non-delegating Yield expressions, and emit identical bytecode.
10941159
10951160 There are some caveats to be addressed later:
1096 
 1161
10971162 1) the `op_to_this` is always performed, whether it's used or not, like normal generators. (https://bugs.webkit.org/show_bug.cgi?id=151586)
1098 
 1163
10991164 2) for async arrow functions, the home object is always stored on the "body" function, regardless of whether it's needed or
11001165 not, for the same reason as #1 (and should also be fixed as part of https://bugs.webkit.org/show_bug.cgi?id=151586)
11011166

12031268 For lazily reified properties, JSFunction::put() implements complex conditional
12041269 behavior that is different than the set of cacheable put operations above.
12051270 Hence, it should not claim that the property put is cacheable.
1206 
 1271
12071272 2. Cacheable puts are cached on the original structure of the object before the
12081273 put operation.
12091274

14611526 https://bugs.webkit.org/show_bug.cgi?id=163947
14621527
14631528 Reviewed by Geoffrey Garen.
1464 
 1529
14651530 I want to introduce another HeapTimer. Prior to this change, that would have meant writing
14661531 exact copies of that timer's logic for each platform that has a HeapTimer (CF, GLIB, and
14671532 EFL). That logic would in turn be a duplicate of the logic already present in

14691534 own code for scheduling timers, so a new subclass would have to duplicate that code. Then,
14701535 to add insult to injury, the USE(CF) version of HeapTimer would have to have an extra case
14711536 for that new subclass since it doesn't use virtual methods effectively.
1472 
 1537
14731538 This changes HeapTimer on USE(CF) to know to get its runloop from Heap and to use virtual
14741539 methods effectively so that it doesn't have to know about all of its subclasses.
1475 
 1540
14761541 This also moves IncrementalSweeper's code for scheduling timers into HeapTimer. This means
14771542 that future subclasses of HeapTimer could simply use that logic.
1478 
 1543
14791544 This keeps changes to GCActivityCallback to a minimum. It still has a lot of
14801545 platform-specific code and I'm not sure that this code can be trivially deduplicated since
14811546 that code has more quirks. That's fine for now, since I mainly just need a sane way of

21042169 https://bugs.webkit.org/show_bug.cgi?id=163802
21052170
21062171 Reviewed by Keith Miller.
2107 
 2172
21082173 JSC often suffers from the inline cargo cult, and Heap is a prime example. This outlines a
21092174 bunch of Heap methods that are either already very big, or call out-of-line methods, or call
21102175 very big methods, or are not called often enough for inlining to matter.
2111 
 2176
21122177 This simplifies concurrent GC work because I'm so tired of recompiling the world when I touch
21132178 one of these methods.
2114 
 2179
21152180 This looks to be perf-neutral.
21162181
21172182 * heap/Heap.cpp:

24812546 https://bugs.webkit.org/show_bug.cgi?id=163738
24822547
24832548 Reviewed by Geoffrey Garen.
2484 
 2549
24852550 We need to know if we're currently in an allocation slow path, so that code can assert that
24862551 it's not being used from inside a destructor that runs during a sweep. We need to know if
24872552 we're currently collecting, because some code behaves differently during collection, and

24892554 runs during marking. If we are collecting, we need to know if it's an eden collection or a
24902555 full collection. If we are requesting a collection, we need to know if we're requesting an
24912556 eden collection, a full collection, or any kind of collection.
2492 
 2557
24932558 Prior to this change, you would reason about all of these things using the HeapOperation. It
24942559 had the following states: NoOperation, Allocation, FullCollection, EdenCollection, and
24952560 AnyCollection. NoOperation versus Allocation was primarily for asserting that sweep didn't

24972562 would even use HeapOperation in places where we knew that it could only be either Full or
24982563 Eden, because we just needed a variable to tell us which generation we were talking about.
24992564 It was all very confusing.
2500 
 2565
25012566 Where it completely breaks down is the fact that a concurrent GC has two logical threads, the
25022567 mutator and the collector, which can change state independently. The mutator can be
25032568 allocating. It can also be doing some work to help the GC. That's three states: running,

25072572 states: every combination of mutator running, allocating, or helping GC, crossed with
25082573 collector not running, running eden, or running full. So, this change decouples mutator state
25092574 from collector state and uses two separate fields with two different types.
2510 
 2575
25112576 Mutator state is described using MutatorState, which can be either MutatorState::Running,
25122577 MutatorState::Allocating, or MutatorState::HelpingGC.
2513 
 2578
25142579 Collector state is described using Optional<CollectionScope>. CollectionScope describes how
25152580 big the scope of the collection is, and it can be either CollectionScope::Eden or
25162581 CollectionScope::Full. If the Optional is Nullopt, it means that we are not collecting. This

25192584 want to know about the generation. Also, we can use Nullopt in methods that request
25202585 collection, which those methods take to mean that they can run any kind of collection (the
25212586 old AnyCollection).
2522 
 2587
25232588 Another use of HeapOperation was to answer questions about whether the caller is running as
25242589 part of the GC or as part of the mutator. Optional<CollectionScope> does not answer this,
25252590 since code that runs in the mutator while the mutator is not HelpingGC at the same time as

25362601 checks look for GCThreadType::Helper. The "should I run as mutator" query can now be answered
25372602 by checking with mayBeGCThread, which returns Optional<GCThreadType>; if engaged, then run as
25382603 GC, else run as GC if MutatorState is HelpingGC, else run as mutator.
2539 
 2604
25402605 This doesn't change the way that the GC behaves, but it does change how the GC represents a
25412606 fundamental piece of state. So, it's a big change. It should be perf-neutral (still testing).
25422607

30963161 https://bugs.webkit.org/show_bug.cgi?id=163686
30973162
30983163 Reviewed by Geoffrey Garen.
3099 
 3164
31003165 Change the JITWorklist to use AutomaticThread, so that the Baseline JIT's concurrent
31013166 compiler thread shuts down automatically after inactivity.
3102 
 3167
31033168 With this change, all of JSC's threads shut down automatically. If you run splay for a few
31043169 seconds (which fires up all threads - compiler and GC) and then go to sleep for a second,
31053170 you'll see that the only threads left are the main thread and the bmalloc thread.

31423207 https://bugs.webkit.org/show_bug.cgi?id=163615
31433208
31443209 Reviewed by Mark Lam.
3145 
 3210
31463211 AutomaticThread is a new feature in WTF that allows you to easily create worker threads that
31473212 shut down automatically. This changes DFG::Worklist to use AutomaticThread, so that its
31483213 threads shut down automatically, too. This has the potential to save a lot of memory.
3149 
 3214
31503215 This required some improvements to AutomaticThread: Worklist likes to be able to keep state
31513216 around for the whole lifetime of a thread, and so it likes knowing when threads are born and
31523217 when they die. I added virtual methods for that. Also, Worklist uses notifyOne() so I added
31533218 that, too.
3154 
 3219
31553220 This looks to be perf-neutral.
31563221
31573222 * dfg/DFGThreadData.cpp:

33153380 https://bugs.webkit.org/show_bug.cgi?id=163576
33163381
33173382 Reviewed by Andreas Kling.
3318 
 3383
33193384 Added a sleepSeconds() function, which made it easier for me to test this change.
3320 
 3385
33213386 The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
33223387 shut down automatically after 1 second of inactivity. Maybe this will save some memory.
33233388

33453410 https://bugs.webkit.org/show_bug.cgi?id=163371
33463411
33473412 Reviewed by Geoffrey Garen and Saam Barati.
3348 
 3413
33493414 This adds a new kind of call inline cache for when the DFG can prove what the callee
33503415 executable is. In those cases, we can skip some of the things that the traditional call IC
33513416 would do:
3352 
 3417
33533418 - No need to check who the callee is.
33543419 - No need to do arity checks.
3355 
 3420
33563421 This case isn't as simple as just emitting a call instruction since the callee may not be
33573422 compiled at the time that the caller is compiled. So, we need lazy resolution. Also, the
33583423 callee may be jettisoned independently of the caller, so we need to be able to revert the
33593424 call to an unlinked state. This means that we need almost all of the things that
33603425 CallLinkInfo has. CallLinkInfo already knows about different kinds of calls. This patch
33613426 teaches it about new "Direct" call types.
3362 
 3427
33633428 The direct non-tail call IC looks like this:
3364 
 3429
33653430 set up arguments
33663431 FastPath:
33673432 call _SlowPath
33683433 lea -FrameSize(%rbp), %rsp
3369 
 3434
33703435 SlowPath:
33713436 pop
33723437 call operationLinkDirectCall
33733438 check exception
33743439 jmp FastPath
3375 
 3440
33763441 The job of operationLinkDirectCall is to link the fast path's call entrypoint of the callee.
33773442 This means that in steady state, a call is just that: a call. There are no extra branches or
33783443 checks.
3379 
 3444
33803445 The direct tail call IC is a bit more complicated because the act of setting up arguments
33813446 destroys our frame, which would prevent us from being able to throw an exception if we
33823447 failed to compile the callee. So, direct tail call ICs look like this:
3383 
 3448
33843449 jmp _SlowPath
33853450 FastPath:
33863451 set up arguments
33873452 jmp 0 // patch to jump to callee
3388 
 3453
33893454 SlowPath:
33903455 silent spill
33913456 call operationLinkDirectCall
33923457 silent fill
33933458 check exception
33943459 jmp FastPath
3395 
 3460
33963461 The jmp to the slow path is patched to be a fall-through jmp when we link the call.
3397 
 3462
33983463 Direct calls mean less code at call sites, fewer checks on the steady state call fast path,
33993464 and no need for arity fixup. This looks like a slight speed-up (~0.8%) on both Octane and
34003465 AsmBench.

35553620 Specific items which do not contain "prototype" include (most) built-in functions (such as Math.pow),
35563621 MethodDefinitions which are not either class "constructor" methods or GeneratorMethods, AsyncFunctions,
35573622 and ArrowFunctions.
3558 
 3623
35593624 For details, see the following spec text, and the difference between GeneratorMethod evaluation and
35603625 the evaluation of other MethodDefinition forms.
3561 
 3626
35623627 - https://tc39.github.io/ecma262/#sec-method-definitions-runtime-semantics-propertydefinitionevaluation
35633628 - https://tc39.github.io/ecma262/#sec-arrow-function-definitions-runtime-semantics-evaluation
35643629 - https://tc39.github.io/ecmascript-asyncawait/#async-function-instances
35653630 - https://tc39.github.io/ecma262/#sec-generator-function-definitions-runtime-semantics-propertydefinitionevaluation
3566 
 3631
35673632
35683633 * runtime/Executable.h:
35693634 * runtime/JSFunction.cpp:

37093774 <rdar://problem/28804381>
37103775
37113776 Reviewed by Geoffrey Garen.
3712 
 3777
37133778 Before r207408, IRC had a mode where it would silently assign the first assignable register (so
37143779 %rax, %xmm0, etc) to any tmp that was not colorable due to a pathological interference fencepost.
37153780 We reason about interference at instruction boundaries. This means that if you have, for example,

37203785 to only be hit by fuzzing, which may not then stress that code enough to shake out the register
37213786 corruption. Also, this can only happen for floating point registers, so it's hard to get an
37223787 exciting crash. The worst case is that your numbers get all messed up.
3723 
 3788
37243789 This change fixes the issue:
3725 
 3790
37263791 - IRC will now crash if it can't color a tmp.
3727 
 3792
37283793 - IRC doesn't crash on our tests anymore because I added a padInterference() utility that works
37293794 around the interference problem by inserting Nops to pad between those instructions where
37303795 conflating their early and late actions into one interference fencepost could create an
37313796 uncolorable graph.
3732 
 3797
37333798 See https://bugs.webkit.org/show_bug.cgi?id=163548#c2 for a detailed discussion of how the
37343799 problem can arise.
3735 
 3800
37363801 This problem almost made me want to abandon our use of interference at instruction boundaries,
37373802 and introduce something more comprehensive, like interference at various stages of an
37383803 instruction's execution. The reason why I didn't do this is that this problem only arises in well

37463811 padInterference() so the IR stays nice and compact. Those Nops get removed by any phase that does
37473812 DCE, which includes eliminateDeadCode(), allocateStack(), and reportUsedRegisters(). In practice
37483813 allocateStack() kills them.
3749 
 3814
37503815 This also finally refactors our passing of RegisterSet to pass it by value, since it's small
37513816 enough that we're not gaining anything by using references. On x86, RegisterSet ought to be
37523817 smaller than a pointer.

40134078 https://bugs.webkit.org/show_bug.cgi?id=163509
40144079
40154080 Reviewed by Mark Lam.
4016 
 4081
40174082 The worklist building function in IRC skips temporaries that have no degree. This doesn't appear
40184083 to be necessary. This has been there since the original IRC commit. It hasn't caused bugs because
40194084 ordinarily, the only way to have a tmp with no degree is to not have any mention of that tmp. But
40204085 while working on bug 163371, I hit a crazy corner case where a temporary would have no
40214086 interference edges (i.e. no degree). Here's how it happens:
4022 
 4087
40234088 A spill tmp from a previous iteration of IRC may have no degree: imagine a tmp that is live
40244089 everywhere and interferes with everyone, but has one use like:
40254090

40394104
40404105 Then, we might coalesce %someOtherTmp with %newTmp. Once this happens, if we make the %newTmp be
40414106 the master, we're in deep trouble because %newTmp is not on any worklist.
4042 
 4107
40434108 I don't know how to reproduce this except through the patch in bug 163371. Removing the two lines
40444109 of code that skipped no-degree tmps causes no regressions, and resolves the problem I was having.
40454110

44234488 https://bugs.webkit.org/show_bug.cgi?id=163343
44244489
44254490 Reviewed by Mark Lam.
4426 
 4491
44274492 When I first added the concept of NewGrey/OldGrey, I had the SlotVisitor store the old cell
44284493 state in itself, so that it could use it to decide what to do for reportExtraMemoryVisited().
4429 
 4494
44304495 Then I changed it in a recent commit, because I wanted the freedom to have SlotVisitor visit
44314496 multiple objects in tandem. But I never ended up using this capability. Still, I liked the
44324497 new way better: instead of the SlotVisitor rembemering the state-before-blackening, we would
44334498 make the object's state reflect whether it was black for the first time or not. That seemed
44344499 convenient.
4435 
 4500
44364501 Unfortunately it's wrong. After we blacken the object, a concurrent barrier could instantly
44374502 grey it. Then we would forget that we are visiting this object for the first time.
44384503 Subsequent visits will think that they are not the first. So, we will fail to do the right
44394504 thing in reportExtraMemoryVisited().
4440 
 4505
44414506 So, this reverts that change. This is a little more than just a revert, though. I've changed
44424507 the terminology a bit. For example, I got tired of reading Black and having to remind myself
44434508 that it really means that the object has begun being visited, instead of the more strict
44444509 meaning that implies that it has already been visited. We want to say that it's Black or
44454510 currently being scanned. I'm going to adopt Siebert's term for this: Anthracite [1]. So, our
44464511 black CellState is now called AnthraciteOrBlack.
4447 
 4512
44484513 [1] https://pdfs.semanticscholar.org/7ae4/633265aead1f8835cf7966e179d02c2c8a4b.pdf
44494514
44504515 * heap/CellState.h:

45444609 https://bugs.webkit.org/show_bug.cgi?id=163337
45454610
45464611 Reviewed by Mark Lam.
4547 
 4612
45484613 It turns out that HeapSnapshot was not down with revisiting. The concurrent GC is going to be
45494614 built around the idea that we can revisit objects many times. This means that any action that
45504615 should only take place once per object must check the object's state. This fixes the snapshot
45514616 code to do this.
4552 
 4617
45534618 While writing this code, I realized that we're actually doing this check incorrectly, so I
45544619 filed bug 163343. That bug requires a race, so we aren't going to see it yet.
45554620

45804645
45814646 (InjectedScript.prototype._describe):
45824647 Provide a friendlier name, "Proxy" instead of "ProxyObject".
4583 
 4648
45844649 (InjectedScript.RemoteObject):
45854650 When generating a preview for a Proxy object, generate it from the final target
45864651 and mark it as lossy so that the object can always be expanded to get the internal

46194684 and we asserted that it matched a breakpoint location identified
46204685 by the parser. This could get out of sync, or nodes could forget to
46214686 emit debug hooks expected by the parser.
4622 
 4687
46234688 With this change, we always check and emit a debug hook for any
46244689 node. The default behavior is for BytecodeGenerator::emitNode
46254690 to emit the debug hook when emitting the node itself. This covers

47644829 https://bugs.webkit.org/show_bug.cgi?id=163334
47654830
47664831 Reviewed by Mark Lam.
4767 
 4832
47684833 I guess that the idea of JITWriteBarrier was to make sure that if you slap some heap pointer
47694834 bits into machine code, then you better execute a barrier on the code block. But it's a
47704835 complicated piece of code, and I can never remember how it quite works. These days it looks

47724837 not really necessary to have something like this, since our convention is that any pointer
47734838 stored in machine code must always be shadowed in the GC heap. I think that convention has
47744839 won by overwhelming majority, so we should finally remove JITWriteBarrier.
4775 
 4840
47764841 A practical outcome of this change is that it makes it easier to implement DirectCall ICs,
47774842 which will have to store the callee in the CallLinkInfo but not in the machine code.
47784843

48214886 https://bugs.webkit.org/show_bug.cgi?id=162309
48224887
48234888 Reviewed by Geoffrey Garen.
4824 
 4889
48254890 It used to be that we would forget which objects are live the moment we started collection.
48264891 That's because the flip at the beginning clears all mark bits.
4827 
 4892
48284893 But we already have a facility for tracking objects that are live-but-not-marked. It's called
48294894 newlyAllocated. So, instead of clearing mark bits, we want to just transfer them to
48304895 newlyAllocated. Then we want to clear all newlyAllocated after GC.
4831 
 4896
48324897 This implements such an approach, along with a versioning optimization for newlyAllocated.
48334898 Instead of walking the whole heap to clear newlyAllocated bits at the end of the GC, we bump
48344899 the newlyAllocatedVersion, which causes MarkedBlock to treat newlyAllocated as if it was
48354900 clear.
4836 
 4901
48374902 We could have even avoided allocating newlyAllocated in most cases, since empirically most
48384903 blocks are either completely empty or completely full. An earlier version of this patch did
48394904 this, but it was not better than this patch. In fact, it seemed to actually be worse for PLT
48404905 and membuster.
4841 
 4906
48424907 To validate this change, we now run the conservative scan after the beginMarking flip. And it
48434908 totally works!
4844 
 4909
48454910 This is a huge step towards concurrent GC. It means that we ought to be able to run the
48464911 allocator while marking. Since we already separately made it possible to run the barrier
48474912 while marking, this means that we're pretty much ready for some serious concurrency action.
4848 
 4913
48494914 This appears to be perf-neutral and space-neutral.
48504915
48514916 * JavaScriptCore.xcodeproj/project.pbxproj:

50025067 https://bugs.webkit.org/show_bug.cgi?id=162749
50035068
50045069 Reviewed by Yusuke Suzuki.
5005 
 5070
50065071 We have a lot of defenses against emitting code that materializes huge contants. But if we do
50075072 end up with such code in the backend, it's better to convert those materializations into add
50085073 instructions by checking if other registers are known to contain nearby constants. That's

50175082 https://bugs.webkit.org/show_bug.cgi?id=163264
50185083
50195084 Reviewed by Mark Lam.
5020 
 5085
50215086 When writing the lea patch (r207039), I was very careful about how I convert a Shl into a
50225087 BaseIndex scale. But I forgot to check if the older code for creating BaseIndexes for
50235088 effectiveAddr() got this right. It turns out that the older code missed the <<32 corner
50245089 case.
5025 
 5090
50265091 It's sad that the two paths can't share all of their code, but it's somewhat inevitable due
50275092 to how matching an address and matching a lea have to do very different things. Matching a
50285093 lea means creating an instruction that is distinct from other instructions to do multiple

50325097 has to figure out Add(@value, $const) on its own. This change makes the situation slightly
50335098 more sane by adding a scaleForShl() helper that handles this weird case. It's based on the
50345099 new Shl handling from r207039, and exposes it as an API for effectiveAddr() to use.
5035 
 5100
50365101 The testLoadBaseIndexShift32() used to crash. I don't think that this case affects JS
50375102 content, since <<32 is such a bizarre outlier. I don't think we even have a path along
50385103 which the FTL would emit a 64-bit <<32. It probably won't even affect WebAssembly since

50835148 https://bugs.webkit.org/show_bug.cgi?id=163234
50845149
50855150 Reviewed by Saam Barati.
5086 
 5151
50875152 This adds comprehensive support for emitting lea on x86.
5088 
 5153
50895154 When adding this, I found that it was useful to also finally add more reassociation. That
50905155 reduces the amount of patterns that the instruction selector has to deal with.
50915156

52245289 https://bugs.webkit.org/show_bug.cgi?id=163175
52255290
52265291 Reviewed by Keith Miller.
5227 
 5292
52285293 You can now call Procedure::pinRegister(), or Code::pinRegister(), and it will make this
52295294 register behave as follows:
5230 
 5295
52315296 - B3 and Air will emit no code that modifies the value in this register, except if that
52325297 happens via a Patchpoint or stackmap constraint (i.e. the user explicitly asked for it).
52335298 - B3 and Air will allow others to modify the register. For example, if the register is not

52385303 changing). For example, if we went back to having pinned tag registers, we would tell B3
52395304 to use them by (1) excluding them from any clobber set (easy, since they're callee save)
52405305 and (2) emitting ArgumentReg to grab their value. There's a test that does this.
5241 
5242  This is accomplished by taking regsInPriorityOrder() and making it a method of Code. Air
 5306
 5307 This is accomplished by taking regsInPriorityOrder() and making it a method of Code. Air
52435308 already used this API when choosing registers in register allocation. Code now also vends a
52445309 mutableRegs() set, which is derived from regsInPriorityOrder(), that can quickly tell you if
52455310 a register can be mutated. Doing it this way means that most of this is a purely mechanical
52465311 change. The calls to mutableRegs() are the places where we had to change logic:
5247 
 5312
52485313 - The register allocators needs to know that coalescing with a precolored pinned tmp is free.
52495314 - The callee-save handler needs to know that we're not supposed to save/restore pinned
52505315 registers.
5251 
 5316
52525317 Note that in this scheme, pinned registers are simply registers that do not appear in
52535318 regsInPriorityOrder(). This means, for example, that we will now say that FP is pinned. So,
52545319 this means that you can also pin registers by calling setRegsInPriorityOrder() and passing a

53035368 https://bugs.webkit.org/show_bug.cgi?id=163172
53045369
53055370 Reviewed by Keith Miller.
5306 
 5371
53075372 If we have mutable pinned registers then we need to know which operations mutate them. At
53085373 first I considered making this into a heap range thing, but I think that this would be very
53095374 confusing. Also, in the future, we might want to make Effects track register sets of

63046369 the instruction stream with NOPs to provide space for a jump. This changes
63056370 Air::generate() to use labelIgnoringWatchpoints() to create pcToOriginMap
63066371 entries to eliminate unneccesary NOPs.
6307 
 6372
63086373 * b3/air/AirGenerate.cpp:
63096374 (JSC::B3::Air::generate):
63106375 * b3/testb3.cpp:

63386403 https://bugs.webkit.org/show_bug.cgi?id=162845
63396404
63406405 Reviewed by Geoffrey Garen.
6341 
 6406
63426407 While writing some documentation, I found some small holes in the code.
63436408
63446409 * b3/B3Effects.cpp:

64376502 https://bugs.webkit.org/show_bug.cgi?id=162842
64386503
64396504 Reviewed by Dan Bernstein.
6440 
 6505
64416506 This function has become dead code. This change removes it.
64426507
64436508 * heap/CellContainer.h:

64926557 https://bugs.webkit.org/show_bug.cgi?id=162689
64936558
64946559 Reviewed by Geoffrey Garen.
6495 
 6560
64966561 This adds a traps flag to B3::Kind. It also makes B3::Kind work more like Air::Kind, in the
64976562 sense that it's a bag of distinct bits - it doesn't need to be a union unless we get enough
64986563 things that it would make a difference.
6499 
 6564
65006565 The only analysis that needs to know about traps is effects. It now knows that traps implies
65016566 sideExits, which means that this turns off DCE. The only optimization that needs to know
65026567 about traps is eliminateCommonSubexpressions(), which needs to pessimize its store
65036568 elimination if the store traps.
6504 
 6569
65056570 The hard part of this change is teaching the instruction selector to faithfully carry the
65066571 traps flag down to Air. I got this to work by making ArgPromise a non-copyable object that
65076572 knows whether you've used it in an instruction. It knows when you call consume(). If you do

65096574 along with a few other hacks, means that all of the load-op and load-op-store fusions
65106575 correctly carry the trap bit: if any of the B3 loads or stores involved traps then you get
65116576 traps in Air.
6512 
 6577
65136578 This framework also sets us up to do bug 162688, since the ArgPromise::inst() hook is
65146579 powerful enough to allow wrapping the instruction with a Patch.
6515 
 6580
65166581 I added some tests to testb3 that verify that optimizations are appropriately inhibited and
65176582 that the traps flag survives until the bitter end of Air.
65186583

65836648 https://bugs.webkit.org/show_bug.cgi?id=162764
65846649
65856650 Reviewed by Saam Barati.
6586 
 6651
65876652 There are some interesting cases where we can reduce the number of constant materializations if
65886653 we teach moveConstants() how to edit code. The two examples that this patch supports are:
6589 
 6654
65906655 - Loads and stores from a constant pointer. Since loads and stores get an offset for free
65916656 and the instruction selector is really good at handling it, and since we can query Air to
65926657 see what kinds of offsets are legal, we can sometimes avoid using a constant pointer that
65936658 is specific to the absolute address of that load and instead pick some other constant
65946659 that is within offset distance of ours.
6595 
 6660
65966661 - Add and Sub by a constant (x + c, x - c). Since x + c = x - -c and x - c = x + -c, we can
65976662 flip Add to Sub or vice versa if the negated constant is available.
6598 
 6663
65996664 This change makes moveConstants() pick the most dominant constant that works for an value. In
66006665 the case of memory accesses, it uses Air::Arg::isValidAddrForm() to work out what other
66016666 constants would work. In the case of Add/Sub, it simply looks for the negated constant. This
66026667 should result in something like a minimal number of constants since these rules always pick the
66036668 most dominant constant that works - so if an Add's constant is already most dominant then
66046669 nothing changes, but if the negated one is more dominant then it becomes a Sub.
6605 
 6670
66066671 This is a 0.5% speed-up on LongSpider and neutral elsewhere. It's a speed-up because the
66076672 absolute address thing reduces the number of address materializations that we have to do, while
66086673 the add/sub thing prevents us from having to materialize 0x1000000000000 to box doubles.

68986963 Ensure that once we have the Script that we always
68996964 resolve the breakpoint location before setting the
69006965 breakpoint. The different paths are:
6901 
 6966
69026967 - setBreakpoint(scriptId, location)
69036968 - Here we know the SourceProvider by its SourceID
69046969 - resolve and set
6905 
 6970
69066971 - setBreakpointByURL(url, location)
69076972 - Search for existing Scripts that match the URL
69086973 - resolve in each and set
69096974 - When new Scripts are parsed that match the URL
69106975 - resolve and set
6911 
 6976
69126977
691369782016-09-30 Joseph Pecoraro <pecoraro@apple.com>
69146979

70477112 (JSC::Debugger::stepIntoStatement):
70487113 (JSC::Debugger::exception):
70497114 (JSC::Debugger::didReachBreakpoint):
7050 
 7115
70517116 Use new variable names, and clarify if we should attempt
70527117 to pause or not.
70537118

70597124 (JSC::Debugger::updateCallFrameInternal):
70607125 (JSC::Debugger::pauseIfNeeded):
70617126 Allow updateCallFrame to either attempt a pause or not.
7062 
 7127
70637128 (JSC::Debugger::atStatement):
70647129 Attempt pause and reset the at first expression flag.
70657130

70757140 Attempt pause when leaving a function.
70767141 If the user did a step-over and is leaving the
70777142 function, then behave like step-out.
7078 
 7143
70797144 (JSC::Debugger::unwindEvent):
70807145 Behave like return except don't change any
70817146 pausing states. If we needed to pause the

70947159 When the program doesn't have a parent, clear all
70957160 our state so we don't errantly pause on the next
70967161 JavaScript microtask that gets executed.
7097 
 7162
70987163 (JSC::Debugger::clearNextPauseState):
70997164 Helper to clear all of the pause states now that
71007165 it happens in a couple places.

71777242 https://bugs.webkit.org/show_bug.cgi?id=162699
71787243
71797244 Reviewed by Mark Lam.
7180 
 7245
71817246 This follows a similar change in B3 (r206595) and replaces Air::Opcode with Air::Kind,
71827247 which holds onto the opcode and some additional flags. Because Air is an orthogonal ISA
71837248 (the opcode tells you what the operation does but each operand is allowed to also contain
71847249 effectively instructions for what to do to read or write that operand), the flags are
71857250 meant to be orthogonal to opcode. This allows us to say things like Add32<Trap>, which
71867251 makes sense if any of the operands to the Add32 are addresses.
7187 
 7252
71887253 To demonstrate the flags facility this partly adds a trap flag to Air. B3 doesn't use it
71897254 yet, but I made sure that Air respects it. Basically that means blocking DCE when the flag
71907255 is set, by making it imply hasNonArgNonControlEffects.

72687333 https://bugs.webkit.org/show_bug.cgi?id=162721
72697334
72707335 Reviewed by Keith Miller.
7271 
 7336
72727337 The put_by_id-in-put_by_val optimization had the write barrier in the wrong place and
72737338 incorrectly filtered on value instead of base.
7274 
 7339
72757340 No reduced test case. You really need to run Dromaeo/jslib to catch it. I love Dromaeo's
72767341 ability to catch GC bugs.
72777342

73247389 Opcode was how you knew what subclass of Value you had. The opcode told you what the Value
73257390 actually did. This change replaces Opcode with Kind, which is a tuple of opcode and other
73267391 stuff.
7327 
 7392
73287393 Opcodes are great, and that's how most compilers work. But opcodes are one-dimensional. Here
73297394 is how this manifests. Say you have an opcode, like Load. You will be happy if your IR has
73307395 one Load opcode. But then, you might add Load8S/Load8Z/Load16S/Load16Z opcodes, as we have
73317396 done in B3. B3 has one dimension of Load opcodes, which determines something like the C type
73327397 of the load. But in the very near future, we will want to add two more dimensions to Loads:
7333 
 7398
73347399 - A flag to say if the load traps.
73357400 - A flag to say if the load has acquire semantics.
7336 
 7401
73377402 Mapping these three dimensions (type, trap, acquire) onto the one-dimensional Opcode space
73387403 would create mayham: Load8S, Load8STrap, Load8SAcquire, Load8STrapAcquire, Load8Z,
73397404 Load8ZTrap, etc.
7340 
 7405
73417406 This happens in other parts of the IR. For example, we have a dimension of arithmetic
73427407 operations: add, sub, mul, div, mod, etc. Then we have the chill flag. But since opcodes
73437408 are one-dimensional, that means having ChillDiv and ChillMod, and tons of places in the
73447409 compiler that case on both Div and ChillDiv, or case on both Mod and ChillMod, since they
73457410 are only interested in the kind of arithmetic being done and not the chillness.
7346 
 7411
73477412 Though the examples all involve bits (chill or not, trapping or not, etc), I can imagine
73487413 other properties that behave more like small enums, like if we fill out more memory ordering
73497414 modes other than just "acquire? yes/no". There will eventually have to be something like a
73507415 std::memory_order associated with memory accesses.
7351 
 7416
73527417 One approach to this problem is to have a Value subclass that contains fields with the meta
73537418 data. I don't like this for two reasons:
7354 
 7419
73557420 - In bug 162688, I want to make trapping memory accesses have stackmaps. This means that a
73567421 trapping memory access would have a different Value subclass than a non-trapping memory
73577422 access. So, this meta-data needs to channel into ValueType::accepts(). Currently that
73587423 takes Opcode and nothing else.
7359 
 7424
73607425 - Compiler IRs are all about making common tasks easy. If it becomes commonplace for opcodes
73617426 to require a custom Value subclass just for a bit then that's not very easy.
7362 
 7427
73637428 This change addresses this problem by making the compiler pass around Kinds rather than
73647429 Opcodes. A Kind contains an Opcode as well as any number of opcode-specific bits. This
73657430 change demonstrates how Kind should be used by converting chillness to it. Kind has

73687433 chill(Div). IR dumps will print it like this:
73697434
73707435 Int32 @38 = Div<Chill>(@36, @37, DFG:@24, ControlDependent)
7371 
 7436
73727437 Where "Div<Chill>" is how a Kind that hasExtraBits() dumps itself. If a Kind does not
73737438 hasExtraBits() (the normal case) then it dumps like a normal Opcode (without the "<>").
7374 
 7439
73757440 I replaced many uses of Opcode with Kind. New code has to be mindful that Opcode may not be
73767441 the right way to summarize what a value does, and so in many cases it's better to carry
73777442 around a Kind instead - especially if you will use it to stamp out new Values. Opcode is no

73797444 now wants a Kind instead of an Opcode. All Value constructors now take Kind instead of
73807445 Opcode. But most opcodes don't get any extra Kind bits, and so the code that operates on
73817446 those opcodes is largely unchanged.
7382 
 7447
73837448 * CMakeLists.txt:
73847449 * JavaScriptCore.xcodeproj/project.pbxproj:
73857450 * b3/B3ArgumentRegValue.h:

75067571 https://bugs.webkit.org/show_bug.cgi?id=162316
75077572
75087573 Reviewed by Geoffrey Garen.
7509 
 7574
75107575 This makes our write barrier behave correctly when it races with the collector. The
75117576 collector wants to do this when visiting:
7512 
 7577
75137578 object->cellState = black
75147579 visit(object)
7515 
 7580
75167581 The mutator wants to do this when storing:
7517 
 7582
75187583 object->property = newValue
75197584 if (object->cellState == black)
75207585 remember(object)
7521 
 7586
75227587 Prior to this change, this didn't work right because the compiler would sometimes place
75237588 barriers before the store to the property and because the mutator did not have adequate
75247589 fences.
7525 
 7590
75267591 Prior to this change, the DFG and FTL would emit this:
7527 
 7592
75287593 if (object->cellState == black)
75297594 remember(object)
75307595 object->property = newValue
7531 
 7596
75327597 Which is wrong, because the object could start being scanned just after the cellState
75337598 check, at which point the store would be lost. We need to confirm that the state was not
75347599 black *after* the store! This change was harder than you'd expect: placing the barrier

75397604 (because of the store-load fence) and it writes only cellState (because the B3 heap ranges
75407605 don't have any way to represent any of the GC's other state, which means that B3 does not
75417606 have to worry about aliasing with any of that).
7542 
 7607
75437608 The collector already uses a store-load fence on x86 just after setting the cellState and
75447609 before visiting the object. The mutator needs to do the same. But we cannot put a
75457610 store-load fence of any kind before store barriers, because that causes enormous slow

75487613 reasonable if the slow down only happened while the GC was running. Then, the concurrent GC
75497614 would lift throughput-while-collecting from 0% of peak to 85% of peak. This changes the
75507615 barrier so that it looks like this:
7551 
 7616
75527617 if (object->cellState <= heap.sneakyBlackThreshold)
75537618 slowPath(object)
7554 
 7619
75557620 Where sneakyBlackThreshold is the normal blackThreshold when we're not collecting, or a
75567621 tautoligical threshold (that makes everything look black) when we are collecting. This
75577622 turns out to not be any more expensive than the barrier in tip of tree when the GC is not

75597624 concurrently yet. I still have more work to do.) The slowPath() does some extra work to
75607625 check if we are concurrently collecting; if so, it does a fence and rechecks if the object
75617626 really did need that barrier.
7562 
 7627
75637628 This also reintroduces elimination of redundant store barriers, which was lost in the last
75647629 store barrier change. We can only do it when there is no possibility of GC, exit, or
75657630 exceptions between the two store barriers. We could remove the exit/exception limitation if

75697634 same object. This same optimization also sometimes strength-reduces the store barrier so
75707635 that it uses a constant black threshold rather than the sneaky one, thereby saving one
75717636 load.
7572 
 7637
75737638 Even with all of those optimizations, I still had problems with barrier cost. I found that one
75747639 of the benchmarks that was being hit particularly hard was JetStream/regexp-2010. Fortunately
75757640 that benchmark does most of its barriers in a tight C++ loop in RegExpMatchesArray.h. When we

75797644 optimization. The most efficient version of such an optimization that I could come up with was
75807645 to have a DeferralContext object that houses a boolean that is false by default, but the GC
75817646 writes true into it if it would have wanted to GC. You thread a pointer to the deferralContext
7582  through all of your allocations. This kind of mechanism has the overhead of a zero
 7647 through all of your allocations. This kind of mechanism has the overhead of a zero
75837648 initialization on the stack on entry and a zero check on exit. This is probably even efficient
75847649 enough that we could start thinking about having the DFG use it, for example if we found a
75857650 bounded-time section of code with a lot of barriers and entry/exit sites that aren't totally
75867651 wacky. This optimization took this patch from 0.68% JetStream regressed to neutral, according
75877652 to my latest data.
7588 
 7653
75897654 Finally, an earlier version of this change put the store-load fence in B3 IR, so I ended up
75907655 adding FTLOutput support for it and AbstractHeapRepository magic for decorating the heaps.
75917656 I think we might as well keep that, it'll be useful.

79618026
79628027 Make the subclass of CallSlowPathGenerator that takes arguments variadic
79638028 so it can take any number of arguments. Also updates the slowPathCall helper
7964  function to be variadic. I had to move the spill mode and exception check
 8029 function to be variadic. I had to move the spill mode and exception check
79658030 requirement parameters to before the arguments since the variadic arguments
79668031 must be at the end. As a convenience, I added an overload of slowPathCall that
79678032 doesn't take spill mode and exception check requirement parameters.

Source/JavaScriptCore/CMakeLists.txt

@@set(JavaScriptCore_SOURCES
878878 wasm/JSWebAssembly.cpp
879879 wasm/WasmB3IRGenerator.cpp
880880 wasm/WasmCallingConvention.cpp
 881 wasm/WasmFormat.cpp
881882 wasm/WasmMemory.cpp
882883 wasm/WasmModuleParser.cpp
883884 wasm/WasmPlan.cpp
 885 wasm/WasmValidate.cpp
884886
885887 wasm/js/JSWebAssemblyCompileError.cpp
886888 wasm/js/JSWebAssemblyInstance.cpp

Source/JavaScriptCore/DerivedSources.make

@@all : \
6464 AirOpcode.h \
6565 YarrCanonicalizeUnicode.cpp \
6666 WasmOps.h \
 67 WasmValidateInlines.h \
6768#
6869
6970# JavaScript builtins.

@@YarrCanonicalizeUnicode.cpp: $(JavaScriptCore)/generateYarrCanonicalizeUnicode $
301302WasmOps.h: $(JavaScriptCore)/wasm/generateWasmOpsHeader.py $(JavaScriptCore)/wasm/generateWasm.py $(JavaScriptCore)/wasm/wasm.json
302303 $(PYTHON) $(JavaScriptCore)/wasm/generateWasmOpsHeader.py $(JavaScriptCore)/wasm/wasm.json ./WasmOps.h
303304
 305WasmValidateInlines.h: $(JavaScriptCore)/wasm/generateWasmValidateInlinesHeader.py $(JavaScriptCore)/wasm/generateWasm.py $(JavaScriptCore)/wasm/wasm.json
 306 $(PYTHON) $(JavaScriptCore)/wasm/generateWasmValidateInlinesHeader.py $(JavaScriptCore)/wasm/wasm.json ./WasmValidateInlines.h
 307
304308# Dynamically-defined targets are listed below. Static targets belong up top.
305309
306310all : \

Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

12271227 52C952B919A28A1C0069B386 /* TypeProfiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 52C952B819A28A1C0069B386 /* TypeProfiler.cpp */; };
12281228 531374BD1D5CE67600AF7A0B /* WasmPlan.h in Headers */ = {isa = PBXBuildFile; fileRef = 531374BC1D5CE67600AF7A0B /* WasmPlan.h */; };
12291229 531374BF1D5CE95000AF7A0B /* WasmPlan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 531374BE1D5CE95000AF7A0B /* WasmPlan.cpp */; };
 1230 533B15DF1DC7F463004D500A /* WasmOps.h in Headers */ = {isa = PBXBuildFile; fileRef = 533B15DE1DC7F463004D500A /* WasmOps.h */; };
12301231 5341FC701DAC33E500E7E4D7 /* B3WasmBoundsCheckValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5341FC6F1DAC33E500E7E4D7 /* B3WasmBoundsCheckValue.cpp */; };
12311232 5341FC721DAC343C00E7E4D7 /* B3WasmBoundsCheckValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 5341FC711DAC343C00E7E4D7 /* B3WasmBoundsCheckValue.h */; };
12321233 53486BB71C1795C300F6F3AF /* JSTypedArray.h in Headers */ = {isa = PBXBuildFile; fileRef = 53486BB61C1795C300F6F3AF /* JSTypedArray.h */; settings = {ATTRIBUTES = (Public, ); }; };

12501251 53F40E8B1D5901BB0099A1B6 /* WasmFunctionParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F40E8A1D5901BB0099A1B6 /* WasmFunctionParser.h */; };
12511252 53F40E8D1D5901F20099A1B6 /* WasmParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F40E8C1D5901F20099A1B6 /* WasmParser.h */; };
12521253 53F40E8F1D5902820099A1B6 /* WasmB3IRGenerator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53F40E8E1D5902820099A1B6 /* WasmB3IRGenerator.cpp */; };
1253  53F40E911D5903020099A1B6 /* WasmOps.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F40E901D5903020099A1B6 /* WasmOps.h */; };
12541254 53F40E931D5A4AB30099A1B6 /* WasmB3IRGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F40E921D5A4AB30099A1B6 /* WasmB3IRGenerator.h */; };
12551255 53F40E951D5A7AEF0099A1B6 /* WasmModuleParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F40E941D5A7AEF0099A1B6 /* WasmModuleParser.h */; };
12561256 53F40E971D5A7BEC0099A1B6 /* WasmModuleParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53F40E961D5A7BEC0099A1B6 /* WasmModuleParser.cpp */; };

12591259 53FA2AE31CF380390022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53FA2AE21CF380390022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp */; };
12601260 53FD04D31D7AB277003287D3 /* WasmCallingConvention.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53FD04D11D7AB187003287D3 /* WasmCallingConvention.cpp */; };
12611261 53FD04D41D7AB291003287D3 /* WasmCallingConvention.h in Headers */ = {isa = PBXBuildFile; fileRef = 53FD04D21D7AB187003287D3 /* WasmCallingConvention.h */; };
1262  5C4E8E961DBEBE620036F1FC /* JSONParseTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C4E8E941DBEBDA20036F1FC /* JSONParseTest.cpp */; };
 1262 53FF7F991DBFCD9000A26CCC /* WasmValidate.h in Headers */ = {isa = PBXBuildFile; fileRef = 53FF7F981DBFCD9000A26CCC /* WasmValidate.h */; };
 1263 53FF7F9B1DBFD2B900A26CCC /* WasmValidate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53FF7F9A1DBFD2B900A26CCC /* WasmValidate.cpp */; };
 1264 53FF7F9D1DC00DB100A26CCC /* WasmFormat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53FF7F9C1DC00DB100A26CCC /* WasmFormat.cpp */; };
12631265 5B70CFDE1DB69E6600EC23F9 /* JSAsyncFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 5B70CFD81DB69E5C00EC23F9 /* JSAsyncFunction.h */; };
12641266 5B70CFDF1DB69E6600EC23F9 /* JSAsyncFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5B70CFD91DB69E5C00EC23F9 /* JSAsyncFunction.cpp */; };
12651267 5B70CFE01DB69E6600EC23F9 /* AsyncFunctionPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = 5B70CFDA1DB69E5C00EC23F9 /* AsyncFunctionPrototype.h */; };
12661268 5B70CFE11DB69E6600EC23F9 /* AsyncFunctionPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5B70CFDB1DB69E5C00EC23F9 /* AsyncFunctionPrototype.cpp */; };
12671269 5B70CFE21DB69E6600EC23F9 /* AsyncFunctionConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 5B70CFDC1DB69E5C00EC23F9 /* AsyncFunctionConstructor.h */; };
12681270 5B70CFE31DB69E6600EC23F9 /* AsyncFunctionConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5B70CFDD1DB69E5C00EC23F9 /* AsyncFunctionConstructor.cpp */; };
 1271 5C4E8E961DBEBE620036F1FC /* JSONParseTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C4E8E941DBEBDA20036F1FC /* JSONParseTest.cpp */; };
12691272 5D5D8AD10E0D0EBE00F9C692 /* libedit.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D5D8AD00E0D0EBE00F9C692 /* libedit.dylib */; };
12701273 5DBB151B131D0B310056AD36 /* testapi.js in Copy Support Script */ = {isa = PBXBuildFile; fileRef = 14D857740A4696C80032146C /* testapi.js */; };
12711274 5DBB1525131D0BD70056AD36 /* minidom.js in Copy Support Script */ = {isa = PBXBuildFile; fileRef = 1412110D0A48788700480255 /* minidom.js */; };

35523555 52C952B819A28A1C0069B386 /* TypeProfiler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TypeProfiler.cpp; sourceTree = "<group>"; };
35533556 531374BC1D5CE67600AF7A0B /* WasmPlan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmPlan.h; sourceTree = "<group>"; };
35543557 531374BE1D5CE95000AF7A0B /* WasmPlan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmPlan.cpp; sourceTree = "<group>"; };
 3558 533B15DE1DC7F463004D500A /* WasmOps.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmOps.h; sourceTree = "<group>"; };
35553559 5341FC6F1DAC33E500E7E4D7 /* B3WasmBoundsCheckValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = B3WasmBoundsCheckValue.cpp; path = b3/B3WasmBoundsCheckValue.cpp; sourceTree = "<group>"; };
35563560 5341FC711DAC343C00E7E4D7 /* B3WasmBoundsCheckValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3WasmBoundsCheckValue.h; path = b3/B3WasmBoundsCheckValue.h; sourceTree = "<group>"; };
35573561 53486BB61C1795C300F6F3AF /* JSTypedArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSTypedArray.h; sourceTree = "<group>"; };

35793583 53F40E8A1D5901BB0099A1B6 /* WasmFunctionParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmFunctionParser.h; sourceTree = "<group>"; };
35803584 53F40E8C1D5901F20099A1B6 /* WasmParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmParser.h; sourceTree = "<group>"; };
35813585 53F40E8E1D5902820099A1B6 /* WasmB3IRGenerator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmB3IRGenerator.cpp; sourceTree = "<group>"; };
3582  53F40E901D5903020099A1B6 /* WasmOps.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmOps.h; sourceTree = "<group>"; };
35833586 53F40E921D5A4AB30099A1B6 /* WasmB3IRGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmB3IRGenerator.h; sourceTree = "<group>"; };
35843587 53F40E941D5A7AEF0099A1B6 /* WasmModuleParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmModuleParser.h; sourceTree = "<group>"; };
35853588 53F40E961D5A7BEC0099A1B6 /* WasmModuleParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmModuleParser.cpp; sourceTree = "<group>"; };

35883591 53FA2AE21CF380390022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp; sourceTree = "<group>"; };
35893592 53FD04D11D7AB187003287D3 /* WasmCallingConvention.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmCallingConvention.cpp; sourceTree = "<group>"; };
35903593 53FD04D21D7AB187003287D3 /* WasmCallingConvention.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmCallingConvention.h; sourceTree = "<group>"; };
3591  5C4E8E941DBEBDA20036F1FC /* JSONParseTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JSONParseTest.cpp; path = API/tests/JSONParseTest.cpp; sourceTree = "<group>"; };
3592  5C4E8E951DBEBDA20036F1FC /* JSONParseTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSONParseTest.h; path = API/tests/JSONParseTest.h; sourceTree = "<group>"; };
 3594 53FF7F981DBFCD9000A26CCC /* WasmValidate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmValidate.h; sourceTree = "<group>"; };
 3595 53FF7F9A1DBFD2B900A26CCC /* WasmValidate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmValidate.cpp; sourceTree = "<group>"; };
 3596 53FF7F9C1DC00DB100A26CCC /* WasmFormat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmFormat.cpp; sourceTree = "<group>"; };
35933597 5B70CFD81DB69E5C00EC23F9 /* JSAsyncFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSAsyncFunction.h; sourceTree = "<group>"; };
35943598 5B70CFD91DB69E5C00EC23F9 /* JSAsyncFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSAsyncFunction.cpp; sourceTree = "<group>"; };
35953599 5B70CFDA1DB69E5C00EC23F9 /* AsyncFunctionPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AsyncFunctionPrototype.h; sourceTree = "<group>"; };

35973601 5B70CFDC1DB69E5C00EC23F9 /* AsyncFunctionConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AsyncFunctionConstructor.h; sourceTree = "<group>"; };
35983602 5B70CFDD1DB69E5C00EC23F9 /* AsyncFunctionConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AsyncFunctionConstructor.cpp; sourceTree = "<group>"; };
35993603 5B8243041DB7AA4900EA6384 /* AsyncFunctionPrototype.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = AsyncFunctionPrototype.js; sourceTree = "<group>"; };
 3604 5C4E8E941DBEBDA20036F1FC /* JSONParseTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JSONParseTest.cpp; path = API/tests/JSONParseTest.cpp; sourceTree = "<group>"; };
 3605 5C4E8E951DBEBDA20036F1FC /* JSONParseTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSONParseTest.h; path = API/tests/JSONParseTest.h; sourceTree = "<group>"; };
36003606 5D5D8AD00E0D0EBE00F9C692 /* libedit.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libedit.dylib; path = /usr/lib/libedit.dylib; sourceTree = "<absolute>"; };
36013607 5DAFD6CB146B686300FBEFB4 /* JSC.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = JSC.xcconfig; sourceTree = "<group>"; };
36023608 5DDDF44614FEE72200B4FB4D /* LLIntDesiredOffsets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLIntDesiredOffsets.h; path = LLIntOffsets/LLIntDesiredOffsets.h; sourceTree = BUILT_PRODUCTS_DIR; };

58395845 996B73131BD9FA2C00331B84 /* SymbolConstructor.lut.h */,
58405846 996B73141BD9FA2C00331B84 /* SymbolPrototype.lut.h */,
58415847 65A946141C8E9F6F00A7209A /* YarrCanonicalizeUnicode.cpp */,
 5848 533B15DE1DC7F463004D500A /* WasmOps.h */,
58425849 );
58435850 name = "Derived Sources";
58445851 path = DerivedSources/JavaScriptCore;

58755882 53F40E921D5A4AB30099A1B6 /* WasmB3IRGenerator.h */,
58765883 53FD04D11D7AB187003287D3 /* WasmCallingConvention.cpp */,
58775884 53FD04D21D7AB187003287D3 /* WasmCallingConvention.h */,
5878  53F40E901D5903020099A1B6 /* WasmOps.h */,
 5885 53FF7F9C1DC00DB100A26CCC /* WasmFormat.cpp */,
58795886 7BC547D21B69599B00959B58 /* WasmFormat.h */,
58805887 53F40E8A1D5901BB0099A1B6 /* WasmFunctionParser.h */,
58815888 535557151D9DFA32006D583B /* WasmMemory.cpp */,

58865893 531374BC1D5CE67600AF7A0B /* WasmPlan.h */,
58875894 53F40E8C1D5901F20099A1B6 /* WasmParser.h */,
58885895 53F40E841D58F9770099A1B6 /* WasmSections.h */,
 5896 53FF7F9A1DBFD2B900A26CCC /* WasmValidate.cpp */,
 5897 53FF7F981DBFCD9000A26CCC /* WasmValidate.h */,
58895898 );
58905899 path = wasm;
58915900 sourceTree = "<group>";

79867995 0F2BDC491522809600CD8910 /* DFGVariableEvent.h in Headers */,
79877996 0F2BDC4B1522809D00CD8910 /* DFGVariableEventStream.h in Headers */,
79887997 0FFFC96014EF90BD00C72532 /* DFGVirtualRegisterAllocationPhase.h in Headers */,
 7998 53FF7F991DBFCD9000A26CCC /* WasmValidate.h in Headers */,
79897999 0FC97F4218202119002C9B26 /* DFGWatchpointCollectionPhase.h in Headers */,
79908000 0FDB2CE8174830A2007B3C1B /* DFGWorklist.h in Headers */,
79918001 147341DA1DC0300100AA29BA /* WebAssemblyExecutable.h in Headers */,

83898399 A7C0C4AC168103020017011D /* JSScriptRefPrivate.h in Headers */,
83908400 FE1220271BE7F58C0039E6F2 /* JITAddGenerator.h in Headers */,
83918401 0F919D11157F332C004A4E7D /* JSSegmentedVariableObject.h in Headers */,
8392  53F40E911D5903020099A1B6 /* WasmOps.h in Headers */,
83938402 A7299D9E17D12837005F5FF9 /* JSSet.h in Headers */,
83948403 A790DD70182F499700588807 /* JSSetIterator.h in Headers */,
83958404 BC18C45E0E16F5CD00B34460 /* CLoopStack.h in Headers */,

87698778 14F7256614EE265E00B1652B /* WeakHandleOwner.h in Headers */,
87708779 14E84FA214EE1ACC00D6D5D4 /* WeakImpl.h in Headers */,
87718780 14BE7D3317135CF400D1807A /* WeakInlines.h in Headers */,
 8781 533B15DF1DC7F463004D500A /* WasmOps.h in Headers */,
87728782 A7CA3AE417DA41AE006538AF /* WeakMapConstructor.h in Headers */,
87738783 A7CA3AEC17DA5168006538AF /* WeakMapData.h in Headers */,
87748784 A7CA3AE617DA41AE006538AF /* WeakMapPrototype.h in Headers */,

99309940 0FF4275715914A20004CB9FF /* LinkBuffer.cpp in Sources */,
99319941 A7E2EA6C0FB460CF00601F06 /* LiteralParser.cpp in Sources */,
99329942 A5A1A0951D8CB341004C2EB8 /* DebuggerParseData.cpp in Sources */,
 9943 53FF7F9D1DC00DB100A26CCC /* WasmFormat.cpp in Sources */,
99339944 FE3913541B794F6E00EDAF71 /* LiveObjectList.cpp in Sources */,
99349945 FE20CE9D15F04A9500DF3430 /* LLIntCLoop.cpp in Sources */,
99359946 0F4680D214BBD16500BFE272 /* LLIntData.cpp in Sources */,

1008810099 14469DEB107EC7E700650446 /* StringConstructor.cpp in Sources */,
1008910100 70EC0EC61AA0D7DA00B6AAFA /* StringIteratorPrototype.cpp in Sources */,
1009010101 14469DEC107EC7E700650446 /* StringObject.cpp in Sources */,
 10102 53FF7F9B1DBFD2B900A26CCC /* WasmValidate.cpp in Sources */,
1009110103 14469DED107EC7E700650446 /* StringPrototype.cpp in Sources */,
1009210104 9335F24D12E6765B002B5553 /* StringRecursionChecker.cpp in Sources */,
1009310105 BCDE3B430E6C832D001453A7 /* Structure.cpp in Sources */,

Source/JavaScriptCore/testWasm.cpp

@@inline JSValue boxd(double value)
269269 return box(bitwise_cast<uint64_t>(value));
270270}
271271
 272static void checkPlan(Plan& plan, unsigned expectedNumberOfFunctions)
 273{
 274 if (plan.failed()) {
 275 dataLogLn("Module failed to compile with error: ", plan.errorMessage());
 276 CRASH();
 277 }
 278
 279 if (plan.resultSize() != expectedNumberOfFunctions) {
 280 dataLogLn("Incorrect number of functions");
 281 CRASH();
 282 }
 283
 284 for (unsigned i = 0; i < expectedNumberOfFunctions; ++i) {
 285 if (!plan.result(i)) {
 286 dataLogLn("Function at index, " , i, " failed to compile correctly");
 287 CRASH();
 288 }
 289 }
 290
 291}
 292
272293// For now we inline the test files.
273294static void runWasmTests()
274295{

@@static void runWasmTests()
290311 };
291312
292313 Plan plan(*vm, vector);
293  if (plan.failed() || plan.resultSize() != 2 || !plan.result(0) || !plan.result(1)) {
294  dataLogLn("Module failed to compile correctly.");
295  CRASH();
296  }
 314 checkPlan(plan, 2);
297315
298316 // Test this doesn't crash.
299317 CHECK(isIdentical(invoke<float>(*plan.result(1)->jsEntryPoint, { boxf(0.0), boxf(1.5) }), -1.5f));

@@static void runWasmTests()
319337 };
320338
321339 Plan plan(*vm, vector);
322  if (plan.failed() || plan.resultSize() != 2 || !plan.result(0) || !plan.result(1)) {
323  dataLogLn("Module failed to compile correctly.");
324  CRASH();
325  }
 340 checkPlan(plan, 2);
326341
327342 // Test this doesn't crash.
328343 CHECK(isIdentical(invoke<float>(*plan.result(1)->jsEntryPoint, { boxf(0.0), boxf(1.5) }), 1.5f));

@@static void runWasmTests()
353368 };
354369
355370 Plan plan(*vm, vector);
356  if (plan.failed() || plan.resultSize() != 2 || !plan.result(0) || !plan.result(1)) {
357  dataLogLn("Module failed to compile correctly.");
358  CRASH();
359  }
 371 checkPlan(plan, 2);
360372
361373 // Test this doesn't crash.
362374 CHECK_EQ(invoke<int>(*plan.result(1)->jsEntryPoint, { box(0) }), 0);

@@static void runWasmTests()
387399 };
388400
389401 Plan plan(*vm, vector);
390  if (plan.failed() || plan.resultSize() != 1 || !plan.result(0)) {
391  dataLogLn("Module failed to compile correctly.");
392  CRASH();
393  }
 402 checkPlan(plan, 1);
394403
395404 // Test this doesn't crash.
396405 CHECK_EQ(invoke<int>(*plan.result(0)->jsEntryPoint, { box(0) }), 1);

@@static void runWasmTests()
447456 };
448457
449458 Plan plan(*vm, vector);
450  if (plan.failed() || plan.resultSize() != 2 || !plan.result(0) || !plan.result(1)) {
451  dataLogLn("Module failed to compile correctly.");
452  CRASH();
453  }
 459 checkPlan(plan, 2);
454460
455461 // Test this doesn't crash.
456462 CHECK_EQ(invoke<int>(*plan.result(1)->jsEntryPoint, { box(0) }), 0);

@@static void runWasmTests()
463469
464470 {
465471 // Generated from:
466  // (module
467  // (memory 1)
468  // (func (export "i32_load8_s") (param $i i32) (param $ptr i32) (result i32)
469  // (i64.store (get_local $ptr) (get_local $i))
470  // (return (i64.load (get_local $ptr)))
471  // )
472  // )
 472 // (module
 473 // (memory 1)
 474 // (func (export "i64") (param $i i64) (param $ptr i32) (result i64)
 475 // (i64.store (get_local $ptr) (get_local $i))
 476 // (return (i64.load (get_local $ptr)))
 477 // )
 478 // )
473479 Vector<uint8_t> vector = {
474480 0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
475481 0x02, 0x02, 0x01, 0x01, 0x02, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
476  0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x69, 0x33,
477  0x32, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x38, 0x5f, 0x73, 0x00, 0x00, 0x0a, 0x95, 0x80, 0x80, 0x80,
478  0x00, 0x01, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14, 0x01, 0x14, 0x00, 0x34, 0x03, 0x00, 0x14,
479  0x01, 0x2b, 0x03, 0x00, 0x09, 0x0f
 482 0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x03, 0x69, 0x36,
 483 0x34, 0x00, 0x00, 0x0a, 0x95, 0x80, 0x80, 0x80, 0x00, 0x01, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x00,
 484 0x14, 0x01, 0x14, 0x00, 0x34, 0x03, 0x00, 0x14, 0x01, 0x2b, 0x03, 0x00, 0x09, 0x0f
480485 };
481486
482487 Plan plan(*vm, vector);
483  if (plan.failed() || plan.resultSize() != 1 || !plan.result(0)) {
484  dataLogLn("Module failed to compile correctly.");
485  CRASH();
486  }
 488 checkPlan(plan, 1);
487489
488490 // Test this doesn't crash.
489491 CHECK_EQ(invoke<int>(*plan.result(0)->jsEntryPoint, { box(0), box(10) }), 0);

@@static void runWasmTests()
510512 };
511513
512514 Plan plan(*vm, vector);
513  if (plan.failed() || plan.resultSize() != 1 || !plan.result(0)) {
514  dataLogLn("Module failed to compile correctly.");
515  CRASH();
516  }
 515 checkPlan(plan, 1);
517516
518517 // Test this doesn't crash.
519518 CHECK_EQ(invoke<int>(*plan.result(0)->jsEntryPoint, { box(0), box(10) }), 0);

@@static void runWasmTests()
550549 };
551550
552551 Plan plan(*vm, vector);
553  if (plan.failed() || plan.resultSize() != 1 || !plan.result(0)) {
554  dataLogLn("Module failed to compile correctly.");
555  CRASH();
556  }
 552 checkPlan(plan, 1);
557553 ASSERT(plan.memory()->size());
558554
559555 // Test this doesn't crash.

@@static void runWasmTests()
605601 };
606602
607603 Plan plan(*vm, vector);
608  if (plan.failed() || plan.resultSize() != 1 || !plan.result(0)) {
609  dataLogLn("Module failed to compile correctly.");
610  CRASH();
611  }
 604 checkPlan(plan, 1);
612605 ASSERT(plan.memory()->size());
613606
614607 // Test this doesn't crash.

@@static void runWasmTests()
649642 };
650643
651644 Plan plan(*vm, vector);
652  if (plan.failed() || plan.resultSize() != 1 || !plan.result(0)) {
653  dataLogLn("Module failed to compile correctly.");
654  CRASH();
655  }
 645 checkPlan(plan, 1);
656646 ASSERT(plan.memory()->size());
657647
658648 // Test this doesn't crash.

@@static void runWasmTests()
680670 };
681671
682672 Plan plan(*vm, vector);
683  if (plan.failed() || plan.resultSize() != 1 || !plan.result(0)) {
684  dataLogLn("Module failed to compile correctly.");
685  CRASH();
686  }
 673 checkPlan(plan, 1);
687674
688675 // Test this doesn't crash.
689676 CHECK_EQ(invoke<int>(*plan.result(0)->jsEntryPoint, { box(0) }), 0);

@@static void runWasmTests()
710697 };
711698
712699 Plan plan(*vm, vector);
713  if (plan.failed() || plan.resultSize() != 1 || !plan.result(0)) {
714  dataLogLn("Module failed to compile correctly.");
715  CRASH();
716  }
 700 checkPlan(plan, 1);
717701
718702 // Test this doesn't crash.
719703 CHECK_EQ(invoke<int>(*plan.result(0)->jsEntryPoint, { box(0), box(10) }), 0);

@@static void runWasmTests()
741725 };
742726
743727 Plan plan(*vm, vector);
744  if (plan.failed() || plan.resultSize() != 1 || !plan.result(0)) {
745  dataLogLn("Module failed to compile correctly.");
746  CRASH();
747  }
 728 checkPlan(plan, 1);
748729
749730 // Test this doesn't crash.
750731 CHECK_EQ(invoke<int>(*plan.result(0)->jsEntryPoint, { box(0), box(10) }), 0);

@@static void runWasmTests()
781762 };
782763
783764 Plan plan(*vm, vector);
784  if (plan.failed() || plan.resultSize() != 1 || !plan.result(0)) {
785  dataLogLn("Module failed to compile correctly.");
786  CRASH();
787  }
 765 checkPlan(plan, 1);
788766 ASSERT(plan.memory()->size());
789767
790768 // Test this doesn't crash.

@@static void runWasmTests()
836814 };
837815
838816 Plan plan(*vm, vector);
839  if (plan.failed() || plan.resultSize() != 1 || !plan.result(0)) {
840  dataLogLn("Module failed to compile correctly.");
841  CRASH();
842  }
 817 checkPlan(plan, 1);
843818 ASSERT(plan.memory()->size());
844819
845820 // Test this doesn't crash.

@@static void runWasmTests()
880855 };
881856
882857 Plan plan(*vm, vector);
883  if (plan.failed() || plan.resultSize() != 1 || !plan.result(0)) {
884  dataLogLn("Module failed to compile correctly.");
885  CRASH();
886  }
 858 checkPlan(plan, 1);
887859 ASSERT(plan.memory()->size());
888860
889861 // Test this doesn't crash.

@@static void runWasmTests()
911883 };
912884
913885 Plan plan(*vm, vector);
914  if (plan.failed() || plan.resultSize() != 1 || !plan.result(0)) {
915  dataLogLn("Module failed to compile correctly.");
916  CRASH();
917  }
 886 checkPlan(plan, 1);
918887
919888 // Test this doesn't crash.
920889 CHECK_EQ(invoke<int>(*plan.result(0)->jsEntryPoint, { box(0) }), 0);

@@static void runWasmTests()
941910 };
942911
943912 Plan plan(*vm, vector);
944  if (plan.failed() || plan.resultSize() != 1 || !plan.result(0)) {
945  dataLogLn("Module failed to compile correctly.");
946  CRASH();
947  }
 913 checkPlan(plan, 1);
948914
949915 // Test this doesn't crash.
950916 CHECK_EQ(invoke<int>(*plan.result(0)->jsEntryPoint, { box(0), box(1) }), 1);

@@static void runWasmTests()
982948 };
983949
984950 Plan plan(*vm, vector);
985  if (plan.failed() || plan.resultSize() != 1 || !plan.result(0)) {
986  dataLogLn("Module failed to compile correctly.");
987  CRASH();
988  }
 951 checkPlan(plan, 1);
989952
990953 // Test this doesn't crash.
991954 CHECK_EQ(invoke<int>(*plan.result(0)->jsEntryPoint, { box(0), box(1) }), 1);

@@static void runWasmTests()
1009972 };
1010973
1011974 Plan plan(*vm, vector);
1012  if (plan.failed() || plan.resultSize() != 1 || !plan.result(0)) {
1013  dataLogLn("Module failed to compile correctly.");
1014  CRASH();
1015  }
 975 checkPlan(plan, 1);
1016976
1017977 // Test this doesn't crash.
1018978 CHECK_EQ(invoke<int>(*plan.result(0)->jsEntryPoint, { }), 5);

@@static void runWasmTests()
1030990 };
1031991
1032992 Plan plan(*vm, vector);
1033  if (plan.failed() || plan.resultSize() != 1 || !plan.result(0)) {
1034  dataLogLn("Module failed to compile correctly.");
1035  CRASH();
1036  }
 993 checkPlan(plan, 1);
1037994
1038995 // Test this doesn't crash.
1039996 CHECK_EQ(invoke<int>(*plan.result(0)->jsEntryPoint, { }), 11);

@@static void runWasmTests()
10501007 };
10511008
10521009 Plan plan(*vm, vector);
1053  if (plan.failed() || plan.resultSize() != 1 || !plan.result(0)) {
1054  dataLogLn("Module failed to compile correctly.");
1055  CRASH();
1056  }
 1010 checkPlan(plan, 1);
10571011
10581012 // Test this doesn't crash.
10591013 CHECK_EQ(invoke<int>(*plan.result(0)->jsEntryPoint, { }), 11);

@@static void runWasmTests()
10701024 };
10711025
10721026 Plan plan(*vm, vector);
1073  if (plan.failed() || plan.resultSize() != 1 || !plan.result(0)) {
1074  dataLogLn("Module failed to compile correctly.");
1075  CRASH();
1076  }
 1027 checkPlan(plan, 1);
10771028
10781029 // Test this doesn't crash.
10791030 CHECK_EQ(invoke<int>(*plan.result(0)->jsEntryPoint, { }), 11);

@@static void runWasmTests()
10891040 };
10901041
10911042 Plan plan(*vm, vector);
1092  if (plan.failed() || plan.resultSize() != 1 || !plan.result(0)) {
1093  dataLogLn("Module failed to compile correctly.");
1094  CRASH();
1095  }
 1043 checkPlan(plan, 1);
10961044
10971045 // Test this doesn't crash.
10981046 CHECK_EQ(invoke<int>(*plan.result(0)->jsEntryPoint, { box(0), box(1) }), 1);

@@static void runWasmTests()
11181066 };
11191067
11201068 Plan plan(*vm, vector);
1121  if (plan.failed() || plan.resultSize() != 1 || !plan.result(0)) {
1122  dataLogLn("Module failed to compile correctly.");
1123  CRASH();
1124  }
 1069 checkPlan(plan, 1);
11251070
11261071 // Test this doesn't crash.
11271072 CHECK_EQ(invoke<int>(*plan.result(0)->jsEntryPoint, { box(0) }), 0);

@@static void runWasmTests()
11541099 };
11551100
11561101 Plan plan(*vm, vector);
1157  if (plan.failed() || plan.resultSize() != 1 || !plan.result(0)) {
1158  dataLogLn("Module failed to compile correctly.");
1159  CRASH();
1160  }
 1102 checkPlan(plan, 1);
11611103
11621104 // Test this doesn't crash.
11631105 CHECK_EQ(invoke<int>(*plan.result(0)->jsEntryPoint, { box(0) }), 0);

@@static void runWasmTests()
11981140 };
11991141
12001142 Plan plan(*vm, vector);
1201  if (plan.failed() || plan.resultSize() != 1 || !plan.result(0)) {
1202  dataLogLn("Module failed to compile correctly.");
1203  CRASH();
1204  }
 1143 checkPlan(plan, 1);
12051144
12061145 // Test this doesn't crash.
12071146 CHECK_EQ(invoke<int>(*plan.result(0)->jsEntryPoint, { box(0), box(1) }), 0);

@@static void runWasmTests()
12511190 };
12521191
12531192 Plan plan(*vm, vector);
1254  if (plan.failed() || plan.resultSize() != 1 || !plan.result(0)) {
1255  dataLogLn("Module failed to compile correctly.");
1256  CRASH();
1257  }
 1193 checkPlan(plan, 1);
12581194
12591195 // Test this doesn't crash.
12601196 CHECK_EQ(invoke<int>(*plan.result(0)->jsEntryPoint, { box(0), box(1) }), 1);

Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp

@@private:
8787 {
8888 }
8989
 90 LazyBlock()
 91 {
 92 }
 93
9094 explicit operator bool() const { return !!m_block; }
9195
9296 BasicBlock* get(Procedure& proc)

@@public:
118122 result.append(proc.addVariable(toB3Type(signature)));
119123 }
120124
 125 ControlData()
 126 {
 127 }
 128
121129 void dump(PrintStream& out) const
122130 {
123131 switch (type()) {

@@public:
172180
173181 B3IRGenerator(Memory*, Procedure&, Vector<UnlinkedCall>& unlinkedCalls);
174182
175  void addArguments(const Vector<Type>&);
176  void addLocal(Type, uint32_t);
 183 bool WARN_UNUSED_RETURN addArguments(const Vector<Type>&);
 184 bool WARN_UNUSED_RETURN addLocal(Type, uint32_t);
177185 ExpressionType addConstant(Type, uint64_t);
178186
179187 // Locals

@@public:
191199 // Control flow
192200 ControlData WARN_UNUSED_RETURN addBlock(Type signature);
193201 ControlData WARN_UNUSED_RETURN addLoop(Type signature);
194  ControlData WARN_UNUSED_RETURN addIf(ExpressionType condition, Type signature);
195  bool WARN_UNUSED_RETURN addElse(ControlData&);
 202 bool WARN_UNUSED_RETURN addIf(ExpressionType condition, Type signature, ControlData& result);
 203 bool WARN_UNUSED_RETURN addElse(ControlData&, const ExpressionList&);
196204
197205 bool WARN_UNUSED_RETURN addReturn(const ExpressionList& returnValues);
198206 bool WARN_UNUSED_RETURN addBranch(ControlData&, ExpressionType condition, const ExpressionList& returnValues);

@@B3IRGenerator::B3IRGenerator(Memory* memory, Procedure& procedure, Vector<Unlink
245253 }
246254}
247255
248 void B3IRGenerator::addLocal(Type type, uint32_t count)
 256bool B3IRGenerator::addLocal(Type type, uint32_t count)
249257{
250  m_locals.reserveCapacity(m_locals.size() + count);
 258 if (!m_locals.tryReserveCapacity(m_locals.size() + count))
 259 return false;
 260
251261 for (uint32_t i = 0; i < count; ++i)
252  m_locals.append(m_proc.addVariable(toB3Type(type)));
 262 m_locals.uncheckedAppend(m_proc.addVariable(toB3Type(type)));
 263 return true;
253264}
254265
255 void B3IRGenerator::addArguments(const Vector<Type>& types)
 266bool B3IRGenerator::addArguments(const Vector<Type>& types)
256267{
257268 ASSERT(!m_locals.size());
 269 if (!m_locals.tryReserveCapacity(types.size()))
 270 return false;
 271
258272 m_locals.grow(types.size());
259273 wasmCallingConvention().loadArguments(types, m_proc, m_currentBlock, Origin(),
260274 [&] (ExpressionType argument, unsigned i) {

@@void B3IRGenerator::addArguments(const Vector<Type>& types)
262276 m_locals[i] = argumentVariable;
263277 m_currentBlock->appendNew<VariableValue>(m_proc, Set, Origin(), argumentVariable, argument);
264278 });
 279 return true;
265280}
266281
267282bool B3IRGenerator::getLocal(uint32_t index, ExpressionType& result)

@@B3IRGenerator::ControlData B3IRGenerator::addLoop(Type signature)
493508 return ControlData(m_proc, signature, body);
494509}
495510
496 B3IRGenerator::ControlData B3IRGenerator::addIf(ExpressionType condition, Type signature)
 511bool B3IRGenerator::addIf(ExpressionType condition, Type signature, ControlType& result)
497512{
498513 // FIXME: This needs to do some kind of stack passing.
499514

@@B3IRGenerator::ControlData B3IRGenerator::addIf(ExpressionType condition, Type s
507522 notTaken->addPredecessor(m_currentBlock);
508523
509524 m_currentBlock = taken;
510  return ControlData(m_proc, signature, notTaken, continuation);
 525 result = ControlData(m_proc, signature, notTaken, continuation);
 526 return true;
511527}
512528
513 bool B3IRGenerator::addElse(ControlData& data)
 529bool B3IRGenerator::addElse(ControlData& data, const ExpressionList&)
514530{
515531 ASSERT(data.continuation);
516532 m_currentBlock = data.special;

Source/JavaScriptCore/wasm/WasmFormat.cpp

 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 "WasmFormat.h"
 28
 29#if ENABLE(WEBASSEMBLY)
 30
 31namespace JSC { namespace Wasm {
 32
 33const char* toString(Type type)
 34{
 35 switch (type) {
 36 case Void:
 37 return "void";
 38 case I32:
 39 return "i32";
 40 case I64:
 41 return "i64";
 42 case F32:
 43 return "f32";
 44 case F64:
 45 return "f64";
 46 }
 47}
 48
 49} } // namespace JSC::Wasm
 50
 51#endif // ENABLE(B3_JIT)

Source/JavaScriptCore/wasm/WasmFormat.h

@@inline bool isValueType(Type type)
9797 return false;
9898}
9999
 100const char* toString(Type);
100101
101102struct Signature {
102103 Type returnType;

Source/JavaScriptCore/wasm/WasmFunctionParser.h

@@FunctionParser<Context>::FunctionParser(Context& context, const uint8_t* functio
7373{
7474 if (verbose)
7575 dataLogLn("Parsing function starting at: ", (uintptr_t)functionStart, " of length: ", functionLength);
76  m_context.addArguments(m_signature->arguments);
7776}
7877
7978template<typename Context>
8079bool FunctionParser<Context>::parse()
8180{
 81 if (!m_context.addArguments(m_signature->arguments))
 82 return false;
 83
8284 uint32_t localCount;
8385 if (!parseVarUInt32(localCount))
8486 return false;

@@bool FunctionParser<Context>::parse()
9294 if (!parseValueType(typeOfLocal))
9395 return false;
9496
95  m_context.addLocal(typeOfLocal, numberOfLocals);
 97 if (!m_context.addLocal(typeOfLocal, numberOfLocals))
 98 return false;
9699 }
97100
98101 return parseBlock();

@@bool FunctionParser<Context>::parseExpression(OpType op)
282285 return false;
283286
284287 ExpressionType condition = m_expressionStack.takeLast();
285  m_controlStack.append(m_context.addIf(condition, inlineSignature));
 288 ControlType control;
 289 if (!m_context.addIf(condition, inlineSignature, control))
 290 return false;
 291
 292 m_controlStack.append(control);
286293 return true;
287294 }
288295
289296 case OpType::Else: {
290  return m_context.addElse(m_controlStack.last());
 297 return m_context.addElse(m_controlStack.last(), m_expressionStack);
291298 }
292299
293300 case OpType::Br:

@@bool FunctionParser<Context>::parseUnreachableExpression(OpType op)
349356 ControlType& data = m_controlStack.last();
350357 ASSERT(data.type() == BlockType::If);
351358 m_unreachableBlocks = 0;
352  return m_context.addElse(data);
 359 return m_context.addElse(data, m_expressionStack);
353360 }
354361
355362 case OpType::End: {

Source/JavaScriptCore/wasm/WasmPlan.cpp

3232#include "WasmB3IRGenerator.h"
3333#include "WasmCallingConvention.h"
3434#include "WasmModuleParser.h"
 35#include "WasmValidate.h"
3536#include <wtf/DataLog.h>
3637
3738namespace JSC { namespace Wasm {

@@Plan::Plan(VM& vm, const uint8_t* source, size_t sourceLength)
6364 const uint8_t* functionStart = source + info.start;
6465 size_t functionLength = info.end - info.start;
6566 ASSERT(functionLength <= sourceLength);
 67
 68 String error = validateFunction(functionStart, functionLength, info.signature, moduleParser.functionInformation());
 69 if (!error.isNull()) {
 70 m_errorMessage = error;
 71 return;
 72 }
 73
6674 m_result.append(parseAndCompile(vm, functionStart, functionLength, moduleParser.memory().get(), info.signature, moduleParser.functionInformation()));
6775 }
6876

Source/JavaScriptCore/wasm/WasmValidate.cpp

 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 "WasmValidate.h"
 28
 29#if ENABLE(WEBASSEMBLY)
 30
 31#include "WasmFunctionParser.h"
 32#include <wtf/text/StringBuilder.h>
 33
 34namespace JSC { namespace Wasm {
 35
 36class Validate {
 37public:
 38 class ControlData {
 39 public:
 40 ControlData(BlockType type, Type signature)
 41 : m_blockType(type)
 42 , m_signature(signature)
 43 {
 44 }
 45
 46 ControlData()
 47 {
 48 }
 49
 50 void dump(PrintStream& out) const
 51 {
 52 switch (type()) {
 53 case BlockType::If:
 54 out.print("If: ");
 55 break;
 56 case BlockType::Block:
 57 out.print("Block: ");
 58 break;
 59 case BlockType::Loop:
 60 out.print("Loop: ");
 61 break;
 62 }
 63 }
 64
 65 BlockType type() const { return m_blockType; }
 66 Type signature() const { return m_signature; }
 67 private:
 68 BlockType m_blockType;
 69 Type m_signature;
 70 };
 71 typedef Type ExpressionType;
 72 typedef ControlData ControlType;
 73 typedef Vector<ExpressionType, 1> ExpressionList;
 74 static const ExpressionType emptyExpression = Void;
 75
 76 bool WARN_UNUSED_RETURN addArguments(const Vector<Type>&);
 77 bool WARN_UNUSED_RETURN addLocal(Type, uint32_t);
 78 ExpressionType addConstant(Type type, uint64_t) { return type; }
 79
 80 // Locals
 81 bool WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
 82 bool WARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value);
 83
 84 // Memory
 85 bool WARN_UNUSED_RETURN load(LoadOpType, ExpressionType pointer, ExpressionType& result, uint32_t offset);
 86 bool WARN_UNUSED_RETURN store(StoreOpType, ExpressionType pointer, ExpressionType value, uint32_t offset);
 87
 88 // Basic operators
 89 bool WARN_UNUSED_RETURN binaryOp(BinaryOpType, ExpressionType left, ExpressionType right, ExpressionType& result);
 90 bool WARN_UNUSED_RETURN unaryOp(UnaryOpType, ExpressionType arg, ExpressionType& result);
 91
 92 // Control flow
 93 ControlData WARN_UNUSED_RETURN addBlock(Type signature);
 94 ControlData WARN_UNUSED_RETURN addLoop(Type signature);
 95 bool WARN_UNUSED_RETURN addIf(ExpressionType condition, Type signature, ControlData& result);
 96 bool WARN_UNUSED_RETURN addElse(ControlData&, const ExpressionList&);
 97
 98 bool WARN_UNUSED_RETURN addReturn(const ExpressionList& returnValues);
 99 bool WARN_UNUSED_RETURN addBranch(ControlData&, ExpressionType condition, const ExpressionList& returnValues);
 100 bool WARN_UNUSED_RETURN endBlock(ControlData&, ExpressionList& expressionStack);
 101
 102 bool WARN_UNUSED_RETURN addCall(unsigned calleeIndex, const FunctionInformation&, const Vector<ExpressionType>& args, ExpressionType& result);
 103 bool WARN_UNUSED_RETURN isContinuationReachable(ControlData&) { return true; }
 104
 105 void dump(const Vector<ControlType>& controlStack, const ExpressionList& expressionStack);
 106
 107 String errorMessage() const { return m_errorMessage; }
 108 Validate(ExpressionType returnType)
 109 : m_returnType(returnType)
 110 {
 111 }
 112
 113private:
 114 bool unify(Type, Type);
 115 bool unify(const ExpressionList&, const ControlData&);
 116
 117 ExpressionType m_returnType;
 118 Vector<Type> m_locals;
 119 String m_errorMessage;
 120};
 121
 122bool Validate::addArguments(const Vector<Type>& args)
 123{
 124 for (Type arg : args) {
 125 if (!addLocal(arg, 1))
 126 return false;
 127 }
 128 return true;
 129}
 130
 131bool Validate::addLocal(Type type, uint32_t count)
 132{
 133 if (!m_locals.tryReserveCapacity(m_locals.size() + count))
 134 return false;
 135
 136 for (uint32_t i = 0; i < count; ++i)
 137 m_locals.uncheckedAppend(type);
 138 return true;
 139}
 140
 141bool Validate::getLocal(uint32_t index, ExpressionType& result)
 142{
 143 if (index < m_locals.size()) {
 144 result = m_locals[index];
 145 return true;
 146 }
 147 m_errorMessage = ASCIILiteral("Attempt to use unknown local.");
 148 return false;
 149}
 150
 151bool Validate::setLocal(uint32_t index, ExpressionType value)
 152{
 153 ExpressionType localType;
 154 if (!getLocal(index, localType))
 155 return false;
 156
 157 if (localType == value)
 158 return true;
 159
 160 m_errorMessage = makeString("Attempt to set local with type: ", toString(localType), " with a variable of type: ", toString(value));
 161 return false;
 162}
 163
 164Validate::ControlType Validate::addBlock(Type signature)
 165{
 166 return ControlData(BlockType::Block, signature);
 167}
 168
 169Validate::ControlType Validate::addLoop(Type signature)
 170{
 171 return ControlData(BlockType::Loop, signature);
 172}
 173
 174bool Validate::addIf(ExpressionType condition, Type signature, ControlType& result)
 175{
 176 if (condition != I32) {
 177 m_errorMessage = makeString("Attempting to use ", toString(condition), " as the condition for an if block");
 178 return false;
 179 }
 180 result = ControlData(BlockType::If, signature);
 181 return true;
 182}
 183
 184bool Validate::addElse(ControlType& current, const ExpressionList& values)
 185{
 186 if (current.type() != BlockType::If) {
 187 m_errorMessage = makeString("Attempting to add else block to something other than an if");
 188 return false;
 189 }
 190
 191 if (!unify(values, current)) {
 192 ASSERT(errorMessage());
 193 return false;
 194 }
 195
 196 current = ControlData(BlockType::Block, current.signature());
 197 return true;
 198}
 199
 200bool Validate::addReturn(const ExpressionList& returnValues)
 201{
 202 if (m_returnType == Void)
 203 return true;
 204 ASSERT(returnValues.size() == 1);
 205
 206 if (m_returnType == returnValues[0])
 207 return true;
 208
 209 m_errorMessage = makeString("Attempting to add return with type: ", toString(returnValues[0]), " but function expects return with type: ", toString(m_returnType));
 210 return false;
 211}
 212
 213bool Validate::addBranch(ControlType& target, ExpressionType condition, const ExpressionList& stack)
 214{
 215 // Void means this is not a conditional branch.
 216 if (condition != Void && condition != I32) {
 217 m_errorMessage = makeString("Attempting to add a conditional branch with condition type: ", toString(condition), " but expected i32.");
 218 return false;
 219 }
 220
 221 if (target.type() == BlockType::If)
 222 return true;
 223
 224 if (target.signature() == Void)
 225 return true;
 226
 227 ASSERT(stack.size() == 1);
 228 if (target.signature() == stack[0])
 229 return true;
 230
 231 m_errorMessage = makeString("Attempting to branch to block with expected type: ", toString(target.signature()), " but branching with type: ", toString(target.signature()));
 232 return false;
 233}
 234
 235bool Validate::endBlock(ControlType& block, ExpressionList& stack)
 236{
 237 if (block.signature() == Void)
 238 return true;
 239
 240
 241 ASSERT(stack.size() == 1);
 242 if (block.signature() == stack[0])
 243 return true;
 244
 245 m_errorMessage = makeString("Block fallthrough has expected type: ", toString(block.signature()), " but produced type: ", toString(block.signature()));
 246 return false;
 247}
 248
 249bool Validate::addCall(unsigned, const FunctionInformation& info, const Vector<ExpressionType>& args, ExpressionType& result)
 250{
 251 if (info.signature->arguments.size() != args.size()) {
 252 StringBuilder builder;
 253 builder.append("Arity mismatch in call, expected: ");
 254 builder.appendNumber(info.signature->arguments.size());
 255 builder.append(" but got: ");
 256 builder.appendNumber(args.size());
 257 m_errorMessage = builder.toString();
 258 return false;
 259 }
 260
 261 for (unsigned i = 0; i < args.size(); ++i) {
 262 if (args[i] != info.signature->arguments[i]) {
 263 m_errorMessage = makeString("Expected argument type: ", toString(info.signature->arguments[i]), " does not match passed argument type: ", toString(args[i]));
 264 return false;
 265 }
 266 }
 267
 268 result = info.signature->returnType;
 269 return true;
 270}
 271
 272bool Validate::unify(const ExpressionList& values, const ControlType& block)
 273{
 274 ASSERT(values.size() <= 1);
 275 if (block.signature() == Void)
 276 return true;
 277
 278 if (!values.size()) {
 279 m_errorMessage = makeString("Block has non-void signature but has no stack entries on exit");
 280 return false;
 281 }
 282
 283 if (values[0] == block.signature())
 284 return true;
 285
 286 m_errorMessage = makeString("Expected control flow to return value with type: ", toString(block.signature()), " but got value with type: ", toString(values[0]));
 287 return false;
 288}
 289
 290void Validate::dump(const Vector<ControlType>&, const ExpressionList&)
 291{
 292 dataLogLn("Validating");
 293}
 294
 295String validateFunction(const uint8_t* source, size_t length, const Signature* signature, const Vector<FunctionInformation>& functions)
 296{
 297 Validate context(signature->returnType);
 298 FunctionParser<Validate> validator(context, source, length, signature, functions);
 299 if (!validator.parse()) {
 300 // FIXME: add better location information here. see: https://bugs.webkit.org/show_bug.cgi?id=164288
 301 return context.errorMessage();
 302 }
 303
 304 return String();
 305}
 306
 307} } // namespace JSC::Wasm
 308
 309#include "WasmValidateInlines.h"
 310
 311#endif // ENABLE(WEBASSEMBLY)

Source/JavaScriptCore/wasm/WasmValidate.h

 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 "WasmFormat.h"
 31
 32namespace JSC { namespace Wasm {
 33
 34String validateFunction(const uint8_t*, size_t, const Signature*, const Vector<FunctionInformation>&);
 35
 36} } // namespace JSC::Wasm
 37
 38#endif // ENABLE(WEBASSEMBLY)

Source/JavaScriptCore/wasm/generateWasmValidateInlinesHeader.py

 1#!/usr/bin/env python
 2
 3# Copyright (C) 2016 Apple Inc. All rights reserved.
 4#
 5# Redistribution and use in source and binary forms, with or without
 6# modification, are permitted provided that the following conditions
 7# are met:
 8#
 9# 1. Redistributions of source code must retain the above copyright
 10# notice, this list of conditions and the following disclaimer.
 11# 2. Redistributions in binary form must reproduce the above copyright
 12# notice, this list of conditions and the following disclaimer in the
 13# documentation and/or other materials provided with the distribution.
 14#
 15# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 16# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 17# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 18# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 19# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 20# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 21# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 22# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 23# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 24# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 25
 26# This tool has a couple of helpful macros to process Wasm files from the wasm.json.
 27
 28from generateWasm import *
 29import optparse
 30import sys
 31
 32parser = optparse.OptionParser(usage="usage: %prog <wasm.json> <WasmOps.h>")
 33(options, args) = parser.parse_args(sys.argv[0:])
 34if len(args) != 3:
 35 parser.error(parser.usage)
 36
 37wasm = Wasm(args[0], args[1])
 38opcodes = wasm.opcodes
 39wasmValidateInlinesHFile = open(args[2], "w")
 40
 41
 42def cppType(name):
 43 result = {
 44 "bool": "I32",
 45 "addr": "I32",
 46 "i32": "I32",
 47 "i64": "I64",
 48 "f32": "F32",
 49 "f64": "F64",
 50 }.get(name, None)
 51 if result == None:
 52 raise ValueError("Unknown type name: " + name)
 53 return result
 54
 55
 56def toCpp(name):
 57 return wasm.toCpp(name)
 58
 59
 60def unaryMacro(name):
 61 op = opcodes[name]
 62 return """
 63 case UnaryOpType::""" + toCpp(name) + """: {
 64 if (value != """ + cppType(op["parameter"][0]) + """) {
 65 m_errorMessage = makeString(\"""" + name + """ expects the value to be of type: ", toString(""" + cppType(op["parameter"][0]) + """), " but got a value with type: ", toString(value));
 66 return false;
 67 }
 68
 69 result = """ + cppType(op["return"][0]) + """;
 70 return true;
 71 }"""
 72
 73
 74def binaryMacro(name):
 75 op = opcodes[name]
 76 return """
 77 case BinaryOpType::""" + toCpp(name) + """: {
 78 if (left != """ + cppType(op["parameter"][0]) + """) {
 79 m_errorMessage = makeString(\"""" + name + """ expects the left value to be of type: ", toString(""" + cppType(op["parameter"][0]) + """), " but got a value with type: ", toString(left));
 80 return false;
 81 }
 82
 83 if (right != """ + cppType(op["parameter"][1]) + """) {
 84 m_errorMessage = makeString(\"""" + name + """ expects the right value to be of type: ", toString(""" + cppType(op["parameter"][0]) + """), " but got a value with type: ", toString(right));
 85 return false;
 86 }
 87
 88 result = """ + cppType(op["return"][0]) + """;
 89 return true;
 90 }"""
 91
 92
 93def loadMacro(name):
 94 op = opcodes[name]
 95 return """
 96 case LoadOpType::""" + toCpp(name) + """: {
 97 if (pointer != """ + cppType(op["parameter"][0]) + """) {
 98 m_errorMessage = makeString(\"""" + name + """ expects the pointer to be of type: ", toString(""" + cppType(op["parameter"][0]) + """), " but got a value with type: ", toString(pointer));
 99 return false;
 100 }
 101
 102 result = """ + cppType(op["return"][0]) + """;
 103 return true;
 104 }"""
 105
 106
 107def storeMacro(name):
 108 op = opcodes[name]
 109 return """
 110 case StoreOpType::""" + toCpp(name) + """: {
 111 if (pointer != """ + cppType(op["parameter"][0]) + """) {
 112 m_errorMessage = makeString(\"""" + name + """ expects the pointer to be of type: ", toString(""" + cppType(op["parameter"][0]) + """), " but got a value with type: ", toString(pointer));
 113 return false;
 114 }
 115
 116 if (value != """ + cppType(op["parameter"][1]) + """) {
 117 m_errorMessage = makeString(\"""" + name + """ expects the value to be of type: ", toString(""" + cppType(op["parameter"][0]) + """), " but got a value with type: ", toString(value));
 118 return false;
 119 }
 120
 121 return true;
 122 }"""
 123
 124
 125unaryCases = "".join([op for op in wasm.opcodeIterator(isUnary, unaryMacro)])
 126binaryCases = "".join([op for op in wasm.opcodeIterator(isBinary, binaryMacro)])
 127loadCases = "".join([op for op in wasm.opcodeIterator(lambda op: op["category"] == "memory" and len(op["return"]) == 1, loadMacro)])
 128storeCases = "".join([op for op in wasm.opcodeIterator(lambda op: op["category"] == "memory" and len(op["return"]) == 0, storeMacro)])
 129
 130contents = wasm.header + """
 131// This file is intended to be inlined by WasmValidate.cpp only! It should not be included elsewhere.
 132
 133#pragma once
 134
 135#if ENABLE(WEBASSEMBLY)
 136
 137namespace JSC { namespace Wasm {
 138
 139bool Validate::unaryOp(UnaryOpType op, ExpressionType value, ExpressionType& result)
 140{
 141 switch (op) {
 142""" + unaryCases + """
 143 }
 144}
 145
 146bool Validate::binaryOp(BinaryOpType op, ExpressionType left, ExpressionType right, ExpressionType& result)
 147{
 148 switch (op) {
 149""" + binaryCases + """
 150 }
 151}
 152
 153bool Validate::load(LoadOpType op, ExpressionType pointer, ExpressionType& result, uint32_t)
 154{
 155 switch (op) {
 156""" + loadCases + """
 157 }
 158}
 159
 160bool Validate::store(StoreOpType op, ExpressionType pointer, ExpressionType value, uint32_t)
 161{
 162 switch (op) {
 163""" + storeCases + """
 164 }
 165}
 166
 167} } // namespace JSC::Wasm
 168
 169#endif // ENABLE(WEBASSEMBLY)
 170
 171"""
 172
 173wasmValidateInlinesHFile.write(contents)
 174wasmValidateInlinesHFile.close()