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>
27struct 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//*************************************************************
44INT32 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
68INT32 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
128void 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
143void 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
158INT32 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
180INT32 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==============================================================================*/
212mdFieldDef 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.
242UINT32 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
286void 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 fatHeader;
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 headerSize = 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
460void 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==============================================================================*/
499void 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==============================================================================*/
528INT32 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==============================================================================*/
565INT32 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==============================================================================*/
595void 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==============================================================================*/
616void 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==============================================================================*/
636void 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==============================================================================*/
660INT32 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==============================================================================*/
690INT32 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==============================================================================*/
724void 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==============================================================================*/
780void 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==============================================================================*/
804void 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
823void 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