/*
- * Copyright (C) 2011, 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2013-2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#include "config.h"
#include "DFGOperations.h"
-#include "Arguments.h"
#include "ButterflyInlines.h"
+#include "ClonedArguments.h"
#include "CodeBlock.h"
#include "CommonSlowPaths.h"
#include "CopiedSpaceInlines.h"
#include "DFGToFTLDeferredCompilationCallback.h"
#include "DFGToFTLForOSREntryDeferredCompilationCallback.h"
#include "DFGWorklist.h"
+#include "DirectArguments.h"
#include "FTLForOSREntryJITCode.h"
#include "FTLOSREntry.h"
#include "HostCallReturnValue.h"
#include "Interpreter.h"
#include "JIT.h"
#include "JITExceptions.h"
-#include "JSActivation.h"
-#include "VM.h"
+#include "JSCInlines.h"
+#include "JSLexicalEnvironment.h"
#include "JSNameScope.h"
-#include "NameInstance.h"
#include "ObjectConstructor.h"
-#include "JSCInlines.h"
#include "Repatch.h"
+#include "ScopedArguments.h"
#include "StringConstructor.h"
+#include "Symbol.h"
+#include "TypeProfilerLog.h"
#include "TypedArrayInlines.h"
+#include "VM.h"
#include <wtf/InlineASM.h>
#if ENABLE(JIT)
{
VM& vm = exec->vm();
NativeCallFrameTracer tracer(&vm, exec);
+ ASSERT(isIndex(index));
if (direct) {
RELEASE_ASSERT(baseValue.isObject());
asObject(baseValue)->putDirectIndex(exec, index, value, 0, strict ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
JSValue value = JSValue::decode(encodedValue);
if (LIKELY(property.isUInt32())) {
+ // Despite its name, JSValue::isUInt32 will return true only for positive boxed int32_t; all those values are valid array indices.
+ ASSERT(isIndex(property.asUInt32()));
putByVal<strict, direct>(exec, baseValue, property.asUInt32(), value);
return;
}
if (property.isDouble()) {
double propertyAsDouble = property.asDouble();
uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
- if (propertyAsDouble == propertyAsUInt32) {
+ if (propertyAsDouble == propertyAsUInt32 && isIndex(propertyAsUInt32)) {
putByVal<strict, direct>(exec, baseValue, propertyAsUInt32, value);
return;
}
}
- if (isName(property)) {
- PutPropertySlot slot(baseValue, strict);
- if (direct) {
- RELEASE_ASSERT(baseValue.isObject());
- asObject(baseValue)->putDirect(*vm, jsCast<NameInstance*>(property.asCell())->privateName(), value, slot);
- } else
- baseValue.put(exec, jsCast<NameInstance*>(property.asCell())->privateName(), value, slot);
+ // Don't put to an object if toString throws an exception.
+ auto propertyName = property.toPropertyKey(exec);
+ if (vm->exception())
return;
- }
- // Don't put to an object if toString throws an exception.
- Identifier ident = property.toString(exec)->toIdentifier(exec);
- if (!vm->exception()) {
- PutPropertySlot slot(baseValue, strict);
- if (direct) {
- RELEASE_ASSERT(baseValue.isObject());
- asObject(baseValue)->putDirect(*vm, jsCast<NameInstance*>(property.asCell())->privateName(), value, slot);
- } else
- baseValue.put(exec, ident, value, slot);
- }
+ PutPropertySlot slot(baseValue, strict);
+ if (direct) {
+ RELEASE_ASSERT(baseValue.isObject());
+ if (Optional<uint32_t> index = parseIndex(propertyName))
+ asObject(baseValue)->putDirectIndex(exec, index.value(), value, 0, strict ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
+ else
+ asObject(baseValue)->putDirect(*vm, propertyName, value, slot);
+ } else
+ baseValue.put(exec, propertyName, value, slot);
}
template<typename ViewClass>
VM& vm = exec->vm();
NativeCallFrameTracer tracer(&vm, exec);
if (size < 0) {
- vm.throwException(exec, createRangeError(exec, "Requested length is negative"));
+ vm.throwException(exec, createRangeError(exec, ASCIILiteral("Requested length is negative")));
return 0;
}
return bitwise_cast<char*>(ViewClass::create(exec, structure, size));
RefPtr<ArrayBuffer> buffer = jsBuffer->impl();
if (buffer->byteLength() % ViewClass::elementSize) {
- vm.throwException(exec, createRangeError(exec, "ArrayBuffer length minus the byteOffset is not a multiple of the element size"));
+ vm.throwException(exec, createRangeError(exec, ASCIILiteral("ArrayBuffer length minus the byteOffset is not a multiple of the element size")));
return 0;
}
return bitwise_cast<char*>(
if (value.isInt32())
length = value.asInt32();
else if (!value.isNumber()) {
- vm.throwException(exec, createTypeError(exec, "Invalid array length argument"));
+ vm.throwException(exec, createTypeError(exec, ASCIILiteral("Invalid array length argument")));
return 0;
} else {
length = static_cast<int>(value.asNumber());
if (length != value.asNumber()) {
- vm.throwException(exec, createTypeError(exec, "Invalid array length argument (fractional lengths not allowed)"));
+ vm.throwException(exec, createTypeError(exec, ASCIILiteral("Invalid array length argument (fractional lengths not allowed)")));
return 0;
}
}
if (length < 0) {
- vm.throwException(exec, createRangeError(exec, "Requested length is negative"));
+ vm.throwException(exec, createRangeError(exec, ASCIILiteral("Requested length is negative")));
return 0;
}
ASSERT(jsCast<JSFunction*>(constructor)->methodTable(vm)->getConstructData(jsCast<JSFunction*>(constructor), constructData) == ConstructTypeJS);
#endif
- return constructEmptyObject(exec, jsCast<JSFunction*>(constructor)->allocationProfile(exec, inlineCapacity)->structure());
+ return constructEmptyObject(exec, jsCast<JSFunction*>(constructor)->rareData(exec, inlineCapacity)->allocationProfile()->structure());
}
EncodedJSValue JIT_OPERATION operationValueAdd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
} else if (property.isDouble()) {
double propertyAsDouble = property.asDouble();
uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
- if (propertyAsUInt32 == propertyAsDouble)
+ if (propertyAsUInt32 == propertyAsDouble && isIndex(propertyAsUInt32))
return getByVal(exec, base, propertyAsUInt32);
} else if (property.isString()) {
Structure& structure = *base->structure(vm);
if (JSCell::canUseFastGetOwnProperty(structure)) {
- if (JSValue result = base->fastGetOwnProperty(vm, structure, asString(property)->value(exec)))
- return JSValue::encode(result);
+ if (RefPtr<AtomicStringImpl> existingAtomicString = asString(property)->toExistingAtomicString(exec)) {
+ if (JSValue result = base->fastGetOwnProperty(vm, structure, existingAtomicString.get()))
+ return JSValue::encode(result);
+ }
}
}
}
- if (isName(property))
- return JSValue::encode(baseValue.get(exec, jsCast<NameInstance*>(property.asCell())->privateName()));
-
- Identifier ident = property.toString(exec)->toIdentifier(exec);
- return JSValue::encode(baseValue.get(exec, ident));
+ baseValue.requireObjectCoercible(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ auto propertyName = property.toPropertyKey(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ return JSValue::encode(baseValue.get(exec, propertyName));
}
EncodedJSValue JIT_OPERATION operationGetByValCell(ExecState* exec, JSCell* base, EncodedJSValue encodedProperty)
} else if (property.isString()) {
Structure& structure = *base->structure(vm);
if (JSCell::canUseFastGetOwnProperty(structure)) {
- if (JSValue result = base->fastGetOwnProperty(vm, structure, asString(property)->value(exec)))
- return JSValue::encode(result);
+ if (RefPtr<AtomicStringImpl> existingAtomicString = asString(property)->toExistingAtomicString(exec)) {
+ if (JSValue result = base->fastGetOwnProperty(vm, structure, existingAtomicString.get()))
+ return JSValue::encode(result);
+ }
}
}
- if (isName(property))
- return JSValue::encode(JSValue(base).get(exec, jsCast<NameInstance*>(property.asCell())->privateName()));
-
- Identifier ident = property.toString(exec)->toIdentifier(exec);
- return JSValue::encode(JSValue(base).get(exec, ident));
+ auto propertyName = property.toPropertyKey(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ return JSValue::encode(JSValue(base).get(exec, propertyName));
}
ALWAYS_INLINE EncodedJSValue getByValCellInt(ExecState* exec, JSCell* base, int32_t index)
return newTypedArrayWithOneArgument<JSFloat64Array>(exec, structure, encodedValue);
}
-JSCell* JIT_OPERATION operationCreateInlinedArguments(
- ExecState* exec, InlineCallFrame* inlineCallFrame)
+JSCell* JIT_OPERATION operationCreateActivationDirect(ExecState* exec, Structure* structure, JSScope* scope, SymbolTable* table)
{
VM& vm = exec->vm();
NativeCallFrameTracer tracer(&vm, exec);
- // NB: This needs to be exceedingly careful with top call frame tracking, since it
- // may be called from OSR exit, while the state of the call stack is bizarre.
- Arguments* result = Arguments::create(vm, exec, inlineCallFrame);
- ASSERT(!vm.exception());
+ return JSLexicalEnvironment::create(vm, structure, scope, table);
+}
+
+JSCell* JIT_OPERATION operationCreateDirectArguments(ExecState* exec, Structure* structure, int32_t length, int32_t minCapacity)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer target(&vm, exec);
+ DirectArguments* result = DirectArguments::create(
+ vm, structure, length, std::max(length, minCapacity));
+ // The caller will store to this object without barriers. Most likely, at this point, this is
+ // still a young object and so no barriers are needed. But it's good to be careful anyway,
+ // since the GC should be allowed to do crazy (like pretenuring, for example).
+ vm.heap.writeBarrier(result);
return result;
}
-JSCell* JIT_OPERATION operationCreateInlinedArgumentsDuringOSRExit(ExecState* exec, InlineCallFrame* inlineCallFrame)
+JSCell* JIT_OPERATION operationCreateScopedArguments(ExecState* exec, Structure* structure, Register* argumentStart, int32_t length, JSFunction* callee, JSLexicalEnvironment* scope)
{
- DeferGCForAWhile(exec->vm().heap);
- return operationCreateInlinedArguments(exec, inlineCallFrame);
+ VM& vm = exec->vm();
+ NativeCallFrameTracer target(&vm, exec);
+
+ // We could pass the ScopedArgumentsTable* as an argument. We currently don't because I
+ // didn't feel like changing the max number of arguments for a slow path call from 6 to 7.
+ ScopedArgumentsTable* table = scope->symbolTable()->arguments();
+
+ return ScopedArguments::createByCopyingFrom(
+ vm, structure, argumentStart, length, callee, table, scope);
}
-void JIT_OPERATION operationTearOffInlinedArguments(
- ExecState* exec, JSCell* argumentsCell, JSCell* activationCell, InlineCallFrame* inlineCallFrame)
+JSCell* JIT_OPERATION operationCreateClonedArguments(ExecState* exec, Structure* structure, Register* argumentStart, int32_t length, JSFunction* callee)
{
- ASSERT_UNUSED(activationCell, !activationCell); // Currently, we don't inline functions with activations.
- jsCast<Arguments*>(argumentsCell)->tearOff(exec, inlineCallFrame);
+ VM& vm = exec->vm();
+ NativeCallFrameTracer target(&vm, exec);
+ return ClonedArguments::createByCopyingFrom(
+ exec, structure, argumentStart, length, callee);
}
-EncodedJSValue JIT_OPERATION operationGetArgumentByVal(ExecState* exec, int32_t argumentsRegister, int32_t index)
+JSCell* JIT_OPERATION operationCreateDirectArgumentsDuringExit(ExecState* exec, InlineCallFrame* inlineCallFrame, JSFunction* callee, int32_t argumentCount)
{
VM& vm = exec->vm();
- NativeCallFrameTracer tracer(&vm, exec);
+ NativeCallFrameTracer target(&vm, exec);
+
+ DeferGCForAWhile deferGC(vm.heap);
+
+ CodeBlock* codeBlock;
+ if (inlineCallFrame)
+ codeBlock = baselineCodeBlockForInlineCallFrame(inlineCallFrame);
+ else
+ codeBlock = exec->codeBlock();
+
+ unsigned length = argumentCount - 1;
+ unsigned capacity = std::max(length, static_cast<unsigned>(codeBlock->numParameters() - 1));
+ DirectArguments* result = DirectArguments::create(
+ vm, codeBlock->globalObject()->directArgumentsStructure(), length, capacity);
+
+ result->callee().set(vm, result, callee);
+
+ Register* arguments =
+ exec->registers() + (inlineCallFrame ? inlineCallFrame->stackOffset : 0) +
+ CallFrame::argumentOffset(0);
+ for (unsigned i = length; i--;)
+ result->setIndexQuickly(vm, i, arguments[i].jsValue());
+
+ return result;
+}
- JSValue argumentsValue = exec->uncheckedR(argumentsRegister).jsValue();
+JSCell* JIT_OPERATION operationCreateClonedArgumentsDuringExit(ExecState* exec, InlineCallFrame* inlineCallFrame, JSFunction* callee, int32_t argumentCount)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer target(&vm, exec);
+
+ DeferGCForAWhile deferGC(vm.heap);
- // If there are no arguments, and we're accessing out of bounds, then we have to create the
- // arguments in case someone has installed a getter on a numeric property.
- if (!argumentsValue)
- exec->uncheckedR(argumentsRegister) = argumentsValue = Arguments::create(exec->vm(), exec);
+ CodeBlock* codeBlock;
+ if (inlineCallFrame)
+ codeBlock = baselineCodeBlockForInlineCallFrame(inlineCallFrame);
+ else
+ codeBlock = exec->codeBlock();
- return JSValue::encode(argumentsValue.get(exec, index));
+ unsigned length = argumentCount - 1;
+ ClonedArguments* result = ClonedArguments::createEmpty(
+ vm, codeBlock->globalObject()->outOfBandArgumentsStructure(), callee);
+
+ Register* arguments =
+ exec->registers() + (inlineCallFrame ? inlineCallFrame->stackOffset : 0) +
+ CallFrame::argumentOffset(0);
+ for (unsigned i = length; i--;)
+ result->putDirectIndex(exec, i, arguments[i].jsValue());
+
+ result->putDirect(vm, vm.propertyNames->length, jsNumber(length));
+
+ return result;
}
-EncodedJSValue JIT_OPERATION operationGetInlinedArgumentByVal(
- ExecState* exec, int32_t argumentsRegister, InlineCallFrame* inlineCallFrame, int32_t index)
+size_t JIT_OPERATION operationObjectIsObject(ExecState* exec, JSGlobalObject* globalObject, JSCell* object)
{
VM& vm = exec->vm();
NativeCallFrameTracer tracer(&vm, exec);
- JSValue argumentsValue = exec->uncheckedR(argumentsRegister).jsValue();
+ ASSERT(jsDynamicCast<JSObject*>(object));
- // If there are no arguments, and we're accessing out of bounds, then we have to create the
- // arguments in case someone has installed a getter on a numeric property.
- if (!argumentsValue) {
- exec->uncheckedR(argumentsRegister) = argumentsValue =
- Arguments::create(exec->vm(), exec, inlineCallFrame);
+ if (object->structure(vm)->masqueradesAsUndefined(globalObject))
+ return false;
+ if (object->type() == JSFunctionType)
+ return false;
+ if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) {
+ CallData callData;
+ if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone)
+ return false;
}
- return JSValue::encode(argumentsValue.get(exec, index));
+ return true;
}
-JSCell* JIT_OPERATION operationNewFunctionNoCheck(ExecState* exec, JSCell* functionExecutable)
+size_t JIT_OPERATION operationObjectIsFunction(ExecState* exec, JSGlobalObject* globalObject, JSCell* object)
{
- ASSERT(functionExecutable->inherits(FunctionExecutable::info()));
VM& vm = exec->vm();
NativeCallFrameTracer tracer(&vm, exec);
- return JSFunction::create(vm, static_cast<FunctionExecutable*>(functionExecutable), exec->scope());
-}
-size_t JIT_OPERATION operationIsObject(ExecState* exec, EncodedJSValue value)
-{
- return jsIsObjectType(exec, JSValue::decode(value));
+ ASSERT(jsDynamicCast<JSObject*>(object));
+
+ if (object->structure(vm)->masqueradesAsUndefined(globalObject))
+ return false;
+ if (object->type() == JSFunctionType)
+ return true;
+ if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) {
+ CallData callData;
+ if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone)
+ return true;
+ }
+
+ return false;
}
-size_t JIT_OPERATION operationIsFunction(EncodedJSValue value)
+JSCell* JIT_OPERATION operationTypeOfObject(ExecState* exec, JSGlobalObject* globalObject, JSCell* object)
{
- return jsIsFunctionType(JSValue::decode(value));
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+
+ ASSERT(jsDynamicCast<JSObject*>(object));
+
+ if (object->structure(vm)->masqueradesAsUndefined(globalObject))
+ return vm.smallStrings.undefinedString();
+ if (object->type() == JSFunctionType)
+ return vm.smallStrings.functionString();
+ if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) {
+ CallData callData;
+ if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone)
+ return vm.smallStrings.functionString();
+ }
+
+ return vm.smallStrings.objectString();
}
-JSCell* JIT_OPERATION operationTypeOf(ExecState* exec, JSCell* value)
+int32_t JIT_OPERATION operationTypeOfObjectAsTypeofType(ExecState* exec, JSGlobalObject* globalObject, JSCell* object)
{
VM& vm = exec->vm();
NativeCallFrameTracer tracer(&vm, exec);
- return jsTypeStringForValue(exec, JSValue(value)).asCell();
+
+ ASSERT(jsDynamicCast<JSObject*>(object));
+
+ if (object->structure(vm)->masqueradesAsUndefined(globalObject))
+ return static_cast<int32_t>(TypeofType::Undefined);
+ if (object->type() == JSFunctionType)
+ return static_cast<int32_t>(TypeofType::Function);
+ if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) {
+ CallData callData;
+ if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone)
+ return static_cast<int32_t>(TypeofType::Function);
+ }
+
+ return static_cast<int32_t>(TypeofType::Object);
}
char* JIT_OPERATION operationAllocatePropertyStorageWithInitialCapacity(ExecState* exec)
return reinterpret_cast<char*>(asObject(cell)->ensureContiguous(vm).data());
}
-char* JIT_OPERATION operationRageEnsureContiguous(ExecState* exec, JSCell* cell)
-{
- VM& vm = exec->vm();
- NativeCallFrameTracer tracer(&vm, exec);
-
- if (!cell->isObject())
- return 0;
-
- return reinterpret_cast<char*>(asObject(cell)->rageEnsureContiguous(vm).data());
-}
-
char* JIT_OPERATION operationEnsureArrayStorage(ExecState* exec, JSCell* cell)
{
VM& vm = exec->vm();
return JSValue::decode(value).toString(exec);
}
+JSCell* JIT_OPERATION operationCallStringConstructorOnCell(ExecState* exec, JSCell* cell)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+
+ return stringConstructor(exec, cell);
+}
+
+JSCell* JIT_OPERATION operationCallStringConstructor(ExecState* exec, EncodedJSValue value)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+
+ return stringConstructor(exec, JSValue::decode(value));
+}
+
JSCell* JIT_OPERATION operationMakeRope2(ExecState* exec, JSString* left, JSString* right)
{
VM& vm = exec->vm();
return static_cast<char*>(exec->codeBlock()->stringSwitchJumpTable(tableIndex).ctiForValue(string->value(exec).impl()).executableAddress());
}
-void JIT_OPERATION operationNotifyWrite(ExecState* exec, VariableWatchpointSet* set, EncodedJSValue encodedValue)
+int32_t JIT_OPERATION operationSwitchStringAndGetBranchOffset(ExecState* exec, size_t tableIndex, JSString* string)
{
VM& vm = exec->vm();
NativeCallFrameTracer tracer(&vm, exec);
- JSValue value = JSValue::decode(encodedValue);
- set->notifyWrite(vm, value);
+ return exec->codeBlock()->stringSwitchJumpTable(tableIndex).offsetForValue(string->value(exec).impl(), std::numeric_limits<int32_t>::min());
+}
+
+void JIT_OPERATION operationNotifyWrite(ExecState* exec, WatchpointSet* set)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+
+ set->touch("Executed NotifyWrite");
+}
+
+void JIT_OPERATION operationThrowStackOverflowForVarargs(ExecState* exec)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+ throwStackOverflowError(exec);
+}
+
+int32_t JIT_OPERATION operationSizeOfVarargs(ExecState* exec, EncodedJSValue encodedArguments, int32_t firstVarArgOffset)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+ JSValue arguments = JSValue::decode(encodedArguments);
+
+ return sizeOfVarargs(exec, arguments, firstVarArgOffset);
+}
+
+void JIT_OPERATION operationLoadVarargs(ExecState* exec, int32_t firstElementDest, EncodedJSValue encodedArguments, int32_t offset, int32_t length, int32_t mandatoryMinimum)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+ JSValue arguments = JSValue::decode(encodedArguments);
+
+ loadVarargs(exec, VirtualRegister(firstElementDest), arguments, offset, length);
+
+ for (int32_t i = length; i < mandatoryMinimum; ++i)
+ exec->r(firstElementDest + i) = jsUndefined();
}
double JIT_OPERATION operationFModOnInts(int32_t a, int32_t b)
return tryConvertToInt52(value);
}
+void JIT_OPERATION operationProcessTypeProfilerLogDFG(ExecState* exec)
+{
+ exec->vm().typeProfilerLog()->processLogEntries(ASCIILiteral("Log Full, called from inside DFG."));
+}
+
size_t JIT_OPERATION dfgConvertJSValueToInt32(ExecState* exec, EncodedJSValue value)
{
VM* vm = &exec->vm();
dataLog("\n");
}
-extern "C" void JIT_OPERATION triggerReoptimizationNow(CodeBlock* codeBlock)
+extern "C" void JIT_OPERATION triggerReoptimizationNow(CodeBlock* codeBlock, OSRExitBase* exit)
{
// It's sort of preferable that we don't GC while in here. Anyways, doing so wouldn't
// really be profitable.
ASSERT(codeBlock->hasOptimizedReplacement());
CodeBlock* optimizedCodeBlock = codeBlock->replacement();
ASSERT(JITCode::isOptimizingJIT(optimizedCodeBlock->jitType()));
+
+ bool didTryToEnterIntoInlinedLoops = false;
+ for (InlineCallFrame* inlineCallFrame = exit->m_codeOrigin.inlineCallFrame; inlineCallFrame; inlineCallFrame = inlineCallFrame->caller.inlineCallFrame) {
+ if (inlineCallFrame->executable->didTryToEnterInLoop()) {
+ didTryToEnterIntoInlinedLoops = true;
+ break;
+ }
+ }
// In order to trigger reoptimization, one of two things must have happened:
// 1) We exited more than some number of times.
// 2) We exited and got stuck in a loop, and now we're exiting again.
bool didExitABunch = optimizedCodeBlock->shouldReoptimizeNow();
bool didGetStuckInLoop =
- codeBlock->checkIfOptimizationThresholdReached()
+ (codeBlock->checkIfOptimizationThresholdReached() || didTryToEnterIntoInlinedLoops)
&& optimizedCodeBlock->shouldReoptimizeFromLoopNow();
if (!didExitABunch && !didGetStuckInLoop) {
Operands<JSValue>(), ToFTLDeferredCompilationCallback::create(codeBlock));
}
-void JIT_OPERATION triggerTierUpNow(ExecState* exec)
+static void triggerTierUpNowCommon(ExecState* exec, bool inLoop)
{
VM* vm = &exec->vm();
NativeCallFrameTracer tracer(vm, exec);
DeferGC deferGC(vm->heap);
CodeBlock* codeBlock = exec->codeBlock();
+ if (codeBlock->jitType() != JITCode::DFGJIT) {
+ dataLog("Unexpected code block in DFG->FTL tier-up: ", *codeBlock, "\n");
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+
JITCode* jitCode = codeBlock->jitCode()->dfg();
if (Options::verboseOSR()) {
*codeBlock, ": Entered triggerTierUpNow with executeCounter = ",
jitCode->tierUpCounter, "\n");
}
-
+ if (inLoop)
+ jitCode->nestedTriggerIsSet = 1;
+
triggerFTLReplacementCompile(vm, codeBlock, jitCode);
}
+void JIT_OPERATION triggerTierUpNow(ExecState* exec)
+{
+ triggerTierUpNowCommon(exec, false);
+}
+
+void JIT_OPERATION triggerTierUpNowInLoop(ExecState* exec)
+{
+ triggerTierUpNowCommon(exec, true);
+}
+
char* JIT_OPERATION triggerOSREntryNow(
ExecState* exec, int32_t bytecodeIndex, int32_t streamIndex)
{
DeferGC deferGC(vm->heap);
CodeBlock* codeBlock = exec->codeBlock();
+ if (codeBlock->jitType() != JITCode::DFGJIT) {
+ dataLog("Unexpected code block in DFG->FTL tier-up: ", *codeBlock, "\n");
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+
JITCode* jitCode = codeBlock->jitCode()->dfg();
+ jitCode->nestedTriggerIsSet = 0;
if (Options::verboseOSR()) {
dataLog(
- *codeBlock, ": Entered triggerTierUpNow with executeCounter = ",
+ *codeBlock, ": Entered triggerOSREntryNow with executeCounter = ",
jitCode->tierUpCounter, "\n");
}
// OSR entry failed. Oh no! This implies that we need to retry. We retry
// without exponential backoff and we only do this for the entry code block.
- jitCode->osrEntryBlock.clear();
+ jitCode->osrEntryBlock = nullptr;
jitCode->osrEntryRetry = 0;
return 0;
}