B3 should support multiple entrypoints
[WebKit-https.git] / Source / JavaScriptCore / b3 / air / AirValidate.cpp
1 /*
2  * Copyright (C) 2015-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 "AirValidate.h"
28
29 #if ENABLE(B3_JIT)
30
31 #include "AirCode.h"
32 #include "AirInstInlines.h"
33 #include "B3Procedure.h"
34
35 namespace JSC { namespace B3 { namespace Air {
36
37 namespace {
38
39 class Validater {
40 public:
41     Validater(Code& code, const char* dumpBefore)
42         : m_code(code)
43         , m_dumpBefore(dumpBefore)
44     {
45     }
46
47 #define VALIDATE(condition, message) do {                               \
48         if (condition)                                                  \
49             break;                                                      \
50         fail(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #condition, toCString message); \
51     } while (false)
52     
53     void run()
54     {
55         HashSet<StackSlot*> validSlots;
56         HashSet<BasicBlock*> validBlocks;
57         HashSet<Special*> validSpecials;
58         
59         for (BasicBlock* block : m_code)
60             validBlocks.add(block);
61         for (StackSlot* slot : m_code.stackSlots())
62             validSlots.add(slot);
63         for (Special* special : m_code.specials())
64             validSpecials.add(special);
65
66         for (BasicBlock* block : m_code) {
67             // Blocks that are entrypoints must not have predecessors.
68             if (m_code.isEntrypoint(block))
69                 VALIDATE(!block->numPredecessors(), ("At entrypoint ", *block));
70             
71             for (unsigned instIndex = 0; instIndex < block->size(); ++instIndex) {
72                 Inst& inst = block->at(instIndex);
73                 for (Arg& arg : inst.args) {
74                     switch (arg.kind()) {
75                     case Arg::Stack:
76                         VALIDATE(validSlots.contains(arg.stackSlot()), ("At ", inst, " in ", *block));
77                         break;
78                     case Arg::Special:
79                         VALIDATE(validSpecials.contains(arg.special()), ("At ", inst, " in ", *block));
80                         break;
81                     default:
82                         break;
83                     }
84                 }
85                 VALIDATE(inst.isValidForm(), ("At ", inst, " in ", *block));
86                 if (instIndex == block->size() - 1)
87                     VALIDATE(inst.isTerminal(), ("At ", inst, " in ", *block));
88                 else
89                     VALIDATE(!inst.isTerminal(), ("At ", inst, " in ", *block));
90
91                 // forEachArg must return Arg&'s that point into the args array.
92                 inst.forEachArg(
93                     [&] (Arg& arg, Arg::Role, Arg::Type, Arg::Width) {
94                         VALIDATE(&arg >= &inst.args[0], ("At ", arg, " in ", inst, " in ", *block));
95                         VALIDATE(&arg <= &inst.args.last(), ("At ", arg, " in ", inst, " in ", *block));
96                     });
97                 
98                 switch (inst.opcode) {
99                 case EntrySwitch:
100                     VALIDATE(block->numSuccessors() == m_code.proc().numEntrypoints(), ("At ", inst, " in ", *block));
101                     break;
102                 default:
103                     break;
104                 }
105             }
106             for (BasicBlock* successor : block->successorBlocks())
107                 VALIDATE(validBlocks.contains(successor), ("In ", *block));
108         }
109     }
110
111 private:
112     NO_RETURN_DUE_TO_CRASH void fail(
113         const char* filename, int lineNumber, const char* function, const char* condition,
114         CString message)
115     {
116         CString failureMessage;
117         {
118             StringPrintStream out;
119             out.print("AIR VALIDATION FAILURE\n");
120             out.print("    ", condition, " (", filename, ":", lineNumber, ")\n");
121             out.print("    ", message, "\n");
122             out.print("    After ", m_code.lastPhaseName(), "\n");
123             failureMessage = out.toCString();
124         }
125
126         dataLog(failureMessage);
127         if (m_dumpBefore) {
128             dataLog("Before ", m_code.lastPhaseName(), ":\n");
129             dataLog(m_dumpBefore);
130         }
131         dataLog("At time of failure:\n");
132         dataLog(m_code);
133
134         dataLog(failureMessage);
135         WTFReportAssertionFailure(filename, lineNumber, function, condition);
136         CRASH();
137     }
138     
139     Code& m_code;
140     const char* m_dumpBefore;
141 };
142
143 } // anonymous namespace
144
145 void validate(Code& code, const char* dumpBefore)
146 {
147     Validater validater(code, dumpBefore);
148     validater.run();
149 }
150
151 } } } // namespace JSC::B3::Air
152
153 #endif // ENABLE(B3_JIT)
154