diff options
Diffstat (limited to 'Source/JavaScriptCore/b3/B3Value.cpp')
-rw-r--r-- | Source/JavaScriptCore/b3/B3Value.cpp | 720 |
1 files changed, 720 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/b3/B3Value.cpp b/Source/JavaScriptCore/b3/B3Value.cpp new file mode 100644 index 000000000..ee23808b5 --- /dev/null +++ b/Source/JavaScriptCore/b3/B3Value.cpp @@ -0,0 +1,720 @@ +/* + * 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. + */ + +#include "config.h" +#include "B3Value.h" + +#if ENABLE(B3_JIT) + +#include "B3ArgumentRegValue.h" +#include "B3CCallValue.h" +#include "B3ControlValue.h" +#include "B3MemoryValue.h" +#include "B3OriginDump.h" +#include "B3ProcedureInlines.h" +#include "B3SlotBaseValue.h" +#include "B3StackSlot.h" +#include "B3UpsilonValue.h" +#include "B3ValueInlines.h" +#include "B3ValueKeyInlines.h" +#include "B3VariableValue.h" +#include <wtf/CommaPrinter.h> +#include <wtf/StringPrintStream.h> + +namespace JSC { namespace B3 { + +const char* const Value::dumpPrefix = "@"; + +Value::~Value() +{ +} + +void Value::replaceWithIdentity(Value* value) +{ + // This is a bit crazy. It does an in-place replacement of whatever Value subclass this is with + // a plain Identity Value. We first collect all of the information we need, then we destruct the + // previous value in place, and then we construct the Identity Value in place. + + ASSERT(m_type == value->m_type); + + if (m_type == Void) { + replaceWithNop(); + return; + } + + unsigned index = m_index; + Type type = m_type; + Origin origin = m_origin; + BasicBlock* owner = this->owner; + + RELEASE_ASSERT(type == value->type()); + + this->~Value(); + + new (this) Value(Identity, type, origin, value); + + this->owner = owner; + this->m_index = index; +} + +void Value::replaceWithNop() +{ + unsigned index = m_index; + Origin origin = m_origin; + BasicBlock* owner = this->owner; + + this->~Value(); + + new (this) Value(Nop, Void, origin); + + this->owner = owner; + this->m_index = index; +} + +void Value::replaceWithPhi() +{ + if (m_type == Void) { + replaceWithNop(); + return; + } + + unsigned index = m_index; + Origin origin = m_origin; + BasicBlock* owner = this->owner; + Type type = m_type; + + this->~Value(); + + new (this) Value(Phi, type, origin); + + this->owner = owner; + this->m_index = index; +} + +void Value::dump(PrintStream& out) const +{ + bool isConstant = false; + + switch (m_opcode) { + case Const32: + out.print("$", asInt32(), "("); + isConstant = true; + break; + case Const64: + out.print("$", asInt64(), "("); + isConstant = true; + break; + case ConstFloat: + out.print("$", asFloat(), "("); + isConstant = true; + break; + case ConstDouble: + out.print("$", asDouble(), "("); + isConstant = true; + break; + default: + break; + } + + out.print(dumpPrefix, m_index); + + if (isConstant) + out.print(")"); +} + +Value* Value::cloneImpl() const +{ + return new Value(*this); +} + +void Value::dumpChildren(CommaPrinter& comma, PrintStream& out) const +{ + for (Value* child : children()) + out.print(comma, pointerDump(child)); +} + +void Value::deepDump(const Procedure* proc, PrintStream& out) const +{ + out.print(m_type, " ", dumpPrefix, m_index, " = ", m_opcode); + + out.print("("); + CommaPrinter comma; + dumpChildren(comma, out); + + if (m_origin) + out.print(comma, OriginDump(proc, m_origin)); + + dumpMeta(comma, out); + + { + CString string = toCString(effects()); + if (string.length()) + out.print(comma, string); + } + + out.print(")"); +} + +Value* Value::negConstant(Procedure&) const +{ + return nullptr; +} + +Value* Value::addConstant(Procedure&, int32_t) const +{ + return nullptr; +} + +Value* Value::addConstant(Procedure&, const Value*) const +{ + return nullptr; +} + +Value* Value::subConstant(Procedure&, const Value*) const +{ + return nullptr; +} + +Value* Value::mulConstant(Procedure&, const Value*) const +{ + return nullptr; +} + +Value* Value::checkAddConstant(Procedure&, const Value*) const +{ + return nullptr; +} + +Value* Value::checkSubConstant(Procedure&, const Value*) const +{ + return nullptr; +} + +Value* Value::checkMulConstant(Procedure&, const Value*) const +{ + return nullptr; +} + +Value* Value::checkNegConstant(Procedure&) const +{ + return nullptr; +} + +Value* Value::divConstant(Procedure&, const Value*) const +{ + return nullptr; +} + +Value* Value::modConstant(Procedure&, const Value*) const +{ + return nullptr; +} + +Value* Value::bitAndConstant(Procedure&, const Value*) const +{ + return nullptr; +} + +Value* Value::bitOrConstant(Procedure&, const Value*) const +{ + return nullptr; +} + +Value* Value::bitXorConstant(Procedure&, const Value*) const +{ + return nullptr; +} + +Value* Value::shlConstant(Procedure&, const Value*) const +{ + return nullptr; +} + +Value* Value::sShrConstant(Procedure&, const Value*) const +{ + return nullptr; +} + +Value* Value::zShrConstant(Procedure&, const Value*) const +{ + return nullptr; +} + +Value* Value::bitwiseCastConstant(Procedure&) const +{ + return nullptr; +} + +Value* Value::doubleToFloatConstant(Procedure&) const +{ + return nullptr; +} + +Value* Value::floatToDoubleConstant(Procedure&) const +{ + return nullptr; +} + +Value* Value::absConstant(Procedure&) const +{ + return nullptr; +} + +Value* Value::ceilConstant(Procedure&) const +{ + return nullptr; +} + +Value* Value::floorConstant(Procedure&) const +{ + return nullptr; +} + +Value* Value::sqrtConstant(Procedure&) const +{ + return nullptr; +} + +TriState Value::equalConstant(const Value*) const +{ + return MixedTriState; +} + +TriState Value::notEqualConstant(const Value*) const +{ + return MixedTriState; +} + +TriState Value::lessThanConstant(const Value*) const +{ + return MixedTriState; +} + +TriState Value::greaterThanConstant(const Value*) const +{ + return MixedTriState; +} + +TriState Value::lessEqualConstant(const Value*) const +{ + return MixedTriState; +} + +TriState Value::greaterEqualConstant(const Value*) const +{ + return MixedTriState; +} + +TriState Value::aboveConstant(const Value*) const +{ + return MixedTriState; +} + +TriState Value::belowConstant(const Value*) const +{ + return MixedTriState; +} + +TriState Value::aboveEqualConstant(const Value*) const +{ + return MixedTriState; +} + +TriState Value::belowEqualConstant(const Value*) const +{ + return MixedTriState; +} + +TriState Value::equalOrUnorderedConstant(const Value*) const +{ + return MixedTriState; +} + +Value* Value::invertedCompare(Procedure& proc) const +{ + if (!numChildren()) + return nullptr; + if (Optional<Opcode> invertedOpcode = B3::invertedCompare(opcode(), child(0)->type())) + return proc.add<Value>(*invertedOpcode, type(), origin(), children()); + return nullptr; +} + +bool Value::isRounded() const +{ + ASSERT(isFloat(type())); + switch (opcode()) { + case Floor: + case Ceil: + case IToD: + return true; + + case ConstDouble: { + double value = asDouble(); + return std::isfinite(value) && value == ceil(value); + } + + case ConstFloat: { + float value = asFloat(); + return std::isfinite(value) && value == ceilf(value); + } + + default: + return false; + } +} + +bool Value::returnsBool() const +{ + if (type() != Int32) + return false; + switch (opcode()) { + case Const32: + return asInt32() == 0 || asInt32() == 1; + case BitAnd: + return child(1)->isInt32(1) + || (child(0)->returnsBool() && child(1)->hasInt() && child(1)->asInt() & 1); + case Equal: + case NotEqual: + case LessThan: + case GreaterThan: + case LessEqual: + case GreaterEqual: + case Above: + case Below: + case AboveEqual: + case BelowEqual: + case EqualOrUnordered: + return true; + case Phi: + // FIXME: We should have a story here. + // https://bugs.webkit.org/show_bug.cgi?id=150725 + return false; + default: + return false; + } +} + +TriState Value::asTriState() const +{ + switch (opcode()) { + case Const32: + return triState(!!asInt32()); + case Const64: + return triState(!!asInt64()); + case ConstDouble: + // Use "!= 0" to really emphasize what this mean with respect to NaN and such. + return triState(asDouble() != 0); + case ConstFloat: + return triState(asFloat() != 0.); + default: + return MixedTriState; + } +} + +Effects Value::effects() const +{ + Effects result; + switch (opcode()) { + case Nop: + case Identity: + case Const32: + case Const64: + case ConstDouble: + case ConstFloat: + case SlotBase: + case ArgumentReg: + case FramePointer: + case Add: + case Sub: + case Mul: + case Neg: + case ChillDiv: + case ChillMod: + case BitAnd: + case BitOr: + case BitXor: + case Shl: + case SShr: + case ZShr: + case Clz: + case Abs: + case Ceil: + case Floor: + case Sqrt: + case BitwiseCast: + case SExt8: + case SExt16: + case SExt32: + case ZExt32: + case Trunc: + case IToD: + case FloatToDouble: + case DoubleToFloat: + case Equal: + case NotEqual: + case LessThan: + case GreaterThan: + case LessEqual: + case GreaterEqual: + case Above: + case Below: + case AboveEqual: + case BelowEqual: + case EqualOrUnordered: + case Select: + break; + case Div: + case Mod: + result.controlDependent = true; + break; + case Load8Z: + case Load8S: + case Load16Z: + case Load16S: + case Load: + result.reads = as<MemoryValue>()->range(); + result.controlDependent = true; + break; + case Store8: + case Store16: + case Store: + result.writes = as<MemoryValue>()->range(); + result.controlDependent = true; + break; + case CCall: + result = as<CCallValue>()->effects; + break; + case Patchpoint: + result = as<PatchpointValue>()->effects; + break; + case CheckAdd: + case CheckSub: + case CheckMul: + case Check: + result.exitsSideways = true; + // The program could read anything after exiting, and it's on us to declare this. + result.reads = HeapRange::top(); + break; + case Upsilon: + case Set: + result.writesLocalState = true; + break; + case Phi: + case Get: + result.readsLocalState = true; + break; + case Jump: + case Branch: + case Switch: + case Return: + case Oops: + result.terminal = true; + break; + } + return result; +} + +ValueKey Value::key() const +{ + switch (opcode()) { + case FramePointer: + return ValueKey(opcode(), type()); + case Identity: + case Abs: + case Ceil: + case Floor: + case Sqrt: + case SExt8: + case SExt16: + case SExt32: + case ZExt32: + case Clz: + case Trunc: + case IToD: + case FloatToDouble: + case DoubleToFloat: + case Check: + case BitwiseCast: + case Neg: + return ValueKey(opcode(), type(), child(0)); + case Add: + case Sub: + case Mul: + case Div: + case Mod: + case ChillDiv: + case ChillMod: + case BitAnd: + case BitOr: + case BitXor: + case Shl: + case SShr: + case ZShr: + case Equal: + case NotEqual: + case LessThan: + case GreaterThan: + case Above: + case Below: + case AboveEqual: + case BelowEqual: + case EqualOrUnordered: + case CheckAdd: + case CheckSub: + case CheckMul: + return ValueKey(opcode(), type(), child(0), child(1)); + case Select: + return ValueKey(opcode(), type(), child(0), child(1), child(2)); + case Const32: + return ValueKey(Const32, type(), static_cast<int64_t>(asInt32())); + case Const64: + return ValueKey(Const64, type(), asInt64()); + case ConstDouble: + return ValueKey(ConstDouble, type(), asDouble()); + case ConstFloat: + return ValueKey(ConstFloat, type(), asFloat()); + case ArgumentReg: + return ValueKey( + ArgumentReg, type(), + static_cast<int64_t>(as<ArgumentRegValue>()->argumentReg().index())); + case SlotBase: + return ValueKey( + SlotBase, type(), + static_cast<int64_t>(as<SlotBaseValue>()->slot()->index())); + default: + return ValueKey(); + } +} + +void Value::performSubstitution() +{ + for (Value*& child : children()) { + while (child->opcode() == Identity) + child = child->child(0); + } +} + +void Value::dumpMeta(CommaPrinter&, PrintStream&) const +{ +} + +#if !ASSERT_DISABLED +void Value::checkOpcode(Opcode opcode) +{ + ASSERT(!ArgumentRegValue::accepts(opcode)); + ASSERT(!CCallValue::accepts(opcode)); + ASSERT(!CheckValue::accepts(opcode)); + ASSERT(!Const32Value::accepts(opcode)); + ASSERT(!Const64Value::accepts(opcode)); + ASSERT(!ConstDoubleValue::accepts(opcode)); + ASSERT(!ConstFloatValue::accepts(opcode)); + ASSERT(!ControlValue::accepts(opcode)); + ASSERT(!MemoryValue::accepts(opcode)); + ASSERT(!PatchpointValue::accepts(opcode)); + ASSERT(!SlotBaseValue::accepts(opcode)); + ASSERT(!UpsilonValue::accepts(opcode)); + ASSERT(!VariableValue::accepts(opcode)); +} +#endif // !ASSERT_DISABLED + +Type Value::typeFor(Opcode opcode, Value* firstChild, Value* secondChild) +{ + switch (opcode) { + case Identity: + case Add: + case Sub: + case Mul: + case Div: + case Mod: + case Neg: + case ChillDiv: + case ChillMod: + case BitAnd: + case BitOr: + case BitXor: + case Shl: + case SShr: + case ZShr: + case Clz: + case Abs: + case Ceil: + case Floor: + case Sqrt: + case CheckAdd: + case CheckSub: + case CheckMul: + return firstChild->type(); + case FramePointer: + return pointerType(); + case SExt8: + case SExt16: + case Trunc: + case Equal: + case NotEqual: + case LessThan: + case GreaterThan: + case LessEqual: + case GreaterEqual: + case Above: + case Below: + case AboveEqual: + case BelowEqual: + case EqualOrUnordered: + return Int32; + case SExt32: + case ZExt32: + return Int64; + case FloatToDouble: + case IToD: + return Double; + case DoubleToFloat: + return Float; + case BitwiseCast: + switch (firstChild->type()) { + case Int64: + return Double; + case Double: + return Int64; + case Int32: + return Float; + case Float: + return Int32; + case Void: + ASSERT_NOT_REACHED(); + } + return Void; + case Nop: + return Void; + case Select: + ASSERT(secondChild); + return secondChild->type(); + default: + RELEASE_ASSERT_NOT_REACHED(); + } +} + +} } // namespace JSC::B3 + +#endif // ENABLE(B3_JIT) |