DynamicLinker
DynamicLinker (콜 사이트 연결 관리자)
RelinkableCallSite 객체를 위한 링커입니다. Dynalink를 쓸 때 핵심이 되는 객체로, 콜 사이트를 사용 가능한 언어 런타임들의 링커(GuardingDynamicLinker 객체)와 조율해 연결합니다.
본문
Dynalink를 사용하려면 DynamicLinkerFactory로 동적 링커를 하나 이상 만들고, invokedynamic 부트스트랩 메서드에서 그 link(RelinkableCallSite) 메서드를 호출해 콜 사이트를 관리하면 됩니다. 전형적인 사용 패턴은 이래요.
class MyLanguageRuntime {
private static final GuardingDynamicLinker myLanguageLinker = new MyLanguageLinker();
private static final DynamicLinker dynamicLinker = createDynamicLinker();
private static DynamicLinker createDynamicLinker() {
final DynamicLinkerFactory factory = new DynamicLinkerFactory();
factory.setPrioritizedLinker(myLanguageLinker);
return factory.createLinker();
}
public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType type) {
return dynamicLinker.link(
new SimpleRelinkableCallSite(
new CallSiteDescriptor(lookup, parseOperation(name), type)));
}
private static Operation parseOperation(String name) { /* ... */ }
}
위 예처럼 정적 링커 인스턴스 하나만 쓰는 경우가 많지만, 언어 런타임이 '컨텍스트 클래스 로더' 개념을 가진다면 클래스 로더마다 동적 링커를 하나씩 만들어 그 로더에 보이는 다른 언어 런타임의 링커를 포함시키는 게 좋아요(DynamicLinkerFactory.setClassLoader(ClassLoader) 참고).
제공해야 할 것은 세 가지입니다. 첫째, 자신의 언어를 위한 GuardingDynamicLinker입니다. 자체 객체 모델이나 타입 변환이 없으면 구현할 필요가 없고 setPrioritizedLinker만 호출하지 않으면 돼요. 둘째, 콜 사이트를 나타내는 클래스 선택인데 프로그램 성능에 영향을 줄 수 있습니다. SimpleRelinkableCallSite 대신 ChainedCallSite를 쓸 수도 있고, 실험해서 런타임에 맞는 것을 고르면 됩니다. 셋째, 콜 사이트에 CallSiteDescriptor를 제공해야 합니다. 이것은 룩업을 수행하는 클래스, 호출되는 연산, 메서드 시그니처 등 콜 사이트에 대한 모든 정보를 담은 불변 객체입니다. 콜 사이트 이름이나 정적 매개변수에서 연산을 인코딩·디코딩하는 방식은 사용자가 정해야 하며, 위 예의 parseOperation이 그 역할을 합니다.
주요 메서드
-
link(T callSite)—invokedynamic콜 사이트를 연결합니다. 콜 사이트에 이 링커의 재연결 메커니즘을 호출하는 메서드 핸들을 설치해요. 다음에 콜 사이트가 호출되면 실제로 호출된 인자에 맞춰 연결됩니다. 연결된 콜 사이트 자신을 반환하므로 호출 체이닝이 쉽습니다. -
getLinkerServices()— 개별 언어별 링커에 노출되는, 이 클래스의 링커 서비스를 나타내는LinkerServices객체를 반환합니다. 보통은link만 신경 쓰지만 특정 메서드 핸들을 조회하거나 타입 변환기에 접근할 때 하위 서비스를 직접 쓸 수도 있어요. -
getLinkedCallSiteLocation()— 현재 스레드에서 연결 중인invokedynamic콜 사이트의 위치를 기술하는 스택 트레이스 요소를 반환합니다.