com.oracle.truffle.llvm.parser.LlvmNodeFactory.java Source code

Java tutorial

Introduction

Here is the source code for com.oracle.truffle.llvm.parser.LlvmNodeFactory.java

Source

/*
 * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package com.oracle.truffle.llvm.parser;

import java.math.*;
import java.util.*;

import org.antlr.v4.runtime.Token;

import com.oracle.truffle.api.frame.*;
import com.oracle.truffle.api.nodes.*;
import com.oracle.truffle.api.source.*;
import com.oracle.truffle.llvm.runtime.*;
import com.oracle.truffle.llvm.access.*;
import com.oracle.truffle.llvm.call.*;
import com.oracle.truffle.llvm.node.expression.*;
import com.oracle.truffle.llvm.nodes.*;
import com.oracle.truffle.llvm.nodes.controlflow.*;
import com.oracle.truffle.llvm.nodes.local.*;
import com.oracle.truffle.llvm.runtime.*;
import com.oracle.truffle.llvm.types.*;
import com.oracle.truffle.llvm.types.LlvmStringLiteralNode;

/**
 * Helper class used by the Llvm {@link LlvmParser} to create nodes. The code is factored out of the
 * automatically generated parser to keep the attributed grammar of Llvm small.
 */
public class LlvmNodeFactory {

    /**
     * Local variable names that are visible in the current block. Variables are not visible outside
     * of their defining block, to prevent the usage of undefined variables. Because of that, we can
     * decide during parsing if a name references a local variable or is a function name.
     */
    static class LexicalScope {
        protected final LexicalScope outer;
        protected final Map<String, FrameSlot> locals;
        protected Map<String, LlvmBlockNode> blockMap;

        public LexicalScope(LexicalScope outer) {
            this.outer = outer;
            this.locals = new HashMap<>();
            this.blockMap = new HashMap<>();
            if (outer != null) {
                locals.putAll(outer.locals);
            }
        }
    }

    /* State while parsing a source unit. */
    private final LlvmContext context;
    private final Source source;

    /* State while parsing a function. */
    private int functionStartPos;
    private String functionName;
    private int functionBodyStartPos; // includes parameter list
    private int parameterCount;
    private FrameDescriptor frameDescriptor;
    private List<LlvmStatementNode> methodNodes;

    /* State while parsing a block. */
    private LexicalScope lexicalScope;

    // basic block definition
    private String basicBlockName;
    private int basicBlockStartPos;
    private int basicBlockEndPos;

    public LlvmNodeFactory(LlvmContext context, Source source) {
        this.context = context;
        this.source = source;
    }

    public void startFunction(Token nameToken, int bodyStartPos) {
        assert functionStartPos == 0;
        assert functionName == null;
        assert functionBodyStartPos == 0;
        assert parameterCount == 0;
        assert frameDescriptor == null;
        assert lexicalScope == null;

        functionStartPos = nameToken.getStartIndex();
        functionName = nameToken.getText();
        functionBodyStartPos = bodyStartPos;
        frameDescriptor = new FrameDescriptor();
        methodNodes = new ArrayList<>();
        startBlock();
    }

    public void addFormalParameter(Token nameToken) {
        List<String> list = new ArrayList();
        /*
         * Method parameters are assigned to local variables at the beginning of the method. This
         * ensures that accesses to parameters are specialized the same way as local variables are
         * specialized.
         */
        final SourceSection src = srcFromToken(nameToken);
        final LlvmReadArgumentNode readArg = new LlvmReadArgumentNode(src, parameterCount);
        // ?
        methodNodes.add(createAssignment(nameToken, readArg));
        parameterCount++;
    }

    public void finishFunction(LlvmStatementNode bodyNode) {
        methodNodes.add(bodyNode);
        final int bodyEndPos = bodyNode.getSourceSection().getCharEndIndex();
        final SourceSection functionSrc = source.createSection(functionName, functionStartPos,
                bodyEndPos - functionStartPos);
        final LlvmStatementNode methodBlock = finishBlock(methodNodes, functionBodyStartPos,
                bodyEndPos - functionBodyStartPos);
        assert lexicalScope == null : "Wrong scoping of blocks in parser";

        final LlvmFunctionBodyNode functionBodyNode = new LlvmFunctionBodyNode(functionSrc, methodBlock);
        final LlvmRootNode rootNode = new LlvmRootNode(this.context, frameDescriptor, functionBodyNode,
                functionName);
        rootNode.assignSourceSection(functionSrc);

        context.getFunctionRegistry().register(functionName, rootNode);

        functionStartPos = 0;
        functionName = null;
        functionBodyStartPos = 0;
        parameterCount = 0;
        frameDescriptor = null;
        lexicalScope = null;
    }

    public void startBlock() {
        lexicalScope = new LexicalScope(lexicalScope);
    }

    public LlvmStatementNode finishBlock(List<LlvmStatementNode> bodyNodes, int startPos, int length) {
        lexicalScope = lexicalScope.outer;

        List<LlvmStatementNode> flattenedNodes = new ArrayList<>(bodyNodes.size());
        flattenBlocks(bodyNodes, flattenedNodes);

        final SourceSection src = source.createSection("block", startPos, length);
        return new LlvmBlockNode(src, flattenedNodes.toArray(new LlvmStatementNode[flattenedNodes.size()]));
    }

    private void flattenBlocks(Iterable<? extends Node> bodyNodes, List<LlvmStatementNode> flattenedNodes) {
        for (Node n : bodyNodes) {
            if (n instanceof LlvmBlockNode) {
                flattenBlocks(n.getChildren(), flattenedNodes);
            } else {
                flattenedNodes.add((LlvmStatementNode) n);
            }
        }
    }

    // /**
    // * Returns an {@link LlvmBreakNode} for the given token.
    // *
    // * @param breakToken The token containing the break node's info.
    // * @return A LlvmBreakNode for the given token.
    // */
    // public LlvmStatementNode createBreak(Token breakToken) {
    // final LlvmBreakNode breakNode = new LlvmBreakNode(srcFromToken(breakToken));
    // return breakNode;
    // }
    //
    // /**
    // * Returns an {@link LlvmContinueNode} for the given token.
    // *
    // * @param continueToken The token containing the continue node's info.
    // * @return A LlvmContinueNode built using the given token.
    // */
    // public LlvmStatementNode createContinue(Token continueToken) {
    // final LlvmContinueNode continueNode = new LlvmContinueNode(srcFromToken(continueToken));
    // return continueNode;
    // }
    //
    // /**
    // * Returns an {@link LlvmWhileNode} for the given parameters.
    // *
    // * @param whileToken The token containing the while node's info
    // * @param conditionNode The conditional node for this while loop
    // * @param bodyNode The body of the while loop
    // * @return A LlvmWhileNode built using the given parameters.
    // */
    public LlvmStatementNode createWhile(Token whileToken, LlvmExpressionNode conditionNode,
            Map<String, LlvmStatementNode> bodyNode, Token nameToken) {
        final int start = whileToken.getStartIndex();
        List<LlvmStatementNode> whileList = new ArrayList();
        if (bodyNode.values() instanceof List) {
            whileList = (List) bodyNode.values();
        } else {
            whileList = new ArrayList(bodyNode.values());
        }
        List<LlvmStatementNode> whileBody = new ArrayList();
        int length = 0;
        while (length < whileList.size()) {
            if (whileList.get(length) != null)
                whileBody.add(whileList.get(length));
            length++;
        }
        final int end = whileBody.get(whileBody.size() - 1).getSourceSection().getCharEndIndex();
        whileBody.add(lexicalScope.blockMap.get(nameToken.getText()));
        LlvmStatementNode whileReturnNode = this.createBasicBlockNode(nameToken, whileBody, start, end - start);
        final LlvmWhileNode whileNode = new LlvmWhileNode(
                source.createSection(whileToken.getText(), start, end - start), conditionNode, whileReturnNode);
        return whileNode;
        // final int start = whileToken.getStartIndex();
        // final int end = bodyNode.getSourceSection().getCharEndIndex();
        // List<LlvmStatementNode> whileBody = new ArrayList();
        // System.out.println(nameToken.getText());
        // whileBody.add(bodyNode);
        // whileBody.add(lexicalScope.blockMap.get(nameToken.getText()));
        //
        // bodyNode = this.createBasicBlockNode(nameToken, whileBody, start, end - start);
        // final LlvmWhileNode whileNode = new LlvmWhileNode(source.createSection(whileToken.getText(),
        // start, end - start), conditionNode, bodyNode);
        // return whileNode;
    }

    //
    // /**
    // * Returns an {@link LlvmIfNode} for the given parameters.
    // *
    // * @param ifToken The token containing the if node's info
    // * @param conditionNode The condition node of this if statement
    // * @param thenPartNode The then part of the if
    // * @param elsePartNode The else part of the if
    // * @return An LlvmIfNode for the given parameters.
    // */
    public LlvmStatementNode createIf(Token ifToken, String str, LlvmExpressionNode conditionNode,
            LlvmStatementNode thenPartNode, LlvmStatementNode elsePartNode) {
        final int start = ifToken.getStartIndex();
        final int end = elsePartNode == null ? thenPartNode.getSourceSection().getCharEndIndex()
                : elsePartNode.getSourceSection().getCharEndIndex();
        final SourceSection src = source.createSection(str, start, end - start);
        final LlvmIfNode ifNode = new LlvmIfNode(source.createSection(ifToken.getText(), start, end - start),
                conditionNode, thenPartNode, elsePartNode);
        return ifNode;
    }

    // /**
    // * Returns an {@link LlvmReturnNode} for the given parameters.
    // *
    // * @param t The token containing the return node's info
    // * @param valueNode The value of the return
    // * @return An LlvmReturnNode for the given parameters.
    // */
    public LlvmStatementNode createReturn(Token t, LlvmExpressionNode valueNode) {
        final int start = t.getStartIndex();
        final int length = valueNode == null ? t.getText().length()
                : valueNode.getSourceSection().getCharEndIndex() - start;
        final LlvmReturnNode returnNode = new LlvmReturnNode(source.createSection(t.getText(), start, length),
                valueNode);
        // final LlvmStatementNode returnNode = null;
        return returnNode;
    }

    /**
     * Returns the corresponding subclass of {@link LlvmExpressionNode} for binary expressions.
     * </br>These nodes are currently not instrumented.
     *
     * @param opToken The operator of the binary expression
     * @param leftNode The left node of the expression
     * @param rightNode The right node of the expression
     * @return A subclass of LlvmExpressionNode using the given parameters based on the given
     *         opToken.
     */
    public LlvmExpressionNode createBinary(Token opToken, LlvmExpressionNode leftNode,
            LlvmExpressionNode rightNode) {
        int start = leftNode.getSourceSection().getCharIndex();
        int length = rightNode.getSourceSection().getCharEndIndex() - start;
        final SourceSection src = source.createSection(opToken.getText(), start, length);
        switch (opToken.getText()) {
        case "add":
        case "fadd":
            return LlvmAddNodeGen.create(src, leftNode, rightNode);
        case "mul":
        case "fmul":
            return LlvmMulNodeGen.create(src, leftNode, rightNode);
        case "udiv":
        case "sdiv":
        case "fdiv":
            return LlvmDivNodeGen.create(src, leftNode, rightNode);
        case "sub":
        case "fsub":
            return LlvmSubNodeGen.create(src, leftNode, rightNode);
        case "urem":
        case "srem":
            return LlvmRemNodeGen.create(src, leftNode, rightNode);
        default:
            throw new RuntimeException("unexpected operation: " + opToken.getText());
        }
    }

    public LlvmExpressionNode createArrayCopyBinary(Token opToken, LlvmExpressionNode leftNode,
            LlvmExpressionNode rightNode) {
        int start = leftNode.getSourceSection().getCharIndex();
        int length = leftNode.getSourceSection().getCharEndIndex() + 2 - start;
        final SourceSection src = source.createSection(opToken.getText(), start, length);
        return LlvmArrayPointNodeGen.create(src, leftNode, rightNode);
    }

    public LlvmExpressionNode createCompBinary(Token opToken, String cmpType, LlvmExpressionNode leftNode,
            LlvmExpressionNode rightNode) {
        int start = leftNode.getSourceSection().getCharIndex();
        int length = rightNode.getSourceSection().getCharEndIndex() - start;
        final SourceSection src = source.createSection(opToken.getText(), start, length);
        return LlvmCompNodeGen.create(src, cmpType, leftNode, rightNode);
    }

    /**
     * Returns an {@link LlvmInvokeNode} for the given parameters.
     *
     * @param functionNode The function being called
     * @param parameterNodes The parameters of the function call
     * @param finalToken A token used to determine the end of the sourceSelection for this call
     * @return An LlvmInvokeNode for the given parameters.
     */
    public LlvmExpressionNode createCall(LlvmExpressionNode functionNode, List<LlvmExpressionNode> parameterNodes,
            Token finalToken) {
        final int startPos = functionNode.getSourceSection().getCharIndex();
        final int endPos = finalToken.getStartIndex() + finalToken.getText().length();
        final SourceSection src = source.createSection(functionNode.getSourceSection().getIdentifier(), startPos,
                endPos - startPos);
        return LlvmInvokeNode.create(src, functionNode,
                parameterNodes.toArray(new LlvmExpressionNode[parameterNodes.size()]));
    }

    /**
     * Returns an {@link LlvmWriteLocalVariableNode} for the given parameters.
     *
     * @param nameToken The name of the variable being assigned
     * @param valueNode The value to be assigned
     * @return An LlvmExpressionNode for the given parameters.
     */
    public LlvmExpressionNode createAssignment(Token nameToken, LlvmExpressionNode valueNode) {
        FrameSlot frameLlvmot = frameDescriptor.findOrAddFrameSlot(nameToken.getText());
        lexicalScope.locals.put(nameToken.getText(), frameLlvmot);
        final int start = nameToken.getStartIndex();
        final int length = valueNode.getSourceSection().getCharEndIndex() - start;
        return LlvmWriteLocalVariableNodeGen.create(source.createSection("=", start, length), valueNode,
                frameLlvmot);
    }

    public LlvmExpressionNode createReassignment(Token nameToken, LlvmExpressionNode valueNode) {
        FrameSlot frameLlvmot = frameDescriptor.findOrAddFrameSlot(nameToken.getText());
        lexicalScope.locals.put(nameToken.getText(), frameLlvmot);
        final int start = nameToken.getStartIndex();
        final int length = start - valueNode.getSourceSection().getCharIndex();
        return LlvmWriteLocalArrayVariableNodeGen.create(source.createSection("=", start, length), valueNode,
                frameLlvmot);
    }

    public LlvmStatementNode createBasicBlockNode(Token nameToken, List<LlvmStatementNode> bodyNodes, int startPos,
            int length) {
        // lexicalScope = lexicalScope.outer;
        FrameSlot frameLlvmot = frameDescriptor.findOrAddFrameSlot(nameToken.getText());
        lexicalScope.locals.put(nameToken.getText(), frameLlvmot);
        List<LlvmStatementNode> flattenedNodes = new ArrayList<>(bodyNodes.size());
        flattenBlocks(bodyNodes, flattenedNodes);
        final SourceSection src = source.createSection(nameToken.getText(), startPos, length);
        LlvmBlockNode blockNode = new LlvmBlockNode(src,
                flattenedNodes.toArray(new LlvmStatementNode[flattenedNodes.size()]));
        // ??
        blockNode.assignSourceSection(src);
        lexicalScope.blockMap.put(nameToken.getText(), blockNode);
        return blockNode;
    }

    // public LlvmExpressionNode createReadBlock(Token nameToken) {
    // final FrameSlot frameLlvmot = lexicalScope.locals.get(nameToken.getText());
    // final SourceSection src = srcFromToken(nameToken);
    // if (frameLlvmot != null) {
    // return LlvmReadLocalVariableNodeGen.create(src, frameLlvmot);
    // } else {
    // // read before writen
    // FrameSlot frameLlvmotTwo = frameDescriptor.findOrAddFrameSlot(nameToken.getText());
    // lexicalScope.locals.put(nameToken.getText(), frameLlvmotTwo);
    // final int start = nameToken.getStartIndex();
    // final int length = 50;
    // return LlvmWriteLocalVariableNodeGen.create(source.createSection("=", start, length), null,
    // frameLlvmot);
    // }
    // }

    // public LlvmExpressionNode createCallBasicBlock(Token nameToken, Token finalToken) {
    // FrameSlot frameLlvmot = frameDescriptor.findOrAddFrameSlot(nameToken.getText());
    // lexicalScope.locals.put(nameToken.getText(), frameLlvmot);
    // final int startPos = nameToken.getStartIndex();
    // final int endPos = finalToken.getStartIndex() + finalToken.getText().length();
    // final SourceSection src = source.createSection(nameToken.getText(), startPos, endPos - startPos);
    // LlvmExpressionNode basicBlockNode = this.createRead(nameToken);
    // return LlvmInvokeBasicBlockNode.create(src, nameToken, basicBlockNode);
    // }
    public LlvmStatementNode createCallBasicBlock(LlvmExpressionNode blockNode, Token finalToken) {
        final int startPos = blockNode.getSourceSection().getCharIndex();
        final int endPos = finalToken.getStartIndex() + finalToken.getText().length();
        final SourceSection src = source.createSection(blockNode.getSourceSection().getIdentifier(), startPos,
                endPos - startPos);
        // return LlvmInvokeBasicBlockNode.create(src, blockNode);
        return lexicalScope.blockMap.get(blockNode.getSourceSection().getIdentifier());
    }

    public LlvmExpressionNode createisReadBlock(Token nameToken) {
        FrameSlot frameLlvmot = lexicalScope.locals.get(nameToken.getText());
        final SourceSection src = srcFromToken(nameToken);
        if (frameLlvmot != null) {
            return LlvmReadLocalVariableNodeGen.create(src, frameLlvmot);
        } else {
            // LlvmBlockNode block = new LlvmBlockNode(src, null);
            // block.assignSourceSection(src);
            // frameLlvmot = frameDescriptor.findOrAddFrameSlot(nameToken.getText());
            // lexicalScope.locals.put(nameToken.getText(), frameLlvmot);
            // return new LlvmBasicBlockLiteralNode(src, block);
            return null;
        }
    }

    //
    // /**
    // * Returns a {@link LlvmReadLocalVariableNode} if this read is a local variable or a
    // * {@link LlvmFunctionLiteralNode} if this read is global. In Simple, the only global names are
    // * functions. </br> There is currently no instrumentation for this node.
    // *
    // * @param nameToken The name of the variable/function being read
    // * @return either:
    // * <ul>
    // * <li>A LlvmReadLocalVariableNode representing the local variable being read.</li>
    // * <li>A LlvmFunctionLiteralNode representing the function definition</li>
    // * </ul>
    // */
    public LlvmExpressionNode createRead(Token nameToken) {
        final FrameSlot frameLlvmot = lexicalScope.locals.get(nameToken.getText());
        final SourceSection src = srcFromToken(nameToken);
        if (frameLlvmot != null) {
            /* Read of a local variable. */
            // return new LlvmFunctionLiteralNode(src,
            // context.getFunctionRegistry().lookup(nameToken.val));
            return LlvmReadLocalVariableNodeGen.create(src, frameLlvmot);
        } else {
            /* Read of a global name. In our language, the only global names are functions. */
            return new LlvmFunctionLiteralNode(src, context.getFunctionRegistry().lookup(nameToken.getText()));
        }
    }

    public LlvmExpressionNode createStringLiteral(Token literalToken) {
        /* Remove the trailing and ending " */
        String literal = literalToken.getText();
        assert literal.length() >= 2 && literal.startsWith("\"") && literal.endsWith("\"");
        final SourceSection src = srcFromToken(literalToken);
        literal = literal.substring(1, literal.length() - 1);

        return new LlvmStringLiteralNode(src, literal);
    }

    public LlvmExpressionNode createNumericLiteral(Token literalToken) {
        final SourceSection src = srcFromToken(literalToken);
        try {
            /* Try if the literal is small enough to fit into a long value. */
            return new LlvmLongLiteralNode(src, Long.parseLong(literalToken.getText()));
        } catch (NumberFormatException ex) {
            /* Overflow of long value, so fall back to BigInteger. */
            return new LlvmBigIntegerLiteralNode(src, new BigInteger(literalToken.getText()));
        }
    }

    public LlvmExpressionNode createFloatLiteral(Token literalToken) {
        final SourceSection src = srcFromToken(literalToken);
        try {
            /* Try if the literal is small enough to fit into a long value. */
            return new LlvmFloatLiteralNode(src, Long.parseLong(literalToken.getText()));
        } catch (NumberFormatException ex) {
            /* Overflow of long value, so fall back to BigInteger. */
            return new LlvmDoubleLiteralNode(src, new Double(literalToken.getText()));
        }
    }

    public LlvmExpressionNode createArrayLiteral(Token literalToken) {
        final SourceSection src = srcFromToken(literalToken);
        String[] str = literalToken.getText().split("x");
        switch (str[0]) {
        case "i32":
        case "i8":
            return new LlvmIntArrayLiteralNode(src, new int[Integer.parseInt(str[1])]);
        case "i64":
            return new LlvmBigIntArrayLiteralNode(src, new BigInteger[Integer.parseInt(str[1])]);
        }
        return null;
    }

    public LlvmExpressionNode createParenExpression(LlvmExpressionNode expressionNode, int start, int length) {
        final SourceSection src = source.createSection("()", start, length);
        return new LlvmParenExpressionNode(src, expressionNode);
    }

    /**
     * Returns an {@link LlvmReadPropertyNode} for the given parameters.
     *
     * @param receiverNode The receiver of the property access
     * @param nameToken The name of the property being accessed
     * @return An LlvmExpressionNode for the given parameters.
     */
    public LlvmExpressionNode createReadProperty(LlvmExpressionNode receiverNode, Token nameToken) {
        final int startPos = receiverNode.getSourceSection().getCharIndex();
        final int endPos = nameToken.getStartIndex() + nameToken.getText().length();
        final SourceSection src = source.createSection(".", startPos, endPos - startPos);
        return LlvmReadPropertyNode.create(src, receiverNode, nameToken.getText());
    }

    /**
     * Returns an {@link LlvmWritePropertyNode} for the given parameters.
     *
     * @param receiverNode The receiver object of the property assignment
     * @param nameToken The name of the property being assigned
     * @param valueNode The value to be assigned
     * @return An LlvmExpressionNode for the given parameters.
     */
    public LlvmExpressionNode createWriteProperty(LlvmExpressionNode receiverNode, Token nameToken,
            LlvmExpressionNode valueNode) {
        final int start = receiverNode.getSourceSection().getCharIndex();
        final int length = valueNode.getSourceSection().getCharEndIndex() - start;
        SourceSection src = source.createSection("=", start, length);
        return LlvmWritePropertyNode.create(src, receiverNode, nameToken.getText(), valueNode);
    }

    /**
     * Creates source description of a single token.
     */
    private SourceSection srcFromToken(Token token) {
        return source.createSection(token.getText(), token.getStartIndex(), token.getText().length());
    }

}