summaryrefslogtreecommitdiff
path: root/src/md/compiler/regmeta_vm.cpp
blob: 4b227add89f708c371c9bd816be65d08e8201e46 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

    
//*****************************************************************************

// 
// RegMeta.cpp
//
// Implementation for meta data public interface methods for full version.
//
//*****************************************************************************
#include "stdafx.h"
#include "regmeta.h"
#include "metadata.h"
#include "corerror.h"
#include "mdutil.h"
#include "rwutil.h"
#include "mdlog.h"
#include "importhelper.h"
#include "filtermanager.h"
#include "mdperf.h"
#include "switches.h"
#include "posterror.h"
#include "stgio.h"
#include "sstring.h"

#include <metamodelrw.h>




#define DEFINE_CUSTOM_NODUPCHECK    1
#define DEFINE_CUSTOM_DUPCHECK      2
#define SET_CUSTOM                  3

#if defined(_DEBUG) && defined(_TRACE_REMAPS)
#define LOGGING
#endif
#include <log.h>

#ifdef _MSC_VER
#pragma warning(disable: 4102)
#endif

//*****************************************************************************
// Call this after initialization is complete.
//*****************************************************************************
HRESULT RegMeta::AddToCache()
{
#if defined(FEATURE_METADATA_IN_VM)
    HRESULT hr = S_OK;

    // The ref count must be > 0 before the module is published, else another
    //  thread could find, use, and release the module, causing it to be deleted
    //  before this thread gets a chance to addref.
    _ASSERTE(GetRefCount() > 0);
    // add this RegMeta to the loaded module list.
    m_bCached = true;
    IfFailGo(LOADEDMODULES::AddModuleToLoadedList(this));
ErrExit:
    if (FAILED(hr))
    {
        _ASSERTE(!LOADEDMODULES::IsEntryInList(this));
        m_bCached = false;
    }
    return hr;
#else // FEATURE_METADATA_IN_VM 
    return S_OK;
#endif // FEATURE_METADATA_IN_VM 
} // RegMeta::AddToCache


//*****************************************************************************
// Search the cached RegMetas for a given scope.
//*****************************************************************************
HRESULT RegMeta::FindCachedReadOnlyEntry(
    LPCWSTR     szName,                 // Name of the desired file.
    DWORD       dwOpenFlags,            // Flags the new file is opened with.
    RegMeta     **ppMeta)               // Put found RegMeta here.
{
#if defined(FEATURE_METADATA_IN_VM)
    return LOADEDMODULES::FindCachedReadOnlyEntry(szName, dwOpenFlags, ppMeta);
#else // FEATURE_METADATA_IN_VM 
    // No cache support in standalone version.
    *ppMeta = NULL;
    return S_FALSE;
#endif // FEATURE_METADATA_IN_VM 
} // RegMeta::FindCachedReadOnlyEntry


#ifdef FEATURE_METADATA_EMIT_ALL

//*****************************************************************************
// Helper function to startup the EE
// 
// Notes:
//    This is called by code:RegMeta.DefineSecurityAttributeSet.
//*****************************************************************************
HRESULT RegMeta::StartupEE()
{
    UNREACHABLE_MSG_RET("About to CoCreateInstance!  This code should not be "
                        "reachable or needs to be reimplemented for CoreCLR!");
}

#endif //FEATURE_METADATA_EMIT_ALL

#ifdef FEATURE_METADATA_EMIT

//*****************************************************************************
// Persist a set of security custom attributes into a set of permission set
// blobs on the same class or method.
// 
// Notes:
//    Only in the full version because this is an emit operation.
//*****************************************************************************
HRESULT RegMeta::DefineSecurityAttributeSet(// Return code.
    mdToken     tkObj,                  // [IN] Class or method requiring security attributes.
    COR_SECATTR rSecAttrs[],            // [IN] Array of security attribute descriptions.
    ULONG       cSecAttrs,              // [IN] Count of elements in above array.
    ULONG       *pulErrorAttr)          // [OUT] On error, index of attribute causing problem.
{
    return E_NOTIMPL;
} // RegMeta::DefineSecurityAttributeSet

#endif //FEATURE_METADATA_EMIT


//*****************************************************************************
// Implementation of IMetaDataImport::ResolveTypeRef to resolve a typeref across scopes. 
// 
// Arguments:
//    tr - typeref within this scope to resolve
//    riid - interface on ppIScope to support
//    ppIScope - out-parameter to get metadata scope for typedef (*ptd)
//    ptd - out-parameter to get typedef that the ref resolves to.
// 
// Notes:
// TypeDefs define a type within a scope. TypeRefs refer to type-defs in other scopes
// and allow you to import a type from another scope. This function attempts to determine
// which type-def a type-ref points to.
// 
// This resolve (type-ref, this cope) --> (type-def=*ptd, other scope=*ppIScope)
// 
// However, this resolution requires knowing what modules have been loaded, which is not decided
// until runtime via loader / fusion policy. Thus this interface can't possibly be correct since
// it doesn't have that knowledge. Furthermore, when inspecting metadata from another process
// (such as a debugger inspecting the debuggee's metadata), this API can be truly misleading.
// 
// This API usage should be avoided.
// 
//*****************************************************************************
STDMETHODIMP 
RegMeta::ResolveTypeRef(
    mdTypeRef   tr, 
    REFIID      riid, 
    IUnknown ** ppIScope, 
    mdTypeDef * ptd)
{
#ifdef FEATURE_METADATA_IN_VM
    HRESULT hr;

    BEGIN_ENTRYPOINT_NOTHROW;

    TypeRefRec * pTypeRefRec;
    WCHAR        wzNameSpace[_MAX_PATH];
    CMiniMdRW *  pMiniMd = NULL;

    LOG((LOGMD, "{%08x} RegMeta::ResolveTypeRef(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", 
        this, tr, riid, ppIScope, ptd));

    START_MD_PERF();
    LOCKREAD();

    pMiniMd = &(m_pStgdb->m_MiniMd);

    _ASSERTE((ppIScope != NULL) && (ptd != NULL));

    // Init the output values.
    *ppIScope = NULL;
    *ptd = 0;

    if (IsNilToken(tr))
    {
        if (ptd != NULL) 
        {
            *ptd = mdTypeDefNil;
        }

        if (ppIScope != NULL)
        {
            *ppIScope = NULL;
        }
        
        STOP_MD_PERF(ResolveTypeRef);
        hr = E_INVALIDARG;
        goto ErrExit;
    }

    if (TypeFromToken(tr) == mdtTypeDef)
    {
        // Shortcut when we receive a TypeDef token
        *ptd = tr;
        STOP_MD_PERF(ResolveTypeRef);
        hr = this->QueryInterface(riid, (void **)ppIScope);
        goto ErrExit;
    }

    // Get the class ref row.
    _ASSERTE(TypeFromToken(tr) == mdtTypeRef);

    IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tr), &pTypeRefRec));
    IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, wzNameSpace, lengthof(wzNameSpace), NULL));
    if (hr != NOERROR)
    {
        _ASSERTE(hr == CLDB_S_TRUNCATION);
        // Truncate the namespace string
        wzNameSpace[lengthof(wzNameSpace) - 1] = 0;
    }
    
    //***********************
    // before we go off to CORPATH, check the loaded modules!
    //***********************
    if (LOADEDMODULES::ResolveTypeRefWithLoadedModules(
        tr, 
        this, 
        pMiniMd, 
        riid, 
        ppIScope, 
        ptd) == NOERROR)
    {
        // Done!! We found one match among the loaded modules.
        goto ErrExit;
    }

    IfFailGo(META_E_CANNOTRESOLVETYPEREF);

ErrExit:
    STOP_MD_PERF(ResolveTypeRef);
    END_ENTRYPOINT_NOTHROW;
    
    return hr;
#else // FEATURE_METADATA_IN_VM
    return E_NOTIMPL;
#endif // FEATURE_METADATA_IN_VM
} // RegMeta::ResolveTypeRef



// Full version handles metadata caching, which Release() needs to coordinate with. 
// Thus Release() is in a satellite lib.
ULONG RegMeta::Release()
{
    // This is called during cleanup.  We can not fail this call by probing.
    // As long as we make sure the cleanup does not use too much space through 
    // BEGIN_CLEANUP_ENTRYPOINT, we are OK.
    CONTRACT_VIOLATION (SOToleranceViolation);
    BEGIN_CLEANUP_ENTRYPOINT;

#if defined(FEATURE_METADATA_IN_VM)
    _ASSERTE(!m_bCached || LOADEDMODULES::IsEntryInList(this));
#else
    _ASSERTE(!m_bCached);
#endif // FEATURE_METADATA_IN_VM 
    BOOL  bCached = m_bCached;
    ULONG cRef = InterlockedDecrement(&m_cRef);
    // NOTE: 'this' may be unsafe after this point, if the module is cached, and
    //  another thread finds the module in the cache, releases it, and deletes it
    //  before we get around to deleting it. (That's why we must make a local copy
    //  of m_bCached.)
    // If no references left...
    if (cRef == 0)
    {
        if (!bCached)
        {   // If the module is not (was not) cached, no other thread can have
            //  discovered the module, so this thread can now safely delete it.
            delete this;
        }
#if defined(FEATURE_METADATA_IN_VM)
        else if (LOADEDMODULES::RemoveModuleFromLoadedList(this))
        {   // If the module was cached, RemoveModuleFromLoadedList() will try to
            //  safely un-publish the module, and if it succeeds, no other thread
            //  has (or will) discover the module, so this thread can delete it.
            m_bCached = false;
            delete this;
        }
#endif // FEATURE_METADATA_IN_VM 
    }
    END_CLEANUP_ENTRYPOINT
    
    return cRef;
} // RegMeta::Release