1 /*
2  * Copyright 2016 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "src/sksl/ir/SkSLSymbolTable.h"
9 
10 #include "src/sksl/ir/SkSLSymbolAlias.h"
11 #include "src/sksl/ir/SkSLType.h"
12 #include "src/sksl/ir/SkSLUnresolvedFunction.h"
13 
14 namespace SkSL {
15 
GetFunctions(const Symbol & s)16 std::vector<const FunctionDeclaration*> SymbolTable::GetFunctions(const Symbol& s) {
17     switch (s.kind()) {
18         case Symbol::Kind::kFunctionDeclaration:
19             return { &s.as<FunctionDeclaration>() };
20         case Symbol::Kind::kUnresolvedFunction:
21             return s.as<UnresolvedFunction>().functions();
22         default:
23             return std::vector<const FunctionDeclaration*>();
24     }
25 }
26 
operator [](StringFragment name)27 const Symbol* SymbolTable::operator[](StringFragment name) {
28     return this->lookup(fBuiltin ? nullptr : this, MakeSymbolKey(name));
29 }
30 
lookup(SymbolTable * writableSymbolTable,const SymbolKey & key)31 const Symbol* SymbolTable::lookup(SymbolTable* writableSymbolTable, const SymbolKey& key) {
32     // Symbol-table lookup can cause new UnresolvedFunction nodes to be created; however, we don't
33     // want these to end up in built-in root symbol tables (where they will outlive the Program
34     // associated with those UnresolvedFunction nodes). `writableSymbolTable` tracks the closest
35     // symbol table to the root which is not a built-in.
36     if (!fBuiltin) {
37         writableSymbolTable = this;
38     }
39     const Symbol** symbolPPtr = fSymbols.find(key);
40     if (!symbolPPtr) {
41         if (fParent) {
42             return fParent->lookup(writableSymbolTable, key);
43         }
44         return nullptr;
45     }
46 
47     const Symbol* symbol = *symbolPPtr;
48     if (fParent) {
49         auto functions = GetFunctions(*symbol);
50         if (functions.size() > 0) {
51             bool modified = false;
52             const Symbol* previous = fParent->lookup(writableSymbolTable, key);
53             if (previous) {
54                 auto previousFunctions = GetFunctions(*previous);
55                 for (const FunctionDeclaration* prev : previousFunctions) {
56                     bool found = false;
57                     for (const FunctionDeclaration* current : functions) {
58                         if (current->matches(*prev)) {
59                             found = true;
60                             break;
61                         }
62                     }
63                     if (!found) {
64                         functions.push_back(prev);
65                         modified = true;
66                     }
67                 }
68                 if (modified) {
69                     SkASSERT(functions.size() > 1);
70                     return writableSymbolTable
71                                    ? writableSymbolTable->takeOwnershipOfSymbol(
72                                              std::make_unique<UnresolvedFunction>(functions))
73                                    : nullptr;
74                 }
75             }
76         }
77     }
78     while (symbol && symbol->is<SymbolAlias>()) {
79         symbol = symbol->as<SymbolAlias>().origSymbol();
80     }
81     return symbol;
82 }
83 
takeOwnershipOfString(String str)84 const String* SymbolTable::takeOwnershipOfString(String str) {
85     fOwnedStrings.push_front(std::move(str));
86     // Because fOwnedStrings is a linked list, pointers to elements are stable.
87     return &fOwnedStrings.front();
88 }
89 
addAlias(StringFragment name,const Symbol * symbol)90 void SymbolTable::addAlias(StringFragment name, const Symbol* symbol) {
91     this->add(std::make_unique<SymbolAlias>(symbol->fOffset, name, symbol));
92 }
93 
addWithoutOwnership(const Symbol * symbol)94 void SymbolTable::addWithoutOwnership(const Symbol* symbol) {
95     const StringFragment& name = symbol->name();
96 
97     const Symbol*& refInSymbolTable = fSymbols[MakeSymbolKey(name)];
98     if (refInSymbolTable == nullptr) {
99         refInSymbolTable = symbol;
100         return;
101     }
102 
103     if (!symbol->is<FunctionDeclaration>()) {
104         fErrorReporter.error(symbol->fOffset, "symbol '" + name + "' was already defined");
105         return;
106     }
107 
108     std::vector<const FunctionDeclaration*> functions;
109     if (refInSymbolTable->is<FunctionDeclaration>()) {
110         functions = {&refInSymbolTable->as<FunctionDeclaration>(),
111                      &symbol->as<FunctionDeclaration>()};
112 
113         refInSymbolTable = this->takeOwnershipOfSymbol(
114                 std::make_unique<UnresolvedFunction>(std::move(functions)));
115     } else if (refInSymbolTable->is<UnresolvedFunction>()) {
116         functions = refInSymbolTable->as<UnresolvedFunction>().functions();
117         functions.push_back(&symbol->as<FunctionDeclaration>());
118 
119         refInSymbolTable = this->takeOwnershipOfSymbol(
120                 std::make_unique<UnresolvedFunction>(std::move(functions)));
121     }
122 }
123 
addArrayDimension(const Type * type,int arraySize)124 const Type* SymbolTable::addArrayDimension(const Type* type, int arraySize) {
125     if (arraySize != 0) {
126         String baseName = type->name();
127         String arrayName = (arraySize != Type::kUnsizedArray)
128                                    ? String::printf("%s[%d]", baseName.c_str(), arraySize)
129                                    : String::printf("%s[]", baseName.c_str());
130         type = this->takeOwnershipOfSymbol(Type::MakeArrayType(std::move(arrayName),
131                                                                *type, arraySize));
132     }
133     return type;
134 }
135 
136 }  // namespace SkSL
137