WebKit Bugzilla
Attachment 372074 Details for
Bug 198600
: [WHLSL] Implement out-of-bounds and nullptr behavior
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
patch
c-backup.diff (text/plain), 46.25 KB, created by
Saam Barati
on 2019-06-13 12:49:17 PDT
(
hide
)
Description:
patch
Filename:
MIME Type:
Creator:
Saam Barati
Created:
2019-06-13 12:49:17 PDT
Size:
46.25 KB
patch
obsolete
>Index: Source/WebCore/ChangeLog >=================================================================== >--- Source/WebCore/ChangeLog (revision 246409) >+++ Source/WebCore/ChangeLog (working copy) >@@ -1,3 +1,76 @@ >+2019-06-13 Saam Barati <sbarati@apple.com> >+ >+ [WHLSL] Implement out-of-bounds and nullptr behavior >+ https://bugs.webkit.org/show_bug.cgi?id=198600 >+ <rdar://problem/51668853> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ The behavior we're implementing is: >+ - OOB writes are ignored. >+ - OOB reads return zero. >+ - Writes to null are ignored. >+ - Reads from null return zero. >+ - &*x == x, including &*null == null. >+ >+ We implement this like so: >+ - The value stack in FunctionWriter turns into a stack of pairs: rvalues and lvalues. >+ rvalues are represented the same as before. Lvalues are always pointers. >+ - Anything that produces an lvalue must push a pointer to the stack. Not >+ all things produce lvalues, so that entry in the stack may be empty. >+ However, all things that produce lvalues also produce rvalues. So, "*x = 42" works, >+ and so does "foo(*x)". Nodes that produce lvalues are responsible for also producing >+ an rvalue, which should be the value as if the lvalue was dereferenced at that point >+ in program execution. So the "*x" in "thread int* x = null; *x" produces the int zero >+ for its rvalue, and null for its lvalue. >+ - Dereference just works, as dereference produces both an lvalue and rvalue. Dereference >+ node's child must also be an lvalue. So we just forward that value along on >+ the stack. For the rvalue, if we try to dereference nullptr, we just fill in >+ zero bytes instead. Otherwise, the rvalue is the result of dereferencing the >+ non-null pointer. >+ - Assignment expressions check if the incoming lvalue is null. If it is, it >+ skips the assignment. >+ - operator&[] returns nullptr on an OOB access. Then, based on the above >+ behavior, we get the desired OOB reads return zero, and OOB writes are >+ ignored. >+ - MakePointerExpression just takes the last lvalue off the stack (which must >+ be a pointer) and returns it as an rvalue. >+ - VariableReference will push both the variable value and a pointer to the variable >+ onto the stack. >+ >+ This patch also fixes a few bugs where we weren't giving certain AST nodes the >+ proper address space values. >+ >+ This patch also removes code to generate native functions for operators >+ "operator[]" and "operator[]=" as we should never be generating these >+ ourselves. We should only be generating the "operator&[]" ander. >+ >+ Tests: webgpu/whlsl-null-dereference.html >+ webgpu/whlsl-oob-access.html >+ >+ * Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp: >+ (WebCore::WHLSL::Metal::FunctionDefinitionWriter::FunctionDefinitionWriter): >+ (WebCore::WHLSL::Metal::FunctionDefinitionWriter::appendRightValue): >+ (WebCore::WHLSL::Metal::FunctionDefinitionWriter::appendLeftValue): >+ (WebCore::WHLSL::Metal::FunctionDefinitionWriter::takeLastValue): >+ (WebCore::WHLSL::Metal::FunctionDefinitionWriter::takeLastLeftValue): >+ (WebCore::WHLSL::Metal::FunctionDefinitionWriter::visit): >+ (WebCore::WHLSL::Metal::FunctionDefinitionWriter::emitLoop): >+ * Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp: >+ (WebCore::WHLSL::Metal::writeNativeFunction): >+ * Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.h: >+ * Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.cpp: >+ (WebCore::WHLSL::Metal::TypeNamer::emitUnnamedTypeDefinition): >+ * Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.cpp: >+ (WebCore::WHLSL::PreserveLifetimes::assignVariableIntoStruct): >+ * Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp: >+ (WebCore::WHLSL::PropertyResolver::visit): >+ * Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt: >+ * platform/graphics/gpu/cocoa/GPUComputePipelineMetal.mm: >+ (WebCore::trySetFunctions): >+ * platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm: >+ (WebCore::trySetFunctions): >+ > 2019-06-13 Commit Queue <commit-queue@webkit.org> > > Unreviewed, rolling out r246396 and r246397. >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.cpp (revision 246404) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLPreserveVariableLifetimes.cpp (working copy) >@@ -110,7 +110,7 @@ public: > > auto rhs = makeUniqueRef<AST::VariableReference>(AST::VariableReference::wrap(variable)); > rhs->setType(variable.type()->clone()); >- rhs->setTypeAnnotation(AST::RightValue()); >+ rhs->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); > > auto assignment = makeUniqueRef<AST::AssignmentExpression>(variable.origin(), WTFMove(lhs), WTFMove(rhs)); > assignment->setType(variable.type()->clone()); >@@ -136,7 +136,7 @@ public: > > auto makePointerExpression = makeUniqueRef<AST::MakePointerExpression>(functionDefinition.origin(), WTFMove(structVariableReference)); > makePointerExpression->setType(m_pointerToStructType->clone()); >- makePointerExpression->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); >+ makePointerExpression->setTypeAnnotation(AST::RightValue()); > > auto pointerDeclaration = makeUniqueRef<AST::VariableDeclaration>(functionDefinition.origin(), AST::Qualifiers(), > m_pointerToStructType->clone(), "wrapper"_s, WTF::nullopt, Optional<UniqueRef<AST::Expression>>(WTFMove(makePointerExpression))); >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp (revision 246404) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLPropertyResolver.cpp (working copy) >@@ -687,7 +687,11 @@ void PropertyResolver::visit(AST::ReadMo > expressions.append(WTFMove(assignmentExpression)); > } > >- return {{ WTFMove(expressions), readModifyWriteExpression.newVariableReference() }}; >+ auto variableReference = readModifyWriteExpression.newVariableReference(); >+ variableReference->setType(readModifyWriteExpression.leftValue().resolvedType().clone()); >+ variableReference->setTypeAnnotation(AST::LeftValue { AST::AddressSpace::Thread }); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198169 Is this right? >+ >+ return {{ WTFMove(expressions), WTFMove(variableReference) }}; > }); > > if (!modifyResult) { >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt (revision 246404) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt (working copy) >@@ -439,6 +439,9 @@ native uint operator+(uint, uint); > native bool operator<(int, int); > native bool operator<(uint, uint); > native bool operator<(float, float); >+native bool operator==(float, float); >+native bool operator==(int, int); >+native bool operator==(thread int*, thread int*); > native float operator*(float, float); > > native bool operator.x(bool2); >Index: Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp (revision 246404) >+++ Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp (working copy) >@@ -88,8 +88,18 @@ public: > , m_functionMapping(functionMapping) > , m_layout(layout) > { >+ m_stringBuilder.append(makeString( >+ "template <typename T>\n" >+ "inline void ", memsetZeroFunctionName, "(thread T& value)\n" >+ "{\n" >+ " thread char* ptr = static_cast<thread char*>(static_cast<thread void*>(&value));\n" >+ " for (size_t i = 0; i < sizeof(T); ++i)\n" >+ " ptr[i] = 0;\n" >+ "}\n")); > } > >+ static constexpr const char* memsetZeroFunctionName = "memsetZero"; >+ > virtual ~FunctionDefinitionWriter() = default; > > String toString() { return m_stringBuilder.toString(); } >@@ -153,12 +163,41 @@ protected: > return makeString("variable", m_variableCount++); > } > >+ struct StackItem { >+ String value; >+ String leftValue; >+ }; >+ >+ void appendRightValue(AST::Expression&, String value) >+ { >+ m_stack.append({ WTFMove(value), String() }); >+ } >+ >+ void appendLeftValue(AST::Expression& expression, String value, String leftValue) >+ { >+ ASSERT_UNUSED(expression, expression.typeAnnotation().leftAddressSpace()); >+ m_stack.append({ WTFMove(value), WTFMove(leftValue) }); >+ } >+ >+ String takeLastValue() >+ { >+ ASSERT(m_stack.last().value); >+ return m_stack.takeLast().value; >+ } >+ >+ String takeLastLeftValue() >+ { >+ ASSERT(m_stack.last().leftValue); >+ return m_stack.takeLast().leftValue; >+ } >+ > Intrinsics& m_intrinsics; > TypeNamer& m_typeNamer; > HashMap<AST::FunctionDeclaration*, String>& m_functionMapping; > HashMap<AST::VariableDeclaration*, String> m_variableMapping; > StringBuilder m_stringBuilder; >- Vector<String> m_stack; >+ >+ Vector<StackItem> m_stack; > std::unique_ptr<EntryPointScaffolding> m_entryPointScaffolding; > Layout& m_layout; > unsigned m_variableCount { 0 }; >@@ -169,7 +208,7 @@ void FunctionDefinitionWriter::visit(AST > { > auto iterator = m_functionMapping.find(&nativeFunctionDeclaration); > ASSERT(iterator != m_functionMapping.end()); >- m_stringBuilder.append(writeNativeFunction(nativeFunctionDeclaration, iterator->value, m_intrinsics, m_typeNamer)); >+ m_stringBuilder.append(writeNativeFunction(nativeFunctionDeclaration, iterator->value, m_intrinsics, m_typeNamer, memsetZeroFunctionName)); > } > > void FunctionDefinitionWriter::visit(AST::FunctionDefinition& functionDefinition) >@@ -246,7 +285,7 @@ void FunctionDefinitionWriter::visit(AST > void FunctionDefinitionWriter::visit(AST::EffectfulExpressionStatement& effectfulExpressionStatement) > { > checkErrorAndVisit(effectfulExpressionStatement.effectfulExpression()); >- m_stack.takeLast(); // The statement is already effectful, so we don't need to do anything with the result. >+ takeLastValue(); // The statement is already effectful, so we don't need to do anything with the result. > } > > void FunctionDefinitionWriter::visit(AST::Fallthrough&) >@@ -264,7 +303,7 @@ void FunctionDefinitionWriter::emitLoop( > > if (loopConditionLocation == LoopConditionLocation::BeforeBody && conditionExpression) { > checkErrorAndVisit(*conditionExpression); >- m_stringBuilder.append(makeString("if (!", m_stack.takeLast(), ") break;\n")); >+ m_stringBuilder.append(makeString("if (!", takeLastValue(), ") break;\n")); > } > > m_stringBuilder.append("do {\n"); >@@ -276,12 +315,12 @@ void FunctionDefinitionWriter::emitLoop( > checkErrorAndVisit(*increment); > // Expression results get pushed to m_stack. We don't use the result > // of increment, so we dispense of that now. >- m_stack.takeLast(); >+ takeLastValue(); > } > > if (loopConditionLocation == LoopConditionLocation::AfterBody && conditionExpression) { > checkErrorAndVisit(*conditionExpression); >- m_stringBuilder.append(makeString("if (!", m_stack.takeLast(), ") break;\n")); >+ m_stringBuilder.append(makeString("if (!", takeLastValue(), ") break;\n")); > } > > m_stringBuilder.append("} \n"); >@@ -305,7 +344,7 @@ void FunctionDefinitionWriter::visit(AST > checkErrorAndVisit(statement); > }, [&](UniqueRef<AST::Expression>& expression) { > checkErrorAndVisit(expression); >- m_stack.takeLast(); // We don't need to do anything with the result. >+ takeLastValue(); // We don't need to do anything with the result. > }), forLoop.initialization()); > > emitLoop(LoopConditionLocation::BeforeBody, forLoop.condition(), forLoop.increment(), forLoop.body()); >@@ -315,7 +354,7 @@ void FunctionDefinitionWriter::visit(AST > void FunctionDefinitionWriter::visit(AST::IfStatement& ifStatement) > { > checkErrorAndVisit(ifStatement.conditional()); >- m_stringBuilder.append(makeString("if (", m_stack.takeLast(), ") {\n")); >+ m_stringBuilder.append(makeString("if (", takeLastValue(), ") {\n")); > checkErrorAndVisit(ifStatement.body()); > if (ifStatement.elseBody()) { > m_stringBuilder.append("} else {\n"); >@@ -330,10 +369,10 @@ void FunctionDefinitionWriter::visit(AST > checkErrorAndVisit(*returnStatement.value()); > if (m_entryPointScaffolding) { > auto variableName = generateNextVariableName(); >- m_stringBuilder.append(m_entryPointScaffolding->pack(m_stack.takeLast(), variableName)); >+ m_stringBuilder.append(m_entryPointScaffolding->pack(takeLastValue(), variableName)); > m_stringBuilder.append(makeString("return ", variableName, ";\n")); > } else >- m_stringBuilder.append(makeString("return ", m_stack.takeLast(), ";\n")); >+ m_stringBuilder.append(makeString("return ", takeLastValue(), ";\n")); > } else > m_stringBuilder.append("return;\n"); > } >@@ -342,7 +381,7 @@ void FunctionDefinitionWriter::visit(AST > { > checkErrorAndVisit(switchStatement.value()); > >- m_stringBuilder.append(makeString("switch (", m_stack.takeLast(), ") {")); >+ m_stringBuilder.append(makeString("switch (", takeLastValue(), ") {")); > for (auto& switchCase : switchStatement.switchCases()) > checkErrorAndVisit(switchCase); > m_stringBuilder.append("}\n"); >@@ -375,7 +414,7 @@ void FunctionDefinitionWriter::visit(AST > auto variableName = generateNextVariableName(); > auto mangledTypeName = m_typeNamer.mangledNameForType(integerLiteral.resolvedType()); > m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = static_cast<", mangledTypeName, ">(", integerLiteral.value(), ");\n")); >- m_stack.append(variableName); >+ appendRightValue(integerLiteral, variableName); > } > > void FunctionDefinitionWriter::visit(AST::UnsignedIntegerLiteral& unsignedIntegerLiteral) >@@ -383,7 +422,7 @@ void FunctionDefinitionWriter::visit(AST > auto variableName = generateNextVariableName(); > auto mangledTypeName = m_typeNamer.mangledNameForType(unsignedIntegerLiteral.resolvedType()); > m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = static_cast<", mangledTypeName, ">(", unsignedIntegerLiteral.value(), ");\n")); >- m_stack.append(variableName); >+ appendRightValue(unsignedIntegerLiteral, variableName); > } > > void FunctionDefinitionWriter::visit(AST::FloatLiteral& floatLiteral) >@@ -391,7 +430,7 @@ void FunctionDefinitionWriter::visit(AST > auto variableName = generateNextVariableName(); > auto mangledTypeName = m_typeNamer.mangledNameForType(floatLiteral.resolvedType()); > m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = static_cast<", mangledTypeName, ">(", floatLiteral.value(), ");\n")); >- m_stack.append(variableName); >+ appendRightValue(floatLiteral, variableName); > } > > void FunctionDefinitionWriter::visit(AST::NullLiteral& nullLiteral) >@@ -408,7 +447,7 @@ void FunctionDefinitionWriter::visit(AST > else > m_stringBuilder.append("nullptr"); > m_stringBuilder.append(";\n"); >- m_stack.append(variableName); >+ appendRightValue(nullLiteral, variableName); > } > > void FunctionDefinitionWriter::visit(AST::BooleanLiteral& booleanLiteral) >@@ -416,7 +455,7 @@ void FunctionDefinitionWriter::visit(AST > auto variableName = generateNextVariableName(); > auto mangledTypeName = m_typeNamer.mangledNameForType(booleanLiteral.resolvedType()); > m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = static_cast<", mangledTypeName, ">(", booleanLiteral.value() ? "true" : "false", ");\n")); >- m_stack.append(variableName); >+ appendRightValue(booleanLiteral, variableName); > } > > void FunctionDefinitionWriter::visit(AST::EnumerationMemberLiteral& enumerationMemberLiteral) >@@ -426,7 +465,7 @@ void FunctionDefinitionWriter::visit(AST > auto variableName = generateNextVariableName(); > auto mangledTypeName = m_typeNamer.mangledNameForType(enumerationMemberLiteral.resolvedType()); > m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = ", mangledTypeName, '.', m_typeNamer.mangledNameForEnumerationMember(*enumerationMemberLiteral.enumerationMember()), ";\n")); >- m_stack.append(variableName); >+ appendRightValue(enumerationMemberLiteral, variableName); > } > > void FunctionDefinitionWriter::visit(AST::Expression& expression) >@@ -434,37 +473,39 @@ void FunctionDefinitionWriter::visit(AST > Visitor::visit(expression); > } > >-void FunctionDefinitionWriter::visit(AST::DotExpression&) >+void FunctionDefinitionWriter::visit(AST::DotExpression& dotExpression) > { > // This should be lowered already. > // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195788 Replace this with ASSERT_NOT_REACHED(). > notImplemented(); >- m_stack.append("dummy"); >+ appendRightValue(dotExpression, "dummy"); > } > > void FunctionDefinitionWriter::visit(AST::GlobalVariableReference& globalVariableReference) > { >- auto variableName = generateNextVariableName(); >+ auto valueName = generateNextVariableName(); >+ auto pointerName = generateNextVariableName(); > auto mangledTypeName = m_typeNamer.mangledNameForType(globalVariableReference.resolvedType()); > checkErrorAndVisit(globalVariableReference.base()); >- m_stringBuilder.append(makeString("thread ", mangledTypeName, "& ", variableName, " = ", m_stack.takeLast(), "->", m_typeNamer.mangledNameForStructureElement(globalVariableReference.structField()), ";\n")); >- m_stack.append(variableName); >+ m_stringBuilder.append(makeString("thread ", mangledTypeName, "* ", pointerName, " = &", takeLastValue(), "->", m_typeNamer.mangledNameForStructureElement(globalVariableReference.structField()), ";\n")); >+ m_stringBuilder.append(makeString(mangledTypeName, ' ', valueName, " = ", "*", pointerName, ";\n")); >+ appendLeftValue(globalVariableReference, valueName, pointerName); > } > >-void FunctionDefinitionWriter::visit(AST::IndexExpression&) >+void FunctionDefinitionWriter::visit(AST::IndexExpression& indexExpression) > { > // This should be lowered already. > // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195788 Replace this with ASSERT_NOT_REACHED(). > notImplemented(); >- m_stack.append("dummy"); >+ appendRightValue(indexExpression, "dummy"); > } > >-void FunctionDefinitionWriter::visit(AST::PropertyAccessExpression&) >+void FunctionDefinitionWriter::visit(AST::PropertyAccessExpression& propertyAccessExpression) > { > // This should be lowered already. > // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195788 Replace this with ASSERT_NOT_REACHED(). > notImplemented(); >- m_stack.append("dummy"); >+ appendRightValue(propertyAccessExpression, "dummy"); > } > > void FunctionDefinitionWriter::visit(AST::VariableDeclaration& variableDeclaration) >@@ -476,7 +517,7 @@ void FunctionDefinitionWriter::visit(AST > // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198160 Implement qualifiers. > if (variableDeclaration.initializer()) { > checkErrorAndVisit(*variableDeclaration.initializer()); >- m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(*variableDeclaration.type()), ' ', variableName, " = ", m_stack.takeLast(), ";\n")); >+ m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(*variableDeclaration.type()), ' ', variableName, " = ", takeLastValue(), ";\n")); > } else > m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(*variableDeclaration.type()), ' ', variableName, ";\n")); > } >@@ -484,11 +525,11 @@ void FunctionDefinitionWriter::visit(AST > void FunctionDefinitionWriter::visit(AST::AssignmentExpression& assignmentExpression) > { > checkErrorAndVisit(assignmentExpression.left()); >- auto leftName = m_stack.takeLast(); >+ auto pointerName = takeLastLeftValue(); > checkErrorAndVisit(assignmentExpression.right()); >- auto rightName = m_stack.takeLast(); >- m_stringBuilder.append(makeString(leftName, " = ", rightName, ";\n")); >- m_stack.append(rightName); >+ auto rightName = takeLastValue(); >+ m_stringBuilder.append(makeString("if (", pointerName, ") *", pointerName, " = ", rightName, ";\n")); >+ appendRightValue(assignmentExpression, rightName); > } > > void FunctionDefinitionWriter::visit(AST::CallExpression& callExpression) >@@ -496,7 +537,7 @@ void FunctionDefinitionWriter::visit(AST > Vector<String> argumentNames; > for (auto& argument : callExpression.arguments()) { > checkErrorAndVisit(argument); >- argumentNames.append(m_stack.takeLast()); >+ argumentNames.append(takeLastValue()); > } > ASSERT(callExpression.function()); > auto iterator = m_functionMapping.find(callExpression.function()); >@@ -509,7 +550,7 @@ void FunctionDefinitionWriter::visit(AST > m_stringBuilder.append(argumentNames[i]); > } > m_stringBuilder.append(");\n"); >- m_stack.append(variableName); >+ appendRightValue(callExpression, variableName); > } > > void FunctionDefinitionWriter::visit(AST::CommaExpression& commaExpression) >@@ -517,26 +558,30 @@ void FunctionDefinitionWriter::visit(AST > String result; > for (auto& expression : commaExpression.list()) { > checkErrorAndVisit(expression); >- result = m_stack.takeLast(); >+ result = takeLastValue(); > } >- m_stack.append(result); >+ appendRightValue(commaExpression, result); > } > > void FunctionDefinitionWriter::visit(AST::DereferenceExpression& dereferenceExpression) > { > checkErrorAndVisit(dereferenceExpression.pointer()); >- auto right = m_stack.takeLast(); >+ auto right = takeLastValue(); > auto variableName = generateNextVariableName(); >- m_stringBuilder.append(makeString(AST::toString(*dereferenceExpression.typeAnnotation().leftAddressSpace()), ' ', m_typeNamer.mangledNameForType(dereferenceExpression.resolvedType()), "& ", variableName, " = *", right, ";\n")); >- m_stack.append(variableName); >+ auto pointerName = generateNextVariableName(); >+ m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(dereferenceExpression.pointer().resolvedType()), ' ', pointerName, " = ", right, ";\n")); >+ m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(dereferenceExpression.resolvedType()), ' ', variableName, ";\n")); >+ m_stringBuilder.append(makeString("if (", pointerName, ") ", variableName, " = *", right, ";\n")); >+ m_stringBuilder.append(makeString("else ", memsetZeroFunctionName, '(', variableName, ");\n")); >+ appendLeftValue(dereferenceExpression, variableName, pointerName); > } > > void FunctionDefinitionWriter::visit(AST::LogicalExpression& logicalExpression) > { > checkErrorAndVisit(logicalExpression.left()); >- auto left = m_stack.takeLast(); >+ auto left = takeLastValue(); > checkErrorAndVisit(logicalExpression.right()); >- auto right = m_stack.takeLast(); >+ auto right = takeLastValue(); > auto variableName = generateNextVariableName(); > m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(logicalExpression.resolvedType()), ' ', variableName, " = ", left)); > switch (logicalExpression.type()) { >@@ -549,22 +594,24 @@ void FunctionDefinitionWriter::visit(AST > break; > } > m_stringBuilder.append(makeString(right, ";\n")); >- m_stack.append(variableName); >+ appendRightValue(logicalExpression, variableName); > } > > void FunctionDefinitionWriter::visit(AST::LogicalNotExpression& logicalNotExpression) > { > checkErrorAndVisit(logicalNotExpression.operand()); >- auto operand = m_stack.takeLast(); >+ auto operand = takeLastValue(); > auto variableName = generateNextVariableName(); > m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(logicalNotExpression.resolvedType()), ' ', variableName, " = !", operand, ";\n")); >- m_stack.append(variableName); >+ appendRightValue(logicalNotExpression, variableName); > } > > void FunctionDefinitionWriter::visit(AST::MakeArrayReferenceExpression& makeArrayReferenceExpression) > { > checkErrorAndVisit(makeArrayReferenceExpression.leftValue()); >- auto lValue = m_stack.takeLast(); >+ // FIXME: This needs to be made to work. It probably should be using the last leftValue too. >+ // https://bugs.webkit.org/show_bug.cgi?id=198838 >+ auto lValue = takeLastValue(); > auto variableName = generateNextVariableName(); > auto mangledTypeName = m_typeNamer.mangledNameForType(makeArrayReferenceExpression.resolvedType()); > if (is<AST::PointerType>(makeArrayReferenceExpression.resolvedType())) >@@ -574,16 +621,16 @@ void FunctionDefinitionWriter::visit(AST > m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = { &(", lValue, "[0]), ", arrayType.numElements(), " };\n")); > } else > m_stringBuilder.append(makeString(mangledTypeName, ' ', variableName, " = { &", lValue, ", 1 };\n")); >- m_stack.append(variableName); >+ appendRightValue(makeArrayReferenceExpression, variableName); > } > > void FunctionDefinitionWriter::visit(AST::MakePointerExpression& makePointerExpression) > { > checkErrorAndVisit(makePointerExpression.leftValue()); >- auto lValue = m_stack.takeLast(); >+ auto pointer = takeLastLeftValue(); > auto variableName = generateNextVariableName(); >- m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(makePointerExpression.resolvedType()), ' ', variableName, " = &", lValue, ";\n")); >- m_stack.append(variableName); >+ m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(makePointerExpression.resolvedType()), ' ', variableName, " = ", pointer, ";\n")); >+ appendRightValue(makePointerExpression, variableName); > } > > void FunctionDefinitionWriter::visit(AST::ReadModifyWriteExpression&) >@@ -595,19 +642,19 @@ void FunctionDefinitionWriter::visit(AST > void FunctionDefinitionWriter::visit(AST::TernaryExpression& ternaryExpression) > { > checkErrorAndVisit(ternaryExpression.predicate()); >- auto check = m_stack.takeLast(); >+ auto check = takeLastValue(); > > auto variableName = generateNextVariableName(); > m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(ternaryExpression.resolvedType()), ' ', variableName, ";\n")); > > m_stringBuilder.append(makeString("if (", check, ") {\n")); > checkErrorAndVisit(ternaryExpression.bodyExpression()); >- m_stringBuilder.append(makeString(variableName, " = ", m_stack.takeLast(), ";\n")); >+ m_stringBuilder.append(makeString(variableName, " = ", takeLastValue(), ";\n")); > m_stringBuilder.append("} else {\n"); > checkErrorAndVisit(ternaryExpression.elseExpression()); >- m_stringBuilder.append(makeString(variableName, " = ", m_stack.takeLast(), ";\n")); >+ m_stringBuilder.append(makeString(variableName, " = ", takeLastValue(), ";\n")); > m_stringBuilder.append("}\n"); >- m_stack.append(variableName); >+ appendRightValue(ternaryExpression, variableName); > } > > void FunctionDefinitionWriter::visit(AST::VariableReference& variableReference) >@@ -615,7 +662,9 @@ void FunctionDefinitionWriter::visit(AST > ASSERT(variableReference.variable()); > auto iterator = m_variableMapping.find(variableReference.variable()); > ASSERT(iterator != m_variableMapping.end()); >- m_stack.append(iterator->value); >+ auto pointerName = generateNextVariableName(); >+ m_stringBuilder.append(makeString("thread ", m_typeNamer.mangledNameForType(variableReference.resolvedType()), "* ", pointerName, " = &", iterator->value, ";\n")); >+ appendLeftValue(variableReference, iterator->value, pointerName); > } > > String FunctionDefinitionWriter::constantExpressionString(AST::ConstantExpression& constantExpression) >Index: Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp (revision 246404) >+++ Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp (working copy) >@@ -81,7 +81,7 @@ static String atomicName(String input) > return "fetch_xor"_str; > } > >-String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclaration, String& outputFunctionName, Intrinsics& intrinsics, TypeNamer& typeNamer) >+String writeNativeFunction(AST::NativeFunctionDeclaration& nativeFunctionDeclaration, String& outputFunctionName, Intrinsics& intrinsics, TypeNamer& typeNamer, const char* memsetZeroFunctionName) > { > StringBuilder stringBuilder; > if (nativeFunctionDeclaration.isCast()) { >@@ -89,8 +89,7 @@ String writeNativeFunction(AST::NativeFu > if (!nativeFunctionDeclaration.parameters().size()) { > stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, "() {\n")); > stringBuilder.append(makeString(" ", metalReturnName, " x;\n")); >- stringBuilder.append(" thread char* ptr = static_cast<thread char*>(static_cast<thread void*>(&x));\n"); >- stringBuilder.append(makeString(" for (size_t i = 0; i < sizeof(", metalReturnName, "); ++i) ptr[i] = 0;\n")); >+ stringBuilder.append(makeString(" ", memsetZeroFunctionName, "(x);\n")); > stringBuilder.append(" return x;\n"); > stringBuilder.append("}\n"); > return stringBuilder.toString(); >@@ -215,38 +214,14 @@ String writeNativeFunction(AST::NativeFu > return stringBuilder.toString(); > } > >- if (nativeFunctionDeclaration.name() == "operator[]") { >- ASSERT(nativeFunctionDeclaration.parameters().size() == 2); >- auto metalParameter1Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type()); >- auto metalParameter2Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[1]->type()); >- auto metalReturnName = typeNamer.mangledNameForType(nativeFunctionDeclaration.type()); >- stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " m, ", metalParameter2Name, " i) {\n")); >- stringBuilder.append(makeString(" return m[i];\n")); >- stringBuilder.append("}\n"); >- return stringBuilder.toString(); >- } >- > if (nativeFunctionDeclaration.name() == "operator&[]") { > ASSERT(nativeFunctionDeclaration.parameters().size() == 2); > auto metalParameter1Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type()); > auto metalParameter2Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[1]->type()); > auto metalReturnName = typeNamer.mangledNameForType(nativeFunctionDeclaration.type()); >- auto fieldName = nativeFunctionDeclaration.name().substring("operator&[]."_str.length()); > stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " v, ", metalParameter2Name, " n) {\n")); >- stringBuilder.append(makeString(" return &(v.pointer[n]);\n")); >- stringBuilder.append("}\n"); >- return stringBuilder.toString(); >- } >- >- if (nativeFunctionDeclaration.name() == "operator[]=") { >- ASSERT(nativeFunctionDeclaration.parameters().size() == 3); >- auto metalParameter1Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type()); >- auto metalParameter2Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[1]->type()); >- auto metalParameter3Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[2]->type()); >- auto metalReturnName = typeNamer.mangledNameForType(nativeFunctionDeclaration.type()); >- stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " m, ", metalParameter2Name, " i, ", metalParameter3Name, " v) {\n")); >- stringBuilder.append(makeString(" m[i] = v;\n")); >- stringBuilder.append(makeString(" return m;\n")); >+ stringBuilder.append(" if (n < v.length) return &(v.pointer[n]);\n"); >+ stringBuilder.append(" return nullptr;\n"); > stringBuilder.append("}\n"); > return stringBuilder.toString(); > } >Index: Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.h >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.h (revision 246404) >+++ Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.h (working copy) >@@ -45,7 +45,7 @@ namespace Metal { > > class TypeNamer; > >-String writeNativeFunction(AST::NativeFunctionDeclaration&, String& outputFunctionName, Intrinsics&, TypeNamer&); >+String writeNativeFunction(AST::NativeFunctionDeclaration&, String& outputFunctionName, Intrinsics&, TypeNamer&, const char* memsetZeroFunctionName); > > } > >Index: Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.cpp (revision 246404) >+++ Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLTypeNamer.cpp (working copy) >@@ -396,7 +396,7 @@ void TypeNamer::emitUnnamedTypeDefinitio > ASSERT(baseTypeNameNode.parent()); > stringBuilder.append(makeString("struct ", arrayReferenceType.mangledName(), "{ \n")); > stringBuilder.append(makeString(" ", toString(arrayReferenceType.addressSpace()), " ", arrayReferenceType.parent()->mangledName(), "* pointer;\n")); >- stringBuilder.append(" uint length;\n"); >+ stringBuilder.append(" uint32_t length;\n"); > stringBuilder.append("};\n"); > } else { > ASSERT(is<ArrayTypeNameNode>(baseTypeNameNode)); >Index: Source/WebCore/platform/graphics/gpu/cocoa/GPUComputePipelineMetal.mm >=================================================================== >--- Source/WebCore/platform/graphics/gpu/cocoa/GPUComputePipelineMetal.mm (revision 246404) >+++ Source/WebCore/platform/graphics/gpu/cocoa/GPUComputePipelineMetal.mm (working copy) >@@ -92,8 +92,9 @@ static Optional<WHLSL::ComputeDimensions > BEGIN_BLOCK_OBJC_EXCEPTIONS; > computeLibrary = adoptNS([device.platformDevice() newLibraryWithSource:whlslCompileResult->metalSource options:nil error:&error]); > END_BLOCK_OBJC_EXCEPTIONS; >- > ASSERT(computeLibrary); >+ if (!computeLibrary) >+ NSLog(@"%@", error); > // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195771 Once we zero-fill variables, there should be no warnings, so we should be able to ASSERT(!error) here. > > computeEntryPoint = whlslCompileResult->mangledEntryPointName; >Index: Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm >=================================================================== >--- Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm (revision 246404) >+++ Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm (working copy) >@@ -417,6 +417,8 @@ static bool trySetFunctions(const char* > END_BLOCK_OBJC_EXCEPTIONS; > > ASSERT(vertexLibrary); >+ if (!vertexLibrary) >+ NSLog(@"%@", error); > // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195771 Once we zero-fill variables, there should be no warnings, so we should be able to ASSERT(!error) here. > > fragmentLibrary = vertexLibrary; >Index: LayoutTests/ChangeLog >=================================================================== >--- LayoutTests/ChangeLog (revision 246404) >+++ LayoutTests/ChangeLog (working copy) >@@ -1,3 +1,16 @@ >+2019-06-13 Saam Barati <sbarati@apple.com> >+ >+ [WHLSL] Implement out-of-bounds and nullptr behavior >+ https://bugs.webkit.org/show_bug.cgi?id=198600 >+ <rdar://problem/51668853> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * webgpu/whlsl-null-dereference-expected.txt: Added. >+ * webgpu/whlsl-null-dereference.html: Added. >+ * webgpu/whlsl-oob-access-expected.txt: Added. >+ * webgpu/whlsl-oob-access.html: Added. >+ > 2019-06-13 Antoine Quint <graouts@apple.com> > > "display: contents" Content click does not trigger >Index: LayoutTests/webgpu/whlsl-null-dereference-expected.txt >=================================================================== >--- LayoutTests/webgpu/whlsl-null-dereference-expected.txt (nonexistent) >+++ LayoutTests/webgpu/whlsl-null-dereference-expected.txt (working copy) >@@ -0,0 +1,12 @@ >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+PASS resultsFloat32Array[0] is 2 >+PASS resultsFloat32Array[1] is 4 >+PASS resultsFloat32Array[2] is 6 >+PASS resultsFloat32Array[3] is 8 >+PASS resultsFloat32Array[4] is 5 >+PASS resultsFloat32Array[5] is 6 >+PASS resultsFloat32Array[6] is 7 >+PASS resultsFloat32Array[7] is 8 >+ >Index: LayoutTests/webgpu/whlsl-null-dereference.html >=================================================================== >--- LayoutTests/webgpu/whlsl-null-dereference.html (nonexistent) >+++ LayoutTests/webgpu/whlsl-null-dereference.html (working copy) >@@ -0,0 +1,124 @@ >+<!DOCTYPE html> >+<html> >+<head> >+<script src="../resources/js-test-pre.js"></script> >+</head> >+<body> >+<script> >+const shaderSource = ` >+typedef Foo = thread int*; >+Foo getNullPtr() >+{ >+ return null; >+} >+ >+struct XYZ { >+ float x; >+ float y; >+ float z; >+} >+ >+[numthreads(2, 1, 1)] >+compute void computeShader(device float[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) { >+ Foo ptr = null; >+ *ptr = 42; >+ *getNullPtr() = 42; >+ if (*ptr == 0) { >+ if (ptr == getNullPtr()) { >+ if (*getNullPtr() == 0) { >+ thread XYZ* xyzPtr = null; >+ XYZ xyz; >+ xyz.x = 1; >+ xyz.y = 1; >+ xyz.z = 1; >+ if (xyz.z == 1.0 && xyz.y == 1.0 && xyz.z == 1.0) { >+ *xyzPtr = xyz; >+ xyz = *xyzPtr; >+ if (xyz.z == 0.0 && xyz.y == 0.0 && xyz.z == 0.0) { >+ if (&*getNullPtr() == null) { >+ if (&*(&*getNullPtr()) == null) { >+ buffer[uint(threadID.x)] = buffer[uint(threadID.x)] * 2.0; >+ } >+ } >+ } >+ } >+ } >+ } >+ } >+} >+`; >+let resultsFloat32Array; >+async function start() { >+ const adapter = await navigator.gpu.requestAdapter(); >+ const device = await adapter.requestDevice(); >+ >+ const shaderModule = device.createShaderModule({code: shaderSource, isWHLSL: true}); >+ const computeStage = {module: shaderModule, entryPoint: "computeShader"}; >+ >+ const bindGroupLayoutDescriptor = {bindings: [{binding: 0, visibility: 7, type: "storage-buffer"}]}; >+ const bindGroupLayout = device.createBindGroupLayout(bindGroupLayoutDescriptor); >+ const pipelineLayoutDescriptor = {bindGroupLayouts: [bindGroupLayout]}; >+ const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor); >+ >+ const computePipelineDescriptor = {computeStage, layout: pipelineLayout}; >+ const computePipeline = device.createComputePipeline(computePipelineDescriptor); >+ >+ const bufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 8, usage: GPUBufferUsage.MAP_WRITE | GPUBufferUsage.TRANSFER_SRC}; >+ const buffer = device.createBuffer(bufferDescriptor); >+ const bufferArrayBuffer = await buffer.mapWriteAsync(); >+ const bufferFloat32Array = new Float32Array(bufferArrayBuffer); >+ bufferFloat32Array[0] = 1; >+ bufferFloat32Array[1] = 2; >+ bufferFloat32Array[2] = 3; >+ bufferFloat32Array[3] = 4; >+ bufferFloat32Array[4] = 5; >+ bufferFloat32Array[5] = 6; >+ bufferFloat32Array[6] = 7; >+ bufferFloat32Array[7] = 8; >+ buffer.unmap(); >+ >+ const resultsBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 8, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.TRANSFER_DST | GPUBufferUsage.MAP_READ}; >+ const resultsBuffer = device.createBuffer(resultsBufferDescriptor); >+ >+ const bufferBinding = {buffer: resultsBuffer, size: 4}; >+ const bindGroupBinding = {binding: 0, resource: bufferBinding}; >+ const bindGroupDescriptor = {layout: bindGroupLayout, bindings: [bindGroupBinding]}; >+ const bindGroup = device.createBindGroup(bindGroupDescriptor); >+ >+ const commandEncoder = device.createCommandEncoder(); // {} >+ commandEncoder.copyBufferToBuffer(buffer, 0, resultsBuffer, 0, Float32Array.BYTES_PER_ELEMENT * 8); >+ const computePassEncoder = commandEncoder.beginComputePass(); >+ computePassEncoder.setPipeline(computePipeline); >+ computePassEncoder.setBindGroup(0, bindGroup); >+ computePassEncoder.dispatch(2, 1, 1); >+ computePassEncoder.endPass(); >+ const commandBuffer = commandEncoder.finish(); >+ device.getQueue().submit([commandBuffer]); >+ >+ const resultsArrayBuffer = await resultsBuffer.mapReadAsync(); >+ resultsFloat32Array = new Float32Array(resultsArrayBuffer); >+ shouldBe("resultsFloat32Array[0]", "2"); >+ shouldBe("resultsFloat32Array[1]", "4"); >+ shouldBe("resultsFloat32Array[2]", "6"); >+ shouldBe("resultsFloat32Array[3]", "8"); >+ shouldBe("resultsFloat32Array[4]", "5"); >+ shouldBe("resultsFloat32Array[5]", "6"); >+ shouldBe("resultsFloat32Array[6]", "7"); >+ shouldBe("resultsFloat32Array[7]", "8"); >+ resultsBuffer.unmap(); >+} >+if (window.testRunner) >+ testRunner.waitUntilDone(); >+window.addEventListener("load", function() { >+ start().then(function() { >+ if (window.testRunner) >+ testRunner.notifyDone(); >+ }, function() { >+ if (window.testRunner) >+ testRunner.notifyDone(); >+ }); >+}); >+</script> >+<script src="../resources/js-test-post.js"></script> >+</body> >+</html> >Index: LayoutTests/webgpu/whlsl-oob-access-expected.txt >=================================================================== >--- LayoutTests/webgpu/whlsl-oob-access-expected.txt (nonexistent) >+++ LayoutTests/webgpu/whlsl-oob-access-expected.txt (working copy) >@@ -0,0 +1,12 @@ >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+PASS resultsFloat32Array[0] is 2 >+PASS resultsFloat32Array[1] is 4 >+PASS resultsFloat32Array[2] is 6 >+PASS resultsFloat32Array[3] is 8 >+PASS resultsFloat32Array[4] is 5 >+PASS resultsFloat32Array[5] is 6 >+PASS resultsFloat32Array[6] is 7 >+PASS resultsFloat32Array[7] is 8 >+ >Index: LayoutTests/webgpu/whlsl-oob-access.html >=================================================================== >--- LayoutTests/webgpu/whlsl-oob-access.html (nonexistent) >+++ LayoutTests/webgpu/whlsl-oob-access.html (working copy) >@@ -0,0 +1,91 @@ >+<!DOCTYPE html> >+<html> >+<head> >+<script src="../resources/js-test-pre.js"></script> >+</head> >+<body> >+<script> >+const shaderSource = ` >+[numthreads(2, 1, 1)] >+compute void computeShader(device float[] buffer : register(u0), float3 threadID : SV_DispatchThreadID) { >+ buffer[1337] = 0.0; >+ buffer[42424242] = 0.0; >+ if (buffer[100000] == 0.0) >+ buffer[uint(threadID.x)] = buffer[uint(threadID.x)] * 2.0; >+} >+`; >+let resultsFloat32Array; >+async function start() { >+ const adapter = await navigator.gpu.requestAdapter(); >+ const device = await adapter.requestDevice(); >+ >+ const shaderModule = device.createShaderModule({code: shaderSource, isWHLSL: true}); >+ const computeStage = {module: shaderModule, entryPoint: "computeShader"}; >+ >+ const bindGroupLayoutDescriptor = {bindings: [{binding: 0, visibility: 7, type: "storage-buffer"}]}; >+ const bindGroupLayout = device.createBindGroupLayout(bindGroupLayoutDescriptor); >+ const pipelineLayoutDescriptor = {bindGroupLayouts: [bindGroupLayout]}; >+ const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor); >+ >+ const computePipelineDescriptor = {computeStage, layout: pipelineLayout}; >+ const computePipeline = device.createComputePipeline(computePipelineDescriptor); >+ >+ const bufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 8, usage: GPUBufferUsage.MAP_WRITE | GPUBufferUsage.TRANSFER_SRC}; >+ const buffer = device.createBuffer(bufferDescriptor); >+ const bufferArrayBuffer = await buffer.mapWriteAsync(); >+ const bufferFloat32Array = new Float32Array(bufferArrayBuffer); >+ bufferFloat32Array[0] = 1; >+ bufferFloat32Array[1] = 2; >+ bufferFloat32Array[2] = 3; >+ bufferFloat32Array[3] = 4; >+ bufferFloat32Array[4] = 5; >+ bufferFloat32Array[5] = 6; >+ bufferFloat32Array[6] = 7; >+ bufferFloat32Array[7] = 8; >+ buffer.unmap(); >+ >+ const resultsBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT * 8, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.TRANSFER_DST | GPUBufferUsage.MAP_READ}; >+ const resultsBuffer = device.createBuffer(resultsBufferDescriptor); >+ >+ const bufferBinding = {buffer: resultsBuffer, size: 4}; >+ const bindGroupBinding = {binding: 0, resource: bufferBinding}; >+ const bindGroupDescriptor = {layout: bindGroupLayout, bindings: [bindGroupBinding]}; >+ const bindGroup = device.createBindGroup(bindGroupDescriptor); >+ >+ const commandEncoder = device.createCommandEncoder(); // {} >+ commandEncoder.copyBufferToBuffer(buffer, 0, resultsBuffer, 0, Float32Array.BYTES_PER_ELEMENT * 8); >+ const computePassEncoder = commandEncoder.beginComputePass(); >+ computePassEncoder.setPipeline(computePipeline); >+ computePassEncoder.setBindGroup(0, bindGroup); >+ computePassEncoder.dispatch(2, 1, 1); >+ computePassEncoder.endPass(); >+ const commandBuffer = commandEncoder.finish(); >+ device.getQueue().submit([commandBuffer]); >+ >+ const resultsArrayBuffer = await resultsBuffer.mapReadAsync(); >+ resultsFloat32Array = new Float32Array(resultsArrayBuffer); >+ shouldBe("resultsFloat32Array[0]", "2"); >+ shouldBe("resultsFloat32Array[1]", "4"); >+ shouldBe("resultsFloat32Array[2]", "6"); >+ shouldBe("resultsFloat32Array[3]", "8"); >+ shouldBe("resultsFloat32Array[4]", "5"); >+ shouldBe("resultsFloat32Array[5]", "6"); >+ shouldBe("resultsFloat32Array[6]", "7"); >+ shouldBe("resultsFloat32Array[7]", "8"); >+ resultsBuffer.unmap(); >+} >+if (window.testRunner) >+ testRunner.waitUntilDone(); >+window.addEventListener("load", function() { >+ start().then(function() { >+ if (window.testRunner) >+ testRunner.notifyDone(); >+ }, function() { >+ if (window.testRunner) >+ testRunner.notifyDone(); >+ }); >+}); >+</script> >+<script src="../resources/js-test-post.js"></script> >+</body> >+</html>
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
rmorisset
:
review+
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 198600
:
371908
|
371912
|
372013
|
372074
|
372127
|
372128