/* * Copyright (C) 2015-2016 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 { struct Effects { // True if this cannot continue execution in the current block. bool terminal { 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 { 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 { false }; // 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 { false }; // True if this reads from the local state. This is only used for Phi and Get. bool readsLocalState { 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 RegisterSets. 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 { false }; bool writesPinned { false }; 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; 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; } // Returns true if reordering instructions with these respective effects would change program // behavior in an observable way. bool interferes(const Effects&) const; JS_EXPORT_PRIVATE bool operator==(const Effects&) const; JS_EXPORT_PRIVATE bool operator!=(const Effects&) const; JS_EXPORT_PRIVATE void dump(PrintStream& out) const; }; } } // namespace JSC::B3 #endif // ENABLE(B3_JIT)