/*
 * Copyright (c) 2016, 2020, 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.runtime.nodes.func;

import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.DirectCallNode;
import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.llvm.runtime.LLVMArgumentBuffer;
import com.oracle.truffle.llvm.runtime.LLVMContext;
import com.oracle.truffle.llvm.runtime.LLVMExitException;
import com.oracle.truffle.llvm.runtime.LLVMFunction;
import com.oracle.truffle.llvm.runtime.LLVMLanguage;
import com.oracle.truffle.llvm.runtime.memory.LLVMStack;
import com.oracle.truffle.llvm.runtime.pointer.LLVMManagedPointer;
import com.oracle.truffle.llvm.runtime.types.FunctionType;
import com.oracle.truffle.llvm.runtime.types.PrimitiveType;
import com.oracle.truffle.llvm.runtime.types.PrimitiveType.PrimitiveKind;
import com.oracle.truffle.llvm.runtime.types.Type;
import com.oracle.truffle.llvm.runtime.types.VoidType;

public class LLVMGlobalRootNode extends RootNode {

    private final DirectCallNode startFunction;
    private final int mainFunctionType;
    private final String applicationPath;
    private final LLVMFunction mainFunction;

    public LLVMGlobalRootNode(LLVMLanguage language, FrameDescriptor descriptor, LLVMFunction mainFunction, CallTarget startFunction, String applicationPath) {
        super(language, descriptor);
        this.mainFunction = mainFunction;
        this.startFunction = Truffle.getRuntime().createDirectCallNode(startFunction);
        this.mainFunctionType = getMainFunctionType(mainFunction);
        this.applicationPath = applicationPath;
    }

    @Override
    public boolean isInternal() {
        return true;
    }

    @Override
    public Object execute(VirtualFrame frame) {
        return executeWithoutFrame();
    }

    @SuppressWarnings("try")
    @TruffleBoundary
    private Object executeWithoutFrame() {
        LLVMStack stack = getContext().getThreadingStack().getStack();
        try {
            Object appPath = new LLVMArgumentBuffer(applicationPath);
            LLVMManagedPointer applicationPathObj = LLVMManagedPointer.create(appPath);
            Object[] realArgs = new Object[]{stack, mainFunctionType, applicationPathObj, getContext().getSymbol(mainFunction)};
            Object result = startFunction.call(realArgs);
            getContext().awaitThreadTermination();
            return (int) result;
        } catch (LLVMExitException e) {
            LLVMContext context = getContext();
            // if any variant of exit or abort was called, we know that all the necessary
            // cleanup was already done
            context.setCleanupNecessary(false);
            context.awaitThreadTermination();
            return e.getExceptionExitStatus();
        } finally {
            // if not done already, we want at least call a shutdown command
            getContext().shutdownThreads();
        }
    }

    
Identify the signature of the main method so that crt0.c:_start can invoke the main method with the correct signature. This is necessary because languages like Rust use non-standard C main functions.
/** * Identify the signature of the main method so that crt0.c:_start can invoke the main method * with the correct signature. This is necessary because languages like Rust use non-standard C * main functions. */
private static int getMainFunctionType(LLVMFunction function) { CompilerAsserts.neverPartOfCompilation(); FunctionType functionType = function.getType(); Type returnType = functionType.getReturnType(); if (functionType.getNumberOfArguments() > 0 && functionType.getArgumentType(0) instanceof PrimitiveType) { if (((PrimitiveType) functionType.getArgumentType(0)).getPrimitiveKind() == PrimitiveKind.I64) { return 1; } } if (returnType instanceof VoidType) { return 2; } else if (returnType instanceof PrimitiveType) { switch (((PrimitiveType) returnType).getPrimitiveKind()) { case I8: return 3; case I16: return 4; case I32: return 0; case I64: return 5; } } throw new AssertionError("Unexpected main method signature"); } public final LLVMContext getContext() { return lookupContextReference(LLVMLanguage.class).get(); } }