File: B3Effects.h

package info (click to toggle)
webkit2gtk 2.51.1-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 455,340 kB
  • sloc: cpp: 3,865,253; javascript: 197,710; ansic: 165,177; python: 49,241; asm: 21,868; ruby: 18,095; perl: 16,926; xml: 4,623; sh: 2,409; yacc: 2,356; java: 2,019; lex: 1,330; pascal: 372; makefile: 210
file content (139 lines) | stat: -rw-r--r-- 6,174 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/*
 * Copyright (C) 2015-2017 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. 
 */

#pragma once

#if ENABLE(B3_JIT)

#include "B3HeapRange.h"
#include <wtf/PrintStream.h>

namespace JSC { namespace B3 {

enum class Mutability : uint8_t {
    Mutable,
    Immutable,
};

struct Effects {
    // True if this cannot continue execution in the current block.
    bool terminal : 1 { false };

    // True if this value can cause execution to terminate abruptly, and that this abrupt termination is
    // observable. An example of how this gets used is to limit the hoisting of controlDependent values.
    // Note that if exitsSideways is set to true but reads is bottom, then B3 is free to assume that
    // after abrupt termination of this procedure, none of the heap will be read. That's usually false,
    // so make sure that reads corresponds to the set of things that are readable after this function
    // terminates abruptly.
    bool exitsSideways : 1 { false };

    // True if the instruction may change semantics if hoisted above some control flow. For example,
    // loads are usually control-dependent because we must assume that any control construct (either
    // a terminal like Branch or anything that exits sideways, like Check) validates whether the
    // pointer is valid. Hoisting the load above control may cause the load to trap even though it
    // would not have otherwise trapped.
    bool controlDependent : 1 { false };

    // Mutability::Immutable if the instruction is readings an immutable value. This read itself can
    // be control dependent, but once it succeeds, the subsequent code must be producing the same value.
    // CSE leverages this information and eliminate redundant loads when the target and preceding load
    // are the same and Mutability::Immutable.
    Mutability readsMutability : 1 { Mutability::Mutable };

    // True if this writes to the local state. Operations that write local state don't write to anything
    // in "memory" but they have a side-effect anyway. This is for modeling Upsilons, Sets, and Fences.
    // This is a way of saying: even though this operation is not a terminal, does not exit sideways,
    // and does not write to the heap, you still cannot kill this operation.
    bool writesLocalState : 1 { false };

    // True if this reads from the local state. This is only used for Phi and Get.
    bool readsLocalState : 1 { false };

    // B3 understands things about pinned registers. Therefore, it needs to know who reads them and
    // who writes them. We don't track this on a per-register basis because that would be harder and
    // we don't need it. Note that if you want to construct an immutable pinned register while also
    // having other pinned registers that are mutable, then you can use ArgumentReg. Also note that
    // nobody will stop you from making this get out-of-sync with your clobbered register sets in
    // Patchpoint. It's recommended that you err on the side of being conservative.
    // FIXME: Explore making these be RegisterSetBuilders. That's mainly hard because it would be awkward to
    // reconcile with StackmapValue's support for clobbered regs.
    // https://bugs.webkit.org/show_bug.cgi?id=163173
    bool readsPinned : 1 { false };
    bool writesPinned : 1 { false };

    // Memory fences cannot be reordered around each other regardless of their effects. This is flagged
    // if the operation is a memory fence.
    bool fence : 1 { false };

    // WARNING: The B3::hoistLoopInvariantValues() phase thinks that it understands this exhaustively. If you
    // add any new kinds of things that can be read or written, you should check that phase.

    HeapRange writes;
    HeapRange reads;

    static Effects none()
    {
        return Effects();
    }

    static Effects forCall()
    {
        Effects result;
        result.exitsSideways = true;
        result.controlDependent = true;
        result.writes = HeapRange::top();
        result.reads = HeapRange::top();
        result.readsPinned = true;
        result.writesPinned = true;
        result.fence = true;
        return result;
    }
    
    static Effects forCheck()
    {
        Effects result;
        result.exitsSideways = true;
        // The program could read anything after exiting, and it's on us to declare this.
        result.reads = HeapRange::top();
        return result;
    }

    bool mustExecute() const
    {
        return terminal || exitsSideways || writesLocalState || writes || writesPinned || fence;
    }

    // Returns true if reordering instructions with these respective effects would change program
    // behavior in an observable way.
    bool interferes(const Effects&) const;
    
    friend bool operator==(const Effects&, const Effects&) = default;

    JS_EXPORT_PRIVATE void dump(PrintStream& out) const;
};

} } // namespace JSC::B3

#endif // ENABLE(B3_JIT)