Merge the jsCStack branch
https://bugs.webkit.org/show_bug.cgi?id=127763
Reviewed by Mark Hahnenberg.
Source/JavaScriptCore:
Changes from http://svn.webkit.org/repository/webkit/branches/jsCStack
up to changeset 162958.
Source/WebCore:
Changes from http://svn.webkit.org/repository/webkit/branches/jsCStack
up to changeset 162958.
Source/WTF:
Changes from http://svn.webkit.org/repository/webkit/branches/jsCStack
up to changeset 162958.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@163027 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
index be2a40c..198a0bb 100644
--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -32,6 +32,7 @@
#include "DFGAbstractInterpreterInlines.h"
#include "DFGInPlaceAbstractState.h"
#include "FTLAbstractHeapRepository.h"
+#include "FTLAvailableRecovery.h"
#include "FTLForOSREntryJITCode.h"
#include "FTLFormattedValue.h"
#include "FTLInlineCacheSize.h"
@@ -51,6 +52,10 @@
static std::atomic<int> compileCounter;
+// FIXME: Get rid of this and introduce a real stack check.
+// https://bugs.webkit.org/show_bug.cgi?id=125650
+static uintptr_t stackLimit;
+
// 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 { \
@@ -92,19 +97,20 @@
llvm->ModuleCreateWithNameInContext(name.data(), m_ftlState.context);
m_ftlState.function = addFunction(
- m_ftlState.module, name.data(), functionType(m_out.int64, m_out.intPtr));
+ m_ftlState.module, name.data(), functionType(m_out.int64));
setFunctionCallingConv(m_ftlState.function, LLVMCCallConv);
+ if (isX86() && Options::llvmDisallowAVX()) {
+ // AVX makes V8/raytrace 80% slower. It makes Kraken/audio-oscillator 4.5x
+ // slower. It should be disabled.
+ addTargetDependentFunctionAttr(m_ftlState.function, "target-features", "-avx");
+ }
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);
-
+ m_prologue = FTL_NEW_BLOCK(m_out, ("Prologue"));
+ LBasicBlock stackOverflow = FTL_NEW_BLOCK(m_out, ("Stack overflow"));
+ m_handleExceptions = FTL_NEW_BLOCK(m_out, ("Handle Exceptions"));
+
for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
m_highBlock = m_graph.block(blockIndex);
if (!m_highBlock)
@@ -112,8 +118,42 @@
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)));
+ m_out.appendTo(m_prologue, stackOverflow);
+ createPhiVariables();
+ LValue capturedAlloca = m_out.alloca(arrayType(m_out.int64, m_graph.m_nextMachineLocal));
+ m_captured = m_out.add(
+ m_out.ptrToInt(capturedAlloca, m_out.intPtr),
+ m_out.constIntPtr(m_graph.m_nextMachineLocal * sizeof(Register)));
+
+ // We should not create any alloca's after this point, since they will cease to
+ // be mem2reg candidates.
+
+ m_ftlState.capturedStackmapID = m_stackmapIDs++;
+ m_out.call(
+ m_out.stackmapIntrinsic(), m_out.constInt64(m_ftlState.capturedStackmapID),
+ m_out.int32Zero, capturedAlloca);
+
+ m_callFrame = m_out.ptrToInt(
+ m_out.call(m_out.frameAddressIntrinsic(), m_out.int32Zero), m_out.intPtr);
+ m_tagTypeNumber = m_out.constInt64(TagTypeNumber);
+ m_tagMask = m_out.constInt64(TagMask);
+
+ m_out.storePtr(m_out.constIntPtr(codeBlock()), addressFor(JSStack::CodeBlock));
+ m_out.branch(
+ m_out.below(m_callFrame, m_out.loadPtr(m_out.absolute(&stackLimit))),
+ stackOverflow, lowBlock(m_graph.block(0)));
+
+ m_out.appendTo(stackOverflow, m_handleExceptions);
+ // FIXME: Do a real stack check and throw the exception appropriately.
+ // https://bugs.webkit.org/show_bug.cgi?id=125650
+ m_out.crash();
+
+ m_out.appendTo(m_handleExceptions, lowBlock(m_graph.block(0)));
+ m_ftlState.handleExceptionStackmapID = m_stackmapIDs++;
+ m_out.call(
+ m_out.stackmapIntrinsic(), m_out.constInt64(m_ftlState.handleExceptionStackmapID),
+ m_out.constInt32(MacroAssembler::maxJumpReplacementSize()));
+ m_out.unreachable();
Vector<BasicBlock*> depthFirst;
m_graph.getBlocksInDepthFirstOrder(depthFirst);
@@ -226,6 +266,8 @@
if (verboseCompilationEnabled())
dataLog("Lowering ", m_node, "\n");
+ m_availableRecoveries.resize(0);
+
bool shouldExecuteEffects = m_interpreter.startExecuting(m_node);
switch (m_node->op()) {
@@ -265,19 +307,17 @@
compileValueAdd();
break;
case ArithAdd:
- compileAddSub();
- break;
case ArithSub:
- compileAddSub();
+ compileArithAddOrSub();
break;
case ArithMul:
compileArithMul();
break;
case ArithDiv:
- compileArithDivMod();
+ compileArithDiv();
break;
case ArithMod:
- compileArithDivMod();
+ compileArithMod();
break;
case ArithMin:
case ArithMax:
@@ -286,6 +326,15 @@
case ArithAbs:
compileArithAbs();
break;
+ case ArithSin:
+ compileArithSin();
+ break;
+ case ArithCos:
+ compileArithCos();
+ break;
+ case ArithSqrt:
+ compileArithSqrt();
+ break;
case ArithNegate:
compileArithNegate();
break;
@@ -322,6 +371,9 @@
case CheckFunction:
compileCheckFunction();
break;
+ case CheckExecutable:
+ compileCheckExecutable();
+ break;
case ArrayifyToStructure:
compileArrayifyToStructure();
break;
@@ -334,6 +386,7 @@
case GetById:
compileGetById();
break;
+ case PutByIdDirect:
case PutById:
compilePutById();
break;
@@ -372,9 +425,18 @@
case NewArrayBuffer:
compileNewArrayBuffer();
break;
+ case NewArrayWithSize:
+ compileNewArrayWithSize();
+ break;
case AllocatePropertyStorage:
compileAllocatePropertyStorage();
break;
+ case ToString:
+ compileToString();
+ break;
+ case MakeRope:
+ compileMakeRope();
+ break;
case StringCharAt:
compileStringCharAt();
break;
@@ -396,6 +458,12 @@
case NotifyWrite:
compileNotifyWrite();
break;
+ case GetCallee:
+ compileGetCallee();
+ break;
+ case GetScope:
+ compileGetScope();
+ break;
case GetMyScope:
compileGetMyScope();
break;
@@ -466,6 +534,12 @@
case Int52ToValue:
compileInt52ToValue();
break;
+ case CheckArgumentsNotCreated:
+ compileCheckArgumentsNotCreated();
+ break;
+ case CountExecution:
+ compileCountExecution();
+ break;
case StoreBarrier:
compileStoreBarrier();
break;
@@ -482,6 +556,7 @@
case VariableWatchpoint:
case FunctionReentryWatchpoint:
case TypedArrayWatchpoint:
+ case AllocationProfileWatchpoint:
break;
default:
RELEASE_ASSERT_NOT_REACHED();
@@ -815,24 +890,53 @@
lowJSValue(m_node->child1()), lowJSValue(m_node->child2())));
}
- void compileAddSub()
+ void compileArithAddOrSub()
{
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);
+ setInt32(isSub ? m_out.sub(left, right) : m_out.add(left, right));
break;
}
- LValue overflow = isSub ? m_out.subWithOverflow32(left, right) : m_out.addWithOverflow32(left, right);
+ LValue result;
+ if (!isSub) {
+ result = m_out.addWithOverflow32(left, right);
+
+ if (doesKill(m_node->child2())) {
+ addAvailableRecovery(
+ m_node->child2(), SubRecovery,
+ m_out.extractValue(result, 0), left, ValueFormatInt32);
+ } else if (doesKill(m_node->child1())) {
+ addAvailableRecovery(
+ m_node->child1(), SubRecovery,
+ m_out.extractValue(result, 0), right, ValueFormatInt32);
+ }
+ } else {
+ result = m_out.subWithOverflow32(left, right);
+
+ if (doesKill(m_node->child2())) {
+ // result = left - right
+ // result - left = -right
+ // right = left - result
+ addAvailableRecovery(
+ m_node->child2(), SubRecovery,
+ left, m_out.extractValue(result, 0), ValueFormatInt32);
+ } else if (doesKill(m_node->child1())) {
+ // result = left - right
+ // result + right = left
+ addAvailableRecovery(
+ m_node->child1(), AddRecovery,
+ m_out.extractValue(result, 0), right, ValueFormatInt32);
+ }
+ }
- speculate(Overflow, noValue(), 0, m_out.extractValue(overflow, 1));
- setInt32(result);
+ speculate(Overflow, noValue(), 0, m_out.extractValue(result, 1));
+ setInt32(m_out.extractValue(result, 0));
break;
}
@@ -848,11 +952,41 @@
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);
+ LValue result;
+ if (!isSub) {
+ result = m_out.addWithOverflow64(left, right);
+
+ if (doesKill(m_node->child2())) {
+ addAvailableRecovery(
+ m_node->child2(), SubRecovery,
+ m_out.extractValue(result, 0), left, ValueFormatInt52);
+ } else if (doesKill(m_node->child1())) {
+ addAvailableRecovery(
+ m_node->child1(), SubRecovery,
+ m_out.extractValue(result, 0), right, ValueFormatInt52);
+ }
+ } else {
+ result = m_out.subWithOverflow64(left, right);
+
+ if (doesKill(m_node->child2())) {
+ // result = left - right
+ // result - left = -right
+ // right = left - result
+ addAvailableRecovery(
+ m_node->child2(), SubRecovery,
+ left, m_out.extractValue(result, 0), ValueFormatInt52);
+ } else if (doesKill(m_node->child1())) {
+ // result = left - right
+ // result + right = left
+ addAvailableRecovery(
+ m_node->child1(), AddRecovery,
+ m_out.extractValue(result, 0), right, ValueFormatInt52);
+ }
+ }
+
+ speculate(Int52Overflow, noValue(), 0, m_out.extractValue(result, 1));
+ setInt52(m_out.extractValue(result, 0));
break;
}
@@ -876,11 +1010,15 @@
case Int32Use: {
LValue left = lowInt32(m_node->child1());
LValue right = lowInt32(m_node->child2());
- LValue result = m_out.mul(left, right);
+
+ LValue result;
- if (shouldCheckOverflow(m_node->arithMode())) {
+ if (!shouldCheckOverflow(m_node->arithMode()))
+ result = m_out.mul(left, right);
+ else {
LValue overflowResult = m_out.mulWithOverflow32(left, right);
speculate(Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
+ result = m_out.extractValue(overflowResult, 0);
}
if (shouldCheckNegativeZero(m_node->arithMode())) {
@@ -904,11 +1042,10 @@
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));
+ LValue result = m_out.extractValue(overflowResult, 0);
if (shouldCheckNegativeZero(m_node->arithMode())) {
LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("ArithMul slow case"));
@@ -939,16 +1076,16 @@
}
}
- void compileArithDivMod()
+ void compileArithDiv()
{
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"));
+ LBasicBlock unsafeDenominator = FTL_NEW_BLOCK(m_out, ("ArithDiv unsafe denominator"));
+ LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithDiv continuation"));
+ LBasicBlock done = FTL_NEW_BLOCK(m_out, ("ArithDiv done"));
Vector<ValueFromBlock, 3> results;
@@ -991,8 +1128,8 @@
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"));
+ LBasicBlock zeroNumerator = FTL_NEW_BLOCK(m_out, ("ArithDiv zero numerator"));
+ LBasicBlock numeratorContinuation = FTL_NEW_BLOCK(m_out, ("ArithDiv numerator continuation"));
m_out.branch(m_out.isZero32(numerator), zeroNumerator, numeratorContinuation);
@@ -1006,17 +1143,15 @@
m_out.appendTo(numeratorContinuation, innerLastNext);
}
- LValue divModResult = m_node->op() == ArithDiv
- ? m_out.div(numerator, denominator)
- : m_out.rem(numerator, denominator);
+ LValue result = m_out.div(numerator, denominator);
if (shouldCheckOverflow(m_node->arithMode())) {
speculate(
Overflow, noValue(), 0,
- m_out.notEqual(m_out.mul(divModResult, denominator), numerator));
+ m_out.notEqual(m_out.mul(result, denominator), numerator));
}
- results.append(m_out.anchor(divModResult));
+ results.append(m_out.anchor(result));
m_out.jump(done);
m_out.appendTo(done, lastNext);
@@ -1026,9 +1161,8 @@
}
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));
+ setDouble(m_out.doubleDiv(
+ lowDouble(m_node->child1()), lowDouble(m_node->child2())));
break;
}
@@ -1038,6 +1172,99 @@
}
}
+ void compileArithMod()
+ {
+ 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, ("ArithMod unsafe denominator"));
+ LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMod continuation"));
+ LBasicBlock done = FTL_NEW_BLOCK(m_out, ("ArithMod 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);
+
+ // FIXME: -2^31 / -1 will actually yield negative zero, so we could have a
+ // separate case for that. But it probably doesn't matter so much.
+ 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 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 modByZero = FTL_NEW_BLOCK(m_out, ("ArithMod modulo by zero"));
+ LBasicBlock notModByZero = FTL_NEW_BLOCK(m_out, ("ArithMod not modulo by zero"));
+ LBasicBlock neg2ToThe31ByNeg1 = FTL_NEW_BLOCK(m_out, ("ArithMod -2^31/-1"));
+
+ m_out.branch(m_out.isZero32(denominator), modByZero, notModByZero);
+
+ m_out.appendTo(modByZero, notModByZero);
+ results.append(m_out.anchor(m_out.int32Zero));
+ m_out.jump(done);
+
+ m_out.appendTo(notModByZero, neg2ToThe31ByNeg1);
+ m_out.branch(m_out.equal(numerator, neg2ToThe31), neg2ToThe31ByNeg1, continuation);
+
+ m_out.appendTo(neg2ToThe31ByNeg1, continuation);
+ results.append(m_out.anchor(m_out.int32Zero));
+ m_out.jump(done);
+ }
+
+ m_out.appendTo(continuation, done);
+
+ LValue remainder = m_out.rem(numerator, denominator);
+
+ if (shouldCheckNegativeZero(m_node->arithMode())) {
+ LBasicBlock negativeNumerator = FTL_NEW_BLOCK(m_out, ("ArithMod negative numerator"));
+ LBasicBlock numeratorContinuation = FTL_NEW_BLOCK(m_out, ("ArithMod numerator continuation"));
+
+ m_out.branch(
+ m_out.lessThan(numerator, m_out.int32Zero),
+ negativeNumerator, numeratorContinuation);
+
+ LBasicBlock innerLastNext = m_out.appendTo(negativeNumerator, numeratorContinuation);
+
+ speculate(NegativeZero, noValue(), 0, m_out.isZero32(remainder));
+
+ m_out.jump(numeratorContinuation);
+
+ m_out.appendTo(numeratorContinuation, innerLastNext);
+ }
+
+ results.append(m_out.anchor(remainder));
+ m_out.jump(done);
+
+ m_out.appendTo(done, lastNext);
+
+ setInt32(m_out.phi(m_out.int32, results));
+ break;
+ }
+
+ case NumberUse: {
+ setDouble(
+ m_out.doubleRem(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
+ break;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
+ }
+
void compileArithMinOrMax()
{
switch (m_node->binaryUseKind()) {
@@ -1114,6 +1341,12 @@
break;
}
}
+
+ void compileArithSin() { setDouble(m_out.doubleSin(lowDouble(m_node->child1()))); }
+
+ void compileArithCos() { setDouble(m_out.doubleCos(lowDouble(m_node->child1()))); }
+
+ void compileArithSqrt() { setDouble(m_out.doubleSqrt(lowDouble(m_node->child1()))); }
void compileArithNegate()
{
@@ -1121,16 +1354,18 @@
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)));
-
+ LValue result;
+ if (!shouldCheckOverflow(m_node->arithMode()))
+ result = m_out.neg(value);
+ else 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));
+ result = m_out.extractValue(overflowResult, 0);
+ } else {
+ speculate(Overflow, noValue(), 0, m_out.testIsZero32(value, m_out.constInt32(0x7fffffff)));
+ result = m_out.neg(value);
}
setInt32(result);
@@ -1151,7 +1386,7 @@
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);
+ LValue result = m_out.extractValue(overflowResult, 0);
speculate(NegativeZero, noValue(), 0, m_out.isZero64(result));
setInt52(result);
break;
@@ -1275,6 +1510,17 @@
m_out.notEqual(cell, weakPointer(m_node->function())));
}
+ void compileCheckExecutable()
+ {
+ LValue cell = lowCell(m_node->child1());
+
+ speculate(
+ BadExecutable, jsValueValue(cell), m_node->child1().node(),
+ m_out.notEqual(
+ m_out.loadPtr(cell, m_heaps.JSFunction_executable),
+ weakPointer(m_node->executable())));
+ }
+
void compileArrayifyToStructure()
{
LValue cell = lowCell(m_node->child1());
@@ -1370,8 +1616,8 @@
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);
+ m_out.constInt64(stackmapID), m_out.constInt32(sizeOfGetById()),
+ constNull(m_out.ref8), m_out.constInt32(1), base);
setInstructionCallingConvention(call, LLVMAnyRegCallConv);
setJSValue(call);
@@ -1395,8 +1641,8 @@
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);
+ m_out.constInt64(stackmapID), m_out.constInt32(sizeOfPutById()),
+ constNull(m_out.ref8), m_out.constInt32(2), base, value);
setInstructionCallingConvention(call, LLVMAnyRegCallConv);
m_ftlState.putByIds.append(PutByIdDescriptor(
@@ -1463,20 +1709,20 @@
case Array::Int32:
case Array::Double:
case Array::Contiguous: {
- setInt32(m_out.load32(lowStorage(m_node->child2()), m_heaps.Butterfly_publicLength));
+ setInt32(m_out.load32NonNegative(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));
+ setInt32(m_out.load32NonNegative(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));
+ m_out.load32NonNegative(lowCell(m_node->child1()), m_heaps.JSArrayBufferView_length));
return;
}
@@ -1518,7 +1764,7 @@
m_out.branch(
m_out.aboveOrEqual(
- index, m_out.load32(storage, m_heaps.Butterfly_publicLength)),
+ index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength)),
slowCase, fastCase);
LBasicBlock lastNext = m_out.appendTo(fastCase, slowCase);
@@ -1565,7 +1811,7 @@
m_out.branch(
m_out.aboveOrEqual(
- index, m_out.load32(storage, m_heaps.Butterfly_publicLength)),
+ index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength)),
slowCase, inBounds);
LBasicBlock lastNext = m_out.appendTo(inBounds, boxPath);
@@ -1687,6 +1933,7 @@
Edge child2 = m_graph.varArgChild(m_node, 1);
Edge child3 = m_graph.varArgChild(m_node, 2);
Edge child4 = m_graph.varArgChild(m_node, 3);
+ Edge child5 = m_graph.varArgChild(m_node, 4);
switch (m_node->arrayMode().type()) {
case Array::Generic: {
@@ -1801,6 +2048,9 @@
m_out.zeroExt(index, m_out.intPtr),
m_out.constIntPtr(logElementSize(type)))));
+ LType refType;
+ LValue valueToStore;
+
if (isInt(type)) {
LValue intValue;
switch (child3.useKind()) {
@@ -1876,34 +2126,53 @@
switch (elementSize(type)) {
case 1:
- m_out.store8(m_out.intCast(intValue, m_out.int8), pointer);
+ valueToStore = m_out.intCast(intValue, m_out.int8);
+ refType = m_out.ref8;
break;
case 2:
- m_out.store16(m_out.intCast(intValue, m_out.int16), pointer);
+ valueToStore = m_out.intCast(intValue, m_out.int16);
+ refType = m_out.ref16;
break;
case 4:
- m_out.store32(intValue, pointer);
+ valueToStore = intValue;
+ refType = m_out.ref32;
break;
default:
RELEASE_ASSERT_NOT_REACHED();
}
+ } else /* !isInt(type) */ {
+ LValue value = lowDouble(child3);
+ switch (type) {
+ case TypeFloat32:
+ valueToStore = m_out.fpCast(value, m_out.floatType);
+ refType = m_out.refFloat;
+ break;
+ case TypeFloat64:
+ valueToStore = value;
+ refType = m_out.refDouble;
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+ }
+
+ if (m_node->arrayMode().isInBounds())
+ m_out.store(valueToStore, pointer, refType);
+ else {
+ LBasicBlock isInBounds = FTL_NEW_BLOCK(m_out, ("PutByVal typed array in bounds case"));
+ LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("PutByVal typed array continuation"));
- return;
+ m_out.branch(
+ m_out.aboveOrEqual(index, lowInt32(child5)),
+ continuation, isInBounds);
+
+ LBasicBlock lastNext = m_out.appendTo(isInBounds, continuation);
+ m_out.store(valueToStore, pointer, refType);
+ m_out.jump(continuation);
+
+ m_out.appendTo(continuation, lastNext);
}
- 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;
}
@@ -2060,6 +2329,109 @@
m_out.constIntPtr(m_node->numConstants())));
}
+ void compileNewArrayWithSize()
+ {
+ LValue publicLength = lowInt32(m_node->child1());
+
+ JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->codeOrigin);
+ Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(
+ m_node->indexingType());
+
+ if (!globalObject->isHavingABadTime() && !hasArrayStorage(m_node->indexingType())) {
+ ASSERT(
+ hasUndecided(structure->indexingType())
+ || hasInt32(structure->indexingType())
+ || hasDouble(structure->indexingType())
+ || hasContiguous(structure->indexingType()));
+
+ LBasicBlock fastCase = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize fast case"));
+ LBasicBlock largeCase = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize large case"));
+ LBasicBlock failCase = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize fail case"));
+ LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize slow case"));
+ LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize continuation"));
+
+ m_out.branch(
+ m_out.aboveOrEqual(publicLength, m_out.constInt32(MIN_SPARSE_ARRAY_INDEX)),
+ largeCase, fastCase);
+
+ LBasicBlock lastNext = m_out.appendTo(fastCase, largeCase);
+
+ // We don't round up to BASE_VECTOR_LEN for new Array(blah).
+ LValue vectorLength = publicLength;
+
+ LValue payloadSize =
+ m_out.shl(m_out.zeroExt(vectorLength, m_out.intPtr), m_out.constIntPtr(3));
+
+ LValue butterflySize = m_out.add(
+ payloadSize, m_out.constIntPtr(sizeof(IndexingHeader)));
+
+ LValue endOfStorage = allocateBasicStorageAndGetEnd(butterflySize, failCase);
+
+ LValue butterfly = m_out.sub(endOfStorage, payloadSize);
+
+ LValue object = allocateObject<JSArray>(
+ m_out.constIntPtr(structure), butterfly, failCase);
+
+ m_out.store32(publicLength, butterfly, m_heaps.Butterfly_publicLength);
+ m_out.store32(vectorLength, butterfly, m_heaps.Butterfly_vectorLength);
+
+ if (hasDouble(m_node->indexingType())) {
+ LBasicBlock initLoop = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize double init loop"));
+ LBasicBlock initDone = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize double init done"));
+
+ ValueFromBlock originalIndex = m_out.anchor(vectorLength);
+ ValueFromBlock originalPointer = m_out.anchor(butterfly);
+ m_out.branch(m_out.notZero32(vectorLength), initLoop, initDone);
+
+ LBasicBlock initLastNext = m_out.appendTo(initLoop, initDone);
+ LValue index = m_out.phi(m_out.int32, originalIndex);
+ LValue pointer = m_out.phi(m_out.intPtr, originalPointer);
+
+ m_out.store64(
+ m_out.constInt64(bitwise_cast<int64_t>(QNaN)),
+ TypedPointer(m_heaps.indexedDoubleProperties.atAnyIndex(), pointer));
+
+ LValue nextIndex = m_out.sub(index, m_out.int32One);
+ addIncoming(index, m_out.anchor(nextIndex));
+ addIncoming(pointer, m_out.anchor(m_out.add(pointer, m_out.intPtrEight)));
+ m_out.branch(m_out.notZero32(nextIndex), initLoop, initDone);
+
+ m_out.appendTo(initDone, initLastNext);
+ }
+
+ ValueFromBlock fastResult = m_out.anchor(object);
+ m_out.jump(continuation);
+
+ m_out.appendTo(largeCase, failCase);
+ ValueFromBlock largeStructure = m_out.anchor(m_out.constIntPtr(
+ globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage)));
+ m_out.jump(slowCase);
+
+ m_out.appendTo(failCase, slowCase);
+ ValueFromBlock failStructure = m_out.anchor(m_out.constIntPtr(structure));
+ m_out.jump(slowCase);
+
+ m_out.appendTo(slowCase, continuation);
+ LValue structureValue = m_out.phi(
+ m_out.intPtr, largeStructure, failStructure);
+ ValueFromBlock slowResult = m_out.anchor(vmCall(
+ m_out.operation(operationNewArrayWithSize),
+ m_callFrame, structureValue, publicLength));
+ m_out.jump(continuation);
+
+ m_out.appendTo(continuation, lastNext);
+ setJSValue(m_out.phi(m_out.intPtr, fastResult, slowResult));
+ return;
+ }
+
+ LValue structureValue = m_out.select(
+ m_out.aboveOrEqual(publicLength, m_out.constInt32(MIN_SPARSE_ARRAY_INDEX)),
+ m_out.constIntPtr(
+ globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage)),
+ m_out.constIntPtr(structure));
+ setJSValue(vmCall(m_out.operation(operationNewArrayWithSize), m_callFrame, structureValue, publicLength));
+ }
+
void compileAllocatePropertyStorage()
{
StructureTransitionData& data = m_node->structureTransitionData();
@@ -2102,6 +2474,160 @@
setStorage(result);
}
+ void compileToString()
+ {
+ switch (m_node->child1().useKind()) {
+ case StringObjectUse: {
+ LValue cell = lowCell(m_node->child1());
+ speculateStringObjectForCell(m_node->child1(), cell);
+ m_interpreter.filter(m_node->child1(), SpecStringObject);
+
+ setJSValue(m_out.loadPtr(cell, m_heaps.JSWrapperObject_internalValue));
+ return;
+ }
+
+ case StringOrStringObjectUse: {
+ LValue cell = lowCell(m_node->child1());
+ LValue structure = m_out.loadPtr(cell, m_heaps.JSCell_structure);
+
+ LBasicBlock notString = FTL_NEW_BLOCK(m_out, ("ToString StringOrStringObject not string case"));
+ LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ToString StringOrStringObject continuation"));
+
+ ValueFromBlock simpleResult = m_out.anchor(cell);
+ m_out.branch(
+ m_out.equal(structure, m_out.constIntPtr(vm().stringStructure.get())),
+ continuation, notString);
+
+ LBasicBlock lastNext = m_out.appendTo(notString, continuation);
+ speculateStringObjectForStructure(m_node->child1(), structure);
+ ValueFromBlock unboxedResult = m_out.anchor(
+ m_out.loadPtr(cell, m_heaps.JSWrapperObject_internalValue));
+ m_out.jump(continuation);
+
+ m_out.appendTo(continuation, lastNext);
+ setJSValue(m_out.phi(m_out.int64, simpleResult, unboxedResult));
+
+ m_interpreter.filter(m_node->child1(), SpecString | SpecStringObject);
+ return;
+ }
+
+ case CellUse:
+ case UntypedUse: {
+ LValue value;
+ if (m_node->child1().useKind() == CellUse)
+ value = lowCell(m_node->child1());
+ else
+ value = lowJSValue(m_node->child1());
+
+ LBasicBlock isCell = FTL_NEW_BLOCK(m_out, ("ToString CellUse/UntypedUse is cell"));
+ LBasicBlock notString = FTL_NEW_BLOCK(m_out, ("ToString CellUse/UntypedUse not string"));
+ LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ToString CellUse/UntypedUse continuation"));
+
+ LValue isCellPredicate;
+ if (m_node->child1().useKind() == CellUse)
+ isCellPredicate = m_out.booleanTrue;
+ else
+ isCellPredicate = this->isCell(value);
+ m_out.branch(isCellPredicate, isCell, notString);
+
+ LBasicBlock lastNext = m_out.appendTo(isCell, notString);
+ ValueFromBlock simpleResult = m_out.anchor(value);
+ LValue isStringPredicate;
+ if (m_node->child1()->prediction() & SpecString) {
+ isStringPredicate = m_out.equal(
+ m_out.loadPtr(value, m_heaps.JSCell_structure),
+ m_out.constIntPtr(vm().stringStructure.get()));
+ } else
+ isStringPredicate = m_out.booleanFalse;
+ m_out.branch(isStringPredicate, continuation, notString);
+
+ m_out.appendTo(notString, continuation);
+ LValue operation;
+ if (m_node->child1().useKind() == CellUse)
+ operation = m_out.operation(operationToStringOnCell);
+ else
+ operation = m_out.operation(operationToString);
+ ValueFromBlock convertedResult = m_out.anchor(vmCall(operation, m_callFrame, value));
+ m_out.jump(continuation);
+
+ m_out.appendTo(continuation, lastNext);
+ setJSValue(m_out.phi(m_out.int64, simpleResult, convertedResult));
+ return;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
+ }
+
+ void compileMakeRope()
+ {
+ LValue kids[3];
+ unsigned numKids;
+ kids[0] = lowCell(m_node->child1());
+ kids[1] = lowCell(m_node->child2());
+ if (m_node->child3()) {
+ kids[2] = lowCell(m_node->child3());
+ numKids = 3;
+ } else {
+ kids[2] = 0;
+ numKids = 2;
+ }
+
+ LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("MakeRope slow path"));
+ LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("MakeRope continuation"));
+
+ LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath);
+
+ MarkedAllocator& allocator =
+ vm().heap.allocatorForObjectWithImmortalStructureDestructor(sizeof(JSRopeString));
+
+ LValue result = allocateCell(
+ m_out.constIntPtr(&allocator),
+ m_out.constIntPtr(vm().stringStructure.get()),
+ slowPath);
+
+ m_out.storePtr(m_out.intPtrZero, result, m_heaps.JSString_value);
+ for (unsigned i = 0; i < numKids; ++i)
+ m_out.storePtr(kids[i], result, m_heaps.JSRopeString_fibers[i]);
+ for (unsigned i = numKids; i < JSRopeString::s_maxInternalRopeLength; ++i)
+ m_out.storePtr(m_out.intPtrZero, result, m_heaps.JSRopeString_fibers[i]);
+ LValue flags = m_out.load32(kids[0], m_heaps.JSString_flags);
+ LValue length = m_out.load32(kids[0], m_heaps.JSString_length);
+ for (unsigned i = 1; i < numKids; ++i) {
+ flags = m_out.bitAnd(flags, m_out.load32(kids[i], m_heaps.JSString_flags));
+ length = m_out.add(length, m_out.load32(kids[i], m_heaps.JSString_length));
+ }
+ m_out.store32(
+ m_out.bitAnd(m_out.constInt32(JSString::Is8Bit), flags),
+ result, m_heaps.JSString_flags);
+ m_out.store32(length, result, m_heaps.JSString_length);
+
+ ValueFromBlock fastResult = m_out.anchor(result);
+ m_out.jump(continuation);
+
+ m_out.appendTo(slowPath, continuation);
+ ValueFromBlock slowResult;
+ switch (numKids) {
+ case 2:
+ slowResult = m_out.anchor(vmCall(
+ m_out.operation(operationMakeRope2), m_callFrame, kids[0], kids[1]));
+ break;
+ case 3:
+ slowResult = m_out.anchor(vmCall(
+ m_out.operation(operationMakeRope3), m_callFrame, kids[0], kids[1], kids[2]));
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
+ m_out.jump(continuation);
+
+ m_out.appendTo(continuation, lastNext);
+ setJSValue(m_out.phi(m_out.int64, fastResult, slowResult));
+ }
+
void compileStringCharAt()
{
LValue base = lowCell(m_node->child1());
@@ -2114,7 +2640,7 @@
m_out.branch(
m_out.aboveOrEqual(
- index, m_out.load32(base, m_heaps.JSString_length)),
+ index, m_out.load32NonNegative(base, m_heaps.JSString_length)),
slowPath, fastPath);
LBasicBlock lastNext = m_out.appendTo(fastPath, slowPath);
@@ -2210,7 +2736,8 @@
speculate(
Uncountable, noValue(), 0,
- m_out.aboveOrEqual(index, m_out.load32(base, m_heaps.JSString_length)));
+ m_out.aboveOrEqual(
+ index, m_out.load32NonNegative(base, m_heaps.JSString_length)));
LValue stringImpl = m_out.loadPtr(base, m_heaps.JSString_value);
@@ -2345,6 +2872,16 @@
m_out.appendTo(continuation, lastNext);
}
+ void compileGetCallee()
+ {
+ setJSValue(m_out.loadPtr(addressFor(JSStack::Callee)));
+ }
+
+ void compileGetScope()
+ {
+ setJSValue(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.JSFunction_scope));
+ }
+
void compileGetMyScope()
{
setJSValue(m_out.loadPtr(addressFor(
@@ -2488,35 +3025,37 @@
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;
+ int numArgs = numPassedArgs + dummyThisArgument;
- LValue calleeFrame = m_out.add(
- m_callFrame,
- m_out.constIntPtr(sizeof(Register) * virtualRegisterForLocal(m_graph.frameRegisterCount()).offset()));
+ LValue callee = lowJSValue(m_graph.varArgChild(m_node, 0));
- 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));
+ unsigned stackmapID = m_stackmapIDs++;
- for (int i = 0; i < numPassedArgs; ++i) {
- m_out.store64(
- lowJSValue(m_graph.varArgChild(m_node, 1 + i)),
- addressFor(calleeFrame, virtualRegisterForArgument(i + dummyThisArgument).offset()));
- }
+ Vector<LValue> arguments;
+ arguments.append(m_out.constInt64(stackmapID));
+ arguments.append(m_out.constInt32(sizeOfCall()));
+ arguments.append(constNull(m_out.ref8));
+ arguments.append(m_out.constInt32(1 + JSStack::CallFrameHeaderSize - JSStack::CallerFrameAndPCSize + numArgs));
+ arguments.append(callee); // callee -> %rax
+ arguments.append(getUndef(m_out.int64)); // code block
+ arguments.append(getUndef(m_out.int64)); // scope chain
+ arguments.append(callee); // callee -> stack
+ arguments.append(m_out.constInt64(numArgs)); // argument count and zeros for the tag
+ if (dummyThisArgument)
+ arguments.append(getUndef(m_out.int64));
+ for (int i = 0; i < numPassedArgs; ++i)
+ arguments.append(lowJSValue(m_graph.varArgChild(m_node, 1 + i)));
- setJSValue(vmCall(m_out.operation(function), calleeFrame));
+ callPreflight();
+
+ LValue call = m_out.call(m_out.patchpointInt64Intrinsic(), arguments);
+ setInstructionCallingConvention(call, LLVMWebKitJSCallConv);
+
+ m_ftlState.jsCalls.append(JSCall(stackmapID, m_node));
+
+ setJSValue(call);
}
void compileJump()
@@ -2627,7 +3166,7 @@
m_out.branch(
m_out.notEqual(
- m_out.load32(stringValue, m_heaps.JSString_length),
+ m_out.load32NonNegative(stringValue, m_heaps.JSString_length),
m_out.int32One),
lowBlock(data->fallThrough), lengthIs1);
@@ -2708,6 +3247,22 @@
info.m_isInvalidationPoint = true;
}
+ void compileCheckArgumentsNotCreated()
+ {
+ ASSERT(!isEmptySpeculation(
+ m_state.variables().operand(
+ m_graph.argumentsRegisterFor(m_node->codeOrigin)).m_type));
+
+ VirtualRegister reg = m_graph.machineArgumentsRegisterFor(m_node->codeOrigin);
+ speculate(ArgumentsEscaped, noValue(), 0, m_out.notZero64(m_out.load64(addressFor(reg))));
+ }
+
+ void compileCountExecution()
+ {
+ TypedPointer counter = m_out.absolute(m_node->executionCounter()->address());
+ m_out.store64(m_out.add(m_out.load64(counter), m_out.constInt64(1)), counter);
+ }
+
TypedPointer baseIndex(IndexedAbstractHeap& heap, LValue storage, LValue index, Edge edge)
{
return m_out.baseIndex(
@@ -2924,7 +3479,7 @@
{
if (JSArrayBufferView* view = m_graph.tryGetFoldableView(baseEdge.node(), arrayMode))
return m_out.constInt32(view->length());
- return m_out.load32(base, m_heaps.JSArrayBufferView_length);
+ return m_out.load32NonNegative(base, m_heaps.JSArrayBufferView_length);
}
LValue typedArrayLength(Edge baseEdge, ArrayMode arrayMode)
@@ -2948,7 +3503,7 @@
ManualOperandSpeculation));
case StringUse: {
LValue stringValue = lowString(m_node->child1());
- LValue length = m_out.load32(stringValue, m_heaps.JSString_length);
+ LValue length = m_out.load32NonNegative(stringValue, m_heaps.JSString_length);
return m_out.notEqual(length, m_out.int32Zero);
}
case UntypedUse: {
@@ -3082,7 +3637,7 @@
LBasicBlock continuation)
{
LValue isNotInBounds = m_out.aboveOrEqual(
- index, m_out.load32(storage, m_heaps.Butterfly_publicLength));
+ index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength));
if (!m_node->arrayMode().isInBounds()) {
LBasicBlock notInBoundsCase =
FTL_NEW_BLOCK(m_out, ("PutByVal not in bounds"));
@@ -3094,7 +3649,7 @@
LBasicBlock lastNext = m_out.appendTo(notInBoundsCase, performStore);
LValue isOutOfBounds = m_out.aboveOrEqual(
- index, m_out.load32(storage, m_heaps.Butterfly_vectorLength));
+ index, m_out.load32NonNegative(storage, m_heaps.Butterfly_vectorLength));
if (!m_node->arrayMode().isOutOfBounds())
speculate(OutOfBounds, noValue(), 0, isOutOfBounds);
@@ -3718,6 +4273,7 @@
break;
case KnownInt32Use:
case KnownNumberUse:
+ case KnownStringUse:
ASSERT(!m_interpreter.needsTypeCheck(edge));
break;
case Int32Use:
@@ -3741,6 +4297,12 @@
case StringUse:
speculateString(edge);
break;
+ case StringObjectUse:
+ speculateStringObject(edge);
+ break;
+ case StringOrStringObjectUse:
+ speculateStringOrStringObject(edge);
+ break;
case RealNumberUse:
speculateRealNumber(edge);
break;
@@ -3753,6 +4315,9 @@
case BooleanUse:
speculateBoolean(edge);
break;
+ case NotCellUse:
+ speculateNotCell(edge);
+ break;
default:
dataLog("Unsupported speculation use kind: ", edge.useKind(), "\n");
RELEASE_ASSERT_NOT_REACHED();
@@ -3928,6 +4493,55 @@
speculateString(edge, lowCell(edge));
}
+ void speculateStringObject(Edge edge)
+ {
+ if (!m_interpreter.needsTypeCheck(edge, SpecStringObject))
+ return;
+
+ speculateStringObjectForCell(edge, lowCell(edge));
+ m_interpreter.filter(edge, SpecStringObject);
+ }
+
+ void speculateStringOrStringObject(Edge edge)
+ {
+ if (!m_interpreter.needsTypeCheck(edge, SpecString | SpecStringObject))
+ return;
+
+ LBasicBlock notString = FTL_NEW_BLOCK(m_out, ("Speculate StringOrStringObject not string case"));
+ LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Speculate StringOrStringObject continuation"));
+
+ LValue structure = m_out.loadPtr(lowCell(edge), m_heaps.JSCell_structure);
+ m_out.branch(
+ m_out.equal(structure, m_out.constIntPtr(vm().stringStructure.get())),
+ continuation, notString);
+
+ LBasicBlock lastNext = m_out.appendTo(notString, continuation);
+ speculateStringObjectForStructure(edge, structure);
+ m_out.jump(continuation);
+
+ m_out.appendTo(continuation, lastNext);
+
+ m_interpreter.filter(edge, SpecString | SpecStringObject);
+ }
+
+ void speculateStringObjectForCell(Edge edge, LValue cell)
+ {
+ speculateStringObjectForStructure(edge, m_out.loadPtr(cell, m_heaps.JSCell_structure));
+ }
+
+ void speculateStringObjectForStructure(Edge edge, LValue structure)
+ {
+ Structure* stringObjectStructure =
+ m_graph.globalObjectFor(m_node->codeOrigin)->stringObjectStructure();
+
+ if (m_state.forNode(edge).m_currentKnownStructure.isSubsetOf(StructureSet(stringObjectStructure)))
+ return;
+
+ speculate(
+ NotStringObject, noValue(), 0,
+ m_out.notEqual(structure, weakPointer(stringObjectStructure)));
+ }
+
void speculateNonNullObject(Edge edge, LValue cell)
{
LValue structure = m_out.loadPtr(cell, m_heaps.JSCell_structure);
@@ -3979,6 +4593,15 @@
lowBoolean(edge);
}
+ void speculateNotCell(Edge edge)
+ {
+ if (!m_interpreter.needsTypeCheck(edge))
+ return;
+
+ LValue value = lowJSValue(edge);
+ typeCheck(jsValueValue(value), edge, ~SpecCell, isCell(value));
+ }
+
bool masqueradesAsUndefinedWatchpointIsStillValid()
{
return m_graph.masqueradesAsUndefinedWatchpointIsStillValid(m_node->codeOrigin);
@@ -4106,18 +4729,13 @@
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);
+ m_handleExceptions, 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);
+ m_out.appendTo(continuation);
}
LBasicBlock lowBlock(BasicBlock* block)
@@ -4133,8 +4751,11 @@
void appendOSRExit(
ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition)
{
- if (verboseCompilationEnabled())
+ if (verboseCompilationEnabled()) {
dataLog(" OSR exit #", m_ftlState.jitCode->osrExit.size(), " with availability: ", m_availability, "\n");
+ if (!m_availableRecoveries.isEmpty())
+ dataLog(" Available recoveries: ", listDump(m_availableRecoveries), "\n");
+ }
ASSERT(m_ftlState.jitCode->osrExit.size() == m_ftlState.finalizer->osrExit.size());
@@ -4178,7 +4799,6 @@
OSRExit& exit, ExitArgumentList& arguments, FormattedValue lowValue,
CodeOrigin codeOrigin)
{
- arguments.append(m_callFrame);
if (!!lowValue)
arguments.append(lowValue.value());
@@ -4246,7 +4866,7 @@
{
exit.m_stackmapID = m_stackmapIDs++;
arguments.insert(0, m_out.constInt32(MacroAssembler::maxJumpReplacementSize()));
- arguments.insert(0, m_out.constInt32(exit.m_stackmapID));
+ arguments.insert(0, m_out.constInt64(exit.m_stackmapID));
m_out.call(m_out.stackmapIntrinsic(), arguments);
}
@@ -4260,6 +4880,19 @@
if (tryToSetConstantExitArgument(exit, index, node))
return;
+ for (unsigned i = 0; i < m_availableRecoveries.size(); ++i) {
+ AvailableRecovery recovery = m_availableRecoveries[i];
+ if (recovery.node() != node)
+ continue;
+
+ exit.m_values[index] = ExitValue::recovery(
+ recovery.opcode(), arguments.size(), arguments.size() + 1,
+ recovery.format());
+ arguments.append(recovery.left());
+ arguments.append(recovery.right());
+ return;
+ }
+
LoweredNodeValue value = m_int32Values.get(node);
if (isValid(value)) {
addExitArgument(exit, arguments, index, ValueFormatInt32, value.value());
@@ -4329,6 +4962,29 @@
arguments.append(value);
}
+ bool doesKill(Edge edge)
+ {
+ if (edge.doesNotKill())
+ return false;
+
+ if (edge->hasConstant())
+ return false;
+
+ return true;
+ }
+
+ void addAvailableRecovery(
+ Node* node, RecoveryOpcode opcode, LValue left, LValue right, ValueFormat format)
+ {
+ m_availableRecoveries.append(AvailableRecovery(node, opcode, left, right, format));
+ }
+
+ void addAvailableRecovery(
+ Edge edge, RecoveryOpcode opcode, LValue left, LValue right, ValueFormat format)
+ {
+ addAvailableRecovery(edge.node(), opcode, left, right, format);
+ }
+
void setInt32(Node* node, LValue value)
{
m_int32Values.set(node, LoweredNodeValue(value, m_highBlock));
@@ -4431,35 +5087,37 @@
}
TypedPointer payloadFor(LValue base, int operand)
{
- return addressFor(base, operand, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
+ return addressFor(base, operand, PayloadOffset);
}
TypedPointer tagFor(LValue base, int operand)
{
- return addressFor(base, operand, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
+ return addressFor(base, operand, TagOffset);
}
- TypedPointer addressFor(int operand)
+ TypedPointer addressFor(int operand, ptrdiff_t offset = 0)
{
- return addressFor(m_callFrame, operand);
+ return addressFor(VirtualRegister(operand), offset);
}
- TypedPointer addressFor(VirtualRegister operand)
+ TypedPointer addressFor(VirtualRegister operand, ptrdiff_t offset = 0)
{
- return addressFor(m_callFrame, operand.offset());
+ if (operand.isLocal())
+ return addressFor(m_captured, operand.offset(), offset);
+ return addressFor(m_callFrame, operand.offset(), offset);
}
TypedPointer payloadFor(int operand)
{
- return payloadFor(m_callFrame, operand);
+ return payloadFor(VirtualRegister(operand));
}
TypedPointer payloadFor(VirtualRegister operand)
{
- return payloadFor(m_callFrame, operand.offset());
+ return addressFor(operand, PayloadOffset);
}
TypedPointer tagFor(int operand)
{
- return tagFor(m_callFrame, operand);
+ return tagFor(VirtualRegister(operand));
}
TypedPointer tagFor(VirtualRegister operand)
{
- return tagFor(m_callFrame, operand.offset());
+ return addressFor(operand, TagOffset);
}
VM& vm() { return m_graph.m_vm; }
@@ -4471,9 +5129,11 @@
Output m_out;
LBasicBlock m_prologue;
+ LBasicBlock m_handleExceptions;
HashMap<BasicBlock*, LBasicBlock> m_blocks;
LValue m_callFrame;
+ LValue m_captured;
LValue m_tagTypeNumber;
LValue m_tagMask;
@@ -4489,6 +5149,8 @@
Operands<Availability> m_availability;
+ Vector<AvailableRecovery, 3> m_availableRecoveries;
+
InPlaceAbstractState m_state;
AbstractInterpreter<InPlaceAbstractState> m_interpreter;
BasicBlock* m_highBlock;