1 | // |
2 | // Copyright (c) Microsoft. All rights reserved. |
3 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. |
4 | // |
5 | |
6 | #include "standardpch.h" |
7 | #include "verbremovedup.h" |
8 | #include "simpletimer.h" |
9 | #include "lightweightmap.h" |
10 | #include "methodcontext.h" |
11 | #include "methodcontextiterator.h" |
12 | |
13 | // We use a hash to limit the number of comparisons we need to do. |
14 | // The first level key to our hash map is ILCodeSize and the second |
15 | // level map key is just an index and the value is an existing MC Hash. |
16 | |
17 | LightWeightMap<int, DenseLightWeightMap<char*>*>* inFile = nullptr; |
18 | |
19 | bool unique(MethodContext* mc) |
20 | { |
21 | if (inFile == nullptr) |
22 | inFile = new LightWeightMap<int, DenseLightWeightMap<char*>*>(); |
23 | |
24 | CORINFO_METHOD_INFO newInfo; |
25 | unsigned newFlags = 0; |
26 | mc->repCompileMethod(&newInfo, &newFlags); |
27 | |
28 | char* md5Buff = new char[MD5_HASH_BUFFER_SIZE]; |
29 | mc->dumpMethodMD5HashToBuffer(md5Buff, MD5_HASH_BUFFER_SIZE); |
30 | |
31 | if (inFile->GetIndex(newInfo.ILCodeSize) == -1) |
32 | inFile->Add(newInfo.ILCodeSize, new DenseLightWeightMap<char*>()); |
33 | |
34 | DenseLightWeightMap<char*>* ourRank = inFile->Get(newInfo.ILCodeSize); |
35 | |
36 | for (int i = 0; i < (int)ourRank->GetCount(); i++) |
37 | { |
38 | char* md5Buff2 = ourRank->Get(i); |
39 | |
40 | if (strncmp(md5Buff, md5Buff2, MD5_HASH_BUFFER_SIZE) == 0) |
41 | { |
42 | delete[] md5Buff; |
43 | return false; |
44 | } |
45 | } |
46 | |
47 | ourRank->Append(md5Buff); |
48 | return true; |
49 | } |
50 | |
51 | LightWeightMap<int, DenseLightWeightMap<MethodContext*>*>* inFileLegacy = nullptr; |
52 | |
53 | bool uniqueLegacy(MethodContext* mc) |
54 | { |
55 | if (inFileLegacy == nullptr) |
56 | inFileLegacy = new LightWeightMap<int, DenseLightWeightMap<MethodContext*>*>(); |
57 | |
58 | CORINFO_METHOD_INFO newInfo; |
59 | unsigned newFlags = 0; |
60 | mc->repCompileMethod(&newInfo, &newFlags); |
61 | |
62 | if (inFileLegacy->GetIndex(newInfo.ILCodeSize) == -1) |
63 | inFileLegacy->Add(newInfo.ILCodeSize, new DenseLightWeightMap<MethodContext*>()); |
64 | |
65 | DenseLightWeightMap<MethodContext*>* ourRank = inFileLegacy->Get(newInfo.ILCodeSize); |
66 | |
67 | for (int i = 0; i < (int)ourRank->GetCount(); i++) |
68 | { |
69 | MethodContext* scratch = ourRank->Get(i); |
70 | if (mc->Equal(scratch)) |
71 | { |
72 | return false; |
73 | } |
74 | } |
75 | |
76 | // We store the MethodContext in our map. |
77 | ourRank->Append(mc); |
78 | return true; |
79 | } |
80 | |
81 | int verbRemoveDup::DoWork(const char* nameOfInput, const char* nameOfOutput, bool stripCR, bool legacyCompare) |
82 | { |
83 | LogVerbose("Removing duplicates from '%s', writing to '%s'" , nameOfInput, nameOfOutput); |
84 | |
85 | MethodContextIterator mci(true); |
86 | if (!mci.Initialize(nameOfInput)) |
87 | return -1; |
88 | |
89 | int savedCount = 0; |
90 | |
91 | HANDLE hFileOut = CreateFileA(nameOfOutput, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, |
92 | FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); |
93 | if (hFileOut == INVALID_HANDLE_VALUE) |
94 | { |
95 | LogError("Failed to open output '%s'. GetLastError()=%u" , nameOfOutput, GetLastError()); |
96 | return -1; |
97 | } |
98 | |
99 | while (mci.MoveNext()) |
100 | { |
101 | MethodContext* mc = mci.CurrentTakeOwnership(); |
102 | if (stripCR) |
103 | { |
104 | delete mc->cr; |
105 | mc->cr = new CompileResult(); |
106 | } |
107 | if (legacyCompare) |
108 | { |
109 | if (uniqueLegacy(mc)) |
110 | { |
111 | mc->saveToFile(hFileOut); |
112 | savedCount++; |
113 | |
114 | // In this case, for the legacy comparer, it has placed the 'mc' in the 'inFileLegacy' table, so we |
115 | // can't delete it. |
116 | } |
117 | else |
118 | { |
119 | delete mc; // we no longer need this |
120 | } |
121 | } |
122 | else |
123 | { |
124 | if (unique(mc)) |
125 | { |
126 | mc->saveToFile(hFileOut); |
127 | savedCount++; |
128 | } |
129 | delete mc; // we no longer need this |
130 | } |
131 | } |
132 | |
133 | // We're leaking 'inFile' or 'inFileLegacy', but the process is going away, so it shouldn't matter. |
134 | |
135 | if (CloseHandle(hFileOut) == 0) |
136 | { |
137 | LogError("2nd CloseHandle failed. GetLastError()=%u" , GetLastError()); |
138 | return -1; |
139 | } |
140 | |
141 | LogInfo("Loaded %d, Saved %d" , mci.MethodContextNumber(), savedCount); |
142 | |
143 | if (!mci.Destroy()) |
144 | return -1; |
145 | |
146 | return 0; |
147 | } |
148 | |