| 1 | // Licensed to the .NET Foundation under one or more agreements. |
| 2 | // The .NET Foundation licenses this file to you under the MIT license. |
| 3 | // See the LICENSE file in the project root for more information. |
| 4 | //////////////////////////////////////////////////////////////////////////////// |
| 5 | // COMDynamic.h |
| 6 | // This module defines the native methods that are used for Dynamic IL generation |
| 7 | |
| 8 | //////////////////////////////////////////////////////////////////////////////// |
| 9 | |
| 10 | |
| 11 | #include "common.h" |
| 12 | #include "field.h" |
| 13 | #include "comdynamic.h" |
| 14 | #include "commodule.h" |
| 15 | #include "reflectclasswriter.h" |
| 16 | #include "corerror.h" |
| 17 | #include "iceefilegen.h" |
| 18 | #include "strongname.h" |
| 19 | #include "ceefilegenwriter.h" |
| 20 | #include "typekey.h" |
| 21 | |
| 22 | |
| 23 | //This structure is used in SetMethodIL to walk the exceptions. |
| 24 | //It maps to System.Reflection.Emit.ExceptionHandler class |
| 25 | //DO NOT MOVE ANY OF THE FIELDS |
| 26 | #include <pshpack1.h> |
| 27 | struct ExceptionInstance { |
| 28 | INT32 m_exceptionType; |
| 29 | INT32 m_start; |
| 30 | INT32 m_end; |
| 31 | INT32 m_filterOffset; |
| 32 | INT32 m_handle; |
| 33 | INT32 m_handleEnd; |
| 34 | INT32 m_type; |
| 35 | }; |
| 36 | #include <poppack.h> |
| 37 | |
| 38 | |
| 39 | //************************************************************* |
| 40 | // |
| 41 | // Defining a type into metadata of this dynamic module |
| 42 | // |
| 43 | //************************************************************* |
| 44 | INT32 QCALLTYPE COMDynamicWrite::DefineGenericParam(QCall::ModuleHandle pModule, |
| 45 | LPCWSTR wszFullName, |
| 46 | INT32 tkParent, |
| 47 | INT32 attributes, |
| 48 | INT32 position, |
| 49 | INT32 * pConstraintTokens) |
| 50 | { |
| 51 | QCALL_CONTRACT; |
| 52 | |
| 53 | mdTypeDef classE = mdTokenNil; |
| 54 | |
| 55 | BEGIN_QCALL; |
| 56 | |
| 57 | RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); |
| 58 | _ASSERTE(pRCW); |
| 59 | |
| 60 | IfFailThrow(pRCW->GetEmitter()->DefineGenericParam( |
| 61 | tkParent, position, attributes, wszFullName, 0, (mdToken *)pConstraintTokens, &classE)); |
| 62 | |
| 63 | END_QCALL; |
| 64 | |
| 65 | return (INT32)classE; |
| 66 | } |
| 67 | |
| 68 | INT32 QCALLTYPE COMDynamicWrite::DefineType(QCall::ModuleHandle pModule, |
| 69 | LPCWSTR wszFullName, |
| 70 | INT32 tkParent, |
| 71 | INT32 attributes, |
| 72 | INT32 tkEnclosingType, |
| 73 | INT32 * pInterfaceTokens) |
| 74 | { |
| 75 | QCALL_CONTRACT; |
| 76 | |
| 77 | mdTypeDef classE = mdTokenNil; |
| 78 | |
| 79 | BEGIN_QCALL; |
| 80 | |
| 81 | RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); |
| 82 | _ASSERTE(pRCW); |
| 83 | |
| 84 | HRESULT hr; |
| 85 | |
| 86 | if (RidFromToken(tkEnclosingType)) |
| 87 | { |
| 88 | // defining nested type |
| 89 | hr = pRCW->GetEmitter()->DefineNestedType(wszFullName, |
| 90 | attributes, |
| 91 | tkParent == 0 ? mdTypeRefNil : tkParent, |
| 92 | (mdToken *)pInterfaceTokens, |
| 93 | tkEnclosingType, |
| 94 | &classE); |
| 95 | } |
| 96 | else |
| 97 | { |
| 98 | // top level type |
| 99 | hr = pRCW->GetEmitter()->DefineTypeDef(wszFullName, |
| 100 | attributes, |
| 101 | tkParent == 0 ? mdTypeRefNil : tkParent, |
| 102 | (mdToken *)pInterfaceTokens, |
| 103 | &classE); |
| 104 | } |
| 105 | |
| 106 | if (hr == META_S_DUPLICATE) |
| 107 | { |
| 108 | COMPlusThrow(kArgumentException, W("Argument_DuplicateTypeName" )); |
| 109 | } |
| 110 | |
| 111 | if (FAILED(hr)) { |
| 112 | _ASSERTE(hr == E_OUTOFMEMORY || !"DefineTypeDef Failed" ); |
| 113 | COMPlusThrowHR(hr); |
| 114 | } |
| 115 | |
| 116 | AllocMemTracker amTracker; |
| 117 | pModule->GetClassLoader()->AddAvailableClassDontHaveLock(pModule, |
| 118 | classE, |
| 119 | &amTracker); |
| 120 | amTracker.SuppressRelease(); |
| 121 | |
| 122 | END_QCALL; |
| 123 | |
| 124 | return (INT32)classE; |
| 125 | } |
| 126 | |
| 127 | // This function will reset the parent class in metadata |
| 128 | void QCALLTYPE COMDynamicWrite::SetParentType(QCall::ModuleHandle pModule, INT32 tdType, INT32 tkParent) |
| 129 | { |
| 130 | QCALL_CONTRACT; |
| 131 | |
| 132 | BEGIN_QCALL; |
| 133 | |
| 134 | RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); |
| 135 | _ASSERTE(pRCW); |
| 136 | |
| 137 | IfFailThrow( pRCW->GetEmitHelper()->SetTypeParent(tdType, tkParent) ); |
| 138 | |
| 139 | END_QCALL; |
| 140 | } |
| 141 | |
| 142 | // This function will add another interface impl |
| 143 | void QCALLTYPE COMDynamicWrite::AddInterfaceImpl(QCall::ModuleHandle pModule, INT32 tdType, INT32 tkInterface) |
| 144 | { |
| 145 | QCALL_CONTRACT; |
| 146 | |
| 147 | BEGIN_QCALL; |
| 148 | |
| 149 | RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); |
| 150 | _ASSERTE(pRCW); |
| 151 | |
| 152 | IfFailThrow( pRCW->GetEmitHelper()->AddInterfaceImpl(tdType, tkInterface) ); |
| 153 | |
| 154 | END_QCALL; |
| 155 | } |
| 156 | |
| 157 | // This function will create a method within the class |
| 158 | INT32 QCALLTYPE COMDynamicWrite::DefineMethodSpec(QCall::ModuleHandle pModule, INT32 tkParent, LPCBYTE pSignature, INT32 sigLength) |
| 159 | { |
| 160 | QCALL_CONTRACT; |
| 161 | |
| 162 | mdMethodDef memberE = mdTokenNil; |
| 163 | |
| 164 | BEGIN_QCALL; |
| 165 | |
| 166 | RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); |
| 167 | _ASSERTE(pRCW); |
| 168 | |
| 169 | // Define the Method |
| 170 | IfFailThrow( pRCW->GetEmitter()->DefineMethodSpec(tkParent, //ParentTypeDef |
| 171 | (PCCOR_SIGNATURE)pSignature, //Blob value of a COM+ signature |
| 172 | sigLength, //Size of the signature blob |
| 173 | &memberE) ); //[OUT]methodToken |
| 174 | |
| 175 | END_QCALL; |
| 176 | |
| 177 | return (INT32) memberE; |
| 178 | } |
| 179 | |
| 180 | INT32 QCALLTYPE COMDynamicWrite::DefineMethod(QCall::ModuleHandle pModule, INT32 tkParent, LPCWSTR wszName, LPCBYTE pSignature, INT32 sigLength, INT32 attributes) |
| 181 | { |
| 182 | QCALL_CONTRACT; |
| 183 | |
| 184 | mdMethodDef memberE = mdTokenNil; |
| 185 | |
| 186 | BEGIN_QCALL; |
| 187 | |
| 188 | RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); |
| 189 | _ASSERTE(pRCW); |
| 190 | |
| 191 | // Define the Method |
| 192 | IfFailThrow( pRCW->GetEmitter()->DefineMethod(tkParent, //ParentTypeDef |
| 193 | wszName, //Name of Member |
| 194 | attributes, //Member Attributes (public, etc); |
| 195 | (PCCOR_SIGNATURE)pSignature, //Blob value of a COM+ signature |
| 196 | sigLength, //Size of the signature blob |
| 197 | 0, //Code RVA |
| 198 | miIL | miManaged, //Implementation Flags is default to managed IL |
| 199 | &memberE) ); //[OUT]methodToken |
| 200 | |
| 201 | END_QCALL; |
| 202 | |
| 203 | return (INT32) memberE; |
| 204 | } |
| 205 | |
| 206 | /*================================DefineField================================= |
| 207 | **Action: |
| 208 | **Returns: |
| 209 | **Arguments: |
| 210 | **Exceptions: |
| 211 | ==============================================================================*/ |
| 212 | mdFieldDef QCALLTYPE COMDynamicWrite::DefineField(QCall::ModuleHandle pModule, INT32 tkParent, LPCWSTR wszName, LPCBYTE pSignature, INT32 sigLength, INT32 attr) |
| 213 | { |
| 214 | QCALL_CONTRACT; |
| 215 | |
| 216 | mdFieldDef retVal = mdTokenNil; |
| 217 | |
| 218 | BEGIN_QCALL; |
| 219 | |
| 220 | RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); |
| 221 | _ASSERTE(pRCW); |
| 222 | |
| 223 | //Emit the field. |
| 224 | IfFailThrow( pRCW->GetEmitter()->DefineField(tkParent, |
| 225 | wszName, attr, |
| 226 | (PCCOR_SIGNATURE)pSignature, sigLength, |
| 227 | ELEMENT_TYPE_VOID, NULL, |
| 228 | (ULONG) -1, &retVal) ); |
| 229 | |
| 230 | |
| 231 | END_QCALL; |
| 232 | |
| 233 | return retVal; |
| 234 | } |
| 235 | |
| 236 | // This method computes the same result as COR_ILMETHOD_SECT_EH::Size(...) but |
| 237 | // does so in a way that detects overflow if the number of exception clauses is |
| 238 | // too great (in which case an OOM exception is thrown). We do this rather than |
| 239 | // modifying COR_ILMETHOD_SECT_EH::Size because that routine is published in the |
| 240 | // SDK and can't take breaking changes and because the overflow support (and |
| 241 | // exception mechanism) we're using is only available to the VM. |
| 242 | UINT32 ExceptionHandlingSize(unsigned uNumExceptions, COR_ILMETHOD_SECT_EH_CLAUSE_FAT* pClauses) |
| 243 | { |
| 244 | STANDARD_VM_CONTRACT; |
| 245 | |
| 246 | if (uNumExceptions == 0) |
| 247 | return 0; |
| 248 | |
| 249 | // Speculatively compute the size for the slim version of the header. |
| 250 | S_UINT32 uSmallSize = S_UINT32(sizeof(COR_ILMETHOD_SECT_EH_SMALL)) + |
| 251 | (S_UINT32(sizeof(IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_SMALL)) * (S_UINT32(uNumExceptions - 1))); |
| 252 | |
| 253 | if (uSmallSize.IsOverflow()) |
| 254 | COMPlusThrowOM(); |
| 255 | |
| 256 | if (uSmallSize.Value() > COR_ILMETHOD_SECT_SMALL_MAX_DATASIZE) |
| 257 | goto FatCase; |
| 258 | |
| 259 | // Check whether any of the clauses won't fit in the slim case. |
| 260 | for (UINT32 i = 0; i < uNumExceptions; i++) { |
| 261 | COR_ILMETHOD_SECT_EH_CLAUSE_FAT* pFatClause = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)&pClauses[i]; |
| 262 | if (pFatClause->GetTryOffset() > 0xFFFF || |
| 263 | pFatClause->GetTryLength() > 0xFF || |
| 264 | pFatClause->GetHandlerOffset() > 0xFFFF || |
| 265 | pFatClause->GetHandlerLength() > 0xFF) { |
| 266 | goto FatCase; |
| 267 | } |
| 268 | } |
| 269 | |
| 270 | _ASSERTE(uSmallSize.Value() == COR_ILMETHOD_SECT_EH::Size(uNumExceptions, pClauses)); |
| 271 | return uSmallSize.Value(); |
| 272 | |
| 273 | FatCase: |
| 274 | S_UINT32 uFatSize = S_UINT32(sizeof(COR_ILMETHOD_SECT_EH_FAT)) + |
| 275 | (S_UINT32(sizeof(IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT)) * (S_UINT32(uNumExceptions - 1))); |
| 276 | |
| 277 | if (uFatSize.IsOverflow()) |
| 278 | COMPlusThrowOM(); |
| 279 | |
| 280 | _ASSERTE(uFatSize.Value() == COR_ILMETHOD_SECT_EH::Size(uNumExceptions, pClauses)); |
| 281 | return uFatSize.Value(); |
| 282 | } |
| 283 | |
| 284 | |
| 285 | // SetMethodIL -- This function will create a method within the class |
| 286 | void QCALLTYPE COMDynamicWrite::SetMethodIL(QCall::ModuleHandle pModule, |
| 287 | INT32 tk, |
| 288 | BOOL fIsInitLocal, |
| 289 | LPCBYTE pBody, |
| 290 | INT32 cbBody, |
| 291 | LPCBYTE pLocalSig, |
| 292 | INT32 sigLength, |
| 293 | UINT16 maxStackSize, |
| 294 | ExceptionInstance * pExceptions, |
| 295 | INT32 numExceptions, |
| 296 | INT32 * pTokenFixups, |
| 297 | INT32 numTokenFixups) |
| 298 | { |
| 299 | QCALL_CONTRACT; |
| 300 | |
| 301 | BEGIN_QCALL; |
| 302 | |
| 303 | RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); |
| 304 | _ASSERTE(pRCW); |
| 305 | |
| 306 | _ASSERTE(pLocalSig); |
| 307 | |
| 308 | PCCOR_SIGNATURE pcSig = (PCCOR_SIGNATURE)pLocalSig; |
| 309 | _ASSERTE(*pcSig == IMAGE_CEE_CS_CALLCONV_LOCAL_SIG); |
| 310 | |
| 311 | mdSignature pmLocalSigToken; |
| 312 | if (sigLength==2 && pcSig[0]==0 && pcSig[1]==0) |
| 313 | { |
| 314 | //This is an empty local variable sig |
| 315 | pmLocalSigToken=0; |
| 316 | } |
| 317 | else |
| 318 | { |
| 319 | IfFailThrow(pRCW->GetEmitter()->GetTokenFromSig( pcSig, sigLength, &pmLocalSigToken)); |
| 320 | } |
| 321 | |
| 322 | COR_ILMETHOD_FAT ; |
| 323 | |
| 324 | // set fatHeader.Flags to CorILMethod_InitLocals if user wants to zero init the stack frame. |
| 325 | // |
| 326 | fatHeader.SetFlags(fIsInitLocal ? CorILMethod_InitLocals : 0); |
| 327 | fatHeader.SetMaxStack(maxStackSize); |
| 328 | fatHeader.SetLocalVarSigTok(pmLocalSigToken); |
| 329 | fatHeader.SetCodeSize(cbBody); |
| 330 | bool moreSections = (numExceptions != 0); |
| 331 | |
| 332 | unsigned codeSizeAligned = fatHeader.GetCodeSize(); |
| 333 | if (moreSections) |
| 334 | codeSizeAligned = AlignUp(codeSizeAligned, 4); // to insure EH section aligned |
| 335 | unsigned = COR_ILMETHOD::Size(&fatHeader, numExceptions != 0); |
| 336 | |
| 337 | //Create the exception handlers. |
| 338 | CQuickArray<COR_ILMETHOD_SECT_EH_CLAUSE_FAT> clauses; |
| 339 | if (numExceptions > 0) |
| 340 | { |
| 341 | clauses.AllocThrows(numExceptions); |
| 342 | |
| 343 | for (int i = 0; i < numExceptions; i++) |
| 344 | { |
| 345 | clauses[i].SetFlags((CorExceptionFlag)(pExceptions[i].m_type)); |
| 346 | clauses[i].SetTryOffset(pExceptions[i].m_start); |
| 347 | clauses[i].SetTryLength(pExceptions[i].m_end - pExceptions[i].m_start); |
| 348 | clauses[i].SetHandlerOffset(pExceptions[i].m_handle); |
| 349 | clauses[i].SetHandlerLength(pExceptions[i].m_handleEnd - pExceptions[i].m_handle); |
| 350 | if (pExceptions[i].m_type == COR_ILEXCEPTION_CLAUSE_FILTER) |
| 351 | { |
| 352 | clauses[i].SetFilterOffset(pExceptions[i].m_filterOffset); |
| 353 | } |
| 354 | else if (pExceptions[i].m_type!=COR_ILEXCEPTION_CLAUSE_FINALLY) |
| 355 | { |
| 356 | clauses[i].SetClassToken(pExceptions[i].m_exceptionType); |
| 357 | } |
| 358 | else |
| 359 | { |
| 360 | clauses[i].SetClassToken(mdTypeRefNil); |
| 361 | } |
| 362 | } |
| 363 | } |
| 364 | |
| 365 | unsigned ehSize = ExceptionHandlingSize(numExceptions, clauses.Ptr()); |
| 366 | S_UINT32 totalSizeSafe = S_UINT32(headerSize) + S_UINT32(codeSizeAligned) + S_UINT32(ehSize); |
| 367 | if (totalSizeSafe.IsOverflow()) |
| 368 | COMPlusThrowOM(); |
| 369 | UINT32 totalSize = totalSizeSafe.Value(); |
| 370 | ICeeGen* pGen = pRCW->GetCeeGen(); |
| 371 | BYTE* buf = NULL; |
| 372 | ULONG methodRVA; |
| 373 | pGen->AllocateMethodBuffer(totalSize, &buf, &methodRVA); |
| 374 | if (buf == NULL) |
| 375 | COMPlusThrowOM(); |
| 376 | |
| 377 | _ASSERTE(buf != NULL); |
| 378 | _ASSERTE((((size_t) buf) & 3) == 0); // header is dword aligned |
| 379 | |
| 380 | #ifdef _DEBUG |
| 381 | BYTE* endbuf = &buf[totalSize]; |
| 382 | #endif |
| 383 | |
| 384 | BYTE * startBuf = buf; |
| 385 | |
| 386 | // Emit the header |
| 387 | buf += COR_ILMETHOD::Emit(headerSize, &fatHeader, moreSections, buf); |
| 388 | |
| 389 | //Emit the code |
| 390 | //The fatHeader.CodeSize is a workaround to see if we have an interface or an |
| 391 | //abstract method. Force enough verification in native to ensure that |
| 392 | //this is true. |
| 393 | if (fatHeader.GetCodeSize()!=0) { |
| 394 | memcpy(buf, pBody, fatHeader.GetCodeSize()); |
| 395 | } |
| 396 | buf += codeSizeAligned; |
| 397 | |
| 398 | // Emit the eh |
| 399 | CQuickArray<ULONG> ehTypeOffsets; |
| 400 | if (numExceptions > 0) |
| 401 | { |
| 402 | // Allocate space for the the offsets to the TypeTokens in the Exception headers |
| 403 | // in the IL stream. |
| 404 | ehTypeOffsets.AllocThrows(numExceptions); |
| 405 | |
| 406 | // Emit the eh. This will update the array ehTypeOffsets with offsets |
| 407 | // to Exception type tokens. The offsets are with reference to the |
| 408 | // beginning of eh section. |
| 409 | buf += COR_ILMETHOD_SECT_EH::Emit(ehSize, numExceptions, clauses.Ptr(), |
| 410 | false, buf, ehTypeOffsets.Ptr()); |
| 411 | } |
| 412 | _ASSERTE(buf == endbuf); |
| 413 | |
| 414 | //Get the IL Section. |
| 415 | HCEESECTION ilSection; |
| 416 | IfFailThrow(pGen->GetIlSection(&ilSection)); |
| 417 | |
| 418 | // Token Fixup data... |
| 419 | ULONG ilOffset = methodRVA + headerSize; |
| 420 | |
| 421 | //Add all of the relocs based on the info which I saved from ILGenerator. |
| 422 | |
| 423 | //Add the Token Fixups |
| 424 | for (int iTokenFixup=0; iTokenFixup<numTokenFixups; iTokenFixup++) |
| 425 | { |
| 426 | IfFailThrow(pGen->AddSectionReloc(ilSection, pTokenFixups[iTokenFixup] + ilOffset, ilSection, srRelocMapToken)); |
| 427 | } |
| 428 | |
| 429 | // Add token fixups for exception type tokens. |
| 430 | for (int iException=0; iException < numExceptions; iException++) |
| 431 | { |
| 432 | if (ehTypeOffsets[iException] != (ULONG) -1) |
| 433 | { |
| 434 | IfFailThrow(pGen->AddSectionReloc( |
| 435 | ilSection, |
| 436 | ehTypeOffsets[iException] + codeSizeAligned + ilOffset, |
| 437 | ilSection, srRelocMapToken)); |
| 438 | } |
| 439 | } |
| 440 | |
| 441 | //nasty interface workaround. What does this mean for abstract methods? |
| 442 | if (fatHeader.GetCodeSize() != 0) |
| 443 | { |
| 444 | // add the starting address of the il blob to the il blob hash table |
| 445 | // we need to find this information from out of process for debugger inspection |
| 446 | // APIs so we have to store this information where we can get it later |
| 447 | pModule->SetDynamicIL(mdToken(tk), TADDR(startBuf), FALSE); |
| 448 | |
| 449 | DWORD dwImplFlags; |
| 450 | |
| 451 | //Set the RVA of the method. |
| 452 | IfFailThrow(pRCW->GetMDImport()->GetMethodImplProps(tk, NULL, &dwImplFlags)); |
| 453 | dwImplFlags |= (miManaged | miIL); |
| 454 | IfFailThrow(pRCW->GetEmitter()->SetMethodProps(tk, (DWORD) -1, methodRVA, dwImplFlags)); |
| 455 | } |
| 456 | |
| 457 | END_QCALL; |
| 458 | } |
| 459 | |
| 460 | void QCALLTYPE COMDynamicWrite::TermCreateClass(QCall::ModuleHandle pModule, INT32 tk, QCall::ObjectHandleOnStack retType) |
| 461 | { |
| 462 | QCALL_CONTRACT; |
| 463 | |
| 464 | TypeHandle typeHnd; |
| 465 | |
| 466 | BEGIN_QCALL; |
| 467 | |
| 468 | _ASSERTE(pModule->GetReflectionModule()->GetClassWriter()); |
| 469 | |
| 470 | // Use the same service, regardless of whether we are generating a normal |
| 471 | // class, or the special class for the module that holds global functions |
| 472 | // & methods. |
| 473 | pModule->GetReflectionModule()->AddClass(tk); |
| 474 | |
| 475 | // manually load the class if it is not the global type |
| 476 | if (!IsNilToken(tk)) |
| 477 | { |
| 478 | TypeKey typeKey(pModule, tk); |
| 479 | typeHnd = pModule->GetClassLoader()->LoadTypeHandleForTypeKey(&typeKey, TypeHandle()); |
| 480 | } |
| 481 | |
| 482 | if (!typeHnd.IsNull()) |
| 483 | { |
| 484 | GCX_COOP(); |
| 485 | retType.Set(typeHnd.GetManagedClassObject()); |
| 486 | } |
| 487 | |
| 488 | END_QCALL; |
| 489 | |
| 490 | return; |
| 491 | } |
| 492 | |
| 493 | /*============================SetPInvokeData============================ |
| 494 | **Action: |
| 495 | **Returns: |
| 496 | **Arguments: |
| 497 | **Exceptions: |
| 498 | ==============================================================================*/ |
| 499 | void QCALLTYPE COMDynamicWrite::SetPInvokeData(QCall::ModuleHandle pModule, LPCWSTR wszDllName, LPCWSTR wszFunctionName, INT32 token, INT32 linkFlags) |
| 500 | { |
| 501 | QCALL_CONTRACT; |
| 502 | |
| 503 | BEGIN_QCALL; |
| 504 | |
| 505 | RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); |
| 506 | _ASSERTE(pRCW); |
| 507 | |
| 508 | mdModuleRef mrImportDll = mdTokenNil; |
| 509 | IfFailThrow(pRCW->GetEmitter()->DefineModuleRef(wszDllName, &mrImportDll)); |
| 510 | |
| 511 | IfFailThrow(pRCW->GetEmitter()->DefinePinvokeMap( |
| 512 | token, // the method token |
| 513 | linkFlags, // the mapping flags |
| 514 | wszFunctionName, // function name |
| 515 | mrImportDll)); |
| 516 | |
| 517 | IfFailThrow(pRCW->GetEmitter()->SetMethodProps(token, (DWORD) -1, 0x0, miIL)); |
| 518 | |
| 519 | END_QCALL; |
| 520 | } |
| 521 | |
| 522 | /*============================DefineProperty============================ |
| 523 | **Action: |
| 524 | **Returns: |
| 525 | **Arguments: |
| 526 | **Exceptions: |
| 527 | ==============================================================================*/ |
| 528 | INT32 QCALLTYPE COMDynamicWrite::DefineProperty(QCall::ModuleHandle pModule, INT32 tkParent, LPCWSTR wszName, INT32 attr, LPCBYTE pSignature, INT32 sigLength) |
| 529 | { |
| 530 | QCALL_CONTRACT; |
| 531 | |
| 532 | mdProperty pr = mdTokenNil; |
| 533 | |
| 534 | BEGIN_QCALL; |
| 535 | |
| 536 | RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); |
| 537 | _ASSERTE(pRCW); |
| 538 | |
| 539 | // Define the Property |
| 540 | IfFailThrow(pRCW->GetEmitter()->DefineProperty( |
| 541 | tkParent, // ParentTypeDef |
| 542 | wszName, // Name of Member |
| 543 | attr, // property Attributes (prDefaultProperty, etc); |
| 544 | (PCCOR_SIGNATURE)pSignature, // Blob value of a COM+ signature |
| 545 | sigLength, // Size of the signature blob |
| 546 | ELEMENT_TYPE_VOID, // don't specify the default value |
| 547 | 0, // no default value |
| 548 | (ULONG) -1, // optional length |
| 549 | mdMethodDefNil, // no setter |
| 550 | mdMethodDefNil, // no getter |
| 551 | NULL, // no other methods |
| 552 | &pr)); |
| 553 | |
| 554 | END_QCALL; |
| 555 | |
| 556 | return (INT32)pr; |
| 557 | } |
| 558 | |
| 559 | /*============================DefineEvent============================ |
| 560 | **Action: |
| 561 | **Returns: |
| 562 | **Arguments: |
| 563 | **Exceptions: |
| 564 | ==============================================================================*/ |
| 565 | INT32 QCALLTYPE COMDynamicWrite::DefineEvent(QCall::ModuleHandle pModule, INT32 tkParent, LPCWSTR wszName, INT32 attr, INT32 tkEventType) |
| 566 | { |
| 567 | QCALL_CONTRACT; |
| 568 | |
| 569 | mdProperty ev = mdTokenNil; |
| 570 | |
| 571 | BEGIN_QCALL; |
| 572 | |
| 573 | RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); |
| 574 | _ASSERTE(pRCW); |
| 575 | |
| 576 | // Define the Event |
| 577 | IfFailThrow(pRCW->GetEmitHelper()->DefineEventHelper( |
| 578 | tkParent, // ParentTypeDef |
| 579 | wszName, // Name of Member |
| 580 | attr, // property Attributes (prDefaultProperty, etc); |
| 581 | tkEventType, // the event type. Can be TypeDef or TypeRef |
| 582 | &ev)); |
| 583 | |
| 584 | END_QCALL; |
| 585 | |
| 586 | return (INT32)ev; |
| 587 | } |
| 588 | |
| 589 | /*============================DefineMethodSemantics============================ |
| 590 | **Action: |
| 591 | **Returns: |
| 592 | **Arguments: |
| 593 | **Exceptions: |
| 594 | ==============================================================================*/ |
| 595 | void QCALLTYPE COMDynamicWrite::DefineMethodSemantics(QCall::ModuleHandle pModule, INT32 tkAssociation, INT32 attr, INT32 tkMethod) |
| 596 | { |
| 597 | QCALL_CONTRACT; |
| 598 | |
| 599 | BEGIN_QCALL; |
| 600 | |
| 601 | RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); |
| 602 | _ASSERTE(pRCW); |
| 603 | |
| 604 | // Define the MethodSemantics |
| 605 | IfFailThrow(pRCW->GetEmitHelper()->DefineMethodSemanticsHelper( |
| 606 | tkAssociation, |
| 607 | attr, |
| 608 | tkMethod)); |
| 609 | |
| 610 | END_QCALL; |
| 611 | } |
| 612 | |
| 613 | /*============================SetMethodImpl============================ |
| 614 | ** To set a Method's Implementation flags |
| 615 | ==============================================================================*/ |
| 616 | void QCALLTYPE COMDynamicWrite::SetMethodImpl(QCall::ModuleHandle pModule, INT32 tkMethod, INT32 attr) |
| 617 | { |
| 618 | QCALL_CONTRACT; |
| 619 | |
| 620 | BEGIN_QCALL; |
| 621 | |
| 622 | RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); |
| 623 | _ASSERTE(pRCW); |
| 624 | |
| 625 | // Set the methodimpl flags |
| 626 | IfFailThrow(pRCW->GetEmitter()->SetMethodImplFlags( |
| 627 | tkMethod, |
| 628 | attr)); // change the impl flags |
| 629 | |
| 630 | END_QCALL; |
| 631 | } |
| 632 | |
| 633 | /*============================DefineMethodImpl============================ |
| 634 | ** Define a MethodImpl record |
| 635 | ==============================================================================*/ |
| 636 | void QCALLTYPE COMDynamicWrite::DefineMethodImpl(QCall::ModuleHandle pModule, UINT32 tkType, UINT32 tkBody, UINT32 tkDecl) |
| 637 | { |
| 638 | QCALL_CONTRACT; |
| 639 | |
| 640 | BEGIN_QCALL; |
| 641 | |
| 642 | RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); |
| 643 | _ASSERTE(pRCW); |
| 644 | |
| 645 | // Set the methodimpl flags |
| 646 | IfFailThrow(pRCW->GetEmitter()->DefineMethodImpl( |
| 647 | tkType, |
| 648 | tkBody, |
| 649 | tkDecl)); // change the impl flags |
| 650 | |
| 651 | END_QCALL; |
| 652 | } |
| 653 | |
| 654 | /*============================GetTokenFromSig============================ |
| 655 | **Action: |
| 656 | **Returns: |
| 657 | **Arguments: |
| 658 | **Exceptions: |
| 659 | ==============================================================================*/ |
| 660 | INT32 QCALLTYPE COMDynamicWrite::GetTokenFromSig(QCall::ModuleHandle pModule, LPCBYTE pSignature, INT32 sigLength) |
| 661 | { |
| 662 | QCALL_CONTRACT; |
| 663 | |
| 664 | mdSignature retVal = 0; |
| 665 | |
| 666 | BEGIN_QCALL; |
| 667 | |
| 668 | RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); |
| 669 | _ASSERTE(pRCW); |
| 670 | |
| 671 | _ASSERTE(pSignature); |
| 672 | |
| 673 | // Define the signature |
| 674 | IfFailThrow(pRCW->GetEmitter()->GetTokenFromSig( |
| 675 | pSignature, // Signature blob |
| 676 | sigLength, // blob length |
| 677 | &retVal)); // returned token |
| 678 | |
| 679 | END_QCALL; |
| 680 | |
| 681 | return (INT32)retVal; |
| 682 | } |
| 683 | |
| 684 | /*============================SetParamInfo============================ |
| 685 | **Action: Helper to set parameter information |
| 686 | **Returns: |
| 687 | **Arguments: |
| 688 | **Exceptions: |
| 689 | ==============================================================================*/ |
| 690 | INT32 QCALLTYPE COMDynamicWrite::SetParamInfo(QCall::ModuleHandle pModule, UINT32 tkMethod, UINT32 iSequence, UINT32 iAttributes, LPCWSTR wszParamName) |
| 691 | { |
| 692 | QCALL_CONTRACT; |
| 693 | |
| 694 | mdParamDef retVal = 0; |
| 695 | |
| 696 | BEGIN_QCALL; |
| 697 | |
| 698 | RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); |
| 699 | _ASSERTE(pRCW); |
| 700 | |
| 701 | // Set the methodimpl flags |
| 702 | IfFailThrow(pRCW->GetEmitter()->DefineParam( |
| 703 | tkMethod, |
| 704 | iSequence, // sequence of the parameter |
| 705 | wszParamName, |
| 706 | iAttributes, // change the impl flags |
| 707 | ELEMENT_TYPE_VOID, |
| 708 | 0, |
| 709 | (ULONG) -1, |
| 710 | &retVal)); |
| 711 | |
| 712 | END_QCALL; |
| 713 | |
| 714 | return (INT32)retVal; |
| 715 | } |
| 716 | |
| 717 | |
| 718 | /*============================SetConstantValue============================ |
| 719 | **Action: Helper to set constant value to field or parameter |
| 720 | **Returns: |
| 721 | **Arguments: |
| 722 | **Exceptions: |
| 723 | ==============================================================================*/ |
| 724 | void QCALLTYPE COMDynamicWrite::SetConstantValue(QCall::ModuleHandle pModule, UINT32 tk, DWORD valueCorType, LPVOID pValue) |
| 725 | { |
| 726 | QCALL_CONTRACT; |
| 727 | |
| 728 | BEGIN_QCALL; |
| 729 | |
| 730 | RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); |
| 731 | _ASSERTE(pRCW); |
| 732 | |
| 733 | HRESULT hr; |
| 734 | |
| 735 | if (TypeFromToken(tk) == mdtFieldDef) |
| 736 | { |
| 737 | hr = pRCW->GetEmitter()->SetFieldProps( |
| 738 | tk, // [IN] The FieldDef. |
| 739 | ULONG_MAX, // [IN] Field attributes. |
| 740 | valueCorType, // [IN] Flag for the value type, selected ELEMENT_TYPE_* |
| 741 | pValue, // [IN] Constant value. |
| 742 | (ULONG) -1); // [IN] Optional length. |
| 743 | } |
| 744 | else if (TypeFromToken(tk) == mdtProperty) |
| 745 | { |
| 746 | hr = pRCW->GetEmitter()->SetPropertyProps( |
| 747 | tk, // [IN] The PropertyDef. |
| 748 | ULONG_MAX, // [IN] Property attributes. |
| 749 | valueCorType, // [IN] Flag for the value type, selected ELEMENT_TYPE_* |
| 750 | pValue, // [IN] Constant value. |
| 751 | (ULONG) -1, // [IN] Optional length. |
| 752 | mdMethodDefNil, // [IN] Getter method. |
| 753 | mdMethodDefNil, // [IN] Setter method. |
| 754 | NULL); // [IN] Other methods. |
| 755 | } |
| 756 | else |
| 757 | { |
| 758 | hr = pRCW->GetEmitter()->SetParamProps( |
| 759 | tk, // [IN] The ParamDef. |
| 760 | NULL, |
| 761 | ULONG_MAX, // [IN] Parameter attributes. |
| 762 | valueCorType, // [IN] Flag for the value type, selected ELEMENT_TYPE_* |
| 763 | pValue, // [IN] Constant value. |
| 764 | (ULONG) -1); // [IN] Optional length. |
| 765 | } |
| 766 | if (FAILED(hr)) { |
| 767 | _ASSERTE(!"Set default value is failing" ); |
| 768 | COMPlusThrow(kArgumentException, W("Argument_BadConstantValue" )); |
| 769 | } |
| 770 | |
| 771 | END_QCALL; |
| 772 | } |
| 773 | |
| 774 | /*============================SetFieldLayoutOffset============================ |
| 775 | **Action: set fieldlayout of a field |
| 776 | **Returns: |
| 777 | **Arguments: |
| 778 | **Exceptions: |
| 779 | ==============================================================================*/ |
| 780 | void QCALLTYPE COMDynamicWrite::SetFieldLayoutOffset(QCall::ModuleHandle pModule, INT32 tkField, INT32 iOffset) |
| 781 | { |
| 782 | QCALL_CONTRACT; |
| 783 | |
| 784 | BEGIN_QCALL; |
| 785 | |
| 786 | RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); |
| 787 | _ASSERTE(pRCW); |
| 788 | |
| 789 | // Set the field layout |
| 790 | IfFailThrow(pRCW->GetEmitHelper()->SetFieldLayoutHelper( |
| 791 | tkField, // field |
| 792 | iOffset)); // layout offset |
| 793 | |
| 794 | END_QCALL; |
| 795 | } |
| 796 | |
| 797 | |
| 798 | /*============================SetClassLayout============================ |
| 799 | **Action: |
| 800 | **Returns: |
| 801 | **Arguments: |
| 802 | **Exceptions: |
| 803 | ==============================================================================*/ |
| 804 | void QCALLTYPE COMDynamicWrite::SetClassLayout(QCall::ModuleHandle pModule, INT32 tk, INT32 iPackSize, UINT32 iTotalSize) |
| 805 | { |
| 806 | QCALL_CONTRACT; |
| 807 | |
| 808 | BEGIN_QCALL; |
| 809 | |
| 810 | RefClassWriter* pRCW = pModule->GetReflectionModule()->GetClassWriter(); |
| 811 | _ASSERTE(pRCW); |
| 812 | |
| 813 | // Define the packing size and total size of a class |
| 814 | IfFailThrow(pRCW->GetEmitter()->SetClassLayout( |
| 815 | tk, // Typedef |
| 816 | iPackSize, // packing size |
| 817 | NULL, // no field layout |
| 818 | iTotalSize)); // total size for the type |
| 819 | |
| 820 | END_QCALL; |
| 821 | } |
| 822 | |
| 823 | void QCALLTYPE COMDynamicWrite::DefineCustomAttribute(QCall::ModuleHandle pModule, INT32 token, INT32 conTok, LPCBYTE pBlob, INT32 cbBlob, BOOL toDisk, BOOL updateCompilerFlags) |
| 824 | { |
| 825 | QCALL_CONTRACT; |
| 826 | |
| 827 | BEGIN_QCALL; |
| 828 | |
| 829 | RefClassWriter* pRCW = pModule->GetReflectionModule()->GetClassWriter(); |
| 830 | _ASSERTE(pRCW); |
| 831 | |
| 832 | HRESULT hr; |
| 833 | mdCustomAttribute retToken; |
| 834 | |
| 835 | if (toDisk && pRCW->GetOnDiskEmitter()) |
| 836 | { |
| 837 | hr = pRCW->GetOnDiskEmitter()->DefineCustomAttribute( |
| 838 | token, |
| 839 | conTok, |
| 840 | pBlob, |
| 841 | cbBlob, |
| 842 | &retToken); |
| 843 | } |
| 844 | else |
| 845 | { |
| 846 | hr = pRCW->GetEmitter()->DefineCustomAttribute( |
| 847 | token, |
| 848 | conTok, |
| 849 | pBlob, |
| 850 | cbBlob, |
| 851 | &retToken); |
| 852 | } |
| 853 | |
| 854 | if (FAILED(hr)) |
| 855 | { |
| 856 | // See if the metadata engine gave us any error information. |
| 857 | SafeComHolderPreemp<IErrorInfo> pIErrInfo; |
| 858 | BSTRHolder bstrMessage; |
| 859 | if (SafeGetErrorInfo(&pIErrInfo) == S_OK) |
| 860 | { |
| 861 | if (SUCCEEDED(pIErrInfo->GetDescription(&bstrMessage)) && bstrMessage != NULL) |
| 862 | COMPlusThrow(kArgumentException, IDS_EE_INVALID_CA_EX, bstrMessage); |
| 863 | } |
| 864 | |
| 865 | COMPlusThrow(kArgumentException, IDS_EE_INVALID_CA); |
| 866 | } |
| 867 | |
| 868 | if (updateCompilerFlags) |
| 869 | { |
| 870 | DWORD flags = 0; |
| 871 | DWORD mask = ~(DACF_OBSOLETE_TRACK_JIT_INFO | DACF_IGNORE_PDBS | DACF_ALLOW_JIT_OPTS) & DACF_CONTROL_FLAGS_MASK; |
| 872 | |
| 873 | if ((cbBlob != 6) && (cbBlob != 8)) |
| 874 | { |
| 875 | _ASSERTE(!"COMDynamicWrite::CWInternalCreateCustomAttribute - unexpected size for DebuggableAttribute\n" ); |
| 876 | } |
| 877 | else if ( !((pBlob[0] == 1) && (pBlob[1] == 0)) ) |
| 878 | { |
| 879 | _ASSERTE(!"COMDynamicWrite::CWInternalCreateCustomAttribute - bad format for DebuggableAttribute\n" ); |
| 880 | } |
| 881 | |
| 882 | if (pBlob[2] & 0x1) |
| 883 | { |
| 884 | flags |= DACF_OBSOLETE_TRACK_JIT_INFO; |
| 885 | } |
| 886 | |
| 887 | if (pBlob[2] & 0x2) |
| 888 | { |
| 889 | flags |= DACF_IGNORE_PDBS; |
| 890 | } |
| 891 | |
| 892 | if ( ((pBlob[2] & 0x1) == 0) || (pBlob[3] == 0) ) |
| 893 | { |
| 894 | flags |= DACF_ALLOW_JIT_OPTS; |
| 895 | } |
| 896 | |
| 897 | Assembly* pAssembly = pModule->GetAssembly(); |
| 898 | DomainAssembly* pDomainAssembly = pAssembly->GetDomainAssembly(); |
| 899 | |
| 900 | DWORD actualFlags; |
| 901 | actualFlags = ((DWORD)pDomainAssembly->GetDebuggerInfoBits() & mask) | flags; |
| 902 | pDomainAssembly->SetDebuggerInfoBits((DebuggerAssemblyControlFlags)actualFlags); |
| 903 | |
| 904 | actualFlags = ((DWORD)pAssembly->GetDebuggerInfoBits() & mask) | flags; |
| 905 | pAssembly->SetDebuggerInfoBits((DebuggerAssemblyControlFlags)actualFlags); |
| 906 | |
| 907 | ModuleIterator i = pAssembly->IterateModules(); |
| 908 | while (i.Next()) |
| 909 | { |
| 910 | actualFlags = ((DWORD)(i.GetModule()->GetDebuggerInfoBits()) & mask) | flags; |
| 911 | i.GetModule()->SetDebuggerInfoBits((DebuggerAssemblyControlFlags)actualFlags); |
| 912 | } |
| 913 | } |
| 914 | |
| 915 | END_QCALL; |
| 916 | } |
| 917 | |