<commit_before>/*
 * See LICENSE file in distribution for copyright and licensing information.
 */
package seph.lang.compiler;

import java.util.*;

import seph.lang.*;

import java.lang.invoke.CallSite;
import java.lang.invoke.ConstantCallSite;
import java.lang.invoke.MutableCallSite;
import java.lang.invoke.MethodType;
import static java.lang.invoke.MethodType.*;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;

import static java.lang.invoke.MethodHandles.invoker;
import static java.lang.invoke.MethodHandles.dropArguments;
import static java.lang.invoke.MethodHandles.insertArguments;
import static java.lang.invoke.MethodHandles.filterArguments;
import static java.lang.invoke.MethodHandles.foldArguments;
import static java.lang.invoke.MethodHandles.constant;
import static java.lang.invoke.MethodHandles.identity;
import static java.lang.invoke.MethodHandles.guardWithTest;
import static seph.lang.compiler.CompilationHelpers.*;
import static seph.lang.Types.*;

public class SephCallSite extends MutableCallSite {
    public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType type) {
        return new SephCallSite(lookup, name, type);
    }

    private final boolean intrinsic;
    private final String messageKind;
    private final String messageName;
    private final MethodHandle slowPath;

    public SephCallSite(MethodHandles.Lookup lookup, String name, MethodType type) {
        super(type);

        Object[] pieces = kindNameIntrinsic(name.split(":"));
        this.messageKind = (String)pieces[0];
        this.messageName = (String)pieces[1];
        this.intrinsic   = (Boolean)pieces[2];
        this.slowPath    = computeSlowPath();

        if(intrinsic) {
            setNeutral();
            setTarget(computeIntrinsicPath());
        } else {
            setNeutral();
        }
    }
    
    private final static MethodHandle INTRINSIC_TRUE_MH =  constant(SephObject.class, seph.lang.Runtime.TRUE);
    private final static MethodHandle INTRINSIC_FALSE_MH = constant(SephObject.class, seph.lang.Runtime.FALSE);
    private final static MethodHandle INTRINSIC_NIL_MH =   constant(SephObject.class, seph.lang.Runtime.NIL);

    private MethodHandle computeIntrinsicPath() {
        Class<?>[] argParts = type().dropParameterTypes(0, 3).parameterArray();
        MethodHandle fallback = getTarget();
        if(messageName == "true") {
            MethodHandle intrinsicMH =  dropArguments(INTRINSIC_TRUE_MH, 0, type().parameterArray());
            MethodHandle initialSetup = dropArguments(insertArguments(INITIAL_SETUP_INTRINSIC_TRUE_MH, 0, this, intrinsicMH, fallback), 2, argParts);
            return initialSetup;
        } else if(messageName == "false") {
            MethodHandle intrinsicMH =  dropArguments(INTRINSIC_FALSE_MH, 0, type().parameterArray());
            MethodHandle initialSetup = dropArguments(insertArguments(INITIAL_SETUP_INTRINSIC_FALSE_MH, 0, this, intrinsicMH, fallback), 2, argParts);
            return initialSetup;
        } else if(messageName == "nil") {
            MethodHandle intrinsicMH =  dropArguments(INTRINSIC_NIL_MH, 0, type().parameterArray());
            MethodHandle initialSetup = dropArguments(insertArguments(INITIAL_SETUP_INTRINSIC_NIL_MH, 0, this, intrinsicMH, fallback), 2, argParts);
            return initialSetup;
        } else {
            return null;
        }
    }


    private int arity = -2;
    private boolean keywords = false;;
    
    private void computeArity() {
        int num = type().parameterCount() - 3;
        if(num == 0) {
            keywords = false;
            arity = 0;
        } else {
            Class<?>[] tp = type().parameterArray();
            int minus = 0;
            if(tp[tp.length-2] == String[].class) {
                keywords = true;
                minus = 2;
            }
            if(num == 1 && tp[3] == MethodHandle[].class) {
                arity = -1;
            } else {
                arity = num - minus;
            }
        }
    }

    private int arity() {
        if(arity == -2) {
            computeArity();
        }
        return arity;
    }

    private boolean keywords() {
        if(arity == -2) {
            computeArity();
        }
        return keywords;
    }

    private static Object[] kindNameIntrinsic(Object[] nc) {
        String kind = ((String)nc[1]).intern();
        String name = decode((String)nc[2]).intern();
        boolean intrinsic = nc.length == 4;
        return new Object[] { kind, name, intrinsic };
    }

    public static SephObject setTail(MethodHandle h, SThread thread) {
        thread.tail = h;
        return SThread.TAIL_MARKER;
    }
    
    public final static MethodHandle SET_TAIL_MH = findStatic(SephCallSite.class, "setTail", methodType(SephObject.class, MethodHandle.class, SThread.class));
    public final static MethodType SLOW_PATH_TYPE    = methodType(SephObject.class, SephCallSite.class, String.class, SephObject.class, SThread.class, LexicalScope.class, Object[].class);

    public static void checkForNull(String name, SephObject value, SephObject receiver) {
         if(null == value) {
             throw new RuntimeException(" *** couldn't find: " + name + " on " + receiver);
         }
    }

    public final static MethodHandle CHECK_FOR_NULL_MH = findStatic(SephCallSite.class, "checkForNull", methodType(void.class, String.class, SephObject.class, SephObject.class));

    MethodHandle computeSlowPath() {
            if(messageKind == "message") {
                MethodHandle _test = dropArguments(findVirtual(SephObject.class, "isActivatable", methodType(boolean.class)), 1, type().parameterArray());
                
                MethodHandle invoker = findVirtual(MethodHandle.class, "invokeExact", type());
                MethodHandle _then = filterArguments(invoker, 0, insertArguments(findVirtual(SephObject.class, "activationFor", methodType(MethodHandle.class, int.class, boolean.class)), 1, arity(), keywords()));
                MethodHandle _else = dropArguments(identity(SephObject.class), 1, type().parameterArray());
                MethodHandle all = guardWithTest(_test, _then, _else);

                MethodHandle _nullCheck = dropArguments(insertArguments(CHECK_FOR_NULL_MH, 0, messageName), 
                                                        2, 
                                                        type().dropParameterTypes(0, 1).parameterArray());
                MethodHandle complete = foldArguments(
                                                      foldArguments(all, _nullCheck),
                                                      dropArguments(insertArguments(findVirtual(SephObject.class, "get", methodType(SephObject.class, String.class)), 1, messageName), 1, type().dropParameterTypes(0, 1).parameterArray()));

                return complete;
            } else if(messageKind == "tailMessage") {
                MethodHandle _test = dropArguments(findVirtual(SephObject.class, "isActivatable", methodType(boolean.class)), 1, type().parameterArray());
                MethodHandle _insertArguments = insertArguments(findStatic(MethodHandles.class, "insertArguments", methodType(MethodHandle.class, MethodHandle.class, int.class, Object[].class)), 1, 0).asCollector(Object[].class, type().parameterCount()).asType(type().insertParameterTypes(0, MethodHandle.class).changeReturnType(MethodHandle.class));
                MethodHandle _activationFor = insertArguments(findVirtual(SephObject.class, "activationFor", methodType(MethodHandle.class, int.class, boolean.class)), 1, arity(), keywords());
                MethodHandle _filtered = filterArguments( _insertArguments, 0 ,_activationFor);
                MethodHandle _then = foldArguments(dropArguments(dropArguments(SET_TAIL_MH, 1, SephObject.class, SephObject.class), 4, type().dropParameterTypes(0, 2).parameterArray()), 
                                                   _filtered);
                MethodHandle _else = dropArguments(identity(SephObject.class), 1, type().parameterArray());
                MethodHandle all = guardWithTest(_test, _then, _else);<commit_msg>Use exact invoker instead<commit_after>/*
 * See LICENSE file in distribution for copyright and licensing information.
 */
package seph.lang.compiler;

import java.util.*;

import seph.lang.*;

import java.lang.invoke.CallSite;
import java.lang.invoke.ConstantCallSite;
import java.lang.invoke.MutableCallSite;
import java.lang.invoke.MethodType;
import static java.lang.invoke.MethodType.*;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;

import static java.lang.invoke.MethodHandles.invoker;
import static java.lang.invoke.MethodHandles.dropArguments;
import static java.lang.invoke.MethodHandles.insertArguments;
import static java.lang.invoke.MethodHandles.filterArguments;
import static java.lang.invoke.MethodHandles.foldArguments;
import static java.lang.invoke.MethodHandles.constant;
import static java.lang.invoke.MethodHandles.identity;
import static java.lang.invoke.MethodHandles.guardWithTest;
import static seph.lang.compiler.CompilationHelpers.*;
import static seph.lang.Types.*;

public class SephCallSite extends MutableCallSite {
    public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType type) {
        return new SephCallSite(lookup, name, type);
    }

    private final boolean intrinsic;
    private final String messageKind;
    private final String messageName;
    private final MethodHandle slowPath;

    public SephCallSite(MethodHandles.Lookup lookup, String name, MethodType type) {
        super(type);

        Object[] pieces = kindNameIntrinsic(name.split(":"));
        this.messageKind = (String)pieces[0];
        this.messageName = (String)pieces[1];
        this.intrinsic   = (Boolean)pieces[2];
        this.slowPath    = computeSlowPath();

        if(intrinsic) {
            setNeutral();
            setTarget(computeIntrinsicPath());
        } else {
            setNeutral();
        }
    }
    
    private final static MethodHandle INTRINSIC_TRUE_MH =  constant(SephObject.class, seph.lang.Runtime.TRUE);
    private final static MethodHandle INTRINSIC_FALSE_MH = constant(SephObject.class, seph.lang.Runtime.FALSE);
    private final static MethodHandle INTRINSIC_NIL_MH =   constant(SephObject.class, seph.lang.Runtime.NIL);

    private MethodHandle computeIntrinsicPath() {
        Class<?>[] argParts = type().dropParameterTypes(0, 3).parameterArray();
        MethodHandle fallback = getTarget();
        if(messageName == "true") {
            MethodHandle intrinsicMH =  dropArguments(INTRINSIC_TRUE_MH, 0, type().parameterArray());
            MethodHandle initialSetup = dropArguments(insertArguments(INITIAL_SETUP_INTRINSIC_TRUE_MH, 0, this, intrinsicMH, fallback), 2, argParts);
            return initialSetup;
        } else if(messageName == "false") {
            MethodHandle intrinsicMH =  dropArguments(INTRINSIC_FALSE_MH, 0, type().parameterArray());
            MethodHandle initialSetup = dropArguments(insertArguments(INITIAL_SETUP_INTRINSIC_FALSE_MH, 0, this, intrinsicMH, fallback), 2, argParts);
            return initialSetup;
        } else if(messageName == "nil") {
            MethodHandle intrinsicMH =  dropArguments(INTRINSIC_NIL_MH, 0, type().parameterArray());
            MethodHandle initialSetup = dropArguments(insertArguments(INITIAL_SETUP_INTRINSIC_NIL_MH, 0, this, intrinsicMH, fallback), 2, argParts);
            return initialSetup;
        } else {
            return null;
        }
    }


    private int arity = -2;
    private boolean keywords = false;;
    
    private void computeArity() {
        int num = type().parameterCount() - 3;
        if(num == 0) {
            keywords = false;
            arity = 0;
        } else {
            Class<?>[] tp = type().parameterArray();
            int minus = 0;
            if(tp[tp.length-2] == String[].class) {
                keywords = true;
                minus = 2;
            }
            if(num == 1 && tp[3] == MethodHandle[].class) {
                arity = -1;
            } else {
                arity = num - minus;
            }
        }
    }

    private int arity() {
        if(arity == -2) {
            computeArity();
        }
        return arity;
    }

    private boolean keywords() {
        if(arity == -2) {
            computeArity();
        }
        return keywords;
    }

    private static Object[] kindNameIntrinsic(Object[] nc) {
        String kind = ((String)nc[1]).intern();
        String name = decode((String)nc[2]).intern();
        boolean intrinsic = nc.length == 4;
        return new Object[] { kind, name, intrinsic };
    }

    public static SephObject setTail(MethodHandle h, SThread thread) {
        thread.tail = h;
        return SThread.TAIL_MARKER;
    }
    
    public final static MethodHandle SET_TAIL_MH = findStatic(SephCallSite.class, "setTail", methodType(SephObject.class, MethodHandle.class, SThread.class));
    public final static MethodType SLOW_PATH_TYPE    = methodType(SephObject.class, SephCallSite.class, String.class, SephObject.class, SThread.class, LexicalScope.class, Object[].class);

    public static void checkForNull(String name, SephObject value, SephObject receiver) {
         if(null == value) {
             throw new RuntimeException(" *** couldn't find: " + name + " on " + receiver);
         }
    }

    public final static MethodHandle CHECK_FOR_NULL_MH = findStatic(SephCallSite.class, "checkForNull", methodType(void.class, String.class, SephObject.class, SephObject.class));

    MethodHandle computeSlowPath() {
            if(messageKind == "message") {
                MethodHandle _test = dropArguments(findVirtual(SephObject.class, "isActivatable", methodType(boolean.class)), 1, type().parameterArray());
                
                MethodHandle invoker = MethodHandles.exactInvoker(type());
                MethodHandle _then = filterArguments(invoker, 0, insertArguments(findVirtual(SephObject.class, "activationFor", methodType(MethodHandle.class, int.class, boolean.class)), 1, arity(), keywords()));
                MethodHandle _else = dropArguments(identity(SephObject.class), 1, type().parameterArray());
                MethodHandle all = guardWithTest(_test, _then, _else);

                MethodHandle _nullCheck = dropArguments(insertArguments(CHECK_FOR_NULL_MH, 0, messageName), 
                                                        2, 
                                                        type().dropParameterTypes(0, 1).parameterArray());
                MethodHandle complete = foldArguments(
                                                      foldArguments(all, _nullCheck),
                                                      dropArguments(insertArguments(findVirtual(SephObject.class, "get", methodType(SephObject.class, String.class)), 1, messageName), 1, type().dropParameterTypes(0, 1).parameterArray()));

                return complete;
            } else if(messageKind == "tailMessage") {
                MethodHandle _test = dropArguments(findVirtual(SephObject.class, "isActivatable", methodType(boolean.class)), 1, type().parameterArray());
                MethodHandle _insertArguments = insertArguments(findStatic(MethodHandles.class, "insertArguments", methodType(MethodHandle.class, MethodHandle.class, int.class, Object[].class)), 1, 0).asCollector(Object[].class, type().parameterCount()).asType(type().insertParameterTypes(0, MethodHandle.class).changeReturnType(MethodHandle.class));
                MethodHandle _activationFor = insertArguments(findVirtual(SephObject.class, "activationFor", methodType(MethodHandle.class, int.class, boolean.class)), 1, arity(), keywords());
                MethodHandle _filtered = filterArguments( _insertArguments, 0 ,_activationFor);
                MethodHandle _then = foldArguments(dropArguments(dropArguments(SET_TAIL_MH, 1, SephObject.class, SephObject.class), 4, type().dropParameterTypes(0, 2).parameterArray()), 
                                                   _filtered);
                MethodHandle _else = dropArguments(identity(SephObject.class), 1, type().parameterArray());
                MethodHandle all = guardWithTest(_test, _then, _else);
{'fraction_non_alphanumeric': 0.10744810744810745, 'fraction_numerical': 0.006349206349206349, 'mean_word_length': 2.8113075849232203, 'pattern_counts': {'":': 2, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 20, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '969130', 'n_tokens_mistral': 4509, 'n_tokens_neox': 4245, 'n_words': 950}