/* * Copyright 2020 Google LLC. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "src/sksl/SkSLRehydrator.h" #include #include #include "src/sksl/ir/SkSLBinaryExpression.h" #include "src/sksl/ir/SkSLBreakStatement.h" #include "src/sksl/ir/SkSLContinueStatement.h" #include "src/sksl/ir/SkSLDiscardStatement.h" #include "src/sksl/ir/SkSLDoStatement.h" #include "src/sksl/ir/SkSLEnum.h" #include "src/sksl/ir/SkSLExpression.h" #include "src/sksl/ir/SkSLExpressionStatement.h" #include "src/sksl/ir/SkSLField.h" #include "src/sksl/ir/SkSLFieldAccess.h" #include "src/sksl/ir/SkSLFloatLiteral.h" #include "src/sksl/ir/SkSLForStatement.h" #include "src/sksl/ir/SkSLFunctionCall.h" #include "src/sksl/ir/SkSLFunctionDeclaration.h" #include "src/sksl/ir/SkSLFunctionDefinition.h" #include "src/sksl/ir/SkSLIfStatement.h" #include "src/sksl/ir/SkSLIndexExpression.h" #include "src/sksl/ir/SkSLInlineMarker.h" #include "src/sksl/ir/SkSLIntLiteral.h" #include "src/sksl/ir/SkSLInterfaceBlock.h" #include "src/sksl/ir/SkSLModifiers.h" #include "src/sksl/ir/SkSLPostfixExpression.h" #include "src/sksl/ir/SkSLPrefixExpression.h" #include "src/sksl/ir/SkSLProgramElement.h" #include "src/sksl/ir/SkSLReturnStatement.h" #include "src/sksl/ir/SkSLSetting.h" #include "src/sksl/ir/SkSLStatement.h" #include "src/sksl/ir/SkSLStructDefinition.h" #include "src/sksl/ir/SkSLSwitchCase.h" #include "src/sksl/ir/SkSLSwitchStatement.h" #include "src/sksl/ir/SkSLSwizzle.h" #include "src/sksl/ir/SkSLSymbolAlias.h" #include "src/sksl/ir/SkSLSymbolTable.h" #include "src/sksl/ir/SkSLTernaryExpression.h" #include "src/sksl/ir/SkSLType.h" #include "src/sksl/ir/SkSLUnresolvedFunction.h" #include "src/sksl/ir/SkSLVarDeclarations.h" #include "src/sksl/ir/SkSLVariable.h" namespace SkSL { class AutoRehydratorSymbolTable { public: AutoRehydratorSymbolTable(Rehydrator* rehydrator) : fRehydrator(rehydrator) , fOldSymbols(fRehydrator->fSymbolTable) { fRehydrator->fSymbolTable = fRehydrator->symbolTable(); } ~AutoRehydratorSymbolTable() { fRehydrator->fSymbolTable = std::move(fOldSymbols); } private: Rehydrator* fRehydrator; std::shared_ptr fOldSymbols; }; Rehydrator::Rehydrator(const Context* context, ModifiersPool* modifiers, std::shared_ptr symbolTable, ErrorReporter* errorReporter, const uint8_t* src, size_t length) : fContext(*context) , fModifiers(*modifiers) , fErrors(errorReporter) , fSymbolTable(std::move(symbolTable)) , fStart(src) SkDEBUGCODE(, fEnd(fStart + length)) { SkASSERT(fSymbolTable); SkASSERT(fSymbolTable->isBuiltin()); // skip past string data fIP = fStart; fIP += this->readU16(); } Layout Rehydrator::layout() { switch (this->readU8()) { case kBuiltinLayout_Command: { Layout result; result.fBuiltin = this->readS16(); return result; } case kDefaultLayout_Command: return Layout(); case kLayout_Command: { int flags = this->readU32(); int location = this->readS8(); int offset = this->readS8(); int binding = this->readS8(); int index = this->readS8(); int set = this->readS8(); int builtin = this->readS16(); int inputAttachmentIndex = this->readS8(); int format = this->readS8(); int primitive = this->readS8(); int maxVertices = this->readS8(); int invocations = this->readS8(); StringFragment marker = this->readString(); StringFragment when = this->readString(); int key = this->readS8(); int ctype = this->readS8(); return Layout(flags, location, offset, binding, index, set, builtin, inputAttachmentIndex, (Layout::Format) format, (Layout::Primitive) primitive, maxVertices, invocations, marker, when, (Layout::Key) key, (Layout::CType) ctype); } default: SkASSERT(false); return Layout(); } } Modifiers Rehydrator::modifiers() { switch (this->readU8()) { case kDefaultModifiers_Command: return Modifiers(); case kModifiers8Bit_Command: { Layout l = this->layout(); int flags = this->readU8(); return Modifiers(l, flags); } case kModifiers_Command: { Layout l = this->layout(); int flags = this->readS32(); return Modifiers(l, flags); } default: SkASSERT(false); return Modifiers(); } } const Symbol* Rehydrator::symbol() { int kind = this->readU8(); switch (kind) { case kArrayType_Command: { uint16_t id = this->readU16(); const Type* componentType = this->type(); int8_t count = this->readS8(); String name = componentType->name(); if (count == Type::kUnsizedArray) { name += "[]"; } else { name += "[" + to_string(count) + "]"; } const Type* result = fSymbolTable->takeOwnershipOfSymbol( Type::MakeArrayType(name, *componentType, count)); this->addSymbol(id, result); return result; } case kEnumType_Command: { uint16_t id = this->readU16(); StringFragment name = this->readString(); const Type* result = fSymbolTable->takeOwnershipOfSymbol(Type::MakeEnumType(name)); this->addSymbol(id, result); return result; } case kFunctionDeclaration_Command: { uint16_t id = this->readU16(); Modifiers modifiers = this->modifiers(); StringFragment name = this->readString(); int parameterCount = this->readU8(); std::vector parameters; parameters.reserve(parameterCount); for (int i = 0; i < parameterCount; ++i) { parameters.push_back(this->symbolRef(Symbol::Kind::kVariable)); } const Type* returnType = this->type(); const FunctionDeclaration* result = fSymbolTable->takeOwnershipOfSymbol(std::make_unique( /*offset=*/-1, fModifiers.addToPool(modifiers), name, std::move(parameters), returnType, /*builtin=*/true)); this->addSymbol(id, result); return result; } case kField_Command: { const Variable* owner = this->symbolRef(Symbol::Kind::kVariable); uint8_t index = this->readU8(); const Field* result = fSymbolTable->takeOwnershipOfSymbol( std::make_unique(/*offset=*/-1, owner, index)); return result; } case kStructType_Command: { uint16_t id = this->readU16(); StringFragment name = this->readString(); uint8_t fieldCount = this->readU8(); std::vector fields; fields.reserve(fieldCount); for (int i = 0; i < fieldCount; ++i) { Modifiers m = this->modifiers(); StringFragment fieldName = this->readString(); const Type* type = this->type(); fields.emplace_back(m, fieldName, type); } const Type* result = fSymbolTable->takeOwnershipOfSymbol( Type::MakeStructType(/*offset=*/-1, name, std::move(fields))); this->addSymbol(id, result); return result; } case kSymbolRef_Command: { uint16_t id = this->readU16(); SkASSERT(fSymbols.size() > id); return fSymbols[id]; } case kSymbolAlias_Command: { uint16_t id = this->readU16(); StringFragment name = this->readString(); const Symbol* origSymbol = this->symbol(); const SymbolAlias* symbolAlias = fSymbolTable->takeOwnershipOfSymbol( std::make_unique(/*offset=*/-1, name, origSymbol)); this->addSymbol(id, symbolAlias); return symbolAlias; } case kSystemType_Command: { uint16_t id = this->readU16(); StringFragment name = this->readString(); const Symbol* result = (*fSymbolTable)[name]; SkASSERT(result && result->kind() == Symbol::Kind::kType); this->addSymbol(id, result); return result; } case kUnresolvedFunction_Command: { uint16_t id = this->readU16(); int length = this->readU8(); std::vector functions; functions.reserve(length); for (int i = 0; i < length; ++i) { const Symbol* f = this->symbol(); SkASSERT(f && f->kind() == Symbol::Kind::kFunctionDeclaration); functions.push_back((const FunctionDeclaration*) f); } const UnresolvedFunction* result = fSymbolTable->takeOwnershipOfSymbol( std::make_unique(std::move(functions))); this->addSymbol(id, result); return result; } case kVariable_Command: { uint16_t id = this->readU16(); const Modifiers* m = fModifiers.addToPool(this->modifiers()); StringFragment name = this->readString(); const Type* type = this->type(); Variable::Storage storage = (Variable::Storage) this->readU8(); const Variable* result = fSymbolTable->takeOwnershipOfSymbol(std::make_unique( /*offset=*/-1, m, name, type, /*builtin=*/true, storage)); this->addSymbol(id, result); return result; } default: printf("unsupported symbol %d\n", kind); SkASSERT(false); return nullptr; } } const Type* Rehydrator::type() { const Symbol* result = this->symbol(); SkASSERT(result->kind() == Symbol::Kind::kType); return (const Type*) result; } std::vector> Rehydrator::elements() { SkDEBUGCODE(uint8_t command = )this->readU8(); SkASSERT(command == kElements_Command); std::vector> result; while (std::unique_ptr elem = this->element()) { result.push_back(std::move(elem)); } return result; } std::unique_ptr Rehydrator::element() { int kind = this->readU8(); switch (kind) { case Rehydrator::kEnum_Command: { StringFragment typeName = this->readString(); std::shared_ptr symbols = this->symbolTable(/*inherit=*/false); for (auto& s : symbols->fOwnedSymbols) { SkASSERT(s->kind() == Symbol::Kind::kVariable); Variable& v = (Variable&) *s; int value = this->readS32(); // enum variables aren't really 'declared', but we have to create a declaration to // store the value auto valueLiteral = std::make_unique(fContext, /*offset=*/-1, value); auto declaration = std::make_unique(&v, &v.type(), /*arraySize=*/0, std::move(valueLiteral)); v.setDeclaration(declaration.get()); symbols->takeOwnershipOfIRNode(std::move(declaration)); } return std::make_unique(/*offset=*/-1, typeName, std::move(symbols), /*isSharedWithCpp=*/true, /*isBuiltin=*/true); } case Rehydrator::kFunctionDefinition_Command: { const FunctionDeclaration* decl = this->symbolRef( Symbol::Kind::kFunctionDeclaration); std::unique_ptr body = this->statement(); std::unordered_set refs; uint8_t refCount = this->readU8(); for (int i = 0; i < refCount; ++i) { refs.insert(this->symbolRef( Symbol::Kind::kFunctionDeclaration)); } auto result = std::make_unique(/*offset=*/-1, decl, /*builtin=*/true, std::move(body), std::move(refs)); decl->setDefinition(result.get()); return std::move(result); } case Rehydrator::kInterfaceBlock_Command: { const Symbol* var = this->symbol(); SkASSERT(var && var->is()); StringFragment typeName = this->readString(); StringFragment instanceName = this->readString(); int arraySize = this->readS8(); return std::make_unique(/*offset=*/-1, &var->as(), typeName, instanceName, arraySize, nullptr); } case Rehydrator::kVarDeclarations_Command: { std::unique_ptr decl = this->statement(); return std::make_unique(/*offset=*/-1, std::move(decl)); } case Rehydrator::kStructDefinition_Command: { const Symbol* type = this->symbol(); SkASSERT(type && type->is()); return std::make_unique(/*offset=*/-1, type->as()); } case Rehydrator::kElementsComplete_Command: return nullptr; default: SkDEBUGFAILF("unsupported element %d\n", kind); return nullptr; } } std::unique_ptr Rehydrator::statement() { int kind = this->readU8(); switch (kind) { case Rehydrator::kBlock_Command: { AutoRehydratorSymbolTable symbols(this); int count = this->readU8(); StatementArray statements; statements.reserve_back(count); for (int i = 0; i < count; ++i) { statements.push_back(this->statement()); } bool isScope = this->readU8(); return std::make_unique(/*offset=*/-1, std::move(statements), fSymbolTable, isScope); } case Rehydrator::kBreak_Command: return std::unique_ptr(new BreakStatement(-1)); case Rehydrator::kContinue_Command: return std::unique_ptr(new ContinueStatement(-1)); case Rehydrator::kDiscard_Command: return std::unique_ptr(new DiscardStatement(-1)); case Rehydrator::kDo_Command: { std::unique_ptr stmt = this->statement(); std::unique_ptr expr = this->expression(); return std::unique_ptr(new DoStatement(-1, std::move(stmt), std::move(expr))); } case Rehydrator::kExpressionStatement_Command: { std::unique_ptr expr = this->expression(); return std::unique_ptr(new ExpressionStatement(std::move(expr))); } case Rehydrator::kFor_Command: { std::unique_ptr initializer = this->statement(); std::unique_ptr test = this->expression(); std::unique_ptr next = this->expression(); std::unique_ptr body = this->statement(); std::shared_ptr symbols = this->symbolTable(); return std::unique_ptr(new ForStatement(-1, std::move(initializer), std::move(test), std::move(next), std::move(body), std::move(symbols))); } case Rehydrator::kIf_Command: { bool isStatic = this->readU8(); std::unique_ptr test = this->expression(); std::unique_ptr ifTrue = this->statement(); std::unique_ptr ifFalse = this->statement(); return std::unique_ptr(new IfStatement(-1, isStatic, std::move(test), std::move(ifTrue), std::move(ifFalse))); } case Rehydrator::kInlineMarker_Command: { const FunctionDeclaration* funcDecl = this->symbolRef( Symbol::Kind::kFunctionDeclaration); return std::make_unique(funcDecl); } case Rehydrator::kReturn_Command: { std::unique_ptr expr = this->expression(); if (expr) { return std::unique_ptr(new ReturnStatement(std::move(expr))); } else { return std::unique_ptr(new ReturnStatement(-1)); } } case Rehydrator::kSwitch_Command: { bool isStatic = this->readU8(); AutoRehydratorSymbolTable symbols(this); std::unique_ptr expr = this->expression(); int caseCount = this->readU8(); std::vector> cases; cases.reserve(caseCount); for (int i = 0; i < caseCount; ++i) { std::unique_ptr value = this->expression(); int statementCount = this->readU8(); StatementArray statements; statements.reserve_back(statementCount); for (int j = 0; j < statementCount; ++j) { statements.push_back(this->statement()); } cases.push_back(std::make_unique(/*offset=*/-1, std::move(value), std::move(statements))); } return std::make_unique(-1, isStatic, std::move(expr), std::move(cases), fSymbolTable); } case Rehydrator::kVarDeclaration_Command: { Variable* var = this->symbolRef(Symbol::Kind::kVariable); const Type* baseType = this->type(); int arraySize = this->readS8(); std::unique_ptr value = this->expression(); auto result = std::make_unique(var, baseType, arraySize, std::move(value)); var->setDeclaration(result.get()); return std::move(result); } case Rehydrator::kVoid_Command: return nullptr; default: printf("unsupported statement %d\n", kind); SkASSERT(false); return nullptr; } } std::unique_ptr Rehydrator::expression() { int kind = this->readU8(); switch (kind) { case Rehydrator::kBinary_Command: { std::unique_ptr left = this->expression(); Token::Kind op = (Token::Kind) this->readU8(); std::unique_ptr right = this->expression(); const Type* type = this->type(); return std::make_unique(-1, std::move(left), op, std::move(right), type); } case Rehydrator::kBoolLiteral_Command: { bool value = this->readU8(); return std::make_unique(fContext, -1, value); } case Rehydrator::kConstructor_Command: { const Type* type = this->type(); uint8_t argCount = this->readU8(); ExpressionArray args; args.reserve_back(argCount); for (int i = 0; i < argCount; ++i) { args.push_back(this->expression()); } return std::make_unique(-1, type, std::move(args)); } case Rehydrator::kFieldAccess_Command: { std::unique_ptr base = this->expression(); int index = this->readU8(); FieldAccess::OwnerKind ownerKind = (FieldAccess::OwnerKind) this->readU8(); return std::make_unique(std::move(base), index, ownerKind); } case Rehydrator::kFloatLiteral_Command: { const Type* type = this->type(); FloatIntUnion u; u.fInt = this->readS32(); return std::make_unique(-1, u.fFloat, type); } case Rehydrator::kFunctionCall_Command: { const Type* type = this->type(); const FunctionDeclaration* f = this->symbolRef( Symbol::Kind::kFunctionDeclaration); uint8_t argCount = this->readU8(); ExpressionArray args; args.reserve_back(argCount); for (int i = 0; i < argCount; ++i) { args.push_back(this->expression()); } return std::make_unique(-1, type, f, std::move(args)); } case Rehydrator::kIndex_Command: { std::unique_ptr base = this->expression(); std::unique_ptr index = this->expression(); return std::make_unique(fContext, std::move(base), std::move(index)); } case Rehydrator::kIntLiteral_Command: { const Type* type = this->type(); int value = this->readS32(); return std::make_unique(-1, value, type); } case Rehydrator::kPostfix_Command: { Token::Kind op = (Token::Kind) this->readU8(); std::unique_ptr operand = this->expression(); return std::make_unique(std::move(operand), op); } case Rehydrator::kPrefix_Command: { Token::Kind op = (Token::Kind) this->readU8(); std::unique_ptr operand = this->expression(); return std::make_unique(op, std::move(operand)); } case Rehydrator::kSetting_Command: { StringFragment name = this->readString(); const Type* type = this->type(); return std::make_unique(-1, name, type); } case Rehydrator::kSwizzle_Command: { std::unique_ptr base = this->expression(); int count = this->readU8(); ComponentArray components; for (int i = 0; i < count; ++i) { components.push_back(this->readU8()); } return std::make_unique(fContext, std::move(base), components); } case Rehydrator::kTernary_Command: { std::unique_ptr test = this->expression(); std::unique_ptr ifTrue = this->expression(); std::unique_ptr ifFalse = this->expression(); return std::make_unique(-1, std::move(test), std::move(ifTrue), std::move(ifFalse)); } case Rehydrator::kVariableReference_Command: { const Variable* var = this->symbolRef(Symbol::Kind::kVariable); VariableReference::RefKind refKind = (VariableReference::RefKind) this->readU8(); return std::make_unique(-1, var, refKind); } case Rehydrator::kVoid_Command: return nullptr; default: printf("unsupported expression %d\n", kind); SkASSERT(false); return nullptr; } } std::shared_ptr Rehydrator::symbolTable(bool inherit) { int command = this->readU8(); if (command == kVoid_Command) { return nullptr; } SkASSERT(command == kSymbolTable_Command); uint16_t ownedCount = this->readU16(); std::shared_ptr oldTable = fSymbolTable; std::shared_ptr result = inherit ? std::make_shared(fSymbolTable, /*builtin=*/true) : std::make_shared(fErrors, /*builtin=*/true); fSymbolTable = result; std::vector ownedSymbols; ownedSymbols.reserve(ownedCount); for (int i = 0; i < ownedCount; ++i) { ownedSymbols.push_back(this->symbol()); } uint16_t symbolCount = this->readU16(); std::vector> symbols; symbols.reserve(symbolCount); for (int i = 0; i < symbolCount; ++i) { int index = this->readU16(); fSymbolTable->addWithoutOwnership(ownedSymbols[index]); } fSymbolTable = oldTable; return result; } } // namespace SkSL