Title: [236452] trunk/Tools
Revision
236452
Author
[email protected]
Date
2018-09-24 21:15:06 -0700 (Mon, 24 Sep 2018)

Log Message

[WHLSL] Implement trap statements in Metal code generation
https://bugs.webkit.org/show_bug.cgi?id=189615

Patch by Thomas Denney <[email protected]> on 2018-09-24
Reviewed by Myles C. Maxfield.

Each function called by an entry point now receives an additional
boolean pointer parameter, which is set to false if the function traps.
After each function call (to a non-native function) this trap parameter
is checked. The behavior of the interpreter has also been updated so
that a function entry point catches the trap and instead returns zero,
matching the behavior of compiled code.

* WebGPUShadingLanguageRI/Evaluator.js: Adds a new flag to allow the
test suite to check for traps and also returns zero from entry points
whose invocation trapped.
* WebGPUShadingLanguageRI/Metal/MSLBackend.js: Pass program to function
declarations.
* WebGPUShadingLanguageRI/Metal/MSLCodegenAll.js: Update dependencies.
* WebGPUShadingLanguageRI/Metal/MSLFunctionDeclaration.js: Add program
property.
* WebGPUShadingLanguageRI/Metal/MSLFunctionDefinition.js: Ditto.
* WebGPUShadingLanguageRI/Metal/MSLInsertTrapParameter.js: Added.
* WebGPUShadingLanguageRI/Metal/MSLStatementEmitter.js: Conforms to the
new trapping behavior.
* WebGPUShadingLanguageRI/Test.js: Update tests that trap.

Modified Paths

Added Paths

Diff

Modified: trunk/Tools/ChangeLog (236451 => 236452)


--- trunk/Tools/ChangeLog	2018-09-25 03:33:05 UTC (rev 236451)
+++ trunk/Tools/ChangeLog	2018-09-25 04:15:06 UTC (rev 236452)
@@ -1,5 +1,33 @@
 2018-09-24  Thomas Denney  <[email protected]>
 
+        [WHLSL] Implement trap statements in Metal code generation
+        https://bugs.webkit.org/show_bug.cgi?id=189615
+
+        Reviewed by Myles C. Maxfield.
+
+        Each function called by an entry point now receives an additional
+        boolean pointer parameter, which is set to false if the function traps.
+        After each function call (to a non-native function) this trap parameter
+        is checked. The behavior of the interpreter has also been updated so
+        that a function entry point catches the trap and instead returns zero,
+        matching the behavior of compiled code.
+
+        * WebGPUShadingLanguageRI/Evaluator.js: Adds a new flag to allow the
+        test suite to check for traps and also returns zero from entry points
+        whose invocation trapped.
+        * WebGPUShadingLanguageRI/Metal/MSLBackend.js: Pass program to function
+        declarations.
+        * WebGPUShadingLanguageRI/Metal/MSLCodegenAll.js: Update dependencies.
+        * WebGPUShadingLanguageRI/Metal/MSLFunctionDeclaration.js: Add program
+        property.
+        * WebGPUShadingLanguageRI/Metal/MSLFunctionDefinition.js: Ditto.
+        * WebGPUShadingLanguageRI/Metal/MSLInsertTrapParameter.js: Added.
+        * WebGPUShadingLanguageRI/Metal/MSLStatementEmitter.js: Conforms to the
+        new trapping behavior.
+        * WebGPUShadingLanguageRI/Test.js: Update tests that trap.
+
+2018-09-24  Thomas Denney  <[email protected]>
+
         [WHLSL] It shouldn’t be possible to use ternary expressions as l-values
         https://bugs.webkit.org/show_bug.cgi?id=189290
 

Modified: trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js (236451 => 236452)


--- trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js	2018-09-25 03:33:05 UTC (rev 236451)
+++ trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js	2018-09-25 04:15:06 UTC (rev 236452)
@@ -24,6 +24,8 @@
  */
 "use strict";
 
+let _lastInvocationDidTrap;
+
 // This is a combined LHS/RHS evaluator that passes around EPtr's to everything.
 class Evaluator extends Visitor {
     constructor(program)
@@ -30,7 +32,13 @@
     {
         super();
         this._program = program;
+        _lastInvocationDidTrap = false;
     }
+
+    static lastInvocationDidTrap()
+    {
+        return lastInvocationDidTrap;
+    }
     
     // You must snapshot if you use a value in rvalue context. For example, a call _expression_ will
     // snapshot all of its arguments immediately upon executing them. In general, it should not be
@@ -51,10 +59,10 @@
     runFunc(func)
     {
         return EBuffer.disallowAllocation(
-            () => this._runBody(func.returnType, func.returnEPtr, func.body));
+            () => this._runBody(func.returnType, func.returnEPtr, func.body, func.isEntryPoint));
     }
     
-    _runBody(type, ptr, block)
+    _runBody(type, ptr, block, isEntryPoint)
     {
         if (!ptr)
             throw new Error("Null ptr");
@@ -66,9 +74,14 @@
         } catch (e) {
             if (e == BreakException || e == ContinueException)
                 throw new Error("Should not see break/continue at function scope");
-            if (e instanceof ReturnException) {
-                let result = this._snapshot(type, ptr, e.value);
-                return result;
+            if (e instanceof ReturnException)
+                return this._snapshot(type, ptr, e.value);
+            if (e instanceof WTrapError) {
+                if (isEntryPoint) {
+                    _lastInvocationDidTrap = true;
+                    type.populateDefaultValue(ptr.buffer, ptr.offset);
+                    return ptr;
+                }
             }
             throw e;
         }
@@ -90,17 +103,17 @@
         return callArguments;
     }
 
-    _evaluateFunction(node, argumentList, parameterList, funcBody, returnType, returnEPtr)
+    _evaluateFunction(node, argumentList, parameterList, funcBody, returnType, returnEPtr, isEntryPoint)
     {
         const argumentValues = this._evaluateArguments(argumentList, parameterList);
         for (let i = 0; i < node.argumentList.length; ++i)
             parameterList[i].ePtr.copyFrom(argumentValues[i], parameterList[i].type.size);
-        return EBuffer.allowAllocation(() => this._runBody(returnType, returnEPtr, funcBody));
+        return EBuffer.allowAllocation(() => this._runBody(returnType, returnEPtr, funcBody, isEntryPoint));
     }
 
     visitFunctionLikeBlock(node)
     {
-        return this._evaluateFunction(node, node.argumentList, node.parameters, node.body, node.returnType, node.returnEPtr);
+        return this._evaluateFunction(node, node.argumentList, node.parameters, node.body, node.returnType, node.returnEPtr, false);
     }
     
     visitReturn(node)
@@ -334,7 +347,7 @@
             const callArguments = this._evaluateArguments(node.argumentList, node.func.parameters);
             return EBuffer.allowAllocation(() => this._snapshot(node.func.returnType, node.resultEPtr, node.func.implementation(callArguments, node)));
         } else
-            return this._evaluateFunction(node, node.argumentList, node.func.parameters, node.func.body, node.func.returnType, node.resultEPtr);
+            return this._evaluateFunction(node, node.argumentList, node.func.parameters, node.func.body, node.func.returnType, node.resultEPtr, false);
     }
 }
 

Modified: trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLBackend.js (236451 => 236452)


--- trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLBackend.js	2018-09-25 03:33:05 UTC (rev 236451)
+++ trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLBackend.js	2018-09-25 04:15:06 UTC (rev 236452)
@@ -79,6 +79,8 @@
 
     _msl()
     {
+        insertTrapParameter(this.program);
+
         const functionsToCompile = this._findFunctionsToCompile();
         for (let func of functionsToCompile)
             func.visit(this._typeUnifier);
@@ -156,8 +158,8 @@
     _createFunctionDecls(unifiedFunctionDefs)
     {
         for (let func of unifiedFunctionDefs) {
-            this._forwardFunctionDecls.push(new MSLFunctionForwardDeclaration(this._funcNameMangler, func, this._typeUnifier, this._allTypeAttributes));
-            this._functionDefintions.push(new MSLFunctionDefinition(this._funcNameMangler, func, this._typeUnifier, this._allTypeAttributes));
+            this._forwardFunctionDecls.push(new MSLFunctionForwardDeclaration(this.program, this._funcNameMangler, func, this._typeUnifier, this._allTypeAttributes));
+            this._functionDefintions.push(new MSLFunctionDefinition(this.program, this._funcNameMangler, func, this._typeUnifier, this._allTypeAttributes));
         }
     }
 

Modified: trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLCodegenAll.js (236451 => 236452)


--- trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLCodegenAll.js	2018-09-25 03:33:05 UTC (rev 236451)
+++ trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLCodegenAll.js	2018-09-25 04:15:06 UTC (rev 236452)
@@ -29,6 +29,7 @@
 load("MSLFunctionDeclaration.js");
 load("MSLFunctionDefinition.js");
 load("MSLFunctionForwardDeclaration.js");
+load("MSLInsertTrapParameter.js");
 load("MSLNameMangler.js");
 load("MSLNativeFunctionCall.js");
 load("MSLStatementEmitter.js");

Modified: trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDeclaration.js (236451 => 236452)


--- trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDeclaration.js	2018-09-25 03:33:05 UTC (rev 236451)
+++ trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDeclaration.js	2018-09-25 04:15:06 UTC (rev 236452)
@@ -26,8 +26,9 @@
 // Emits code for the first line of a function declaration or definition.
 class MSLFunctionDeclaration {
 
-    constructor(funcMangler, funcDef, typeUnifier, typeAttributes)
+    constructor(program, funcMangler, funcDef, typeUnifier, typeAttributes)
     {
+        this._program = program;
         this._funcMangler = funcMangler;
         this._func = funcDef;
         this._typeUnifier = typeUnifier;
@@ -34,6 +35,11 @@
         this._typeAttributes = typeAttributes;
     }
 
+    get program()
+    {
+        return this._program;
+    }
+
     get funcMangler()
     {
         return this._funcMangler;

Modified: trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDefinition.js (236451 => 236452)


--- trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDefinition.js	2018-09-25 03:33:05 UTC (rev 236451)
+++ trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDefinition.js	2018-09-25 04:15:06 UTC (rev 236452)
@@ -29,7 +29,7 @@
     {
         let src = "" + "\n" + super.toString();
         src += "\n{\n";
-        let emitter = new MSLStatementEmitter(this.funcMangler, this.typeUnifier, this.func, this.paramMap, this.func.name, this.typeAttributes);
+        let emitter = new MSLStatementEmitter(this.program, this.funcMangler, this.typeUnifier, this.func, this.paramMap, this.func.name, this.typeAttributes);
         src += emitter.indentedSource();
         src += "}";
         return src;

Added: trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLInsertTrapParameter.js (0 => 236452)


--- trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLInsertTrapParameter.js	                        (rev 0)
+++ trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLInsertTrapParameter.js	2018-09-25 04:15:06 UTC (rev 236452)
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2018 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. ``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
+ * 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.
+ */
+
+function insertTrapParameter(program)
+{
+    const functionVisitedOrder = [];
+    const entryPointFunctions = new Set();
+    class FindEntryPoints extends Visitor {
+        visitFuncDef(node)
+        {
+            if (node.isEntryPoint && !entryPointFunctions.has(node)) {
+                entryPointFunctions.add(node);
+                functionVisitedOrder.push(node);
+            }
+        }
+    }
+    program.visit(new FindEntryPoints());
+
+    const functionsCalledByEntryPoints = new Set();
+    class FindFunctionsCalledByEntryPoints extends Visitor {
+        visitCallExpression(node)
+        {
+            super.visitCallExpression(node);
+            if (node.func instanceof FuncDef && !functionsCalledByEntryPoints.has(node.func)) {
+                functionsCalledByEntryPoints.add(node.func);
+                functionVisitedOrder.push(node.func);
+                node.func.visit(this);
+            }
+        }
+    }
+    for (let entryPoint of entryPointFunctions)
+        entryPoint.visit(new FindFunctionsCalledByEntryPoints());
+
+    for (let entryPoint of entryPointFunctions) {
+        const trapVariable = new VariableDecl(entryPoint.origin, null, program.types.get("bool"), new BoolLiteral(entryPoint.origin, true));
+        entryPoint.body.statements.unshift(trapVariable);
+        entryPoint._trapPointerExpression = new MakePtrExpression(entryPoint.origin, VariableRef.wrap(trapVariable));
+    }
+
+    for (let func of functionsCalledByEntryPoints) {
+        const trapParameter = new FuncParameter(func.origin, null, new PtrType(func.origin, "thread", TypeRef.wrap(program.types.get("bool"))));
+        func.parameters.push(trapParameter);
+        func._trapPointerExpression = VariableRef.wrap(trapParameter);
+    }
+
+    const visitedFunctions = new Set();
+    class UpdateCallExpressions extends Visitor {
+        constructor(caller)
+        {
+            super();
+            this._caller = caller;
+            if (!visitedFunctions.has(this._caller)) {
+                visitedFunctions.add(this._caller);
+                caller.visit(this);
+            }
+        }
+
+        visitCallExpression(node)
+        {
+            super.visitCallExpression(node);
+            if (node.func instanceof FuncDef) {
+                node.argumentList.push(this._caller._trapPointerExpression);
+                new UpdateCallExpressions(node.func);
+            }
+        }
+    }
+
+    for (let entryPoint of entryPointFunctions)
+        new UpdateCallExpressions(entryPoint);
+}

Modified: trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLStatementEmitter.js (236451 => 236452)


--- trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLStatementEmitter.js	2018-09-25 03:33:05 UTC (rev 236451)
+++ trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLStatementEmitter.js	2018-09-25 04:15:06 UTC (rev 236452)
@@ -25,9 +25,10 @@
 
 class MSLStatementEmitter extends Visitor {
 
-    constructor(funcMangler, typeUnifier, func, paramMap, debugName, typeAttributes)
+    constructor(program, funcMangler, typeUnifier, func, paramMap, debugName, typeAttributes)
     {
         super();
+        this._program = program;
         this._funcMangler = funcMangler;
         this._typeUnifier = typeUnifier;
         this._func = func;
@@ -47,9 +48,24 @@
 
     _emitTrap()
     {
-        this._add('// FIXME: Handle traps.');
+        // No need to update this if in an entry point, we can just return zero.
+        if (!this._func.isEntryPoint)
+            this._add(`*(${this._func._trapPointerExpression.visit(this)}) = false;`);
+        this._emitTrapReturn();
     }
 
+    _emitTrapReturn()
+    {
+        if (this._func.returnType.equals(this._program.intrinsics.void))
+            this._add('return;');
+        else {
+            const id = this._fresh();
+            this._add(`${this._typeUnifier.uniqueTypeId(this._func.returnType)} ${id};`);
+            this._zeroInitialize(this._func.returnType, id);
+            this._add(`return ${id};`);
+        }
+    }
+
     _zeroInitialize(type, variableName, allowComment = true)
     {
         const emitter = this;
@@ -414,6 +430,10 @@
                 this._add(`${resultVariable} = ${callString};`);
             else
                 this._add(`${callString};`);
+
+            this._add(`if (!(*(${this._func._trapPointerExpression.visit(this)}))) {`);
+            this._indent(() => this._emitTrapReturn());
+            this._add("}");
         } else
             this._makeNativeFunctionCall(node.func, resultVariable, args);
 

Modified: trunk/Tools/WebGPUShadingLanguageRI/Test.js (236451 => 236452)


--- trunk/Tools/WebGPUShadingLanguageRI/Test.js	2018-09-25 03:33:05 UTC (rev 236451)
+++ trunk/Tools/WebGPUShadingLanguageRI/Test.js	2018-09-25 04:15:06 UTC (rev 236452)
@@ -314,6 +314,16 @@
     }
 }
 
+function checkTrap(program, callback, checkFunction)
+{
+    const result = callback();
+    // FIXME: Rewrite tests so that they return non-zero values in the case that they didn't trap.
+    // The check function is optional in the case of a void return type.
+    checkFunction(program, result, 0);
+    if (!Evaluator.lastInvocationDidTrap)
+        throw new Error("Did not trap");
+}
+
 let tests;
 let okToTest = false;
 
@@ -928,9 +938,7 @@
             return *p;
         }
     `);
-    checkFail(
-        () => callFunction(program, "foo", []),
-        (e) => e instanceof WTrapError);
+    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
 }
 
 tests.defaultInitializedNull = function()
@@ -942,9 +950,7 @@
             return *p;
         }
     `);
-    checkFail(
-        () => callFunction(program, "foo", []),
-        (e) => e instanceof WTrapError);
+    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
 }
 
 tests.passNullToPtrMonomorphic = function()
@@ -959,9 +965,7 @@
             return foo(null);
         }
     `);
-    checkFail(
-        () => callFunction(program, "bar", []),
-        (e) => e instanceof WTrapError);
+    checkTrap(program, () => callFunction(program, "bar", []), checkInt);
 }
 
 tests.loadNullArrayRef = function()
@@ -1006,9 +1010,7 @@
             return p[0u];
         }
     `);
-    checkFail(
-        () => callFunction(program, "foo", []),
-        (e) => e instanceof WTrapError);
+    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
 }
 
 tests.defaultInitializedNullArrayRef = function()
@@ -1020,9 +1022,7 @@
             return p[0u];
         }
     `);
-    checkFail(
-        () => callFunction(program, "foo", []),
-        (e) => e instanceof WTrapError);
+    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
 }
 
 tests.defaultInitializedNullArrayRefIntLiteral = function()
@@ -1034,9 +1034,7 @@
             return p[0];
         }
     `);
-    checkFail(
-        () => callFunction(program, "foo", []),
-        (e) => e instanceof WTrapError);
+    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
 }
 
 tests.passNullToPtrMonomorphicArrayRef = function()
@@ -1051,9 +1049,7 @@
             return foo(null);
         }
     `);
-    checkFail(
-        () => callFunction(program, "bar", []),
-        (e) => e instanceof WTrapError);
+    checkTrap(program, () => callFunction(program, "bar", []), checkInt);
 }
 
 tests.returnIntLiteralUint = function()
@@ -2501,7 +2497,7 @@
     let src = "" int sum() {\n";
     src += "    int i = 0;\n";
     let target = 0;
-    const numVars = 1024;
+    const numVars = 50;
     for (let i = 0; i < numVars; i++) {
         const value = i * 3;
         src += `   i = ${i};\n`;
@@ -3880,16 +3876,15 @@
             trap;
         }
     `);
-    checkFail(
-        () => callFunction(program, "foo", []),
-        e => e instanceof WTrapError);
+    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
     checkInt(program, callFunction(program, "foo2", [makeInt(program, 1)]), 4);
-    checkFail(
-        () => callFunction(program, "foo2", [makeInt(program, 3)]),
-        e => e instanceof WTrapError);
-    checkFail(
-        () => callFunction(program, "foo3", []),
-        e => e instanceof WTrapError);
+    checkTrap(program, () => callFunction(program, "foo2", [makeInt(program, 3)]), checkInt);
+    checkTrap(program, () => callFunction(program, "foo3", []), (progam, result, expected) => {
+        for (let i = 0; i < 4; i++) {
+            if (result.ePtr.get(i) != expected)
+                throw new Error(`Non-zero return value at offset ${i}`);
+        }
+    });
 }
 
 /*
@@ -4651,9 +4646,7 @@
             return foo.bar->bar - bar.foo->foo;
         }
     `);
-    checkFail(
-        () => checkInt(program, callFunction(program, "foo", []), -511),
-        e => e instanceof WTrapError);
+    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
 }
 
 tests.mutuallyRecursiveStructWithPointers = function()
@@ -6346,164 +6339,148 @@
     checkInt(program, callFunction(program, "foo", [makeInt(program, 3), makeInt(program, 4), makeInt(program, 5)]), 3);
 
     program = doPrep(`
-        test void foo() {
+        test int foo() {
             thread atomic_int* x = null;
             InterlockedAdd(x, 1, null);
+            return 1;
         }
     `);
-    checkFail(
-        () => callFunction(program, "foo", []),
-        (e) => e instanceof WTrapError);
+    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
 
     program = doPrep(`
-        test void foo() {
+        test int foo() {
             thread atomic_uint* x = null;
             InterlockedAdd(x, 1, null);
+            return 1;
         }
     `);
-    checkFail(
-        () => callFunction(program, "foo", []),
-        (e) => e instanceof WTrapError);
+    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
 
     program = doPrep(`
-        test void foo() {
+        test int foo() {
             thread atomic_int* x = null;
             InterlockedAnd(x, 1, null);
+            return 1;
         }
     `);
-    checkFail(
-        () => callFunction(program, "foo", []),
-        (e) => e instanceof WTrapError);
+    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
 
     program = doPrep(`
-        test void foo() {
+        test int foo() {
             thread atomic_uint* x = null;
             InterlockedAnd(x, 1, null);
+            return 1;
         }
     `);
-    checkFail(
-        () => callFunction(program, "foo", []),
-        (e) => e instanceof WTrapError);
+    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
 
     program = doPrep(`
-        test void foo() {
+        test int foo() {
             thread atomic_int* x = null;
             InterlockedExchange(x, 1, null);
+            return 1;
         }
     `);
-    checkFail(
-        () => callFunction(program, "foo", []),
-        (e) => e instanceof WTrapError);
+    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
 
     program = doPrep(`
-        test void foo() {
+        test int foo() {
             thread atomic_uint* x = null;
             InterlockedExchange(x, 1, null);
+            return 1;
         }
     `);
-    checkFail(
-        () => callFunction(program, "foo", []),
-        (e) => e instanceof WTrapError);
+    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
 
     program = doPrep(`
-        test void foo() {
+        test int foo() {
             thread atomic_int* x = null;
             InterlockedMax(x, 1, null);
+            return 1;
         }
     `);
-    checkFail(
-        () => callFunction(program, "foo", []),
-        (e) => e instanceof WTrapError);
+    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
 
     program = doPrep(`
-        test void foo() {
+        test int foo() {
             thread atomic_uint* x = null;
             InterlockedMax(x, 1, null);
+            return 1;
         }
     `);
-    checkFail(
-        () => callFunction(program, "foo", []),
-        (e) => e instanceof WTrapError);
+    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
 
     program = doPrep(`
-        test void foo() {
+        test int foo() {
             thread atomic_int* x = null;
             InterlockedMin(x, 1, null);
+            return 1;
         }
     `);
-    checkFail(
-        () => callFunction(program, "foo", []),
-        (e) => e instanceof WTrapError);
+    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
 
     program = doPrep(`
-        test void foo() {
+        test int foo() {
             thread atomic_uint* x = null;
             InterlockedMin(x, 1, null);
+            return 1;
         }
     `);
-    checkFail(
-        () => callFunction(program, "foo", []),
-        (e) => e instanceof WTrapError);
+    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
 
     program = doPrep(`
-        test void foo() {
+        test int foo() {
             thread atomic_int* x = null;
             InterlockedOr(x, 1, null);
+            return 1;
         }
     `);
-    checkFail(
-        () => callFunction(program, "foo", []),
-        (e) => e instanceof WTrapError);
+    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
 
     program = doPrep(`
-        test void foo() {
+        test int foo() {
             thread atomic_uint* x = null;
             InterlockedOr(x, 1, null);
+            return 1;
         }
     `);
-    checkFail(
-        () => callFunction(program, "foo", []),
-        (e) => e instanceof WTrapError);
+    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
 
     program = doPrep(`
-        test void foo() {
+        test int foo() {
             thread atomic_int* x = null;
             InterlockedXor(x, 1, null);
+            return 1;
         }
     `);
-    checkFail(
-        () => callFunction(program, "foo", []),
-        (e) => e instanceof WTrapError);
+    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
 
     program = doPrep(`
-        test void foo() {
+        test int foo() {
             thread atomic_uint* x = null;
             InterlockedXor(x, 1, null);
+            return 1;
         }
     `);
-    checkFail(
-        () => callFunction(program, "foo", []),
-        (e) => e instanceof WTrapError);
+    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
 
     program = doPrep(`
-        test void foo() {
+        test int foo() {
             thread atomic_int* x = null;
             InterlockedCompareExchange(x, 1, 2, null);
+            return 1;
         }
     `);
-    checkFail(
-        () => callFunction(program, "foo", []),
-        (e) => e instanceof WTrapError);
+    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
 
     program = doPrep(`
-        test void foo() {
+        test int foo() {
             thread atomic_uint* x = null;
             InterlockedCompareExchange(x, 1, 2, null);
+            return 1;
         }
     `);
-    checkFail(
-        () => callFunction(program, "foo", []),
-        (e) => e instanceof WTrapError);
+    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
 }
 
 tests.selfCasts = function()
@@ -9155,6 +9132,120 @@
     checkInt(program, callFunction(program, "foo", []), 42);
 };
 
+tests.passingArrayToFunction = function()
+{
+    let program = doPrep(`
+        test int foo()
+        {
+            int[10] arr;
+            for (uint i = 0; i < arr.length; i++)
+                arr[i] = int(i) + 1;
+            return sum(arr);
+        }
+
+        int sum(int[10] xs)
+        {
+            int t = 0;
+            for (uint i = 0; i < xs.length; i++)
+                t = t + xs[i];
+            return t;
+        }
+    `);
+    checkInt(program, callFunction(program, "foo", []), 55);
+}
+
+tests.returnAnArrayFromAFunction = function()
+{
+    let program = doPrep(`
+        test int foo()
+        {
+            int[5] ys = bar();
+            return ys[0] + ys[1] + ys[2] + ys[3] + ys[4];
+        }
+
+        int[5] bar()
+        {
+            int[5] xs;
+            xs[0] = 1;
+            xs[1] = 2;
+            xs[2] = 3;
+            xs[3] = 4;
+            xs[4] = 5;
+            return xs;
+        }
+    `);
+}
+
+tests.copyArray = function()
+{
+    let program = doPrep(`
+        test int foo()
+        {
+            int[10] xs;
+            for (uint i = 0; i < xs.length; i++)
+                xs[i] = int(i) + 1;
+            int[10] ys = xs;
+            for (uint i = 0; i < xs.length; i++)
+                xs[i] = 0;
+            int sum = 0;
+            for (uint i = 0; i < ys.length; i++)
+                sum = sum + ys[i];
+            return sum;
+        }
+    `);
+    checkInt(program, callFunction(program, "foo", []), 55);
+}
+
+tests.settingAnArrayInsideAStruct = function()
+{
+    let program = doPrep(`
+        struct Foo {
+            int[1] array;
+        }
+        test int foo()
+        {
+            Foo foo;
+            thread Foo* bar = &foo;
+            bar->array[0] = 21;
+            return foo.array[0];
+        }
+    `);
+    checkInt(program, callFunction(program, "foo", []), 21);
+}
+
+tests.trapBecauseOfIndexAcesss = () => {
+    const program = doPrep(`
+        test int foo()
+        {
+            int[5] array;
+            array[6] = 42;
+            return array[6];
+        }
+    `);
+    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
+}
+
+tests.trapTransitively = () => {
+    const program = doPrep(`
+        test int foo()
+        {
+            willTrapTransitively();
+            return 42;
+        }
+
+        void willTrapTransitively()
+        {
+            doTrap();
+        }
+
+        void doTrap()
+        {
+            trap;
+        }
+    `);
+    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
+};
+
 okToTest = true;
 
 let testFilter = /.*/; // run everything by default
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to