summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp')
-rw-r--r--Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp4515
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)
-