Commit 950457b3 by Olli Etuaho

Fix destructing TStrings through BuiltInFunctionEmulator after free

BuiltInFunctionEmulator gets destructed after the PoolAllocator has already freed memory. That's why BuiltInFunctionEmulator can't hold any objects that contain parts stored in the memory pool that would be accessed in its destructor. Use only pointers to TType objects inside BuiltInFunctionEmulator, so that the BuiltInFunctionEmulator destructor doesn't access TStrings which have data in the memory pool. Also fix style issues in BuiltInFunctionEmulator. BUG=angleproject:1010 TEST=dEQP-GLES3.functional.shaders.builtin_functions.* Change-Id: Ic35caf80bf125d0427c2ed2024e98657756103b6 Reviewed-on: https://chromium-review.googlesource.com/272738Tested-by: 's avatarOlli Etuaho <oetuaho@nvidia.com> Reviewed-by: 's avatarZhenyao Mo <zmo@chromium.org>
parent c378cd8a
......@@ -11,28 +11,30 @@
class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTraverser
{
public:
BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator& emulator)
BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator &emulator)
: mEmulator(emulator)
{
}
virtual bool visitUnary(Visit visit, TIntermUnary* node)
virtual bool visitUnary(Visit visit, TIntermUnary *node)
{
if (visit == PreVisit) {
bool needToEmulate = mEmulator.SetFunctionCalled(
node->getOp(), node->getOperand()->getType());
if (visit == PreVisit)
{
bool needToEmulate = mEmulator.SetFunctionCalled(node->getOp(), node->getOperand()->getType());
if (needToEmulate)
node->setUseEmulatedFunction();
}
return true;
}
virtual bool visitAggregate(Visit visit, TIntermAggregate* node)
virtual bool visitAggregate(Visit visit, TIntermAggregate *node)
{
if (visit == PreVisit)
{
if (visit == PreVisit) {
// Here we handle all the built-in functions instead of the ones we
// currently identified as problematic.
switch (node->getOp()) {
switch (node->getOp())
{
case EOpLessThan:
case EOpGreaterThan:
case EOpLessThanEqual:
......@@ -59,14 +61,14 @@ class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTr
break;
default:
return true;
};
const TIntermSequence& sequence = *(node->getSequence());
}
const TIntermSequence &sequence = *(node->getSequence());
bool needToEmulate = false;
// Right now we only handle built-in functions with two or three parameters.
if (sequence.size() == 2)
{
TIntermTyped* param1 = sequence[0]->getAsTyped();
TIntermTyped* param2 = sequence[1]->getAsTyped();
TIntermTyped *param1 = sequence[0]->getAsTyped();
TIntermTyped *param2 = sequence[1]->getAsTyped();
if (!param1 || !param2)
return true;
needToEmulate = mEmulator.SetFunctionCalled(
......@@ -74,9 +76,9 @@ class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTr
}
else if (sequence.size() == 3)
{
TIntermTyped* param1 = sequence[0]->getAsTyped();
TIntermTyped* param2 = sequence[1]->getAsTyped();
TIntermTyped* param3 = sequence[2]->getAsTyped();
TIntermTyped *param1 = sequence[0]->getAsTyped();
TIntermTyped *param2 = sequence[1]->getAsTyped();
TIntermTyped *param3 = sequence[2]->getAsTyped();
if (!param1 || !param2 || !param3)
return true;
needToEmulate = mEmulator.SetFunctionCalled(
......@@ -94,34 +96,28 @@ class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTr
}
private:
BuiltInFunctionEmulator& mEmulator;
BuiltInFunctionEmulator &mEmulator;
};
BuiltInFunctionEmulator::BuiltInFunctionEmulator()
{}
void BuiltInFunctionEmulator::addEmulatedFunction(
TOperator op, const TType& param,
const char* emulatedFunctionDefinition)
void BuiltInFunctionEmulator::addEmulatedFunction(TOperator op, const TType *param,
const char *emulatedFunctionDefinition)
{
mEmulatedFunctions[FunctionId(op, param)] =
std::string(emulatedFunctionDefinition);
mEmulatedFunctions[FunctionId(op, param)] = std::string(emulatedFunctionDefinition);
}
void BuiltInFunctionEmulator::addEmulatedFunction(
TOperator op, const TType& param1, const TType& param2,
const char* emulatedFunctionDefinition)
void BuiltInFunctionEmulator::addEmulatedFunction(TOperator op, const TType *param1, const TType *param2,
const char *emulatedFunctionDefinition)
{
mEmulatedFunctions[FunctionId(op, param1, param2)] =
std::string(emulatedFunctionDefinition);
mEmulatedFunctions[FunctionId(op, param1, param2)] = std::string(emulatedFunctionDefinition);
}
void BuiltInFunctionEmulator::addEmulatedFunction(
TOperator op, const TType& param1, const TType& param2, const TType& param3,
const char* emulatedFunctionDefinition)
void BuiltInFunctionEmulator::addEmulatedFunction(TOperator op, const TType *param1, const TType *param2,
const TType *param3, const char *emulatedFunctionDefinition)
{
mEmulatedFunctions[FunctionId(op, param1, param2, param3)] =
std::string(emulatedFunctionDefinition);
mEmulatedFunctions[FunctionId(op, param1, param2, param3)] = std::string(emulatedFunctionDefinition);
}
bool BuiltInFunctionEmulator::IsOutputEmpty() const
......@@ -129,48 +125,48 @@ bool BuiltInFunctionEmulator::IsOutputEmpty() const
return (mFunctions.size() == 0);
}
void BuiltInFunctionEmulator::OutputEmulatedFunctions(
TInfoSinkBase& out) const
void BuiltInFunctionEmulator::OutputEmulatedFunctions(TInfoSinkBase &out) const
{
for (size_t i = 0; i < mFunctions.size(); ++i) {
for (size_t i = 0; i < mFunctions.size(); ++i)
{
out << mEmulatedFunctions.find(mFunctions[i])->second << "\n\n";
}
}
bool BuiltInFunctionEmulator::SetFunctionCalled(
TOperator op, const TType& param)
bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op, const TType &param)
{
return SetFunctionCalled(FunctionId(op, param));
return SetFunctionCalled(FunctionId(op, &param));
}
bool BuiltInFunctionEmulator::SetFunctionCalled(
TOperator op, const TType& param1, const TType& param2)
bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op, const TType &param1, const TType &param2)
{
return SetFunctionCalled(FunctionId(op, param1, param2));
return SetFunctionCalled(FunctionId(op, &param1, &param2));
}
bool BuiltInFunctionEmulator::SetFunctionCalled(
TOperator op, const TType& param1, const TType& param2, const TType& param3)
bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op,
const TType &param1, const TType &param2, const TType &param3)
{
return SetFunctionCalled(FunctionId(op, param1, param2, param3));
return SetFunctionCalled(FunctionId(op, &param1, &param2, &param3));
}
bool BuiltInFunctionEmulator::SetFunctionCalled(
const FunctionId& functionId) {
bool BuiltInFunctionEmulator::SetFunctionCalled(const FunctionId &functionId)
{
if (mEmulatedFunctions.find(functionId) != mEmulatedFunctions.end())
{
for (size_t i = 0; i < mFunctions.size(); ++i) {
for (size_t i = 0; i < mFunctions.size(); ++i)
{
if (mFunctions[i] == functionId)
return true;
}
mFunctions.push_back(functionId);
// Copy the functionId if it needs to be stored, to make sure that the TType pointers inside
// remain valid and constant.
mFunctions.push_back(functionId.getCopy());
return true;
}
return false;
}
void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation(
TIntermNode* root)
void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation(TIntermNode *root)
{
ASSERT(root);
......@@ -188,32 +184,30 @@ void BuiltInFunctionEmulator::Cleanup()
//static
TString BuiltInFunctionEmulator::GetEmulatedFunctionName(
const TString& name)
const TString &name)
{
ASSERT(name[name.length() - 1] == '(');
return "webgl_" + name.substr(0, name.length() - 1) + "_emu(";
}
BuiltInFunctionEmulator::FunctionId::FunctionId
(TOperator op, const TType& param)
BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op, const TType *param)
: mOp(op),
mParam1(param),
mParam2(EbtVoid),
mParam3(EbtVoid)
mParam2(new TType(EbtVoid)),
mParam3(new TType(EbtVoid))
{
}
BuiltInFunctionEmulator::FunctionId::FunctionId
(TOperator op, const TType& param1, const TType& param2)
BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op, const TType *param1, const TType *param2)
: mOp(op),
mParam1(param1),
mParam2(param2),
mParam3(EbtVoid)
mParam3(new TType(EbtVoid))
{
}
BuiltInFunctionEmulator::FunctionId::FunctionId
(TOperator op, const TType& param1, const TType& param2, const TType& param3)
BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op,
const TType *param1, const TType *param2, const TType *param3)
: mOp(op),
mParam1(param1),
mParam2(param2),
......@@ -221,25 +215,28 @@ BuiltInFunctionEmulator::FunctionId::FunctionId
{
}
bool BuiltInFunctionEmulator::FunctionId::operator==
(const BuiltInFunctionEmulator::FunctionId& other) const
bool BuiltInFunctionEmulator::FunctionId::operator==(const BuiltInFunctionEmulator::FunctionId &other) const
{
return (mOp == other.mOp &&
mParam1 == other.mParam1 &&
mParam2 == other.mParam2 &&
mParam3 == other.mParam3);
*mParam1 == *other.mParam1 &&
*mParam2 == *other.mParam2 &&
*mParam3 == *other.mParam3);
}
bool BuiltInFunctionEmulator::FunctionId::operator<
(const BuiltInFunctionEmulator::FunctionId& other) const
bool BuiltInFunctionEmulator::FunctionId::operator<(const BuiltInFunctionEmulator::FunctionId &other) const
{
if (mOp != other.mOp)
return mOp < other.mOp;
if (mParam1 != other.mParam1)
return mParam1 < other.mParam1;
if (mParam2 != other.mParam2)
return mParam2 < other.mParam2;
if (mParam3 != other.mParam3)
return mParam3 < other.mParam3;
if (*mParam1 != *other.mParam1)
return *mParam1 < *other.mParam1;
if (*mParam2 != *other.mParam2)
return *mParam2 < *other.mParam2;
if (*mParam3 != *other.mParam3)
return *mParam3 < *other.mParam3;
return false; // all fields are equal
}
BuiltInFunctionEmulator::FunctionId BuiltInFunctionEmulator::FunctionId::getCopy() const
{
return FunctionId(mOp, new TType(*mParam1), new TType(*mParam2), new TType(*mParam3));
}
......@@ -21,23 +21,25 @@ class BuiltInFunctionEmulator
public:
BuiltInFunctionEmulator();
void MarkBuiltInFunctionsForEmulation(TIntermNode* root);
void MarkBuiltInFunctionsForEmulation(TIntermNode *root);
void Cleanup();
// "name(" becomes "webgl_name_emu(".
static TString GetEmulatedFunctionName(const TString& name);
static TString GetEmulatedFunctionName(const TString &name);
bool IsOutputEmpty() const;
// Output function emulation definition. This should be before any other
// shader source.
void OutputEmulatedFunctions(TInfoSinkBase& out) const;
void OutputEmulatedFunctions(TInfoSinkBase &out) const;
// Add functions that need to be emulated.
void addEmulatedFunction(TOperator op, const TType& param, const char* emulatedFunctionDefinition);
void addEmulatedFunction(TOperator op, const TType& param1, const TType& param2, const char* emulatedFunctionDefinition);
void addEmulatedFunction(TOperator op, const TType& param1, const TType& param2, const TType& param3, const char* emulatedFunctionDefinition);
void addEmulatedFunction(TOperator op, const TType *param, const char *emulatedFunctionDefinition);
void addEmulatedFunction(TOperator op, const TType *param1, const TType *param2,
const char *emulatedFunctionDefinition);
void addEmulatedFunction(TOperator op, const TType *param1, const TType *param2, const TType *param3,
const char *emulatedFunctionDefinition);
private:
class BuiltInFunctionEmulationMarker;
......@@ -46,28 +48,32 @@ class BuiltInFunctionEmulator
// emulated. If the function is not in mEmulatedFunctions, this becomes a
// no-op. Returns true if the function call needs to be replaced with an
// emulated one.
bool SetFunctionCalled(TOperator op, const TType& param);
bool SetFunctionCalled(
TOperator op, const TType& param1, const TType& param2);
bool SetFunctionCalled(
TOperator op, const TType& param1, const TType& param2, const TType& param3);
bool SetFunctionCalled(TOperator op, const TType &param);
bool SetFunctionCalled(TOperator op, const TType &param1, const TType &param2);
bool SetFunctionCalled(TOperator op, const TType &param1, const TType &param2, const TType &param3);
class FunctionId {
public:
FunctionId(TOperator op, const TType& param);
FunctionId(TOperator op, const TType& param1, const TType& param2);
FunctionId(TOperator op, const TType& param1, const TType& param2, const TType& param3);
FunctionId(TOperator op, const TType *param);
FunctionId(TOperator op, const TType *param1, const TType *param2);
FunctionId(TOperator op, const TType *param1, const TType *param2, const TType *param3);
bool operator==(const FunctionId& other) const;
bool operator<(const FunctionId& other) const;
bool operator==(const FunctionId &other) const;
bool operator<(const FunctionId &other) const;
FunctionId getCopy() const;
private:
TOperator mOp;
TType mParam1;
TType mParam2;
TType mParam3;
// The memory that these TType objects use is freed by PoolAllocator. The BuiltInFunctionEmulator's lifetime
// can extend until after the memory pool is freed, but that's not an issue since this class never destructs
// these objects.
const TType *mParam1;
const TType *mParam2;
const TType *mParam3;
};
bool SetFunctionCalled(const FunctionId& functionId);
bool SetFunctionCalled(const FunctionId &functionId);
// Map from function id to emulated function definition
std::map<FunctionId, std::string> mEmulatedFunctions;
......
......@@ -17,10 +17,10 @@ void InitBuiltInFunctionEmulatorForGLSL(BuiltInFunctionEmulator *emu, sh::GLenum
// evaluated. This is unlikely to show up in real shaders, but is something to
// consider.
TType float1(EbtFloat);
TType float2(EbtFloat, 2);
TType float3(EbtFloat, 3);
TType float4(EbtFloat, 4);
TType *float1 = new TType(EbtFloat);
TType *float2 = new TType(EbtFloat, 2);
TType *float3 = new TType(EbtFloat, 3);
TType *float4 = new TType(EbtFloat, 4);
if (shaderType == GL_FRAGMENT_SHADER)
{
......
......@@ -11,10 +11,10 @@
void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu)
{
TType float1(EbtFloat);
TType float2(EbtFloat, 2);
TType float3(EbtFloat, 3);
TType float4(EbtFloat, 4);
TType *float1 = new TType(EbtFloat);
TType *float2 = new TType(EbtFloat, 2);
TType *float3 = new TType(EbtFloat, 3);
TType *float4 = new TType(EbtFloat, 4);
emu->addEmulatedFunction(EOpMod, float1, float1,
"float webgl_mod_emu(float x, float y)\n"
......@@ -250,7 +250,7 @@ void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu)
" return (y << 16) | x;\n"
"}\n");
TType uint1(EbtUInt);
TType *uint1 = new TType(EbtUInt);
emu->addEmulatedFunction(EOpUnpackSnorm2x16, uint1,
"float webgl_fromSnorm(in uint x) {\n"
......@@ -327,9 +327,9 @@ void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu)
" return mul(float4x1(r), float1x3(c));\n"
"}\n");
TType mat2(EbtFloat, 2, 2);
TType mat3(EbtFloat, 3, 3);
TType mat4(EbtFloat, 4, 4);
TType *mat2 = new TType(EbtFloat, 2, 2);
TType *mat3 = new TType(EbtFloat, 3, 3);
TType *mat4 = new TType(EbtFloat, 4, 4);
// Remember here that the parameter matrix is actually the transpose
// of the matrix that we're trying to invert, and the resulting matrix
......@@ -408,10 +408,10 @@ void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu)
" return cof / determinant(transpose(m));\n"
"}\n");
TType bool1(EbtBool);
TType bool2(EbtBool, 2);
TType bool3(EbtBool, 3);
TType bool4(EbtBool, 4);
TType *bool1 = new TType(EbtBool);
TType *bool2 = new TType(EbtBool, 2);
TType *bool3 = new TType(EbtBool, 3);
TType *bool4 = new TType(EbtBool, 4);
// Emulate ESSL3 variant of mix that takes last argument as boolean vector.
// genType mix (genType x, genType y, genBType a): Selects which vector each returned component comes from.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment