]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - dfg/DFGOperations.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / dfg / DFGOperations.cpp
index 15cb4f5c45caa1d282da2c7e874bfcf0cd62d910..6f9512ba534c490d4bf998af5d0824412dbb914e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -26,8 +26,8 @@
 #include "config.h"
 #include "DFGOperations.h"
 
-#include "Arguments.h"
 #include "ButterflyInlines.h"
+#include "ClonedArguments.h"
 #include "CodeBlock.h"
 #include "CommonSlowPaths.h"
 #include "CopiedSpaceInlines.h"
@@ -38,6 +38,7 @@
 #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)
@@ -66,6 +69,7 @@ static inline void putByVal(ExecState* exec, JSValue baseValue, uint32_t index,
 {
     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);
@@ -96,6 +100,8 @@ ALWAYS_INLINE static void JIT_OPERATION operationPutByValInternal(ExecState* exe
     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;
     }
@@ -103,32 +109,26 @@ ALWAYS_INLINE static void JIT_OPERATION operationPutByValInternal(ExecState* exe
     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>
@@ -137,7 +137,7 @@ char* newTypedArrayWithSize(ExecState* exec, Structure* structure, int32_t size)
     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));
@@ -156,7 +156,7 @@ char* newTypedArrayWithOneArgument(
         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*>(
@@ -183,18 +183,18 @@ char* newTypedArrayWithOneArgument(
     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;
     }
     
@@ -229,7 +229,7 @@ JSCell* JIT_OPERATION operationCreateThis(ExecState* exec, JSObject* constructor
     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)
@@ -292,22 +292,26 @@ EncodedJSValue JIT_OPERATION operationGetByVal(ExecState* exec, EncodedJSValue e
         } 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)
@@ -327,16 +331,17 @@ EncodedJSValue JIT_OPERATION operationGetByValCell(ExecState* exec, JSCell* base
     } 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)
@@ -757,87 +762,182 @@ char* JIT_OPERATION operationNewFloat64ArrayWithOneArgument(
     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)
@@ -914,17 +1014,6 @@ char* JIT_OPERATION operationEnsureContiguous(ExecState* exec, JSCell* cell)
     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();
@@ -976,6 +1065,22 @@ JSCell* JIT_OPERATION operationToString(ExecState* exec, EncodedJSValue value)
     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();
@@ -1024,13 +1129,48 @@ char* JIT_OPERATION operationSwitchString(ExecState* exec, size_t tableIndex, JS
     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)
@@ -1058,6 +1198,11 @@ int64_t JIT_OPERATION operationConvertDoubleToInt52(double value)
     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();
@@ -1105,7 +1250,7 @@ void JIT_OPERATION debugOperationPrintSpeculationFailure(ExecState* exec, void*
     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.
@@ -1129,13 +1274,21 @@ extern "C" void JIT_OPERATION triggerReoptimizationNow(CodeBlock* codeBlock)
     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) {
@@ -1198,13 +1351,18 @@ static void triggerFTLReplacementCompile(VM* vm, CodeBlock* codeBlock, JITCode*
         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()) {
@@ -1212,10 +1370,22 @@ void JIT_OPERATION triggerTierUpNow(ExecState* exec)
             *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)
 {
@@ -1224,11 +1394,17 @@ char* JIT_OPERATION triggerOSREntryNow(
     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");
     }
     
@@ -1271,7 +1447,7 @@ char* JIT_OPERATION triggerOSREntryNow(
         
         // 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;
     }