Skip to content
This repository has been archived by the owner on Mar 15, 2022. It is now read-only.

Commit

Permalink
Merge pull request #458 from erozenfeld/SynchMethods
Browse files Browse the repository at this point in the history
Support for synchronized methods.
  • Loading branch information
erozenfeld committed Apr 17, 2015
2 parents 8a66b4f + ac30783 commit 1f1bdd6
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 31 deletions.
2 changes: 1 addition & 1 deletion include/Reader/reader.h
Original file line number Diff line number Diff line change
Expand Up @@ -2846,7 +2846,7 @@ class ReaderBase {
virtual IRNode *refAnyType(IRNode *Arg1) = 0;
virtual IRNode *refAnyVal(IRNode *Val, CORINFO_RESOLVED_TOKEN *ResolvedToken);
virtual void rethrow() = 0;
virtual void returnOpcode(IRNode *Opr, bool IsSynchronousMethod) = 0;
virtual void returnOpcode(IRNode *Opr, bool IsSynchronizedMethod) = 0;
virtual IRNode *shift(ReaderBaseNS::ShiftOpcode Opcode, IRNode *ShiftAmount,
IRNode *ShiftOperand) = 0;
virtual IRNode *sizeofOpcode(CORINFO_RESOLVED_TOKEN *ResolvedToken) = 0;
Expand Down
16 changes: 15 additions & 1 deletion include/Reader/readerir.h
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ class GenIR : public ReaderBase {
};

void rethrow() override { throw NotYetImplementedException("rethrow"); };
void returnOpcode(IRNode *Opr, bool SynchronousMethod) override;
void returnOpcode(IRNode *Opr, bool IsSynchronizedMethod) override;
IRNode *shift(ReaderBaseNS::ShiftOpcode Opcode, IRNode *ShiftAmount,
IRNode *ShiftOperand) override;
IRNode *sizeofOpcode(CORINFO_RESOLVED_TOKEN *ResolvedToken) override;
Expand Down Expand Up @@ -755,6 +755,13 @@ class GenIR : public ReaderBase {
IRNode *callRuntimeHandleHelper(CorInfoHelpFunc Helper, IRNode *Arg1,
IRNode *Arg2, IRNode *NullCheckArg);

/// Generate a helper call to enter or exit a monitor used by synchronized
/// methods.
///
/// \param IsEnter true if the monitor should be entered; false if the monitor
/// should be exited.
void callMonitorHelper(bool IsEnter);

IRNode *convertToBoxHelperArgumentType(IRNode *Opr,
CorInfoType CorType) override;

Expand Down Expand Up @@ -1274,6 +1281,13 @@ class GenIR : public ReaderBase {
bool NeedsSecurityObject;
llvm::BasicBlock *EntryBlock;
llvm::Instruction *TempInsertionPoint;
IRNode *MethodSyncHandle; ///< If the method is synchronized, this is
///< the handle used for entering and exiting
///< the monitor.
llvm::Value *SyncFlag; ///< For synchronized methods this flag
///< indicates whether the monitor has been
///< entered. It is set and checked by monitor
///< helpers.
uint32_t TargetPointerSizeInBits;
const uint32_t UnmanagedAddressSpace = 0;
const uint32_t ManagedAddressSpace = 1;
Expand Down
101 changes: 72 additions & 29 deletions lib/Reader/readerir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,9 +303,10 @@ void GenIR::readerPrePass(uint8_t *Buffer, uint32_t NumBytes) {
ABIMethodSignature(MethodSignature, *this, *JitContext->TheABIInfo);
Function = ABIMethodSig.createFunction(*this, *JitContext->CurrentModule);

EntryBlock = BasicBlock::Create(*JitContext->LLVMContext, "entry", Function);
llvm::LLVMContext &LLVMContext = *JitContext->LLVMContext;
EntryBlock = BasicBlock::Create(LLVMContext, "entry", Function);

LLVMBuilder = new IRBuilder<>(*this->JitContext->LLVMContext);
LLVMBuilder = new IRBuilder<>(LLVMContext);
LLVMBuilder->SetInsertPoint(EntryBlock);

// Note numArgs may exceed the IL argument count when there
Expand Down Expand Up @@ -367,9 +368,26 @@ void GenIR::readerPrePass(uint8_t *Buffer, uint32_t NumBytes) {
// Check for special cases where the Jit needs to do extra work.
const uint32_t MethodFlags = getCurrentMethodAttribs();

// TODO: support for synchronized methods
// Check for synchronized method. If a method is synchronized the JIT is
// required to insert a helper call to MONITOR_ENTER before we start the user
// code. A similar call to MONITOR_EXIT will be placed at the return site.
// TODO: when we start catching exceptions we should create a try/fault for
// the entire method so that we can exit the monitor on unhandled exceptions.
MethodSyncHandle = nullptr;
SyncFlag = nullptr;
if (MethodFlags & CORINFO_FLG_SYNCH) {
throw NotYetImplementedException("synchronized method");
MethodSyncHandle = rdrGetCritSect();
Type *SyncFlagType = Type::getInt8Ty(LLVMContext);

// Create address taken local SyncFlag. This will be passed by address to
// MONITOR_ENTER and MONITOR_EXIT. MONITOR_ENTER will set SyncFlag once lock
// has been obtained, MONITOR_EXIT only releases lock if SyncFlag is set.
SyncFlag = createTemporary(SyncFlagType, "SyncFlag");
Constant *ZeroConst = Constant::getNullValue(SyncFlagType);
LLVMBuilder->CreateStore(ZeroConst, SyncFlag);

const bool IsEnter = true;
callMonitorHelper(IsEnter);
}

if ((JitFlags & CORJIT_FLG_DEBUG_CODE) && !(JitFlags & CORJIT_FLG_IL_STUB)) {
Expand Down Expand Up @@ -539,6 +557,19 @@ void GenIR::insertIRForSecurityObject() {
// via the GC encoding.
}

void GenIR::callMonitorHelper(bool IsEnter) {
CorInfoHelpFunc HelperId;
const uint32_t MethodFlags = getCurrentMethodAttribs();
if (MethodFlags & CORINFO_FLG_STATIC) {
HelperId =
IsEnter ? CORINFO_HELP_MON_ENTER_STATIC : CORINFO_HELP_MON_EXIT_STATIC;
} else {
HelperId = IsEnter ? CORINFO_HELP_MON_ENTER : CORINFO_HELP_MON_EXIT;
}
callHelperImpl(HelperId, Type::getVoidTy(*JitContext->LLVMContext),
MethodSyncHandle, (IRNode *)SyncFlag);
}

#pragma endregion

#pragma region UTILITIES
Expand Down Expand Up @@ -4239,44 +4270,56 @@ bool GenIR::fgOptRecurse(mdToken Token) {
return true;
}

void GenIR::returnOpcode(IRNode *Opr, bool IsSynchronousMethod) {
void GenIR::returnOpcode(IRNode *Opr, bool IsSynchronizedMethod) {
const ABIArgInfo &ResultInfo = ABIMethodSig.getResultInfo();
const CallArgType &ResultArgType = MethodSignature.getResultType();
CorInfoType ResultCorType = ResultArgType.CorType;
Value *ResultValue = nullptr;
bool IsVoidReturn = ResultCorType == CORINFO_TYPE_VOID;

if (ResultCorType == CORINFO_TYPE_VOID) {
if (IsVoidReturn) {
assert(Opr == nullptr);
assert(ResultInfo.getType()->isVoidTy());
LLVMBuilder->CreateRetVoid();
return;
}
} else {
assert(Opr != nullptr);

assert(Opr != nullptr);
if (ResultInfo.getKind() == ABIArgInfo::Indirect) {
Type *ResultTy = ResultInfo.getType();
ResultValue = convertFromStackType(Opr, ResultCorType, ResultTy);

Value *ResultValue = nullptr;
if (ResultInfo.getKind() == ABIArgInfo::Indirect) {
Type *ResultTy = ResultInfo.getType();
ResultValue = convertFromStackType(Opr, ResultCorType, ResultTy);

CORINFO_CLASS_HANDLE ResultClass = ResultArgType.Class;
if (JitContext->JitInfo->isStructRequiringStackAllocRetBuf(ResultClass) ==
TRUE) {
// The return buffer must be on the stack; a simple store will suffice.
LLVMBuilder->CreateStore(ResultValue, IndirectResult);
CORINFO_CLASS_HANDLE ResultClass = ResultArgType.Class;
if (JitContext->JitInfo->isStructRequiringStackAllocRetBuf(ResultClass) ==
TRUE) {
// The return buffer must be on the stack; a simple store will suffice.
LLVMBuilder->CreateStore(ResultValue, IndirectResult);
} else {
const bool IsVolatile = false;
storeIndirectArg(ResultArgType, ResultValue, IndirectResult,
IsVolatile);
}

ResultValue = IndirectResult;
} else {
const bool IsVolatile = false;
storeIndirectArg(ResultArgType, ResultValue, IndirectResult, IsVolatile);
Type *ResultTy = getType(ResultCorType, ResultArgType.Class);
ResultValue = convertFromStackType(Opr, ResultCorType, ResultTy);
ResultValue =
ABISignature::coerce(*this, ResultInfo.getType(), ResultValue);
}
}

ResultValue = IndirectResult;
} else {
Type *ResultTy = getType(ResultCorType, ResultArgType.Class);
ResultValue = convertFromStackType(Opr, ResultCorType, ResultTy);
ResultValue =
ABISignature::coerce(*this, ResultInfo.getType(), ResultValue);
// If the method is synchronized, then we must insert a call to MONITOR_EXIT
// before returning. The call to MONITOR_EXIT must occur after the return
// value has been calculated.
if (IsSynchronizedMethod) {
const bool IsEnter = false;
callMonitorHelper(IsEnter);
}

LLVMBuilder->CreateRet(ResultValue);
if (IsVoidReturn) {
LLVMBuilder->CreateRetVoid();
} else {
LLVMBuilder->CreateRet(ResultValue);
}
}

bool GenIR::needSequencePoints() { return false; }
Expand Down

0 comments on commit 1f1bdd6

Please sign in to comment.