benchmarks/JetStream2/WSL/Rewriter.js (339 lines of code) (raw):

/* * Copyright (C) 2017 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ "use strict"; // FIXME: This should have sensible behavior when it encounters definitions that it cannot handle. Right // now we are hackishly preventing this by wrapping things in TypeRef. That's probably wrong. // https://bugs.webkit.org/show_bug.cgi?id=176208 class Rewriter { constructor() { this._mapping = new Map(); } _mapNode(oldItem, newItem) { this._mapping.set(oldItem, newItem); return newItem; } _getMapping(oldItem) { let result = this._mapping.get(oldItem); if (result) return result; return oldItem; } // We return identity for anything that is not inside a function/struct body. When processing // function bodies, we only recurse into them and never out of them - for example if there is a // function call to another function then we don't rewrite the other function. This is how we stop // that. visitFuncDef(node) { return node; } visitNativeFunc(node) { return node; } visitNativeFuncInstance(node) { return node; } visitNativeType(node) { return node; } visitTypeDef(node) { return node; } visitStructType(node) { return node; } visitConstexprTypeParameter(node) { return node; } visitProtocolDecl(node) { return node; } visitEnumType(node) { return node; } // This is almost wrong. We instantiate Func in Substitution in ProtocolDecl. Then, we end up // not rewriting type variables. I think that just works because not rewriting them there is OK. // Everywhere else, it's mandatory that we don't rewrite these because we always assume that // type variables are outside the scope of rewriting. visitTypeVariable(node) { return node; } visitProtocolFuncDecl(node) { let result = new ProtocolFuncDecl( node.origin, node.name, node.returnType.visit(this), node.typeParameters.map(parameter => parameter.visit(this)), node.parameters.map(parameter => parameter.visit(this)), node.isCast, node.shaderType); result.protocolDecl = node.protocolDecl; result.possibleOverloads = node.possibleOverloads; return result; } visitNativeTypeInstance(node) { return new NativeTypeInstance( node.type.visit(this), node.typeArguments.map(argument => argument.visit(this))); } visitFuncParameter(node) { let result = new FuncParameter(node.origin, node.name, node.type.visit(this)); this._mapNode(node, result); result.ePtr = node.ePtr; return result; } visitVariableDecl(node) { let result = new VariableDecl( node.origin, node.name, node.type.visit(this), Node.visit(node.initializer, this)); this._mapNode(node, result); result.ePtr = node.ePtr; return result; } visitBlock(node) { let result = new Block(node.origin); for (let statement of node.statements) result.add(statement.visit(this)); return result; } visitCommaExpression(node) { return new CommaExpression(node.origin, node.list.map(expression => { let result = expression.visit(this); if (!result) throw new Error("Null result from " + expression); return result; })); } visitProtocolRef(node) { return node; } visitTypeRef(node) { let result = new TypeRef(node.origin, node.name, node.typeArguments.map(typeArgument => typeArgument.visit(this))); result.type = Node.visit(node.type, this); return result; } visitField(node) { return new Field(node.origin, node.name, node.type.visit(this)); } visitEnumMember(node) { return new EnumMember(node.origin, node.name, node.value.visit(this)); } visitEnumLiteral(node) { let result = new EnumLiteral(node.origin, node.member); result.ePtr = node.ePtr; return result; } visitReferenceType(node) { return new node.constructor(node.origin, node.addressSpace, node.elementType.visit(this)); } visitPtrType(node) { return this.visitReferenceType(node); } visitArrayRefType(node) { return this.visitReferenceType(node); } visitArrayType(node) { return new ArrayType(node.origin, node.elementType.visit(this), node.numElements.visit(this)); } visitAssignment(node) { let result = new Assignment(node.origin, node.lhs.visit(this), node.rhs.visit(this)); result.type = Node.visit(node.type, this); return result; } visitReadModifyWriteExpression(node) { let result = new ReadModifyWriteExpression(node.origin, node.lValue.visit(this)); result.oldValueVar = node.oldValueVar.visit(this); result.newValueVar = node.newValueVar.visit(this); result.newValueExp = node.newValueExp.visit(this); result.resultExp = node.resultExp.visit(this); return result; } visitDereferenceExpression(node) { let result = new DereferenceExpression(node.origin, node.ptr.visit(this)); result.type = Node.visit(node.type, this); result.addressSpace = node.addressSpace; return result; } _handlePropertyAccessExpression(result, node) { result.possibleGetOverloads = node.possibleGetOverloads; result.possibleSetOverloads = node.possibleSetOverloads; result.possibleAndOverloads = node.possibleAndOverloads; result.baseType = Node.visit(node.baseType, this); result.callForGet = Node.visit(node.callForGet, this); result.resultTypeForGet = Node.visit(node.resultTypeForGet, this); result.callForAnd = Node.visit(node.callForAnd, this); result.resultTypeForAnd = Node.visit(node.resultTypeForAnd, this); result.callForSet = Node.visit(node.callForSet, this); result.errorForSet = node.errorForSet; result.updateCalls(); } visitDotExpression(node) { let result = new DotExpression(node.origin, node.struct.visit(this), node.fieldName); this._handlePropertyAccessExpression(result, node); return result; } visitIndexExpression(node) { let result = new IndexExpression(node.origin, node.array.visit(this), node.index.visit(this)); this._handlePropertyAccessExpression(result, node); return result; } visitMakePtrExpression(node) { let result = new MakePtrExpression(node.origin, node.lValue.visit(this)); result.ePtr = node.ePtr; return result; } visitMakeArrayRefExpression(node) { let result = new MakeArrayRefExpression(node.origin, node.lValue.visit(this)); if (node.numElements) result.numElements = node.numElements.visit(this); result.ePtr = node.ePtr; return result; } visitConvertPtrToArrayRefExpression(node) { let result = new ConvertPtrToArrayRefExpression(node.origin, node.lValue.visit(this)); result.ePtr = node.ePtr; return result; } visitVariableRef(node) { let result = new VariableRef(node.origin, node.name); result.variable = this._getMapping(node.variable); return result; } visitReturn(node) { return new Return(node.origin, Node.visit(node.value, this)); } visitContinue(node) { return new Continue(node.origin); } visitBreak(node) { return new Break(node.origin); } visitTrapStatement(node) { return new TrapStatement(node.origin); } visitGenericLiteral(node) { // FIXME: This doesn't seem right. let result = new IntLiteral(node.origin, node.value); result.type = node.type.visit(this); result.ePtr = node.ePtr; return result; } visitGenericLiteralType(node) { let result = new node.constructor(node.origin, node.value); result.type = Node.visit(node.type, this); result.preferredType = node.preferredType.visit(this); return result; } visitBoolLiteral(node) { return node; } visitNullLiteral(node) { let result = new NullLiteral(node.origin); result.type = node.type.visit(this); result.ePtr = node.ePtr; return result; } visitNullType(node) { let result = new NullType(node.origin); result.type = Node.visit(node.type, this); return result; } processDerivedCallData(node, result) { let handleTypeArguments = actualTypeArguments => { if (actualTypeArguments) return actualTypeArguments.map(actualTypeArgument => actualTypeArgument.visit(this)); else return null; } result.actualTypeArguments = handleTypeArguments(node.actualTypeArguments); result.instantiatedActualTypeArguments = handleTypeArguments(node.instantiatedActualTypeArguments); let argumentTypes = node.argumentTypes; if (argumentTypes) result.argumentTypes = argumentTypes.map(argumentType => argumentType.visit(this)); result.func = node.func; result.nativeFuncInstance = node.nativeFuncInstance; result.possibleOverloads = node.possibleOverloads; if (node.isCast) result.setCastData(node.returnType.visit(this)); result.resultType = Node.visit(node.resultType, this); result.resultEPtr = node.resultEPtr; return result; } visitCallExpression(node) { let result = new CallExpression( node.origin, node.name, node.typeArguments.map(typeArgument => typeArgument.visit(this)), node.argumentList.map(argument => Node.visit(argument, this))); return this.processDerivedCallData(node, result); } visitFunctionLikeBlock(node) { let result = new FunctionLikeBlock( node.origin, Node.visit(node.returnType, this), node.argumentList.map(argument => argument.visit(this)), node.parameters.map(parameter => parameter.visit(this)), node.body.visit(this)); result.returnEPtr = node.returnEPtr; return result; } visitLogicalNot(node) { let result = new LogicalNot(node.origin, node.operand.visit(this)); result.ePtr = node.ePtr; return result; } visitLogicalExpression(node) { let result = new LogicalExpression(node.origin, node.text, node.left.visit(this), node.right.visit(this)); result.ePtr = node.ePtr; return result; } visitIfStatement(node) { return new IfStatement(node.origin, node.conditional.visit(this), node.body.visit(this), Node.visit(node.elseBody, this)); } visitWhileLoop(node) { return new WhileLoop(node.origin, node.conditional.visit(this), node.body.visit(this)); } visitDoWhileLoop(node) { return new DoWhileLoop(node.origin, node.body.visit(this), node.conditional.visit(this)); } visitForLoop(node) { return new ForLoop(node.origin, Node.visit(node.initialization, this), Node.visit(node.condition, this), Node.visit(node.increment, this), node.body.visit(this)); } visitSwitchStatement(node) { let result = new SwitchStatement(node.origin, Node.visit(node.value, this)); for (let switchCase of node.switchCases) result.add(switchCase.visit(this)); result.type = Node.visit(node.type, this); return result; } visitSwitchCase(node) { return new SwitchCase(node.origin, Node.visit(node.value, this), node.body.visit(this)); } visitAnonymousVariable(node) { let result = new AnonymousVariable(node.origin, node.type.visit(this)); result._index = node._index; this._mapNode(node, result); result.ePtr = node.ePtr; return result; } visitIdentityExpression(node) { return new IdentityExpression(node.target.visit(this)); } }