/* * 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/SkSLNullLiteral.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/SkSLSwitchCase.h" #include "src/sksl/ir/SkSLSwitchStatement.h" #include "src/sksl/ir/SkSLSwizzle.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/SkSLVarDeclarationsStatement.h" #include "src/sksl/ir/SkSLVariable.h" #include "src/sksl/ir/SkSLWhileStatement.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; }; 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(); uint8_t count = this->readU8(); const Type* result = fSymbolTable->takeOwnershipOfSymbol( std::make_unique(componentType->name() + "[" + to_string(count) + "]", Type::TypeKind::kArray, *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( std::make_unique(name, Type::TypeKind::kEnum)); 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, 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 kNullableType_Command: { uint16_t id = this->readU16(); const Type* base = this->type(); const Type* result = fSymbolTable->takeOwnershipOfSymbol( std::make_unique(base->name() + "?", Type::TypeKind::kNullable, *base)); this->addSymbol(id, result); 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( std::make_unique(/*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 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(); Modifiers m = 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, 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); uint8_t count = this->readU8(); std::vector> result; result.reserve(count); for (int i = 0; i < count; ++i) { result.push_back(this->element()); } 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(); v.fInitialValue = symbols->takeOwnershipOfIRNode( std::make_unique(fContext, /*offset=*/-1, value)); v.fWriteCount = 1; } return std::unique_ptr(new Enum(-1, typeName, std::move(symbols))); } 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)); } FunctionDefinition* result = new FunctionDefinition(-1, *decl, std::move(body), std::move(refs)); decl->fDefinition = result; return std::unique_ptr(result); } case Rehydrator::kInterfaceBlock_Command: { const Symbol* var = this->symbol(); SkASSERT(var && var->kind() == Symbol::Kind::kVariable); StringFragment typeName = this->readString(); StringFragment instanceName = this->readString(); uint8_t sizeCount = this->readU8(); std::vector> sizes; sizes.reserve(sizeCount); for (int i = 0; i < sizeCount; ++i) { sizes.push_back(this->expression()); } return std::unique_ptr(new InterfaceBlock(-1, (Variable*) var, typeName, instanceName, std::move(sizes), nullptr)); } case Rehydrator::kVarDeclarations_Command: { const Type* baseType = this->type(); int count = this->readU8(); std::vector> vars; vars.reserve(count); for (int i = 0 ; i < count; ++i) { std::unique_ptr s = this->statement(); SkASSERT(s->kind() == Statement::Kind::kVarDeclaration); vars.emplace_back((VarDeclaration*) s.release()); } return std::unique_ptr(new VarDeclarations(-1, baseType, std::move(vars))); } default: printf("unsupported element %d\n", kind); SkASSERT(false); return nullptr; } } std::unique_ptr Rehydrator::statement() { int kind = this->readU8(); switch (kind) { case Rehydrator::kBlock_Command: { AutoRehydratorSymbolTable symbols(this); int count = this->readU8(); std::vector> statements; statements.reserve(count); for (int i = 0; i < count; ++i) { statements.push_back(this->statement()); } bool isScope = this->readU8(); return std::unique_ptr(new Block(-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(); std::vector> statements; statements.reserve(statementCount); for (int j = 0; j < statementCount; ++j) { statements.push_back(this->statement()); } cases.emplace_back(new SwitchCase(-1, std::move(value), std::move(statements))); } return std::unique_ptr(new SwitchStatement(-1, isStatic, std::move(expr), std::move(cases), fSymbolTable)); } case Rehydrator::kVarDeclaration_Command: { Variable* var = this->symbolRef(Symbol::Kind::kVariable); uint8_t sizeCount = this->readU8(); std::vector> sizes; sizes.reserve(sizeCount); for (int i = 0; i < sizeCount; ++i) { sizes.push_back(this->expression()); } std::unique_ptr value = this->expression(); if (value) { var->fInitialValue = value.get(); SkASSERT(var->fWriteCount == 0); ++var->fWriteCount; } return std::unique_ptr(new VarDeclaration(var, std::move(sizes), std::move(value))); } case Rehydrator::kVarDeclarations_Command: { const Type* baseType = this->type(); int count = this->readU8(); std::vector> vars; vars.reserve(count); for (int i = 0 ; i < count; ++i) { std::unique_ptr s = this->statement(); SkASSERT(s->kind() == Statement::Kind::kVarDeclaration); vars.emplace_back((VarDeclaration*) s.release()); } return std::make_unique( std::make_unique(-1, baseType, std::move(vars))); } case Rehydrator::kVoid_Command: return nullptr; case Rehydrator::kWhile_Command: { std::unique_ptr expr = this->expression(); std::unique_ptr stmt = this->statement(); return std::unique_ptr(new WhileStatement(-1, std::move(expr), std::move(stmt))); } 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(); std::vector> args; args.reserve(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: { FloatIntUnion u; u.fInt = this->readS32(); return std::make_unique(fContext, -1, u.fFloat); } case Rehydrator::kFunctionCall_Command: { const Type* type = this->type(); const FunctionDeclaration* f = this->symbolRef( Symbol::Kind::kFunctionDeclaration); uint8_t argCount = this->readU8(); std::vector> args; args.reserve(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: { int value = this->readS32(); return std::make_unique(fContext, -1, value); } case Rehydrator::kNullLiteral_Command: return std::make_unique(fContext, -1); 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(); std::unique_ptr value = this->expression(); return std::make_unique(-1, name, std::move(value)); } case Rehydrator::kSwizzle_Command: { std::unique_ptr base = this->expression(); int count = this->readU8(); std::vector components; components.reserve(count); for (int i = 0; i < count; ++i) { components.push_back(this->readU8()); } return std::make_unique(fContext, std::move(base), std::move(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) : std::make_shared(fErrors); 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) { StringFragment name = this->readString(); int index = this->readU16(); fSymbolTable->addWithoutOwnership(name, ownedSymbols[index]); } fSymbolTable = oldTable; return result; } } // namespace SkSL