From 6cfe96aaf185d38937a07b662fd5fa3a3e8e70f3 Mon Sep 17 00:00:00 2001 From: dcubed Date: Wed, 5 Dec 2007 09:00:00 -0800 Subject: [PATCH] 6664627: Merge changes made only in hotspot 11 forward to jdk 7 Reviewed-by: jcoomes --- src/cpu/sparc/vm/stubGenerator_sparc.cpp | 1 + src/cpu/sparc/vm/vtableStubs_sparc.cpp | 57 +++++++--------------- src/cpu/x86/vm/stubGenerator_x86_32.cpp | 1 + src/cpu/x86/vm/stubGenerator_x86_64.cpp | 7 +++ src/cpu/x86/vm/vtableStubs_x86_32.cpp | 34 ++++++------- src/cpu/x86/vm/vtableStubs_x86_64.cpp | 61 ++++++++++++------------ src/share/vm/oops/klassVtable.cpp | 43 ++++++++--------- src/share/vm/oops/klassVtable.hpp | 2 +- src/share/vm/runtime/sharedRuntime.cpp | 5 ++ src/share/vm/runtime/sharedRuntime.hpp | 1 + src/share/vm/runtime/stubRoutines.cpp | 1 + src/share/vm/runtime/stubRoutines.hpp | 2 + 12 files changed, 102 insertions(+), 113 deletions(-) diff --git a/src/cpu/sparc/vm/stubGenerator_sparc.cpp b/src/cpu/sparc/vm/stubGenerator_sparc.cpp index 03c740857..290cedb9b 100644 --- a/src/cpu/sparc/vm/stubGenerator_sparc.cpp +++ b/src/cpu/sparc/vm/stubGenerator_sparc.cpp @@ -2911,6 +2911,7 @@ class StubGenerator: public StubCodeGenerator { // These entry points require SharedInfo::stack0 to be set up in non-core builds StubRoutines::_throw_AbstractMethodError_entry = generate_throw_exception("AbstractMethodError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_AbstractMethodError), false); + StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError), false); StubRoutines::_throw_ArithmeticException_entry = generate_throw_exception("ArithmeticException throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_ArithmeticException), true); StubRoutines::_throw_NullPointerException_entry = generate_throw_exception("NullPointerException throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException), true); StubRoutines::_throw_NullPointerException_at_call_entry= generate_throw_exception("NullPointerException at call throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call), false); diff --git a/src/cpu/sparc/vm/vtableStubs_sparc.cpp b/src/cpu/sparc/vm/vtableStubs_sparc.cpp index a1a5a82c8..c1ed4b351 100644 --- a/src/cpu/sparc/vm/vtableStubs_sparc.cpp +++ b/src/cpu/sparc/vm/vtableStubs_sparc.cpp @@ -175,17 +175,12 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) { // %%%% Could load both offset and interface in one ldx, if they were // in the opposite order. This would save a load. __ ld_ptr(L0, base + itableOffsetEntry::interface_offset_in_bytes(), L1); -#ifdef ASSERT - Label ok; - // Check that entry is non-null and an Oop - __ bpr(Assembler::rc_nz, false, Assembler::pt, L1, ok); - __ delayed()->nop(); - __ stop("null entry point found in itable's offset table"); - __ bind(ok); - __ verify_oop(L1); -#endif // ASSERT - __ cmp(G5_interface, L1); + // If the entry is NULL then we've reached the end of the table + // without finding the expected interface, so throw an exception + Label throw_icce; + __ bpr(Assembler::rc_z, false, Assembler::pn, L1, throw_icce); + __ delayed()->cmp(G5_interface, L1); __ brx(Assembler::notEqual, true, Assembler::pn, search); __ delayed()->add(L0, itableOffsetEntry::size() * wordSize, L0); @@ -223,24 +218,30 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) { __ JMP(G3_scratch, 0); __ delayed()->nop(); + __ bind(throw_icce); + Address icce(G3_scratch, StubRoutines::throw_IncompatibleClassChangeError_entry()); + __ jump_to(icce, 0); + __ delayed()->restore(); + masm->flush(); + + guarantee(__ pc() <= s->code_end(), "overflowed buffer"); + s->set_exception_points(npe_addr, ame_addr); return s; } int VtableStub::pd_code_size_limit(bool is_vtable_stub) { - if (TraceJumps || DebugVtables || CountCompiledCalls || VerifyOops) return 999; + if (TraceJumps || DebugVtables || CountCompiledCalls || VerifyOops) return 1000; else { const int slop = 2*BytesPerInstWord; // sethi;add (needed for long offsets) if (is_vtable_stub) { const int basic = 5*BytesPerInstWord; // ld;ld;ld,jmp,nop return basic + slop; } else { -#ifdef ASSERT - return 999; -#endif // ASSERT - const int basic = 17*BytesPerInstWord; // save, ld, ld, sll, and, add, add, ld, cmp, br, add, ld, add, ld, ld, jmp, restore + // save, ld, ld, sll, and, add, add, ld, cmp, br, add, ld, add, ld, ld, jmp, restore, sethi, jmpl, restore + const int basic = (20 LP64_ONLY(+ 6)) * BytesPerInstWord; return (basic + slop); } } @@ -252,29 +253,3 @@ int VtableStub::pd_code_alignment() { const unsigned int icache_line_size = 32; return icache_line_size; } - - -//Reconciliation History -// 1.2 97/12/09 17:13:31 vtableStubs_i486.cpp -// 1.4 98/01/21 19:18:37 vtableStubs_i486.cpp -// 1.5 98/02/13 16:33:55 vtableStubs_i486.cpp -// 1.7 98/03/05 17:17:28 vtableStubs_i486.cpp -// 1.9 98/05/18 09:26:17 vtableStubs_i486.cpp -// 1.10 98/05/26 16:28:13 vtableStubs_i486.cpp -// 1.11 98/05/27 08:51:35 vtableStubs_i486.cpp -// 1.12 98/06/15 15:04:12 vtableStubs_i486.cpp -// 1.13 98/07/28 18:44:22 vtableStubs_i486.cpp -// 1.15 98/08/28 11:31:19 vtableStubs_i486.cpp -// 1.16 98/09/02 12:58:31 vtableStubs_i486.cpp -// 1.17 98/09/04 12:15:52 vtableStubs_i486.cpp -// 1.18 98/11/19 11:55:24 vtableStubs_i486.cpp -// 1.19 99/01/12 14:57:56 vtableStubs_i486.cpp -// 1.20 99/01/19 17:42:52 vtableStubs_i486.cpp -// 1.22 99/01/21 10:29:25 vtableStubs_i486.cpp -// 1.30 99/06/02 15:27:39 vtableStubs_i486.cpp -// 1.26 99/06/24 14:25:07 vtableStubs_i486.cpp -// 1.23 99/02/22 14:37:52 vtableStubs_i486.cpp -// 1.28 99/06/29 18:06:17 vtableStubs_i486.cpp -// 1.29 99/07/22 17:03:44 vtableStubs_i486.cpp -// 1.30 99/08/11 09:33:27 vtableStubs_i486.cpp -//End diff --git a/src/cpu/x86/vm/stubGenerator_x86_32.cpp b/src/cpu/x86/vm/stubGenerator_x86_32.cpp index 98c1ce59a..5ea4177f9 100644 --- a/src/cpu/x86/vm/stubGenerator_x86_32.cpp +++ b/src/cpu/x86/vm/stubGenerator_x86_32.cpp @@ -2151,6 +2151,7 @@ class StubGenerator: public StubCodeGenerator { // These entry points require SharedInfo::stack0 to be set up in non-core builds // and need to be relocatable, so they each fabricate a RuntimeStub internally. StubRoutines::_throw_AbstractMethodError_entry = generate_throw_exception("AbstractMethodError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_AbstractMethodError), false); + StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError), false); StubRoutines::_throw_ArithmeticException_entry = generate_throw_exception("ArithmeticException throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_ArithmeticException), true); StubRoutines::_throw_NullPointerException_entry = generate_throw_exception("NullPointerException throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException), true); StubRoutines::_throw_NullPointerException_at_call_entry= generate_throw_exception("NullPointerException at call throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call), false); diff --git a/src/cpu/x86/vm/stubGenerator_x86_64.cpp b/src/cpu/x86/vm/stubGenerator_x86_64.cpp index 738beafa3..720222b31 100644 --- a/src/cpu/x86/vm/stubGenerator_x86_64.cpp +++ b/src/cpu/x86/vm/stubGenerator_x86_64.cpp @@ -2832,6 +2832,13 @@ class StubGenerator: public StubCodeGenerator { throw_AbstractMethodError), false); + StubRoutines::_throw_IncompatibleClassChangeError_entry = + generate_throw_exception("IncompatibleClassChangeError throw_exception", + CAST_FROM_FN_PTR(address, + SharedRuntime:: + throw_IncompatibleClassChangeError), + false); + StubRoutines::_throw_ArithmeticException_entry = generate_throw_exception("ArithmeticException throw_exception", CAST_FROM_FN_PTR(address, diff --git a/src/cpu/x86/vm/vtableStubs_x86_32.cpp b/src/cpu/x86/vm/vtableStubs_x86_32.cpp index fcf84f7b4..09d37901e 100644 --- a/src/cpu/x86/vm/vtableStubs_x86_32.cpp +++ b/src/cpu/x86/vm/vtableStubs_x86_32.cpp @@ -138,29 +138,21 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) { __ round_to(rbx, BytesPerLong); } - Label hit, next, entry; + Label hit, next, entry, throw_icce; - __ jmp(entry); + __ jmpb(entry); __ bind(next); __ addl(rbx, itableOffsetEntry::size() * wordSize); __ bind(entry); -#ifdef ASSERT - // Check that the entry is non-null - if (DebugVtables) { - Label L; - __ pushl(rbx); - __ movl(rbx, Address(rbx, itableOffsetEntry::interface_offset_in_bytes())); - __ testl(rbx, rbx); - __ jcc(Assembler::notZero, L); - __ stop("null entry point found in itable's offset table"); - __ bind(L); - __ popl(rbx); - } -#endif - __ cmpl(rax, Address(rbx, itableOffsetEntry::interface_offset_in_bytes())); + // If the entry is NULL then we've reached the end of the table + // without finding the expected interface, so throw an exception + __ movl(rdx, Address(rbx, itableOffsetEntry::interface_offset_in_bytes())); + __ testl(rdx, rdx); + __ jcc(Assembler::zero, throw_icce); + __ cmpl(rax, rdx); __ jcc(Assembler::notEqual, next); // We found a hit, move offset into rbx, @@ -194,7 +186,15 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) { address ame_addr = __ pc(); __ jmp(Address(method, methodOopDesc::from_compiled_offset())); + __ bind(throw_icce); + // Restore saved register + __ popl(rdx); + __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); + masm->flush(); + + guarantee(__ pc() <= s->code_end(), "overflowed buffer"); + s->set_exception_points(npe_addr, ame_addr); return s; } @@ -207,7 +207,7 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) { return (DebugVtables ? 210 : 16) + (CountCompiledCalls ? 6 : 0); } else { // Itable stub size - return (DebugVtables ? 140 : 55) + (CountCompiledCalls ? 6 : 0); + return (DebugVtables ? 144 : 64) + (CountCompiledCalls ? 6 : 0); } } diff --git a/src/cpu/x86/vm/vtableStubs_x86_64.cpp b/src/cpu/x86/vm/vtableStubs_x86_64.cpp index fb6e87bb7..c68f7f363 100644 --- a/src/cpu/x86/vm/vtableStubs_x86_64.cpp +++ b/src/cpu/x86/vm/vtableStubs_x86_64.cpp @@ -153,7 +153,7 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) { // Round up to align_object_offset boundary __ round_to_q(rbx, BytesPerLong); } - Label hit, next, entry; + Label hit, next, entry, throw_icce; __ jmpb(entry); @@ -162,22 +162,13 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) { __ bind(entry); -#ifdef ASSERT - // Check that the entry is non-null - if (DebugVtables) { - Label L; - __ pushq(rbx); - __ movq(rbx, Address(rbx, itableOffsetEntry::interface_offset_in_bytes())); - __ testq(rbx, rbx); - __ jcc(Assembler::notZero, L); - __ stop("null entry point found in itable's offset table"); - __ bind(L); - __ popq(rbx); - } -#endif - - __ cmpq(rax, Address(rbx, itableOffsetEntry::interface_offset_in_bytes())); - __ jcc(Assembler::notEqual, next); + // If the entry is NULL then we've reached the end of the table + // without finding the expected interface, so throw an exception + __ movq(j_rarg1, Address(rbx, itableOffsetEntry::interface_offset_in_bytes())); + __ testq(j_rarg1, j_rarg1); + __ jcc(Assembler::zero, throw_icce); + __ cmpq(rax, j_rarg1); + __ jccb(Assembler::notEqual, next); // We found a hit, move offset into j_rarg1 __ movl(j_rarg1, Address(rbx, itableOffsetEntry::offset_offset_in_bytes())); @@ -203,23 +194,31 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) { #ifdef ASSERT - if (DebugVtables) { - Label L2; - __ cmpq(method, (int)NULL); - __ jcc(Assembler::equal, L2); - __ cmpq(Address(method, methodOopDesc::from_compiled_offset()), (int)NULL_WORD); - __ jcc(Assembler::notZero, L2); - __ stop("compiler entrypoint is null"); - __ bind(L2); - } + if (DebugVtables) { + Label L2; + __ cmpq(method, (int)NULL); + __ jcc(Assembler::equal, L2); + __ cmpq(Address(method, methodOopDesc::from_compiled_offset()), (int)NULL_WORD); + __ jcc(Assembler::notZero, L2); + __ stop("compiler entrypoint is null"); + __ bind(L2); + } #endif // ASSERT - // rbx: methodOop - // j_rarg0: receiver - address ame_addr = __ pc(); - __ jmp(Address(method, methodOopDesc::from_compiled_offset())); + // rbx: methodOop + // j_rarg0: receiver + address ame_addr = __ pc(); + __ jmp(Address(method, methodOopDesc::from_compiled_offset())); + + __ bind(throw_icce); + // Restore saved register + __ popq(j_rarg1); + __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); __ flush(); + + guarantee(__ pc() <= s->code_end(), "overflowed buffer"); + s->set_exception_points(npe_addr, ame_addr); return s; } @@ -230,7 +229,7 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) { return (DebugVtables ? 512 : 24) + (CountCompiledCalls ? 13 : 0); } else { // Itable stub size - return (DebugVtables ? 636 : 64) + (CountCompiledCalls ? 13 : 0); + return (DebugVtables ? 636 : 72) + (CountCompiledCalls ? 13 : 0); } } diff --git a/src/share/vm/oops/klassVtable.cpp b/src/share/vm/oops/klassVtable.cpp index 1b105cd2d..84ce0c58a 100644 --- a/src/share/vm/oops/klassVtable.cpp +++ b/src/share/vm/oops/klassVtable.cpp @@ -735,7 +735,7 @@ klassItable::klassItable(instanceKlassHandle klass) { } } - // This lenght of the itable was either zero, or it has not yet been initialized. + // The length of the itable was either zero, or it has not yet been initialized. _table_offset = 0; _size_offset_table = 0; _size_method_table = 0; @@ -870,16 +870,19 @@ static int initialize_count = 0; // Initialization void klassItable::initialize_itable(bool checkconstraints, TRAPS) { - // Cannot be setup doing bootstrapping - if (Universe::is_bootstrapping()) return; - - int num_interfaces = nof_interfaces(); + // Cannot be setup doing bootstrapping, interfaces don't have + // itables, and klass with only ones entry have empty itables + if (Universe::is_bootstrapping() || + _klass->is_interface() || + _klass->itable_length() == itableOffsetEntry::size()) return; + + // There's alway an extra itable entry so we can null-terminate it. + guarantee(size_offset_table() >= 1, "too small"); + int num_interfaces = size_offset_table() - 1; if (num_interfaces > 0) { - if (TraceItables) tty->print_cr("%3d: Initializing itables for %s", ++initialize_count, _klass->name()->as_C_string()); + if (TraceItables) tty->print_cr("%3d: Initializing itables for %s", ++initialize_count, + _klass->name()->as_C_string()); - // In debug mode, we got an extra NULL/NULL entry - debug_only(num_interfaces--); - assert(num_interfaces > 0, "to few interfaces in offset itable"); // Interate through all interfaces int i; @@ -890,12 +893,10 @@ void klassItable::initialize_itable(bool checkconstraints, TRAPS) { initialize_itable_for_interface(ioe->offset(), interf_h, checkconstraints, CHECK); } -#ifdef ASSERT - // Check that the last entry is empty - itableOffsetEntry* ioe = offset_entry(i); - assert(ioe->interface_klass() == NULL && ioe->offset() == 0, "terminator entry missing"); -#endif } + // Check that the last entry is empty + itableOffsetEntry* ioe = offset_entry(size_offset_table() - 1); + guarantee(ioe->interface_klass() == NULL && ioe->offset() == 0, "terminator entry missing"); } @@ -972,7 +973,7 @@ void klassItable::initialize_itable_for_interface(int method_table_offset, Klass } } -// Update entry for specic methodOop +// Update entry for specific methodOop void klassItable::initialize_with_method(methodOop m) { itableMethodEntry* ime = method_entry(0); for(int i = 0; i < _size_method_table; i++) { @@ -1085,12 +1086,8 @@ int klassItable::compute_itable_size(objArrayHandle transitive_interfaces) { CountInterfacesClosure cic; visit_all_interfaces(transitive_interfaces(), &cic); - // Add one extra entry in debug mode, so we can null-terminate the table - int nof_methods = cic.nof_methods(); - int nof_interfaces = cic.nof_interfaces(); - debug_only(if (nof_interfaces > 0) nof_interfaces++); - - int itable_size = calc_itable_size(nof_interfaces, nof_methods); + // There's alway an extra itable entry so we can null-terminate it. + int itable_size = calc_itable_size(cic.nof_interfaces() + 1, cic.nof_methods()); // Statistics update_stats(itable_size * HeapWordSize); @@ -1110,8 +1107,8 @@ void klassItable::setup_itable_offset_table(instanceKlassHandle klass) { int nof_methods = cic.nof_methods(); int nof_interfaces = cic.nof_interfaces(); - // Add one extra entry in debug mode, so we can null-terminate the table - debug_only(if (nof_interfaces > 0) nof_interfaces++); + // Add one extra entry so we can null-terminate the table + nof_interfaces++; assert(compute_itable_size(objArrayHandle(klass->transitive_interfaces())) == calc_itable_size(nof_interfaces, nof_methods), diff --git a/src/share/vm/oops/klassVtable.hpp b/src/share/vm/oops/klassVtable.hpp index 221e1d21d..2ef1848f5 100644 --- a/src/share/vm/oops/klassVtable.hpp +++ b/src/share/vm/oops/klassVtable.hpp @@ -259,7 +259,7 @@ class klassItable : public ResourceObj { itableMethodEntry* method_entry(int i) { assert(0 <= i && i <= _size_method_table, "index out of bounds"); return &((itableMethodEntry*)method_start())[i]; } - int nof_interfaces() { return _size_offset_table; } + int size_offset_table() { return _size_offset_table; } // Initialization void initialize_itable(bool checkconstraints, TRAPS); diff --git a/src/share/vm/runtime/sharedRuntime.cpp b/src/share/vm/runtime/sharedRuntime.cpp index e9a568588..cda256b74 100644 --- a/src/share/vm/runtime/sharedRuntime.cpp +++ b/src/share/vm/runtime/sharedRuntime.cpp @@ -467,6 +467,11 @@ JRT_ENTRY(void, SharedRuntime::throw_AbstractMethodError(JavaThread* thread)) throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_AbstractMethodError()); JRT_END +JRT_ENTRY(void, SharedRuntime::throw_IncompatibleClassChangeError(JavaThread* thread)) + // These errors occur only at call sites + throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_IncompatibleClassChangeError(), "vtable stub"); +JRT_END + JRT_ENTRY(void, SharedRuntime::throw_ArithmeticException(JavaThread* thread)) throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_ArithmeticException(), "/ by zero"); JRT_END diff --git a/src/share/vm/runtime/sharedRuntime.hpp b/src/share/vm/runtime/sharedRuntime.hpp index b91837f36..b2138d0a7 100644 --- a/src/share/vm/runtime/sharedRuntime.hpp +++ b/src/share/vm/runtime/sharedRuntime.hpp @@ -104,6 +104,7 @@ class SharedRuntime: AllStatic { STACK_OVERFLOW }; static void throw_AbstractMethodError(JavaThread* thread); + static void throw_IncompatibleClassChangeError(JavaThread* thread); static void throw_ArithmeticException(JavaThread* thread); static void throw_NullPointerException(JavaThread* thread); static void throw_NullPointerException_at_call(JavaThread* thread); diff --git a/src/share/vm/runtime/stubRoutines.cpp b/src/share/vm/runtime/stubRoutines.cpp index 63b30d86d..bdad678b0 100644 --- a/src/share/vm/runtime/stubRoutines.cpp +++ b/src/share/vm/runtime/stubRoutines.cpp @@ -40,6 +40,7 @@ address StubRoutines::_call_stub_entry = NULL; address StubRoutines::_catch_exception_entry = NULL; address StubRoutines::_forward_exception_entry = NULL; address StubRoutines::_throw_AbstractMethodError_entry = NULL; +address StubRoutines::_throw_IncompatibleClassChangeError_entry = NULL; address StubRoutines::_throw_ArithmeticException_entry = NULL; address StubRoutines::_throw_NullPointerException_entry = NULL; address StubRoutines::_throw_NullPointerException_at_call_entry = NULL; diff --git a/src/share/vm/runtime/stubRoutines.hpp b/src/share/vm/runtime/stubRoutines.hpp index 17246a8bc..677419164 100644 --- a/src/share/vm/runtime/stubRoutines.hpp +++ b/src/share/vm/runtime/stubRoutines.hpp @@ -84,6 +84,7 @@ class StubRoutines: AllStatic { static address _forward_exception_entry; static address _catch_exception_entry; static address _throw_AbstractMethodError_entry; + static address _throw_IncompatibleClassChangeError_entry; static address _throw_ArithmeticException_entry; static address _throw_NullPointerException_entry; static address _throw_NullPointerException_at_call_entry; @@ -184,6 +185,7 @@ class StubRoutines: AllStatic { static address forward_exception_entry() { return _forward_exception_entry; } // Implicit exceptions static address throw_AbstractMethodError_entry() { return _throw_AbstractMethodError_entry; } + static address throw_IncompatibleClassChangeError_entry(){ return _throw_IncompatibleClassChangeError_entry; } static address throw_ArithmeticException_entry() { return _throw_ArithmeticException_entry; } static address throw_NullPointerException_entry() { return _throw_NullPointerException_entry; } static address throw_NullPointerException_at_call_entry(){ return _throw_NullPointerException_at_call_entry; } -- GitLab