Remove unsafe compiler methods related to external values
We don't want to be polluting the global namespace with external values,
especially when the typical/recommended way to use the Compiler is with
a single long-lived instance. Force client code to manage ownership (the
only non-unit-test case was already doing this), and pass external
values to convertProgram, so they can be added to the Program's symbol
table.
Change-Id: If4c1db5e48a62e2cf4333b8d80420f2dfede27ab
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/319125
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: John Stiles <johnstiles@google.com>
diff --git a/modules/particles/include/SkParticleEffect.h b/modules/particles/include/SkParticleEffect.h
index 1780c37..4a474aa 100644
--- a/modules/particles/include/SkParticleEffect.h
+++ b/modules/particles/include/SkParticleEffect.h
@@ -17,12 +17,12 @@
#include "modules/particles/include/SkParticleData.h"
#include <memory>
+#include <vector>
class SkCanvas;
class SkFieldVisitor;
class SkParticleBinding;
class SkParticleDrawable;
-class SkParticleExternalValue;
namespace skresources {
class ResourceProvider;
@@ -30,6 +30,7 @@
namespace SkSL {
class ByteCode;
+ class ExternalValue;
} // namespace SkSL
class SkParticleEffectParams : public SkRefCnt {
@@ -129,7 +130,7 @@
// Cached
struct Program {
std::unique_ptr<SkSL::ByteCode> fByteCode;
- SkTArray<std::unique_ptr<SkParticleExternalValue>> fExternalValues;
+ std::vector<std::unique_ptr<SkSL::ExternalValue>> fExternalValues;
};
Program fEffectProgram;
diff --git a/modules/particles/src/SkParticleEffect.cpp b/modules/particles/src/SkParticleEffect.cpp
index 55c1bba..b754519 100644
--- a/modules/particles/src/SkParticleEffect.cpp
+++ b/modules/particles/src/SkParticleEffect.cpp
@@ -123,17 +123,17 @@
SkSL::Program::Settings settings;
settings.fRemoveDeadFunctions = false;
- SkTArray<std::unique_ptr<SkParticleExternalValue>> externalValues;
+ std::vector<std::unique_ptr<SkSL::ExternalValue>> externalValues;
+ externalValues.reserve(fBindings.size());
for (const auto& binding : fBindings) {
if (binding) {
- auto value = binding->toValue(compiler);
- compiler.registerExternalValue(value.get());
- externalValues.push_back(std::move(value));
+ externalValues.push_back(binding->toValue(compiler));
}
}
- auto program = compiler.convertProgram(SkSL::Program::kGeneric_Kind, code, settings);
+ auto program = compiler.convertProgram(SkSL::Program::kGeneric_Kind, code, settings,
+ &externalValues);
if (!program) {
SkDebugf("%s\n", compiler.errorText().c_str());
return;
@@ -225,7 +225,7 @@
if (const auto& byteCode = fParams->fEffectProgram.fByteCode) {
if (auto fun = byteCode->getFunction(entry)) {
for (const auto& value : fParams->fEffectProgram.fExternalValues) {
- value->setEffect(this);
+ static_cast<SkParticleExternalValue*>(value.get())->setEffect(this);
}
SkAssertResult(byteCode->run(fun, &fState.fAge, sizeof(EffectState) / sizeof(float),
nullptr, 0,
@@ -269,7 +269,7 @@
args[i] = fParticles.fData[i].get() + start;
}
for (const auto& value : fParams->fParticleProgram.fExternalValues) {
- value->setEffect(this);
+ static_cast<SkParticleExternalValue*>(value.get())->setEffect(this);
}
memcpy(&fParticleUniforms[1], &fState.fAge, sizeof(EffectState));
SkAssertResult(byteCode->runStriped(fun, count, args, SkParticles::kNumChannels,
diff --git a/src/sksl/SkSLCompiler.cpp b/src/sksl/SkSLCompiler.cpp
index f38da67..ffe6811 100644
--- a/src/sksl/SkSLCompiler.cpp
+++ b/src/sksl/SkSLCompiler.cpp
@@ -1556,16 +1556,13 @@
return madeChanges;
}
-void Compiler::registerExternalValue(ExternalValue* value) {
- fRootSymbolTable->addWithoutOwnership(value->fName, value);
-}
+std::unique_ptr<Program> Compiler::convertProgram(
+ Program::Kind kind,
+ String text,
+ const Program::Settings& settings,
+ const std::vector<std::unique_ptr<ExternalValue>>* externalValues) {
+ SkASSERT(!externalValues || (kind == Program::kGeneric_Kind));
-const Symbol* Compiler::takeOwnership(std::unique_ptr<const Symbol> symbol) {
- return fRootSymbolTable->takeOwnershipOfSymbol(std::move(symbol));
-}
-
-std::unique_ptr<Program> Compiler::convertProgram(Program::Kind kind, String text,
- const Program::Settings& settings) {
fErrorText = "";
fErrorCount = 0;
fInliner.reset(context(), settings);
@@ -1636,6 +1633,13 @@
fIRGenerator->start(&settings, fInterpreterSymbolTable, /*inherited=*/nullptr);
break;
}
+ if (externalValues) {
+ // Add any external values to the symbol table. IRGenerator::start() has pushed a table, so
+ // we're only making these visible to the current Program.
+ for (const auto& ev : *externalValues) {
+ fIRGenerator->fSymbolTable->addWithoutOwnership(ev->fName, ev.get());
+ }
+ }
std::unique_ptr<String> textPtr(new String(std::move(text)));
fSource = textPtr.get();
fIRGenerator->convertProgram(kind, textPtr->c_str(), textPtr->size(), &elements);
diff --git a/src/sksl/SkSLCompiler.h b/src/sksl/SkSLCompiler.h
index 6bd1423..d3915f4 100644
--- a/src/sksl/SkSLCompiler.h
+++ b/src/sksl/SkSLCompiler.h
@@ -117,12 +117,14 @@
Compiler& operator=(const Compiler&) = delete;
/**
- * Registers an ExternalValue as a top-level symbol which is visible in the global namespace.
+ * If externalValues is supplied, those values are registered in the symbol table of the
+ * Program, but ownership is *not* transferred. It is up to the caller to keep them alive.
*/
- void registerExternalValue(ExternalValue* value);
-
- std::unique_ptr<Program> convertProgram(Program::Kind kind, String text,
- const Program::Settings& settings);
+ std::unique_ptr<Program> convertProgram(
+ Program::Kind kind,
+ String text,
+ const Program::Settings& settings,
+ const std::vector<std::unique_ptr<ExternalValue>>* externalValues = nullptr);
bool toSPIRV(Program& program, OutputStream& out);
@@ -150,11 +152,6 @@
bool toPipelineStage(Program& program, PipelineStageArgs* outArgs);
#endif
- /**
- * Takes ownership of the given symbol. It will be destroyed when the compiler is destroyed.
- */
- const Symbol* takeOwnership(std::unique_ptr<const Symbol> symbol);
-
void error(int offset, String msg) override;
String errorText();
diff --git a/src/sksl/SkSLExternalValue.h b/src/sksl/SkSLExternalValue.h
index 1de6ab7..f5aeafa 100644
--- a/src/sksl/SkSLExternalValue.h
+++ b/src/sksl/SkSLExternalValue.h
@@ -93,9 +93,7 @@
/**
* Resolves 'name' within this context and returns an ExternalValue which represents it, or
- * null if no such child exists. If the implementation of this method creates new
- * ExternalValues and there isn't a more convenient place for ownership of the objects to
- * reside, the compiler's takeOwnership method may be useful.
+ * null if no such child exists.
*
* The 'name' string may not persist after this call; do not store this pointer.
*/
diff --git a/tests/SkSLInterpreterTest.cpp b/tests/SkSLInterpreterTest.cpp
index 13573de..a233ab1 100644
--- a/tests/SkSLInterpreterTest.cpp
+++ b/tests/SkSLInterpreterTest.cpp
@@ -956,8 +956,8 @@
SkSL::ExternalValue* getChild(const char* name) const override {
if (fValue.getType() == skjson::Value::Type::kObject) {
const skjson::Value& v = fValue.as<skjson::ObjectValue>()[name];
- return (SkSL::ExternalValue*) fCompiler.takeOwnership(std::unique_ptr<Symbol>(
- new JSONExternalValue(name, &v, &fCompiler)));
+ fOwned.push_back(std::make_unique<JSONExternalValue>(name, &v, &fCompiler));
+ return fOwned.back().get();
}
return nullptr;
}
@@ -965,6 +965,7 @@
private:
const skjson::Value& fValue;
SkSL::Compiler& fCompiler;
+ mutable std::vector<std::unique_ptr<SkSL::ExternalValue>> fOwned;
using INHERITED = SkSL::ExternalValue;
};
@@ -1009,17 +1010,13 @@
" outValue = 152;"
" return root.child.value2 ? root.value1 * root.child.value3 : -1;"
"}";
- compiler.registerExternalValue((SkSL::ExternalValue*) compiler.takeOwnership(
- std::unique_ptr<SkSL::Symbol>(new JSONExternalValue("root", &dom.root(), &compiler))));
int32_t outValue = -1;
- compiler.registerExternalValue((SkSL::ExternalValue*) compiler.takeOwnership(
- std::unique_ptr<SkSL::Symbol>(new PointerExternalValue("outValue",
- *compiler.context().fInt_Type,
- &outValue,
- sizeof(outValue)))));
+ std::vector<std::unique_ptr<SkSL::ExternalValue>> externalValues;
+ externalValues.push_back(std::make_unique<JSONExternalValue>("root", &dom.root(), &compiler));
+ externalValues.push_back(std::make_unique<PointerExternalValue>(
+ "outValue", *compiler.context().fInt_Type, &outValue, sizeof(outValue)));
std::unique_ptr<SkSL::Program> program = compiler.convertProgram(
- SkSL::Program::kGeneric_Kind,
- SkSL::String(src), settings);
+ SkSL::Program::kGeneric_Kind, SkSL::String(src), settings, &externalValues);
REPORTER_ASSERT(r, program);
if (program) {
std::unique_ptr<SkSL::ByteCode> byteCode = compiler.toByteCode(*program);
@@ -1045,14 +1042,11 @@
" value *= 2;"
"}";
int32_t value[4] = { 1, 2, 3, 4 };
- compiler.registerExternalValue((SkSL::ExternalValue*) compiler.takeOwnership(
- std::unique_ptr<SkSL::Symbol>(new PointerExternalValue("value",
- *compiler.context().fInt4_Type,
- value,
- sizeof(value)))));
- std::unique_ptr<SkSL::Program> program = compiler.convertProgram(SkSL::Program::kGeneric_Kind,
- SkSL::String(src),
- settings);
+ std::vector<std::unique_ptr<SkSL::ExternalValue>> externalValues;
+ externalValues.push_back(std::make_unique<PointerExternalValue>(
+ "value", *compiler.context().fInt4_Type, value, sizeof(value)));
+ std::unique_ptr<SkSL::Program> program = compiler.convertProgram(
+ SkSL::Program::kGeneric_Kind, SkSL::String(src), settings, &externalValues);
REPORTER_ASSERT(r, program);
if (program) {
std::unique_ptr<SkSL::ByteCode> byteCode = compiler.toByteCode(*program);
@@ -1109,15 +1103,11 @@
const char* src = "float main() {"
" return external(25);"
"}";
- compiler.registerExternalValue((SkSL::ExternalValue*) compiler.takeOwnership(
- std::unique_ptr<SkSL::Symbol>(new FunctionExternalValue("external",
- [] (float x) {
- return (float) sqrt(x);
- },
- compiler))));
- std::unique_ptr<SkSL::Program> program = compiler.convertProgram(SkSL::Program::kGeneric_Kind,
- SkSL::String(src),
- settings);
+ std::vector<std::unique_ptr<SkSL::ExternalValue>> externalValues;
+ externalValues.push_back(std::make_unique<FunctionExternalValue>(
+ "external", [](float x) { return (float)sqrt(x); }, compiler));
+ std::unique_ptr<SkSL::Program> program = compiler.convertProgram(
+ SkSL::Program::kGeneric_Kind, SkSL::String(src), settings, &externalValues);
REPORTER_ASSERT(r, program);
if (program) {
std::unique_ptr<SkSL::ByteCode> byteCode = compiler.toByteCode(*program);
@@ -1171,21 +1161,22 @@
DEF_TEST(SkSLInterpreterExternalValuesVectorCall, r) {
SkSL::Compiler compiler;
SkSL::Program::Settings settings;
- const char* src = "float4 main() {"
- " return external(float4(1, 4, 9, 16));"
- "}";
- compiler.registerExternalValue((SkSL::ExternalValue*) compiler.takeOwnership(
- std::unique_ptr<SkSL::Symbol>(new VectorFunctionExternalValue("external",
- [] (float in[4], float out[4]) {
- out[0] = sqrt(in[0]);
- out[1] = sqrt(in[1]);
- out[2] = sqrt(in[2]);
- out[3] = sqrt(in[3]);
- },
- compiler))));
- std::unique_ptr<SkSL::Program> program = compiler.convertProgram(SkSL::Program::kGeneric_Kind,
- SkSL::String(src),
- settings);
+ const char* src =
+ "float4 main() {"
+ " return external(float4(1, 4, 9, 16));"
+ "}";
+ std::vector<std::unique_ptr<SkSL::ExternalValue>> externalValues;
+ externalValues.push_back(std::make_unique<VectorFunctionExternalValue>(
+ "external",
+ [](float in[4], float out[4]) {
+ out[0] = sqrt(in[0]);
+ out[1] = sqrt(in[1]);
+ out[2] = sqrt(in[2]);
+ out[3] = sqrt(in[3]);
+ },
+ compiler));
+ std::unique_ptr<SkSL::Program> program = compiler.convertProgram(
+ SkSL::Program::kGeneric_Kind, SkSL::String(src), settings, &externalValues);
REPORTER_ASSERT(r, program);
if (program) {
std::unique_ptr<SkSL::ByteCode> byteCode = compiler.toByteCode(*program);