| /* |
| * Copyright 2020 Google LLC. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #ifndef SKSL_REHYDRATOR |
| #define SKSL_REHYDRATOR |
| |
| #include "include/core/SkTypes.h" |
| #include "include/private/SkSLDefines.h" |
| #include "include/private/SkSLLayout.h" |
| #include "include/private/SkSLModifiers.h" |
| #include "src/sksl/SkSLContext.h" |
| #include "src/sksl/ir/SkSLSymbolTable.h" |
| |
| #include <memory> |
| #include <string_view> |
| #include <string> |
| #include <vector> |
| |
| namespace SkSL { |
| |
| class Compiler; |
| class ErrorReporter; |
| class Expression; |
| class ModifiersPool; |
| class ProgramElement; |
| class Statement; |
| class Symbol; |
| class Type; |
| struct Program; |
| |
| /** |
| * Interprets a simple bytecode format that encodes the structure of an SkSL IR tree. This is used |
| * to process the .sksl files representing SkSL's core include files, so that they can be quickly |
| * reconstituted at runtime. |
| */ |
| class Rehydrator { |
| public: |
| static constexpr uint16_t kVersion = 12; |
| |
| // see binary_format.md for a description of the command data |
| enum Command { |
| kArrayType_Command, |
| kBinary_Command, |
| kBlock_Command, |
| kBoolLiteral_Command, |
| kBreak_Command, |
| kBuiltinLayout_Command, |
| kConstructorArray_Command, |
| kConstructorArrayCast_Command, |
| kConstructorCompound_Command, |
| kConstructorCompoundCast_Command, |
| kConstructorDiagonalMatrix_Command, |
| kConstructorMatrixResize_Command, |
| kConstructorScalarCast_Command, |
| kConstructorSplat_Command, |
| kConstructorStruct_Command, |
| kContinue_Command, |
| kDefaultLayout_Command, |
| kDefaultModifiers_Command, |
| kDiscard_Command, |
| kDo_Command, |
| kElements_Command, |
| kElementsComplete_Command, |
| kExpressionStatement_Command, |
| kField_Command, |
| kFieldAccess_Command, |
| kFloatLiteral_Command, |
| kFor_Command, |
| kFunctionCall_Command, |
| kFunctionDeclaration_Command, |
| kFunctionDefinition_Command, |
| kFunctionPrototype_Command, |
| kGlobalVar_Command, |
| kIf_Command, |
| kIndex_Command, |
| kUnused_Command, // was kInlineMarker_Command |
| kInterfaceBlock_Command, |
| kIntLiteral_Command, |
| kLayout_Command, |
| kModifiers8Bit_Command, |
| kModifiers_Command, |
| kNop_Command, |
| kPostfix_Command, |
| kPrefix_Command, |
| kProgram_Command, |
| kReturn_Command, |
| kSetting_Command, |
| kSharedFunction_Command, |
| kStructDefinition_Command, |
| kStructType_Command, |
| kSwitch_Command, |
| kSwizzle_Command, |
| kSymbolRef_Command, |
| kSymbolTable_Command, |
| kTernary_Command, |
| kUnresolvedFunction_Command, |
| kVariable_Command, |
| kVarDeclaration_Command, |
| kVariableReference_Command, |
| kVoid_Command, |
| }; |
| |
| // src must remain in memory as long as the objects created from it do |
| Rehydrator(Compiler& compiler, const uint8_t* src, size_t length, |
| std::shared_ptr<SymbolTable> base = nullptr); |
| |
| #ifdef SK_DEBUG |
| ~Rehydrator(); |
| #endif |
| |
| // Reads a symbol table and makes it current (inheriting from the previous current table) |
| std::shared_ptr<SymbolTable> symbolTable(); |
| |
| // Reads a collection of program elements and returns it |
| std::vector<std::unique_ptr<ProgramElement>> elements(); |
| |
| // Reads an entire program. |
| // |
| // NOTE: The program is initialized using a new ProgramConfig that may differ from the one that |
| // was assigned to the context of the Compiler this Rehydrator was constructed with. |
| std::unique_ptr<Program> program(); |
| |
| private: |
| // If this ID appears in place of a symbol ID, it means the corresponding symbol isn't actually |
| // present in the file as it's a builtin. The string name of the symbol follows. |
| static constexpr uint16_t kBuiltin_Symbol = 65535; |
| |
| int8_t readS8() { |
| SkASSERT(fIP < fEnd); |
| return *(fIP++); |
| } |
| |
| uint8_t readU8() { |
| return this->readS8(); |
| } |
| |
| int16_t readS16() { |
| uint8_t b1 = this->readU8(); |
| uint8_t b2 = this->readU8(); |
| return (b2 << 8) + b1; |
| } |
| |
| uint16_t readU16() { |
| return this->readS16(); |
| } |
| |
| int32_t readS32() { |
| uint8_t b1 = this->readU8(); |
| uint8_t b2 = this->readU8(); |
| uint8_t b3 = this->readU8(); |
| uint8_t b4 = this->readU8(); |
| return (b4 << 24) + (b3 << 16) + (b2 << 8) + b1; |
| } |
| |
| uint32_t readU32() { |
| return this->readS32(); |
| } |
| |
| std::string_view readString() { |
| uint16_t offset = this->readU16(); |
| uint8_t length = *(uint8_t*) (fStringStart + offset); |
| const char* chars = (const char*) fStringStart + offset + 1; |
| return std::string_view(chars, length); |
| } |
| |
| void addSymbol(int id, const Symbol* symbol) { |
| while ((size_t) id >= fSymbols.size()) { |
| fSymbols.push_back(nullptr); |
| } |
| fSymbols[id] = symbol; |
| } |
| |
| template<typename T> |
| T* symbolRef() { |
| uint16_t result = this->readU16(); |
| SkASSERTF(result != kBuiltin_Symbol, "use possiblyBuiltinSymbolRef() instead"); |
| SkASSERT(fSymbols.size() > result); |
| return (T*) fSymbols[result]; |
| } |
| |
| /** |
| * Reads either a symbol belonging to this program, or a named reference to a builtin symbol. |
| * This has to be a separate method from symbolRef() because builtin symbols can be const, and |
| * thus this method must have a const return, but there is at least one case in which we |
| * specifically require a non-const return value. |
| */ |
| const Symbol* possiblyBuiltinSymbolRef() { |
| uint16_t id = this->readU16(); |
| if (id == kBuiltin_Symbol) { |
| std::string_view name = this->readString(); |
| const Symbol* result = (*fSymbolTable)[name]; |
| SkASSERTF(result, "symbol '%s' not found", std::string(name).c_str()); |
| return result; |
| } |
| SkASSERT(fSymbols.size() > id); |
| return fSymbols[id]; |
| } |
| |
| Layout layout(); |
| |
| Modifiers modifiers(); |
| |
| const Symbol* symbol(); |
| |
| std::unique_ptr<ProgramElement> element(); |
| |
| std::unique_ptr<Statement> statement(); |
| |
| std::unique_ptr<Expression> expression(); |
| |
| ExpressionArray expressionArray(); |
| |
| const Type* type(); |
| |
| Context& context() const; |
| |
| ErrorReporter* errorReporter() const { return this->context().fErrors; } |
| |
| ModifiersPool& modifiersPool() const { return *this->context().fModifiersPool; } |
| |
| Compiler& fCompiler; |
| std::shared_ptr<SymbolTable> fSymbolTable; |
| std::vector<const Symbol*> fSymbols; |
| |
| const uint8_t* fStringStart; |
| const uint8_t* fIP; |
| SkDEBUGCODE(const uint8_t* fEnd;) |
| |
| friend class AutoRehydratorSymbolTable; |
| friend class Dehydrator; |
| }; |
| |
| } // namespace SkSL |
| |
| #endif |