Diff
Modified: trunk/Tools/ChangeLog (222117 => 222118)
--- trunk/Tools/ChangeLog 2017-09-15 23:44:45 UTC (rev 222117)
+++ trunk/Tools/ChangeLog 2017-09-15 23:48:18 UTC (rev 222118)
@@ -1,3 +1,96 @@
+2017-09-15 Filip Pizlo <[email protected]>
+
+ WSL Evaluator should only allocate EBuffers when dealing with intrinsics
+ https://bugs.webkit.org/show_bug.cgi?id=176973
+
+ Reviewed by Myles Maxfield.
+
+ Whether or not two temporary values share the same EBuffer is ultimately observable in WSL,
+ because you can do this:
+
+ thread int^ operator&[](thread int^ ptr, uint index)
+ {
+ g_ptr = ptr;
+ return ptr;
+ }
+
+ And then this is a thing:
+
+ 42[0];
+ // g_ptr now points to 42's location
+
+ Normally this would have a lot of bad implications. But in WSL, if you did choose to do this,
+ you'd get a pointer to something well-defined: the EBuffer of 42's GenericLiteral. Each static
+ occurrence of a literal gets its own location, and the semantics of the language call for
+ 42 to be stored into this location when `42` "executes". So, while the programmer could do all
+ kinds of strange things, at least the strangeness they would see is something we can spec.
+
+ But to do this, the interpreter needs to allocate EBuffers in the same way a compiler would.
+ It cannot allocate them during execution, except when interacting with intrinsics, which won't
+ know the difference.
+
+ In the process, I found places that needed to use AutoWrapper instead of TypeRef.wrap.
+
+ * WebGPUShadingLanguageRI/AutoWrapper.js:
+ (AutoWrapper.prototype.visitGenericLiteralType):
+ (AutoWrapper.prototype.visitNullType):
+ (AutoWrapper):
+ * WebGPUShadingLanguageRI/CallExpression.js:
+ (CallExpression.prototype.resolve):
+ * WebGPUShadingLanguageRI/CallFunction.js:
+ (callFunction):
+ * WebGPUShadingLanguageRI/Checker.js:
+ * WebGPUShadingLanguageRI/CreateLiteralType.js:
+ (createLiteralType.GenericLiteralType.prototype.commitUnification):
+ * WebGPUShadingLanguageRI/EBuffer.js:
+ (EBuffer):
+ (EBuffer.setCanAllocateEBuffers):
+ (EBuffer.disallowAllocation):
+ (EBuffer.allowAllocation):
+ * WebGPUShadingLanguageRI/EBufferBuilder.js:
+ (EBufferBuilder.prototype.visitVariableDecl):
+ (EBufferBuilder.prototype.visitFuncDef):
+ (EBufferBuilder.prototype.visitFunctionLikeBlock):
+ (EBufferBuilder.prototype.visitCallExpression):
+ (EBufferBuilder.prototype.visitMakePtrExpression):
+ (EBufferBuilder.prototype.visitGenericLiteral):
+ (EBufferBuilder.prototype.visitNullLiteral):
+ (EBufferBuilder.prototype.visitBoolLiteral):
+ (EBufferBuilder.prototype.visitLogicalNot):
+ (EBufferBuilder):
+ * WebGPUShadingLanguageRI/EPtr.js:
+ (EPtr.box):
+ (EPtr.prototype.box):
+ * WebGPUShadingLanguageRI/Evaluator.js:
+ (Evaluator.prototype._snapshot):
+ (Evaluator.prototype.runFunc):
+ (Evaluator.prototype._runBody):
+ (Evaluator.prototype.visitFunctionLikeBlock):
+ (Evaluator.prototype.visitMakePtrExpression):
+ (Evaluator.prototype.visitGenericLiteral):
+ (Evaluator.prototype.visitNullLiteral):
+ (Evaluator.prototype.visitBoolLiteral):
+ (Evaluator.prototype.visitLogicalNot):
+ (Evaluator.prototype.visitCallExpression):
+ (Evaluator):
+ (Evaluator.prototype.runBody): Deleted.
+ * WebGPUShadingLanguageRI/Inliner.js:
+ (Inliner.prototype.visitCallExpression):
+ * WebGPUShadingLanguageRI/InstantiateImmediates.js:
+ (InstantiateImmediates.prototype.visitTypeRef):
+ * WebGPUShadingLanguageRI/Rewriter.js:
+ (Rewriter.prototype.visitMakePtrExpression):
+ (Rewriter.prototype.visitGenericLiteral):
+ (Rewriter.prototype.visitNullLiteral):
+ (Rewriter.prototype.processDerivedCallData):
+ (Rewriter.prototype.visitFunctionLikeBlock):
+ (Rewriter.prototype.visitLogicalNot):
+ * WebGPUShadingLanguageRI/TypeRef.js:
+ (TypeRef.prototype.toString):
+ (TypeRef):
+ * WebGPUShadingLanguageRI/Visitor.js:
+ (Visitor.prototype.visitProtocolDecl):
+
2017-09-14 Filip Pizlo <[email protected]>
Rationalize how WSL's operator&[] works
Modified: trunk/Tools/WebGPUShadingLanguageRI/AutoWrapper.js (222117 => 222118)
--- trunk/Tools/WebGPUShadingLanguageRI/AutoWrapper.js 2017-09-15 23:44:45 UTC (rev 222117)
+++ trunk/Tools/WebGPUShadingLanguageRI/AutoWrapper.js 2017-09-15 23:48:18 UTC (rev 222118)
@@ -64,4 +64,14 @@
{
return TypeRef.wrap(node);
}
+
+ visitGenericLiteralType(node)
+ {
+ return node;
+ }
+
+ visitNullType(node)
+ {
+ return node;
+ }
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/CallExpression.js (222117 => 222118)
--- trunk/Tools/WebGPUShadingLanguageRI/CallExpression.js 2017-09-15 23:44:45 UTC (rev 222117)
+++ trunk/Tools/WebGPUShadingLanguageRI/CallExpression.js 2017-09-15 23:48:18 UTC (rev 222118)
@@ -45,9 +45,10 @@
resolve(overload)
{
this.func = overload.func;
- this.actualTypeArguments = overload.typeArguments.map(typeArgument => typeArgument instanceof Type ? TypeRef.wrap(typeArgument) : typeArgument);
+ this.actualTypeArguments = overload.typeArguments.map(typeArgument => typeArgument instanceof Type ? typeArgument.visit(new AutoWrapper()) : typeArgument);
let result = overload.func.returnType.substituteToUnification(
overload.func.typeParameters, overload.unificationContext);
+ this.resultType = result.visit(new AutoWrapper());
if (!result)
throw new Error("Null return type");
return result;
Modified: trunk/Tools/WebGPUShadingLanguageRI/CallFunction.js (222117 => 222118)
--- trunk/Tools/WebGPUShadingLanguageRI/CallFunction.js 2017-09-15 23:44:45 UTC (rev 222117)
+++ trunk/Tools/WebGPUShadingLanguageRI/CallFunction.js 2017-09-15 23:48:18 UTC (rev 222118)
@@ -39,7 +39,7 @@
type.visit(new StructLayoutBuilder());
func.parameters[i].ePtr.copyFrom(argumentList[i].ePtr, type.size);
}
- let result = new Evaluator(program).runBody(func.returnType, func.body);
+ let result = new Evaluator(program).runFunc(func);
return new TypedValue(func.returnType.unifyNode, result);
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/Checker.js (222117 => 222118)
--- trunk/Tools/WebGPUShadingLanguageRI/Checker.js 2017-09-15 23:44:45 UTC (rev 222117)
+++ trunk/Tools/WebGPUShadingLanguageRI/Checker.js 2017-09-15 23:48:18 UTC (rev 222118)
@@ -193,7 +193,7 @@
{
let structType = node.struct.visit(this).unifyNode;
- node.structType = TypeRef.wrap(structType);
+ node.structType = structType.visit(new AutoWrapper());
let underlyingStruct = structType;
@@ -330,7 +330,7 @@
let newArgument = argument.visit(this);
if (!newArgument)
throw new Error("visitor returned null for " + argument);
- return TypeRef.wrap(newArgument);
+ return newArgument.visit(new AutoWrapper());
});
// Here we need to handle the cases where operator&[] is called with a type that isn't sufficiently
Modified: trunk/Tools/WebGPUShadingLanguageRI/CreateLiteralType.js (222117 => 222118)
--- trunk/Tools/WebGPUShadingLanguageRI/CreateLiteralType.js 2017-09-15 23:44:45 UTC (rev 222117)
+++ trunk/Tools/WebGPUShadingLanguageRI/CreateLiteralType.js 2017-09-15 23:48:18 UTC (rev 222118)
@@ -87,7 +87,7 @@
commitUnification(unificationContext)
{
- this.type = TypeRef.wrap(unificationContext.find(this));
+ this.type = unificationContext.find(this).visit(new AutoWrapper());
}
toString()
Modified: trunk/Tools/WebGPUShadingLanguageRI/EBuffer.js (222117 => 222118)
--- trunk/Tools/WebGPUShadingLanguageRI/EBuffer.js 2017-09-15 23:44:45 UTC (rev 222117)
+++ trunk/Tools/WebGPUShadingLanguageRI/EBuffer.js 2017-09-15 23:48:18 UTC (rev 222118)
@@ -25,14 +25,38 @@
"use strict";
let eBufferCount = 0;
+let canAllocateEBuffers = true;
class EBuffer {
constructor(size)
{
+ if (!canAllocateEBuffers)
+ throw new Error("Trying to allocate EBuffer while allocation is disallowed");
this._index = eBufferCount++;
this._array = new Array(size);
}
+ static setCanAllocateEBuffers(value, callback)
+ {
+ let oldCanAllocateEBuffers = canAllocateEBuffers;
+ canAllocateEBuffers = value;
+ try {
+ return callback();
+ } finally {
+ canAllocateEBuffers = oldCanAllocateEBuffers;
+ }
+ }
+
+ static disallowAllocation(callback)
+ {
+ return EBuffer.setCanAllocateEBuffers(false, callback);
+ }
+
+ static allowAllocation(callback)
+ {
+ return EBuffer.setCanAllocateEBuffers(true, callback);
+ }
+
get(index)
{
if (index < 0 || index >= this._array.length)
Modified: trunk/Tools/WebGPUShadingLanguageRI/EBufferBuilder.js (222117 => 222118)
--- trunk/Tools/WebGPUShadingLanguageRI/EBufferBuilder.js 2017-09-15 23:44:45 UTC (rev 222117)
+++ trunk/Tools/WebGPUShadingLanguageRI/EBufferBuilder.js 2017-09-15 23:48:18 UTC (rev 222118)
@@ -59,6 +59,51 @@
node.initializer.visit(this);
}
+ visitFuncDef(node)
+ {
+ node.returnEPtr = this._createEPtr(node.returnType);
+ super.visitFuncDef(node);
+ }
+
+ visitFunctionLikeBlock(node)
+ {
+ node.returnEPtr = this._createEPtr(node.returnType);
+ super.visitFunctionLikeBlock(node);
+ }
+
+ visitCallExpression(node)
+ {
+ node.resultEPtr = this._createEPtr(node.resultType);
+ super.visitCallExpression(node);
+ }
+
+ visitMakePtrExpression(node)
+ {
+ node.ePtr = EPtr.box();
+ super.visitMakePtrExpression(node);
+ }
+
+ visitGenericLiteral(node)
+ {
+ node.ePtr = EPtr.box();
+ }
+
+ visitNullLiteral(node)
+ {
+ node.ePtr = EPtr.box();
+ }
+
+ visitBoolLiteral(node)
+ {
+ node.ePtr = EPtr.box();
+ }
+
+ visitLogicalNot(node)
+ {
+ node.ePtr = EPtr.box();
+ super.visitLogicalNot(node);
+ }
+
visitLetExpression(node)
{
this._createEPtrForNode(node);
@@ -65,5 +110,17 @@
node.argument.visit(this);
node.body.visit(this);
}
+
+ visitMakeArrayRefExpression(node)
+ {
+ node.ePtr = EPtr.box();
+ super.visitMakeArrayRefExpression(node);
+ }
+
+ visitConvertPtrToArrayRefExpression(node)
+ {
+ node.ePtr = EPtr.box();
+ super.visitConvertPtrToArrayRefExpression(node);
+ }
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/EPtr.js (222117 => 222118)
--- trunk/Tools/WebGPUShadingLanguageRI/EPtr.js 2017-09-15 23:44:45 UTC (rev 222117)
+++ trunk/Tools/WebGPUShadingLanguageRI/EPtr.js 2017-09-15 23:48:18 UTC (rev 222118)
@@ -38,11 +38,15 @@
// In a real execution environment, uses of this manifest as SSA temporaries.
static box(value)
{
- let buffer = new EBuffer(1);
- buffer.set(0, value);
- return new EPtr(buffer, 0);
+ return new EPtr(new EBuffer(1), 0).box(value);
}
+ box(value)
+ {
+ this._buffer.set(0, value);
+ return this;
+ }
+
get buffer() { return this._buffer; }
get offset() { return this._offset; }
Modified: trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js (222117 => 222118)
--- trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js 2017-09-15 23:44:45 UTC (rev 222117)
+++ trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js 2017-09-15 23:48:18 UTC (rev 222118)
@@ -35,18 +35,27 @@
// You must snapshot if you use a value in rvalue context. For example, a call _expression_ will
// snapshot all of its arguments immedaitely upon executing them. In general, it should not be
// possible for a pointer returned from a visit method in rvalue context to live across any effects.
- _snapshot(type, ptr)
+ _snapshot(type, dstPtr, srcPtr)
{
let size = type.size;
if (!size)
throw new Error("Cannot get size of type: " + type);
- let result = new EPtr(new EBuffer(size), 0);
- result.copyFrom(ptr, size);
- return result;
+ if (!dstPtr)
+ dstPtr = new EPtr(new EBuffer(size), 0);
+ dstPtr.copyFrom(srcPtr, size);
+ return dstPtr;
}
- runBody(type, block)
+ runFunc(func)
{
+ return EBuffer.disallowAllocation(
+ () => this._runBody(func.returnType, func.returnEPtr, func.body));
+ }
+
+ _runBody(type, ptr, block)
+ {
+ if (!ptr)
+ throw new Error("Null ptr");
try {
block.visit(this);
// FIXME: We should have a check that there is no way to drop out of a function without
@@ -56,7 +65,7 @@
if (e == BreakException || e == ContinueException)
throw new Error("Should not see break/continue at function scope");
if (e instanceof ReturnException)
- return this._snapshot(type, e.value);
+ return this._snapshot(type, ptr, e.value);
throw e;
}
}
@@ -68,7 +77,7 @@
node.argumentList[i].visit(this),
node.parameters[i].type.size);
}
- return this.runBody(node.returnType, node.body);
+ return this._runBody(node.returnType, node.returnEPtr, node.body);
}
visitReturn(node)
@@ -103,17 +112,17 @@
visitMakePtrExpression(node)
{
- return EPtr.box(node.lValue.visit(this));
+ return node.ePtr.box(node.lValue.visit(this));
}
visitMakeArrayRefExpression(node)
{
- return EPtr.box(new EArrayRef(node.lValue.visit(this), node.numElements.visit(this).loadValue()));
+ return node.ePtr.box(new EArrayRef(node.lValue.visit(this), node.numElements.visit(this).loadValue()));
}
visitConvertPtrToArrayRefExpression(node)
{
- return EPtr.box(new EArrayRef(node.lValue.visit(this).loadValue(), 1));
+ return node.ePtr.box(new EArrayRef(node.lValue.visit(this).loadValue(), 1));
}
visitDotExpression(node)
@@ -138,23 +147,23 @@
visitGenericLiteral(node)
{
- return EPtr.box(node.value);
+ return node.ePtr.box(node.value);
}
visitNullLiteral(node)
{
- return EPtr.box(null);
+ return node.ePtr.box(null);
}
visitBoolLiteral(node)
{
- return EPtr.box(node.value);
+ return node.ePtr.box(node.value);
}
visitLogicalNot(node)
{
let result = !node.operand.visit(this).loadValue();
- return EPtr.box(result);
+ return node.ePtr.box(result);
}
visitIfStatement(node)
@@ -238,9 +247,16 @@
if (!type || !argument)
throw new Error("Cannot get type or argument; i = " + i + ", argument = " + argument + ", type = " + type + "; in " + node);
let argumentValue = argument.visit(this);
- callArguments.push(this._snapshot(type, argumentValue));
+ callArguments.push(() => this._snapshot(type, null, argumentValue));
}
- return node.func.implementation(callArguments, node);
+
+ // For simplicity, we allow intrinsics to just allocate new buffers, and we allocate new
+ // buffers when snapshotting their arguments. This is not observable to the user, so it's OK.
+ let result = EBuffer.allowAllocation(
+ () => node.func.implementation(callArguments.map(thunk => thunk()), node));
+
+ result = this._snapshot(node.nativeFuncInstance.returnType, node.resultEPtr, result);
+ return result;
}
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/Inliner.js (222117 => 222118)
--- trunk/Tools/WebGPUShadingLanguageRI/Inliner.js 2017-09-15 23:44:45 UTC (rev 222117)
+++ trunk/Tools/WebGPUShadingLanguageRI/Inliner.js 2017-09-15 23:48:18 UTC (rev 222118)
@@ -51,8 +51,10 @@
return result;
}
_inlineFunction(this._program, func, this._visiting);
- return new FunctionLikeBlock(
+ let resultingBlock = new FunctionLikeBlock(
result.origin, func.returnType, result.argumentList, func.parameters, func.body);
+ resultingBlock.returnEPtr = result.resultEPtr;
+ return resultingBlock;
});
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/InstantiateImmediates.js (222117 => 222118)
--- trunk/Tools/WebGPUShadingLanguageRI/InstantiateImmediates.js 2017-09-15 23:44:45 UTC (rev 222117)
+++ trunk/Tools/WebGPUShadingLanguageRI/InstantiateImmediates.js 2017-09-15 23:48:18 UTC (rev 222118)
@@ -28,7 +28,7 @@
visitTypeRef(node)
{
node = super.visitTypeRef(node);
- let result = TypeRef.wrap(node.instantiatedType);
+ let result = node.instantiatedType.visit(new AutoWrapper());
return result;
}
Modified: trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js (222117 => 222118)
--- trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js 2017-09-15 23:44:45 UTC (rev 222117)
+++ trunk/Tools/WebGPUShadingLanguageRI/Rewriter.js 2017-09-15 23:48:18 UTC (rev 222118)
@@ -186,7 +186,9 @@
visitMakePtrExpression(node)
{
- return new MakePtrExpression(node.origin, node.lValue.visit(this));
+ let result = new MakePtrExpression(node.origin, node.lValue.visit(this));
+ result.ePtr = node.ePtr;
+ return result;
}
visitMakeArrayRefExpression(node)
@@ -194,12 +196,15 @@
let result = new MakeArrayRefExpression(node.origin, node.lValue.visit(this));
if (node.numElements)
result.numElements = node.numElements.visit(this);
+ result.ePtr = node.ePtr;
return result;
}
visitConvertPtrToArrayRefExpression(node)
{
- return new ConvertPtrToArrayRefExpression(node.origin, node.lValue.visit(this));
+ let result = new ConvertPtrToArrayRefExpression(node.origin, node.lValue.visit(this));
+ result.ePtr = node.ePtr;
+ return result;
}
visitVariableRef(node)
@@ -228,6 +233,7 @@
{
let result = new IntLiteral(node.origin, node.value);
result.type = node.type.visit(this);
+ result.ePtr = node.ePtr;
return result;
}
@@ -248,6 +254,7 @@
{
let result = new NullLiteral(node.origin);
result.type = node.type.visit(this);
+ result.ePtr = node.ePtr;
return result;
}
@@ -273,6 +280,8 @@
result.possibleOverloads = node.possibleOverloads;
if (node.isCast)
result.setCastData(node.returnType.visit(this));
+ result.resultType = node.resultType ? node.resultType.visit(this) : null;
+ result.resultEPtr = node.resultEPtr;
return result;
}
@@ -287,17 +296,21 @@
visitFunctionLikeBlock(node)
{
- return new FunctionLikeBlock(
+ let result = new FunctionLikeBlock(
node.origin,
node.returnType ? node.returnType.visit(this) : null,
node.argumentList.map(argument => argument.visit(this)),
node.parameters.map(parameter => parameter.visit(this)),
node.body.visit(this));
+ result.returnEPtr = node.returnEPtr;
+ return result;
}
visitLogicalNot(node)
{
- return new LogicalNot(node.origin, node.operand.visit(this));
+ let result = new LogicalNot(node.origin, node.operand.visit(this));
+ result.ePtr = node.ePtr;
+ return result;
}
visitIfStatement(node)
Modified: trunk/Tools/WebGPUShadingLanguageRI/TypeRef.js (222117 => 222118)
--- trunk/Tools/WebGPUShadingLanguageRI/TypeRef.js 2017-09-15 23:44:45 UTC (rev 222117)
+++ trunk/Tools/WebGPUShadingLanguageRI/TypeRef.js 2017-09-15 23:48:18 UTC (rev 222118)
@@ -117,7 +117,7 @@
toString()
{
if (!this.name)
- return this.type.toString();
+ return "ref:" + this.type.toString();
if (!this.typeArguments.length)
return this.name;
return this.name + "<" + this.typeArguments + ">";
Modified: trunk/Tools/WebGPUShadingLanguageRI/Visitor.js (222117 => 222118)
--- trunk/Tools/WebGPUShadingLanguageRI/Visitor.js 2017-09-15 23:44:45 UTC (rev 222117)
+++ trunk/Tools/WebGPUShadingLanguageRI/Visitor.js 2017-09-15 23:48:18 UTC (rev 222118)
@@ -305,6 +305,8 @@
}
if (node.returnType)
node.returnType.visit(this);
+ if (node.resultType)
+ node.resultType.visit(this);
}
visitLogicalNot(node)
@@ -321,6 +323,8 @@
for (let parameter of node.parameters)
parameter.visit(this);
node.body.visit(this);
+ if (node.resultType)
+ node.resultType.visit(this);
}
visitLetExpression(node)