Make JetStream 2
[WebKit-https.git] / PerformanceTests / JetStream2 / WSL / Rewriter.js
1 /*
2  * Copyright (C) 2017 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 "use strict";
26
27 // FIXME: This should have sensible behavior when it encounters definitions that it cannot handle. Right
28 // now we are hackishly preventing this by wrapping things in TypeRef. That's probably wrong.
29 // https://bugs.webkit.org/show_bug.cgi?id=176208
30 class Rewriter {
31     constructor()
32     {
33         this._mapping = new Map();
34     }
35     
36     _mapNode(oldItem, newItem)
37     {
38         this._mapping.set(oldItem, newItem);
39         return newItem;
40     }
41     
42     _getMapping(oldItem)
43     {
44         let result = this._mapping.get(oldItem);
45         if (result)
46             return result;
47         return oldItem;
48     }
49     
50     // We return identity for anything that is not inside a function/struct body. When processing
51     // function bodies, we only recurse into them and never out of them - for example if there is a
52     // function call to another function then we don't rewrite the other function. This is how we stop
53     // that.
54     visitFuncDef(node) { return node; }
55     visitNativeFunc(node) { return node; }
56     visitNativeFuncInstance(node) { return node; }
57     visitNativeType(node) { return node; }
58     visitTypeDef(node) { return node; }
59     visitStructType(node) { return node; }
60     visitConstexprTypeParameter(node) { return node; }
61     visitProtocolDecl(node) { return node; }
62     visitEnumType(node) { return node; }
63
64     // This is almost wrong. We instantiate Func in Substitution in ProtocolDecl. Then, we end up
65     // not rewriting type variables. I think that just works because not rewriting them there is OK.
66     // Everywhere else, it's mandatory that we don't rewrite these because we always assume that
67     // type variables are outside the scope of rewriting.
68     visitTypeVariable(node) { return node; }
69
70     visitProtocolFuncDecl(node)
71     {
72         let result = new ProtocolFuncDecl(
73             node.origin, node.name,
74             node.returnType.visit(this),
75             node.typeParameters.map(parameter => parameter.visit(this)),
76             node.parameters.map(parameter => parameter.visit(this)),
77             node.isCast,
78             node.shaderType);
79         result.protocolDecl = node.protocolDecl;
80         result.possibleOverloads = node.possibleOverloads;
81         return result;
82     }
83     
84     visitNativeTypeInstance(node)
85     {
86         return new NativeTypeInstance(
87             node.type.visit(this),
88             node.typeArguments.map(argument => argument.visit(this)));
89     }
90     
91     visitFuncParameter(node)
92     {
93         let result = new FuncParameter(node.origin, node.name, node.type.visit(this));
94         this._mapNode(node, result);
95         result.ePtr = node.ePtr;
96         return result;
97     }
98     
99     visitVariableDecl(node)
100     {
101         let result = new VariableDecl(
102             node.origin, node.name,
103             node.type.visit(this),
104             Node.visit(node.initializer, this));
105         this._mapNode(node, result);
106         result.ePtr = node.ePtr;
107         return result;
108     }
109     
110     visitBlock(node)
111     {
112         let result = new Block(node.origin);
113         for (let statement of node.statements)
114             result.add(statement.visit(this));
115         return result;
116     }
117     
118     visitCommaExpression(node)
119     {
120         return new CommaExpression(node.origin, node.list.map(expression => {
121             let result = expression.visit(this);
122             if (!result)
123                 throw new Error("Null result from " + expression);
124             return result;
125         }));
126     }
127     
128     visitProtocolRef(node)
129     {
130         return node;
131     }
132     
133     visitTypeRef(node)
134     {
135         let result = new TypeRef(node.origin, node.name, node.typeArguments.map(typeArgument => typeArgument.visit(this)));
136         result.type = Node.visit(node.type, this);
137         return result;
138     }
139     
140     visitField(node)
141     {
142         return new Field(node.origin, node.name, node.type.visit(this));
143     }
144     
145     visitEnumMember(node)
146     {
147         return new EnumMember(node.origin, node.name, node.value.visit(this));
148     }
149     
150     visitEnumLiteral(node)
151     {
152         let result = new EnumLiteral(node.origin, node.member);
153         result.ePtr = node.ePtr;
154         return result;
155     }
156     
157     visitReferenceType(node)
158     {
159         return new node.constructor(node.origin, node.addressSpace, node.elementType.visit(this));
160     }
161     
162     visitPtrType(node)
163     {
164         return this.visitReferenceType(node);
165     }
166     
167     visitArrayRefType(node)
168     {
169         return this.visitReferenceType(node);
170     }
171     
172     visitArrayType(node)
173     {
174         return new ArrayType(node.origin, node.elementType.visit(this), node.numElements.visit(this));
175     }
176     
177     visitAssignment(node)
178     {
179         let result = new Assignment(node.origin, node.lhs.visit(this), node.rhs.visit(this));
180         result.type = Node.visit(node.type, this);
181         return result;
182     }
183     
184     visitReadModifyWriteExpression(node)
185     {
186         let result = new ReadModifyWriteExpression(node.origin, node.lValue.visit(this));
187         result.oldValueVar = node.oldValueVar.visit(this);
188         result.newValueVar = node.newValueVar.visit(this);
189         result.newValueExp = node.newValueExp.visit(this);
190         result.resultExp = node.resultExp.visit(this);
191         return result;
192     }
193     
194     visitDereferenceExpression(node)
195     {
196         let result = new DereferenceExpression(node.origin, node.ptr.visit(this));
197         result.type = Node.visit(node.type, this);
198         result.addressSpace = node.addressSpace;
199         return result;
200     }
201     
202     _handlePropertyAccessExpression(result, node)
203     {
204         result.possibleGetOverloads = node.possibleGetOverloads;
205         result.possibleSetOverloads = node.possibleSetOverloads;
206         result.possibleAndOverloads = node.possibleAndOverloads;
207         result.baseType = Node.visit(node.baseType, this);
208         result.callForGet = Node.visit(node.callForGet, this);
209         result.resultTypeForGet = Node.visit(node.resultTypeForGet, this);
210         result.callForAnd = Node.visit(node.callForAnd, this);
211         result.resultTypeForAnd = Node.visit(node.resultTypeForAnd, this);
212         result.callForSet = Node.visit(node.callForSet, this);
213         result.errorForSet = node.errorForSet;
214         result.updateCalls();
215     }
216     
217     visitDotExpression(node)
218     {
219         let result = new DotExpression(node.origin, node.struct.visit(this), node.fieldName);
220         this._handlePropertyAccessExpression(result, node);
221         return result;
222     }
223     
224     visitIndexExpression(node)
225     {
226         let result = new IndexExpression(node.origin, node.array.visit(this), node.index.visit(this));
227         this._handlePropertyAccessExpression(result, node);
228         return result;
229     }
230     
231     visitMakePtrExpression(node)
232     {
233         let result = new MakePtrExpression(node.origin, node.lValue.visit(this));
234         result.ePtr = node.ePtr;
235         return result;
236     }
237     
238     visitMakeArrayRefExpression(node)
239     {
240         let result = new MakeArrayRefExpression(node.origin, node.lValue.visit(this));
241         if (node.numElements)
242             result.numElements = node.numElements.visit(this);
243         result.ePtr = node.ePtr;
244         return result;
245     }
246     
247     visitConvertPtrToArrayRefExpression(node)
248     {
249         let result = new ConvertPtrToArrayRefExpression(node.origin, node.lValue.visit(this));
250         result.ePtr = node.ePtr;
251         return result;
252     }
253     
254     visitVariableRef(node)
255     {
256         let result = new VariableRef(node.origin, node.name);
257         result.variable = this._getMapping(node.variable);
258         return result;
259     }
260     
261     visitReturn(node)
262     {
263         return new Return(node.origin, Node.visit(node.value, this));
264     }
265     
266     visitContinue(node)
267     {
268         return new Continue(node.origin);
269     }
270     
271     visitBreak(node)
272     {
273         return new Break(node.origin);
274     }
275
276     visitTrapStatement(node)
277     {
278         return new TrapStatement(node.origin);
279     }
280     
281     visitGenericLiteral(node)
282     {
283         // FIXME: This doesn't seem right.
284         let result = new IntLiteral(node.origin, node.value);
285         result.type = node.type.visit(this);
286         result.ePtr = node.ePtr;
287         return result;
288     }
289     
290     visitGenericLiteralType(node)
291     {
292         let result = new node.constructor(node.origin, node.value);
293         result.type = Node.visit(node.type, this);
294         result.preferredType = node.preferredType.visit(this);
295         return result;
296     }
297
298     visitBoolLiteral(node)
299     {
300         return node;
301     }
302     
303     visitNullLiteral(node)
304     {
305         let result = new NullLiteral(node.origin);
306         result.type = node.type.visit(this);
307         result.ePtr = node.ePtr;
308         return result;
309     }
310     
311     visitNullType(node)
312     {
313         let result = new NullType(node.origin);
314         result.type = Node.visit(node.type, this);
315         return result;
316     }
317
318     processDerivedCallData(node, result)
319     {
320         let handleTypeArguments = actualTypeArguments => {
321             if (actualTypeArguments)
322                 return actualTypeArguments.map(actualTypeArgument => actualTypeArgument.visit(this));
323             else
324                 return null;
325         }
326         result.actualTypeArguments = handleTypeArguments(node.actualTypeArguments);
327         result.instantiatedActualTypeArguments = handleTypeArguments(node.instantiatedActualTypeArguments);
328         let argumentTypes = node.argumentTypes;
329         if (argumentTypes)
330             result.argumentTypes = argumentTypes.map(argumentType => argumentType.visit(this));
331         result.func = node.func;
332         result.nativeFuncInstance = node.nativeFuncInstance;
333         result.possibleOverloads = node.possibleOverloads;
334         if (node.isCast)
335             result.setCastData(node.returnType.visit(this));
336         result.resultType = Node.visit(node.resultType, this);
337         result.resultEPtr = node.resultEPtr;
338         return result;
339     }
340
341     visitCallExpression(node)
342     {
343         let result = new CallExpression(
344             node.origin, node.name,
345             node.typeArguments.map(typeArgument => typeArgument.visit(this)),
346             node.argumentList.map(argument => Node.visit(argument, this)));
347         return this.processDerivedCallData(node, result);
348     }
349     
350     visitFunctionLikeBlock(node)
351     {
352         let result = new FunctionLikeBlock(
353             node.origin,
354             Node.visit(node.returnType, this),
355             node.argumentList.map(argument => argument.visit(this)),
356             node.parameters.map(parameter => parameter.visit(this)),
357             node.body.visit(this));
358         result.returnEPtr = node.returnEPtr;
359         return result;
360     }
361     
362     visitLogicalNot(node)
363     {
364         let result = new LogicalNot(node.origin, node.operand.visit(this));
365         result.ePtr = node.ePtr;
366         return result;
367     }
368     
369     visitLogicalExpression(node)
370     {
371         let result = new LogicalExpression(node.origin, node.text, node.left.visit(this), node.right.visit(this));
372         result.ePtr = node.ePtr;
373         return result;
374     }
375
376     visitIfStatement(node)
377     {
378         return new IfStatement(node.origin, node.conditional.visit(this), node.body.visit(this), Node.visit(node.elseBody, this));
379     }
380
381     visitWhileLoop(node)
382     {
383         return new WhileLoop(node.origin, node.conditional.visit(this), node.body.visit(this));
384     }
385
386     visitDoWhileLoop(node)
387     {
388         return new DoWhileLoop(node.origin, node.body.visit(this), node.conditional.visit(this));
389     }
390
391     visitForLoop(node)
392     {
393         return new ForLoop(node.origin,
394             Node.visit(node.initialization, this),
395             Node.visit(node.condition, this),
396             Node.visit(node.increment, this),
397             node.body.visit(this));
398     }
399     
400     visitSwitchStatement(node)
401     {
402         let result = new SwitchStatement(node.origin, Node.visit(node.value, this));
403         for (let switchCase of node.switchCases)
404             result.add(switchCase.visit(this));
405         result.type = Node.visit(node.type, this);
406         return result;
407     }
408     
409     visitSwitchCase(node)
410     {
411         return new SwitchCase(node.origin, Node.visit(node.value, this), node.body.visit(this));
412     }
413     
414     visitAnonymousVariable(node)
415     {
416         let result = new AnonymousVariable(node.origin, node.type.visit(this));
417         result._index = node._index;
418         this._mapNode(node, result);
419         result.ePtr = node.ePtr;
420         return result;
421     }
422     
423     visitIdentityExpression(node)
424     {
425         return new IdentityExpression(node.target.visit(this));
426     }
427 }
428