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