CallSite — invokedynamic 호출 지점의 타깃을 담는 홀더

CallSite — invokedynamic 호출 지점의 타깃을 담는 홀더

CallSite변경 가능한 MethodHandle(타깃이라고 부름)을 담는 홀더예요. invokedynamic 명령어가 CallSite에 연결되면, 그 사이트의 현재 타깃에 모든 호출을 위임해요.

출처: Java API Reference

본문

하나의 CallSite는 여러 invokedynamic 명령어와 연결될 수도 있고, 어떤 명령어와도 연결되지 않은 "자유 부유(free floating)" 상태일 수도 있어요. 어느 경우든 dynamic invoker라고 부르는 연결된 메서드 핸들을 통해 호출될 수 있어요.

CallSite추상 sealed 클래스라서 사용자가 직접 상속할 수 없어요. 인스턴스화되거나 상속될 수 있는 구체적인 non-sealed 하위 클래스가 셋 있어요.

  • 상수 타깃이 필요 없을 때: invokedynamic 명령어를 ConstantCallSite로 영구적으로 묶을 수 있어요.
  • 변경 가능한 타깃이 필요한데 volatile 변수 의미론이 필요할 때 (타깃 변경이 다른 스레드에 즉시·확실하게 보여야 할 때): VolatileCallSite를 써요.
  • 그 외에 변경 가능한 타깃이 필요할 때: MutableCallSite를 써요.

비상수 콜 사이트는 타깃을 바꿔 다시 연결(relink)될 수 있어요. 단 새 타깃은 이전 타깃과 같은 타입이어야 해요. 그래서 콜 사이트는 연속된 타깃들로 재연결될 수 있지만, 타입 자체를 바꾸진 못해요.

상속 구조는 다음과 같아요.

java.lang.Object
  java.lang.invoke.CallSite

sealed 클래스이며 ConstantCallSite, MutableCallSite, VolatileCallSite만 허용해요.

예시

모든 dynamic 콜 사이트를 연결해 그 인자를 출력하는 부트스트랩 메서드 예시예요.

static void test() throws Throwable {
    // 아래 줄은 JVM 명령어의 의사코드
    InvokeDynamic[#bootstrapDynamic].baz("baz arg", 2, 3.14);
}
private static void printArgs(Object... args) {
    System.out.println(java.util.Arrays.deepToString(args));
}
private static final MethodHandle printArgs;
static {
    MethodHandles.Lookup lookup = MethodHandles.lookup();
    Class thisClass = lookup.lookupClass(); // (나는 누구?)
    printArgs = lookup.findStatic(thisClass,
        "printArgs", MethodType.methodType(void.class, Object[].class));
}
private static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String name, MethodType type) {
    // caller와 name은 무시하고 type은 맞춘다:
    return new ConstantCallSite(printArgs.asType(type));
}

자바 1.7부터 제공돼요.

더 알아보기 (Learn more)