Add a WASM function validator.
[WebKit-https.git] / 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
28 from generateWasm import *
29 import optparse
30 import sys
31
32 parser = optparse.OptionParser(usage="usage: %prog <wasm.json> <WasmOps.h>")
33 (options, args) = parser.parse_args(sys.argv[0:])
34 if len(args) != 3:
35     parser.error(parser.usage)
36
37 wasm = Wasm(args[0], args[1])
38 opcodes = wasm.opcodes
39 wasmValidateInlinesHFile = open(args[2], "w")
40
41
42 def 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
56 def toCpp(name):
57     return wasm.toCpp(name)
58
59
60 def 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
74 def 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
93 def 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
107 def 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
125 unaryCases = "".join([op for op in wasm.opcodeIterator(isUnary, unaryMacro)])
126 binaryCases = "".join([op for op in wasm.opcodeIterator(isBinary, binaryMacro)])
127 loadCases = "".join([op for op in wasm.opcodeIterator(lambda op: op["category"] == "memory" and len(op["return"]) == 1, loadMacro)])
128 storeCases = "".join([op for op in wasm.opcodeIterator(lambda op: op["category"] == "memory" and len(op["return"]) == 0, storeMacro)])
129
130 contents = 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
137 namespace JSC { namespace Wasm {
138
139 bool Validate::unaryOp(UnaryOpType op, ExpressionType value, ExpressionType& result)
140 {
141     switch (op) {
142 """ + unaryCases + """
143     }
144 }
145
146 bool Validate::binaryOp(BinaryOpType op, ExpressionType left, ExpressionType right, ExpressionType& result)
147 {
148     switch (op) {
149 """ + binaryCases + """
150     }
151 }
152
153 bool Validate::load(LoadOpType op, ExpressionType pointer, ExpressionType& result, uint32_t)
154 {
155     switch (op) {
156 """ + loadCases + """
157     }
158 }
159
160 bool 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
173 wasmValidateInlinesHFile.write(contents)
174 wasmValidateInlinesHFile.close()