Changeset 208238 in webkit


Ignore:
Timestamp:
Nov 1, 2016 1:40:40 PM (7 years ago)
Author:
keith_miller@apple.com
Message:

Add a WASM function validator.
https://bugs.webkit.org/show_bug.cgi?id=161707

Reviewed by Saam Barati.

This is a new template specialization of the Wasm FunctionParser class. Instead of having
the FunctionParser track what B3 values each stack entry refers to the validator has each
entry refer to the type of the stack entry. Additionally, the control stack tracks what type
of block the object is and what the result type of the block is. The validation functions
for unary, binary, and memory operations are autogenerated by the
generateWasmValidateInlinesHeader.py script.

There are still a couple issue with validating that will be addressed in follow-up patches.
1) We need to handle result types from basic blocks. https://bugs.webkit.org/show_bug.cgi?id=164100
2) We need to handle popping things from stacks when they don't exist. https://bugs.webkit.org/show_bug.cgi?id=164275

  • CMakeLists.txt:
  • DerivedSources.make:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • testWasm.cpp:

(runWasmTests):

  • wasm/WasmB3IRGenerator.cpp:
  • wasm/WasmFormat.cpp: Added.

(JSC::Wasm::toString):

  • wasm/WasmFormat.h:
  • wasm/WasmFunctionParser.h:

(JSC::Wasm::FunctionParser<Context>::parseExpression):
(JSC::Wasm::FunctionParser<Context>::parseUnreachableExpression):

  • wasm/WasmPlan.cpp:

(JSC::Wasm::Plan::Plan):

  • wasm/WasmValidate.cpp: Added.

(JSC::Wasm::Validate::ControlData::ControlData):
(JSC::Wasm::Validate::ControlData::dump):
(JSC::Wasm::Validate::ControlData::type):
(JSC::Wasm::Validate::ControlData::signature):
(JSC::Wasm::Validate::addConstant):
(JSC::Wasm::Validate::isContinuationReachable):
(JSC::Wasm::Validate::errorMessage):
(JSC::Wasm::Validate::Validate):
(JSC::Wasm::Validate::addArguments):
(JSC::Wasm::Validate::addLocal):
(JSC::Wasm::Validate::getLocal):
(JSC::Wasm::Validate::setLocal):
(JSC::Wasm::Validate::addBlock):
(JSC::Wasm::Validate::addLoop):
(JSC::Wasm::Validate::addIf):
(JSC::Wasm::Validate::addElse):
(JSC::Wasm::Validate::addReturn):
(JSC::Wasm::Validate::addBranch):
(JSC::Wasm::Validate::endBlock):
(JSC::Wasm::Validate::addCall):
(JSC::Wasm::Validate::unify):
(JSC::Wasm::Validate::dump):
(JSC::Wasm::validateFunction):

  • wasm/WasmValidate.h: Added.
  • wasm/generateWasmValidateInlinesHeader.py: Added.

(cppType):
(toCpp):
(unaryMacro):
(binaryMacro):
(loadMacro):
(storeMacro):

Location:
trunk/Source/JavaScriptCore
Files:
4 added
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/CMakeLists.txt

    r208209 r208238  
    880880    wasm/WasmB3IRGenerator.cpp
    881881    wasm/WasmCallingConvention.cpp
     882    wasm/WasmFormat.cpp
    882883    wasm/WasmMemory.cpp
    883884    wasm/WasmModuleParser.cpp
    884885    wasm/WasmPlan.cpp
     886    wasm/WasmValidate.cpp
    885887
    886888    wasm/js/JSWebAssemblyCompileError.cpp
  • trunk/Source/JavaScriptCore/ChangeLog

    r208235 r208238  
     12016-11-01  Keith Miller  <keith_miller@apple.com>
     2
     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
    1662016-11-01  Saam Barati  <sbarati@apple.com>
    267
     
    16791744        Async functions generate bytecode equivalent to the following, which is
    16801745        highly dependent on the Generator implementation:
    1681        
     1746
    16821747        ```
    16831748        // Before translation:
     
    17011766
    17021767        There are some caveats to be addressed later:
    1703        
     1768
    17041769        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)
    1705        
     1770
    17061771        2) for async arrow functions, the home object is always stored on the "body" function, regardless of whether it's needed or
    17071772        not, for the same reason as #1 (and should also be fixed as part of https://bugs.webkit.org/show_bug.cgi?id=151586)
     
    18111876           behavior that is different than the set of cacheable put operations above.
    18121877           Hence, it should not claim that the property put is cacheable.
    1813    
     1878
    18141879        2. Cacheable puts are cached on the original structure of the object before the
    18151880           put operation.
     
    20692134
    20702135        Reviewed by Geoffrey Garen.
    2071        
     2136
    20722137        I want to introduce another HeapTimer. Prior to this change, that would have meant writing
    20732138        exact copies of that timer's logic for each platform that has a HeapTimer (CF, GLIB, and
     
    20772142        to add insult to injury, the USE(CF) version of HeapTimer would have to have an extra case
    20782143        for that new subclass since it doesn't use virtual methods effectively.
    2079        
     2144
    20802145        This changes HeapTimer on USE(CF) to know to get its runloop from Heap and to use virtual
    20812146        methods effectively so that it doesn't have to know about all of its subclasses.
    2082        
     2147
    20832148        This also moves IncrementalSweeper's code for scheduling timers into HeapTimer. This means
    20842149        that future subclasses of HeapTimer could simply use that logic.
    2085        
     2150
    20862151        This keeps changes to GCActivityCallback to a minimum. It still has a lot of
    20872152        platform-specific code and I'm not sure that this code can be trivially deduplicated since
     
    27122777
    27132778        Reviewed by Keith Miller.
    2714        
     2779
    27152780        JSC often suffers from the inline cargo cult, and Heap is a prime example. This outlines a
    27162781        bunch of Heap methods that are either already very big, or call out-of-line methods, or call
    27172782        very big methods, or are not called often enough for inlining to matter.
    2718        
     2783
    27192784        This simplifies concurrent GC work because I'm so tired of recompiling the world when I touch
    27202785        one of these methods.
    2721        
     2786
    27222787        This looks to be perf-neutral.
    27232788
     
    30893154
    30903155        Reviewed by Geoffrey Garen.
    3091        
     3156
    30923157        We need to know if we're currently in an allocation slow path, so that code can assert that
    30933158        it's not being used from inside a destructor that runs during a sweep. We need to know if
     
    30973162        full collection. If we are requesting a collection, we need to know if we're requesting an
    30983163        eden collection, a full collection, or any kind of collection.
    3099        
     3164
    31003165        Prior to this change, you would reason about all of these things using the HeapOperation. It
    31013166        had the following states: NoOperation, Allocation, FullCollection, EdenCollection, and
     
    31053170        Eden, because we just needed a variable to tell us which generation we were talking about.
    31063171        It was all very confusing.
    3107        
     3172
    31083173        Where it completely breaks down is the fact that a concurrent GC has two logical threads, the
    31093174        mutator and the collector, which can change state independently. The mutator can be
     
    31153180        collector not running, running eden, or running full. So, this change decouples mutator state
    31163181        from collector state and uses two separate fields with two different types.
    3117        
     3182
    31183183        Mutator state is described using MutatorState, which can be either MutatorState::Running,
    31193184        MutatorState::Allocating, or MutatorState::HelpingGC.
    3120        
     3185
    31213186        Collector state is described using Optional<CollectionScope>. CollectionScope describes how
    31223187        big the scope of the collection is, and it can be either CollectionScope::Eden or
     
    31273192        collection, which those methods take to mean that they can run any kind of collection (the
    31283193        old AnyCollection).
    3129        
     3194
    31303195        Another use of HeapOperation was to answer questions about whether the caller is running as
    31313196        part of the GC or as part of the mutator. Optional<CollectionScope> does not answer this,
     
    31443209        by checking with mayBeGCThread, which returns Optional<GCThreadType>; if engaged, then run as
    31453210        GC, else run as GC if MutatorState is HelpingGC, else run as mutator.
    3146        
     3211
    31473212        This doesn't change the way that the GC behaves, but it does change how the GC represents a
    31483213        fundamental piece of state. So, it's a big change. It should be perf-neutral (still testing).
     
    37043769
    37053770        Reviewed by Geoffrey Garen.
    3706        
     3771
    37073772        Change the JITWorklist to use AutomaticThread, so that the Baseline JIT's concurrent
    37083773        compiler thread shuts down automatically after inactivity.
    3709        
     3774
    37103775        With this change, all of JSC's threads shut down automatically. If you run splay for a few
    37113776        seconds (which fires up all threads - compiler and GC) and then go to sleep for a second,
     
    37503815
    37513816        Reviewed by Mark Lam.
    3752        
     3817
    37533818        AutomaticThread is a new feature in WTF that allows you to easily create worker threads that
    37543819        shut down automatically. This changes DFG::Worklist to use AutomaticThread, so that its
    37553820        threads shut down automatically, too. This has the potential to save a lot of memory.
    3756        
     3821
    37573822        This required some improvements to AutomaticThread: Worklist likes to be able to keep state
    37583823        around for the whole lifetime of a thread, and so it likes knowing when threads are born and
    37593824        when they die. I added virtual methods for that. Also, Worklist uses notifyOne() so I added
    37603825        that, too.
    3761        
     3826
    37623827        This looks to be perf-neutral.
    37633828
     
    39233988
    39243989        Reviewed by Andreas Kling.
    3925        
     3990
    39263991        Added a sleepSeconds() function, which made it easier for me to test this change.
    3927        
     3992
    39283993        The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
    39293994        shut down automatically after 1 second of inactivity. Maybe this will save some memory.
     
    39534018
    39544019        Reviewed by Geoffrey Garen and Saam Barati.
    3955        
     4020
    39564021        This adds a new kind of call inline cache for when the DFG can prove what the callee
    39574022        executable is. In those cases, we can skip some of the things that the traditional call IC
    39584023        would do:
    3959        
     4024
    39604025        - No need to check who the callee is.
    39614026        - No need to do arity checks.
    3962        
     4027
    39634028        This case isn't as simple as just emitting a call instruction since the callee may not be
    39644029        compiled at the time that the caller is compiled. So, we need lazy resolution. Also, the
     
    39674032        CallLinkInfo has. CallLinkInfo already knows about different kinds of calls. This patch
    39684033        teaches it about new "Direct" call types.
    3969        
     4034
    39704035        The direct non-tail call IC looks like this:
    3971        
     4036
    39724037                set up arguments
    39734038            FastPath:
    39744039                call _SlowPath
    39754040                lea -FrameSize(%rbp), %rsp
    3976            
     4041
    39774042            SlowPath:
    39784043                pop
     
    39804045                check exception
    39814046                jmp FastPath
    3982        
     4047
    39834048        The job of operationLinkDirectCall is to link the fast path's call entrypoint of the callee.
    39844049        This means that in steady state, a call is just that: a call. There are no extra branches or
    39854050        checks.
    3986        
     4051
    39874052        The direct tail call IC is a bit more complicated because the act of setting up arguments
    39884053        destroys our frame, which would prevent us from being able to throw an exception if we
    39894054        failed to compile the callee. So, direct tail call ICs look like this:
    3990        
     4055
    39914056                jmp _SlowPath
    39924057            FastPath:
    39934058                set up arguments
    39944059                jmp 0 // patch to jump to callee
    3995            
     4060
    39964061            SlowPath:
    39974062                silent spill
     
    40004065                check exception
    40014066                jmp FastPath
    4002        
     4067
    40034068        The jmp to the slow path is patched to be a fall-through jmp when we link the call.
    4004        
     4069
    40054070        Direct calls mean less code at call sites, fewer checks on the steady state call fast path,
    40064071        and no need for arity fixup. This looks like a slight speed-up (~0.8%) on both Octane and
     
    41634228        MethodDefinitions which are not either class "constructor" methods or GeneratorMethods, AsyncFunctions,
    41644229        and ArrowFunctions.
    4165        
     4230
    41664231        For details, see the following spec text, and the difference between GeneratorMethod evaluation and
    41674232        the evaluation of other MethodDefinition forms.
    4168        
     4233
    41694234        - https://tc39.github.io/ecma262/#sec-method-definitions-runtime-semantics-propertydefinitionevaluation
    41704235        - https://tc39.github.io/ecma262/#sec-arrow-function-definitions-runtime-semantics-evaluation
    41714236        - https://tc39.github.io/ecmascript-asyncawait/#async-function-instances
    41724237        - https://tc39.github.io/ecma262/#sec-generator-function-definitions-runtime-semantics-propertydefinitionevaluation
    4173        
     4238
    41744239
    41754240        * runtime/Executable.h:
     
    43174382
    43184383        Reviewed by Geoffrey Garen.
    4319        
     4384
    43204385        Before r207408, IRC had a mode where it would silently assign the first assignable register (so
    43214386        %rax, %xmm0, etc) to any tmp that was not colorable due to a pathological interference fencepost.
     
    43284393        corruption. Also, this can only happen for floating point registers, so it's hard to get an
    43294394        exciting crash. The worst case is that your numbers get all messed up.
    4330        
     4395
    43314396        This change fixes the issue:
    4332        
     4397
    43334398        - IRC will now crash if it can't color a tmp.
    4334        
     4399
    43354400        - IRC doesn't crash on our tests anymore because I added a padInterference() utility that works
    43364401          around the interference problem by inserting Nops to pad between those instructions where
    43374402          conflating their early and late actions into one interference fencepost could create an
    43384403          uncolorable graph.
    4339        
     4404
    43404405        See https://bugs.webkit.org/show_bug.cgi?id=163548#c2 for a detailed discussion of how the
    43414406        problem can arise.
    4342        
     4407
    43434408        This problem almost made me want to abandon our use of interference at instruction boundaries,
    43444409        and introduce something more comprehensive, like interference at various stages of an
     
    43544419        DCE, which includes eliminateDeadCode(), allocateStack(), and reportUsedRegisters(). In practice
    43554420        allocateStack() kills them.
    4356        
     4421
    43574422        This also finally refactors our passing of RegisterSet to pass it by value, since it's small
    43584423        enough that we're not gaining anything by using references. On x86, RegisterSet ought to be
     
    46214686
    46224687        Reviewed by Mark Lam.
    4623        
     4688
    46244689        The worklist building function in IRC skips temporaries that have no degree. This doesn't appear
    46254690        to be necessary. This has been there since the original IRC commit. It hasn't caused bugs because
     
    46274692        while working on bug 163371, I hit a crazy corner case where a temporary would have no
    46284693        interference edges (i.e. no degree). Here's how it happens:
    4629        
     4694
    46304695        A spill tmp from a previous iteration of IRC may have no degree: imagine a tmp that is live
    46314696        everywhere and interferes with everyone, but has one use like:
     
    46474712        Then, we might coalesce %someOtherTmp with %newTmp.  Once this happens, if we make the %newTmp be
    46484713        the master, we're in deep trouble because %newTmp is not on any worklist.
    4649        
     4714
    46504715        I don't know how to reproduce this except through the patch in bug 163371. Removing the two lines
    46514716        of code that skipped no-degree tmps causes no regressions, and resolves the problem I was having.
     
    50315096
    50325097        Reviewed by Mark Lam.
    5033        
     5098
    50345099        When I first added the concept of NewGrey/OldGrey, I had the SlotVisitor store the old cell
    50355100        state in itself, so that it could use it to decide what to do for reportExtraMemoryVisited().
    5036        
     5101
    50375102        Then I changed it in a recent commit, because I wanted the freedom to have SlotVisitor visit
    50385103        multiple objects in tandem. But I never ended up using this capability. Still, I liked the
     
    50405105        make the object's state reflect whether it was black for the first time or not. That seemed
    50415106        convenient.
    5042        
     5107
    50435108        Unfortunately it's wrong. After we blacken the object, a concurrent barrier could instantly
    50445109        grey it. Then we would forget that we are visiting this object for the first time.
    50455110        Subsequent visits will think that they are not the first. So, we will fail to do the right
    50465111        thing in reportExtraMemoryVisited().
    5047        
     5112
    50485113        So, this reverts that change. This is a little more than just a revert, though. I've changed
    50495114        the terminology a bit. For example, I got tired of reading Black and having to remind myself
     
    50525117        currently being scanned. I'm going to adopt Siebert's term for this: Anthracite [1]. So, our
    50535118        black CellState is now called AnthraciteOrBlack.
    5054        
     5119
    50555120        [1] https://pdfs.semanticscholar.org/7ae4/633265aead1f8835cf7966e179d02c2c8a4b.pdf
    50565121
     
    51525217
    51535218        Reviewed by Mark Lam.
    5154        
     5219
    51555220        It turns out that HeapSnapshot was not down with revisiting. The concurrent GC is going to be
    51565221        built around the idea that we can revisit objects many times. This means that any action that
    51575222        should only take place once per object must check the object's state. This fixes the snapshot
    51585223        code to do this.
    5159        
     5224
    51605225        While writing this code, I realized that we're actually doing this check incorrectly, so I
    51615226        filed bug 163343. That bug requires a race, so we aren't going to see it yet.
     
    51885253        (InjectedScript.prototype._describe):
    51895254        Provide a friendlier name, "Proxy" instead of "ProxyObject".
    5190        
     5255
    51915256        (InjectedScript.RemoteObject):
    51925257        When generating a preview for a Proxy object, generate it from the final target
     
    52275292        by the parser. This could get out of sync, or nodes could forget to
    52285293        emit debug hooks expected by the parser.
    5229        
     5294
    52305295        With this change, we always check and emit a debug hook for any
    52315296        node. The default behavior is for BytecodeGenerator::emitNode
     
    53725437
    53735438        Reviewed by Mark Lam.
    5374        
     5439
    53755440        I guess that the idea of JITWriteBarrier was to make sure that if you slap some heap pointer
    53765441        bits into machine code, then you better execute a barrier on the code block. But it's a
     
    53805445        stored in machine code must always be shadowed in the GC heap. I think that convention has
    53815446        won by overwhelming majority, so we should finally remove JITWriteBarrier.
    5382        
     5447
    53835448        A practical outcome of this change is that it makes it easier to implement DirectCall ICs,
    53845449        which will have to store the callee in the CallLinkInfo but not in the machine code.
     
    54295494
    54305495        Reviewed by Geoffrey Garen.
    5431        
     5496
    54325497        It used to be that we would forget which objects are live the moment we started collection.
    54335498        That's because the flip at the beginning clears all mark bits.
    5434        
     5499
    54355500        But we already have a facility for tracking objects that are live-but-not-marked. It's called
    54365501        newlyAllocated. So, instead of clearing mark bits, we want to just transfer them to
    54375502        newlyAllocated. Then we want to clear all newlyAllocated after GC.
    5438        
     5503
    54395504        This implements such an approach, along with a versioning optimization for newlyAllocated.
    54405505        Instead of walking the whole heap to clear newlyAllocated bits at the end of the GC, we bump
    54415506        the newlyAllocatedVersion, which causes MarkedBlock to treat newlyAllocated as if it was
    54425507        clear.
    5443        
     5508
    54445509        We could have even avoided allocating newlyAllocated in most cases, since empirically most
    54455510        blocks are either completely empty or completely full. An earlier version of this patch did
    54465511        this, but it was not better than this patch. In fact, it seemed to actually be worse for PLT
    54475512        and membuster.
    5448        
     5513
    54495514        To validate this change, we now run the conservative scan after the beginMarking flip. And it
    54505515        totally works!
    5451        
     5516
    54525517        This is a huge step towards concurrent GC. It means that we ought to be able to run the
    54535518        allocator while marking. Since we already separately made it possible to run the barrier
    54545519        while marking, this means that we're pretty much ready for some serious concurrency action.
    5455        
     5520
    54565521        This appears to be perf-neutral and space-neutral.
    54575522
     
    56105675
    56115676        Reviewed by Yusuke Suzuki.
    5612        
     5677
    56135678        We have a lot of defenses against emitting code that materializes huge contants. But if we do
    56145679        end up with such code in the backend, it's better to convert those materializations into add
     
    56255690
    56265691        Reviewed by Mark Lam.
    5627        
     5692
    56285693        When writing the lea patch (r207039), I was very careful about how I convert a Shl into a
    56295694        BaseIndex scale. But I forgot to check if the older code for creating BaseIndexes for
    56305695        effectiveAddr() got this right. It turns out that the older code missed the <<32 corner
    56315696        case.
    5632        
     5697
    56335698        It's sad that the two paths can't share all of their code, but it's somewhat inevitable due
    56345699        to how matching an address and matching a lea have to do very different things. Matching a
     
    56405705        more sane by adding a scaleForShl() helper that handles this weird case. It's based on the
    56415706        new Shl handling from r207039, and exposes it as an API for effectiveAddr() to use.
    5642        
     5707
    56435708        The testLoadBaseIndexShift32() used to crash. I don't think that this case affects JS
    56445709        content, since <<32 is such a bizarre outlier. I don't think we even have a path along
     
    56915756
    56925757        Reviewed by Saam Barati.
    5693        
     5758
    56945759        This adds comprehensive support for emitting lea on x86.
    5695        
     5760
    56965761        When adding this, I found that it was useful to also finally add more reassociation. That
    56975762        reduces the amount of patterns that the instruction selector has to deal with.
     
    58325897
    58335898        Reviewed by Keith Miller.
    5834        
     5899
    58355900        You can now call Procedure::pinRegister(), or Code::pinRegister(), and it will make this
    58365901        register behave as follows:
    5837        
     5902
    58385903        - B3 and Air will emit no code that modifies the value in this register, except if that
    58395904          happens via a Patchpoint or stackmap constraint (i.e. the user explicitly asked for it).
     
    58465911          to use them by (1) excluding them from any clobber set (easy, since they're callee save)
    58475912          and (2) emitting ArgumentReg to grab their value. There's a test that does this.
    5848        
    5849         This is accomplished by taking regsInPriorityOrder() and making it a method of Code. Air 
     5913
     5914        This is accomplished by taking regsInPriorityOrder() and making it a method of Code. Air
    58505915        already used this API when choosing registers in register allocation. Code now also vends a
    58515916        mutableRegs() set, which is derived from regsInPriorityOrder(), that can quickly tell you if
    58525917        a register can be mutated. Doing it this way means that most of this is a purely mechanical
    58535918        change. The calls to mutableRegs() are the places where we had to change logic:
    5854        
     5919
    58555920        - The register allocators needs to know that coalescing with a precolored pinned tmp is free.
    58565921        - The callee-save handler needs to know that we're not supposed to save/restore pinned
    58575922          registers.
    5858        
     5923
    58595924        Note that in this scheme, pinned registers are simply registers that do not appear in
    58605925        regsInPriorityOrder(). This means, for example, that we will now say that FP is pinned. So,
     
    59115976
    59125977        Reviewed by Keith Miller.
    5913        
     5978
    59145979        If we have mutable pinned registers then we need to know which operations mutate them. At
    59155980        first I considered making this into a heap range thing, but I think that this would be very
     
    69126977        Air::generate() to use labelIgnoringWatchpoints() to create pcToOriginMap
    69136978        entries to eliminate unneccesary NOPs.
    6914        
     6979
    69156980        * b3/air/AirGenerate.cpp:
    69166981        (JSC::B3::Air::generate):
     
    69467011
    69477012        Reviewed by Geoffrey Garen.
    6948        
     7013
    69497014        While writing some documentation, I found some small holes in the code.
    69507015
     
    70457110
    70467111        Reviewed by Dan Bernstein.
    7047        
     7112
    70487113        This function has become dead code. This change removes it.
    70497114
     
    71007165
    71017166        Reviewed by Geoffrey Garen.
    7102        
     7167
    71037168        This adds a traps flag to B3::Kind. It also makes B3::Kind work more like Air::Kind, in the
    71047169        sense that it's a bag of distinct bits - it doesn't need to be a union unless we get enough
    71057170        things that it would make a difference.
    7106        
     7171
    71077172        The only analysis that needs to know about traps is effects. It now knows that traps implies
    71087173        sideExits, which means that this turns off DCE. The only optimization that needs to know
    71097174        about traps is eliminateCommonSubexpressions(), which needs to pessimize its store
    71107175        elimination if the store traps.
    7111        
     7176
    71127177        The hard part of this change is teaching the instruction selector to faithfully carry the
    71137178        traps flag down to Air. I got this to work by making ArgPromise a non-copyable object that
     
    71177182        correctly carry the trap bit: if any of the B3 loads or stores involved traps then you get
    71187183        traps in Air.
    7119        
     7184
    71207185        This framework also sets us up to do bug 162688, since the ArgPromise::inst() hook is
    71217186        powerful enough to allow wrapping the instruction with a Patch.
    7122        
     7187
    71237188        I added some tests to testb3 that verify that optimizations are appropriately inhibited and
    71247189        that the traps flag survives until the bitter end of Air.
     
    71917256
    71927257        Reviewed by Saam Barati.
    7193        
     7258
    71947259        There are some interesting cases where we can reduce the number of constant materializations if
    71957260        we teach moveConstants() how to edit code. The two examples that this patch supports are:
    7196        
     7261
    71977262            - Loads and stores from a constant pointer. Since loads and stores get an offset for free
    71987263              and the instruction selector is really good at handling it, and since we can query Air to
     
    72007265              is specific to the absolute address of that load and instead pick some other constant
    72017266              that is within offset distance of ours.
    7202            
     7267
    72037268            - Add and Sub by a constant (x + c, x - c). Since x + c = x - -c and x - c = x + -c, we can
    72047269              flip Add to Sub or vice versa if the negated constant is available.
    7205        
     7270
    72067271        This change makes moveConstants() pick the most dominant constant that works for an value. In
    72077272        the case of memory accesses, it uses Air::Arg::isValidAddrForm() to work out what other
     
    72107275        most dominant constant that works - so if an Add's constant is already most dominant then
    72117276        nothing changes, but if the negated one is more dominant then it becomes a Sub.
    7212        
     7277
    72137278        This is a 0.5% speed-up on LongSpider and neutral elsewhere. It's a speed-up because the
    72147279        absolute address thing reduces the number of address materializations that we have to do, while
     
    75067571        resolve the breakpoint location before setting the
    75077572        breakpoint. The different paths are:
    7508        
     7573
    75097574        - setBreakpoint(scriptId, location)
    75107575          - Here we know the SourceProvider by its SourceID
    75117576            - resolve and set
    7512        
     7577
    75137578        - setBreakpointByURL(url, location)
    75147579          - Search for existing Scripts that match the URL
     
    75167581          - When new Scripts are parsed that match the URL
    75177582            - resolve and set
    7518            
     7583
    75197584
    752075852016-09-30  Joseph Pecoraro  <pecoraro@apple.com>
     
    76557720        (JSC::Debugger::exception):
    76567721        (JSC::Debugger::didReachBreakpoint):
    7657        
     7722
    76587723        Use new variable names, and clarify if we should attempt
    76597724        to pause or not.
     
    76677732        (JSC::Debugger::pauseIfNeeded):
    76687733        Allow updateCallFrame to either attempt a pause or not.
    7669        
     7734
    76707735        (JSC::Debugger::atStatement):
    76717736        Attempt pause and reset the at first expression flag.
     
    76837748        If the user did a step-over and is leaving the
    76847749        function, then behave like step-out.
    7685        
     7750
    76867751        (JSC::Debugger::unwindEvent):
    76877752        Behave like return except don't change any
     
    77027767        our state so we don't errantly pause on the next
    77037768        JavaScript microtask that gets executed.
    7704        
     7769
    77057770        (JSC::Debugger::clearNextPauseState):
    77067771        Helper to clear all of the pause states now that
     
    77857850
    77867851        Reviewed by Mark Lam.
    7787        
     7852
    77887853        This follows a similar change in B3 (r206595) and replaces Air::Opcode with Air::Kind,
    77897854        which holds onto the opcode and some additional flags. Because Air is an orthogonal ISA
     
    77927857        meant to be orthogonal to opcode. This allows us to say things like Add32<Trap>, which
    77937858        makes sense if any of the operands to the Add32 are addresses.
    7794        
     7859
    77957860        To demonstrate the flags facility this partly adds a trap flag to Air. B3 doesn't use it
    77967861        yet, but I made sure that Air respects it. Basically that means blocking DCE when the flag
     
    78767941
    78777942        Reviewed by Keith Miller.
    7878        
     7943
    78797944        The put_by_id-in-put_by_val optimization had the write barrier in the wrong place and
    78807945        incorrectly filtered on value instead of base.
    7881        
     7946
    78827947        No reduced test case. You really need to run Dromaeo/jslib to catch it. I love Dromaeo's
    78837948        ability to catch GC bugs.
     
    79327997        actually did. This change replaces Opcode with Kind, which is a tuple of opcode and other
    79337998        stuff.
    7934        
     7999
    79358000        Opcodes are great, and that's how most compilers work. But opcodes are one-dimensional. Here
    79368001        is how this manifests. Say you have an opcode, like Load. You will be happy if your IR has
     
    79388003        done in B3. B3 has one dimension of Load opcodes, which determines something like the C type
    79398004        of the load. But in the very near future, we will want to add two more dimensions to Loads:
    7940        
     8005
    79418006        - A flag to say if the load traps.
    79428007        - A flag to say if the load has acquire semantics.
    7943        
     8008
    79448009        Mapping these three dimensions (type, trap, acquire) onto the one-dimensional Opcode space
    79458010        would create mayham: Load8S, Load8STrap, Load8SAcquire, Load8STrapAcquire, Load8Z,
    79468011        Load8ZTrap, etc.
    7947        
     8012
    79488013        This happens in other parts of the IR. For example, we have a dimension of arithmetic
    79498014        operations: add, sub, mul, div, mod, etc. Then we have the chill flag. But since opcodes
     
    79518016        compiler that case on both Div and ChillDiv, or case on both Mod and ChillMod, since they
    79528017        are only interested in the kind of arithmetic being done and not the chillness.
    7953        
     8018
    79548019        Though the examples all involve bits (chill or not, trapping or not, etc), I can imagine
    79558020        other properties that behave more like small enums, like if we fill out more memory ordering
    79568021        modes other than just "acquire? yes/no". There will eventually have to be something like a
    79578022        std::memory_order associated with memory accesses.
    7958        
     8023
    79598024        One approach to this problem is to have a Value subclass that contains fields with the meta
    79608025        data. I don't like this for two reasons:
    7961        
     8026
    79628027        - In bug 162688, I want to make trapping memory accesses have stackmaps. This means that a
    79638028          trapping memory access would have a different Value subclass than a non-trapping memory
    79648029          access. So, this meta-data needs to channel into ValueType::accepts(). Currently that
    79658030          takes Opcode and nothing else.
    7966        
     8031
    79678032        - Compiler IRs are all about making common tasks easy. If it becomes commonplace for opcodes
    79688033          to require a custom Value subclass just for a bit then that's not very easy.
    7969        
     8034
    79708035        This change addresses this problem by making the compiler pass around Kinds rather than
    79718036        Opcodes. A Kind contains an Opcode as well as any number of opcode-specific bits. This
     
    79768041
    79778042            Int32 @38 = Div<Chill>(@36, @37, DFG:@24, ControlDependent)
    7978        
     8043
    79798044        Where "Div<Chill>" is how a Kind that hasExtraBits() dumps itself. If a Kind does not
    79808045        hasExtraBits() (the normal case) then it dumps like a normal Opcode (without the "<>").
    7981        
     8046
    79828047        I replaced many uses of Opcode with Kind. New code has to be mindful that Opcode may not be
    79838048        the right way to summarize what a value does, and so in many cases it's better to carry
     
    79878052        Opcode. But most opcodes don't get any extra Kind bits, and so the code that operates on
    79888053        those opcodes is largely unchanged.
    7989        
     8054
    79908055        * CMakeLists.txt:
    79918056        * JavaScriptCore.xcodeproj/project.pbxproj:
     
    81148179
    81158180        Reviewed by Geoffrey Garen.
    8116        
     8181
    81178182        This makes our write barrier behave correctly when it races with the collector. The
    81188183        collector wants to do this when visiting:
    8119        
     8184
    81208185            object->cellState = black
    81218186            visit(object)
    8122        
     8187
    81238188        The mutator wants to do this when storing:
    8124        
     8189
    81258190            object->property = newValue
    81268191            if (object->cellState == black)
    81278192                remember(object)
    8128        
     8193
    81298194        Prior to this change, this didn't work right because the compiler would sometimes place
    81308195        barriers before the store to the property and because the mutator did not have adequate
    81318196        fences.
    8132        
     8197
    81338198        Prior to this change, the DFG and FTL would emit this:
    8134        
     8199
    81358200            if (object->cellState == black)
    81368201                remember(object)
    81378202            object->property = newValue
    8138        
     8203
    81398204        Which is wrong, because the object could start being scanned just after the cellState
    81408205        check, at which point the store would be lost. We need to confirm that the state was not
     
    81478212        don't have any way to represent any of the GC's other state, which means that B3 does not
    81488213        have to worry about aliasing with any of that).
    8149        
     8214
    81508215        The collector already uses a store-load fence on x86 just after setting the cellState and
    81518216        before visiting the object. The mutator needs to do the same. But we cannot put a
     
    81568221        would lift throughput-while-collecting from 0% of peak to 85% of peak. This changes the
    81578222        barrier so that it looks like this:
    8158        
     8223
    81598224            if (object->cellState <= heap.sneakyBlackThreshold)
    81608225                slowPath(object)
    8161        
     8226
    81628227        Where sneakyBlackThreshold is the normal blackThreshold when we're not collecting, or a
    81638228        tautoligical threshold (that makes everything look black) when we are collecting. This
     
    81678232        check if we are concurrently collecting; if so, it does a fence and rechecks if the object
    81688233        really did need that barrier.
    8169        
     8234
    81708235        This also reintroduces elimination of redundant store barriers, which was lost in the last
    81718236        store barrier change. We can only do it when there is no possibility of GC, exit, or
     
    81778242        that it uses a constant black threshold rather than the sneaky one, thereby saving one
    81788243        load.
    8179        
     8244
    81808245        Even with all of those optimizations, I still had problems with barrier cost. I found that one
    81818246        of the benchmarks that was being hit particularly hard was JetStream/regexp-2010. Fortunately
     
    81878252        to have a DeferralContext object that houses a boolean that is false by default, but the GC
    81888253        writes true into it if it would have wanted to GC. You thread a pointer to the deferralContext
    8189         through all of your allocations. This kind of mechanism has the overhead of a zero 
     8254        through all of your allocations. This kind of mechanism has the overhead of a zero
    81908255        initialization on the stack on entry and a zero check on exit. This is probably even efficient
    81918256        enough that we could start thinking about having the DFG use it, for example if we found a
     
    81938258        wacky. This optimization took this patch from 0.68% JetStream regressed to neutral, according
    81948259        to my latest data.
    8195        
     8260
    81968261        Finally, an earlier version of this change put the store-load fence in B3 IR, so I ended up
    81978262        adding FTLOutput support for it and AbstractHeapRepository magic for decorating the heaps.
     
    85698634        Make the subclass of CallSlowPathGenerator that takes arguments variadic
    85708635        so it can take any number of arguments. Also updates the slowPathCall helper
    8571         function to be variadic. I had to move the spill mode and exception check 
     8636        function to be variadic. I had to move the spill mode and exception check
    85728637        requirement parameters to before the arguments since the variadic arguments
    85738638        must be at the end. As a convenience, I added an overload of slowPathCall that
  • trunk/Source/JavaScriptCore/DerivedSources.make

    r208148 r208238  
    6565    YarrCanonicalizeUnicode.cpp \
    6666    WasmOps.h \
     67    WasmValidateInlines.h \
    6768#
    6869
     
    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
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r208209 r208238  
    12311231                531374BD1D5CE67600AF7A0B /* WasmPlan.h in Headers */ = {isa = PBXBuildFile; fileRef = 531374BC1D5CE67600AF7A0B /* WasmPlan.h */; };
    12321232                531374BF1D5CE95000AF7A0B /* WasmPlan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 531374BE1D5CE95000AF7A0B /* WasmPlan.cpp */; };
     1233                533B15DF1DC7F463004D500A /* WasmOps.h in Headers */ = {isa = PBXBuildFile; fileRef = 533B15DE1DC7F463004D500A /* WasmOps.h */; };
    12331234                5341FC701DAC33E500E7E4D7 /* B3WasmBoundsCheckValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5341FC6F1DAC33E500E7E4D7 /* B3WasmBoundsCheckValue.cpp */; };
    12341235                5341FC721DAC343C00E7E4D7 /* B3WasmBoundsCheckValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 5341FC711DAC343C00E7E4D7 /* B3WasmBoundsCheckValue.h */; };
     
    12541255                53F40E8D1D5901F20099A1B6 /* WasmParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F40E8C1D5901F20099A1B6 /* WasmParser.h */; };
    12551256                53F40E8F1D5902820099A1B6 /* WasmB3IRGenerator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53F40E8E1D5902820099A1B6 /* WasmB3IRGenerator.cpp */; };
    1256                 53F40E911D5903020099A1B6 /* WasmOps.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F40E901D5903020099A1B6 /* WasmOps.h */; };
    12571257                53F40E931D5A4AB30099A1B6 /* WasmB3IRGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F40E921D5A4AB30099A1B6 /* WasmB3IRGenerator.h */; };
    12581258                53F40E951D5A7AEF0099A1B6 /* WasmModuleParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F40E941D5A7AEF0099A1B6 /* WasmModuleParser.h */; };
     
    12631263                53FD04D31D7AB277003287D3 /* WasmCallingConvention.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53FD04D11D7AB187003287D3 /* WasmCallingConvention.cpp */; };
    12641264                53FD04D41D7AB291003287D3 /* WasmCallingConvention.h in Headers */ = {isa = PBXBuildFile; fileRef = 53FD04D21D7AB187003287D3 /* WasmCallingConvention.h */; };
    1265                 5C4E8E961DBEBE620036F1FC /* JSONParseTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C4E8E941DBEBDA20036F1FC /* JSONParseTest.cpp */; };
     1265                53FF7F991DBFCD9000A26CCC /* WasmValidate.h in Headers */ = {isa = PBXBuildFile; fileRef = 53FF7F981DBFCD9000A26CCC /* WasmValidate.h */; };
     1266                53FF7F9B1DBFD2B900A26CCC /* WasmValidate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53FF7F9A1DBFD2B900A26CCC /* WasmValidate.cpp */; };
     1267                53FF7F9D1DC00DB100A26CCC /* WasmFormat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53FF7F9C1DC00DB100A26CCC /* WasmFormat.cpp */; };
    12661268                5B70CFDE1DB69E6600EC23F9 /* JSAsyncFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 5B70CFD81DB69E5C00EC23F9 /* JSAsyncFunction.h */; };
    12671269                5B70CFDF1DB69E6600EC23F9 /* JSAsyncFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5B70CFD91DB69E5C00EC23F9 /* JSAsyncFunction.cpp */; };
     
    12701272                5B70CFE21DB69E6600EC23F9 /* AsyncFunctionConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 5B70CFDC1DB69E5C00EC23F9 /* AsyncFunctionConstructor.h */; };
    12711273                5B70CFE31DB69E6600EC23F9 /* AsyncFunctionConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5B70CFDD1DB69E5C00EC23F9 /* AsyncFunctionConstructor.cpp */; };
     1274                5C4E8E961DBEBE620036F1FC /* JSONParseTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C4E8E941DBEBDA20036F1FC /* JSONParseTest.cpp */; };
    12721275                5D5D8AD10E0D0EBE00F9C692 /* libedit.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D5D8AD00E0D0EBE00F9C692 /* libedit.dylib */; };
    12731276                5DBB151B131D0B310056AD36 /* testapi.js in Copy Support Script */ = {isa = PBXBuildFile; fileRef = 14D857740A4696C80032146C /* testapi.js */; };
     
    35593562                531374BC1D5CE67600AF7A0B /* WasmPlan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmPlan.h; sourceTree = "<group>"; };
    35603563                531374BE1D5CE95000AF7A0B /* WasmPlan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmPlan.cpp; sourceTree = "<group>"; };
     3564                533B15DE1DC7F463004D500A /* WasmOps.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmOps.h; sourceTree = "<group>"; };
    35613565                5341FC6F1DAC33E500E7E4D7 /* B3WasmBoundsCheckValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = B3WasmBoundsCheckValue.cpp; path = b3/B3WasmBoundsCheckValue.cpp; sourceTree = "<group>"; };
    35623566                5341FC711DAC343C00E7E4D7 /* B3WasmBoundsCheckValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3WasmBoundsCheckValue.h; path = b3/B3WasmBoundsCheckValue.h; sourceTree = "<group>"; };
     
    35863590                53F40E8C1D5901F20099A1B6 /* WasmParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmParser.h; sourceTree = "<group>"; };
    35873591                53F40E8E1D5902820099A1B6 /* WasmB3IRGenerator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmB3IRGenerator.cpp; sourceTree = "<group>"; };
    3588                 53F40E901D5903020099A1B6 /* WasmOps.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmOps.h; sourceTree = "<group>"; };
    35893592                53F40E921D5A4AB30099A1B6 /* WasmB3IRGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmB3IRGenerator.h; sourceTree = "<group>"; };
    35903593                53F40E941D5A7AEF0099A1B6 /* WasmModuleParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmModuleParser.h; sourceTree = "<group>"; };
     
    35953598                53FD04D11D7AB187003287D3 /* WasmCallingConvention.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmCallingConvention.cpp; sourceTree = "<group>"; };
    35963599                53FD04D21D7AB187003287D3 /* WasmCallingConvention.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmCallingConvention.h; sourceTree = "<group>"; };
    3597                 5C4E8E941DBEBDA20036F1FC /* JSONParseTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JSONParseTest.cpp; path = API/tests/JSONParseTest.cpp; sourceTree = "<group>"; };
    3598                 5C4E8E951DBEBDA20036F1FC /* JSONParseTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSONParseTest.h; path = API/tests/JSONParseTest.h; sourceTree = "<group>"; };
     3600                53FF7F981DBFCD9000A26CCC /* WasmValidate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmValidate.h; sourceTree = "<group>"; };
     3601                53FF7F9A1DBFD2B900A26CCC /* WasmValidate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmValidate.cpp; sourceTree = "<group>"; };
     3602                53FF7F9C1DC00DB100A26CCC /* WasmFormat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmFormat.cpp; sourceTree = "<group>"; };
    35993603                5B70CFD81DB69E5C00EC23F9 /* JSAsyncFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSAsyncFunction.h; sourceTree = "<group>"; };
    36003604                5B70CFD91DB69E5C00EC23F9 /* JSAsyncFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSAsyncFunction.cpp; sourceTree = "<group>"; };
     
    36043608                5B70CFDD1DB69E5C00EC23F9 /* AsyncFunctionConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AsyncFunctionConstructor.cpp; sourceTree = "<group>"; };
    36053609                5B8243041DB7AA4900EA6384 /* AsyncFunctionPrototype.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = AsyncFunctionPrototype.js; sourceTree = "<group>"; };
     3610                5C4E8E941DBEBDA20036F1FC /* JSONParseTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JSONParseTest.cpp; path = API/tests/JSONParseTest.cpp; sourceTree = "<group>"; };
     3611                5C4E8E951DBEBDA20036F1FC /* JSONParseTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSONParseTest.h; path = API/tests/JSONParseTest.h; sourceTree = "<group>"; };
    36063612                5D5D8AD00E0D0EBE00F9C692 /* libedit.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libedit.dylib; path = /usr/lib/libedit.dylib; sourceTree = "<absolute>"; };
    36073613                5DAFD6CB146B686300FBEFB4 /* JSC.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = JSC.xcconfig; sourceTree = "<group>"; };
     
    58465852                                996B73141BD9FA2C00331B84 /* SymbolPrototype.lut.h */,
    58475853                                65A946141C8E9F6F00A7209A /* YarrCanonicalizeUnicode.cpp */,
     5854                                533B15DE1DC7F463004D500A /* WasmOps.h */,
    58485855                        );
    58495856                        name = "Derived Sources";
     
    58825889                                53FD04D11D7AB187003287D3 /* WasmCallingConvention.cpp */,
    58835890                                53FD04D21D7AB187003287D3 /* WasmCallingConvention.h */,
    5884                                 53F40E901D5903020099A1B6 /* WasmOps.h */,
     5891                                53FF7F9C1DC00DB100A26CCC /* WasmFormat.cpp */,
    58855892                                7BC547D21B69599B00959B58 /* WasmFormat.h */,
    58865893                                53F40E8A1D5901BB0099A1B6 /* WasmFunctionParser.h */,
     
    58935900                                53F40E8C1D5901F20099A1B6 /* WasmParser.h */,
    58945901                                53F40E841D58F9770099A1B6 /* WasmSections.h */,
     5902                                53FF7F9A1DBFD2B900A26CCC /* WasmValidate.cpp */,
     5903                                53FF7F981DBFCD9000A26CCC /* WasmValidate.h */,
    58955904                        );
    58965905                        path = wasm;
     
    79978006                                0F2BDC4B1522809D00CD8910 /* DFGVariableEventStream.h in Headers */,
    79988007                                0FFFC96014EF90BD00C72532 /* DFGVirtualRegisterAllocationPhase.h in Headers */,
     8008                                53FF7F991DBFCD9000A26CCC /* WasmValidate.h in Headers */,
    79998009                                0FC97F4218202119002C9B26 /* DFGWatchpointCollectionPhase.h in Headers */,
    80008010                                0FDB2CE8174830A2007B3C1B /* DFGWorklist.h in Headers */,
     
    84008410                                FE1220271BE7F58C0039E6F2 /* JITAddGenerator.h in Headers */,
    84018411                                0F919D11157F332C004A4E7D /* JSSegmentedVariableObject.h in Headers */,
    8402                                 53F40E911D5903020099A1B6 /* WasmOps.h in Headers */,
    84038412                                A7299D9E17D12837005F5FF9 /* JSSet.h in Headers */,
    84048413                                A790DD70182F499700588807 /* JSSetIterator.h in Headers */,
     
    87818790                                14E84FA214EE1ACC00D6D5D4 /* WeakImpl.h in Headers */,
    87828791                                14BE7D3317135CF400D1807A /* WeakInlines.h in Headers */,
     8792                                533B15DF1DC7F463004D500A /* WasmOps.h in Headers */,
    87838793                                A7CA3AE417DA41AE006538AF /* WeakMapConstructor.h in Headers */,
    87848794                                A7CA3AEC17DA5168006538AF /* WeakMapData.h in Headers */,
     
    99429952                                A7E2EA6C0FB460CF00601F06 /* LiteralParser.cpp in Sources */,
    99439953                                A5A1A0951D8CB341004C2EB8 /* DebuggerParseData.cpp in Sources */,
     9954                                53FF7F9D1DC00DB100A26CCC /* WasmFormat.cpp in Sources */,
    99449955                                FE3913541B794F6E00EDAF71 /* LiveObjectList.cpp in Sources */,
    99459956                                FE20CE9D15F04A9500DF3430 /* LLIntCLoop.cpp in Sources */,
     
    1010010111                                70EC0EC61AA0D7DA00B6AAFA /* StringIteratorPrototype.cpp in Sources */,
    1010110112                                14469DEC107EC7E700650446 /* StringObject.cpp in Sources */,
     10113                                53FF7F9B1DBFD2B900A26CCC /* WasmValidate.cpp in Sources */,
    1010210114                                14469DED107EC7E700650446 /* StringPrototype.cpp in Sources */,
    1010310115                                9335F24D12E6765B002B5553 /* StringRecursionChecker.cpp in Sources */,
  • trunk/Source/JavaScriptCore/testWasm.cpp

    r207825 r208238  
    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()
     
    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.
     
    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.
     
    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.
     
    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.
     
    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.
     
    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
    480         };
    481 
    482         Plan plan(*vm, vector);
    483         if (plan.failed() || plan.resultSize() != 1 || !plan.result(0)) {
    484             dataLogLn("Module failed to compile correctly.");
    485             CRASH();
    486         }
     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
     485        };
     486
     487        Plan plan(*vm, vector);
     488        checkPlan(plan, 1);
    487489
    488490        // Test this doesn't crash.
     
    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.
     
    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
     
    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
     
    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
     
    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.
     
    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.
     
    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.
     
    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
     
    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
     
    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
     
    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.
     
    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.
     
    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.
     
    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.
     
    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.
     
    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.
     
    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.
     
    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.
     
    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.
     
    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.
     
    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.
     
    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.
  • trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp

    r207825 r208238  
    8888        }
    8989
     90        LazyBlock()
     91        {
     92        }
     93
    9094        explicit operator bool() const { return !!m_block; }
    9195
     
    117121            if (signature != Void)
    118122                result.append(proc.addVariable(toB3Type(signature)));
     123        }
     124
     125        ControlData()
     126        {
    119127        }
    120128
     
    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
     
    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);
     
    246254}
    247255
    248 void B3IRGenerator::addLocal(Type type, uint32_t count)
    249 {
    250     m_locals.reserveCapacity(m_locals.size() + count);
     256bool B3IRGenerator::addLocal(Type type, uint32_t count)
     257{
     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)));
    253 }
    254 
    255 void B3IRGenerator::addArguments(const Vector<Type>& types)
     262        m_locals.uncheckedAppend(m_proc.addVariable(toB3Type(type)));
     263    return true;
     264}
     265
     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(),
     
    263277            m_currentBlock->appendNew<VariableValue>(m_proc, Set, Origin(), argumentVariable, argument);
    264278        });
     279    return true;
    265280}
    266281
     
    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.
     
    508523
    509524    m_currentBlock = taken;
    510     return ControlData(m_proc, signature, notTaken, continuation);
    511 }
    512 
    513 bool B3IRGenerator::addElse(ControlData& data)
     525    result = ControlData(m_proc, signature, notTaken, continuation);
     526    return true;
     527}
     528
     529bool B3IRGenerator::addElse(ControlData& data, const ExpressionList&)
    514530{
    515531    ASSERT(data.continuation);
  • trunk/Source/JavaScriptCore/wasm/WasmFormat.h

    r207693 r208238  
    9898}
    9999
     100const char* toString(Type);
    100101
    101102struct Signature {
  • trunk/Source/JavaScriptCore/wasm/WasmFunctionParser.h

    r207825 r208238  
    7474    if (verbose)
    7575        dataLogLn("Parsing function starting at: ", (uintptr_t)functionStart, " of length: ", functionLength);
    76     m_context.addArguments(m_signature->arguments);
    7776}
    7877
     
    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))
     
    9395            return false;
    9496
    95         m_context.addLocal(typeOfLocal, numberOfLocals);
     97        if (!m_context.addLocal(typeOfLocal, numberOfLocals))
     98            return false;
    9699    }
    97100
     
    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
     
    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
  • trunk/Source/JavaScriptCore/wasm/WasmPlan.cpp

    r207825 r208238  
    3333#include "WasmCallingConvention.h"
    3434#include "WasmModuleParser.h"
     35#include "WasmValidate.h"
    3536#include <wtf/DataLog.h>
    3637
     
    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    }
Note: See TracChangeset for help on using the changeset viewer.