gfx/angle/src/compiler/SymbolTable.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 //
michael@0 2 // Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
michael@0 3 // Use of this source code is governed by a BSD-style license that can be
michael@0 4 // found in the LICENSE file.
michael@0 5 //
michael@0 6
michael@0 7 #ifndef _SYMBOL_TABLE_INCLUDED_
michael@0 8 #define _SYMBOL_TABLE_INCLUDED_
michael@0 9
michael@0 10 //
michael@0 11 // Symbol table for parsing. Has these design characteristics:
michael@0 12 //
michael@0 13 // * Same symbol table can be used to compile many shaders, to preserve
michael@0 14 // effort of creating and loading with the large numbers of built-in
michael@0 15 // symbols.
michael@0 16 //
michael@0 17 // * Name mangling will be used to give each function a unique name
michael@0 18 // so that symbol table lookups are never ambiguous. This allows
michael@0 19 // a simpler symbol table structure.
michael@0 20 //
michael@0 21 // * Pushing and popping of scope, so symbol table will really be a stack
michael@0 22 // of symbol tables. Searched from the top, with new inserts going into
michael@0 23 // the top.
michael@0 24 //
michael@0 25 // * Constants: Compile time constant symbols will keep their values
michael@0 26 // in the symbol table. The parser can substitute constants at parse
michael@0 27 // time, including doing constant folding and constant propagation.
michael@0 28 //
michael@0 29 // * No temporaries: Temporaries made from operations (+, --, .xy, etc.)
michael@0 30 // are tracked in the intermediate representation, not the symbol table.
michael@0 31 //
michael@0 32
michael@0 33 #include <assert.h>
michael@0 34
michael@0 35 #include "common/angleutils.h"
michael@0 36 #include "compiler/InfoSink.h"
michael@0 37 #include "compiler/intermediate.h"
michael@0 38
michael@0 39 //
michael@0 40 // Symbol base class. (Can build functions or variables out of these...)
michael@0 41 //
michael@0 42 class TSymbol {
michael@0 43 public:
michael@0 44 POOL_ALLOCATOR_NEW_DELETE();
michael@0 45 TSymbol(const TString *n) : name(n) { }
michael@0 46 virtual ~TSymbol() { /* don't delete name, it's from the pool */ }
michael@0 47
michael@0 48 const TString& getName() const { return *name; }
michael@0 49 virtual const TString& getMangledName() const { return getName(); }
michael@0 50 virtual bool isFunction() const { return false; }
michael@0 51 virtual bool isVariable() const { return false; }
michael@0 52 void setUniqueId(int id) { uniqueId = id; }
michael@0 53 int getUniqueId() const { return uniqueId; }
michael@0 54 virtual void dump(TInfoSink &infoSink) const = 0;
michael@0 55 void relateToExtension(const TString& ext) { extension = ext; }
michael@0 56 const TString& getExtension() const { return extension; }
michael@0 57
michael@0 58 private:
michael@0 59 DISALLOW_COPY_AND_ASSIGN(TSymbol);
michael@0 60
michael@0 61 const TString *name;
michael@0 62 unsigned int uniqueId; // For real comparing during code generation
michael@0 63 TString extension;
michael@0 64 };
michael@0 65
michael@0 66 //
michael@0 67 // Variable class, meaning a symbol that's not a function.
michael@0 68 //
michael@0 69 // There could be a separate class heirarchy for Constant variables;
michael@0 70 // Only one of int, bool, or float, (or none) is correct for
michael@0 71 // any particular use, but it's easy to do this way, and doesn't
michael@0 72 // seem worth having separate classes, and "getConst" can't simply return
michael@0 73 // different values for different types polymorphically, so this is
michael@0 74 // just simple and pragmatic.
michael@0 75 //
michael@0 76 class TVariable : public TSymbol {
michael@0 77 public:
michael@0 78 TVariable(const TString *name, const TType& t, bool uT = false ) : TSymbol(name), type(t), userType(uT), unionArray(0) { }
michael@0 79 virtual ~TVariable() { }
michael@0 80 virtual bool isVariable() const { return true; }
michael@0 81 TType& getType() { return type; }
michael@0 82 const TType& getType() const { return type; }
michael@0 83 bool isUserType() const { return userType; }
michael@0 84 void setQualifier(TQualifier qualifier) { type.setQualifier(qualifier); }
michael@0 85
michael@0 86 virtual void dump(TInfoSink &infoSink) const;
michael@0 87
michael@0 88 ConstantUnion* getConstPointer()
michael@0 89 {
michael@0 90 if (!unionArray)
michael@0 91 unionArray = new ConstantUnion[type.getObjectSize()];
michael@0 92
michael@0 93 return unionArray;
michael@0 94 }
michael@0 95
michael@0 96 ConstantUnion* getConstPointer() const { return unionArray; }
michael@0 97
michael@0 98 void shareConstPointer( ConstantUnion *constArray)
michael@0 99 {
michael@0 100 if (unionArray == constArray)
michael@0 101 return;
michael@0 102
michael@0 103 delete[] unionArray;
michael@0 104 unionArray = constArray;
michael@0 105 }
michael@0 106
michael@0 107 private:
michael@0 108 DISALLOW_COPY_AND_ASSIGN(TVariable);
michael@0 109
michael@0 110 TType type;
michael@0 111 bool userType;
michael@0 112 // we are assuming that Pool Allocator will free the memory allocated to unionArray
michael@0 113 // when this object is destroyed
michael@0 114 ConstantUnion *unionArray;
michael@0 115 };
michael@0 116
michael@0 117 //
michael@0 118 // The function sub-class of symbols and the parser will need to
michael@0 119 // share this definition of a function parameter.
michael@0 120 //
michael@0 121 struct TParameter {
michael@0 122 TString *name;
michael@0 123 TType* type;
michael@0 124 };
michael@0 125
michael@0 126 //
michael@0 127 // The function sub-class of a symbol.
michael@0 128 //
michael@0 129 class TFunction : public TSymbol {
michael@0 130 public:
michael@0 131 TFunction(TOperator o) :
michael@0 132 TSymbol(0),
michael@0 133 returnType(TType(EbtVoid, EbpUndefined)),
michael@0 134 op(o),
michael@0 135 defined(false) { }
michael@0 136 TFunction(const TString *name, TType& retType, TOperator tOp = EOpNull) :
michael@0 137 TSymbol(name),
michael@0 138 returnType(retType),
michael@0 139 mangledName(TFunction::mangleName(*name)),
michael@0 140 op(tOp),
michael@0 141 defined(false) { }
michael@0 142 virtual ~TFunction();
michael@0 143 virtual bool isFunction() const { return true; }
michael@0 144
michael@0 145 static TString mangleName(const TString& name) { return name + '('; }
michael@0 146 static TString unmangleName(const TString& mangledName)
michael@0 147 {
michael@0 148 return TString(mangledName.c_str(), mangledName.find_first_of('('));
michael@0 149 }
michael@0 150
michael@0 151 void addParameter(TParameter& p)
michael@0 152 {
michael@0 153 parameters.push_back(p);
michael@0 154 mangledName = mangledName + p.type->getMangledName();
michael@0 155 }
michael@0 156
michael@0 157 const TString& getMangledName() const { return mangledName; }
michael@0 158 const TType& getReturnType() const { return returnType; }
michael@0 159
michael@0 160 void relateToOperator(TOperator o) { op = o; }
michael@0 161 TOperator getBuiltInOp() const { return op; }
michael@0 162
michael@0 163 void setDefined() { defined = true; }
michael@0 164 bool isDefined() { return defined; }
michael@0 165
michael@0 166 size_t getParamCount() const { return parameters.size(); }
michael@0 167 const TParameter& getParam(size_t i) const { return parameters[i]; }
michael@0 168
michael@0 169 virtual void dump(TInfoSink &infoSink) const;
michael@0 170
michael@0 171 private:
michael@0 172 DISALLOW_COPY_AND_ASSIGN(TFunction);
michael@0 173
michael@0 174 typedef TVector<TParameter> TParamList;
michael@0 175 TParamList parameters;
michael@0 176 TType returnType;
michael@0 177 TString mangledName;
michael@0 178 TOperator op;
michael@0 179 bool defined;
michael@0 180 };
michael@0 181
michael@0 182
michael@0 183 class TSymbolTableLevel {
michael@0 184 public:
michael@0 185 typedef TMap<TString, TSymbol*> tLevel;
michael@0 186 typedef tLevel::const_iterator const_iterator;
michael@0 187 typedef const tLevel::value_type tLevelPair;
michael@0 188 typedef std::pair<tLevel::iterator, bool> tInsertResult;
michael@0 189
michael@0 190 POOL_ALLOCATOR_NEW_DELETE();
michael@0 191 TSymbolTableLevel() { }
michael@0 192 ~TSymbolTableLevel();
michael@0 193
michael@0 194 bool insert(const TString &name, TSymbol &symbol)
michael@0 195 {
michael@0 196 //
michael@0 197 // returning true means symbol was added to the table
michael@0 198 //
michael@0 199 tInsertResult result;
michael@0 200 result = level.insert(tLevelPair(name, &symbol));
michael@0 201
michael@0 202 return result.second;
michael@0 203 }
michael@0 204
michael@0 205 bool insert(TSymbol &symbol)
michael@0 206 {
michael@0 207 return insert(symbol.getMangledName(), symbol);
michael@0 208 }
michael@0 209
michael@0 210 TSymbol* find(const TString& name) const
michael@0 211 {
michael@0 212 tLevel::const_iterator it = level.find(name);
michael@0 213 if (it == level.end())
michael@0 214 return 0;
michael@0 215 else
michael@0 216 return (*it).second;
michael@0 217 }
michael@0 218
michael@0 219 const_iterator begin() const
michael@0 220 {
michael@0 221 return level.begin();
michael@0 222 }
michael@0 223
michael@0 224 const_iterator end() const
michael@0 225 {
michael@0 226 return level.end();
michael@0 227 }
michael@0 228
michael@0 229 void relateToOperator(const char* name, TOperator op);
michael@0 230 void relateToExtension(const char* name, const TString& ext);
michael@0 231 void dump(TInfoSink &infoSink) const;
michael@0 232
michael@0 233 protected:
michael@0 234 tLevel level;
michael@0 235 };
michael@0 236
michael@0 237 class TSymbolTable {
michael@0 238 public:
michael@0 239 TSymbolTable() : uniqueId(0)
michael@0 240 {
michael@0 241 //
michael@0 242 // The symbol table cannot be used until push() is called, but
michael@0 243 // the lack of an initial call to push() can be used to detect
michael@0 244 // that the symbol table has not been preloaded with built-ins.
michael@0 245 //
michael@0 246 }
michael@0 247
michael@0 248 ~TSymbolTable()
michael@0 249 {
michael@0 250 // level 0 is always built In symbols, so we never pop that out
michael@0 251 while (table.size() > 1)
michael@0 252 pop();
michael@0 253 }
michael@0 254
michael@0 255 //
michael@0 256 // When the symbol table is initialized with the built-ins, there should
michael@0 257 // 'push' calls, so that built-ins are at level 0 and the shader
michael@0 258 // globals are at level 1.
michael@0 259 //
michael@0 260 bool isEmpty() { return table.size() == 0; }
michael@0 261 bool atBuiltInLevel() { return table.size() == 1; }
michael@0 262 bool atGlobalLevel() { return table.size() <= 2; }
michael@0 263 void push()
michael@0 264 {
michael@0 265 table.push_back(new TSymbolTableLevel);
michael@0 266 precisionStack.push_back( PrecisionStackLevel() );
michael@0 267 }
michael@0 268
michael@0 269 void pop()
michael@0 270 {
michael@0 271 delete table[currentLevel()];
michael@0 272 table.pop_back();
michael@0 273 precisionStack.pop_back();
michael@0 274 }
michael@0 275
michael@0 276 bool insert(TSymbol& symbol)
michael@0 277 {
michael@0 278 symbol.setUniqueId(++uniqueId);
michael@0 279 return table[currentLevel()]->insert(symbol);
michael@0 280 }
michael@0 281
michael@0 282 bool insertConstInt(const char *name, int value)
michael@0 283 {
michael@0 284 TVariable *constant = new TVariable(NewPoolTString(name), TType(EbtInt, EbpUndefined, EvqConst, 1));
michael@0 285 constant->getConstPointer()->setIConst(value);
michael@0 286 return insert(*constant);
michael@0 287 }
michael@0 288
michael@0 289 bool insertBuiltIn(TType *rvalue, const char *name, TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0)
michael@0 290 {
michael@0 291 TFunction *function = new TFunction(NewPoolTString(name), *rvalue);
michael@0 292
michael@0 293 TParameter param1 = {NULL, ptype1};
michael@0 294 function->addParameter(param1);
michael@0 295
michael@0 296 if(ptype2)
michael@0 297 {
michael@0 298 TParameter param2 = {NULL, ptype2};
michael@0 299 function->addParameter(param2);
michael@0 300 }
michael@0 301
michael@0 302 if(ptype3)
michael@0 303 {
michael@0 304 TParameter param3 = {NULL, ptype3};
michael@0 305 function->addParameter(param3);
michael@0 306 }
michael@0 307
michael@0 308 return insert(*function);
michael@0 309 }
michael@0 310
michael@0 311 TSymbol* find(const TString& name, bool* builtIn = 0, bool *sameScope = 0)
michael@0 312 {
michael@0 313 int level = currentLevel();
michael@0 314 TSymbol* symbol;
michael@0 315 do {
michael@0 316 symbol = table[level]->find(name);
michael@0 317 --level;
michael@0 318 } while (symbol == 0 && level >= 0);
michael@0 319 level++;
michael@0 320 if (builtIn)
michael@0 321 *builtIn = level == 0;
michael@0 322 if (sameScope)
michael@0 323 *sameScope = level == currentLevel();
michael@0 324 return symbol;
michael@0 325 }
michael@0 326
michael@0 327 TSymbol *findBuiltIn(const TString &name)
michael@0 328 {
michael@0 329 return table[0]->find(name);
michael@0 330 }
michael@0 331
michael@0 332 TSymbolTableLevel* getGlobalLevel() {
michael@0 333 assert(table.size() >= 2);
michael@0 334 return table[1];
michael@0 335 }
michael@0 336
michael@0 337 TSymbolTableLevel* getOuterLevel() {
michael@0 338 assert(table.size() >= 2);
michael@0 339 return table[currentLevel() - 1];
michael@0 340 }
michael@0 341
michael@0 342 void relateToOperator(const char* name, TOperator op) {
michael@0 343 table[0]->relateToOperator(name, op);
michael@0 344 }
michael@0 345 void relateToExtension(const char* name, const TString& ext) {
michael@0 346 table[0]->relateToExtension(name, ext);
michael@0 347 }
michael@0 348 int getMaxSymbolId() { return uniqueId; }
michael@0 349 void dump(TInfoSink &infoSink) const;
michael@0 350
michael@0 351 bool setDefaultPrecision( const TPublicType& type, TPrecision prec ){
michael@0 352 if (IsSampler(type.type))
michael@0 353 return true; // Skip sampler types for the time being
michael@0 354 if (type.type != EbtFloat && type.type != EbtInt)
michael@0 355 return false; // Only set default precision for int/float
michael@0 356 if (type.size != 1 || type.matrix || type.array)
michael@0 357 return false; // Not allowed to set for aggregate types
michael@0 358 int indexOfLastElement = static_cast<int>(precisionStack.size()) - 1;
michael@0 359 precisionStack[indexOfLastElement][type.type] = prec; // Uses map operator [], overwrites the current value
michael@0 360 return true;
michael@0 361 }
michael@0 362
michael@0 363 // Searches down the precisionStack for a precision qualifier for the specified TBasicType
michael@0 364 TPrecision getDefaultPrecision( TBasicType type){
michael@0 365 if( type != EbtFloat && type != EbtInt ) return EbpUndefined;
michael@0 366 int level = static_cast<int>(precisionStack.size()) - 1;
michael@0 367 assert( level >= 0); // Just to be safe. Should not happen.
michael@0 368 PrecisionStackLevel::iterator it;
michael@0 369 TPrecision prec = EbpUndefined; // If we dont find anything we return this. Should we error check this?
michael@0 370 while( level >= 0 ){
michael@0 371 it = precisionStack[level].find( type );
michael@0 372 if( it != precisionStack[level].end() ){
michael@0 373 prec = (*it).second;
michael@0 374 break;
michael@0 375 }
michael@0 376 level--;
michael@0 377 }
michael@0 378 return prec;
michael@0 379 }
michael@0 380
michael@0 381 protected:
michael@0 382 int currentLevel() const { return static_cast<int>(table.size()) - 1; }
michael@0 383
michael@0 384 std::vector<TSymbolTableLevel*> table;
michael@0 385 typedef std::map< TBasicType, TPrecision > PrecisionStackLevel;
michael@0 386 std::vector< PrecisionStackLevel > precisionStack;
michael@0 387 int uniqueId; // for unique identification in code generation
michael@0 388 };
michael@0 389
michael@0 390 #endif // _SYMBOL_TABLE_INCLUDED_

mercurial