⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 236452 in webkit


Ignore:
Timestamp:
Sep 24, 2018, 9:15:06 PM (8 years ago)
Author:
commit-queue@webkit.org
Message:

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

Patch by Thomas Denney <​tdenney@apple.com> 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.
Location:
trunk/Tools
Files:
1 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/Tools/ChangeLog

    r236449 r236452  
     12018-09-24  Thomas Denney  <tdenney@apple.com>
     2
     3        [WHLSL] Implement trap statements in Metal code generation
     4        https://bugs.webkit.org/show_bug.cgi?id=189615
     5
     6        Reviewed by Myles C. Maxfield.
     7
     8        Each function called by an entry point now receives an additional
     9        boolean pointer parameter, which is set to false if the function traps.
     10        After each function call (to a non-native function) this trap parameter
     11        is checked. The behavior of the interpreter has also been updated so
     12        that a function entry point catches the trap and instead returns zero,
     13        matching the behavior of compiled code.
     14
     15        * WebGPUShadingLanguageRI/Evaluator.js: Adds a new flag to allow the
     16        test suite to check for traps and also returns zero from entry points
     17        whose invocation trapped.
     18        * WebGPUShadingLanguageRI/Metal/MSLBackend.js: Pass program to function
     19        declarations.
     20        * WebGPUShadingLanguageRI/Metal/MSLCodegenAll.js: Update dependencies.
     21        * WebGPUShadingLanguageRI/Metal/MSLFunctionDeclaration.js: Add program
     22        property.
     23        * WebGPUShadingLanguageRI/Metal/MSLFunctionDefinition.js: Ditto.
     24        * WebGPUShadingLanguageRI/Metal/MSLInsertTrapParameter.js: Added.
     25        * WebGPUShadingLanguageRI/Metal/MSLStatementEmitter.js: Conforms to the
     26        new trapping behavior.
     27        * WebGPUShadingLanguageRI/Test.js: Update tests that trap.
     28
    1292018-09-24  Thomas Denney  <tdenney@apple.com>
    230
  • trunk/Tools/WebGPUShadingLanguageRI/Evaluator.js

    r235879 r236452  
    2525"use strict";
    2626
     27let _lastInvocationDidTrap;
     28
    2729// This is a combined LHS/RHS evaluator that passes around EPtr's to everything.
    2830class Evaluator extends Visitor {
    … …  
    3133        super();
    3234        this._program = program;
     35        _lastInvocationDidTrap = false;
     36    }
     37
     38    static lastInvocationDidTrap()
     39    {
     40        return lastInvocationDidTrap;
    3341    }
    3442   
    … …  
    5260    {
    5361        return EBuffer.disallowAllocation(
    54             () => this._runBody(func.returnType, func.returnEPtr, func.body));
    55     }
    56    
    57     _runBody(type, ptr, block)
     62            () => this._runBody(func.returnType, func.returnEPtr, func.body, func.isEntryPoint));
     63    }
     64   
     65    _runBody(type, ptr, block, isEntryPoint)
    5866    {
    5967        if (!ptr)
    … …  
    6775            if (e == BreakException || e == ContinueException)
    6876                throw new Error("Should not see break/continue at function scope");
    69             if (e instanceof ReturnException) {
    70                 let result = this._snapshot(type, ptr, e.value);
    71                 return result;
     77            if (e instanceof ReturnException)
     78                return this._snapshot(type, ptr, e.value);
     79            if (e instanceof WTrapError) {
     80                if (isEntryPoint) {
     81                    _lastInvocationDidTrap = true;
     82                    type.populateDefaultValue(ptr.buffer, ptr.offset);
     83                    return ptr;
     84                }
    7285            }
    7386            throw e;
    … …  
    91104    }
    92105
    93     _evaluateFunction(node, argumentList, parameterList, funcBody, returnType, returnEPtr)
     106    _evaluateFunction(node, argumentList, parameterList, funcBody, returnType, returnEPtr, isEntryPoint)
    94107    {
    95108        const argumentValues = this._evaluateArguments(argumentList, parameterList);
    96109        for (let i = 0; i < node.argumentList.length; ++i)
    97110            parameterList[i].ePtr.copyFrom(argumentValues[i], parameterList[i].type.size);
    98         return EBuffer.allowAllocation(() => this._runBody(returnType, returnEPtr, funcBody));
     111        return EBuffer.allowAllocation(() => this._runBody(returnType, returnEPtr, funcBody, isEntryPoint));
    99112    }
    100113
    101114    visitFunctionLikeBlock(node)
    102115    {
    103         return this._evaluateFunction(node, node.argumentList, node.parameters, node.body, node.returnType, node.returnEPtr);
     116        return this._evaluateFunction(node, node.argumentList, node.parameters, node.body, node.returnType, node.returnEPtr, false);
    104117    }
    105118   
    … …  
    335348            return EBuffer.allowAllocation(() => this._snapshot(node.func.returnType, node.resultEPtr, node.func.implementation(callArguments, node)));
    336349        } else
    337             return this._evaluateFunction(node, node.argumentList, node.func.parameters, node.func.body, node.func.returnType, node.resultEPtr);
     350            return this._evaluateFunction(node, node.argumentList, node.func.parameters, node.func.body, node.func.returnType, node.resultEPtr, false);
    338351    }
    339352}
  • trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLBackend.js

    r236299 r236452  
    8080    _msl()
    8181    {
     82        insertTrapParameter(this.program);
     83
    8284        const functionsToCompile = this._findFunctionsToCompile();
    8385        for (let func of functionsToCompile)
    … …  
    157159    {
    158160        for (let func of unifiedFunctionDefs) {
    159             this._forwardFunctionDecls.push(new MSLFunctionForwardDeclaration(this._funcNameMangler, func, this._typeUnifier, this._allTypeAttributes));
    160             this._functionDefintions.push(new MSLFunctionDefinition(this._funcNameMangler, func, this._typeUnifier, this._allTypeAttributes));
     161            this._forwardFunctionDecls.push(new MSLFunctionForwardDeclaration(this.program, this._funcNameMangler, func, this._typeUnifier, this._allTypeAttributes));
     162            this._functionDefintions.push(new MSLFunctionDefinition(this.program, this._funcNameMangler, func, this._typeUnifier, this._allTypeAttributes));
    161163        }
    162164    }
  • trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLCodegenAll.js

    r236299 r236452  
    3030load("MSLFunctionDefinition.js");
    3131load("MSLFunctionForwardDeclaration.js");
     32load("MSLInsertTrapParameter.js");
    3233load("MSLNameMangler.js");
    3334load("MSLNativeFunctionCall.js");
  • trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDeclaration.js

    r236299 r236452  
    2727class MSLFunctionDeclaration {
    2828
    29     constructor(funcMangler, funcDef, typeUnifier, typeAttributes)
     29    constructor(program, funcMangler, funcDef, typeUnifier, typeAttributes)
    3030    {
     31        this._program = program;
    3132        this._funcMangler = funcMangler;
    3233        this._func = funcDef;
    3334        this._typeUnifier = typeUnifier;
    3435        this._typeAttributes = typeAttributes;
     36    }
     37
     38    get program()
     39    {
     40        return this._program;
    3541    }
    3642
  • trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLFunctionDefinition.js

    r236299 r236452  
    3030        let src = this.commentLine() + "\n" + super.toString();
    3131        src += "\n{\n";
    32         let emitter = new MSLStatementEmitter(this.funcMangler, this.typeUnifier, this.func, this.paramMap, this.func.name, this.typeAttributes);
     32        let emitter = new MSLStatementEmitter(this.program, this.funcMangler, this.typeUnifier, this.func, this.paramMap, this.func.name, this.typeAttributes);
    3333        src += emitter.indentedSource();
    3434        src += "}";
  • trunk/Tools/WebGPUShadingLanguageRI/Metal/MSLStatementEmitter.js

    r236299 r236452  
    2626class MSLStatementEmitter extends Visitor {
    2727
    28     constructor(funcMangler, typeUnifier, func, paramMap, debugName, typeAttributes)
     28    constructor(program, funcMangler, typeUnifier, func, paramMap, debugName, typeAttributes)
    2929    {
    3030        super();
     31        this._program = program;
    3132        this._funcMangler = funcMangler;
    3233        this._typeUnifier = typeUnifier;
    … …  
    4849    _emitTrap()
    4950    {
    50         this._add('// FIXME: Handle traps.');
     51        // No need to update this if in an entry point, we can just return zero.
     52        if (!this._func.isEntryPoint)
     53            this._add(`*(${this._func._trapPointerExpression.visit(this)}) = false;`);
     54        this._emitTrapReturn();
     55    }
     56
     57    _emitTrapReturn()
     58    {
     59        if (this._func.returnType.equals(this._program.intrinsics.void))
     60            this._add('return;');
     61        else {
     62            const id = this._fresh();
     63            this._add(`${this._typeUnifier.uniqueTypeId(this._func.returnType)} ${id};`);
     64            this._zeroInitialize(this._func.returnType, id);
     65            this._add(`return ${id};`);
     66        }
    5167    }
    5268
    … …  
    415431            else
    416432                this._add(`${callString};`);
     433
     434            this._add(`if (!(*(${this._func._trapPointerExpression.visit(this)}))) {`);
     435            this._indent(() => this._emitTrapReturn());
     436            this._add("}");
    417437        } else
    418438            this._makeNativeFunctionCall(node.func, resultVariable, args);
  • trunk/Tools/WebGPUShadingLanguageRI/Test.js

    r236449 r236452  
    315315}
    316316
     317function checkTrap(program, callback, checkFunction)
     318{
     319    const result = callback();
     320    // FIXME: Rewrite tests so that they return non-zero values in the case that they didn't trap.
     321    // The check function is optional in the case of a void return type.
     322    checkFunction(program, result, 0);
     323    if (!Evaluator.lastInvocationDidTrap)
     324        throw new Error("Did not trap");
     325}
     326
    317327let tests;
    318328let okToTest = false;
    … …  
    929939        }
    930940    `);
    931     checkFail(
    932         () => callFunction(program, "foo", []),
    933         (e) => e instanceof WTrapError);
     941    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
    934942}
    935943
    … …  
    943951        }
    944952    `);
    945     checkFail(
    946         () => callFunction(program, "foo", []),
    947         (e) => e instanceof WTrapError);
     953    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
    948954}
    949955
    … …  
    960966        }
    961967    `);
    962     checkFail(
    963         () => callFunction(program, "bar", []),
    964         (e) => e instanceof WTrapError);
     968    checkTrap(program, () => callFunction(program, "bar", []), checkInt);
    965969}
    966970
    … …  
    10071011        }
    10081012    `);
    1009     checkFail(
    1010         () => callFunction(program, "foo", []),
    1011         (e) => e instanceof WTrapError);
     1013    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
    10121014}
    10131015
    … …  
    10211023        }
    10221024    `);
    1023     checkFail(
    1024         () => callFunction(program, "foo", []),
    1025         (e) => e instanceof WTrapError);
     1025    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
    10261026}
    10271027
    … …  
    10351035        }
    10361036    `);
    1037     checkFail(
    1038         () => callFunction(program, "foo", []),
    1039         (e) => e instanceof WTrapError);
     1037    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
    10401038}
    10411039
    … …  
    10521050        }
    10531051    `);
    1054     checkFail(
    1055         () => callFunction(program, "bar", []),
    1056         (e) => e instanceof WTrapError);
     1052    checkTrap(program, () => callFunction(program, "bar", []), checkInt);
    10571053}
    10581054
    … …  
    25022498    src += "    int i = 0;\n";
    25032499    let target = 0;
    2504     const numVars = 1024;
     2500    const numVars = 50;
    25052501    for (let i = 0; i < numVars; i++) {
    25062502        const value = i * 3;
    … …  
    38813877        }
    38823878    `);
    3883     checkFail(
    3884         () => callFunction(program, "foo", []),
    3885         e => e instanceof WTrapError);
     3879    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
    38863880    checkInt(program, callFunction(program, "foo2", [makeInt(program, 1)]), 4);
    3887     checkFail(
    3888         () => callFunction(program, "foo2", [makeInt(program, 3)]),
    3889         e => e instanceof WTrapError);
    3890     checkFail(
    3891         () => callFunction(program, "foo3", []),
    3892         e => e instanceof WTrapError);
     3881    checkTrap(program, () => callFunction(program, "foo2", [makeInt(program, 3)]), checkInt);
     3882    checkTrap(program, () => callFunction(program, "foo3", []), (progam, result, expected) => {
     3883        for (let i = 0; i < 4; i++) {
     3884            if (result.ePtr.get(i) != expected)
     3885                throw new Error(`Non-zero return value at offset ${i}`);
     3886        }
     3887    });
    38933888}
    38943889
    … …  
    46524647        }
    46534648    `);
    4654     checkFail(
    4655         () => checkInt(program, callFunction(program, "foo", []), -511),
    4656         e => e instanceof WTrapError);
     4649    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
    46574650}
    46584651
    … …  
    63476340
    63486341    program = doPrep(`
    6349         test void foo() {
     6342        test int foo() {
    63506343            thread atomic_int* x = null;
    63516344            InterlockedAdd(x, 1, null);
    6352         }
    6353     `);
    6354     checkFail(
    6355         () => callFunction(program, "foo", []),
    6356         (e) => e instanceof WTrapError);
     6345            return 1;
     6346        }
     6347    `);
     6348    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
    63576349
    63586350    program = doPrep(`
    6359         test void foo() {
     6351        test int foo() {
    63606352            thread atomic_uint* x = null;
    63616353            InterlockedAdd(x, 1, null);
    6362         }
    6363     `);
    6364     checkFail(
    6365         () => callFunction(program, "foo", []),
    6366         (e) => e instanceof WTrapError);
     6354            return 1;
     6355        }
     6356    `);
     6357    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
    63676358
    63686359    program = doPrep(`
    6369         test void foo() {
     6360        test int foo() {
    63706361            thread atomic_int* x = null;
    63716362            InterlockedAnd(x, 1, null);
    6372         }
    6373     `);
    6374     checkFail(
    6375         () => callFunction(program, "foo", []),
    6376         (e) => e instanceof WTrapError);
     6363            return 1;
     6364        }
     6365    `);
     6366    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
    63776367
    63786368    program = doPrep(`
    6379         test void foo() {
     6369        test int foo() {
    63806370            thread atomic_uint* x = null;
    63816371            InterlockedAnd(x, 1, null);
    6382         }
    6383     `);
    6384     checkFail(
    6385         () => callFunction(program, "foo", []),
    6386         (e) => e instanceof WTrapError);
     6372            return 1;
     6373        }
     6374    `);
     6375    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
    63876376
    63886377    program = doPrep(`
    6389         test void foo() {
     6378        test int foo() {
    63906379            thread atomic_int* x = null;
    63916380            InterlockedExchange(x, 1, null);
    6392         }
    6393     `);
    6394     checkFail(
    6395         () => callFunction(program, "foo", []),
    6396         (e) => e instanceof WTrapError);
     6381            return 1;
     6382        }
     6383    `);
     6384    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
    63976385
    63986386    program = doPrep(`
    6399         test void foo() {
     6387        test int foo() {
    64006388            thread atomic_uint* x = null;
    64016389            InterlockedExchange(x, 1, null);
    6402         }
    6403     `);
    6404     checkFail(
    6405         () => callFunction(program, "foo", []),
    6406         (e) => e instanceof WTrapError);
     6390            return 1;
     6391        }
     6392    `);
     6393    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
    64076394
    64086395    program = doPrep(`
    6409         test void foo() {
     6396        test int foo() {
    64106397            thread atomic_int* x = null;
    64116398            InterlockedMax(x, 1, null);
    6412         }
    6413     `);
    6414     checkFail(
    6415         () => callFunction(program, "foo", []),
    6416         (e) => e instanceof WTrapError);
     6399            return 1;
     6400        }
     6401    `);
     6402    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
    64176403
    64186404    program = doPrep(`
    6419         test void foo() {
     6405        test int foo() {
    64206406            thread atomic_uint* x = null;
    64216407            InterlockedMax(x, 1, null);
    6422         }
    6423     `);
    6424     checkFail(
    6425         () => callFunction(program, "foo", []),
    6426         (e) => e instanceof WTrapError);
     6408            return 1;
     6409        }
     6410    `);
     6411    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
    64276412
    64286413    program = doPrep(`
    6429         test void foo() {
     6414        test int foo() {
    64306415            thread atomic_int* x = null;
    64316416            InterlockedMin(x, 1, null);
    6432         }
    6433     `);
    6434     checkFail(
    6435         () => callFunction(program, "foo", []),
    6436         (e) => e instanceof WTrapError);
     6417            return 1;
     6418        }
     6419    `);
     6420    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
    64376421
    64386422    program = doPrep(`
    6439         test void foo() {
     6423        test int foo() {
    64406424            thread atomic_uint* x = null;
    64416425            InterlockedMin(x, 1, null);
    6442         }
    6443     `);
    6444     checkFail(
    6445         () => callFunction(program, "foo", []),
    6446         (e) => e instanceof WTrapError);
     6426            return 1;
     6427        }
     6428    `);
     6429    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
    64476430
    64486431    program = doPrep(`
    6449         test void foo() {
     6432        test int foo() {
    64506433            thread atomic_int* x = null;
    64516434            InterlockedOr(x, 1, null);
    6452         }
    6453     `);
    6454     checkFail(
    6455         () => callFunction(program, "foo", []),
    6456         (e) => e instanceof WTrapError);
     6435            return 1;
     6436        }
     6437    `);
     6438    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
    64576439
    64586440    program = doPrep(`
    6459         test void foo() {
     6441        test int foo() {
    64606442            thread atomic_uint* x = null;
    64616443            InterlockedOr(x, 1, null);
    6462         }
    6463     `);
    6464     checkFail(
    6465         () => callFunction(program, "foo", []),
    6466         (e) => e instanceof WTrapError);
     6444            return 1;
     6445        }
     6446    `);
     6447    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
    64676448
    64686449    program = doPrep(`
    6469         test void foo() {
     6450        test int foo() {
    64706451            thread atomic_int* x = null;
    64716452            InterlockedXor(x, 1, null);
    6472         }
    6473     `);
    6474     checkFail(
    6475         () => callFunction(program, "foo", []),
    6476         (e) => e instanceof WTrapError);
     6453            return 1;
     6454        }
     6455    `);
     6456    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
    64776457
    64786458    program = doPrep(`
    6479         test void foo() {
     6459        test int foo() {
    64806460            thread atomic_uint* x = null;
    64816461            InterlockedXor(x, 1, null);
    6482         }
    6483     `);
    6484     checkFail(
    6485         () => callFunction(program, "foo", []),
    6486         (e) => e instanceof WTrapError);
     6462            return 1;
     6463        }
     6464    `);
     6465    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
    64876466
    64886467    program = doPrep(`
    6489         test void foo() {
     6468        test int foo() {
    64906469            thread atomic_int* x = null;
    64916470            InterlockedCompareExchange(x, 1, 2, null);
    6492         }
    6493     `);
    6494     checkFail(
    6495         () => callFunction(program, "foo", []),
    6496         (e) => e instanceof WTrapError);
     6471            return 1;
     6472        }
     6473    `);
     6474    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
    64976475
    64986476    program = doPrep(`
    6499         test void foo() {
     6477        test int foo() {
    65006478            thread atomic_uint* x = null;
    65016479            InterlockedCompareExchange(x, 1, 2, null);
    6502         }
    6503     `);
    6504     checkFail(
    6505         () => callFunction(program, "foo", []),
    6506         (e) => e instanceof WTrapError);
     6480            return 1;
     6481        }
     6482    `);
     6483    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
    65076484}
    65086485
    … …  
    91569133};
    91579134
     9135tests.passingArrayToFunction = function()
     9136{
     9137    let program = doPrep(`
     9138        test int foo()
     9139        {
     9140            int[10] arr;
     9141            for (uint i = 0; i < arr.length; i++)
     9142                arr[i] = int(i) + 1;
     9143            return sum(arr);
     9144        }
     9145
     9146        int sum(int[10] xs)
     9147        {
     9148            int t = 0;
     9149            for (uint i = 0; i < xs.length; i++)
     9150                t = t + xs[i];
     9151            return t;
     9152        }
     9153    `);
     9154    checkInt(program, callFunction(program, "foo", []), 55);
     9155}
     9156
     9157tests.returnAnArrayFromAFunction = function()
     9158{
     9159    let program = doPrep(`
     9160        test int foo()
     9161        {
     9162            int[5] ys = bar();
     9163            return ys[0] + ys[1] + ys[2] + ys[3] + ys[4];
     9164        }
     9165
     9166        int[5] bar()
     9167        {
     9168            int[5] xs;
     9169            xs[0] = 1;
     9170            xs[1] = 2;
     9171            xs[2] = 3;
     9172            xs[3] = 4;
     9173            xs[4] = 5;
     9174            return xs;
     9175        }
     9176    `);
     9177}
     9178
     9179tests.copyArray = function()
     9180{
     9181    let program = doPrep(`
     9182        test int foo()
     9183        {
     9184            int[10] xs;
     9185            for (uint i = 0; i < xs.length; i++)
     9186                xs[i] = int(i) + 1;
     9187            int[10] ys = xs;
     9188            for (uint i = 0; i < xs.length; i++)
     9189                xs[i] = 0;
     9190            int sum = 0;
     9191            for (uint i = 0; i < ys.length; i++)
     9192                sum = sum + ys[i];
     9193            return sum;
     9194        }
     9195    `);
     9196    checkInt(program, callFunction(program, "foo", []), 55);
     9197}
     9198
     9199tests.settingAnArrayInsideAStruct = function()
     9200{
     9201    let program = doPrep(`
     9202        struct Foo {
     9203            int[1] array;
     9204        }
     9205        test int foo()
     9206        {
     9207            Foo foo;
     9208            thread Foo* bar = &foo;
     9209            bar->array[0] = 21;
     9210            return foo.array[0];
     9211        }
     9212    `);
     9213    checkInt(program, callFunction(program, "foo", []), 21);
     9214}
     9215
     9216tests.trapBecauseOfIndexAcesss = () => {
     9217    const program = doPrep(`
     9218        test int foo()
     9219        {
     9220            int[5] array;
     9221            array[6] = 42;
     9222            return array[6];
     9223        }
     9224    `);
     9225    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
     9226}
     9227
     9228tests.trapTransitively = () => {
     9229    const program = doPrep(`
     9230        test int foo()
     9231        {
     9232            willTrapTransitively();
     9233            return 42;
     9234        }
     9235
     9236        void willTrapTransitively()
     9237        {
     9238            doTrap();
     9239        }
     9240
     9241        void doTrap()
     9242        {
     9243            trap;
     9244        }
     9245    `);
     9246    checkTrap(program, () => callFunction(program, "foo", []), checkInt);
     9247};
     9248
    91589249okToTest = true;
    91599250
Note: See TracChangeset for help on using the changeset viewer.