1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //    http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef sw_RoutineCache_hpp
16 #define sw_RoutineCache_hpp
17 
18 #include "LRUCache.hpp"
19 
20 #include "Reactor/Reactor.hpp"
21 
22 namespace sw
23 {
24 	template<class State>
25 	class RoutineCache : public LRUCache<State, Routine>
26 	{
27 	public:
28 		RoutineCache(int n, const char *precache = 0);
29 		~RoutineCache();
30 
31 	private:
32 		const char *precache;
33 		#if defined(_WIN32)
34 		HMODULE precacheDLL;
35 		#endif
36 	};
37 }
38 
39 #if defined(_WIN32)
40 	#include "Shader/Constants.hpp"
41 	#include "Reactor/DLL.hpp"
42 #endif
43 
44 namespace sw
45 {
46 	template<class State>
RoutineCache(int n,const char * precache)47 	RoutineCache<State>::RoutineCache(int n, const char *precache) : LRUCache<State, Routine>(n), precache(precache)
48 	{
49 		#if defined(_WIN32)
50 			precacheDLL = 0;
51 
52 			if(precache)
53 			{
54 				char dllName[1024]; sprintf(dllName, "%s.dll", precache);
55 				char dirName[1024]; sprintf(dirName, "%s.dir", precache);
56 
57 				precacheDLL = LoadLibrary(dllName);
58 				FILE *dir = fopen(dirName, "rb");
59 				int ordinal = 1;
60 
61 				while(precacheDLL && dir)
62 				{
63 					State state;
64 					int offset;
65 					int size;
66 
67 					size_t bytes = fread(&state, 1, sizeof(State), dir);
68 					bytes += fread(&offset, 1, sizeof(offset), dir);
69 					bytes += fread(&size, 1, sizeof(size), dir);
70 
71 					if(bytes != sizeof(State) + sizeof(offset) + sizeof(size))
72 					{
73 						break;
74 					}
75 
76 					void (*routine)(void) = (void(*)(void))GetProcAddress(precacheDLL, (char*)ordinal);
77 					ordinal++;
78 
79 					if(routine)
80 					{
81 						add(state, new Routine(routine, size, offset));
82 					}
83 				}
84 
85 				if(dir)
86 				{
87 					fclose(dir);
88 				}
89 			}
90 		#endif
91 	}
92 
93 	template<class State>
~RoutineCache()94 	RoutineCache<State>::~RoutineCache()
95 	{
96 		#if defined(_WIN32)
97 			char dllName[1024]; sprintf(dllName, "%s.dll", precache);
98 			char dirName[1024]; sprintf(dirName, "%s.dir", precache);
99 
100 			if(precache)
101 			{
102 				DLL dll(dllName, &constants, sizeof(Constants));
103 				FILE *dir = fopen(dirName, "wb");
104 
105 				for(int i = 0; i < getSize(); i++)
106 				{
107 					State &state = getKey(i);
108 					Routine *routine = query(state);
109 
110 					if(routine)
111 					{
112 						unsigned char *buffer = (unsigned char*)routine->getBuffer();
113 						unsigned char *entry = (unsigned char*)routine->getEntry();
114 						int size = routine->getBufferSize();
115 						int codeSize = routine->getCodeSize();
116 
117 						#ifndef _M_AMD64
118 							for(int j = 1; j < codeSize - 4; j++)
119 							{
120 								unsigned char modRM_SIB = entry[j - 1];
121 								unsigned int address = *(unsigned int*)&entry[j];
122 
123 								if((modRM_SIB & 0x05) == 0x05 && (address % 4) == 0)
124 								{
125 									if(address >= (unsigned int)buffer && address < (unsigned int)entry)   // Constant stored above the function entry
126 									{
127 										dll.addRelocation(buffer, &entry[j], true);
128 
129 										j += 4;
130 									}
131 								}
132 							}
133 						#else
134 							for(int j = 1; j < codeSize - 4; j++)
135 							{
136 								unsigned char modRM_SIB = entry[j - 1];
137 								uint64_t address = *(uint64_t*)&entry[j];
138 
139 							//	if((modRM_SIB & 0x05) == 0x05 && (address % 4) == 0)
140 								{
141 									if(address >= (uint64_t)buffer && address < (uint64_t)entry)   // Constant stored above the function entry
142 									{
143 										dll.addRelocation(buffer, &entry[j], true);
144 
145 										j += 4;
146 									}
147 								}
148 							}
149 						#endif
150 
151 						dll.addFunction(buffer, entry, size);
152 						fwrite(&state, 1, sizeof(State), dir);
153 						int offset = (int)(entry - buffer);
154 						fwrite(&offset, 1, sizeof(offset), dir);
155 						fwrite(&size, 1, sizeof(size), dir);
156 					}
157 				}
158 
159 				FreeLibrary(precacheDLL);
160 
161 				dll.emit();
162 				fclose(dir);
163 			}
164 			else
165 			{
166 				FreeLibrary(precacheDLL);
167 
168 				remove(dllName);
169 				remove(dirName);
170 			}
171 		#endif
172 	}
173 }
174 
175 #endif   // sw_RoutineCache_hpp
176