Make JetStream 2
[WebKit-https.git] / PerformanceTests / JetStream2 / WSL / FuncInstantiator.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 class FuncInstantiator {
28     constructor(program)
29     {
30         this._program = program;
31         this._instances = new Map();
32     }
33     
34     // Returns a Func object that uniquely identifies a particular system of type arguments. You must
35     // intantiate things with concrete types, because this code casually assumes this. Note that this
36     // will return a different func from `func` no matter what. This ensures that we can use the
37     // returned func for rewrites that instantiate types without destroying our ability to do overload
38     // resolutions on the original Program.
39     getUnique(func, typeArguments)
40     {
41         class FindTypeVariable extends Visitor {
42             visitTypeRef(node)
43             {
44                 for (let typeArgument of node.typeArguments)
45                     typeArgument.visit(this);
46             }
47             
48             visitTypeVariable(node) {
49                 throw new Error("Unexpected type variable: " + node + " when instantiating " + func + " with arguments " + typeArguments);
50             }
51         }
52         for (let typeArgument of typeArguments)
53             typeArgument.visit(new FindTypeVariable());
54         
55         let instances = this._instances.get(func);
56         if (!instances)
57             this._instances.set(func, instances = []);
58         
59         for (let instance of instances) {
60             let ok = true;
61             for (let i = instance.typeArguments.length; i--;) {
62                 if (!instance.typeArguments[i].equals(typeArguments[i])) {
63                     ok = false;
64                     break;
65                 }
66             }
67             if (!ok)
68                 continue;
69             return instance.func;
70         }
71         
72         let thisInstantiator = this;
73         
74         class InstantiationSubstitution extends Substitution {
75             visitCallExpression(node)
76             {
77                 let result = super.visitCallExpression(node);
78                 
79                 // We may have to re-resolve the function call, if it was a call to a protocol
80                 // signature.
81                 if (result.func instanceof ProtocolFuncDecl) {
82                     let overload = resolveOverloadImpl(result.possibleOverloads, result.typeArguments, result.argumentTypes, result.returnType);
83                     if (!overload.func)
84                         throw new Error("Could not resolve protocol signature function call during instantiation: " + result.func + (overload.failures.length ? "; tried:\n" + overload.failures.join("\n") : ""));
85                     result.resolveToOverload(overload);
86                 }
87                 
88                 if (result.func.isNative)
89                     result.nativeFuncInstance = thisInstantiator.getUnique(result.func, result.actualTypeArguments);
90                 
91                 return result;
92             }
93         }
94         
95         let substitution = new InstantiationSubstitution(func.typeParameters, typeArguments);
96
97         class InstantiationInstantiateImmediates extends InstantiateImmediates {
98             visitCallExpression(node)
99             {
100                 // We need to preserve certain things that would have instantiated, but that we cannot
101                 // instantiate without breaking chain-instantiations (generic function calls generic
102                 // function so therefore the instantiated generic function must still have the original
103                 // (uninstantiated) types to instantiate the generic function that it calls).
104                 let result = new CallExpression(
105                     node.origin, node.name, node.typeArguments,
106                     node.argumentList.map(argument => Node.visit(argument, this)));
107                 result = this.processDerivedCallData(node, result);
108                 
109                 result.argumentTypes = Array.from(node.argumentTypes);
110                 if (node.isCast)
111                     result.setCastData(node.returnType);
112                 result.actualTypeArguments = Array.from(node.actualTypeArguments);
113                 
114                 return result;
115             }
116         }
117
118         let instantiateImmediates = new InstantiationInstantiateImmediates();
119         
120         class Instantiate {
121             visitFuncDef(func)
122             {
123                 let returnType = func.returnType.visit(substitution);
124                 returnType = returnType.visit(instantiateImmediates);
125                 let parameters = func.parameters.map(parameter => parameter.visit(substitution));
126                 parameters = parameters.map(parameter => parameter.visit(instantiateImmediates));
127                 let body = func.body.visit(substitution);
128                 body = body.visit(instantiateImmediates);
129                 return new FuncDef(
130                     func.origin, func.name, returnType, [], parameters, body, func.isCast,
131                     func.shaderType);
132             }
133             
134             visitNativeFunc(func)
135             {
136                 return new NativeFuncInstance(
137                     func,
138                     func.returnType.visit(substitution).visit(instantiateImmediates),
139                     func.parameters.map(parameter => parameter.visit(substitution).visit(instantiateImmediates)),
140                     func.isCast,
141                     func.shaderType,
142                     func.instantiateImplementation(substitution));
143             }
144         }
145         let resultingFunc = func.visit(new Instantiate());
146         resultingFunc.uninstantiatedReturnType = func.returnType.visit(substitution);
147         let instance = {func: resultingFunc, typeArguments};
148         instances.push(instance);
149         return resultingFunc;
150     }
151 }
152