/*
* Copyright (c) 2016, Oracle and/or its affiliates.
*
* 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.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE
* COPYRIGHT HOLDER 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.
*/
package com.oracle.truffle.llvm.parser;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.List;
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.RootCallTarget;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.nodes.NodeUtil;
import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.llvm.parser.model.functions.FunctionDeclaration;
import com.oracle.truffle.llvm.parser.model.functions.FunctionDefinition;
import com.oracle.truffle.llvm.parser.model.globals.GlobalAlias;
import com.oracle.truffle.llvm.parser.model.globals.GlobalConstant;
import com.oracle.truffle.llvm.parser.model.globals.GlobalVariable;
import com.oracle.truffle.llvm.parser.model.visitors.ModelVisitor;
import com.oracle.truffle.llvm.runtime.LLVMException;
import com.oracle.truffle.llvm.runtime.LLVMFunctionDescriptor;
import com.oracle.truffle.llvm.runtime.LLVMFunctionDescriptor.LazyToTruffleConverter;
import com.oracle.truffle.llvm.runtime.nodes.api.LLVMExpressionNode;
import com.oracle.truffle.llvm.runtime.LLVMLogger;
import com.oracle.truffle.llvm.runtime.options.LLVMOptions;
import com.oracle.truffle.llvm.runtime.types.Type;
final class LLVMModelVisitor implements ModelVisitor {
private final LLVMParserRuntime visitor;
LLVMModelVisitor(LLVMParserRuntime visitor) {
this.visitor = visitor;
}
@Override
public void visit(GlobalAlias alias) {
visitor.getAliases().put(alias, alias.getValue());
}
@Override
public void visit(GlobalConstant constant) {
visitor.getGlobals().put(constant, null);
}
@Override
public void visit(GlobalVariable variable) {
visitor.getGlobals().put(variable, null);
}
@Override
public void visit(FunctionDeclaration method) {
}
@Override
public void visit(FunctionDefinition method) {
final String name = method.getName();
if (!LLVMLogger.TARGET_NONE.equals(LLVMOptions.DEBUG.printMetadata())) {
method.getMetadata().print(LLVMLogger.print(LLVMOptions.DEBUG.printMetadata()), name);
}
LLVMFunctionDescriptor function = visitor.getContext().lookupFunctionDescriptor(method.getName(),
i -> visitor.getNodeFactory().createFunctionDescriptor(visitor.getContext(), method.getName(), method.getType(), i));
if (LLVMOptions.ENGINE.lazyParsing()) {
function.declareInSulong(new LazyToTruffleConverterImpl(method, visitor));
} else {
function.declareInSulong((new LazyToTruffleConverterImpl(method, visitor)).convert());
}
visitor.addFunction(function);
}
private static class LazyToTruffleConverterImpl implements LazyToTruffleConverter {
private final FunctionDefinition method;
private final LLVMParserRuntime visitor;
LazyToTruffleConverterImpl(FunctionDefinition method, LLVMParserRuntime visitor) {
this.method = method;
this.visitor = visitor;
}
@Override
public RootCallTarget convert() {
CompilerAsserts.neverPartOfCompilation();
FrameDescriptor frame = visitor.getStack().getFrame(method.getName());
final LLVMLifetimeAnalysis lifetimes = LLVMLifetimeAnalysis.getResult(method, frame, visitor.getPhis().getPhiMap(method.getName()));
LLVMExpressionNode body = visitor.createFunction(method, frame.findFrameSlot(LLVMException.FRAME_SLOT_ID), lifetimes);
List<LLVMExpressionNode> copyArgumentsToFrame = visitor.copyArgumentsToFrame(frame, method);
LLVMExpressionNode[] copyArgumentsToFrameArray = copyArgumentsToFrame.toArray(new LLVMExpressionNode[copyArgumentsToFrame.size()]);
final SourceSection sourceSection = visitor.getSourceSection(method);
RootNode rootNode = visitor.getNodeFactory().createFunctionStartNode(visitor, body, copyArgumentsToFrameArray, sourceSection, frame, method, visitor.getSource());
final String astPrintTarget = LLVMOptions.DEBUG.printFunctionASTs();
if (LLVMLogger.TARGET_STDOUT.equals(astPrintTarget) || LLVMLogger.TARGET_ANY.equals(astPrintTarget)) {
// Checkstyle: stop
NodeUtil.printTree(System.out, rootNode);
System.out.flush();
// Checkstyle: resume
} else if (LLVMLogger.TARGET_STDERR.equals(astPrintTarget)) {
// Checkstyle: stop
NodeUtil.printTree(System.err, rootNode);
System.err.flush();
// Checkstyle: resume
} else if (!LLVMLogger.TARGET_NONE.equals(astPrintTarget)) {
try (PrintStream out = new PrintStream(new FileOutputStream(astPrintTarget, true))) {
NodeUtil.printTree(out, rootNode);
out.flush();
} catch (IOException e) {
throw new IllegalStateException("Cannot write to file: " + astPrintTarget);
}
}
RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(rootNode);
visitor.exitFunction();
return callTarget;
}
}
@Override
public void visit(Type type) {
}
}