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 | |