마치 마치 마치 들립니다 packed-switch
Java와 동일합니다 tableswitch
, 그리고 sparse-switch
에게 lookupswitch
.
ㅏ packed-switch
양식별로 인덱싱 된 간단한 점프 테이블을 사용합니다. low + n
, 어디 low
중에서 가장 낮은 테스트 값입니다 case
라벨 및 n
에 대한 입력입니다 switch
. 각 인덱스의 값은 각각의 바이트 코드 오프셋을 나타냅니다. case
. 올바른 점프 주소를 찾는 것은 일정한 시간 조작입니다.
ㅏ sparse-switch
키 값 쌍의 정렬 된 목록을 사용합니다. 각 키는 다음의 테스트 값입니다. case
레이블 및 값은 점프 오프셋입니다. A의 올바른 점프 대상 찾기 lookupswitch
키에서 이진 검색이 필요하므로 로그 시간 조작입니다.
컴파일러는 사용할 것인지 선택합니다. 키가 클러스터링되는 경향이있는 경우 포장 된 밀접하게 함께, a packed-switch
(또는 Java 용어로 a tableswitch
) 효율적으로 방출 될 수 있습니다. 그러나 열쇠가 있다면 부족한, 및 값 범위 (high - low + 1
)는 크고, 점프 테이블을 사용하는 데 큰 바이트 코드 블록이 필요합니다. 해당 범위의 모든 값은 해당하는 것이 있는지 여부에 관계없이 점프 테이블에 존재해야하므로. case
상표. 이 시나리오에서 컴파일러는 a를 방출합니다 sparse-switch
(lookupswitch
).
흥미롭게도 Dalvik 엔지니어는 사용해야 할 주요 분포를 설명하는 방식으로 이러한 Opcode를 이름을 지정하기로 선택한 반면 Java 엔지니어는 바이트 코드 오페라가 닮은 개념적 데이터 구조를 설명하는 이름을 선택했습니다.
몇 가지 예를 살펴 보겠습니다. 다음 Java 코드를 고려하면 tableswitch
(그리고 Dalvik으로 변환 될 때, a packed-switch
):
static String packedSwitch(final int n) {
switch (n) {
case 5:
return "Five";
case 3:
return "Three";
case 1:
return "One";
default:
return "Other";
}
}
개념적으로, 페이로드 packed-switch
Opcode는 다음과 같이 보입니다.
보시다시피, 그것은 상당히 컴팩트합니다. 5 개의 슬롯 중 3 개가 실제를 가리 킵니다 case
나머지 두 개가 default
표적. 그러나 테스트 값이 더 확산되면 어떻게됩니까?
static String sparseSwitch(final int n) {
switch (n) {
case 500:
return "Five Hundred";
case 300:
return "Three Hundred";
case 100:
return "One Hundred";
default:
return "Other";
}
}
컴파일러가 이것을 a로 방출하려고 시도한 경우 packed-switch
, 페이로드는 다음과 같이 보입니다.
수백 개의 슬롯 중 3 개만 실제로 case
원본 코드의 레이블. 나머지는 단순히 점프 테이블을 채우기 위해 있습니다. 공간 효율적이지 않습니까? 그렇기 때문에 컴파일러가 방출되는 이유입니다 sparse-switch
, 이 특정 예에 대해 훨씬 더 컴팩트 한 바이트 코드 풋 프린트가 있습니다.
이제 훨씬 더 합리적입니다. 생각하지 않습니까? 그러나 단점은 입력을 기반으로 어떤 색인을 점프 할 것인지 정확히 알지 못하는 대신 일치하는 테스트 값을 찾을 때까지 테이블에서 이진 검색을 수행해야한다는 것입니다. 스위치가 클수록 효과는 로그 곡선을 가지고 있지만 성능에 미치는 영향이 더 중요합니다.