//http://aospxref.com/android-13.0.0_r3/xref/art/runtime/interpreter/interpreter.cc
staticinlineJValueExecute(Thread*self,constCodeItemDataAccessor&accessor,ShadowFrame&shadow_frame,JValueresult_register,boolstay_in_interpreter=false,boolfrom_deoptimize=false)REQUIRES_SHARED(Locks::mutator_lock_){DCHECK(!shadow_frame.GetMethod()->IsAbstract());DCHECK(!shadow_frame.GetMethod()->IsNative());//----------------------------------------------------------
if(!stay_in_interpreter&&!self->IsForceInterpreter()){jit::Jit*jit=Runtime::Current()->GetJit();if(jit!=nullptr){jit->MethodEntered(self,shadow_frame.GetMethod());if(jit->CanInvokeCompiledCode(method)){JValueresult;// Pop the shadow frame before calling into compiled code.
self->PopShadowFrame();// Calculate the offset of the first input reg. The input registers are in the high regs.
// It's ok to access the code item here since JIT code will have been touched by the
// interpreter and compiler already.
uint16_targ_offset=accessor.RegistersSize()-accessor.InsSize();ArtInterpreterToCompiledCodeBridge(self,nullptr,&shadow_frame,arg_offset,&result);// Push the shadow frame back as the caller will expect it.
self->PushShadowFrame(&shadow_frame);returnresult;}}}}ArtMethod*method=shadow_frame.GetMethod();DCheckStaticState(self,method);// Lock counting is a special version of accessibility checks, and for simplicity and
// reduction of template parameters, we gate it behind access-checks mode.
DCHECK_IMPLIES(method->SkipAccessChecks(),!method->MustCountLocks());VLOG(interpreter)<<"Interpreting "<<method->PrettyMethod();returnExecuteSwitch(self,accessor,shadow_frame,result_register,/*interpret_one_instruction=*/false);}
//http://aospxref.com/android-13.0.0_r3/xref/art/runtime/interpreter/interpreter.cc#ExecuteSwitch
staticJValueExecuteSwitch(Thread*self,constCodeItemDataAccessor&accessor,ShadowFrame&shadow_frame,JValueresult_register,boolinterpret_one_instruction)REQUIRES_SHARED(Locks::mutator_lock_)//http://aospxref.com/android-13.0.0_r3/xref/art/runtime/interpreter/interpreter_switch_impl.h
->ALWAYS_INLINEJValueExecuteSwitchImpl(Thread*self,constCodeItemDataAccessor&accessor,ShadowFrame&shadow_frame,JValueresult_register,boolinterpret_one_instruction)//http://aospxref.com/android-13.0.0_r3/xref/art/runtime/interpreter/interpreter_switch_impl-inl.h
->template<booldo_access_check,booltransaction_active>voidExecuteSwitchImplCpp(SwitchImplContext*ctx){Thread*self=ctx->self;constCodeItemDataAccessor&accessor=ctx->accessor;ShadowFrame&shadow_frame=ctx->shadow_frame;self->VerifyStack();uint32_tdex_pc=shadow_frame.GetDexPC();constauto*constinstrumentation=Runtime::Current()->GetInstrumentation();constuint16_t*constinsns=accessor.Insns();constInstruction*next=Instruction::At(insns+dex_pc);DCHECK(!shadow_frame.GetForceRetryInstruction())<<"Entered interpreter from invoke without retry instruction being handled!";boolconstinterpret_one_instruction=ctx->interpret_one_instruction;while(true){constInstruction*constinst=next;dex_pc=inst->GetDexPc(insns);shadow_frame.SetDexPC(dex_pc);TraceExecution(shadow_frame,inst,dex_pc);uint16_tinst_data=inst->Fetch16(0);boolexit=false;boolsuccess;// Moved outside to keep frames small under asan.
if(InstructionHandler<do_access_check,transaction_active,Instruction::kInvalidFormat>(ctx,instrumentation,self,shadow_frame,dex_pc,inst,inst_data,next,exit).Preamble()){DCHECK_EQ(self->IsExceptionPending(),inst->Opcode(inst_data)==Instruction::MOVE_EXCEPTION);switch(inst->Opcode(inst_data)){//这里可以看到对不同的OPCODE进行处理
#define OPCODE_CASE(OPCODE, OPCODE_NAME, NAME, FORMAT, i, a, e, v) \
case OPCODE: { \
next = inst->RelativeAt(Instruction::SizeInCodeUnits(Instruction::FORMAT)); \
success = OP_##OPCODE_NAME<do_access_check, transaction_active>( \
ctx, instrumentation, self, shadow_frame, dex_pc, inst, inst_data, next, exit); \
if (success && LIKELY(!interpret_one_instruction)) { \
continue; \
} \
break; \
}
DEX_INSTRUCTION_LIST(OPCODE_CASE)#undef OPCODE_CASE
}}if(exit){shadow_frame.SetDexPC(dex::kDexNoIndex);return;// Return statement or debugger forced exit.
}if(self->IsExceptionPending()){if(!InstructionHandler<do_access_check,transaction_active,Instruction::kInvalidFormat>(ctx,instrumentation,self,shadow_frame,dex_pc,inst,inst_data,next,exit).HandlePendingException()){shadow_frame.SetDexPC(dex::kDexNoIndex);return;// Locally unhandled exception - return to caller.
}// Continue execution in the catch block.
}if(interpret_one_instruction){shadow_frame.SetDexPC(next->GetDexPc(insns));// Record where we stopped.
ctx->result=ctx->result_register;return;}}}// NOLINT(readability/fn_size)
functionforceinterpreter(){varlibartmodule=Process.getModuleByName("libart.so");varforceinterpreter_addr=libartmodule.getExportByName("forceinterpreter");console.log("forceinterpreter:"+forceinterpreter_addr);varforceinterpreter=newNativeFunction(forceinterpreter_addr,"void",[]);Interceptor.attach(forceinterpreter_addr,{onEnter:function(args){console.log("go into forceinterpreter");},onLeave:function(retval){console.log("leave forceinterpreter");}});forceinterpreter();}functionhook_start(){varlibcModule=Process.getModuleByName("libc.so");varstrstr=libcModule.getExportByName("strstr");Interceptor.attach(strstr,{onEnter:function(args){this.arg0=args[0];this.arg1=args[1];this.method_name=ptr(this.arg0).readUtf8String();this.call_name=ptr(this.arg1).readUtf8String();if(this.call_name.indexOf("PerformCallFlag")!=-1){console.log(this.method_name);}if(this.call_name.indexOf("InvokeWithArgArrayFlag")!=-1){console.log(this.method_name);}},onLeave:function(retval){if(this.call_name.indexOf("InvokeWithArgArrayFlag")!=-1||this.call_name.indexOf("PerformCallFlag")!=-1){retval.replace(0);}}})}functionmain(){forceinterpreter();hook_start();}setImmediate(main)