diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp')
-rw-r--r-- | Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp | 4515 |
1 files changed, 0 insertions, 4515 deletions
diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp deleted file mode 100644 index be2a40c7d..000000000 --- a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp +++ /dev/null @@ -1,4515 +0,0 @@ -/* - * Copyright (C) 2013 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 "FTLLowerDFGToLLVM.h" - -#if ENABLE(FTL_JIT) - -#include "CodeBlockWithJITType.h" -#include "DFGAbstractInterpreterInlines.h" -#include "DFGInPlaceAbstractState.h" -#include "FTLAbstractHeapRepository.h" -#include "FTLForOSREntryJITCode.h" -#include "FTLFormattedValue.h" -#include "FTLInlineCacheSize.h" -#include "FTLLoweredNodeValue.h" -#include "FTLOutput.h" -#include "FTLThunks.h" -#include "LinkBuffer.h" -#include "OperandsInlines.h" -#include "Operations.h" -#include "VirtualRegister.h" -#include <atomic> -#include <wtf/ProcessID.h> - -namespace JSC { namespace FTL { - -using namespace DFG; - -static std::atomic<int> compileCounter; - -// Using this instead of typeCheck() helps to reduce the load on LLVM, by creating -// significantly less dead code. -#define FTL_TYPE_CHECK(lowValue, highValue, typesPassedThrough, failCondition) do { \ - FormattedValue _ftc_lowValue = (lowValue); \ - Edge _ftc_highValue = (highValue); \ - SpeculatedType _ftc_typesPassedThrough = (typesPassedThrough); \ - if (!m_interpreter.needsTypeCheck(_ftc_highValue, _ftc_typesPassedThrough)) \ - break; \ - typeCheck(_ftc_lowValue, _ftc_highValue, _ftc_typesPassedThrough, (failCondition)); \ - } while (false) - -class LowerDFGToLLVM { -public: - LowerDFGToLLVM(State& state) - : m_graph(state.graph) - , m_ftlState(state) - , m_heaps(state.context) - , m_out(state.context) - , m_availability(OperandsLike, state.graph.block(0)->variablesAtHead) - , m_state(state.graph) - , m_interpreter(state.graph, m_state) - , m_stackmapIDs(0) - { - } - - void lower() - { - CString name; - if (verboseCompilationEnabled()) { - name = toCString( - "jsBody_", ++compileCounter, "_", codeBlock()->inferredName(), - "_", codeBlock()->hash()); - } else - name = "jsBody"; - - m_graph.m_dominators.computeIfNecessary(m_graph); - - m_ftlState.module = - llvm->ModuleCreateWithNameInContext(name.data(), m_ftlState.context); - - m_ftlState.function = addFunction( - m_ftlState.module, name.data(), functionType(m_out.int64, m_out.intPtr)); - setFunctionCallingConv(m_ftlState.function, LLVMCCallConv); - - m_out.initialize(m_ftlState.module, m_ftlState.function, m_heaps); - - m_prologue = appendBasicBlock(m_ftlState.context, m_ftlState.function); - m_out.appendTo(m_prologue); - createPhiVariables(); - - m_callFrame = m_out.param(0); - m_tagTypeNumber = m_out.constInt64(TagTypeNumber); - m_tagMask = m_out.constInt64(TagMask); - - for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) { - m_highBlock = m_graph.block(blockIndex); - if (!m_highBlock) - continue; - m_blocks.add(m_highBlock, FTL_NEW_BLOCK(m_out, ("Block ", *m_highBlock))); - } - - m_out.appendTo(m_prologue); - m_out.jump(lowBlock(m_graph.block(0))); - - Vector<BasicBlock*> depthFirst; - m_graph.getBlocksInDepthFirstOrder(depthFirst); - for (unsigned i = 0; i < depthFirst.size(); ++i) - compileBlock(depthFirst[i]); - - if (Options::dumpLLVMIR()) - dumpModule(m_ftlState.module); - - if (verboseCompilationEnabled()) - m_ftlState.dumpState("after lowering"); - if (validationEnabled()) - verifyModule(m_ftlState.module); - } - -private: - - void createPhiVariables() - { - for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { - BasicBlock* block = m_graph.block(blockIndex); - if (!block) - continue; - for (unsigned nodeIndex = block->size(); nodeIndex--;) { - Node* node = block->at(nodeIndex); - if (node->op() != Phi) - continue; - LType type; - switch (node->flags() & NodeResultMask) { - case NodeResultNumber: - type = m_out.doubleType; - break; - case NodeResultInt32: - type = m_out.int32; - break; - case NodeResultInt52: - type = m_out.int64; - break; - case NodeResultBoolean: - type = m_out.boolean; - break; - case NodeResultJS: - type = m_out.int64; - break; - default: - RELEASE_ASSERT_NOT_REACHED(); - break; - } - m_phis.add(node, buildAlloca(m_out.m_builder, type)); - } - } - } - - void compileBlock(BasicBlock* block) - { - if (!block) - return; - - if (verboseCompilationEnabled()) - dataLog("Compiling block ", *block, "\n"); - - m_highBlock = block; - - LBasicBlock lowBlock = m_blocks.get(m_highBlock); - - m_nextHighBlock = 0; - for (BlockIndex nextBlockIndex = m_highBlock->index + 1; nextBlockIndex < m_graph.numBlocks(); ++nextBlockIndex) { - m_nextHighBlock = m_graph.block(nextBlockIndex); - if (m_nextHighBlock) - break; - } - m_nextLowBlock = m_nextHighBlock ? m_blocks.get(m_nextHighBlock) : 0; - - // All of this effort to find the next block gives us the ability to keep the - // generated IR in roughly program order. This ought not affect the performance - // of the generated code (since we expect LLVM to reorder things) but it will - // make IR dumps easier to read. - m_out.appendTo(lowBlock, m_nextLowBlock); - - if (Options::ftlCrashes()) - m_out.crashNonTerminal(); - - if (!m_highBlock->cfaHasVisited) { - m_out.crash(); - return; - } - - initializeOSRExitStateForBlock(); - - m_state.reset(); - m_state.beginBasicBlock(m_highBlock); - - for (m_nodeIndex = 0; m_nodeIndex < m_highBlock->size(); ++m_nodeIndex) { - if (!compileNode(m_nodeIndex)) - break; - } - } - - bool compileNode(unsigned nodeIndex) - { - if (!m_state.isValid()) { - m_out.unreachable(); - return false; - } - - m_node = m_highBlock->at(nodeIndex); - m_codeOriginForExitProfile = m_node->codeOrigin; - m_codeOriginForExitTarget = m_node->codeOriginForExitTarget; - - if (verboseCompilationEnabled()) - dataLog("Lowering ", m_node, "\n"); - - bool shouldExecuteEffects = m_interpreter.startExecuting(m_node); - - switch (m_node->op()) { - case Upsilon: - compileUpsilon(); - break; - case Phi: - compilePhi(); - break; - case JSConstant: - break; - case WeakJSConstant: - compileWeakJSConstant(); - break; - case GetArgument: - compileGetArgument(); - break; - case ExtractOSREntryLocal: - compileExtractOSREntryLocal(); - break; - case GetLocal: - compileGetLocal(); - break; - case SetLocal: - compileSetLocal(); - break; - case MovHint: - compileMovHint(); - break; - case ZombieHint: - compileZombieHint(); - break; - case Phantom: - compilePhantom(); - break; - case ValueAdd: - compileValueAdd(); - break; - case ArithAdd: - compileAddSub(); - break; - case ArithSub: - compileAddSub(); - break; - case ArithMul: - compileArithMul(); - break; - case ArithDiv: - compileArithDivMod(); - break; - case ArithMod: - compileArithDivMod(); - break; - case ArithMin: - case ArithMax: - compileArithMinOrMax(); - break; - case ArithAbs: - compileArithAbs(); - break; - case ArithNegate: - compileArithNegate(); - break; - case BitAnd: - compileBitAnd(); - break; - case BitOr: - compileBitOr(); - break; - case BitXor: - compileBitXor(); - break; - case BitRShift: - compileBitRShift(); - break; - case BitLShift: - compileBitLShift(); - break; - case BitURShift: - compileBitURShift(); - break; - case UInt32ToNumber: - compileUInt32ToNumber(); - break; - case Int32ToDouble: - compileInt32ToDouble(); - break; - case CheckStructure: - compileCheckStructure(); - break; - case StructureTransitionWatchpoint: - compileStructureTransitionWatchpoint(); - break; - case CheckFunction: - compileCheckFunction(); - break; - case ArrayifyToStructure: - compileArrayifyToStructure(); - break; - case PutStructure: - compilePutStructure(); - break; - case PhantomPutStructure: - compilePhantomPutStructure(); - break; - case GetById: - compileGetById(); - break; - case PutById: - compilePutById(); - break; - case GetButterfly: - compileGetButterfly(); - break; - case ConstantStoragePointer: - compileConstantStoragePointer(); - break; - case GetIndexedPropertyStorage: - compileGetIndexedPropertyStorage(); - break; - case CheckArray: - compileCheckArray(); - break; - case GetArrayLength: - compileGetArrayLength(); - break; - case CheckInBounds: - compileCheckInBounds(); - break; - case GetByVal: - compileGetByVal(); - break; - case PutByVal: - case PutByValAlias: - case PutByValDirect: - compilePutByVal(); - break; - case NewObject: - compileNewObject(); - break; - case NewArray: - compileNewArray(); - break; - case NewArrayBuffer: - compileNewArrayBuffer(); - break; - case AllocatePropertyStorage: - compileAllocatePropertyStorage(); - break; - case StringCharAt: - compileStringCharAt(); - break; - case StringCharCodeAt: - compileStringCharCodeAt(); - break; - case GetByOffset: - compileGetByOffset(); - break; - case PutByOffset: - compilePutByOffset(); - break; - case GetGlobalVar: - compileGetGlobalVar(); - break; - case PutGlobalVar: - compilePutGlobalVar(); - break; - case NotifyWrite: - compileNotifyWrite(); - break; - case GetMyScope: - compileGetMyScope(); - break; - case SkipScope: - compileSkipScope(); - break; - case GetClosureRegisters: - compileGetClosureRegisters(); - break; - case GetClosureVar: - compileGetClosureVar(); - break; - case PutClosureVar: - compilePutClosureVar(); - break; - case CompareEq: - compileCompareEq(); - break; - case CompareEqConstant: - compileCompareEqConstant(); - break; - case CompareStrictEq: - compileCompareStrictEq(); - break; - case CompareStrictEqConstant: - compileCompareStrictEqConstant(); - break; - case CompareLess: - compileCompareLess(); - break; - case CompareLessEq: - compileCompareLessEq(); - break; - case CompareGreater: - compileCompareGreater(); - break; - case CompareGreaterEq: - compileCompareGreaterEq(); - break; - case LogicalNot: - compileLogicalNot(); - break; - case Call: - case Construct: - compileCallOrConstruct(); - break; - case Jump: - compileJump(); - break; - case Branch: - compileBranch(); - break; - case Switch: - compileSwitch(); - break; - case Return: - compileReturn(); - break; - case ForceOSRExit: - compileForceOSRExit(); - break; - case InvalidationPoint: - compileInvalidationPoint(); - break; - case ValueToInt32: - compileValueToInt32(); - break; - case Int52ToValue: - compileInt52ToValue(); - break; - case StoreBarrier: - compileStoreBarrier(); - break; - case ConditionalStoreBarrier: - compileConditionalStoreBarrier(); - break; - case StoreBarrierWithNullCheck: - compileStoreBarrierWithNullCheck(); - break; - case Flush: - case PhantomLocal: - case SetArgument: - case LoopHint: - case VariableWatchpoint: - case FunctionReentryWatchpoint: - case TypedArrayWatchpoint: - break; - default: - RELEASE_ASSERT_NOT_REACHED(); - break; - } - - if (shouldExecuteEffects) - m_interpreter.executeEffects(nodeIndex); - - return true; - } - - void compileValueToInt32() - { - switch (m_node->child1().useKind()) { - case Int32Use: - setInt32(lowInt32(m_node->child1())); - break; - - case MachineIntUse: - setInt32(m_out.castToInt32(lowStrictInt52(m_node->child1()))); - break; - - case NumberUse: - case NotCellUse: { - LoweredNodeValue value = m_int32Values.get(m_node->child1().node()); - if (isValid(value)) { - setInt32(value.value()); - break; - } - - value = m_jsValueValues.get(m_node->child1().node()); - if (isValid(value)) { - LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("ValueToInt32 int case")); - LBasicBlock notIntCase = FTL_NEW_BLOCK(m_out, ("ValueToInt32 not int case")); - LBasicBlock doubleCase = 0; - LBasicBlock notNumberCase = 0; - if (m_node->child1().useKind() == NotCellUse) { - doubleCase = FTL_NEW_BLOCK(m_out, ("ValueToInt32 double case")); - notNumberCase = FTL_NEW_BLOCK(m_out, ("ValueToInt32 not number case")); - } - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ValueToInt32 continuation")); - - Vector<ValueFromBlock> results; - - m_out.branch(isNotInt32(value.value()), notIntCase, intCase); - - LBasicBlock lastNext = m_out.appendTo(intCase, notIntCase); - results.append(m_out.anchor(unboxInt32(value.value()))); - m_out.jump(continuation); - - if (m_node->child1().useKind() == NumberUse) { - m_out.appendTo(notIntCase, continuation); - FTL_TYPE_CHECK( - jsValueValue(value.value()), m_node->child1(), SpecFullNumber, - isCellOrMisc(value.value())); - results.append(m_out.anchor(doubleToInt32(unboxDouble(value.value())))); - m_out.jump(continuation); - } else { - m_out.appendTo(notIntCase, doubleCase); - m_out.branch(isCellOrMisc(value.value()), notNumberCase, doubleCase); - - m_out.appendTo(doubleCase, notNumberCase); - results.append(m_out.anchor(doubleToInt32(unboxDouble(value.value())))); - m_out.jump(continuation); - - m_out.appendTo(notNumberCase, continuation); - - FTL_TYPE_CHECK( - jsValueValue(value.value()), m_node->child1(), ~SpecCell, - isCell(value.value())); - - LValue specialResult = m_out.select( - m_out.equal( - value.value(), - m_out.constInt64(JSValue::encode(jsBoolean(true)))), - m_out.int32One, m_out.int32Zero); - results.append(m_out.anchor(specialResult)); - m_out.jump(continuation); - } - - m_out.appendTo(continuation, lastNext); - setInt32(m_out.phi(m_out.int32, results)); - break; - } - - value = m_doubleValues.get(m_node->child1().node()); - if (isValid(value)) { - setInt32(doubleToInt32(value.value())); - break; - } - - terminate(Uncountable); - break; - } - - case BooleanUse: - setInt32(m_out.zeroExt(lowBoolean(m_node->child1()), m_out.int32)); - break; - - default: - RELEASE_ASSERT_NOT_REACHED(); - break; - } - } - - void compileInt52ToValue() - { - setJSValue(lowJSValue(m_node->child1())); - } - - void compileStoreBarrier() - { - emitStoreBarrier(lowCell(m_node->child1())); - } - - void compileConditionalStoreBarrier() - { - LValue base = lowCell(m_node->child1()); - LValue value = lowJSValue(m_node->child2()); - emitStoreBarrier(base, value, m_node->child2()); - } - - void compileStoreBarrierWithNullCheck() - { -#if ENABLE(GGC) - LBasicBlock isNotNull = FTL_NEW_BLOCK(m_out, ("Store barrier with null check value not null")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Store barrier continuation")); - - LValue base = lowJSValue(m_node->child1()); - m_out.branch(m_out.isZero64(base), continuation, isNotNull); - LBasicBlock lastNext = m_out.appendTo(isNotNull, continuation); - emitStoreBarrier(base); - m_out.appendTo(continuation, lastNext); -#else - speculate(m_node->child1()); -#endif - } - - void compileUpsilon() - { - LValue destination = m_phis.get(m_node->phi()); - - switch (m_node->child1().useKind()) { - case NumberUse: - m_out.set(lowDouble(m_node->child1()), destination); - break; - case Int32Use: - m_out.set(lowInt32(m_node->child1()), destination); - break; - case MachineIntUse: - m_out.set(lowInt52(m_node->child1()), destination); - break; - case BooleanUse: - m_out.set(lowBoolean(m_node->child1()), destination); - break; - case CellUse: - m_out.set(lowCell(m_node->child1()), destination); - break; - case UntypedUse: - m_out.set(lowJSValue(m_node->child1()), destination); - break; - default: - RELEASE_ASSERT_NOT_REACHED(); - break; - } - } - - void compilePhi() - { - LValue source = m_phis.get(m_node); - - switch (m_node->flags() & NodeResultMask) { - case NodeResultNumber: - setDouble(m_out.get(source)); - break; - case NodeResultInt32: - setInt32(m_out.get(source)); - break; - case NodeResultInt52: - setInt52(m_out.get(source)); - break; - case NodeResultBoolean: - setBoolean(m_out.get(source)); - break; - case NodeResultJS: - setJSValue(m_out.get(source)); - break; - default: - RELEASE_ASSERT_NOT_REACHED(); - break; - } - } - - void compileWeakJSConstant() - { - setJSValue(weakPointer(m_node->weakConstant())); - } - - void compileGetArgument() - { - VariableAccessData* variable = m_node->variableAccessData(); - VirtualRegister operand = variable->machineLocal(); - RELEASE_ASSERT(operand.isArgument()); - - LValue jsValue = m_out.load64(addressFor(operand)); - - switch (useKindFor(variable->flushFormat())) { - case Int32Use: - speculate(BadType, jsValueValue(jsValue), m_node, isNotInt32(jsValue)); - setInt32(unboxInt32(jsValue)); - break; - case CellUse: - speculate(BadType, jsValueValue(jsValue), m_node, isNotCell(jsValue)); - setJSValue(jsValue); - break; - case BooleanUse: - speculate(BadType, jsValueValue(jsValue), m_node, isNotBoolean(jsValue)); - setBoolean(unboxBoolean(jsValue)); - break; - case UntypedUse: - setJSValue(jsValue); - break; - default: - RELEASE_ASSERT_NOT_REACHED(); - break; - } - } - - void compileExtractOSREntryLocal() - { - EncodedJSValue* buffer = static_cast<EncodedJSValue*>( - m_ftlState.jitCode->ftlForOSREntry()->entryBuffer()->dataBuffer()); - setJSValue(m_out.load64(m_out.absolute(buffer + m_node->unlinkedLocal().toLocal()))); - } - - void compileGetLocal() - { - // GetLocals arise only for captured variables. - - VariableAccessData* variable = m_node->variableAccessData(); - AbstractValue& value = m_state.variables().operand(variable->local()); - - RELEASE_ASSERT(variable->isCaptured()); - - if (isInt32Speculation(value.m_type)) - setInt32(m_out.load32(payloadFor(variable->machineLocal()))); - else - setJSValue(m_out.load64(addressFor(variable->machineLocal()))); - } - - void compileSetLocal() - { - VariableAccessData* variable = m_node->variableAccessData(); - switch (variable->flushFormat()) { - case FlushedJSValue: { - LValue value = lowJSValue(m_node->child1()); - m_out.store64(value, addressFor(variable->machineLocal())); - break; - } - - case FlushedDouble: { - LValue value = lowDouble(m_node->child1()); - m_out.storeDouble(value, addressFor(variable->machineLocal())); - break; - } - - case FlushedInt32: { - LValue value = lowInt32(m_node->child1()); - m_out.store32(value, payloadFor(variable->machineLocal())); - break; - } - - case FlushedInt52: { - LValue value = lowInt52(m_node->child1()); - m_out.store64(value, addressFor(variable->machineLocal())); - break; - } - - case FlushedCell: { - LValue value = lowCell(m_node->child1()); - m_out.store64(value, addressFor(variable->machineLocal())); - break; - } - - case FlushedBoolean: { - speculateBoolean(m_node->child1()); - m_out.store64( - lowJSValue(m_node->child1(), ManualOperandSpeculation), - addressFor(variable->machineLocal())); - break; - } - - default: - RELEASE_ASSERT_NOT_REACHED(); - break; - } - - m_availability.operand(variable->local()) = Availability(variable->flushedAt()); - } - - void compileMovHint() - { - ASSERT(m_node->containsMovHint()); - ASSERT(m_node->op() != ZombieHint); - - VirtualRegister operand = m_node->unlinkedLocal(); - m_availability.operand(operand) = Availability(m_node->child1().node()); - } - - void compileZombieHint() - { - m_availability.operand(m_node->unlinkedLocal()) = Availability::unavailable(); - } - - void compilePhantom() - { - DFG_NODE_DO_TO_CHILDREN(m_graph, m_node, speculate); - } - - void compileValueAdd() - { - J_JITOperation_EJJ operation; - if (!(m_state.forNode(m_node->child1()).m_type & SpecFullNumber) - && !(m_state.forNode(m_node->child2()).m_type & SpecFullNumber)) - operation = operationValueAddNotNumber; - else - operation = operationValueAdd; - setJSValue(vmCall( - m_out.operation(operation), m_callFrame, - lowJSValue(m_node->child1()), lowJSValue(m_node->child2()))); - } - - void compileAddSub() - { - bool isSub = m_node->op() == ArithSub; - switch (m_node->binaryUseKind()) { - case Int32Use: { - LValue left = lowInt32(m_node->child1()); - LValue right = lowInt32(m_node->child2()); - LValue result = isSub ? m_out.sub(left, right) : m_out.add(left, right); - - if (!shouldCheckOverflow(m_node->arithMode())) { - setInt32(result); - break; - } - - LValue overflow = isSub ? m_out.subWithOverflow32(left, right) : m_out.addWithOverflow32(left, right); - - speculate(Overflow, noValue(), 0, m_out.extractValue(overflow, 1)); - setInt32(result); - break; - } - - case MachineIntUse: { - if (!m_state.forNode(m_node->child1()).couldBeType(SpecInt52) - && !m_state.forNode(m_node->child2()).couldBeType(SpecInt52)) { - Int52Kind kind; - LValue left = lowWhicheverInt52(m_node->child1(), kind); - LValue right = lowInt52(m_node->child2(), kind); - setInt52(isSub ? m_out.sub(left, right) : m_out.add(left, right), kind); - break; - } - - LValue left = lowInt52(m_node->child1()); - LValue right = lowInt52(m_node->child2()); - LValue result = isSub ? m_out.sub(left, right) : m_out.add(left, right); - - LValue overflow = isSub ? m_out.subWithOverflow64(left, right) : m_out.addWithOverflow64(left, right); - speculate(Int52Overflow, noValue(), 0, m_out.extractValue(overflow, 1)); - setInt52(result); - break; - } - - case NumberUse: { - LValue C1 = lowDouble(m_node->child1()); - LValue C2 = lowDouble(m_node->child2()); - - setDouble(isSub ? m_out.doubleSub(C1, C2) : m_out.doubleAdd(C1, C2)); - break; - } - - default: - RELEASE_ASSERT_NOT_REACHED(); - break; - } - } - - void compileArithMul() - { - switch (m_node->binaryUseKind()) { - case Int32Use: { - LValue left = lowInt32(m_node->child1()); - LValue right = lowInt32(m_node->child2()); - LValue result = m_out.mul(left, right); - - if (shouldCheckOverflow(m_node->arithMode())) { - LValue overflowResult = m_out.mulWithOverflow32(left, right); - speculate(Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1)); - } - - if (shouldCheckNegativeZero(m_node->arithMode())) { - LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("ArithMul slow case")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMul continuation")); - - m_out.branch(m_out.notZero32(result), continuation, slowCase); - - LBasicBlock lastNext = m_out.appendTo(slowCase, continuation); - LValue cond = m_out.bitOr(m_out.lessThan(left, m_out.int32Zero), m_out.lessThan(right, m_out.int32Zero)); - speculate(NegativeZero, noValue(), 0, cond); - m_out.jump(continuation); - m_out.appendTo(continuation, lastNext); - } - - setInt32(result); - break; - } - - case MachineIntUse: { - Int52Kind kind; - LValue left = lowWhicheverInt52(m_node->child1(), kind); - LValue right = lowInt52(m_node->child2(), opposite(kind)); - LValue result = m_out.mul(left, right); - - - LValue overflowResult = m_out.mulWithOverflow64(left, right); - speculate(Int52Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1)); - - if (shouldCheckNegativeZero(m_node->arithMode())) { - LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("ArithMul slow case")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMul continuation")); - - m_out.branch(m_out.notZero64(result), continuation, slowCase); - - LBasicBlock lastNext = m_out.appendTo(slowCase, continuation); - LValue cond = m_out.bitOr(m_out.lessThan(left, m_out.int64Zero), m_out.lessThan(right, m_out.int64Zero)); - speculate(NegativeZero, noValue(), 0, cond); - m_out.jump(continuation); - m_out.appendTo(continuation, lastNext); - } - - setInt52(result); - break; - } - - case NumberUse: { - setDouble( - m_out.doubleMul(lowDouble(m_node->child1()), lowDouble(m_node->child2()))); - break; - } - - default: - RELEASE_ASSERT_NOT_REACHED(); - break; - } - } - - void compileArithDivMod() - { - switch (m_node->binaryUseKind()) { - case Int32Use: { - LValue numerator = lowInt32(m_node->child1()); - LValue denominator = lowInt32(m_node->child2()); - - LBasicBlock unsafeDenominator = FTL_NEW_BLOCK(m_out, ("ArithDivMod unsafe denominator")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithDivMod continuation")); - LBasicBlock done = FTL_NEW_BLOCK(m_out, ("ArithDivMod done")); - - Vector<ValueFromBlock, 3> results; - - LValue adjustedDenominator = m_out.add(denominator, m_out.int32One); - - m_out.branch(m_out.above(adjustedDenominator, m_out.int32One), continuation, unsafeDenominator); - - LBasicBlock lastNext = m_out.appendTo(unsafeDenominator, continuation); - - LValue neg2ToThe31 = m_out.constInt32(-2147483647-1); - - if (shouldCheckOverflow(m_node->arithMode())) { - LValue cond = m_out.bitOr(m_out.isZero32(denominator), m_out.equal(numerator, neg2ToThe31)); - speculate(Overflow, noValue(), 0, cond); - m_out.jump(continuation); - } else { - // This is the case where we convert the result to an int after we're done. So, - // if the denominator is zero, then the result should be zero. - // If the denominator is not zero (i.e. it's -1 because we're guarded by the - // check above) and the numerator is -2^31 then the result should be -2^31. - - LBasicBlock divByZero = FTL_NEW_BLOCK(m_out, ("ArithDiv divide by zero")); - LBasicBlock notDivByZero = FTL_NEW_BLOCK(m_out, ("ArithDiv not divide by zero")); - LBasicBlock neg2ToThe31ByNeg1 = FTL_NEW_BLOCK(m_out, ("ArithDiv -2^31/-1")); - - m_out.branch(m_out.isZero32(denominator), divByZero, notDivByZero); - - m_out.appendTo(divByZero, notDivByZero); - results.append(m_out.anchor(m_out.int32Zero)); - m_out.jump(done); - - m_out.appendTo(notDivByZero, neg2ToThe31ByNeg1); - m_out.branch(m_out.equal(numerator, neg2ToThe31), neg2ToThe31ByNeg1, continuation); - - m_out.appendTo(neg2ToThe31ByNeg1, continuation); - results.append(m_out.anchor(neg2ToThe31)); - m_out.jump(done); - } - - m_out.appendTo(continuation, done); - - if (shouldCheckNegativeZero(m_node->arithMode())) { - LBasicBlock zeroNumerator = FTL_NEW_BLOCK(m_out, ("ArithDivMod zero numerator")); - LBasicBlock numeratorContinuation = FTL_NEW_BLOCK(m_out, ("ArithDivMod numerator continuation")); - - m_out.branch(m_out.isZero32(numerator), zeroNumerator, numeratorContinuation); - - LBasicBlock innerLastNext = m_out.appendTo(zeroNumerator, numeratorContinuation); - - speculate( - NegativeZero, noValue(), 0, m_out.lessThan(denominator, m_out.int32Zero)); - - m_out.jump(numeratorContinuation); - - m_out.appendTo(numeratorContinuation, innerLastNext); - } - - LValue divModResult = m_node->op() == ArithDiv - ? m_out.div(numerator, denominator) - : m_out.rem(numerator, denominator); - - if (shouldCheckOverflow(m_node->arithMode())) { - speculate( - Overflow, noValue(), 0, - m_out.notEqual(m_out.mul(divModResult, denominator), numerator)); - } - - results.append(m_out.anchor(divModResult)); - m_out.jump(done); - - m_out.appendTo(done, lastNext); - - setInt32(m_out.phi(m_out.int32, results)); - break; - } - - case NumberUse: { - LValue C1 = lowDouble(m_node->child1()); - LValue C2 = lowDouble(m_node->child2()); - setDouble(m_node->op() == ArithDiv ? m_out.doubleDiv(C1, C2) : m_out.doubleRem(C1, C2)); - break; - } - - default: - RELEASE_ASSERT_NOT_REACHED(); - break; - } - } - - void compileArithMinOrMax() - { - switch (m_node->binaryUseKind()) { - case Int32Use: { - LValue left = lowInt32(m_node->child1()); - LValue right = lowInt32(m_node->child2()); - - setInt32( - m_out.select( - m_node->op() == ArithMin - ? m_out.lessThan(left, right) - : m_out.lessThan(right, left), - left, right)); - break; - } - - case NumberUse: { - LValue left = lowDouble(m_node->child1()); - LValue right = lowDouble(m_node->child2()); - - LBasicBlock notLessThan = FTL_NEW_BLOCK(m_out, ("ArithMin/ArithMax not less than")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMin/ArithMax continuation")); - - Vector<ValueFromBlock, 2> results; - - results.append(m_out.anchor(left)); - m_out.branch( - m_node->op() == ArithMin - ? m_out.doubleLessThan(left, right) - : m_out.doubleGreaterThan(left, right), - continuation, notLessThan); - - LBasicBlock lastNext = m_out.appendTo(notLessThan, continuation); - results.append(m_out.anchor(m_out.select( - m_node->op() == ArithMin - ? m_out.doubleGreaterThanOrEqual(left, right) - : m_out.doubleLessThanOrEqual(left, right), - right, m_out.constDouble(0.0 / 0.0)))); - m_out.jump(continuation); - - m_out.appendTo(continuation, lastNext); - setDouble(m_out.phi(m_out.doubleType, results)); - break; - } - - default: - RELEASE_ASSERT_NOT_REACHED(); - break; - } - } - - void compileArithAbs() - { - switch (m_node->child1().useKind()) { - case Int32Use: { - LValue value = lowInt32(m_node->child1()); - - LValue mask = m_out.aShr(value, m_out.constInt32(31)); - LValue result = m_out.bitXor(mask, m_out.add(mask, value)); - - speculate(Overflow, noValue(), 0, m_out.equal(result, m_out.constInt32(1 << 31))); - - setInt32(result); - break; - } - - case NumberUse: { - setDouble(m_out.doubleAbs(lowDouble(m_node->child1()))); - break; - } - - default: - RELEASE_ASSERT_NOT_REACHED(); - break; - } - } - - void compileArithNegate() - { - switch (m_node->child1().useKind()) { - case Int32Use: { - LValue value = lowInt32(m_node->child1()); - - LValue result = m_out.neg(value); - if (shouldCheckOverflow(m_node->arithMode())) { - if (!shouldCheckNegativeZero(m_node->arithMode())) { - // We don't have a negate-with-overflow intrinsic. Hopefully this - // does the trick, though. - LValue overflowResult = m_out.subWithOverflow32(m_out.int32Zero, value); - speculate(Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1)); - } else - speculate(Overflow, noValue(), 0, m_out.testIsZero32(value, m_out.constInt32(0x7fffffff))); - - } - - setInt32(result); - break; - } - - case MachineIntUse: { - if (!m_state.forNode(m_node->child1()).couldBeType(SpecInt52)) { - Int52Kind kind; - LValue value = lowWhicheverInt52(m_node->child1(), kind); - LValue result = m_out.neg(value); - if (shouldCheckNegativeZero(m_node->arithMode())) - speculate(NegativeZero, noValue(), 0, m_out.isZero64(result)); - setInt52(result, kind); - break; - } - - LValue value = lowInt52(m_node->child1()); - LValue overflowResult = m_out.subWithOverflow64(m_out.int64Zero, value); - speculate(Int52Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1)); - LValue result = m_out.neg(value); - speculate(NegativeZero, noValue(), 0, m_out.isZero64(result)); - setInt52(result); - break; - } - - case NumberUse: { - setDouble(m_out.doubleNeg(lowDouble(m_node->child1()))); - break; - } - - default: - RELEASE_ASSERT_NOT_REACHED(); - break; - } - } - - void compileBitAnd() - { - setInt32(m_out.bitAnd(lowInt32(m_node->child1()), lowInt32(m_node->child2()))); - } - - void compileBitOr() - { - setInt32(m_out.bitOr(lowInt32(m_node->child1()), lowInt32(m_node->child2()))); - } - - void compileBitXor() - { - setInt32(m_out.bitXor(lowInt32(m_node->child1()), lowInt32(m_node->child2()))); - } - - void compileBitRShift() - { - setInt32(m_out.aShr( - lowInt32(m_node->child1()), - m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31)))); - } - - void compileBitLShift() - { - setInt32(m_out.shl( - lowInt32(m_node->child1()), - m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31)))); - } - - void compileBitURShift() - { - setInt32(m_out.lShr( - lowInt32(m_node->child1()), - m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31)))); - } - - void compileUInt32ToNumber() - { - LValue value = lowInt32(m_node->child1()); - - if (doesOverflow(m_node->arithMode())) { - setDouble(m_out.unsignedToDouble(value)); - return; - } - - speculate(Overflow, noValue(), 0, m_out.lessThan(value, m_out.int32Zero)); - setInt32(value); - } - - void compileInt32ToDouble() - { - setDouble(lowDouble(m_node->child1())); - } - - void compileCheckStructure() - { - LValue cell = lowCell(m_node->child1()); - - ExitKind exitKind; - if (m_node->child1()->op() == WeakJSConstant) - exitKind = BadWeakConstantCache; - else - exitKind = BadCache; - - LValue structure = m_out.loadPtr(cell, m_heaps.JSCell_structure); - - if (m_node->structureSet().size() == 1) { - speculate( - exitKind, jsValueValue(cell), 0, - m_out.notEqual(structure, weakPointer(m_node->structureSet()[0]))); - return; - } - - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("CheckStructure continuation")); - - LBasicBlock lastNext = m_out.insertNewBlocksBefore(continuation); - for (unsigned i = 0; i < m_node->structureSet().size() - 1; ++i) { - LBasicBlock nextStructure = FTL_NEW_BLOCK(m_out, ("CheckStructure nextStructure")); - m_out.branch( - m_out.equal(structure, weakPointer(m_node->structureSet()[i])), - continuation, nextStructure); - m_out.appendTo(nextStructure); - } - - speculate( - exitKind, jsValueValue(cell), 0, - m_out.notEqual(structure, weakPointer(m_node->structureSet().last()))); - - m_out.jump(continuation); - m_out.appendTo(continuation, lastNext); - } - - void compileStructureTransitionWatchpoint() - { - addWeakReference(m_node->structure()); - speculateCell(m_node->child1()); - } - - void compileCheckFunction() - { - LValue cell = lowCell(m_node->child1()); - - speculate( - BadFunction, jsValueValue(cell), m_node->child1().node(), - m_out.notEqual(cell, weakPointer(m_node->function()))); - } - - void compileArrayifyToStructure() - { - LValue cell = lowCell(m_node->child1()); - LValue property = !!m_node->child2() ? lowInt32(m_node->child2()) : 0; - - LBasicBlock unexpectedStructure = FTL_NEW_BLOCK(m_out, ("ArrayifyToStructure unexpected structure")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArrayifyToStructure continuation")); - - LValue structure = m_out.loadPtr(cell, m_heaps.JSCell_structure); - - m_out.branch( - m_out.notEqual(structure, weakPointer(m_node->structure())), - unexpectedStructure, continuation); - - LBasicBlock lastNext = m_out.appendTo(unexpectedStructure, continuation); - - if (property) { - switch (m_node->arrayMode().type()) { - case Array::Int32: - case Array::Double: - case Array::Contiguous: - speculate( - Uncountable, noValue(), 0, - m_out.aboveOrEqual(property, m_out.constInt32(MIN_SPARSE_ARRAY_INDEX))); - break; - default: - break; - } - } - - switch (m_node->arrayMode().type()) { - case Array::Int32: - vmCall(m_out.operation(operationEnsureInt32), m_callFrame, cell); - break; - case Array::Double: - vmCall(m_out.operation(operationEnsureDouble), m_callFrame, cell); - break; - case Array::Contiguous: - if (m_node->arrayMode().conversion() == Array::RageConvert) - vmCall(m_out.operation(operationRageEnsureContiguous), m_callFrame, cell); - else - vmCall(m_out.operation(operationEnsureContiguous), m_callFrame, cell); - break; - case Array::ArrayStorage: - case Array::SlowPutArrayStorage: - vmCall(m_out.operation(operationEnsureArrayStorage), m_callFrame, cell); - break; - default: - RELEASE_ASSERT_NOT_REACHED(); - break; - } - - structure = m_out.loadPtr(cell, m_heaps.JSCell_structure); - speculate( - BadIndexingType, jsValueValue(cell), 0, - m_out.notEqual(structure, weakPointer(m_node->structure()))); - m_out.jump(continuation); - - m_out.appendTo(continuation, lastNext); - } - - void compilePutStructure() - { - m_ftlState.jitCode->common.notifyCompilingStructureTransition(m_graph.m_plan, codeBlock(), m_node); - - m_out.store64( - m_out.constIntPtr(m_node->structureTransitionData().newStructure), - lowCell(m_node->child1()), m_heaps.JSCell_structure); - } - - void compilePhantomPutStructure() - { - m_ftlState.jitCode->common.notifyCompilingStructureTransition(m_graph.m_plan, codeBlock(), m_node); - } - - void compileGetById() - { - // UntypedUse is a bit harder to reason about and I'm not sure how best to do it, yet. - // Basically we need to emit a cell branch that takes you to the slow path, but the slow - // path is generated by the IC generator so we can't jump to it from here. And the IC - // generator currently doesn't know how to emit such a branch. So, for now, we just - // restrict this to CellUse. - ASSERT(m_node->child1().useKind() == CellUse); - - LValue base = lowCell(m_node->child1()); - StringImpl* uid = m_graph.identifiers()[m_node->identifierNumber()]; - - // Arguments: id, bytes, target, numArgs, args... - unsigned stackmapID = m_stackmapIDs++; - - if (Options::verboseCompilation()) - dataLog(" Emitting GetById patchpoint with stackmap #", stackmapID, "\n"); - - LValue call = m_out.call( - m_out.patchpointInt64Intrinsic(), - m_out.constInt32(stackmapID), m_out.constInt32(sizeOfGetById()), - constNull(m_out.ref8), m_out.constInt32(2), m_callFrame, base); - setInstructionCallingConvention(call, LLVMAnyRegCallConv); - setJSValue(call); - - m_ftlState.getByIds.append(GetByIdDescriptor(stackmapID, m_node->codeOrigin, uid)); - } - - void compilePutById() - { - // See above; CellUse is easier so we do only that for now. - ASSERT(m_node->child1().useKind() == CellUse); - - LValue base = lowCell(m_node->child1()); - LValue value = lowJSValue(m_node->child2()); - StringImpl* uid = m_graph.identifiers()[m_node->identifierNumber()]; - - // Arguments: id, bytes, target, numArgs, args... - unsigned stackmapID = m_stackmapIDs++; - - if (Options::verboseCompilation()) - dataLog(" Emitting PutById patchpoint with stackmap #", stackmapID, "\n"); - - LValue call = m_out.call( - m_out.patchpointVoidIntrinsic(), - m_out.constInt32(stackmapID), m_out.constInt32(sizeOfPutById()), - constNull(m_out.ref8), m_out.constInt32(3), m_callFrame, base, value); - setInstructionCallingConvention(call, LLVMAnyRegCallConv); - - m_ftlState.putByIds.append(PutByIdDescriptor( - stackmapID, m_node->codeOrigin, uid, - m_graph.executableFor(m_node->codeOrigin)->ecmaMode(), - m_node->op() == PutByIdDirect ? Direct : NotDirect)); - } - - void compileGetButterfly() - { - setStorage(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.JSObject_butterfly)); - } - - void compileConstantStoragePointer() - { - setStorage(m_out.constIntPtr(m_node->storagePointer())); - } - - void compileGetIndexedPropertyStorage() - { - LValue cell = lowCell(m_node->child1()); - - if (m_node->arrayMode().type() == Array::String) { - LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("GetIndexedPropertyStorage String slow case")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetIndexedPropertyStorage String continuation")); - - ValueFromBlock fastResult = m_out.anchor( - m_out.loadPtr(cell, m_heaps.JSString_value)); - - m_out.branch(m_out.notNull(fastResult.value()), continuation, slowPath); - - LBasicBlock lastNext = m_out.appendTo(slowPath, continuation); - - ValueFromBlock slowResult = m_out.anchor( - vmCall(m_out.operation(operationResolveRope), m_callFrame, cell)); - - m_out.jump(continuation); - - m_out.appendTo(continuation, lastNext); - - setStorage(m_out.loadPtr(m_out.phi(m_out.intPtr, fastResult, slowResult), m_heaps.StringImpl_data)); - return; - } - - setStorage(m_out.loadPtr(cell, m_heaps.JSArrayBufferView_vector)); - } - - void compileCheckArray() - { - Edge edge = m_node->child1(); - LValue cell = lowCell(edge); - - if (m_node->arrayMode().alreadyChecked(m_graph, m_node, m_state.forNode(edge))) - return; - - speculate( - BadIndexingType, jsValueValue(cell), 0, - m_out.bitNot(isArrayType(cell, m_node->arrayMode()))); - } - - void compileGetArrayLength() - { - switch (m_node->arrayMode().type()) { - case Array::Int32: - case Array::Double: - case Array::Contiguous: { - setInt32(m_out.load32(lowStorage(m_node->child2()), m_heaps.Butterfly_publicLength)); - return; - } - - case Array::String: { - LValue string = lowCell(m_node->child1()); - setInt32(m_out.load32(string, m_heaps.JSString_length)); - return; - } - - default: - if (isTypedView(m_node->arrayMode().typedArrayType())) { - setInt32( - m_out.load32(lowCell(m_node->child1()), m_heaps.JSArrayBufferView_length)); - return; - } - - RELEASE_ASSERT_NOT_REACHED(); - return; - } - } - - void compileCheckInBounds() - { - speculate( - OutOfBounds, noValue(), 0, - m_out.aboveOrEqual(lowInt32(m_node->child1()), lowInt32(m_node->child2()))); - } - - void compileGetByVal() - { - switch (m_node->arrayMode().type()) { - case Array::Int32: - case Array::Contiguous: { - LValue index = lowInt32(m_node->child2()); - LValue storage = lowStorage(m_node->child3()); - - IndexedAbstractHeap& heap = m_node->arrayMode().type() == Array::Int32 ? - m_heaps.indexedInt32Properties : m_heaps.indexedContiguousProperties; - - if (m_node->arrayMode().isInBounds()) { - LValue result = m_out.load64(baseIndex(heap, storage, index, m_node->child2())); - speculate(LoadFromHole, noValue(), 0, m_out.isZero64(result)); - setJSValue(result); - return; - } - - LValue base = lowCell(m_node->child1()); - - LBasicBlock fastCase = FTL_NEW_BLOCK(m_out, ("GetByVal int/contiguous fast case")); - LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("GetByVal int/contiguous slow case")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetByVal int/contiguous continuation")); - - m_out.branch( - m_out.aboveOrEqual( - index, m_out.load32(storage, m_heaps.Butterfly_publicLength)), - slowCase, fastCase); - - LBasicBlock lastNext = m_out.appendTo(fastCase, slowCase); - - ValueFromBlock fastResult = m_out.anchor( - m_out.load64(baseIndex(heap, storage, index, m_node->child2()))); - m_out.branch(m_out.isZero64(fastResult.value()), slowCase, continuation); - - m_out.appendTo(slowCase, continuation); - ValueFromBlock slowResult = m_out.anchor( - vmCall(m_out.operation(operationGetByValArrayInt), m_callFrame, base, index)); - m_out.jump(continuation); - - m_out.appendTo(continuation, lastNext); - setJSValue(m_out.phi(m_out.int64, fastResult, slowResult)); - return; - } - - case Array::Double: { - LValue index = lowInt32(m_node->child2()); - LValue storage = lowStorage(m_node->child3()); - - IndexedAbstractHeap& heap = m_heaps.indexedDoubleProperties; - - if (m_node->arrayMode().isInBounds()) { - LValue result = m_out.loadDouble( - baseIndex(heap, storage, index, m_node->child2())); - - if (!m_node->arrayMode().isSaneChain()) { - speculate( - LoadFromHole, noValue(), 0, - m_out.doubleNotEqualOrUnordered(result, result)); - } - setDouble(result); - break; - } - - LValue base = lowCell(m_node->child1()); - - LBasicBlock inBounds = FTL_NEW_BLOCK(m_out, ("GetByVal double in bounds")); - LBasicBlock boxPath = FTL_NEW_BLOCK(m_out, ("GetByVal double boxing")); - LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("GetByVal double slow case")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetByVal double continuation")); - - m_out.branch( - m_out.aboveOrEqual( - index, m_out.load32(storage, m_heaps.Butterfly_publicLength)), - slowCase, inBounds); - - LBasicBlock lastNext = m_out.appendTo(inBounds, boxPath); - LValue doubleValue = m_out.loadDouble( - baseIndex(heap, storage, index, m_node->child2())); - m_out.branch( - m_out.doubleNotEqualOrUnordered(doubleValue, doubleValue), slowCase, boxPath); - - m_out.appendTo(boxPath, slowCase); - ValueFromBlock fastResult = m_out.anchor(boxDouble(doubleValue)); - m_out.jump(continuation); - - m_out.appendTo(slowCase, continuation); - ValueFromBlock slowResult = m_out.anchor( - vmCall(m_out.operation(operationGetByValArrayInt), m_callFrame, base, index)); - m_out.jump(continuation); - - m_out.appendTo(continuation, lastNext); - setJSValue(m_out.phi(m_out.int64, fastResult, slowResult)); - return; - } - - case Array::Generic: { - setJSValue(vmCall( - m_out.operation(operationGetByVal), m_callFrame, - lowJSValue(m_node->child1()), lowJSValue(m_node->child2()))); - return; - } - - case Array::String: { - compileStringCharAt(); - return; - } - - default: { - LValue index = lowInt32(m_node->child2()); - LValue storage = lowStorage(m_node->child3()); - - TypedArrayType type = m_node->arrayMode().typedArrayType(); - - if (isTypedView(type)) { - TypedPointer pointer = TypedPointer( - m_heaps.typedArrayProperties, - m_out.add( - storage, - m_out.shl( - m_out.zeroExt(index, m_out.intPtr), - m_out.constIntPtr(logElementSize(type))))); - - if (isInt(type)) { - LValue result; - switch (elementSize(type)) { - case 1: - result = m_out.load8(pointer); - break; - case 2: - result = m_out.load16(pointer); - break; - case 4: - result = m_out.load32(pointer); - break; - default: - RELEASE_ASSERT_NOT_REACHED(); - } - - if (elementSize(type) < 4) { - if (isSigned(type)) - result = m_out.signExt(result, m_out.int32); - else - result = m_out.zeroExt(result, m_out.int32); - setInt32(result); - return; - } - - if (isSigned(type)) { - setInt32(result); - return; - } - - if (m_node->shouldSpeculateInt32()) { - speculate( - Overflow, noValue(), 0, m_out.lessThan(result, m_out.int32Zero)); - setInt32(result); - return; - } - - setDouble(m_out.unsignedToFP(result, m_out.doubleType)); - return; - } - - ASSERT(isFloat(type)); - - LValue result; - switch (type) { - case TypeFloat32: - result = m_out.fpCast(m_out.loadFloat(pointer), m_out.doubleType); - break; - case TypeFloat64: - result = m_out.loadDouble(pointer); - break; - default: - RELEASE_ASSERT_NOT_REACHED(); - } - - result = m_out.select( - m_out.doubleEqual(result, result), result, m_out.constDouble(QNaN)); - setDouble(result); - return; - } - - RELEASE_ASSERT_NOT_REACHED(); - return; - } } - } - - void compilePutByVal() - { - Edge child1 = m_graph.varArgChild(m_node, 0); - Edge child2 = m_graph.varArgChild(m_node, 1); - Edge child3 = m_graph.varArgChild(m_node, 2); - Edge child4 = m_graph.varArgChild(m_node, 3); - - switch (m_node->arrayMode().type()) { - case Array::Generic: { - V_JITOperation_EJJJ operation; - if (m_node->op() == PutByValDirect) { - if (m_graph.isStrictModeFor(m_node->codeOrigin)) - operation = operationPutByValDirectStrict; - else - operation = operationPutByValDirectNonStrict; - } else { - if (m_graph.isStrictModeFor(m_node->codeOrigin)) - operation = operationPutByValStrict; - else - operation = operationPutByValNonStrict; - } - - vmCall( - m_out.operation(operation), m_callFrame, - lowJSValue(child1), lowJSValue(child2), lowJSValue(child3)); - return; - } - - default: - break; - } - - LValue base = lowCell(child1); - LValue index = lowInt32(child2); - LValue storage = lowStorage(child4); - - switch (m_node->arrayMode().type()) { - case Array::Int32: - case Array::Double: - case Array::Contiguous: { - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("PutByVal continuation")); - LBasicBlock outerLastNext = m_out.appendTo(m_out.m_block, continuation); - - switch (m_node->arrayMode().type()) { - case Array::Int32: - case Array::Contiguous: { - LValue value = lowJSValue(child3, ManualOperandSpeculation); - - if (m_node->arrayMode().type() == Array::Int32) - FTL_TYPE_CHECK(jsValueValue(value), child3, SpecInt32, isNotInt32(value)); - - TypedPointer elementPointer = m_out.baseIndex( - m_node->arrayMode().type() == Array::Int32 ? - m_heaps.indexedInt32Properties : m_heaps.indexedContiguousProperties, - storage, m_out.zeroExt(index, m_out.intPtr), - m_state.forNode(child2).m_value); - - if (m_node->op() == PutByValAlias) { - m_out.store64(value, elementPointer); - break; - } - - contiguousPutByValOutOfBounds( - codeBlock()->isStrictMode() - ? operationPutByValBeyondArrayBoundsStrict - : operationPutByValBeyondArrayBoundsNonStrict, - base, storage, index, value, continuation); - - m_out.store64(value, elementPointer); - break; - } - - case Array::Double: { - LValue value = lowDouble(child3); - - FTL_TYPE_CHECK( - doubleValue(value), child3, SpecFullRealNumber, - m_out.doubleNotEqualOrUnordered(value, value)); - - TypedPointer elementPointer = m_out.baseIndex( - m_heaps.indexedDoubleProperties, - storage, m_out.zeroExt(index, m_out.intPtr), - m_state.forNode(child2).m_value); - - if (m_node->op() == PutByValAlias) { - m_out.storeDouble(value, elementPointer); - break; - } - - contiguousPutByValOutOfBounds( - codeBlock()->isStrictMode() - ? operationPutDoubleByValBeyondArrayBoundsStrict - : operationPutDoubleByValBeyondArrayBoundsNonStrict, - base, storage, index, value, continuation); - - m_out.storeDouble(value, elementPointer); - break; - } - - default: - RELEASE_ASSERT_NOT_REACHED(); - } - - m_out.jump(continuation); - m_out.appendTo(continuation, outerLastNext); - return; - } - - default: - TypedArrayType type = m_node->arrayMode().typedArrayType(); - - if (isTypedView(type)) { - TypedPointer pointer = TypedPointer( - m_heaps.typedArrayProperties, - m_out.add( - storage, - m_out.shl( - m_out.zeroExt(index, m_out.intPtr), - m_out.constIntPtr(logElementSize(type))))); - - if (isInt(type)) { - LValue intValue; - switch (child3.useKind()) { - case MachineIntUse: - case Int32Use: { - if (child3.useKind() == Int32Use) - intValue = lowInt32(child3); - else - intValue = m_out.castToInt32(lowStrictInt52(child3)); - - if (isClamped(type)) { - ASSERT(elementSize(type) == 1); - - LBasicBlock atLeastZero = FTL_NEW_BLOCK(m_out, ("PutByVal int clamp atLeastZero")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("PutByVal int clamp continuation")); - - Vector<ValueFromBlock, 2> intValues; - intValues.append(m_out.anchor(m_out.int32Zero)); - m_out.branch( - m_out.lessThan(intValue, m_out.int32Zero), - continuation, atLeastZero); - - LBasicBlock lastNext = m_out.appendTo(atLeastZero, continuation); - - intValues.append(m_out.anchor(m_out.select( - m_out.greaterThan(intValue, m_out.constInt32(255)), - m_out.constInt32(255), - intValue))); - m_out.jump(continuation); - - m_out.appendTo(continuation, lastNext); - intValue = m_out.phi(m_out.int32, intValues); - } - break; - } - - case NumberUse: { - LValue doubleValue = lowDouble(child3); - - if (isClamped(type)) { - ASSERT(elementSize(type) == 1); - - LBasicBlock atLeastZero = FTL_NEW_BLOCK(m_out, ("PutByVal double clamp atLeastZero")); - LBasicBlock withinRange = FTL_NEW_BLOCK(m_out, ("PutByVal double clamp withinRange")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("PutByVal double clamp continuation")); - - Vector<ValueFromBlock, 3> intValues; - intValues.append(m_out.anchor(m_out.int32Zero)); - m_out.branch( - m_out.doubleLessThanOrUnordered(doubleValue, m_out.doubleZero), - continuation, atLeastZero); - - LBasicBlock lastNext = m_out.appendTo(atLeastZero, withinRange); - intValues.append(m_out.anchor(m_out.constInt32(255))); - m_out.branch( - m_out.doubleGreaterThan(doubleValue, m_out.constDouble(255)), - continuation, withinRange); - - m_out.appendTo(withinRange, continuation); - intValues.append(m_out.anchor(m_out.fpToInt32(doubleValue))); - m_out.jump(continuation); - - m_out.appendTo(continuation, lastNext); - intValue = m_out.phi(m_out.int32, intValues); - } else - intValue = doubleToInt32(doubleValue); - break; - } - - default: - RELEASE_ASSERT_NOT_REACHED(); - } - - switch (elementSize(type)) { - case 1: - m_out.store8(m_out.intCast(intValue, m_out.int8), pointer); - break; - case 2: - m_out.store16(m_out.intCast(intValue, m_out.int16), pointer); - break; - case 4: - m_out.store32(intValue, pointer); - break; - default: - RELEASE_ASSERT_NOT_REACHED(); - } - - return; - } - - ASSERT(isFloat(type)); - - LValue value = lowDouble(child3); - switch (type) { - case TypeFloat32: - m_out.storeFloat(m_out.fpCast(value, m_out.floatType), pointer); - break; - case TypeFloat64: - m_out.storeDouble(value, pointer); - break; - default: - RELEASE_ASSERT_NOT_REACHED(); - } - return; - } - - RELEASE_ASSERT_NOT_REACHED(); - break; - } - } - - void compileNewObject() - { - Structure* structure = m_node->structure(); - size_t allocationSize = JSFinalObject::allocationSize(structure->inlineCapacity()); - MarkedAllocator* allocator = &vm().heap.allocatorForObjectWithoutDestructor(allocationSize); - - LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("NewObject slow path")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("NewObject continuation")); - - LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath); - - ValueFromBlock fastResult = m_out.anchor(allocateObject( - m_out.constIntPtr(allocator), m_out.constIntPtr(structure), m_out.intPtrZero, slowPath)); - - m_out.jump(continuation); - - m_out.appendTo(slowPath, continuation); - - ValueFromBlock slowResult = m_out.anchor(vmCall( - m_out.operation(operationNewObject), m_callFrame, m_out.constIntPtr(structure))); - m_out.jump(continuation); - - m_out.appendTo(continuation, lastNext); - setJSValue(m_out.phi(m_out.intPtr, fastResult, slowResult)); - } - - void compileNewArray() - { - // First speculate appropriately on all of the children. Do this unconditionally up here - // because some of the slow paths may otherwise forget to do it. It's sort of arguable - // that doing the speculations up here might be unprofitable for RA - so we can consider - // sinking this to below the allocation fast path if we find that this has a lot of - // register pressure. - for (unsigned operandIndex = 0; operandIndex < m_node->numChildren(); ++operandIndex) - speculate(m_graph.varArgChild(m_node, operandIndex)); - - JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->codeOrigin); - Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation( - m_node->indexingType()); - - RELEASE_ASSERT(structure->indexingType() == m_node->indexingType()); - - if (!globalObject->isHavingABadTime() && !hasArrayStorage(m_node->indexingType())) { - unsigned numElements = m_node->numChildren(); - - ArrayValues arrayValues = allocateJSArray(structure, numElements); - - for (unsigned operandIndex = 0; operandIndex < m_node->numChildren(); ++operandIndex) { - Edge edge = m_graph.varArgChild(m_node, operandIndex); - - switch (m_node->indexingType()) { - case ALL_BLANK_INDEXING_TYPES: - case ALL_UNDECIDED_INDEXING_TYPES: - CRASH(); - break; - - case ALL_DOUBLE_INDEXING_TYPES: - m_out.storeDouble( - lowDouble(edge), - arrayValues.butterfly, m_heaps.indexedDoubleProperties[operandIndex]); - break; - - case ALL_INT32_INDEXING_TYPES: - case ALL_CONTIGUOUS_INDEXING_TYPES: - m_out.store64( - lowJSValue(edge, ManualOperandSpeculation), - arrayValues.butterfly, - m_heaps.forIndexingType(m_node->indexingType())->at(operandIndex)); - break; - - default: - CRASH(); - } - } - - setJSValue(arrayValues.array); - return; - } - - if (!m_node->numChildren()) { - setJSValue(vmCall( - m_out.operation(operationNewEmptyArray), m_callFrame, - m_out.constIntPtr(structure))); - return; - } - - size_t scratchSize = sizeof(EncodedJSValue) * m_node->numChildren(); - ASSERT(scratchSize); - ScratchBuffer* scratchBuffer = vm().scratchBufferForSize(scratchSize); - EncodedJSValue* buffer = static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()); - - for (unsigned operandIndex = 0; operandIndex < m_node->numChildren(); ++operandIndex) { - Edge edge = m_graph.varArgChild(m_node, operandIndex); - m_out.store64( - lowJSValue(edge, ManualOperandSpeculation), - m_out.absolute(buffer + operandIndex)); - } - - m_out.storePtr( - m_out.constIntPtr(scratchSize), m_out.absolute(scratchBuffer->activeLengthPtr())); - - LValue result = vmCall( - m_out.operation(operationNewArray), m_callFrame, - m_out.constIntPtr(structure), m_out.constIntPtr(buffer), - m_out.constIntPtr(m_node->numChildren())); - - m_out.storePtr(m_out.intPtrZero, m_out.absolute(scratchBuffer->activeLengthPtr())); - - setJSValue(result); - } - - void compileNewArrayBuffer() - { - JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->codeOrigin); - Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation( - m_node->indexingType()); - - RELEASE_ASSERT(structure->indexingType() == m_node->indexingType()); - - if (!globalObject->isHavingABadTime() && !hasArrayStorage(m_node->indexingType())) { - unsigned numElements = m_node->numConstants(); - - ArrayValues arrayValues = allocateJSArray(structure, numElements); - - JSValue* data = codeBlock()->constantBuffer(m_node->startConstant()); - for (unsigned index = 0; index < m_node->numConstants(); ++index) { - int64_t value; - if (hasDouble(m_node->indexingType())) - value = bitwise_cast<int64_t>(data[index].asNumber()); - else - value = JSValue::encode(data[index]); - - m_out.store64( - m_out.constInt64(value), - arrayValues.butterfly, - m_heaps.forIndexingType(m_node->indexingType())->at(index)); - } - - setJSValue(arrayValues.array); - return; - } - - setJSValue(vmCall( - m_out.operation(operationNewArrayBuffer), m_callFrame, - m_out.constIntPtr(structure), m_out.constIntPtr(m_node->startConstant()), - m_out.constIntPtr(m_node->numConstants()))); - } - - void compileAllocatePropertyStorage() - { - StructureTransitionData& data = m_node->structureTransitionData(); - - LValue object = lowCell(m_node->child1()); - - if (data.previousStructure->couldHaveIndexingHeader()) { - setStorage(vmCall( - m_out.operation( - operationReallocateButterflyToHavePropertyStorageWithInitialCapacity), - m_callFrame, object)); - return; - } - - LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("AllocatePropertyStorage slow path")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("AllocatePropertyStorage continuation")); - - LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath); - - LValue endOfStorage = allocateBasicStorageAndGetEnd( - m_out.constIntPtr(initialOutOfLineCapacity * sizeof(JSValue)), slowPath); - - ValueFromBlock fastButterfly = m_out.anchor( - m_out.add(m_out.constIntPtr(sizeof(IndexingHeader)), endOfStorage)); - - m_out.jump(continuation); - - m_out.appendTo(slowPath, continuation); - - ValueFromBlock slowButterfly = m_out.anchor(vmCall( - m_out.operation(operationAllocatePropertyStorageWithInitialCapacity), m_callFrame)); - - m_out.jump(continuation); - - m_out.appendTo(continuation, lastNext); - - LValue result = m_out.phi(m_out.intPtr, fastButterfly, slowButterfly); - m_out.storePtr(result, object, m_heaps.JSObject_butterfly); - - setStorage(result); - } - - void compileStringCharAt() - { - LValue base = lowCell(m_node->child1()); - LValue index = lowInt32(m_node->child2()); - LValue storage = lowStorage(m_node->child3()); - - LBasicBlock fastPath = FTL_NEW_BLOCK(m_out, ("GetByVal String fast path")); - LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("GetByVal String slow path")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetByVal String continuation")); - - m_out.branch( - m_out.aboveOrEqual( - index, m_out.load32(base, m_heaps.JSString_length)), - slowPath, fastPath); - - LBasicBlock lastNext = m_out.appendTo(fastPath, slowPath); - - LValue stringImpl = m_out.loadPtr(base, m_heaps.JSString_value); - - LBasicBlock is8Bit = FTL_NEW_BLOCK(m_out, ("GetByVal String 8-bit case")); - LBasicBlock is16Bit = FTL_NEW_BLOCK(m_out, ("GetByVal String 16-bit case")); - LBasicBlock bitsContinuation = FTL_NEW_BLOCK(m_out, ("GetByVal String bitness continuation")); - LBasicBlock bigCharacter = FTL_NEW_BLOCK(m_out, ("GetByVal String big character")); - - m_out.branch( - m_out.testIsZero32( - m_out.load32(stringImpl, m_heaps.StringImpl_hashAndFlags), - m_out.constInt32(StringImpl::flagIs8Bit())), - is16Bit, is8Bit); - - m_out.appendTo(is8Bit, is16Bit); - - ValueFromBlock char8Bit = m_out.anchor(m_out.zeroExt( - m_out.load8(m_out.baseIndex( - m_heaps.characters8, - storage, m_out.zeroExt(index, m_out.intPtr), - m_state.forNode(m_node->child2()).m_value)), - m_out.int32)); - m_out.jump(bitsContinuation); - - m_out.appendTo(is16Bit, bigCharacter); - - ValueFromBlock char16Bit = m_out.anchor(m_out.zeroExt( - m_out.load16(m_out.baseIndex( - m_heaps.characters16, - storage, m_out.zeroExt(index, m_out.intPtr), - m_state.forNode(m_node->child2()).m_value)), - m_out.int32)); - m_out.branch(m_out.aboveOrEqual(char16Bit.value(), m_out.constInt32(0x100)), bigCharacter, bitsContinuation); - - m_out.appendTo(bigCharacter, bitsContinuation); - - Vector<ValueFromBlock, 4> results; - results.append(m_out.anchor(vmCall( - m_out.operation(operationSingleCharacterString), - m_callFrame, char16Bit.value()))); - m_out.jump(continuation); - - m_out.appendTo(bitsContinuation, slowPath); - - LValue character = m_out.phi(m_out.int32, char8Bit, char16Bit); - - LValue smallStrings = m_out.constIntPtr(vm().smallStrings.singleCharacterStrings()); - - results.append(m_out.anchor(m_out.loadPtr(m_out.baseIndex( - m_heaps.singleCharacterStrings, smallStrings, - m_out.zeroExt(character, m_out.intPtr))))); - m_out.jump(continuation); - - m_out.appendTo(slowPath, continuation); - - if (m_node->arrayMode().isInBounds()) { - speculate(OutOfBounds, noValue(), 0, m_out.booleanTrue); - results.append(m_out.anchor(m_out.intPtrZero)); - } else { - JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->codeOrigin); - - if (globalObject->stringPrototypeChainIsSane()) { - LBasicBlock negativeIndex = FTL_NEW_BLOCK(m_out, ("GetByVal String negative index")); - - results.append(m_out.anchor(m_out.constInt64(JSValue::encode(jsUndefined())))); - m_out.branch(m_out.lessThan(index, m_out.int32Zero), negativeIndex, continuation); - - m_out.appendTo(negativeIndex, continuation); - } - - results.append(m_out.anchor(vmCall( - m_out.operation(operationGetByValStringInt), m_callFrame, base, index))); - } - - m_out.jump(continuation); - - m_out.appendTo(continuation, lastNext); - setJSValue(m_out.phi(m_out.int64, results)); - } - - void compileStringCharCodeAt() - { - LBasicBlock is8Bit = FTL_NEW_BLOCK(m_out, ("StringCharCodeAt 8-bit case")); - LBasicBlock is16Bit = FTL_NEW_BLOCK(m_out, ("StringCharCodeAt 16-bit case")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("StringCharCodeAt continuation")); - - LValue base = lowCell(m_node->child1()); - LValue index = lowInt32(m_node->child2()); - LValue storage = lowStorage(m_node->child3()); - - speculate( - Uncountable, noValue(), 0, - m_out.aboveOrEqual(index, m_out.load32(base, m_heaps.JSString_length))); - - LValue stringImpl = m_out.loadPtr(base, m_heaps.JSString_value); - - m_out.branch( - m_out.testIsZero32( - m_out.load32(stringImpl, m_heaps.StringImpl_hashAndFlags), - m_out.constInt32(StringImpl::flagIs8Bit())), - is16Bit, is8Bit); - - LBasicBlock lastNext = m_out.appendTo(is8Bit, is16Bit); - - ValueFromBlock char8Bit = m_out.anchor(m_out.zeroExt( - m_out.load8(m_out.baseIndex( - m_heaps.characters8, - storage, m_out.zeroExt(index, m_out.intPtr), - m_state.forNode(m_node->child2()).m_value)), - m_out.int32)); - m_out.jump(continuation); - - m_out.appendTo(is16Bit, continuation); - - ValueFromBlock char16Bit = m_out.anchor(m_out.zeroExt( - m_out.load16(m_out.baseIndex( - m_heaps.characters16, - storage, m_out.zeroExt(index, m_out.intPtr), - m_state.forNode(m_node->child2()).m_value)), - m_out.int32)); - m_out.jump(continuation); - - m_out.appendTo(continuation, lastNext); - - setInt32(m_out.phi(m_out.int32, char8Bit, char16Bit)); - } - - void compileGetByOffset() - { - StorageAccessData& data = - m_graph.m_storageAccessData[m_node->storageAccessDataIndex()]; - - setJSValue( - m_out.load64( - m_out.address( - m_heaps.properties[data.identifierNumber], - lowStorage(m_node->child1()), - offsetRelativeToBase(data.offset)))); - } - - void compilePutByOffset() - { - StorageAccessData& data = - m_graph.m_storageAccessData[m_node->storageAccessDataIndex()]; - - m_out.store64( - lowJSValue(m_node->child3()), - m_out.address( - m_heaps.properties[data.identifierNumber], - lowStorage(m_node->child1()), - offsetRelativeToBase(data.offset))); - } - - void compileGetGlobalVar() - { - setJSValue(m_out.load64(m_out.absolute(m_node->registerPointer()))); - } - - void compilePutGlobalVar() - { - m_out.store64( - lowJSValue(m_node->child1()), m_out.absolute(m_node->registerPointer())); - } - - void compileNotifyWrite() - { - VariableWatchpointSet* set = m_node->variableWatchpointSet(); - - LValue value = lowJSValue(m_node->child1()); - - LBasicBlock isNotInvalidated = FTL_NEW_BLOCK(m_out, ("NotifyWrite not invalidated case")); - LBasicBlock isClear = FTL_NEW_BLOCK(m_out, ("NotifyWrite clear case")); - LBasicBlock isWatched = FTL_NEW_BLOCK(m_out, ("NotifyWrite watched case")); - LBasicBlock invalidate = FTL_NEW_BLOCK(m_out, ("NotifyWrite invalidate case")); - LBasicBlock invalidateFast = FTL_NEW_BLOCK(m_out, ("NotifyWrite invalidate fast case")); - LBasicBlock invalidateSlow = FTL_NEW_BLOCK(m_out, ("NotifyWrite invalidate slow case")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("NotifyWrite continuation")); - - LValue state = m_out.load8(m_out.absolute(set->addressOfState())); - - m_out.branch( - m_out.equal(state, m_out.constInt8(IsInvalidated)), - continuation, isNotInvalidated); - - LBasicBlock lastNext = m_out.appendTo(isNotInvalidated, isClear); - - LValue isClearValue; - if (set->state() == ClearWatchpoint) - isClearValue = m_out.equal(state, m_out.constInt8(ClearWatchpoint)); - else - isClearValue = m_out.booleanFalse; - m_out.branch(isClearValue, isClear, isWatched); - - m_out.appendTo(isClear, isWatched); - - m_out.store64(value, m_out.absolute(set->addressOfInferredValue())); - m_out.store8(m_out.constInt8(IsWatched), m_out.absolute(set->addressOfState())); - m_out.jump(continuation); - - m_out.appendTo(isWatched, invalidate); - - m_out.branch( - m_out.equal(value, m_out.load64(m_out.absolute(set->addressOfInferredValue()))), - continuation, invalidate); - - m_out.appendTo(invalidate, invalidateFast); - - m_out.branch( - m_out.notZero8(m_out.load8(m_out.absolute(set->addressOfSetIsNotEmpty()))), - invalidateSlow, invalidateFast); - - m_out.appendTo(invalidateFast, invalidateSlow); - - m_out.store64( - m_out.constInt64(JSValue::encode(JSValue())), - m_out.absolute(set->addressOfInferredValue())); - m_out.store8(m_out.constInt8(IsInvalidated), m_out.absolute(set->addressOfState())); - m_out.jump(continuation); - - m_out.appendTo(invalidateSlow, continuation); - - vmCall(m_out.operation(operationInvalidate), m_callFrame, m_out.constIntPtr(set)); - m_out.jump(continuation); - - m_out.appendTo(continuation, lastNext); - } - - void compileGetMyScope() - { - setJSValue(m_out.loadPtr(addressFor( - m_node->codeOrigin.stackOffset() + JSStack::ScopeChain))); - } - - void compileSkipScope() - { - setJSValue(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.JSScope_next)); - } - - void compileGetClosureRegisters() - { - if (WriteBarrierBase<Unknown>* registers = m_graph.tryGetRegisters(m_node->child1().node())) { - setStorage(m_out.constIntPtr(registers)); - return; - } - - setStorage(m_out.loadPtr( - lowCell(m_node->child1()), m_heaps.JSVariableObject_registers)); - } - - void compileGetClosureVar() - { - setJSValue(m_out.load64( - addressFor(lowStorage(m_node->child1()), m_node->varNumber()))); - } - - void compilePutClosureVar() - { - m_out.store64( - lowJSValue(m_node->child3()), - addressFor(lowStorage(m_node->child2()), m_node->varNumber())); - } - - void compileCompareEq() - { - if (m_node->isBinaryUseKind(Int32Use) - || m_node->isBinaryUseKind(MachineIntUse) - || m_node->isBinaryUseKind(NumberUse) - || m_node->isBinaryUseKind(ObjectUse)) { - compileCompareStrictEq(); - return; - } - - if (m_node->isBinaryUseKind(UntypedUse)) { - nonSpeculativeCompare(LLVMIntEQ, operationCompareEq); - return; - } - - RELEASE_ASSERT_NOT_REACHED(); - } - - void compileCompareEqConstant() - { - ASSERT(m_graph.valueOfJSConstant(m_node->child2().node()).isNull()); - setBoolean( - equalNullOrUndefined( - m_node->child1(), AllCellsAreFalse, EqualNullOrUndefined)); - } - - void compileCompareStrictEq() - { - if (m_node->isBinaryUseKind(Int32Use)) { - setBoolean( - m_out.equal(lowInt32(m_node->child1()), lowInt32(m_node->child2()))); - return; - } - - if (m_node->isBinaryUseKind(MachineIntUse)) { - Int52Kind kind; - LValue left = lowWhicheverInt52(m_node->child1(), kind); - LValue right = lowInt52(m_node->child2(), kind); - setBoolean(m_out.equal(left, right)); - return; - } - - if (m_node->isBinaryUseKind(NumberUse)) { - setBoolean( - m_out.doubleEqual(lowDouble(m_node->child1()), lowDouble(m_node->child2()))); - return; - } - - if (m_node->isBinaryUseKind(ObjectUse)) { - setBoolean( - m_out.equal( - lowNonNullObject(m_node->child1()), - lowNonNullObject(m_node->child2()))); - return; - } - - RELEASE_ASSERT_NOT_REACHED(); - } - - void compileCompareStrictEqConstant() - { - JSValue constant = m_graph.valueOfJSConstant(m_node->child2().node()); - - if (constant.isUndefinedOrNull() - && !masqueradesAsUndefinedWatchpointIsStillValid()) { - if (constant.isNull()) { - setBoolean(equalNullOrUndefined(m_node->child1(), AllCellsAreFalse, EqualNull)); - return; - } - - ASSERT(constant.isUndefined()); - setBoolean(equalNullOrUndefined(m_node->child1(), AllCellsAreFalse, EqualUndefined)); - return; - } - - setBoolean( - m_out.equal( - lowJSValue(m_node->child1()), - m_out.constInt64(JSValue::encode(constant)))); - } - - void compileCompareLess() - { - compare(LLVMIntSLT, LLVMRealOLT, operationCompareLess); - } - - void compileCompareLessEq() - { - compare(LLVMIntSLE, LLVMRealOLE, operationCompareLessEq); - } - - void compileCompareGreater() - { - compare(LLVMIntSGT, LLVMRealOGT, operationCompareGreater); - } - - void compileCompareGreaterEq() - { - compare(LLVMIntSGE, LLVMRealOGE, operationCompareGreaterEq); - } - - void compileLogicalNot() - { - setBoolean(m_out.bitNot(boolify(m_node->child1()))); - } - - void compileCallOrConstruct() - { - // FIXME: This is unacceptably slow. - // https://bugs.webkit.org/show_bug.cgi?id=113621 - - J_JITOperation_E function = - m_node->op() == Call ? operationFTLCall : operationFTLConstruct; - - int dummyThisArgument = m_node->op() == Call ? 0 : 1; - - int numPassedArgs = m_node->numChildren() - 1; - - LValue calleeFrame = m_out.add( - m_callFrame, - m_out.constIntPtr(sizeof(Register) * virtualRegisterForLocal(m_graph.frameRegisterCount()).offset())); - - m_out.store32( - m_out.constInt32(numPassedArgs + dummyThisArgument), - payloadFor(calleeFrame, JSStack::ArgumentCount)); - m_out.store64(m_callFrame, calleeFrame, m_heaps.CallFrame_callerFrame); - m_out.store64( - lowJSValue(m_graph.varArgChild(m_node, 0)), - addressFor(calleeFrame, JSStack::Callee)); - - for (int i = 0; i < numPassedArgs; ++i) { - m_out.store64( - lowJSValue(m_graph.varArgChild(m_node, 1 + i)), - addressFor(calleeFrame, virtualRegisterForArgument(i + dummyThisArgument).offset())); - } - - setJSValue(vmCall(m_out.operation(function), calleeFrame)); - } - - void compileJump() - { - m_out.jump(lowBlock(m_node->takenBlock())); - } - - void compileBranch() - { - m_out.branch( - boolify(m_node->child1()), - lowBlock(m_node->takenBlock()), - lowBlock(m_node->notTakenBlock())); - } - - void compileSwitch() - { - SwitchData* data = m_node->switchData(); - switch (data->kind) { - case SwitchImm: { - Vector<ValueFromBlock, 2> intValues; - LBasicBlock switchOnInts = FTL_NEW_BLOCK(m_out, ("Switch/SwitchImm int case")); - - LBasicBlock lastNext = m_out.appendTo(m_out.m_block, switchOnInts); - - switch (m_node->child1().useKind()) { - case Int32Use: { - intValues.append(m_out.anchor(lowInt32(m_node->child1()))); - m_out.jump(switchOnInts); - break; - } - - case UntypedUse: { - LBasicBlock isInt = FTL_NEW_BLOCK(m_out, ("Switch/SwitchImm is int")); - LBasicBlock isNotInt = FTL_NEW_BLOCK(m_out, ("Switch/SwitchImm is not int")); - LBasicBlock isDouble = FTL_NEW_BLOCK(m_out, ("Switch/SwitchImm is double")); - - LValue boxedValue = lowJSValue(m_node->child1()); - m_out.branch(isNotInt32(boxedValue), isNotInt, isInt); - - LBasicBlock innerLastNext = m_out.appendTo(isInt, isNotInt); - - intValues.append(m_out.anchor(unboxInt32(boxedValue))); - m_out.jump(switchOnInts); - - m_out.appendTo(isNotInt, isDouble); - m_out.branch( - isCellOrMisc(boxedValue), lowBlock(data->fallThrough), isDouble); - - m_out.appendTo(isDouble, innerLastNext); - LValue doubleValue = unboxDouble(boxedValue); - LValue intInDouble = m_out.fpToInt32(doubleValue); - intValues.append(m_out.anchor(intInDouble)); - m_out.branch( - m_out.doubleEqual(m_out.intToDouble(intInDouble), doubleValue), - switchOnInts, lowBlock(data->fallThrough)); - break; - } - - default: - RELEASE_ASSERT_NOT_REACHED(); - break; - } - - m_out.appendTo(switchOnInts, lastNext); - buildSwitch(data, m_out.int32, m_out.phi(m_out.int32, intValues)); - return; - } - - case SwitchChar: { - LValue stringValue; - - switch (m_node->child1().useKind()) { - case StringUse: { - stringValue = lowString(m_node->child1()); - break; - } - - case UntypedUse: { - LValue unboxedValue = lowJSValue(m_node->child1()); - - LBasicBlock isCellCase = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar is cell")); - LBasicBlock isStringCase = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar is string")); - - m_out.branch( - isNotCell(unboxedValue), lowBlock(data->fallThrough), isCellCase); - - LBasicBlock lastNext = m_out.appendTo(isCellCase, isStringCase); - LValue cellValue = unboxedValue; - m_out.branch(isNotString(cellValue), lowBlock(data->fallThrough), isStringCase); - - m_out.appendTo(isStringCase, lastNext); - stringValue = cellValue; - break; - } - - default: - RELEASE_ASSERT_NOT_REACHED(); - break; - } - - LBasicBlock lengthIs1 = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar length is 1")); - LBasicBlock needResolution = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar resolution")); - LBasicBlock resolved = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar resolved")); - LBasicBlock is8Bit = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar 8bit")); - LBasicBlock is16Bit = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar 16bit")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar continuation")); - - m_out.branch( - m_out.notEqual( - m_out.load32(stringValue, m_heaps.JSString_length), - m_out.int32One), - lowBlock(data->fallThrough), lengthIs1); - - LBasicBlock lastNext = m_out.appendTo(lengthIs1, needResolution); - Vector<ValueFromBlock, 2> values; - LValue fastValue = m_out.loadPtr(stringValue, m_heaps.JSString_value); - values.append(m_out.anchor(fastValue)); - m_out.branch(m_out.isNull(fastValue), needResolution, resolved); - - m_out.appendTo(needResolution, resolved); - values.append(m_out.anchor( - vmCall(m_out.operation(operationResolveRope), m_callFrame, stringValue))); - m_out.jump(resolved); - - m_out.appendTo(resolved, is8Bit); - LValue value = m_out.phi(m_out.intPtr, values); - LValue characterData = m_out.loadPtr(value, m_heaps.StringImpl_data); - m_out.branch( - m_out.testNonZero32( - m_out.load32(value, m_heaps.StringImpl_hashAndFlags), - m_out.constInt32(StringImpl::flagIs8Bit())), - is8Bit, is16Bit); - - Vector<ValueFromBlock, 2> characters; - m_out.appendTo(is8Bit, is16Bit); - characters.append(m_out.anchor( - m_out.zeroExt(m_out.load8(characterData, m_heaps.characters8[0]), m_out.int16))); - m_out.jump(continuation); - - m_out.appendTo(is16Bit, continuation); - characters.append(m_out.anchor(m_out.load16(characterData, m_heaps.characters16[0]))); - m_out.jump(continuation); - - m_out.appendTo(continuation, lastNext); - buildSwitch(data, m_out.int16, m_out.phi(m_out.int16, characters)); - return; - } - - case SwitchString: - RELEASE_ASSERT_NOT_REACHED(); - break; - } - - RELEASE_ASSERT_NOT_REACHED(); - } - - void compileReturn() - { - // FIXME: have a real epilogue when we switch to using our calling convention. - // https://bugs.webkit.org/show_bug.cgi?id=113621 - m_out.ret(lowJSValue(m_node->child1())); - } - - void compileForceOSRExit() - { - terminate(InadequateCoverage); - } - - void compileInvalidationPoint() - { - if (verboseCompilationEnabled()) - dataLog(" Invalidation point with availability: ", m_availability, "\n"); - - m_ftlState.jitCode->osrExit.append(OSRExit( - UncountableInvalidation, InvalidValueFormat, MethodOfGettingAValueProfile(), - m_codeOriginForExitTarget, m_codeOriginForExitProfile, - m_availability.numberOfArguments(), m_availability.numberOfLocals())); - m_ftlState.finalizer->osrExit.append(OSRExitCompilationInfo()); - - OSRExit& exit = m_ftlState.jitCode->osrExit.last(); - OSRExitCompilationInfo& info = m_ftlState.finalizer->osrExit.last(); - - ExitArgumentList arguments; - - buildExitArguments(exit, arguments, FormattedValue(), exit.m_codeOrigin); - callStackmap(exit, arguments); - - info.m_isInvalidationPoint = true; - } - - TypedPointer baseIndex(IndexedAbstractHeap& heap, LValue storage, LValue index, Edge edge) - { - return m_out.baseIndex( - heap, storage, m_out.zeroExt(index, m_out.intPtr), - m_state.forNode(edge).m_value); - } - - void compare( - LIntPredicate intCondition, LRealPredicate realCondition, - S_JITOperation_EJJ helperFunction) - { - if (m_node->isBinaryUseKind(Int32Use)) { - LValue left = lowInt32(m_node->child1()); - LValue right = lowInt32(m_node->child2()); - setBoolean(m_out.icmp(intCondition, left, right)); - return; - } - - if (m_node->isBinaryUseKind(MachineIntUse)) { - Int52Kind kind; - LValue left = lowWhicheverInt52(m_node->child1(), kind); - LValue right = lowInt52(m_node->child2(), kind); - setBoolean(m_out.icmp(intCondition, left, right)); - return; - } - - if (m_node->isBinaryUseKind(NumberUse)) { - LValue left = lowDouble(m_node->child1()); - LValue right = lowDouble(m_node->child2()); - setBoolean(m_out.fcmp(realCondition, left, right)); - return; - } - - if (m_node->isBinaryUseKind(UntypedUse)) { - nonSpeculativeCompare(intCondition, helperFunction); - return; - } - - RELEASE_ASSERT_NOT_REACHED(); - } - - void nonSpeculativeCompare(LIntPredicate intCondition, S_JITOperation_EJJ helperFunction) - { - LValue left = lowJSValue(m_node->child1()); - LValue right = lowJSValue(m_node->child2()); - - LBasicBlock leftIsInt = FTL_NEW_BLOCK(m_out, ("CompareEq untyped left is int")); - LBasicBlock fastPath = FTL_NEW_BLOCK(m_out, ("CompareEq untyped fast path")); - LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("CompareEq untyped slow path")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("CompareEq untyped continuation")); - - m_out.branch(isNotInt32(left), slowPath, leftIsInt); - - LBasicBlock lastNext = m_out.appendTo(leftIsInt, fastPath); - m_out.branch(isNotInt32(right), slowPath, fastPath); - - m_out.appendTo(fastPath, slowPath); - ValueFromBlock fastResult = m_out.anchor( - m_out.icmp(intCondition, unboxInt32(left), unboxInt32(right))); - m_out.jump(continuation); - - m_out.appendTo(slowPath, continuation); - ValueFromBlock slowResult = m_out.anchor(m_out.notNull(vmCall( - m_out.operation(helperFunction), m_callFrame, left, right))); - m_out.jump(continuation); - - m_out.appendTo(continuation, lastNext); - setBoolean(m_out.phi(m_out.boolean, fastResult, slowResult)); - } - - LValue allocateCell(LValue allocator, LValue structure, LBasicBlock slowPath) - { - LBasicBlock success = FTL_NEW_BLOCK(m_out, ("object allocation success")); - - LValue result = m_out.loadPtr( - allocator, m_heaps.MarkedAllocator_freeListHead); - - m_out.branch(m_out.notNull(result), success, slowPath); - - m_out.appendTo(success); - - m_out.storePtr( - m_out.loadPtr(result, m_heaps.JSCell_freeListNext), - allocator, m_heaps.MarkedAllocator_freeListHead); - - m_out.storePtr(structure, result, m_heaps.JSCell_structure); - - return result; - } - - LValue allocateObject( - LValue allocator, LValue structure, LValue butterfly, LBasicBlock slowPath) - { - LValue result = allocateCell(allocator, structure, slowPath); - m_out.storePtr(butterfly, result, m_heaps.JSObject_butterfly); - return result; - } - - template<typename ClassType> - LValue allocateObject(LValue structure, LValue butterfly, LBasicBlock slowPath) - { - MarkedAllocator* allocator; - size_t size = ClassType::allocationSize(0); - if (ClassType::needsDestruction && ClassType::hasImmortalStructure) - allocator = &vm().heap.allocatorForObjectWithImmortalStructureDestructor(size); - else if (ClassType::needsDestruction) - allocator = &vm().heap.allocatorForObjectWithNormalDestructor(size); - else - allocator = &vm().heap.allocatorForObjectWithoutDestructor(size); - return allocateObject(m_out.constIntPtr(allocator), structure, butterfly, slowPath); - } - - // Returns a pointer to the end of the allocation. - LValue allocateBasicStorageAndGetEnd(LValue size, LBasicBlock slowPath) - { - CopiedAllocator& allocator = vm().heap.storageAllocator(); - - LBasicBlock success = FTL_NEW_BLOCK(m_out, ("storage allocation success")); - - LValue remaining = m_out.loadPtr(m_out.absolute(&allocator.m_currentRemaining)); - LValue newRemaining = m_out.sub(remaining, size); - - m_out.branch(m_out.lessThan(newRemaining, m_out.intPtrZero), slowPath, success); - - m_out.appendTo(success); - - m_out.storePtr(newRemaining, m_out.absolute(&allocator.m_currentRemaining)); - return m_out.sub( - m_out.loadPtr(m_out.absolute(&allocator.m_currentPayloadEnd)), newRemaining); - } - - struct ArrayValues { - ArrayValues() - : array(0) - , butterfly(0) - { - } - - ArrayValues(LValue array, LValue butterfly) - : array(array) - , butterfly(butterfly) - { - } - - LValue array; - LValue butterfly; - }; - ArrayValues allocateJSArray( - Structure* structure, unsigned numElements, LBasicBlock slowPath) - { - ASSERT( - hasUndecided(structure->indexingType()) - || hasInt32(structure->indexingType()) - || hasDouble(structure->indexingType()) - || hasContiguous(structure->indexingType())); - - unsigned vectorLength = std::max(BASE_VECTOR_LEN, numElements); - - LValue endOfStorage = allocateBasicStorageAndGetEnd( - m_out.constIntPtr(sizeof(JSValue) * vectorLength + sizeof(IndexingHeader)), - slowPath); - - LValue butterfly = m_out.sub( - endOfStorage, m_out.constIntPtr(sizeof(JSValue) * vectorLength)); - - LValue object = allocateObject<JSArray>( - m_out.constIntPtr(structure), butterfly, slowPath); - - m_out.store32(m_out.constInt32(numElements), butterfly, m_heaps.Butterfly_publicLength); - m_out.store32(m_out.constInt32(vectorLength), butterfly, m_heaps.Butterfly_vectorLength); - - if (hasDouble(structure->indexingType())) { - for (unsigned i = numElements; i < vectorLength; ++i) { - m_out.store64( - m_out.constInt64(bitwise_cast<int64_t>(QNaN)), - butterfly, m_heaps.indexedDoubleProperties[i]); - } - } - - return ArrayValues(object, butterfly); - } - - ArrayValues allocateJSArray(Structure* structure, unsigned numElements) - { - LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("JSArray allocation slow path")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("JSArray allocation continuation")); - - LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath); - - ArrayValues fastValues = allocateJSArray(structure, numElements, slowPath); - ValueFromBlock fastArray = m_out.anchor(fastValues.array); - ValueFromBlock fastButterfly = m_out.anchor(fastValues.butterfly); - - m_out.jump(continuation); - - m_out.appendTo(slowPath, continuation); - - ValueFromBlock slowArray = m_out.anchor(vmCall( - m_out.operation(operationNewArrayWithSize), m_callFrame, - m_out.constIntPtr(structure), m_out.constInt32(numElements))); - ValueFromBlock slowButterfly = m_out.anchor( - m_out.loadPtr(slowArray.value(), m_heaps.JSObject_butterfly)); - - m_out.jump(continuation); - - m_out.appendTo(continuation, lastNext); - - return ArrayValues( - m_out.phi(m_out.intPtr, fastArray, slowArray), - m_out.phi(m_out.intPtr, fastButterfly, slowButterfly)); - } - - LValue typedArrayLength(Edge baseEdge, ArrayMode arrayMode, LValue base) - { - if (JSArrayBufferView* view = m_graph.tryGetFoldableView(baseEdge.node(), arrayMode)) - return m_out.constInt32(view->length()); - return m_out.load32(base, m_heaps.JSArrayBufferView_length); - } - - LValue typedArrayLength(Edge baseEdge, ArrayMode arrayMode) - { - return typedArrayLength(baseEdge, arrayMode, lowCell(baseEdge)); - } - - LValue boolify(Edge edge) - { - switch (edge.useKind()) { - case BooleanUse: - return lowBoolean(m_node->child1()); - case Int32Use: - return m_out.notZero32(lowInt32(m_node->child1())); - case NumberUse: - return m_out.doubleNotEqual(lowDouble(edge), m_out.doubleZero); - case ObjectOrOtherUse: - return m_out.bitNot( - equalNullOrUndefined( - edge, CellCaseSpeculatesObject, SpeculateNullOrUndefined, - ManualOperandSpeculation)); - case StringUse: { - LValue stringValue = lowString(m_node->child1()); - LValue length = m_out.load32(stringValue, m_heaps.JSString_length); - return m_out.notEqual(length, m_out.int32Zero); - } - case UntypedUse: { - LValue value = lowJSValue(m_node->child1()); - - LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("Boolify untyped slow case")); - LBasicBlock fastCase = FTL_NEW_BLOCK(m_out, ("Boolify untyped fast case")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Boolify untyped continuation")); - - m_out.branch(isNotBoolean(value), slowCase, fastCase); - - LBasicBlock lastNext = m_out.appendTo(fastCase, slowCase); - ValueFromBlock fastResult = m_out.anchor(unboxBoolean(value)); - m_out.jump(continuation); - - m_out.appendTo(slowCase, continuation); - ValueFromBlock slowResult = m_out.anchor(m_out.notNull(vmCall( - m_out.operation(operationConvertJSValueToBoolean), m_callFrame, value))); - m_out.jump(continuation); - - m_out.appendTo(continuation, lastNext); - return m_out.phi(m_out.boolean, fastResult, slowResult); - } - default: - RELEASE_ASSERT_NOT_REACHED(); - return 0; - } - } - - enum StringOrObjectMode { - AllCellsAreFalse, - CellCaseSpeculatesObject - }; - enum EqualNullOrUndefinedMode { - EqualNull, - EqualUndefined, - EqualNullOrUndefined, - SpeculateNullOrUndefined - }; - LValue equalNullOrUndefined( - Edge edge, StringOrObjectMode cellMode, EqualNullOrUndefinedMode primitiveMode, - OperandSpeculationMode operandMode = AutomaticOperandSpeculation) - { - bool validWatchpoint = masqueradesAsUndefinedWatchpointIsStillValid(); - - LValue value = lowJSValue(edge, operandMode); - - LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("EqualNullOrUndefined cell case")); - LBasicBlock primitiveCase = FTL_NEW_BLOCK(m_out, ("EqualNullOrUndefined primitive case")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("EqualNullOrUndefined continuation")); - - m_out.branch(isNotCell(value), primitiveCase, cellCase); - - LBasicBlock lastNext = m_out.appendTo(cellCase, primitiveCase); - - Vector<ValueFromBlock, 3> results; - - switch (cellMode) { - case AllCellsAreFalse: - break; - case CellCaseSpeculatesObject: - FTL_TYPE_CHECK( - jsValueValue(value), edge, (~SpecCell) | SpecObject, - m_out.equal( - m_out.loadPtr(value, m_heaps.JSCell_structure), - m_out.constIntPtr(vm().stringStructure.get()))); - break; - } - - if (validWatchpoint) { - results.append(m_out.anchor(m_out.booleanFalse)); - m_out.jump(continuation); - } else { - LBasicBlock masqueradesCase = - FTL_NEW_BLOCK(m_out, ("EqualNullOrUndefined masquerades case")); - - LValue structure = m_out.loadPtr(value, m_heaps.JSCell_structure); - - results.append(m_out.anchor(m_out.booleanFalse)); - - m_out.branch( - m_out.testNonZero8( - m_out.load8(structure, m_heaps.Structure_typeInfoFlags), - m_out.constInt8(MasqueradesAsUndefined)), - masqueradesCase, continuation); - - m_out.appendTo(masqueradesCase, primitiveCase); - - results.append(m_out.anchor( - m_out.equal( - m_out.constIntPtr(m_graph.globalObjectFor(m_node->codeOrigin)), - m_out.loadPtr(structure, m_heaps.Structure_globalObject)))); - m_out.jump(continuation); - } - - m_out.appendTo(primitiveCase, continuation); - - LValue primitiveResult; - switch (primitiveMode) { - case EqualNull: - primitiveResult = m_out.equal(value, m_out.constInt64(ValueNull)); - break; - case EqualUndefined: - primitiveResult = m_out.equal(value, m_out.constInt64(ValueUndefined)); - break; - case EqualNullOrUndefined: - primitiveResult = m_out.equal( - m_out.bitAnd(value, m_out.constInt64(~TagBitUndefined)), - m_out.constInt64(ValueNull)); - break; - case SpeculateNullOrUndefined: - FTL_TYPE_CHECK( - jsValueValue(value), edge, SpecCell | SpecOther, - m_out.notEqual( - m_out.bitAnd(value, m_out.constInt64(~TagBitUndefined)), - m_out.constInt64(ValueNull))); - primitiveResult = m_out.booleanTrue; - break; - } - results.append(m_out.anchor(primitiveResult)); - m_out.jump(continuation); - - m_out.appendTo(continuation, lastNext); - - return m_out.phi(m_out.boolean, results); - } - - template<typename FunctionType> - void contiguousPutByValOutOfBounds( - FunctionType slowPathFunction, LValue base, LValue storage, LValue index, LValue value, - LBasicBlock continuation) - { - LValue isNotInBounds = m_out.aboveOrEqual( - index, m_out.load32(storage, m_heaps.Butterfly_publicLength)); - if (!m_node->arrayMode().isInBounds()) { - LBasicBlock notInBoundsCase = - FTL_NEW_BLOCK(m_out, ("PutByVal not in bounds")); - LBasicBlock performStore = - FTL_NEW_BLOCK(m_out, ("PutByVal perform store")); - - m_out.branch(isNotInBounds, notInBoundsCase, performStore); - - LBasicBlock lastNext = m_out.appendTo(notInBoundsCase, performStore); - - LValue isOutOfBounds = m_out.aboveOrEqual( - index, m_out.load32(storage, m_heaps.Butterfly_vectorLength)); - - if (!m_node->arrayMode().isOutOfBounds()) - speculate(OutOfBounds, noValue(), 0, isOutOfBounds); - else { - LBasicBlock outOfBoundsCase = - FTL_NEW_BLOCK(m_out, ("PutByVal out of bounds")); - LBasicBlock holeCase = - FTL_NEW_BLOCK(m_out, ("PutByVal hole case")); - - m_out.branch(isOutOfBounds, outOfBoundsCase, holeCase); - - LBasicBlock innerLastNext = m_out.appendTo(outOfBoundsCase, holeCase); - - vmCall( - m_out.operation(slowPathFunction), - m_callFrame, base, index, value); - - m_out.jump(continuation); - - m_out.appendTo(holeCase, innerLastNext); - } - - m_out.store32( - m_out.add(index, m_out.int32One), - storage, m_heaps.Butterfly_publicLength); - - m_out.jump(performStore); - m_out.appendTo(performStore, lastNext); - } - } - - void buildSwitch(SwitchData* data, LType type, LValue switchValue) - { - Vector<SwitchCase> cases; - for (unsigned i = 0; i < data->cases.size(); ++i) { - cases.append(SwitchCase( - constInt(type, data->cases[i].value.switchLookupValue()), - lowBlock(data->cases[i].target))); - } - - m_out.switchInstruction(switchValue, cases, lowBlock(data->fallThrough)); - } - - LValue doubleToInt32(LValue doubleValue, double low, double high, bool isSigned = true) - { - // FIXME: Optimize double-to-int conversions. - // <rdar://problem/14938465> - - LBasicBlock greatEnough = FTL_NEW_BLOCK(m_out, ("doubleToInt32 greatEnough")); - LBasicBlock withinRange = FTL_NEW_BLOCK(m_out, ("doubleToInt32 withinRange")); - LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("doubleToInt32 slowPath")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("doubleToInt32 continuation")); - - Vector<ValueFromBlock, 2> results; - - m_out.branch( - m_out.doubleGreaterThanOrEqual(doubleValue, m_out.constDouble(low)), - greatEnough, slowPath); - - LBasicBlock lastNext = m_out.appendTo(greatEnough, withinRange); - m_out.branch( - m_out.doubleLessThanOrEqual(doubleValue, m_out.constDouble(high)), - withinRange, slowPath); - - m_out.appendTo(withinRange, slowPath); - LValue fastResult; - if (isSigned) - fastResult = m_out.fpToInt32(doubleValue); - else - fastResult = m_out.fpToUInt32(doubleValue); - results.append(m_out.anchor(fastResult)); - m_out.jump(continuation); - - m_out.appendTo(slowPath, continuation); - results.append(m_out.anchor(m_out.call(m_out.operation(toInt32), doubleValue))); - m_out.jump(continuation); - - m_out.appendTo(continuation, lastNext); - return m_out.phi(m_out.int32, results); - } - - LValue doubleToInt32(LValue doubleValue) - { - if (Output::hasSensibleDoubleToInt()) - return sensibleDoubleToInt32(doubleValue); - - double limit = pow(2, 31) - 1; - return doubleToInt32(doubleValue, -limit, limit); - } - - LValue sensibleDoubleToInt32(LValue doubleValue) - { - LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("sensible doubleToInt32 slow path")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("sensible doubleToInt32 continuation")); - - ValueFromBlock fastResult = m_out.anchor( - m_out.sensibleDoubleToInt(doubleValue)); - m_out.branch( - m_out.equal(fastResult.value(), m_out.constInt32(0x80000000)), - slowPath, continuation); - - LBasicBlock lastNext = m_out.appendTo(slowPath, continuation); - ValueFromBlock slowResult = m_out.anchor( - m_out.call(m_out.operation(toInt32), doubleValue)); - m_out.jump(continuation); - - m_out.appendTo(continuation, lastNext); - return m_out.phi(m_out.int32, fastResult, slowResult); - } - - void speculate( - ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition) - { - appendOSRExit(kind, lowValue, highValue, failCondition); - } - - void terminate(ExitKind kind) - { - speculate(kind, noValue(), 0, m_out.booleanTrue); - } - - void typeCheck( - FormattedValue lowValue, Edge highValue, SpeculatedType typesPassedThrough, - LValue failCondition) - { - appendTypeCheck(lowValue, highValue, typesPassedThrough, failCondition); - } - - void appendTypeCheck( - FormattedValue lowValue, Edge highValue, SpeculatedType typesPassedThrough, - LValue failCondition) - { - if (!m_interpreter.needsTypeCheck(highValue, typesPassedThrough)) - return; - ASSERT(mayHaveTypeCheck(highValue.useKind())); - appendOSRExit(BadType, lowValue, highValue.node(), failCondition); - m_interpreter.filter(highValue, typesPassedThrough); - } - - LValue lowInt32(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation) - { - ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || (edge.useKind() == Int32Use || edge.useKind() == KnownInt32Use)); - - if (edge->hasConstant()) { - JSValue value = m_graph.valueOfJSConstant(edge.node()); - if (!value.isInt32()) { - terminate(Uncountable); - return m_out.int32Zero; - } - return m_out.constInt32(value.asInt32()); - } - - LoweredNodeValue value = m_int32Values.get(edge.node()); - if (isValid(value)) - return value.value(); - - value = m_strictInt52Values.get(edge.node()); - if (isValid(value)) - return strictInt52ToInt32(edge, value.value()); - - value = m_int52Values.get(edge.node()); - if (isValid(value)) - return strictInt52ToInt32(edge, int52ToStrictInt52(value.value())); - - value = m_jsValueValues.get(edge.node()); - if (isValid(value)) { - LValue boxedResult = value.value(); - FTL_TYPE_CHECK( - jsValueValue(boxedResult), edge, SpecInt32, isNotInt32(boxedResult)); - LValue result = unboxInt32(boxedResult); - setInt32(edge.node(), result); - return result; - } - - RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecInt32)); - terminate(Uncountable); - return m_out.int32Zero; - } - - enum Int52Kind { StrictInt52, Int52 }; - LValue lowInt52(Edge edge, Int52Kind kind, OperandSpeculationMode mode = AutomaticOperandSpeculation) - { - ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == MachineIntUse); - - if (edge->hasConstant()) { - JSValue value = m_graph.valueOfJSConstant(edge.node()); - if (!value.isMachineInt()) { - terminate(Uncountable); - return m_out.int64Zero; - } - int64_t result = value.asMachineInt(); - if (kind == Int52) - result <<= JSValue::int52ShiftAmount; - return m_out.constInt64(result); - } - - LoweredNodeValue value; - - switch (kind) { - case Int52: - value = m_int52Values.get(edge.node()); - if (isValid(value)) - return value.value(); - - value = m_strictInt52Values.get(edge.node()); - if (isValid(value)) - return strictInt52ToInt52(value.value()); - break; - - case StrictInt52: - value = m_strictInt52Values.get(edge.node()); - if (isValid(value)) - return value.value(); - - value = m_int52Values.get(edge.node()); - if (isValid(value)) - return int52ToStrictInt52(value.value()); - break; - } - - value = m_int32Values.get(edge.node()); - if (isValid(value)) { - return setInt52WithStrictValue( - edge.node(), m_out.signExt(value.value(), m_out.int64), kind); - } - - RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecInt52)); - - value = m_jsValueValues.get(edge.node()); - if (isValid(value)) { - LValue boxedResult = value.value(); - FTL_TYPE_CHECK( - jsValueValue(boxedResult), edge, SpecMachineInt, isNotInt32(boxedResult)); - return setInt52WithStrictValue( - edge.node(), m_out.signExt(unboxInt32(boxedResult), m_out.int64), kind); - } - - RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecMachineInt)); - terminate(Uncountable); - return m_out.int64Zero; - } - - LValue lowInt52(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation) - { - return lowInt52(edge, Int52, mode); - } - - LValue lowStrictInt52(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation) - { - return lowInt52(edge, StrictInt52, mode); - } - - bool betterUseStrictInt52(Node* node) - { - return !isValid(m_int52Values.get(node)); - } - bool betterUseStrictInt52(Edge edge) - { - return betterUseStrictInt52(edge.node()); - } - template<typename T> - Int52Kind bestInt52Kind(T node) - { - return betterUseStrictInt52(node) ? StrictInt52 : Int52; - } - Int52Kind opposite(Int52Kind kind) - { - switch (kind) { - case Int52: - return StrictInt52; - case StrictInt52: - return Int52; - } - RELEASE_ASSERT_NOT_REACHED(); - } - - LValue lowWhicheverInt52(Edge edge, Int52Kind& kind, OperandSpeculationMode mode = AutomaticOperandSpeculation) - { - kind = bestInt52Kind(edge); - return lowInt52(edge, kind, mode); - } - - LValue lowCell(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation) - { - ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || DFG::isCell(edge.useKind())); - - if (edge->op() == JSConstant) { - JSValue value = m_graph.valueOfJSConstant(edge.node()); - if (!value.isCell()) { - terminate(Uncountable); - return m_out.intPtrZero; - } - return m_out.constIntPtr(value.asCell()); - } - - LoweredNodeValue value = m_jsValueValues.get(edge.node()); - if (isValid(value)) { - LValue uncheckedValue = value.value(); - FTL_TYPE_CHECK( - jsValueValue(uncheckedValue), edge, SpecCell, isNotCell(uncheckedValue)); - return uncheckedValue; - } - - RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecCell)); - terminate(Uncountable); - return m_out.intPtrZero; - } - - LValue lowObject(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation) - { - ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == ObjectUse); - - LValue result = lowCell(edge, mode); - speculateObject(edge, result); - return result; - } - - LValue lowString(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation) - { - ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == StringUse || edge.useKind() == KnownStringUse); - - LValue result = lowCell(edge, mode); - speculateString(edge, result); - return result; - } - - LValue lowNonNullObject(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation) - { - ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == ObjectUse); - - LValue result = lowCell(edge, mode); - speculateNonNullObject(edge, result); - return result; - } - - LValue lowBoolean(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation) - { - ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == BooleanUse); - - if (edge->hasConstant()) { - JSValue value = m_graph.valueOfJSConstant(edge.node()); - if (!value.isBoolean()) { - terminate(Uncountable); - return m_out.booleanFalse; - } - return m_out.constBool(value.asBoolean()); - } - - LoweredNodeValue value = m_booleanValues.get(edge.node()); - if (isValid(value)) - return value.value(); - - value = m_jsValueValues.get(edge.node()); - if (isValid(value)) { - LValue unboxedResult = value.value(); - FTL_TYPE_CHECK( - jsValueValue(unboxedResult), edge, SpecBoolean, isNotBoolean(unboxedResult)); - LValue result = unboxBoolean(unboxedResult); - setBoolean(edge.node(), result); - return result; - } - - RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecBoolean)); - terminate(Uncountable); - return m_out.booleanFalse; - } - - LValue lowDouble(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation) - { - ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || isDouble(edge.useKind())); - - if (edge->hasConstant()) { - JSValue value = m_graph.valueOfJSConstant(edge.node()); - if (!value.isNumber()) { - terminate(Uncountable); - return m_out.doubleZero; - } - return m_out.constDouble(value.asNumber()); - } - - LoweredNodeValue value = m_doubleValues.get(edge.node()); - if (isValid(value)) - return value.value(); - - value = m_int32Values.get(edge.node()); - if (isValid(value)) { - LValue result = m_out.intToDouble(value.value()); - setDouble(edge.node(), result); - return result; - } - - value = m_strictInt52Values.get(edge.node()); - if (isValid(value)) - return strictInt52ToDouble(edge, value.value()); - - value = m_int52Values.get(edge.node()); - if (isValid(value)) - return strictInt52ToDouble(edge, int52ToStrictInt52(value.value())); - - value = m_jsValueValues.get(edge.node()); - if (isValid(value)) { - LValue boxedResult = value.value(); - - LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("Double unboxing int case")); - LBasicBlock doubleCase = FTL_NEW_BLOCK(m_out, ("Double unboxing double case")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Double unboxing continuation")); - - m_out.branch(isNotInt32(boxedResult), doubleCase, intCase); - - LBasicBlock lastNext = m_out.appendTo(intCase, doubleCase); - - ValueFromBlock intToDouble = m_out.anchor( - m_out.intToDouble(unboxInt32(boxedResult))); - m_out.jump(continuation); - - m_out.appendTo(doubleCase, continuation); - - FTL_TYPE_CHECK( - jsValueValue(boxedResult), edge, SpecFullNumber, isCellOrMisc(boxedResult)); - - ValueFromBlock unboxedDouble = m_out.anchor(unboxDouble(boxedResult)); - m_out.jump(continuation); - - m_out.appendTo(continuation, lastNext); - - LValue result = m_out.phi(m_out.doubleType, intToDouble, unboxedDouble); - - setDouble(edge.node(), result); - return result; - } - - RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecFullNumber)); - terminate(Uncountable); - return m_out.doubleZero; - } - - LValue lowJSValue(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation) - { - ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == UntypedUse); - - if (edge->hasConstant()) - return m_out.constInt64(JSValue::encode(m_graph.valueOfJSConstant(edge.node()))); - - LoweredNodeValue value = m_jsValueValues.get(edge.node()); - if (isValid(value)) - return value.value(); - - value = m_int32Values.get(edge.node()); - if (isValid(value)) { - LValue result = boxInt32(value.value()); - setJSValue(edge.node(), result); - return result; - } - - value = m_strictInt52Values.get(edge.node()); - if (isValid(value)) - return strictInt52ToJSValue(value.value()); - - value = m_int52Values.get(edge.node()); - if (isValid(value)) - return strictInt52ToJSValue(int52ToStrictInt52(value.value())); - - value = m_booleanValues.get(edge.node()); - if (isValid(value)) { - LValue result = boxBoolean(value.value()); - setJSValue(edge.node(), result); - return result; - } - - value = m_doubleValues.get(edge.node()); - if (isValid(value)) { - LValue result = boxDouble(value.value()); - setJSValue(edge.node(), result); - return result; - } - - RELEASE_ASSERT_NOT_REACHED(); - return 0; - } - - LValue lowStorage(Edge edge) - { - LoweredNodeValue value = m_storageValues.get(edge.node()); - if (isValid(value)) - return value.value(); - - LValue result = lowCell(edge); - setStorage(edge.node(), result); - return result; - } - - LValue strictInt52ToInt32(Edge edge, LValue value) - { - LValue result = m_out.castToInt32(value); - FTL_TYPE_CHECK( - noValue(), edge, SpecInt32, - m_out.notEqual(m_out.signExt(result, m_out.int64), value)); - setInt32(edge.node(), result); - return result; - } - - LValue strictInt52ToDouble(Edge edge, LValue value) - { - LValue result = m_out.intToDouble(value); - setDouble(edge.node(), result); - return result; - } - - LValue strictInt52ToJSValue(LValue value) - { - LBasicBlock isInt32 = FTL_NEW_BLOCK(m_out, ("strictInt52ToJSValue isInt32 case")); - LBasicBlock isDouble = FTL_NEW_BLOCK(m_out, ("strictInt52ToJSValue isDouble case")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("strictInt52ToJSValue continuation")); - - Vector<ValueFromBlock, 2> results; - - LValue int32Value = m_out.castToInt32(value); - m_out.branch( - m_out.equal(m_out.signExt(int32Value, m_out.int64), value), - isInt32, isDouble); - - LBasicBlock lastNext = m_out.appendTo(isInt32, isDouble); - - results.append(m_out.anchor(boxInt32(int32Value))); - m_out.jump(continuation); - - m_out.appendTo(isDouble, continuation); - - results.append(m_out.anchor(boxDouble(m_out.intToDouble(value)))); - m_out.jump(continuation); - - m_out.appendTo(continuation, lastNext); - return m_out.phi(m_out.int64, results); - } - - LValue setInt52WithStrictValue(Node* node, LValue value, Int52Kind kind) - { - switch (kind) { - case StrictInt52: - setStrictInt52(node, value); - return value; - - case Int52: - value = strictInt52ToInt52(value); - setInt52(node, value); - return value; - } - - RELEASE_ASSERT_NOT_REACHED(); - return 0; - } - - LValue strictInt52ToInt52(LValue value) - { - return m_out.shl(value, m_out.constInt64(JSValue::int52ShiftAmount)); - } - - LValue int52ToStrictInt52(LValue value) - { - return m_out.aShr(value, m_out.constInt64(JSValue::int52ShiftAmount)); - } - - LValue isNotInt32(LValue jsValue) - { - return m_out.below(jsValue, m_tagTypeNumber); - } - LValue unboxInt32(LValue jsValue) - { - return m_out.castToInt32(jsValue); - } - LValue boxInt32(LValue value) - { - return m_out.add(m_out.zeroExt(value, m_out.int64), m_tagTypeNumber); - } - - LValue isCellOrMisc(LValue jsValue) - { - return m_out.testIsZero64(jsValue, m_tagTypeNumber); - } - LValue unboxDouble(LValue jsValue) - { - return m_out.bitCast(m_out.add(jsValue, m_tagTypeNumber), m_out.doubleType); - } - LValue boxDouble(LValue doubleValue) - { - return m_out.sub(m_out.bitCast(doubleValue, m_out.int64), m_tagTypeNumber); - } - - LValue isNotCell(LValue jsValue) - { - return m_out.testNonZero64(jsValue, m_tagMask); - } - - LValue isCell(LValue jsValue) - { - return m_out.testIsZero64(jsValue, m_tagMask); - } - - LValue isNotBoolean(LValue jsValue) - { - return m_out.testNonZero64( - m_out.bitXor(jsValue, m_out.constInt64(ValueFalse)), - m_out.constInt64(~1)); - } - LValue unboxBoolean(LValue jsValue) - { - // We want to use a cast that guarantees that LLVM knows that even the integer - // value is just 0 or 1. But for now we do it the dumb way. - return m_out.notZero64(m_out.bitAnd(jsValue, m_out.constInt64(1))); - } - LValue boxBoolean(LValue value) - { - return m_out.select( - value, m_out.constInt64(ValueTrue), m_out.constInt64(ValueFalse)); - } - - void speculate(Edge edge) - { - switch (edge.useKind()) { - case UntypedUse: - break; - case KnownInt32Use: - case KnownNumberUse: - ASSERT(!m_interpreter.needsTypeCheck(edge)); - break; - case Int32Use: - speculateInt32(edge); - break; - case CellUse: - speculateCell(edge); - break; - case KnownCellUse: - ASSERT(!m_interpreter.needsTypeCheck(edge)); - break; - case ObjectUse: - speculateObject(edge); - break; - case ObjectOrOtherUse: - speculateObjectOrOther(edge); - break; - case FinalObjectUse: - speculateFinalObject(edge); - break; - case StringUse: - speculateString(edge); - break; - case RealNumberUse: - speculateRealNumber(edge); - break; - case NumberUse: - speculateNumber(edge); - break; - case MachineIntUse: - speculateMachineInt(edge); - break; - case BooleanUse: - speculateBoolean(edge); - break; - default: - dataLog("Unsupported speculation use kind: ", edge.useKind(), "\n"); - RELEASE_ASSERT_NOT_REACHED(); - } - } - - void speculate(Node*, Edge edge) - { - speculate(edge); - } - - void speculateInt32(Edge edge) - { - lowInt32(edge); - } - - void speculateCell(Edge edge) - { - lowCell(edge); - } - - LValue isObject(LValue cell) - { - return m_out.notEqual( - m_out.loadPtr(cell, m_heaps.JSCell_structure), - m_out.constIntPtr(vm().stringStructure.get())); - } - - LValue isNotString(LValue cell) - { - return isObject(cell); - } - - LValue isString(LValue cell) - { - return m_out.equal( - m_out.loadPtr(cell, m_heaps.JSCell_structure), - m_out.constIntPtr(vm().stringStructure.get())); - } - - LValue isNotObject(LValue cell) - { - return isString(cell); - } - - LValue isArrayType(LValue cell, ArrayMode arrayMode) - { - switch (arrayMode.type()) { - case Array::Int32: - case Array::Double: - case Array::Contiguous: { - LValue indexingType = m_out.load8( - m_out.loadPtr(cell, m_heaps.JSCell_structure), - m_heaps.Structure_indexingType); - - switch (arrayMode.arrayClass()) { - case Array::OriginalArray: - RELEASE_ASSERT_NOT_REACHED(); - return 0; - - case Array::Array: - return m_out.equal( - m_out.bitAnd(indexingType, m_out.constInt8(IsArray | IndexingShapeMask)), - m_out.constInt8(IsArray | arrayMode.shapeMask())); - - case Array::NonArray: - case Array::OriginalNonArray: - return m_out.equal( - m_out.bitAnd(indexingType, m_out.constInt8(IsArray | IndexingShapeMask)), - m_out.constInt8(arrayMode.shapeMask())); - - case Array::PossiblyArray: - return m_out.equal( - m_out.bitAnd(indexingType, m_out.constInt8(IndexingShapeMask)), - m_out.constInt8(arrayMode.shapeMask())); - } - - RELEASE_ASSERT_NOT_REACHED(); - } - - default: - return hasClassInfo(cell, classInfoForType(arrayMode.typedArrayType())); - } - } - - LValue hasClassInfo(LValue cell, const ClassInfo* classInfo) - { - return m_out.equal( - m_out.loadPtr( - m_out.loadPtr(cell, m_heaps.JSCell_structure), - m_heaps.Structure_classInfo), - m_out.constIntPtr(classInfo)); - } - - LValue isType(LValue cell, JSType type) - { - return m_out.equal( - m_out.load8( - m_out.loadPtr(cell, m_heaps.JSCell_structure), - m_heaps.Structure_typeInfoType), - m_out.constInt8(type)); - } - - LValue isNotType(LValue cell, JSType type) - { - return m_out.bitNot(isType(cell, type)); - } - - void speculateObject(Edge edge, LValue cell) - { - FTL_TYPE_CHECK(jsValueValue(cell), edge, SpecObject, isNotObject(cell)); - } - - void speculateObject(Edge edge) - { - speculateObject(edge, lowCell(edge)); - } - - void speculateObjectOrOther(Edge edge) - { - if (!m_interpreter.needsTypeCheck(edge)) - return; - - LValue value = lowJSValue(edge); - - LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("speculateObjectOrOther cell case")); - LBasicBlock primitiveCase = FTL_NEW_BLOCK(m_out, ("speculateObjectOrOther primitive case")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("speculateObjectOrOther continuation")); - - m_out.branch(isNotCell(value), primitiveCase, cellCase); - - LBasicBlock lastNext = m_out.appendTo(cellCase, primitiveCase); - - FTL_TYPE_CHECK( - jsValueValue(value), edge, (~SpecCell) | SpecObject, - m_out.equal( - m_out.loadPtr(value, m_heaps.JSCell_structure), - m_out.constIntPtr(vm().stringStructure.get()))); - - m_out.jump(continuation); - - m_out.appendTo(primitiveCase, continuation); - - FTL_TYPE_CHECK( - jsValueValue(value), edge, SpecCell | SpecOther, - m_out.notEqual( - m_out.bitAnd(value, m_out.constInt64(~TagBitUndefined)), - m_out.constInt64(ValueNull))); - - m_out.jump(continuation); - - m_out.appendTo(continuation, lastNext); - } - - void speculateFinalObject(Edge edge, LValue cell) - { - FTL_TYPE_CHECK( - jsValueValue(cell), edge, SpecFinalObject, isNotType(cell, FinalObjectType)); - } - - void speculateFinalObject(Edge edge) - { - speculateFinalObject(edge, lowCell(edge)); - } - - void speculateString(Edge edge, LValue cell) - { - FTL_TYPE_CHECK(jsValueValue(cell), edge, SpecString, isNotString(cell)); - } - - void speculateString(Edge edge) - { - speculateString(edge, lowCell(edge)); - } - - void speculateNonNullObject(Edge edge, LValue cell) - { - LValue structure = m_out.loadPtr(cell, m_heaps.JSCell_structure); - FTL_TYPE_CHECK( - jsValueValue(cell), edge, SpecObject, - m_out.equal(structure, m_out.constIntPtr(vm().stringStructure.get()))); - if (masqueradesAsUndefinedWatchpointIsStillValid()) - return; - - speculate( - BadType, jsValueValue(cell), edge.node(), - m_out.testNonZero8( - m_out.load8(structure, m_heaps.Structure_typeInfoFlags), - m_out.constInt8(MasqueradesAsUndefined))); - } - - void speculateNumber(Edge edge) - { - // Do an early return here because lowDouble() can create a lot of control flow. - if (!m_interpreter.needsTypeCheck(edge)) - return; - - lowDouble(edge); - } - - void speculateRealNumber(Edge edge) - { - // Do an early return here because lowDouble() can create a lot of control flow. - if (!m_interpreter.needsTypeCheck(edge)) - return; - - LValue value = lowDouble(edge); - FTL_TYPE_CHECK( - doubleValue(value), edge, SpecFullRealNumber, - m_out.doubleNotEqualOrUnordered(value, value)); - } - - void speculateMachineInt(Edge edge) - { - if (!m_interpreter.needsTypeCheck(edge)) - return; - - Int52Kind kind; - lowWhicheverInt52(edge, kind); - } - - void speculateBoolean(Edge edge) - { - lowBoolean(edge); - } - - bool masqueradesAsUndefinedWatchpointIsStillValid() - { - return m_graph.masqueradesAsUndefinedWatchpointIsStillValid(m_node->codeOrigin); - } - - LValue loadMarkByte(LValue base) - { - LValue markedBlock = m_out.bitAnd(base, m_out.constInt64(MarkedBlock::blockMask)); - LValue baseOffset = m_out.bitAnd(base, m_out.constInt64(~MarkedBlock::blockMask)); - LValue markByteIndex = m_out.lShr(baseOffset, m_out.constInt64(MarkedBlock::atomShiftAmount + MarkedBlock::markByteShiftAmount)); - return m_out.load8(m_out.baseIndex(m_heaps.MarkedBlock_markBits, markedBlock, markByteIndex, ScaleOne, MarkedBlock::offsetOfMarks())); - } - - void emitStoreBarrier(LValue base, LValue value, Edge& valueEdge) - { -#if ENABLE(GGC) - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Store barrier continuation")); - LBasicBlock isCell = FTL_NEW_BLOCK(m_out, ("Store barrier is cell block")); - - if (m_state.forNode(valueEdge.node()).couldBeType(SpecCell)) - m_out.branch(isNotCell(value), continuation, isCell); - else - m_out.jump(isCell); - - LBasicBlock lastNext = m_out.appendTo(isCell, continuation); - emitStoreBarrier(base); - m_out.jump(continuation); - - m_out.appendTo(continuation, lastNext); -#else - UNUSED_PARAM(base); - UNUSED_PARAM(value); - UNUSED_PARAM(valueEdge); -#endif - } - - void emitStoreBarrier(LValue base) - { -#if ENABLE(GGC) - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Store barrier continuation")); - LBasicBlock isMarked = FTL_NEW_BLOCK(m_out, ("Store barrier is marked block")); - LBasicBlock bufferHasSpace = FTL_NEW_BLOCK(m_out, ("Store barrier buffer is full")); - LBasicBlock bufferIsFull = FTL_NEW_BLOCK(m_out, ("Store barrier buffer is full")); - - // Check the mark byte. - m_out.branch(m_out.isZero8(loadMarkByte(base)), continuation, isMarked); - - // Append to the write barrier buffer. - LBasicBlock lastNext = m_out.appendTo(isMarked, bufferHasSpace); - LValue currentBufferIndex = m_out.load32(m_out.absolute(&vm().heap.writeBarrierBuffer().m_currentIndex)); - LValue bufferCapacity = m_out.load32(m_out.absolute(&vm().heap.writeBarrierBuffer().m_capacity)); - m_out.branch(m_out.lessThan(currentBufferIndex, bufferCapacity), bufferHasSpace, bufferIsFull); - - // Buffer has space, store to it. - m_out.appendTo(bufferHasSpace, bufferIsFull); - LValue writeBarrierBufferBase = m_out.loadPtr(m_out.absolute(&vm().heap.writeBarrierBuffer().m_buffer)); - m_out.storePtr(base, m_out.baseIndex(m_heaps.WriteBarrierBuffer_bufferContents, writeBarrierBufferBase, m_out.zeroExt(currentBufferIndex, m_out.intPtr), ScalePtr)); - m_out.store32(m_out.add(currentBufferIndex, m_out.constInt32(1)), m_out.absolute(&vm().heap.writeBarrierBuffer().m_currentIndex)); - m_out.jump(continuation); - - // Buffer is out of space, flush it. - m_out.appendTo(bufferIsFull, continuation); - vmCall(m_out.operation(operationFlushWriteBarrierBuffer), m_callFrame, base); - m_out.jump(continuation); - - m_out.appendTo(continuation, lastNext); -#else - UNUSED_PARAM(base); -#endif - } - - enum ExceptionCheckMode { NoExceptions, CheckExceptions }; - - LValue vmCall(LValue function, ExceptionCheckMode mode = CheckExceptions) - { - callPreflight(); - LValue result = m_out.call(function); - callCheck(mode); - return result; - } - LValue vmCall(LValue function, LValue arg1, ExceptionCheckMode mode = CheckExceptions) - { - callPreflight(); - LValue result = m_out.call(function, arg1); - callCheck(mode); - return result; - } - LValue vmCall(LValue function, LValue arg1, LValue arg2, ExceptionCheckMode mode = CheckExceptions) - { - callPreflight(); - LValue result = m_out.call(function, arg1, arg2); - callCheck(mode); - return result; - } - LValue vmCall(LValue function, LValue arg1, LValue arg2, LValue arg3, ExceptionCheckMode mode = CheckExceptions) - { - callPreflight(); - LValue result = m_out.call(function, arg1, arg2, arg3); - callCheck(mode); - return result; - } - LValue vmCall(LValue function, LValue arg1, LValue arg2, LValue arg3, LValue arg4, ExceptionCheckMode mode = CheckExceptions) - { - callPreflight(); - LValue result = m_out.call(function, arg1, arg2, arg3, arg4); - callCheck(mode); - return result; - } - - void callPreflight(CodeOrigin codeOrigin) - { - m_out.store32( - m_out.constInt32( - CallFrame::Location::encodeAsCodeOriginIndex( - m_ftlState.jitCode->common.addCodeOrigin(codeOrigin))), - tagFor(JSStack::ArgumentCount)); - } - void callPreflight() - { - callPreflight(m_node->codeOrigin); - } - - void callCheck(ExceptionCheckMode mode = CheckExceptions) - { - if (mode == NoExceptions) - return; - - LBasicBlock didHaveException = FTL_NEW_BLOCK(m_out, ("Did have exception")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Exception check continuation")); - - m_out.branch( - m_out.notZero64(m_out.load64(m_out.absolute(vm().addressOfException()))), - didHaveException, continuation); - - LBasicBlock lastNext = m_out.appendTo(didHaveException, continuation); - // FIXME: Handle exceptions. https://bugs.webkit.org/show_bug.cgi?id=113622 - m_out.crash(); - - m_out.appendTo(continuation, lastNext); - } - - LBasicBlock lowBlock(BasicBlock* block) - { - return m_blocks.get(block); - } - - void initializeOSRExitStateForBlock() - { - m_availability = m_highBlock->ssa->availabilityAtHead; - } - - void appendOSRExit( - ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition) - { - if (verboseCompilationEnabled()) - dataLog(" OSR exit #", m_ftlState.jitCode->osrExit.size(), " with availability: ", m_availability, "\n"); - - ASSERT(m_ftlState.jitCode->osrExit.size() == m_ftlState.finalizer->osrExit.size()); - - m_ftlState.jitCode->osrExit.append(OSRExit( - kind, lowValue.format(), m_graph.methodOfGettingAValueProfileFor(highValue), - m_codeOriginForExitTarget, m_codeOriginForExitProfile, - m_availability.numberOfArguments(), m_availability.numberOfLocals())); - m_ftlState.finalizer->osrExit.append(OSRExitCompilationInfo()); - - OSRExit& exit = m_ftlState.jitCode->osrExit.last(); - - LBasicBlock lastNext = 0; - LBasicBlock continuation = 0; - - LBasicBlock failCase = FTL_NEW_BLOCK(m_out, ("OSR exit failCase for ", m_node)); - continuation = FTL_NEW_BLOCK(m_out, ("OSR exit continuation for ", m_node)); - - m_out.branch(failCondition, failCase, continuation); - - lastNext = m_out.appendTo(failCase, continuation); - - emitOSRExitCall(exit, lowValue); - - m_out.unreachable(); - - m_out.appendTo(continuation, lastNext); - } - - void emitOSRExitCall(OSRExit& exit, FormattedValue lowValue) - { - ExitArgumentList arguments; - - CodeOrigin codeOrigin = exit.m_codeOrigin; - - buildExitArguments(exit, arguments, lowValue, codeOrigin); - - callStackmap(exit, arguments); - } - - void buildExitArguments( - OSRExit& exit, ExitArgumentList& arguments, FormattedValue lowValue, - CodeOrigin codeOrigin) - { - arguments.append(m_callFrame); - if (!!lowValue) - arguments.append(lowValue.value()); - - for (unsigned i = 0; i < exit.m_values.size(); ++i) { - int operand = exit.m_values.operandForIndex(i); - bool isLive = m_graph.isLiveInBytecode(VirtualRegister(operand), codeOrigin); - if (!isLive) { - exit.m_values[i] = ExitValue::dead(); - continue; - } - - Availability availability = m_availability[i]; - FlushedAt flush = availability.flushedAt(); - switch (flush.format()) { - case DeadFlush: - case ConflictingFlush: - if (availability.hasNode()) { - addExitArgumentForNode(exit, arguments, i, availability.node()); - break; - } - - if (Options::validateFTLOSRExitLiveness()) { - dataLog("Expected r", operand, " to be available but it wasn't.\n"); - RELEASE_ASSERT_NOT_REACHED(); - } - - // This means that the DFG's DCE proved that the value is dead in bytecode - // even though the bytecode liveness analysis thinks it's live. This is - // acceptable since the DFG's DCE is by design more aggressive while still - // being sound. - exit.m_values[i] = ExitValue::dead(); - break; - - case FlushedJSValue: - case FlushedCell: - case FlushedBoolean: - exit.m_values[i] = ExitValue::inJSStack(flush.virtualRegister()); - break; - - case FlushedInt32: - exit.m_values[i] = ExitValue::inJSStackAsInt32(flush.virtualRegister()); - break; - - case FlushedInt52: - exit.m_values[i] = ExitValue::inJSStackAsInt52(flush.virtualRegister()); - break; - - case FlushedDouble: - exit.m_values[i] = ExitValue::inJSStackAsDouble(flush.virtualRegister()); - break; - - case FlushedArguments: - // FIXME: implement PhantomArguments. - // https://bugs.webkit.org/show_bug.cgi?id=113986 - RELEASE_ASSERT_NOT_REACHED(); - break; - } - } - - if (verboseCompilationEnabled()) - dataLog(" Exit values: ", exit.m_values, "\n"); - } - - void callStackmap(OSRExit& exit, ExitArgumentList& arguments) - { - exit.m_stackmapID = m_stackmapIDs++; - arguments.insert(0, m_out.constInt32(MacroAssembler::maxJumpReplacementSize())); - arguments.insert(0, m_out.constInt32(exit.m_stackmapID)); - - m_out.call(m_out.stackmapIntrinsic(), arguments); - } - - void addExitArgumentForNode( - OSRExit& exit, ExitArgumentList& arguments, unsigned index, Node* node) - { - ASSERT(node->shouldGenerate()); - ASSERT(node->hasResult()); - - if (tryToSetConstantExitArgument(exit, index, node)) - return; - - LoweredNodeValue value = m_int32Values.get(node); - if (isValid(value)) { - addExitArgument(exit, arguments, index, ValueFormatInt32, value.value()); - return; - } - - value = m_int52Values.get(node); - if (isValid(value)) { - addExitArgument(exit, arguments, index, ValueFormatInt52, value.value()); - return; - } - - value = m_strictInt52Values.get(node); - if (isValid(value)) { - addExitArgument(exit, arguments, index, ValueFormatStrictInt52, value.value()); - return; - } - - value = m_booleanValues.get(node); - if (isValid(value)) { - LValue valueToPass = m_out.zeroExt(value.value(), m_out.int32); - addExitArgument(exit, arguments, index, ValueFormatBoolean, valueToPass); - return; - } - - value = m_jsValueValues.get(node); - if (isValid(value)) { - addExitArgument(exit, arguments, index, ValueFormatJSValue, value.value()); - return; - } - - value = m_doubleValues.get(node); - if (isValid(value)) { - addExitArgument(exit, arguments, index, ValueFormatDouble, value.value()); - return; - } - - dataLog("Cannot find value for node: ", node, "\n"); - RELEASE_ASSERT_NOT_REACHED(); - } - - bool tryToSetConstantExitArgument(OSRExit& exit, unsigned index, Node* node) - { - if (!node) - return false; - - switch (node->op()) { - case JSConstant: - case WeakJSConstant: - exit.m_values[index] = ExitValue::constant(m_graph.valueOfJSConstant(node)); - return true; - case PhantomArguments: - // FIXME: implement PhantomArguments. - // https://bugs.webkit.org/show_bug.cgi?id=113986 - RELEASE_ASSERT_NOT_REACHED(); - return true; - default: - return false; - } - } - - void addExitArgument( - OSRExit& exit, ExitArgumentList& arguments, unsigned index, ValueFormat format, - LValue value) - { - exit.m_values[index] = ExitValue::exitArgument(ExitArgument(format, arguments.size())); - arguments.append(value); - } - - void setInt32(Node* node, LValue value) - { - m_int32Values.set(node, LoweredNodeValue(value, m_highBlock)); - } - void setInt52(Node* node, LValue value) - { - m_int52Values.set(node, LoweredNodeValue(value, m_highBlock)); - } - void setStrictInt52(Node* node, LValue value) - { - m_strictInt52Values.set(node, LoweredNodeValue(value, m_highBlock)); - } - void setInt52(Node* node, LValue value, Int52Kind kind) - { - switch (kind) { - case Int52: - setInt52(node, value); - return; - - case StrictInt52: - setStrictInt52(node, value); - return; - } - - RELEASE_ASSERT_NOT_REACHED(); - } - void setJSValue(Node* node, LValue value) - { - m_jsValueValues.set(node, LoweredNodeValue(value, m_highBlock)); - } - void setBoolean(Node* node, LValue value) - { - m_booleanValues.set(node, LoweredNodeValue(value, m_highBlock)); - } - void setStorage(Node* node, LValue value) - { - m_storageValues.set(node, LoweredNodeValue(value, m_highBlock)); - } - void setDouble(Node* node, LValue value) - { - m_doubleValues.set(node, LoweredNodeValue(value, m_highBlock)); - } - - void setInt32(LValue value) - { - setInt32(m_node, value); - } - void setInt52(LValue value) - { - setInt52(m_node, value); - } - void setStrictInt52(LValue value) - { - setStrictInt52(m_node, value); - } - void setInt52(LValue value, Int52Kind kind) - { - setInt52(m_node, value, kind); - } - void setJSValue(LValue value) - { - setJSValue(m_node, value); - } - void setBoolean(LValue value) - { - setBoolean(m_node, value); - } - void setStorage(LValue value) - { - setStorage(m_node, value); - } - void setDouble(LValue value) - { - setDouble(m_node, value); - } - - bool isValid(const LoweredNodeValue& value) - { - if (!value) - return false; - if (!m_graph.m_dominators.dominates(value.block(), m_highBlock)) - return false; - return true; - } - - void addWeakReference(JSCell* target) - { - m_graph.m_plan.weakReferences.addLazily(target); - } - - LValue weakPointer(JSCell* pointer) - { - addWeakReference(pointer); - return m_out.constIntPtr(pointer); - } - - TypedPointer addressFor(LValue base, int operand, ptrdiff_t offset = 0) - { - return m_out.address(base, m_heaps.variables[operand], offset); - } - TypedPointer payloadFor(LValue base, int operand) - { - return addressFor(base, operand, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)); - } - TypedPointer tagFor(LValue base, int operand) - { - return addressFor(base, operand, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)); - } - TypedPointer addressFor(int operand) - { - return addressFor(m_callFrame, operand); - } - TypedPointer addressFor(VirtualRegister operand) - { - return addressFor(m_callFrame, operand.offset()); - } - TypedPointer payloadFor(int operand) - { - return payloadFor(m_callFrame, operand); - } - TypedPointer payloadFor(VirtualRegister operand) - { - return payloadFor(m_callFrame, operand.offset()); - } - TypedPointer tagFor(int operand) - { - return tagFor(m_callFrame, operand); - } - TypedPointer tagFor(VirtualRegister operand) - { - return tagFor(m_callFrame, operand.offset()); - } - - VM& vm() { return m_graph.m_vm; } - CodeBlock* codeBlock() { return m_graph.m_codeBlock; } - - Graph& m_graph; - State& m_ftlState; - AbstractHeapRepository m_heaps; - Output m_out; - - LBasicBlock m_prologue; - HashMap<BasicBlock*, LBasicBlock> m_blocks; - - LValue m_callFrame; - LValue m_tagTypeNumber; - LValue m_tagMask; - - HashMap<Node*, LoweredNodeValue> m_int32Values; - HashMap<Node*, LoweredNodeValue> m_strictInt52Values; - HashMap<Node*, LoweredNodeValue> m_int52Values; - HashMap<Node*, LoweredNodeValue> m_jsValueValues; - HashMap<Node*, LoweredNodeValue> m_booleanValues; - HashMap<Node*, LoweredNodeValue> m_storageValues; - HashMap<Node*, LoweredNodeValue> m_doubleValues; - - HashMap<Node*, LValue> m_phis; - - Operands<Availability> m_availability; - - InPlaceAbstractState m_state; - AbstractInterpreter<InPlaceAbstractState> m_interpreter; - BasicBlock* m_highBlock; - BasicBlock* m_nextHighBlock; - LBasicBlock m_nextLowBlock; - - CodeOrigin m_codeOriginForExitTarget; - CodeOrigin m_codeOriginForExitProfile; - unsigned m_nodeIndex; - Node* m_node; - - uint32_t m_stackmapIDs; -}; - -void lowerDFGToLLVM(State& state) -{ - LowerDFGToLLVM lowering(state); - lowering.lower(); -} - -} } // namespace JSC::FTL - -#endif // ENABLE(FTL_JIT) - |