private static void EmitNativeCall(ArmEmitterContext context, Operand nativeContextPtr, Operand funcAddr, bool isJump = false) { context.StoreToContext(); if (isJump) { context.Tailcall(funcAddr, nativeContextPtr); } else { OpCode op = context.CurrOp; Operand returnAddress = context.Call(funcAddr, OperandType.I64, nativeContextPtr); context.LoadFromContext(); // Note: The return value of a translated function is always an Int64 with the address execution has // returned to. We expect this address to be immediately after the current instruction, if it isn't we // keep returning until we reach the dispatcher. Operand nextAddr = Const((long)op.Address + op.OpCodeSizeInBytes); // Try to continue within this block. // If the return address isn't to our next instruction, we need to return so the JIT can figure out // what to do. Operand lblContinue = context.GetLabel(nextAddr.Value); // We need to clear out the call flag for the return address before comparing it. context.BranchIf(lblContinue, context.BitwiseAnd(returnAddress, Const(~CallFlag)), nextAddr, Comparison.Equal); context.Return(returnAddress); } }
private static void EmitTableBranch(ArmEmitterContext context, Operand guestAddress, bool isJump) { context.StoreToContext(); if (guestAddress.Type == OperandType.I32) { guestAddress = context.ZeroExtend32(OperandType.I64, guestAddress); } // Store the target guest address into the native context. The stubs uses this address to dispatch into the // next translation. Operand nativeContext = context.LoadArgument(OperandType.I64, 0); Operand dispAddressAddr = context.Add(nativeContext, Const((ulong)NativeContext.GetDispatchAddressOffset())); context.Store(dispAddressAddr, guestAddress); Operand hostAddress; // If address is mapped onto the function table, we can skip the table walk. Otherwise we fallback // onto the dispatch stub. if (guestAddress.Kind == OperandKind.Constant && context.FunctionTable.IsValid(guestAddress.Value)) { Operand hostAddressAddr = !context.HasPtc ? Const(ref context.FunctionTable.GetValue(guestAddress.Value)) : Const(ref context.FunctionTable.GetValue(guestAddress.Value), new Symbol(SymbolType.FunctionTable, guestAddress.Value)); hostAddress = context.Load(OperandType.I64, hostAddressAddr); } else { hostAddress = !context.HasPtc ? Const((long)context.Stubs.DispatchStub) : Const((long)context.Stubs.DispatchStub, Ptc.DispatchStubSymbol); } if (isJump) { context.Tailcall(hostAddress, nativeContext); } else { OpCode op = context.CurrOp; Operand returnAddress = context.Call(hostAddress, OperandType.I64, nativeContext); context.LoadFromContext(); // Note: The return value of a translated function is always an Int64 with the address execution has // returned to. We expect this address to be immediately after the current instruction, if it isn't we // keep returning until we reach the dispatcher. Operand nextAddr = Const((long)op.Address + op.OpCodeSizeInBytes); // Try to continue within this block. // If the return address isn't to our next instruction, we need to return so the JIT can figure out // what to do. Operand lblContinue = context.GetLabel(nextAddr.Value); context.BranchIf(lblContinue, returnAddress, nextAddr, Comparison.Equal, BasicBlockFrequency.Cold); context.Return(returnAddress); } }