2016-08-17 3 views
0

나는 바이트 코드를 생성하고 클래스로 Unsafe.defineAnonymous을 사용하여로드하기 위해 ASM 라이브러리를 사용한다. 둘 다 대부분의 경우 작동하지만 잠시 후 실패합니다. 그런 다음 출력 된 바이트 코드에 디버그 명령어를 추가하여 출력하고 출력 결과를 2 주 동안 혼란스럽게 만들었습니다.자바 바이트 코드 변수 인덱스 0의 className이 이상하다

(GWT는 GuardWithTestHandle의 약자입니다.)

1, DYNGWT70 및 DYNGWT73의 두 클래스가 생성되고 모두 Unsafe을 사용하여로드됩니다. 각 클래스에 대해 하나의 인스턴스 만 만들어집니다.

public class java.lang.invoke.DYNGuardWithTestHandle70 extends java.lang.invoke.BaseTemplate{ 
    public org.jruby.runtime.builtin.IRubyObject inlinedMethod(org.jruby.runtime.ThreadContext, org.jruby.runtime.builtin.IRubyObject, org.jruby.runtime.builtin.IRubyObject) throws java.lang.Throwable; 
    flags: ACC_PUBLIC 
    Code: 
     stack=8, locals=22, args_size=4 
     0: aload_0 
     1: aload_0 
     2: ldc   #29     // String This is Guard java/lang/invoke/DYNGuardWithTestHandle70 
     4: invokestatic #32     // Method java/lang/invoke/BaseTemplate.tempDebug:(Ljava/lang/invoke/MethodHandle;Ljava/lang/String;)V 
     7: astore  4 
     9: aload   4 
..... 
} 
} 

protected static void tempDebug(MethodHandle mh, String name){ 
    System.err.println("___________Debug: "+mh.getClass().getName()+", "+mh.toString()+ " message="+name); 
} 

DYNGWT73 비슷한 구조를 가지고 :

2

는 DYNGWT70의 레이아웃은 같은 것입니다.

그러나 처음 tempDebug의 출력은 다음과 같습니다

___________Debug: java.lang.invoke.DYNGuardWithTestHandle73/0000000052DFAE40, MethodHandle(ThreadContext,IRubyObject,IRubyObject)IRubyObject uid:9a7bf505-8845-4594-9cf8-69f392eef869 message= This is Guard java/lang/invoke/DYNGuardWithTestHandle70 
...... 
16/Aug/2016:22:13:42:834 -0300 [main] DEBUG java.lang.invoke.BaseTemplate - TypeInconsistException [_mh=MethodHandle(ThreadContext,IRubyObject,IRubyObject)IRubyObject uid:e064b157-f615-4f20-b386-947fc20c61ad, _exce=***** false (Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/builtin/IRubyObject;)Lorg/jruby/runtime/builtin/IRubyObject; (Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/builtin/IRubyObject;J)Lorg/jruby/runtime/builtin/IRubyObject;] 
TypeInconsistException [_mh=MethodHandle(ThreadContext,IRubyObject,IRubyObject)IRubyObject uid:e064b157-f615-4f20-b386-947fc20c61ad, _exce=***** false (Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/builtin/IRubyObject;)Lorg/jruby/runtime/builtin/IRubyObject; (Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/builtin/IRubyObject;J)Lorg/jruby/runtime/builtin/IRubyObject;] 
    at java.lang.invoke.BaseTemplate.debugCompareReceiverTypeMethodDesc(BaseTemplate.java:59) 
    at java.lang.invoke.DYNGuardWithTestHandle70.0000000052B50680.inlinedMethod(Unknown Source) 
    at java.lang.invoke.DYNGuardWithTestHandle70.0000000052B50680.invokeExact_thunkArchetype_L(Unknown Source) 
    at java.lang.invoke.MutableCallSiteDynamicInvokerHandle.invokeExact_thunkArchetype_X(MutableCallSiteDynamicInvok 

내가 mh.getClass().getName()을 이해할 수는 java.lang.invoke.DYNGuardWithTestHandle73/0000000052DFAE40, 그것은 여기 스택을 게시의 목적은이 DYN70의 방법을 실행하는 것을 보여주기 위해 뭔가 DYNGuardWithTestHandle**70**/0000000052DFAExxx 해야한다 예외는 혼란스러운 지점과 관련이 있습니다.

빈도는 높지만이 오류는 항상 발생하는 것은 아닙니다. 누구나 비슷한 이상한 사건을 경험 한 적이 있습니까? 귀하의 제안에 감사드립니다.

+0

오류가 있습니까? 또는 당신의 기대와 현실 사이의 단지 차이? – EJP

+0

이것은 디버그 명령문입니다. 인덱스가 0 인 변수는 ** DYNGuardWithTestHandle70 **이어야합니다. 여기에서 73이므로 DYNGWT70에서만 작동하는 나중의 메소드 호출 명령어에서 오류가 발생합니다. –

+0

나는'MethodHandle'의 커스텀 서브 클래스를 만드는 것이 좋은 생각이라고 생각하지 않습니다. 그것은 문제를 요구하는 것과 같습니다. 그리고 생성 된 코드에 직접 핸들을 사용하고 JVM이 인라이닝을 수행하는 깔끔한 대안과 비교할 때 이치에 맞지 않습니다. 그리고 그것은 당신이 초점을 잃게 만듭니다. 이 예외는 '긴'매개 변수가 하나의 서명에만 존재 함을 나타내며, 이는 일관성없는 유형입니다. – Holger

답변

0

안전하지 않은 비표준 API를 사용하는 경우 적어도 주석을 읽으십시오. 내부 API에 전혀 의존하지 않는 것이 좋습니다. 익명 클래스를 정의하고 있습니다. 유효한 이름이 인 것으로 기대하지 마십시오. Unsafe.defineAnonymousClass

The comments 말 :

// When you load an anonymous class U, it works as if you changed its name just before loading, 
// to a name that you will never use again. Since the name is lost, no other class can directly 
// link to any member of U. 

그래서, /0000000052DFAE40 의도적으로 defineAnonymousClass에 의해 추가됩니다. 예를 들어, 동일한 클래스 바이트를 두 번로드 할 수 있습니다 (일반 ClassLoader로 수행 할 수없는 작업). 이름 충돌을 피하기 위해 다른 접미어가 생성됩니다.

+0

의견을 보내 주셔서 감사합니다. 많은 클래스를 생성하는 경우가 있는데, 대다수는 같은 클래스 이름 (바이트 코드 수준에서)을 공유 할 수 있습니다.그것이 Unsafe API를 선택하는 이유입니다. 내 질문에 지점은''/''다음에 추가 된 16 진수 문자열이 아니며''/''앞에있는 문자열에 있습니다. 올바른 클래스 이름은 "DYNGuardWithTestHandle73/..."이 아닌 "DYNGuardWithTestHandle70/..."이어야합니다. –

+0

@shijiexu 바이트 코드를 생성하는 소스를 비롯하여 전체 사례를 보지 않고 말하기는 어렵습니다. 생성 된 클래스를로드하기위한 소스 병행성에 문제가 있거나 무엇이든지 있어야합니다. 가능한 경우 완전한 검증 가능한 예제를 작성하십시오. – apangin

+0

@shijiexu Unsafe API를 사용하는 이유는 아직 명확하지 않습니다. 고유 한 클래스 이름을 직접 생성하거나 다른 클래스 로더별로 클래스를로드 할 수 있습니다. – apangin