WebKit Bugzilla
Attachment 371768 Details for
Bug 198426
: [WHLSL] Auto initialize local variables
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
patch for landing
c-backup.diff (text/plain), 40.49 KB, created by
Saam Barati
on 2019-06-10 11:54:15 PDT
(
hide
)
Description:
patch for landing
Filename:
MIME Type:
Creator:
Saam Barati
Created:
2019-06-10 11:54:15 PDT
Size:
40.49 KB
patch
obsolete
>Index: Source/WebCore/ChangeLog >=================================================================== >--- Source/WebCore/ChangeLog (revision 246269) >+++ Source/WebCore/ChangeLog (working copy) >@@ -1,3 +1,56 @@ >+2019-06-10 Saam Barati <sbarati@apple.com> >+ >+ [WHLSL] Auto initialize local variables >+ https://bugs.webkit.org/show_bug.cgi?id=198426 >+ >+ Reviewed by Myles Maxfield. >+ >+ This patch implements zero-filling for local variables in two parts: >+ 1. We add a new pass, autoInitializeVariables, which makes any variable declaration >+ without an initializer call the default constructor for the variable's type. >+ Since we auto generate the default constructor, it's a native function whose >+ implementation we control. >+ >+ 2. Each native constructor is implemented as a memset(&value, sizeof(value), 0). >+ This memset is an inlined loop in each constructor. The reason this turns >+ everything into zero is that for every primitive type, the "zero" value is >+ represented as all zeroes in memory: float, int, pointers, etc. >+ >+ Since our ability to test some of this is limited, I opened a follow-up bug to >+ test this more: >+ https://bugs.webkit.org/show_bug.cgi?id=198413 >+ >+ Tests: webgpu/whlsl-zero-initialize-values-2.html >+ webgpu/whlsl-zero-initialize-values.html >+ >+ * Modules/webgpu/WHLSL/AST/WHLSLVariableDeclaration.h: >+ (WebCore::WHLSL::AST::VariableDeclaration::setInitializer): >+ * Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp: >+ (WebCore::WHLSL::Metal::FunctionDefinitionWriter::visit): >+ * Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp: >+ (WebCore::WHLSL::Metal::writeNativeFunction): >+ * Modules/webgpu/WHLSL/WHLSLASTDumper.h: >+ * Modules/webgpu/WHLSL/WHLSLAutoInitializeVariables.cpp: Added. >+ (WebCore::WHLSL::AutoInitialize::AutoInitialize): >+ (WebCore::WHLSL::AutoInitialize::visit): >+ (WebCore::WHLSL::autoInitializeVariables): >+ * Modules/webgpu/WHLSL/WHLSLAutoInitializeVariables.h: Added. >+ * Modules/webgpu/WHLSL/WHLSLChecker.cpp: >+ (WebCore::WHLSL::checkOperatorOverload): >+ (WebCore::WHLSL::Checker::visit): >+ * Modules/webgpu/WHLSL/WHLSLInferTypes.cpp: >+ (WebCore::WHLSL::inferTypesForCallImpl): >+ (WebCore::WHLSL::inferTypesForCall): >+ * Modules/webgpu/WHLSL/WHLSLInferTypes.h: >+ * Modules/webgpu/WHLSL/WHLSLPrepare.cpp: >+ (WebCore::WHLSL::prepareShared): >+ * Modules/webgpu/WHLSL/WHLSLResolveOverloadImpl.cpp: >+ (WebCore::WHLSL::resolveFunctionOverloadImpl): >+ (WebCore::WHLSL::resolveFunctionOverload): >+ * Modules/webgpu/WHLSL/WHLSLResolveOverloadImpl.h: >+ * Sources.txt: >+ * WebCore.xcodeproj/project.pbxproj: >+ > 2019-06-10 Ali Juma <ajuma@chromium.org> > > REGRESSION (r245396): Page load time performance regression >Index: Source/WebCore/Sources.txt >=================================================================== >--- Source/WebCore/Sources.txt (revision 246269) >+++ Source/WebCore/Sources.txt (working copy) >@@ -307,6 +307,7 @@ Modules/websockets/WorkerThreadableWebSo > Modules/webgpu/GPUCanvasContext.cpp > Modules/webgpu/NavigatorGPU.cpp > Modules/webgpu/WHLSL/WHLSLASTDumper.cpp >+Modules/webgpu/WHLSL/WHLSLAutoInitializeVariables.cpp > Modules/webgpu/WHLSL/WHLSLInferTypes.cpp > Modules/webgpu/WHLSL/WHLSLLexer.cpp > Modules/webgpu/WHLSL/WHLSLParser.cpp >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLASTDumper.h >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLASTDumper.h (revision 246269) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLASTDumper.h (working copy) >@@ -142,6 +142,7 @@ MAKE_PRINT_ADAPTOR(StatementDumper, AST: > MAKE_PRINT_ADAPTOR(ProgramDumper, Program&, dumpASTNode); > MAKE_PRINT_ADAPTOR(StructureDefinitionDumper, AST::StructureDefinition&, dumpASTNode); > MAKE_PRINT_ADAPTOR(FunctionDefinitionDumper, AST::FunctionDefinition&, dumpASTNode); >+MAKE_PRINT_ADAPTOR(TypeDumper, AST::UnnamedType&, dumpASTNode); > > > static ALWAYS_INLINE void dumpAST(Program& program) >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLAutoInitializeVariables.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLAutoInitializeVariables.cpp (nonexistent) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLAutoInitializeVariables.cpp (working copy) >@@ -0,0 +1,98 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "WHLSLAutoInitializeVariables.h" >+ >+#if ENABLE(WEBGPU) >+ >+#include "WHLSLAST.h" >+#include "WHLSLASTDumper.h" >+#include "WHLSLNameContext.h" >+#include "WHLSLResolveOverloadImpl.h" >+#include "WHLSLResolvingType.h" >+#include "WHLSLVisitor.h" >+#include <wtf/StringPrintStream.h> >+ >+namespace WebCore { >+ >+namespace WHLSL { >+ >+class AutoInitialize : public Visitor { >+ using Base = Visitor; >+public: >+ AutoInitialize(NameContext& nameContext) >+ : m_nameContext(nameContext) >+ , m_castFunctions(*m_nameContext.getFunctions("operator cast"_str)) >+ { } >+ >+private: >+ void visit(AST::FunctionDeclaration&) >+ { >+ // Skip argument declarations. >+ } >+ >+ void visit(AST::VariableDeclaration& variableDeclaration) >+ { >+ if (variableDeclaration.initializer()) >+ return; >+ >+ AST::UnnamedType* type = variableDeclaration.type(); >+ RELEASE_ASSERT(type); >+ >+#ifndef NDEBUG >+ StringPrintStream printStream; >+ printStream.print(TypeDumper(*type)); >+ String functionName = printStream.toString(); >+#else >+ String functionName = "<zero-init>"_s; >+#endif >+ auto callExpression = makeUniqueRef<AST::CallExpression>(variableDeclaration.origin(), WTFMove(functionName), Vector<UniqueRef<AST::Expression>>()); >+ callExpression->setType(type->clone()); >+ callExpression->setTypeAnnotation(AST::RightValue()); >+ callExpression->setOverloads(m_castFunctions); >+ Vector<std::reference_wrapper<ResolvingType>> argumentTypes; >+ auto* function = resolveFunctionOverload(*callExpression->overloads(), argumentTypes, type); >+ RELEASE_ASSERT(function); >+ callExpression->setFunction(*function); >+ >+ variableDeclaration.setInitializer(WTFMove(callExpression)); >+ } >+ >+ NameContext& m_nameContext; >+ Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>& m_castFunctions; >+}; >+ >+void autoInitializeVariables(Program& program) >+{ >+ AutoInitialize autoInitialize(program.nameContext()); >+ autoInitialize.Visitor::visit(program); >+} >+ >+} // namespace WHLSL >+ >+} // namespace WebCore >+ >+#endif // ENABLE(WEBGPU) >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLAutoInitializeVariables.h >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLAutoInitializeVariables.h (nonexistent) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLAutoInitializeVariables.h (working copy) >@@ -0,0 +1,42 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#pragma once >+ >+#if ENABLE(WEBGPU) >+ >+namespace WebCore { >+ >+namespace WHLSL { >+ >+class Program; >+ >+void autoInitializeVariables(Program&); >+ >+} >+ >+} >+ >+#endif >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLChecker.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLChecker.cpp (revision 246269) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLChecker.cpp (working copy) >@@ -357,7 +357,7 @@ static bool checkOperatorOverload(const > argumentTypes.append((*functionDefinition.parameters()[0]->type())->clone()); > for (auto& argumentType : argumentTypes) > argumentTypeReferences.append(argumentType); >- auto* overload = resolveFunctionOverloadImpl(*getterFuncs, argumentTypeReferences, nullptr); >+ auto* overload = resolveFunctionOverload(*getterFuncs, argumentTypeReferences); > if (!overload) > return false; > auto& resultType = overload->type(); >@@ -979,7 +979,7 @@ void Checker::visit(AST::DotExpression& > AST::UnnamedType* getterReturnType = nullptr; > { > Vector<std::reference_wrapper<ResolvingType>> getterArgumentTypes { baseInfo->resolvingType }; >- getterFunction = resolveFunctionOverloadImpl(dotExpression.possibleGetterOverloads(), getterArgumentTypes, nullptr); >+ getterFunction = resolveFunctionOverload(dotExpression.possibleGetterOverloads(), getterArgumentTypes); > if (getterFunction) > getterReturnType = &getterFunction->type(); > } >@@ -989,7 +989,7 @@ void Checker::visit(AST::DotExpression& > if (auto leftAddressSpace = baseInfo->typeAnnotation.leftAddressSpace()) { > auto argumentType = makeUniqueRef<AST::PointerType>(Lexer::Token(dotExpression.origin()), *leftAddressSpace, baseUnnamedType->get().clone()); > Vector<std::reference_wrapper<ResolvingType>> anderArgumentTypes { baseInfo->resolvingType }; >- anderFunction = resolveFunctionOverloadImpl(dotExpression.possibleAnderOverloads(), anderArgumentTypes, nullptr); >+ anderFunction = resolveFunctionOverload(dotExpression.possibleAnderOverloads(), anderArgumentTypes); > if (anderFunction) > anderReturnType = &downcast<AST::PointerType>(anderFunction->type()).elementType(); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198164 Enforce the return of anders will always be a pointer > } >@@ -999,7 +999,7 @@ void Checker::visit(AST::DotExpression& > { > auto argumentType = makeUniqueRef<AST::PointerType>(Lexer::Token(dotExpression.origin()), AST::AddressSpace::Thread, baseUnnamedType->get().clone()); > Vector<std::reference_wrapper<ResolvingType>> threadAnderArgumentTypes { baseInfo->resolvingType }; >- threadAnderFunction = resolveFunctionOverloadImpl(dotExpression.possibleAnderOverloads(), threadAnderArgumentTypes, nullptr); >+ threadAnderFunction = resolveFunctionOverload(dotExpression.possibleAnderOverloads(), threadAnderArgumentTypes); > if (threadAnderFunction) > threadAnderReturnType = &downcast<AST::PointerType>(threadAnderFunction->type()).elementType(); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=198164 Enforce the return of anders will always be a pointer > } >@@ -1024,7 +1024,7 @@ void Checker::visit(AST::DotExpression& > { > ResolvingType fieldResolvingType(fieldType->clone()); > Vector<std::reference_wrapper<ResolvingType>> setterArgumentTypes { baseInfo->resolvingType, fieldResolvingType }; >- setterFunction = resolveFunctionOverloadImpl(dotExpression.possibleSetterOverloads(), setterArgumentTypes, nullptr); >+ setterFunction = resolveFunctionOverload(dotExpression.possibleSetterOverloads(), setterArgumentTypes); > if (setterFunction) > setterReturnType = &setterFunction->type(); > } >@@ -1397,7 +1397,7 @@ void Checker::visit(AST::CallExpression& > // We don't want to recurse to the same node twice. > > ASSERT(callExpression.hasOverloads()); >- auto* function = resolveFunctionOverloadImpl(*callExpression.overloads(), types, callExpression.castReturnType()); >+ auto* function = resolveFunctionOverload(*callExpression.overloads(), types, callExpression.castReturnType()); > if (!function) { > if (auto newFunction = resolveByInstantiation(callExpression, types, m_intrinsics)) { > m_program.append(WTFMove(*newFunction)); >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLInferTypes.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLInferTypes.cpp (revision 246269) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLInferTypes.cpp (working copy) >@@ -221,7 +221,8 @@ bool inferTypesForTypeArguments(AST::Nam > return true; > } > >-bool inferTypesForCall(AST::FunctionDeclaration& possibleFunction, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes, const AST::NamedType* castReturnType) >+template <typename TypeKind> >+ALWAYS_INLINE bool inferTypesForCallImpl(AST::FunctionDeclaration& possibleFunction, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes, const TypeKind* castReturnType) > { > if (possibleFunction.parameters().size() != argumentTypes.size()) > return false; >@@ -239,6 +240,16 @@ bool inferTypesForCall(AST::FunctionDecl > return true; > } > >+bool inferTypesForCall(AST::FunctionDeclaration& possibleFunction, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes, const AST::NamedType* castReturnType) >+{ >+ return inferTypesForCallImpl(possibleFunction, argumentTypes, castReturnType); >+} >+ >+bool inferTypesForCall(AST::FunctionDeclaration& possibleFunction, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes, const AST::UnnamedType* castReturnType) >+{ >+ return inferTypesForCallImpl(possibleFunction, argumentTypes, castReturnType); >+} >+ > } // namespace WHLSL > > } // namespace WebCore >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLInferTypes.h >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLInferTypes.h (revision 246269) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLInferTypes.h (working copy) >@@ -54,6 +54,7 @@ Optional<UniqueRef<AST::UnnamedType>> ma > Optional<UniqueRef<AST::UnnamedType>> commit(AST::ResolvableType&); > bool inferTypesForTypeArguments(AST::NamedType& possibleType, AST::TypeArguments&); > bool inferTypesForCall(AST::FunctionDeclaration& possibleFunction, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes, const AST::NamedType* castReturnType); >+bool inferTypesForCall(AST::FunctionDeclaration& possibleFunction, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes, const AST::UnnamedType* castReturnType); > > } > >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.cpp (revision 246269) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLPrepare.cpp (working copy) >@@ -29,6 +29,7 @@ > #if ENABLE(WEBGPU) > > #include "WHLSLASTDumper.h" >+#include "WHLSLAutoInitializeVariables.h" > #include "WHLSLCheckDuplicateFunctions.h" > #include "WHLSLChecker.h" > #include "WHLSLFunctionStageChecker.h" >@@ -58,7 +59,7 @@ namespace WHLSL { > static constexpr bool dumpASTBeforeEachPass = false; > static constexpr bool dumpASTAfterParsing = false; > static constexpr bool dumpASTAtEnd = false; >-static constexpr bool alwaysDumpPassFailures = true; >+static constexpr bool alwaysDumpPassFailures = false; > static constexpr bool dumpPassFailure = dumpASTBeforeEachPass || dumpASTAfterParsing || dumpASTAtEnd || alwaysDumpPassFailures; > > static bool dumpASTIfNeeded(bool shouldDump, Program& program, const char* message) >@@ -130,6 +131,7 @@ static Optional<Program> prepareShared(S > RUN_PASS(check, program); > > checkLiteralTypes(program); >+ autoInitializeVariables(program); > resolveProperties(program); > findHighZombies(program); > RUN_PASS(checkStatementBehavior, program); >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLResolveOverloadImpl.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLResolveOverloadImpl.cpp (revision 246269) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLResolveOverloadImpl.cpp (working copy) >@@ -51,7 +51,8 @@ static unsigned conversionCost(AST::Func > return conversionCost; > } > >-AST::FunctionDeclaration* resolveFunctionOverloadImpl(Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>& possibleFunctions, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes, AST::NamedType* castReturnType) >+template <typename TypeKind> >+AST::FunctionDeclaration* resolveFunctionOverloadImpl(Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>& possibleFunctions, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes, TypeKind* castReturnType) > { > Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1> candidates; > for (auto& possibleFunction : possibleFunctions) { >@@ -76,6 +77,21 @@ AST::FunctionDeclaration* resolveFunctio > return nullptr; > } > >+AST::FunctionDeclaration* resolveFunctionOverload(Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>& possibleFunctions, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes) >+{ >+ return resolveFunctionOverloadImpl(possibleFunctions, argumentTypes, static_cast<AST::NamedType*>(nullptr)); >+} >+ >+AST::FunctionDeclaration* resolveFunctionOverload(Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>& possibleFunctions, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes, AST::NamedType* castReturnType) >+{ >+ return resolveFunctionOverloadImpl(possibleFunctions, argumentTypes, castReturnType); >+} >+ >+AST::FunctionDeclaration* resolveFunctionOverload(Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>& possibleFunctions, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes, AST::UnnamedType* castReturnType) >+{ >+ return resolveFunctionOverloadImpl(possibleFunctions, argumentTypes, castReturnType); >+} >+ > AST::NamedType* resolveTypeOverloadImpl(Vector<std::reference_wrapper<AST::NamedType>, 1>& possibleTypes, AST::TypeArguments& typeArguments) > { > AST::NamedType* result = nullptr; >Index: Source/WebCore/Modules/webgpu/WHLSL/WHLSLResolveOverloadImpl.h >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/WHLSLResolveOverloadImpl.h (revision 246269) >+++ Source/WebCore/Modules/webgpu/WHLSL/WHLSLResolveOverloadImpl.h (working copy) >@@ -43,7 +43,9 @@ class NamedType; > > } > >-AST::FunctionDeclaration* resolveFunctionOverloadImpl(Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>& possibleFunctions, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes, AST::NamedType* castReturnType); >+AST::FunctionDeclaration* resolveFunctionOverload(Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>& possibleFunctions, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes); >+AST::FunctionDeclaration* resolveFunctionOverload(Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>& possibleFunctions, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes, AST::NamedType* castReturnType); >+AST::FunctionDeclaration* resolveFunctionOverload(Vector<std::reference_wrapper<AST::FunctionDeclaration>, 1>& possibleFunctions, Vector<std::reference_wrapper<ResolvingType>>& argumentTypes, AST::UnnamedType* castReturnType); > AST::NamedType* resolveTypeOverloadImpl(Vector<std::reference_wrapper<AST::NamedType>, 1>&, AST::TypeArguments&); > > } >Index: Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLVariableDeclaration.h >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLVariableDeclaration.h (revision 246269) >+++ Source/WebCore/Modules/webgpu/WHLSL/AST/WHLSLVariableDeclaration.h (working copy) >@@ -70,6 +70,11 @@ public: > Expression* initializer() { return m_initializer ? &*m_initializer : nullptr; } > bool isAnonymous() const { return m_name.isNull(); } > Optional<UniqueRef<Expression>> takeInitializer() { return WTFMove(m_initializer); } >+ void setInitializer(UniqueRef<Expression> expression) >+ { >+ ASSERT(!initializer()); >+ m_initializer = WTFMove(expression); >+ } > > private: > Qualifiers m_qualifiers; >Index: Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp (revision 246269) >+++ Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp (working copy) >@@ -477,10 +477,8 @@ void FunctionDefinitionWriter::visit(AST > if (variableDeclaration.initializer()) { > checkErrorAndVisit(*variableDeclaration.initializer()); > m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(*variableDeclaration.type()), ' ', variableName, " = ", m_stack.takeLast(), ";\n")); >- } else { >- // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195771 Zero-fill the variable. >+ } else > m_stringBuilder.append(makeString(m_typeNamer.mangledNameForType(*variableDeclaration.type()), ' ', variableName, ";\n")); >- } > } > > void FunctionDefinitionWriter::visit(AST::AssignmentExpression& assignmentExpression) >Index: Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp >=================================================================== >--- Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp (revision 246269) >+++ Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp (working copy) >@@ -104,7 +104,8 @@ String writeNativeFunction(AST::NativeFu > if (!nativeFunctionDeclaration.parameters().size()) { > stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, "() {\n")); > stringBuilder.append(makeString(" ", metalReturnName, " x;\n")); >- // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195771 Zero-fill >+ 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(" return x;\n"); > stringBuilder.append("}\n"); > return stringBuilder.toString(); >Index: Source/WebCore/WebCore.xcodeproj/project.pbxproj >=================================================================== >--- Source/WebCore/WebCore.xcodeproj/project.pbxproj (revision 246269) >+++ Source/WebCore/WebCore.xcodeproj/project.pbxproj (working copy) >@@ -8347,6 +8347,8 @@ > 52B0D4BD1C57FD1E0077CE53 /* PlatformView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformView.h; sourceTree = "<group>"; }; > 52B0D4BF1C57FD660077CE53 /* VideoFullscreenChangeObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoFullscreenChangeObserver.h; sourceTree = "<group>"; }; > 52B0D4C11C57FF910077CE53 /* VideoFullscreenInterfaceMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoFullscreenInterfaceMac.h; sourceTree = "<group>"; }; >+ 52B3434922A0752200E49389 /* WHLSLAutoInitializeVariables.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WHLSLAutoInitializeVariables.h; sourceTree = "<group>"; }; >+ 52B3434B22A0752300E49389 /* WHLSLAutoInitializeVariables.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WHLSLAutoInitializeVariables.cpp; sourceTree = "<group>"; }; > 52D5A18D1C54590300DE34A3 /* VideoFullscreenLayerManagerObjC.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = VideoFullscreenLayerManagerObjC.mm; sourceTree = "<group>"; }; > 52D5A18E1C54590300DE34A3 /* VideoFullscreenLayerManagerObjC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoFullscreenLayerManagerObjC.h; sourceTree = "<group>"; }; > 52D5A1A41C57488900DE34A3 /* VideoFullscreenModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoFullscreenModel.h; sourceTree = "<group>"; }; >@@ -25440,6 +25442,8 @@ > 1CECB3AD21F2B96400F44542 /* Metal */, > C20F88AA22966B0E00D610FA /* WHLSLASTDumper.cpp */, > C20F88AC22966B0F00D610FA /* WHLSLASTDumper.h */, >+ 52B3434B22A0752300E49389 /* WHLSLAutoInitializeVariables.cpp */, >+ 52B3434922A0752200E49389 /* WHLSLAutoInitializeVariables.h */, > C234A9B221E92C1F003C984D /* WHLSLCheckDuplicateFunctions.cpp */, > C234A9AE21E92C1A003C984D /* WHLSLCheckDuplicateFunctions.h */, > 1C840B9B21EC400900D0500D /* WHLSLChecker.cpp */, >Index: LayoutTests/ChangeLog >=================================================================== >--- LayoutTests/ChangeLog (revision 246269) >+++ LayoutTests/ChangeLog (working copy) >@@ -1,3 +1,15 @@ >+2019-06-10 Saam Barati <sbarati@apple.com> >+ >+ [WHLSL] Auto initialize local variables >+ https://bugs.webkit.org/show_bug.cgi?id=198426 >+ >+ Reviewed by Myles Maxfield. >+ >+ * webgpu/whlsl-zero-initialize-values-2-expected.html: Added. >+ * webgpu/whlsl-zero-initialize-values-2.html: Added. >+ * webgpu/whlsl-zero-initialize-values-expected.html: Added. >+ * webgpu/whlsl-zero-initialize-values.html: Added. >+ > 2019-06-10 Youenn Fablet <youenn@apple.com> > > Call was negotiated with H264 Base Profile 42e01f but encoded in High Profile >Index: LayoutTests/webgpu/whlsl-zero-initialize-values-2-expected.html >=================================================================== >--- LayoutTests/webgpu/whlsl-zero-initialize-values-2-expected.html (nonexistent) >+++ LayoutTests/webgpu/whlsl-zero-initialize-values-2-expected.html (working copy) >@@ -0,0 +1,19 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+async function start() { >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("2d"); >+ context.fillStyle = "blue"; >+ context.fillRect(0, 0, 400, 400); >+ context.fillStyle = "black"; >+ context.fillRect(100, 100, 200, 200); >+} >+window.addEventListener("load", start); >+</script> >+</body> >+</html> >Index: LayoutTests/webgpu/whlsl-zero-initialize-values-2.html >=================================================================== >--- LayoutTests/webgpu/whlsl-zero-initialize-values-2.html (nonexistent) >+++ LayoutTests/webgpu/whlsl-zero-initialize-values-2.html (working copy) >@@ -0,0 +1,152 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+const shaderSource = ` >+struct VertexOut { >+ float4 position : SV_Position; >+ float shade : attribute(0); >+} >+ >+struct Bar { >+ float y; >+ float y1; >+ float y2; >+ float y3; >+ float y4; >+ float y5; >+ float y6; >+ float y7; >+ float y8; >+ float y9; >+ float y10; >+ float y11; >+ float y12; >+ float y13; >+ float y14; >+ float y15; >+ float y16; >+ float y17; >+ float y18; >+ float y19; >+ float y20; >+} >+ >+vertex VertexOut vertexShader(float4 position : attribute(0), float shade : attribute(1)) { >+ VertexOut result; >+ >+ Bar bar; >+ >+ result.position = position; >+ result.shade = bar.y20; >+ >+ return result; >+} >+ >+fragment float4 fragmentShader(float shade : attribute(0)) : SV_Target 0 { >+ return float4(shade, shade, shade, 1.0); >+} >+`; >+async function start() { >+ const adapter = await navigator.gpu.requestAdapter(); >+ const device = await adapter.requestDevice(); >+ >+ const shaderModule = device.createShaderModule({code: shaderSource, isWHLSL: true}); >+ const vertexStage = {module: shaderModule, entryPoint: "vertexShader"}; >+ const fragmentStage = {module: shaderModule, entryPoint: "fragmentShader"}; >+ const primitiveTopology = "triangle-strip"; >+ const rasterizationState = {frontFace: "cw", cullMode: "none"}; >+ const alphaBlend = {}; >+ const colorBlend = {}; >+ const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL >+ const depthStencilState = null; >+ >+ const attribute0 = {shaderLocation: 0, format: "float4", offset: 0}; >+ const attribute1 = {shaderLocation: 1, format: "float", offset: 16}; >+ const attributes = [attribute0, attribute1]; >+ const input0 = {stride: 20, attributeSet: attributes}; >+ const inputs = [input0]; >+ const vertexInput = {vertexBuffers: inputs}; >+ >+ const bindGroupLayoutDescriptor = {bindings: [{binding: 0, visibility: 7, type: "uniform-buffer"}]}; >+ const bindGroupLayout = device.createBindGroupLayout(bindGroupLayoutDescriptor); >+ const pipelineLayoutDescriptor = {bindGroupLayouts: [bindGroupLayout]}; >+ const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor); >+ >+ const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout}; >+ const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor); >+ >+ const vertexBuffer0Descriptor = {size: Float32Array.BYTES_PER_ELEMENT * 5 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE}; >+ const vertexBuffer0 = device.createBuffer(vertexBuffer0Descriptor); >+ const vertexBuffer0ArrayBuffer = await vertexBuffer0.mapWriteAsync(); >+ const vertexBuffer0Float32Array = new Float32Array(vertexBuffer0ArrayBuffer); >+ vertexBuffer0Float32Array[0] = -0.5; >+ vertexBuffer0Float32Array[1] = -0.5; >+ vertexBuffer0Float32Array[2] = 1.0; >+ vertexBuffer0Float32Array[3] = 1.0; >+ vertexBuffer0Float32Array[4] = 1.0; >+ >+ vertexBuffer0Float32Array[5] = -0.5; >+ vertexBuffer0Float32Array[6] = 0.5; >+ vertexBuffer0Float32Array[7] = 1.0; >+ vertexBuffer0Float32Array[8] = 1.0; >+ vertexBuffer0Float32Array[9] = 1.0; >+ >+ vertexBuffer0Float32Array[10] = 0.5; >+ vertexBuffer0Float32Array[11] = -0.5; >+ vertexBuffer0Float32Array[12] = 1.0; >+ vertexBuffer0Float32Array[13] = 1.0; >+ vertexBuffer0Float32Array[14] = 1.0; >+ >+ vertexBuffer0Float32Array[15] = 0.5; >+ vertexBuffer0Float32Array[16] = 0.5; >+ vertexBuffer0Float32Array[17] = 1.0; >+ vertexBuffer0Float32Array[18] = 1.0; >+ vertexBuffer0Float32Array[19] = 1.0; >+ vertexBuffer0.unmap(); >+ >+ const resourceBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.MAP_WRITE}; >+ const resourceBuffer = device.createBuffer(resourceBufferDescriptor); >+ const resourceBufferArrayBuffer = await resourceBuffer.mapWriteAsync(); >+ const resourceBufferFloat32Array = new Float32Array(resourceBufferArrayBuffer); >+ resourceBufferFloat32Array[0] = 1; >+ resourceBuffer.unmap(); >+ >+ const bufferBinding = {buffer: resourceBuffer, size: 4}; >+ const bindGroupBinding = {binding: 0, resource: bufferBinding}; >+ const bindGroupDescriptor = {layout: bindGroupLayout, bindings: [bindGroupBinding]}; >+ const bindGroup = device.createBindGroup(bindGroupDescriptor); >+ >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("gpu"); >+ const swapChainDescriptor = {device, format: "bgra8unorm"}; >+ const swapChain = context.configureSwapChain(swapChainDescriptor); >+ const outputTexture = swapChain.getCurrentTexture(); >+ const outputTextureView = outputTexture.createDefaultView(); >+ >+ const commandEncoder = device.createCommandEncoder(); // {} >+ const red = {r: 0, g: 0, b: 1, a: 1}; >+ const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}]; >+ const depthStencilAttachment = null; >+ const renderPassDescriptor = {colorAttachments, depthStencilAttachment}; >+ const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor); >+ renderPassEncoder.setPipeline(renderPipeline); >+ renderPassEncoder.setBindGroup(0, bindGroup); >+ renderPassEncoder.setVertexBuffers(0, [vertexBuffer0], [0]); >+ renderPassEncoder.draw(4, 1, 0, 0); >+ renderPassEncoder.endPass(); >+ const commandBuffer = commandEncoder.finish(); >+ device.getQueue().submit([commandBuffer]); >+ >+ if (window.testRunner) >+ testRunner.notifyDone(); >+} >+if (window.testRunner) >+ testRunner.waitUntilDone(); >+window.addEventListener("load", start); >+</script> >+</body> >+</html> >Index: LayoutTests/webgpu/whlsl-zero-initialize-values-expected.html >=================================================================== >--- LayoutTests/webgpu/whlsl-zero-initialize-values-expected.html (nonexistent) >+++ LayoutTests/webgpu/whlsl-zero-initialize-values-expected.html (working copy) >@@ -0,0 +1,19 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+async function start() { >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("2d"); >+ context.fillStyle = "blue"; >+ context.fillRect(0, 0, 400, 400); >+ context.fillStyle = "black"; >+ context.fillRect(100, 100, 200, 200); >+} >+window.addEventListener("load", start); >+</script> >+</body> >+</html> >Index: LayoutTests/webgpu/whlsl-zero-initialize-values.html >=================================================================== >--- LayoutTests/webgpu/whlsl-zero-initialize-values.html (nonexistent) >+++ LayoutTests/webgpu/whlsl-zero-initialize-values.html (working copy) >@@ -0,0 +1,135 @@ >+<!DOCTYPE html> >+<html> >+<head> >+</head> >+<body> >+<canvas id="canvas" width="400" height="400"></canvas> >+<script> >+const shaderSource = ` >+struct VertexOut { >+ float4 position : SV_Position; >+ float shade : attribute(0); >+} >+ >+thread float* ptr() { >+ float local; >+ return &local; >+} >+ >+vertex VertexOut vertexShader(float4 position : attribute(0), float shade : attribute(1)) { >+ VertexOut result; >+ >+ thread float* p = ptr(); >+ *p = 1.0; >+ float value = *ptr(); // calling ptr() zero initializes. >+ >+ result.position = position; >+ result.shade = value; >+ >+ return result; >+} >+ >+fragment float4 fragmentShader(float shade : attribute(0)) : SV_Target 0 { >+ return float4(shade, shade, shade, 1.0); >+} >+`; >+async function start() { >+ const adapter = await navigator.gpu.requestAdapter(); >+ const device = await adapter.requestDevice(); >+ >+ const shaderModule = device.createShaderModule({code: shaderSource, isWHLSL: true}); >+ const vertexStage = {module: shaderModule, entryPoint: "vertexShader"}; >+ const fragmentStage = {module: shaderModule, entryPoint: "fragmentShader"}; >+ const primitiveTopology = "triangle-strip"; >+ const rasterizationState = {frontFace: "cw", cullMode: "none"}; >+ const alphaBlend = {}; >+ const colorBlend = {}; >+ const colorStates = [{format: "rgba8unorm", alphaBlend, colorBlend, writeMask: 15}]; // GPUColorWriteBits.ALL >+ const depthStencilState = null; >+ >+ const attribute0 = {shaderLocation: 0, format: "float4", offset: 0}; >+ const attribute1 = {shaderLocation: 1, format: "float", offset: 16}; >+ const attributes = [attribute0, attribute1]; >+ const input0 = {stride: 20, attributeSet: attributes}; >+ const inputs = [input0]; >+ const vertexInput = {vertexBuffers: inputs}; >+ >+ const bindGroupLayoutDescriptor = {bindings: [{binding: 0, visibility: 7, type: "uniform-buffer"}]}; >+ const bindGroupLayout = device.createBindGroupLayout(bindGroupLayoutDescriptor); >+ const pipelineLayoutDescriptor = {bindGroupLayouts: [bindGroupLayout]}; >+ const pipelineLayout = device.createPipelineLayout(pipelineLayoutDescriptor); >+ >+ const renderPipelineDescriptor = {vertexStage, fragmentStage, primitiveTopology, rasterizationState, colorStates, depthStencilState, vertexInput, sampleCount: 1, layout: pipelineLayout}; >+ const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor); >+ >+ const vertexBuffer0Descriptor = {size: Float32Array.BYTES_PER_ELEMENT * 5 * 4, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE}; >+ const vertexBuffer0 = device.createBuffer(vertexBuffer0Descriptor); >+ const vertexBuffer0ArrayBuffer = await vertexBuffer0.mapWriteAsync(); >+ const vertexBuffer0Float32Array = new Float32Array(vertexBuffer0ArrayBuffer); >+ vertexBuffer0Float32Array[0] = -0.5; >+ vertexBuffer0Float32Array[1] = -0.5; >+ vertexBuffer0Float32Array[2] = 1.0; >+ vertexBuffer0Float32Array[3] = 1.0; >+ vertexBuffer0Float32Array[4] = 1.0; >+ >+ vertexBuffer0Float32Array[5] = -0.5; >+ vertexBuffer0Float32Array[6] = 0.5; >+ vertexBuffer0Float32Array[7] = 1.0; >+ vertexBuffer0Float32Array[8] = 1.0; >+ vertexBuffer0Float32Array[9] = 1.0; >+ >+ vertexBuffer0Float32Array[10] = 0.5; >+ vertexBuffer0Float32Array[11] = -0.5; >+ vertexBuffer0Float32Array[12] = 1.0; >+ vertexBuffer0Float32Array[13] = 1.0; >+ vertexBuffer0Float32Array[14] = 1.0; >+ >+ vertexBuffer0Float32Array[15] = 0.5; >+ vertexBuffer0Float32Array[16] = 0.5; >+ vertexBuffer0Float32Array[17] = 1.0; >+ vertexBuffer0Float32Array[18] = 1.0; >+ vertexBuffer0Float32Array[19] = 1.0; >+ vertexBuffer0.unmap(); >+ >+ const resourceBufferDescriptor = {size: Float32Array.BYTES_PER_ELEMENT, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.MAP_WRITE}; >+ const resourceBuffer = device.createBuffer(resourceBufferDescriptor); >+ const resourceBufferArrayBuffer = await resourceBuffer.mapWriteAsync(); >+ const resourceBufferFloat32Array = new Float32Array(resourceBufferArrayBuffer); >+ resourceBufferFloat32Array[0] = 1; >+ resourceBuffer.unmap(); >+ >+ const bufferBinding = {buffer: resourceBuffer, size: 4}; >+ const bindGroupBinding = {binding: 0, resource: bufferBinding}; >+ const bindGroupDescriptor = {layout: bindGroupLayout, bindings: [bindGroupBinding]}; >+ const bindGroup = device.createBindGroup(bindGroupDescriptor); >+ >+ const canvas = document.getElementById("canvas"); >+ const context = canvas.getContext("gpu"); >+ const swapChainDescriptor = {device, format: "bgra8unorm"}; >+ const swapChain = context.configureSwapChain(swapChainDescriptor); >+ const outputTexture = swapChain.getCurrentTexture(); >+ const outputTextureView = outputTexture.createDefaultView(); >+ >+ const commandEncoder = device.createCommandEncoder(); // {} >+ const red = {r: 0, g: 0, b: 1, a: 1}; >+ const colorAttachments = [{attachment: outputTextureView, resolveTarget: null, loadOp: "clear", storeOp: "store", clearColor: red}]; >+ const depthStencilAttachment = null; >+ const renderPassDescriptor = {colorAttachments, depthStencilAttachment}; >+ const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor); >+ renderPassEncoder.setPipeline(renderPipeline); >+ renderPassEncoder.setBindGroup(0, bindGroup); >+ renderPassEncoder.setVertexBuffers(0, [vertexBuffer0], [0]); >+ renderPassEncoder.draw(4, 1, 0, 0); >+ renderPassEncoder.endPass(); >+ const commandBuffer = commandEncoder.finish(); >+ device.getQueue().submit([commandBuffer]); >+ >+ if (window.testRunner) >+ testRunner.notifyDone(); >+} >+if (window.testRunner) >+ testRunner.waitUntilDone(); >+window.addEventListener("load", start); >+</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
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 198426
:
371069
|
371767
| 371768