diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2015-05-20 09:56:07 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2015-05-20 09:56:07 +0000 |
commit | 41386e9cb918eed93b3f13648cbef387e371e451 (patch) | |
tree | a97f9d7bd1d9d091833286085f72da9d83fd0606 /Source/JavaScriptCore/jit/JITOperations.cpp | |
parent | e15dd966d523731101f70ccf768bba12435a0208 (diff) | |
download | WebKitGtk-tarball-41386e9cb918eed93b3f13648cbef387e371e451.tar.gz |
webkitgtk-2.4.9webkitgtk-2.4.9
Diffstat (limited to 'Source/JavaScriptCore/jit/JITOperations.cpp')
-rw-r--r-- | Source/JavaScriptCore/jit/JITOperations.cpp | 1174 |
1 files changed, 476 insertions, 698 deletions
diff --git a/Source/JavaScriptCore/jit/JITOperations.cpp b/Source/JavaScriptCore/jit/JITOperations.cpp index b59a028e1..578d15dac 100644 --- a/Source/JavaScriptCore/jit/JITOperations.cpp +++ b/Source/JavaScriptCore/jit/JITOperations.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2015 Apple Inc. All rights reserved. + * Copyright (C) 2013 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,41 +24,32 @@ */ #include "config.h" -#include "JITOperations.h" - #if ENABLE(JIT) +#include "JITOperations.h" +#include "Arguments.h" #include "ArrayConstructor.h" +#include "CallFrameInlines.h" +#include "CommonSlowPaths.h" #include "DFGCompilationMode.h" #include "DFGDriver.h" #include "DFGOSREntry.h" -#include "DFGThunks.h" #include "DFGWorklist.h" -#include "Debugger.h" -#include "DirectArguments.h" #include "Error.h" -#include "ErrorHandlingScope.h" -#include "ExceptionFuzz.h" #include "GetterSetter.h" #include "HostCallReturnValue.h" #include "JIT.h" +#include "JITOperationWrappers.h" #include "JITToDFGDeferredCompilationCallback.h" -#include "JSCInlines.h" #include "JSGlobalObjectFunctions.h" -#include "JSLexicalEnvironment.h" -#include "JSPropertyNameEnumerator.h" +#include "JSNameScope.h" +#include "JSPropertyNameIterator.h" #include "JSStackInlines.h" #include "JSWithScope.h" -#include "LegacyProfiler.h" #include "ObjectConstructor.h" -#include "PropertyName.h" +#include "Operations.h" #include "Repatch.h" #include "RepatchBuffer.h" -#include "ScopedArguments.h" -#include "TestRunnerUtils.h" -#include "TypeProfilerLog.h" -#include "VMInlines.h" -#include <wtf/InlineASM.h> namespace JSC { @@ -80,34 +71,33 @@ void * _ReturnAddress(void); #endif -void JIT_OPERATION operationThrowStackOverflowError(ExecState* exec, CodeBlock* codeBlock) +void JIT_OPERATION operationStackCheck(ExecState* exec, CodeBlock* codeBlock) { // We pass in our own code block, because the callframe hasn't been populated. VM* vm = codeBlock->vm(); - - VMEntryFrame* vmEntryFrame = vm->topVMEntryFrame; - CallFrame* callerFrame = exec->callerFrame(vmEntryFrame); + CallFrame* callerFrame = exec->callerFrameSkippingVMEntrySentinel(); if (!callerFrame) callerFrame = exec; - NativeCallFrameTracerWithRestore tracer(vm, vmEntryFrame, callerFrame); - ErrorHandlingScope errorScope(*vm); - vm->throwException(callerFrame, createStackOverflowError(callerFrame)); + NativeCallFrameTracer tracer(vm, callerFrame); + + JSStack& stack = vm->interpreter->stack(); + + if (UNLIKELY(!stack.grow(&exec->registers()[virtualRegisterForLocal(codeBlock->frameRegisterCount()).offset()]))) + vm->throwException(callerFrame, createStackOverflowError(callerFrame)); } int32_t JIT_OPERATION operationCallArityCheck(ExecState* exec) { VM* vm = &exec->vm(); - VMEntryFrame* vmEntryFrame = vm->topVMEntryFrame; - CallFrame* callerFrame = exec->callerFrame(vmEntryFrame); + CallFrame* callerFrame = exec->callerFrameSkippingVMEntrySentinel(); + NativeCallFrameTracer tracer(vm, callerFrame); JSStack& stack = vm->interpreter->stack(); int32_t missingArgCount = CommonSlowPaths::arityCheckFor(exec, &stack, CodeForCall); - if (missingArgCount < 0) { - NativeCallFrameTracerWithRestore tracer(vm, vmEntryFrame, callerFrame); - throwStackOverflowError(callerFrame); - } + if (missingArgCount < 0) + vm->throwException(callerFrame, createStackOverflowError(callerFrame)); return missingArgCount; } @@ -115,94 +105,81 @@ int32_t JIT_OPERATION operationCallArityCheck(ExecState* exec) int32_t JIT_OPERATION operationConstructArityCheck(ExecState* exec) { VM* vm = &exec->vm(); - VMEntryFrame* vmEntryFrame = vm->topVMEntryFrame; - CallFrame* callerFrame = exec->callerFrame(vmEntryFrame); + CallFrame* callerFrame = exec->callerFrameSkippingVMEntrySentinel(); + NativeCallFrameTracer tracer(vm, callerFrame); JSStack& stack = vm->interpreter->stack(); int32_t missingArgCount = CommonSlowPaths::arityCheckFor(exec, &stack, CodeForConstruct); - if (missingArgCount < 0) { - NativeCallFrameTracerWithRestore tracer(vm, vmEntryFrame, callerFrame); - throwStackOverflowError(callerFrame); - } + if (missingArgCount < 0) + vm->throwException(callerFrame, createStackOverflowError(callerFrame)); return missingArgCount; } -EncodedJSValue JIT_OPERATION operationGetById(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid) +EncodedJSValue JIT_OPERATION operationGetById(ExecState* exec, StructureStubInfo*, EncodedJSValue base, StringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - stubInfo->tookSlowPath = true; - JSValue baseValue = JSValue::decode(base); PropertySlot slot(baseValue); - Identifier ident = Identifier::fromUid(vm, uid); + Identifier ident(vm, uid); return JSValue::encode(baseValue.get(exec, ident, slot)); } -EncodedJSValue JIT_OPERATION operationGetByIdGeneric(ExecState* exec, EncodedJSValue base, UniquedStringImpl* uid) -{ - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); - - JSValue baseValue = JSValue::decode(base); - PropertySlot slot(baseValue); - Identifier ident = Identifier::fromUid(vm, uid); - return JSValue::encode(baseValue.get(exec, ident, slot)); -} - -EncodedJSValue JIT_OPERATION operationGetByIdBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid) +EncodedJSValue JIT_OPERATION operationGetByIdBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, StringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - Identifier ident = Identifier::fromUid(vm, uid); + Identifier ident(vm, uid); AccessType accessType = static_cast<AccessType>(stubInfo->accessType); JSValue baseValue = JSValue::decode(base); PropertySlot slot(baseValue); - bool hasResult = baseValue.getPropertySlot(exec, ident, slot); - + JSValue result = baseValue.get(exec, ident, slot); + if (accessType == static_cast<AccessType>(stubInfo->accessType)) buildGetByIDList(exec, baseValue, ident, slot, *stubInfo); - return JSValue::encode(hasResult? slot.getValue(exec, ident) : jsUndefined()); + return JSValue::encode(result); } -EncodedJSValue JIT_OPERATION operationGetByIdOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid) +EncodedJSValue JIT_OPERATION operationGetByIdOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, StringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - Identifier ident = Identifier::fromUid(vm, uid); + Identifier ident = uid->isEmptyUnique() ? Identifier::from(PrivateName(uid)) : Identifier(vm, uid); + AccessType accessType = static_cast<AccessType>(stubInfo->accessType); JSValue baseValue = JSValue::decode(base); PropertySlot slot(baseValue); + JSValue result = baseValue.get(exec, ident, slot); - bool hasResult = baseValue.getPropertySlot(exec, ident, slot); - if (stubInfo->seen) - repatchGetByID(exec, baseValue, ident, slot, *stubInfo); - else - stubInfo->seen = true; - - return JSValue::encode(hasResult? slot.getValue(exec, ident) : jsUndefined()); + if (accessType == static_cast<AccessType>(stubInfo->accessType)) { + if (stubInfo->seen) + repatchGetByID(exec, baseValue, ident, slot, *stubInfo); + else + stubInfo->seen = true; + } + return JSValue::encode(result); } -EncodedJSValue JIT_OPERATION operationInOptimize(ExecState* exec, StructureStubInfo* stubInfo, JSCell* base, UniquedStringImpl* key) +EncodedJSValue JIT_OPERATION operationInOptimize(ExecState* exec, StructureStubInfo* stubInfo, JSCell* base, StringImpl* key) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); if (!base->isObject()) { - vm->throwException(exec, createInvalidInParameterError(exec, base)); + vm->throwException(exec, createInvalidParameterError(exec, "in", base)); return JSValue::encode(jsUndefined()); } AccessType accessType = static_cast<AccessType>(stubInfo->accessType); - Identifier ident = Identifier::fromUid(vm, key); + Identifier ident(vm, key); PropertySlot slot(base); bool result = asObject(base)->getPropertySlot(exec, ident, slot); @@ -216,19 +193,17 @@ EncodedJSValue JIT_OPERATION operationInOptimize(ExecState* exec, StructureStubI return JSValue::encode(jsBoolean(result)); } -EncodedJSValue JIT_OPERATION operationIn(ExecState* exec, StructureStubInfo* stubInfo, JSCell* base, UniquedStringImpl* key) +EncodedJSValue JIT_OPERATION operationIn(ExecState* exec, StructureStubInfo*, JSCell* base, StringImpl* key) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - - stubInfo->tookSlowPath = true; if (!base->isObject()) { - vm->throwException(exec, createInvalidInParameterError(exec, base)); + vm->throwException(exec, createInvalidParameterError(exec, "in", base)); return JSValue::encode(jsUndefined()); } - Identifier ident = Identifier::fromUid(vm, key); + Identifier ident(vm, key); return JSValue::encode(jsBoolean(asObject(base)->hasProperty(exec, ident))); } @@ -240,232 +215,234 @@ EncodedJSValue JIT_OPERATION operationGenericIn(ExecState* exec, JSCell* base, E return JSValue::encode(jsBoolean(CommonSlowPaths::opIn(exec, JSValue::decode(key), base))); } -void JIT_OPERATION operationPutByIdStrict(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid) +EncodedJSValue JIT_OPERATION operationCallCustomGetter(ExecState* exec, JSCell* base, PropertySlot::GetValueFunc function, StringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - stubInfo->tookSlowPath = true; + Identifier ident(vm, uid); + + return function(exec, JSValue::encode(base), JSValue::encode(base), ident); +} + +EncodedJSValue JIT_OPERATION operationCallGetter(ExecState* exec, JSCell* base, JSCell* getterSetter) +{ + VM* vm = &exec->vm(); + NativeCallFrameTracer tracer(vm, exec); + + return JSValue::encode(callGetter(exec, base, getterSetter)); +} + +void JIT_OPERATION operationPutByIdStrict(ExecState* exec, StructureStubInfo*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) +{ + VM* vm = &exec->vm(); + NativeCallFrameTracer tracer(vm, exec); - Identifier ident = Identifier::fromUid(vm, uid); + Identifier ident(vm, uid); PutPropertySlot slot(JSValue::decode(encodedBase), true, exec->codeBlock()->putByIdContext()); JSValue::decode(encodedBase).put(exec, ident, JSValue::decode(encodedValue), slot); } -void JIT_OPERATION operationPutByIdNonStrict(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid) +void JIT_OPERATION operationPutByIdNonStrict(ExecState* exec, StructureStubInfo*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - stubInfo->tookSlowPath = true; - - Identifier ident = Identifier::fromUid(vm, uid); + Identifier ident(vm, uid); PutPropertySlot slot(JSValue::decode(encodedBase), false, exec->codeBlock()->putByIdContext()); JSValue::decode(encodedBase).put(exec, ident, JSValue::decode(encodedValue), slot); } -void JIT_OPERATION operationPutByIdDirectStrict(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid) +void JIT_OPERATION operationPutByIdDirectStrict(ExecState* exec, StructureStubInfo*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - stubInfo->tookSlowPath = true; - - Identifier ident = Identifier::fromUid(vm, uid); + Identifier ident(vm, uid); PutPropertySlot slot(JSValue::decode(encodedBase), true, exec->codeBlock()->putByIdContext()); asObject(JSValue::decode(encodedBase))->putDirect(exec->vm(), ident, JSValue::decode(encodedValue), slot); } -void JIT_OPERATION operationPutByIdDirectNonStrict(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid) +void JIT_OPERATION operationPutByIdDirectNonStrict(ExecState* exec, StructureStubInfo*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - stubInfo->tookSlowPath = true; - - Identifier ident = Identifier::fromUid(vm, uid); + Identifier ident(vm, uid); PutPropertySlot slot(JSValue::decode(encodedBase), false, exec->codeBlock()->putByIdContext()); asObject(JSValue::decode(encodedBase))->putDirect(exec->vm(), ident, JSValue::decode(encodedValue), slot); } -void JIT_OPERATION operationPutByIdStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid) +void JIT_OPERATION operationPutByIdStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - Identifier ident = Identifier::fromUid(vm, uid); + Identifier ident(vm, uid); AccessType accessType = static_cast<AccessType>(stubInfo->accessType); JSValue value = JSValue::decode(encodedValue); JSValue baseValue = JSValue::decode(encodedBase); PutPropertySlot slot(baseValue, true, exec->codeBlock()->putByIdContext()); - - Structure* structure = baseValue.isCell() ? baseValue.asCell()->structure(*vm) : nullptr; + baseValue.put(exec, ident, value, slot); if (accessType != static_cast<AccessType>(stubInfo->accessType)) return; if (stubInfo->seen) - repatchPutByID(exec, baseValue, structure, ident, slot, *stubInfo, NotDirect); + repatchPutByID(exec, baseValue, ident, slot, *stubInfo, NotDirect); else stubInfo->seen = true; } -void JIT_OPERATION operationPutByIdNonStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid) +void JIT_OPERATION operationPutByIdNonStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - Identifier ident = Identifier::fromUid(vm, uid); + Identifier ident(vm, uid); AccessType accessType = static_cast<AccessType>(stubInfo->accessType); JSValue value = JSValue::decode(encodedValue); JSValue baseValue = JSValue::decode(encodedBase); PutPropertySlot slot(baseValue, false, exec->codeBlock()->putByIdContext()); - - Structure* structure = baseValue.isCell() ? baseValue.asCell()->structure(*vm) : nullptr; + baseValue.put(exec, ident, value, slot); if (accessType != static_cast<AccessType>(stubInfo->accessType)) return; if (stubInfo->seen) - repatchPutByID(exec, baseValue, structure, ident, slot, *stubInfo, NotDirect); + repatchPutByID(exec, baseValue, ident, slot, *stubInfo, NotDirect); else stubInfo->seen = true; } -void JIT_OPERATION operationPutByIdDirectStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid) +void JIT_OPERATION operationPutByIdDirectStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - Identifier ident = Identifier::fromUid(vm, uid); + Identifier ident(vm, uid); AccessType accessType = static_cast<AccessType>(stubInfo->accessType); JSValue value = JSValue::decode(encodedValue); JSObject* baseObject = asObject(JSValue::decode(encodedBase)); PutPropertySlot slot(baseObject, true, exec->codeBlock()->putByIdContext()); - Structure* structure = baseObject->structure(*vm); baseObject->putDirect(exec->vm(), ident, value, slot); if (accessType != static_cast<AccessType>(stubInfo->accessType)) return; if (stubInfo->seen) - repatchPutByID(exec, baseObject, structure, ident, slot, *stubInfo, Direct); + repatchPutByID(exec, baseObject, ident, slot, *stubInfo, Direct); else stubInfo->seen = true; } -void JIT_OPERATION operationPutByIdDirectNonStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid) +void JIT_OPERATION operationPutByIdDirectNonStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - Identifier ident = Identifier::fromUid(vm, uid); + Identifier ident(vm, uid); AccessType accessType = static_cast<AccessType>(stubInfo->accessType); JSValue value = JSValue::decode(encodedValue); JSObject* baseObject = asObject(JSValue::decode(encodedBase)); PutPropertySlot slot(baseObject, false, exec->codeBlock()->putByIdContext()); - Structure* structure = baseObject->structure(*vm); baseObject->putDirect(exec->vm(), ident, value, slot); if (accessType != static_cast<AccessType>(stubInfo->accessType)) return; if (stubInfo->seen) - repatchPutByID(exec, baseObject, structure, ident, slot, *stubInfo, Direct); + repatchPutByID(exec, baseObject, ident, slot, *stubInfo, Direct); else stubInfo->seen = true; } -void JIT_OPERATION operationPutByIdStrictBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid) +void JIT_OPERATION operationPutByIdStrictBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - Identifier ident = Identifier::fromUid(vm, uid); + Identifier ident(vm, uid); AccessType accessType = static_cast<AccessType>(stubInfo->accessType); JSValue value = JSValue::decode(encodedValue); JSValue baseValue = JSValue::decode(encodedBase); PutPropertySlot slot(baseValue, true, exec->codeBlock()->putByIdContext()); - Structure* structure = baseValue.isCell() ? baseValue.asCell()->structure(*vm) : nullptr; baseValue.put(exec, ident, value, slot); - + if (accessType != static_cast<AccessType>(stubInfo->accessType)) return; - - buildPutByIdList(exec, baseValue, structure, ident, slot, *stubInfo, NotDirect); + + buildPutByIdList(exec, baseValue, ident, slot, *stubInfo, NotDirect); } -void JIT_OPERATION operationPutByIdNonStrictBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid) +void JIT_OPERATION operationPutByIdNonStrictBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - Identifier ident = Identifier::fromUid(vm, uid); + Identifier ident(vm, uid); AccessType accessType = static_cast<AccessType>(stubInfo->accessType); JSValue value = JSValue::decode(encodedValue); JSValue baseValue = JSValue::decode(encodedBase); PutPropertySlot slot(baseValue, false, exec->codeBlock()->putByIdContext()); - - Structure* structure = baseValue.isCell() ? baseValue.asCell()->structure(*vm) : nullptr; + baseValue.put(exec, ident, value, slot); if (accessType != static_cast<AccessType>(stubInfo->accessType)) return; - buildPutByIdList(exec, baseValue, structure, ident, slot, *stubInfo, NotDirect); + buildPutByIdList(exec, baseValue, ident, slot, *stubInfo, NotDirect); } -void JIT_OPERATION operationPutByIdDirectStrictBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid) +void JIT_OPERATION operationPutByIdDirectStrictBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - Identifier ident = Identifier::fromUid(vm, uid); + Identifier ident(vm, uid); AccessType accessType = static_cast<AccessType>(stubInfo->accessType); JSValue value = JSValue::decode(encodedValue); JSObject* baseObject = asObject(JSValue::decode(encodedBase)); PutPropertySlot slot(baseObject, true, exec->codeBlock()->putByIdContext()); - - Structure* structure = baseObject->structure(*vm); - baseObject->putDirect(*vm, ident, value, slot); + + baseObject->putDirect(exec->vm(), ident, value, slot); if (accessType != static_cast<AccessType>(stubInfo->accessType)) return; - buildPutByIdList(exec, baseObject, structure, ident, slot, *stubInfo, Direct); + buildPutByIdList(exec, baseObject, ident, slot, *stubInfo, Direct); } -void JIT_OPERATION operationPutByIdDirectNonStrictBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid) +void JIT_OPERATION operationPutByIdDirectNonStrictBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - Identifier ident = Identifier::fromUid(vm, uid); + Identifier ident(vm, uid); AccessType accessType = static_cast<AccessType>(stubInfo->accessType); JSValue value = JSValue::decode(encodedValue); JSObject* baseObject = asObject(JSValue::decode(encodedBase)); PutPropertySlot slot(baseObject, false, exec->codeBlock()->putByIdContext()); - - Structure* structure = baseObject->structure(*vm); - baseObject->putDirect(*vm, ident, value, slot); - + + baseObject ->putDirect(exec->vm(), ident, value, slot); + if (accessType != static_cast<AccessType>(stubInfo->accessType)) return; - buildPutByIdList(exec, baseObject, structure, ident, slot, *stubInfo, Direct); + buildPutByIdList(exec, baseObject, ident, slot, *stubInfo, Direct); } void JIT_OPERATION operationReallocateStorageAndFinishPut(ExecState* exec, JSObject* base, Structure* structure, PropertyOffset offset, EncodedJSValue value) @@ -473,29 +450,29 @@ void JIT_OPERATION operationReallocateStorageAndFinishPut(ExecState* exec, JSObj VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); - ASSERT(structure->outOfLineCapacity() > base->structure(vm)->outOfLineCapacity()); + ASSERT(structure->outOfLineCapacity() > base->structure()->outOfLineCapacity()); ASSERT(!vm.heap.storageAllocator().fastPathShouldSucceed(structure->outOfLineCapacity() * sizeof(JSValue))); base->setStructureAndReallocateStorageIfNecessary(vm, structure); base->putDirect(vm, offset, JSValue::decode(value)); } -static void putByVal(CallFrame* callFrame, JSValue baseValue, JSValue subscript, JSValue value, ByValInfo* byValInfo) +static void putByVal(CallFrame* callFrame, JSValue baseValue, JSValue subscript, JSValue value) { - VM& vm = callFrame->vm(); if (LIKELY(subscript.isUInt32())) { uint32_t i = subscript.asUInt32(); if (baseValue.isObject()) { JSObject* object = asObject(baseValue); if (object->canSetIndexQuickly(i)) object->setIndexQuickly(callFrame->vm(), i, value); - else { - byValInfo->arrayProfile->setOutOfBounds(); - object->methodTable(vm)->putByIndex(object, callFrame, i, value, callFrame->codeBlock()->isStrictMode()); - } + else + object->methodTable()->putByIndex(object, callFrame, i, value, callFrame->codeBlock()->isStrictMode()); } else baseValue.putByIndex(callFrame, i, value, callFrame->codeBlock()->isStrictMode()); + } else if (isName(subscript)) { + PutPropertySlot slot(baseValue, callFrame->codeBlock()->isStrictMode()); + baseValue.put(callFrame, jsCast<NameInstance*>(subscript.asCell())->privateName(), value, slot); } else { - auto property = subscript.toPropertyKey(callFrame); + Identifier property(callFrame, subscript.toString(callFrame)->value(callFrame)); if (!callFrame->vm().exception()) { // Don't put to an object if toString threw an exception. PutPropertySlot slot(baseValue, callFrame->codeBlock()->isStrictMode()); baseValue.put(callFrame, property, value, slot); @@ -503,45 +480,23 @@ static void putByVal(CallFrame* callFrame, JSValue baseValue, JSValue subscript, } } -static void directPutByVal(CallFrame* callFrame, JSObject* baseObject, JSValue subscript, JSValue value, ByValInfo* byValInfo) +static void directPutByVal(CallFrame* callFrame, JSObject* baseObject, JSValue subscript, JSValue value) { - bool isStrictMode = callFrame->codeBlock()->isStrictMode(); if (LIKELY(subscript.isUInt32())) { - // Despite its name, JSValue::isUInt32 will return true only for positive boxed int32_t; all those values are valid array indices. - uint32_t index = subscript.asUInt32(); - ASSERT(isIndex(index)); - if (baseObject->canSetIndexQuicklyForPutDirect(index)) { - baseObject->setIndexQuickly(callFrame->vm(), index, value); - return; - } - - byValInfo->arrayProfile->setOutOfBounds(); - baseObject->putDirectIndex(callFrame, index, value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow); - return; - } - - if (subscript.isDouble()) { - double subscriptAsDouble = subscript.asDouble(); - uint32_t subscriptAsUInt32 = static_cast<uint32_t>(subscriptAsDouble); - if (subscriptAsDouble == subscriptAsUInt32 && isIndex(subscriptAsUInt32)) { - baseObject->putDirectIndex(callFrame, subscriptAsUInt32, value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow); - return; + uint32_t i = subscript.asUInt32(); + baseObject->putDirectIndex(callFrame, i, value); + } else if (isName(subscript)) { + PutPropertySlot slot(baseObject, callFrame->codeBlock()->isStrictMode()); + baseObject->putDirect(callFrame->vm(), jsCast<NameInstance*>(subscript.asCell())->privateName(), value, slot); + } else { + Identifier property(callFrame, subscript.toString(callFrame)->value(callFrame)); + if (!callFrame->vm().exception()) { // Don't put to an object if toString threw an exception. + PutPropertySlot slot(baseObject, callFrame->codeBlock()->isStrictMode()); + baseObject->putDirect(callFrame->vm(), property, value, slot); } } - - // Don't put to an object if toString threw an exception. - auto property = subscript.toPropertyKey(callFrame); - if (callFrame->vm().exception()) - return; - - if (Optional<uint32_t> index = parseIndex(property)) - baseObject->putDirectIndex(callFrame, index.value(), value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow); - else { - PutPropertySlot slot(baseObject, isStrictMode); - baseObject->putDirect(callFrame->vm(), property, value, slot); - } } -void JIT_OPERATION operationPutByVal(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ByValInfo* byValInfo) +void JIT_OPERATION operationPutByVal(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); @@ -555,19 +510,16 @@ void JIT_OPERATION operationPutByVal(ExecState* exec, EncodedJSValue encodedBase JSObject* object = asObject(baseValue); bool didOptimize = false; - ASSERT(exec->locationAsBytecodeOffset()); - ASSERT(!byValInfo->stubRoutine); + unsigned bytecodeOffset = exec->locationAsBytecodeOffset(); + ASSERT(bytecodeOffset); + ByValInfo& byValInfo = exec->codeBlock()->getByValInfo(bytecodeOffset - 1); + ASSERT(!byValInfo.stubRoutine); - Structure* structure = object->structure(vm); - if (hasOptimizableIndexing(structure)) { + if (hasOptimizableIndexing(object->structure())) { // Attempt to optimize. - JITArrayMode arrayMode = jitArrayModeForStructure(structure); - if (jitArrayModePermitsPut(arrayMode) && arrayMode != byValInfo->arrayMode) { - CodeBlock* codeBlock = exec->codeBlock(); - ConcurrentJITLocker locker(codeBlock->m_lock); - byValInfo->arrayProfile->computeUpdatedPrediction(locker, codeBlock, structure); - - JIT::compilePutByVal(&vm, exec->codeBlock(), byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode); + JITArrayMode arrayMode = jitArrayModeForStructure(object->structure()); + if (arrayMode != byValInfo.arrayMode) { + JIT::compilePutByVal(&vm, exec->codeBlock(), &byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode); didOptimize = true; } } @@ -578,18 +530,19 @@ void JIT_OPERATION operationPutByVal(ExecState* exec, EncodedJSValue encodedBase // that intercepts indexed get, then don't even wait until 10 times. For cases // where we see non-index-intercepting objects, this gives 10 iterations worth of // opportunity for us to observe that the get_by_val may be polymorphic. - if (++byValInfo->slowPathCount >= 10 - || object->structure(vm)->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) { + if (++byValInfo.slowPathCount >= 10 + || object->structure()->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) { // Don't ever try to optimize. - ctiPatchCallByReturnAddress(exec->codeBlock(), ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationPutByValGeneric)); + RepatchBuffer repatchBuffer(exec->codeBlock()); + repatchBuffer.relinkCallerToFunction(ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationPutByValGeneric)); } } } - putByVal(exec, baseValue, subscript, value, byValInfo); + putByVal(exec, baseValue, subscript, value); } -void JIT_OPERATION operationDirectPutByVal(ExecState* callFrame, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ByValInfo* byValInfo) +void JIT_OPERATION operationDirectPutByVal(ExecState* callFrame, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue) { VM& vm = callFrame->vm(); NativeCallFrameTracer tracer(&vm, callFrame); @@ -602,20 +555,17 @@ void JIT_OPERATION operationDirectPutByVal(ExecState* callFrame, EncodedJSValue if (subscript.isInt32()) { // See if it's worth optimizing at all. bool didOptimize = false; - - ASSERT(callFrame->locationAsBytecodeOffset()); - ASSERT(!byValInfo->stubRoutine); - - Structure* structure = object->structure(vm); - if (hasOptimizableIndexing(structure)) { + + unsigned bytecodeOffset = callFrame->locationAsBytecodeOffset(); + ASSERT(bytecodeOffset); + ByValInfo& byValInfo = callFrame->codeBlock()->getByValInfo(bytecodeOffset - 1); + ASSERT(!byValInfo.stubRoutine); + + if (hasOptimizableIndexing(object->structure())) { // Attempt to optimize. - JITArrayMode arrayMode = jitArrayModeForStructure(structure); - if (jitArrayModePermitsPut(arrayMode) && arrayMode != byValInfo->arrayMode) { - CodeBlock* codeBlock = callFrame->codeBlock(); - ConcurrentJITLocker locker(codeBlock->m_lock); - byValInfo->arrayProfile->computeUpdatedPrediction(locker, codeBlock, structure); - - JIT::compileDirectPutByVal(&vm, callFrame->codeBlock(), byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode); + JITArrayMode arrayMode = jitArrayModeForStructure(object->structure()); + if (arrayMode != byValInfo.arrayMode) { + JIT::compileDirectPutByVal(&vm, callFrame->codeBlock(), &byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode); didOptimize = true; } } @@ -626,17 +576,18 @@ void JIT_OPERATION operationDirectPutByVal(ExecState* callFrame, EncodedJSValue // that intercepts indexed get, then don't even wait until 10 times. For cases // where we see non-index-intercepting objects, this gives 10 iterations worth of // opportunity for us to observe that the get_by_val may be polymorphic. - if (++byValInfo->slowPathCount >= 10 - || object->structure(vm)->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) { + if (++byValInfo.slowPathCount >= 10 + || object->structure()->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) { // Don't ever try to optimize. - ctiPatchCallByReturnAddress(callFrame->codeBlock(), ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationDirectPutByValGeneric)); + RepatchBuffer repatchBuffer(callFrame->codeBlock()); + repatchBuffer.relinkCallerToFunction(ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationDirectPutByValGeneric)); } } } - directPutByVal(callFrame, object, subscript, value, byValInfo); + directPutByVal(callFrame, object, subscript, value); } -void JIT_OPERATION operationPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ByValInfo* byValInfo) +void JIT_OPERATION operationPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); @@ -645,11 +596,11 @@ void JIT_OPERATION operationPutByValGeneric(ExecState* exec, EncodedJSValue enco JSValue subscript = JSValue::decode(encodedSubscript); JSValue value = JSValue::decode(encodedValue); - putByVal(exec, baseValue, subscript, value, byValInfo); + putByVal(exec, baseValue, subscript, value); } -void JIT_OPERATION operationDirectPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ByValInfo* byValInfo) +void JIT_OPERATION operationDirectPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); @@ -658,13 +609,18 @@ void JIT_OPERATION operationDirectPutByValGeneric(ExecState* exec, EncodedJSValu JSValue subscript = JSValue::decode(encodedSubscript); JSValue value = JSValue::decode(encodedValue); RELEASE_ASSERT(baseValue.isObject()); - directPutByVal(exec, asObject(baseValue), subscript, value, byValInfo); + directPutByVal(exec, asObject(baseValue), subscript, value); } -EncodedJSValue JIT_OPERATION operationCallEval(ExecState* exec, ExecState* execCallee) +EncodedJSValue JIT_OPERATION operationCallEval(ExecState* execCallee) { - UNUSED_PARAM(exec); + CallFrame* callerFrame = execCallee->callerFrame(); + ASSERT(execCallee->callerFrame()->codeBlock()->codeType() != FunctionCode + || !execCallee->callerFrame()->codeBlock()->needsFullScopeChain() + || execCallee->callerFrame()->uncheckedR(execCallee->callerFrame()->codeBlock()->activationRegister().offset()).jsValue()); + execCallee->setScope(callerFrame->scope()); + execCallee->setReturnPC(static_cast<Instruction*>(OUR_RETURN_ADDRESS)); execCallee->setCodeBlock(0); if (!isHostFunction(execCallee->calleeAsValue(), globalFuncEval)) @@ -683,6 +639,7 @@ static void* handleHostCall(ExecState* execCallee, JSValue callee, CodeSpecializ ExecState* exec = execCallee->callerFrame(); VM* vm = &exec->vm(); + execCallee->setScope(exec->scope()); execCallee->setCodeBlock(0); if (kind == CodeForCall) { @@ -728,65 +685,60 @@ static void* handleHostCall(ExecState* execCallee, JSValue callee, CodeSpecializ return vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); } -char* JIT_OPERATION operationLinkCall(ExecState* execCallee, CallLinkInfo* callLinkInfo) +inline char* linkFor(ExecState* execCallee, CodeSpecializationKind kind) { ExecState* exec = execCallee->callerFrame(); VM* vm = &exec->vm(); - CodeSpecializationKind kind = callLinkInfo->specializationKind(); NativeCallFrameTracer tracer(vm, exec); JSValue calleeAsValue = execCallee->calleeAsValue(); JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue); - if (!calleeAsFunctionCell) { - // FIXME: We should cache these kinds of calls. They can be common and currently they are - // expensive. - // https://bugs.webkit.org/show_bug.cgi?id=144458 + if (!calleeAsFunctionCell) return reinterpret_cast<char*>(handleHostCall(execCallee, calleeAsValue, kind)); - } JSFunction* callee = jsCast<JSFunction*>(calleeAsFunctionCell); - JSScope* scope = callee->scopeUnchecked(); + execCallee->setScope(callee->scopeUnchecked()); ExecutableBase* executable = callee->executable(); MacroAssemblerCodePtr codePtr; CodeBlock* codeBlock = 0; + CallLinkInfo& callLinkInfo = exec->codeBlock()->getCallLinkInfo(execCallee->returnPC()); if (executable->isHostFunction()) - codePtr = executable->entrypointFor(*vm, kind, MustCheckArity, callLinkInfo->registerPreservationMode()); + codePtr = executable->generatedJITCodeFor(kind)->addressForCall(); else { FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable); - - if (!isCall(kind) && functionExecutable->constructAbility() == ConstructAbility::CannotConstruct) { - exec->vm().throwException(exec, createNotAConstructorError(exec, callee)); - return reinterpret_cast<char*>(vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress()); - } - - JSObject* error = functionExecutable->prepareForExecution(execCallee, callee, scope, kind); + JSObject* error = functionExecutable->prepareForExecution(execCallee, callee->scope(), kind); if (error) { - exec->vm().throwException(exec, error); + vm->throwException(exec, createStackOverflowError(exec)); return reinterpret_cast<char*>(vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress()); } codeBlock = functionExecutable->codeBlockFor(kind); - ArityCheckMode arity; - if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters()) || callLinkInfo->callType() == CallLinkInfo::CallVarargs || callLinkInfo->callType() == CallLinkInfo::ConstructVarargs) - arity = MustCheckArity; + if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters()) || callLinkInfo.callType == CallLinkInfo::CallVarargs) + codePtr = functionExecutable->generatedJITCodeWithArityCheckFor(kind); else - arity = ArityCheckNotRequired; - codePtr = functionExecutable->entrypointFor(*vm, kind, arity, callLinkInfo->registerPreservationMode()); + codePtr = functionExecutable->generatedJITCodeFor(kind)->addressForCall(); } - if (!callLinkInfo->seenOnce()) - callLinkInfo->setSeen(); + if (!callLinkInfo.seenOnce()) + callLinkInfo.setSeen(); else - linkFor(execCallee, *callLinkInfo, codeBlock, callee, codePtr); - + linkFor(execCallee, callLinkInfo, codeBlock, callee, codePtr, kind); return reinterpret_cast<char*>(codePtr.executableAddress()); } -inline char* virtualForWithFunction( - ExecState* execCallee, CallLinkInfo* callLinkInfo, JSCell*& calleeAsFunctionCell) +char* JIT_OPERATION operationLinkCall(ExecState* execCallee) +{ + return linkFor(execCallee, CodeForCall); +} + +char* JIT_OPERATION operationLinkConstruct(ExecState* execCallee) +{ + return linkFor(execCallee, CodeForConstruct); +} + +inline char* virtualForWithFunction(ExecState* execCallee, CodeSpecializationKind kind, JSCell*& calleeAsFunctionCell) { ExecState* exec = execCallee->callerFrame(); VM* vm = &exec->vm(); - CodeSpecializationKind kind = callLinkInfo->specializationKind(); NativeCallFrameTracer tracer(vm, exec); JSValue calleeAsValue = execCallee->calleeAsValue(); @@ -795,43 +747,80 @@ inline char* virtualForWithFunction( return reinterpret_cast<char*>(handleHostCall(execCallee, calleeAsValue, kind)); JSFunction* function = jsCast<JSFunction*>(calleeAsFunctionCell); - JSScope* scope = function->scopeUnchecked(); + execCallee->setScope(function->scopeUnchecked()); ExecutableBase* executable = function->executable(); if (UNLIKELY(!executable->hasJITCodeFor(kind))) { FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable); - - if (!isCall(kind) && functionExecutable->constructAbility() == ConstructAbility::CannotConstruct) { - exec->vm().throwException(exec, createNotAConstructorError(exec, function)); - return reinterpret_cast<char*>(vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress()); - } - - JSObject* error = functionExecutable->prepareForExecution(execCallee, function, scope, kind); + JSObject* error = functionExecutable->prepareForExecution(execCallee, function->scope(), kind); if (error) { - exec->vm().throwException(exec, error); + exec->vm().throwException(execCallee, error); return reinterpret_cast<char*>(vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress()); } } - return reinterpret_cast<char*>(executable->entrypointFor( - *vm, kind, MustCheckArity, callLinkInfo->registerPreservationMode()).executableAddress()); + return reinterpret_cast<char*>(executable->generatedJITCodeWithArityCheckFor(kind).executableAddress()); +} + +inline char* virtualFor(ExecState* execCallee, CodeSpecializationKind kind) +{ + JSCell* calleeAsFunctionCellIgnored; + return virtualForWithFunction(execCallee, kind, calleeAsFunctionCellIgnored); +} + +static bool attemptToOptimizeClosureCall(ExecState* execCallee, JSCell* calleeAsFunctionCell, CallLinkInfo& callLinkInfo) +{ + if (!calleeAsFunctionCell) + return false; + + JSFunction* callee = jsCast<JSFunction*>(calleeAsFunctionCell); + JSFunction* oldCallee = callLinkInfo.callee.get(); + + if (!oldCallee + || oldCallee->structure() != callee->structure() + || oldCallee->executable() != callee->executable()) + return false; + + ASSERT(callee->executable()->hasJITCodeForCall()); + MacroAssemblerCodePtr codePtr = callee->executable()->generatedJITCodeForCall()->addressForCall(); + + CodeBlock* codeBlock; + if (callee->executable()->isHostFunction()) + codeBlock = 0; + else { + codeBlock = jsCast<FunctionExecutable*>(callee->executable())->codeBlockForCall(); + if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters())) + return false; + } + + linkClosureCall( + execCallee, callLinkInfo, codeBlock, + callee->structure(), callee->executable(), codePtr); + + return true; } -char* JIT_OPERATION operationLinkPolymorphicCall(ExecState* execCallee, CallLinkInfo* callLinkInfo) +char* JIT_OPERATION operationLinkClosureCall(ExecState* execCallee) { - ASSERT(callLinkInfo->specializationKind() == CodeForCall); JSCell* calleeAsFunctionCell; - char* result = virtualForWithFunction(execCallee, callLinkInfo, calleeAsFunctionCell); + char* result = virtualForWithFunction(execCallee, CodeForCall, calleeAsFunctionCell); + CallLinkInfo& callLinkInfo = execCallee->callerFrame()->codeBlock()->getCallLinkInfo(execCallee->returnPC()); - linkPolymorphicCall(execCallee, *callLinkInfo, CallVariant(calleeAsFunctionCell)); + if (!attemptToOptimizeClosureCall(execCallee, calleeAsFunctionCell, callLinkInfo)) + linkSlowFor(execCallee, callLinkInfo, CodeForCall); return result; } -char* JIT_OPERATION operationVirtualCall(ExecState* execCallee, CallLinkInfo* callLinkInfo) +char* JIT_OPERATION operationVirtualCall(ExecState* execCallee) +{ + return virtualFor(execCallee, CodeForCall); +} + +char* JIT_OPERATION operationVirtualConstruct(ExecState* execCallee) { - JSCell* calleeAsFunctionCellIgnored; - return virtualForWithFunction(execCallee, callLinkInfo, calleeAsFunctionCellIgnored); + return virtualFor(execCallee, CodeForConstruct); } + size_t JIT_OPERATION operationCompareLess(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) { VM* vm = &exec->vm(); @@ -889,7 +878,7 @@ size_t JIT_OPERATION operationCompareStringEq(ExecState* exec, JSCell* left, JSC VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - bool result = WTF::equal(*asString(left)->value(exec).impl(), *asString(right)->value(exec).impl()); + bool result = asString(left)->value(exec) == asString(right)->value(exec); #if USE(JSVALUE64) return JSValue::encode(jsBoolean(result)); #else @@ -899,7 +888,7 @@ size_t JIT_OPERATION operationCompareStringEq(ExecState* exec, JSCell* left, JSC size_t JIT_OPERATION operationHasProperty(ExecState* exec, JSObject* base, JSString* property) { - int result = base->hasProperty(exec, property->toIdentifier(exec)); + int result = base->hasProperty(exec, Identifier(exec, property->value(exec))); return result; } @@ -926,20 +915,12 @@ EncodedJSValue JIT_OPERATION operationNewArrayWithSizeAndProfile(ExecState* exec return JSValue::encode(constructArrayWithSizeQuirk(exec, profile, exec->lexicalGlobalObject(), sizeValue)); } -EncodedJSValue JIT_OPERATION operationNewFunction(ExecState* exec, JSScope* scope, JSCell* functionExecutable) -{ - ASSERT(functionExecutable->inherits(FunctionExecutable::info())); - VM& vm = exec->vm(); - NativeCallFrameTracer tracer(&vm, exec); - return JSValue::encode(JSFunction::create(vm, static_cast<FunctionExecutable*>(functionExecutable), scope)); -} - -EncodedJSValue JIT_OPERATION operationNewFunctionWithInvalidatedReallocationWatchpoint(ExecState* exec, JSScope* scope, JSCell* functionExecutable) +EncodedJSValue JIT_OPERATION operationNewFunction(ExecState* exec, JSCell* functionExecutable) { ASSERT(functionExecutable->inherits(FunctionExecutable::info())); VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); - return JSValue::encode(JSFunction::createWithInvalidatedReallocationWatchpoint(vm, static_cast<FunctionExecutable*>(functionExecutable), scope)); + return JSValue::encode(JSFunction::create(vm, static_cast<FunctionExecutable*>(functionExecutable), exec->scope())); } JSCell* JIT_OPERATION operationNewObject(ExecState* exec, Structure* structure) @@ -956,7 +937,7 @@ EncodedJSValue JIT_OPERATION operationNewRegexp(ExecState* exec, void* regexpPtr NativeCallFrameTracer tracer(&vm, exec); RegExp* regexp = static_cast<RegExp*>(regexpPtr); if (!regexp->isValid()) { - vm.throwException(exec, createSyntaxError(exec, ASCIILiteral("Invalid flags supplied to RegExp constructor."))); + vm.throwException(exec, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor.")); return JSValue::encode(jsUndefined()); } @@ -968,7 +949,7 @@ void JIT_OPERATION operationHandleWatchdogTimer(ExecState* exec) VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); - if (UNLIKELY(vm.shouldTriggerTermination(exec))) + if (UNLIKELY(vm.watchdog.didFire(exec))) vm.throwException(exec, createTerminatedExecutionException(&vm)); } @@ -976,13 +957,12 @@ void JIT_OPERATION operationThrowStaticError(ExecState* exec, EncodedJSValue enc { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); - JSValue errorMessageValue = JSValue::decode(encodedValue); - RELEASE_ASSERT(errorMessageValue.isString()); - String errorMessage = asString(errorMessageValue)->value(exec); + + String message = errorDescriptionForValue(exec, JSValue::decode(encodedValue))->value(exec); if (referenceErrorFlag) - vm.throwException(exec, createReferenceError(exec, errorMessage)); + vm.throwException(exec, createReferenceError(exec, message)); else - vm.throwException(exec, createTypeError(exec, errorMessage)); + vm.throwException(exec, createTypeError(exec, message)); } void JIT_OPERATION operationDebug(ExecState* exec, int32_t debugHookID) @@ -994,13 +974,7 @@ void JIT_OPERATION operationDebug(ExecState* exec, int32_t debugHookID) } #if ENABLE(DFG_JIT) -static void updateAllPredictionsAndOptimizeAfterWarmUp(CodeBlock* codeBlock) -{ - codeBlock->updateAllPredictions(); - codeBlock->optimizeAfterWarmUp(); -} - -SlowPathReturnType JIT_OPERATION operationOptimize(ExecState* exec, int32_t bytecodeIndex) +char* JIT_OPERATION operationOptimize(ExecState* exec, int32_t bytecodeIndex) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); @@ -1022,11 +996,7 @@ SlowPathReturnType JIT_OPERATION operationOptimize(ExecState* exec, int32_t byte DeferGCForAWhile deferGC(vm.heap); CodeBlock* codeBlock = exec->codeBlock(); - if (codeBlock->jitType() != JITCode::BaselineJIT) { - dataLog("Unexpected code block in Baseline->DFG tier-up: ", *codeBlock, "\n"); - RELEASE_ASSERT_NOT_REACHED(); - } - + if (bytecodeIndex) { // If we're attempting to OSR from a loop, assume that this should be // separately optimized. @@ -1050,37 +1020,26 @@ SlowPathReturnType JIT_OPERATION operationOptimize(ExecState* exec, int32_t byte codeBlock->updateAllPredictions(); if (Options::verboseOSR()) dataLog("Choosing not to optimize ", *codeBlock, " yet, because the threshold hasn't been reached.\n"); - return encodeResult(0, 0); + return 0; } - if (vm.enabledProfiler()) { - updateAllPredictionsAndOptimizeAfterWarmUp(codeBlock); - return encodeResult(0, 0); - } - - Debugger* debugger = codeBlock->globalObject()->debugger(); - if (debugger && (debugger->isStepping() || codeBlock->baselineAlternative()->hasDebuggerRequests())) { - updateAllPredictionsAndOptimizeAfterWarmUp(codeBlock); - return encodeResult(0, 0); - } - if (codeBlock->m_shouldAlwaysBeInlined) { - updateAllPredictionsAndOptimizeAfterWarmUp(codeBlock); + codeBlock->updateAllPredictions(); + codeBlock->optimizeAfterWarmUp(); if (Options::verboseOSR()) dataLog("Choosing not to optimize ", *codeBlock, " yet, because m_shouldAlwaysBeInlined == true.\n"); - return encodeResult(0, 0); + return 0; } // We cannot be in the process of asynchronous compilation and also have an optimized // replacement. - DFG::Worklist* worklist = DFG::existingGlobalDFGWorklistOrNull(); ASSERT( - !worklist - || !(worklist->compilationState(DFG::CompilationKey(codeBlock, DFG::DFGMode)) != DFG::Worklist::NotKnown + !vm.worklist + || !(vm.worklist->compilationState(DFG::CompilationKey(codeBlock, DFG::DFGMode)) != DFG::Worklist::NotKnown && codeBlock->hasOptimizedReplacement())); DFG::Worklist::State worklistState; - if (worklist) { + if (vm.worklist) { // The call to DFG::Worklist::completeAllReadyPlansForVM() will complete all ready // (i.e. compiled) code blocks. But if it completes ours, we also need to know // what the result was so that we don't plow ahead and attempt OSR or immediate @@ -1099,7 +1058,7 @@ SlowPathReturnType JIT_OPERATION operationOptimize(ExecState* exec, int32_t byte // probably a waste of memory. Our goal here is to complete code blocks as soon as // possible in order to minimize the chances of us executing baseline code after // optimized code is already available. - worklistState = worklist->completeAllReadyPlansForVM( + worklistState = vm.worklist->completeAllReadyPlansForVM( vm, DFG::CompilationKey(codeBlock, DFG::DFGMode)); } else worklistState = DFG::Worklist::NotKnown; @@ -1109,7 +1068,7 @@ SlowPathReturnType JIT_OPERATION operationOptimize(ExecState* exec, int32_t byte // replacement. RELEASE_ASSERT(!codeBlock->hasOptimizedReplacement()); codeBlock->setOptimizationThresholdBasedOnCompilationResult(CompilationDeferred); - return encodeResult(0, 0); + return 0; } if (worklistState == DFG::Worklist::Compiled) { @@ -1122,7 +1081,7 @@ SlowPathReturnType JIT_OPERATION operationOptimize(ExecState* exec, int32_t byte codeBlock->updateAllPredictions(); if (Options::verboseOSR()) dataLog("Code block ", *codeBlock, " was compiled but it doesn't have an optimized replacement.\n"); - return encodeResult(0, 0); + return 0; } } else if (codeBlock->hasOptimizedReplacement()) { if (Options::verboseOSR()) @@ -1146,8 +1105,8 @@ SlowPathReturnType JIT_OPERATION operationOptimize(ExecState* exec, int32_t byte "Triggering reoptimization of ", *codeBlock, "(", *codeBlock->replacement(), ") (in loop).\n"); } - codeBlock->replacement()->jettison(Profiler::JettisonDueToBaselineLoopReoptimizationTrigger, CountReoptimization); - return encodeResult(0, 0); + codeBlock->replacement()->jettison(CountReoptimization); + return 0; } } else { if (!codeBlock->shouldOptimizeNow()) { @@ -1156,7 +1115,7 @@ SlowPathReturnType JIT_OPERATION operationOptimize(ExecState* exec, int32_t byte "Delaying optimization for ", *codeBlock, " because of insufficient profiling.\n"); } - return encodeResult(0, 0); + return 0; } if (Options::verboseOSR()) @@ -1170,31 +1129,40 @@ SlowPathReturnType JIT_OPERATION operationOptimize(ExecState* exec, int32_t byte Operands<JSValue> mustHandleValues(codeBlock->numParameters(), numVarsWithValues); for (size_t i = 0; i < mustHandleValues.size(); ++i) { int operand = mustHandleValues.operandForIndex(i); - mustHandleValues[i] = exec->uncheckedR(operand).jsValue(); + if (operandIsArgument(operand) + && !VirtualRegister(operand).toArgument() + && codeBlock->codeType() == FunctionCode + && codeBlock->specializationKind() == CodeForConstruct) { + // Ugh. If we're in a constructor, the 'this' argument may hold garbage. It will + // also never be used. It doesn't matter what we put into the value for this, + // but it has to be an actual value that can be grokked by subsequent DFG passes, + // so we sanitize it here by turning it into Undefined. + mustHandleValues[i] = jsUndefined(); + } else + mustHandleValues[i] = exec->uncheckedR(operand).jsValue(); } - RefPtr<CodeBlock> replacementCodeBlock = codeBlock->newReplacement(); CompilationResult result = DFG::compile( - vm, replacementCodeBlock.get(), 0, DFG::DFGMode, bytecodeIndex, - mustHandleValues, JITToDFGDeferredCompilationCallback::create()); + vm, codeBlock->newReplacement().get(), DFG::DFGMode, bytecodeIndex, + mustHandleValues, JITToDFGDeferredCompilationCallback::create(), + vm.ensureWorklist()); - if (result != CompilationSuccessful) { - ASSERT(result == CompilationDeferred || replacementCodeBlock->hasOneRef()); - return encodeResult(0, 0); - } + if (result != CompilationSuccessful) + return 0; } CodeBlock* optimizedCodeBlock = codeBlock->replacement(); ASSERT(JITCode::isOptimizingJIT(optimizedCodeBlock->jitType())); - if (void* dataBuffer = DFG::prepareOSREntry(exec, optimizedCodeBlock, bytecodeIndex)) { + if (void* address = DFG::prepareOSREntry(exec, optimizedCodeBlock, bytecodeIndex)) { if (Options::verboseOSR()) { dataLog( - "Performing OSR ", *codeBlock, " -> ", *optimizedCodeBlock, ".\n"); + "Performing OSR ", *codeBlock, " -> ", *optimizedCodeBlock, ", address ", + RawPointer(OUR_RETURN_ADDRESS), " -> ", RawPointer(address), ".\n"); } codeBlock->optimizeSoon(); - return encodeResult(vm.getCTIStub(DFG::osrEntryThunkGenerator).code().executableAddress(), dataBuffer); + return static_cast<char*>(address); } if (Options::verboseOSR()) { @@ -1222,15 +1190,15 @@ SlowPathReturnType JIT_OPERATION operationOptimize(ExecState* exec, int32_t byte "Triggering reoptimization of ", *codeBlock, " -> ", *codeBlock->replacement(), " (after OSR fail).\n"); } - optimizedCodeBlock->jettison(Profiler::JettisonDueToBaselineLoopReoptimizationTriggerOnOSREntryFail, CountReoptimization); - return encodeResult(0, 0); + optimizedCodeBlock->jettison(CountReoptimization); + return 0; } // OSR failed this time, but it might succeed next time! Let the code run a bit // longer and then try again. codeBlock->optimizeAfterWarmUp(); - return encodeResult(0, 0); + return 0; } #endif @@ -1245,32 +1213,6 @@ void JIT_OPERATION operationPutByIndex(ExecState* exec, EncodedJSValue encodedAr } #if USE(JSVALUE64) -void JIT_OPERATION operationPutGetterById(ExecState* exec, EncodedJSValue encodedObjectValue, Identifier* identifier, EncodedJSValue encodedGetterValue) -{ - VM& vm = exec->vm(); - NativeCallFrameTracer tracer(&vm, exec); - - ASSERT(JSValue::decode(encodedObjectValue).isObject()); - JSObject* baseObj = asObject(JSValue::decode(encodedObjectValue)); - - JSValue getter = JSValue::decode(encodedGetterValue); - ASSERT(getter.isObject()); - baseObj->putGetter(exec, *identifier, asObject(getter)); -} - -void JIT_OPERATION operationPutSetterById(ExecState* exec, EncodedJSValue encodedObjectValue, Identifier* identifier, EncodedJSValue encodedSetterValue) -{ - VM& vm = exec->vm(); - NativeCallFrameTracer tracer(&vm, exec); - - ASSERT(JSValue::decode(encodedObjectValue).isObject()); - JSObject* baseObj = asObject(JSValue::decode(encodedObjectValue)); - - JSValue setter = JSValue::decode(encodedSetterValue); - ASSERT(setter.isObject()); - baseObj->putSetter(exec, *identifier, asObject(setter)); -} - void JIT_OPERATION operationPutGetterSetter(ExecState* exec, EncodedJSValue encodedObjectValue, Identifier* identifier, EncodedJSValue encodedGetterValue, EncodedJSValue encodedSetterValue) { VM& vm = exec->vm(); @@ -1279,7 +1221,7 @@ void JIT_OPERATION operationPutGetterSetter(ExecState* exec, EncodedJSValue enco ASSERT(JSValue::decode(encodedObjectValue).isObject()); JSObject* baseObj = asObject(JSValue::decode(encodedObjectValue)); - GetterSetter* accessor = GetterSetter::create(vm, exec->lexicalGlobalObject()); + GetterSetter* accessor = GetterSetter::create(vm); JSValue getter = JSValue::decode(encodedGetterValue); JSValue setter = JSValue::decode(encodedSetterValue); @@ -1288,13 +1230,13 @@ void JIT_OPERATION operationPutGetterSetter(ExecState* exec, EncodedJSValue enco ASSERT(getter.isObject() || setter.isObject()); if (!getter.isUndefined()) - accessor->setGetter(vm, exec->lexicalGlobalObject(), asObject(getter)); + accessor->setGetter(vm, asObject(getter)); if (!setter.isUndefined()) - accessor->setSetter(vm, exec->lexicalGlobalObject(), asObject(setter)); + accessor->setSetter(vm, asObject(setter)); baseObj->putDirectAccessor(exec, *identifier, accessor, Accessor); } #else -void JIT_OPERATION operationPutGetterById(ExecState* exec, JSCell* object, Identifier* identifier, JSCell* getter) +void JIT_OPERATION operationPutGetterSetter(ExecState* exec, JSCell* object, Identifier* identifier, JSCell* getter, JSCell* setter) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); @@ -1302,51 +1244,48 @@ void JIT_OPERATION operationPutGetterById(ExecState* exec, JSCell* object, Ident ASSERT(object && object->isObject()); JSObject* baseObj = object->getObject(); - ASSERT(getter->isObject()); - baseObj->putGetter(exec, *identifier, getter); + GetterSetter* accessor = GetterSetter::create(vm); + + ASSERT(!getter || getter->isObject()); + ASSERT(!setter || setter->isObject()); + ASSERT(getter || setter); + + if (getter) + accessor->setGetter(vm, getter->getObject()); + if (setter) + accessor->setSetter(vm, setter->getObject()); + baseObj->putDirectAccessor(exec, *identifier, accessor, Accessor); } +#endif -void JIT_OPERATION operationPutSetterById(ExecState* exec, JSCell* object, Identifier* identifier, JSCell* setter) +void JIT_OPERATION operationPushNameScope(ExecState* exec, Identifier* identifier, EncodedJSValue encodedValue, int32_t attibutes) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); - ASSERT(object && object->isObject()); - JSObject* baseObj = object->getObject(); + JSNameScope* scope = JSNameScope::create(exec, *identifier, JSValue::decode(encodedValue), attibutes); - ASSERT(setter->isObject()); - baseObj->putSetter(exec, *identifier, setter); + exec->setScope(scope); } -void JIT_OPERATION operationPutGetterSetter(ExecState* exec, JSCell* object, Identifier* identifier, JSCell* getter, JSCell* setter) +void JIT_OPERATION operationPushWithScope(ExecState* exec, EncodedJSValue encodedValue) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); - ASSERT(object && object->isObject()); - JSObject* baseObj = object->getObject(); - - GetterSetter* accessor = GetterSetter::create(vm, exec->lexicalGlobalObject()); - - ASSERT(!getter || getter->isObject()); - ASSERT(!setter || setter->isObject()); - ASSERT(getter || setter); + JSObject* o = JSValue::decode(encodedValue).toObject(exec); + if (vm.exception()) + return; - if (getter) - accessor->setGetter(vm, exec->lexicalGlobalObject(), getter->getObject()); - if (setter) - accessor->setSetter(vm, exec->lexicalGlobalObject(), setter->getObject()); - baseObj->putDirectAccessor(exec, *identifier, accessor, Accessor); + exec->setScope(JSWithScope::create(exec, o)); } -#endif -void JIT_OPERATION operationPopScope(ExecState* exec, int32_t scopeReg) +void JIT_OPERATION operationPopScope(ExecState* exec) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); - JSScope* scope = exec->uncheckedR(scopeReg).Register::scope(); - exec->uncheckedR(scopeReg) = scope->next(); + exec->setScope(exec->scope()->next()); } void JIT_OPERATION operationProfileDidCall(ExecState* exec, EncodedJSValue encodedValue) @@ -1369,246 +1308,141 @@ void JIT_OPERATION operationProfileWillCall(ExecState* exec, EncodedJSValue enco EncodedJSValue JIT_OPERATION operationCheckHasInstance(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBaseVal) { - VM& vm = exec->vm(); - NativeCallFrameTracer tracer(&vm, exec); + VM* vm = &exec->vm(); + NativeCallFrameTracer tracer(vm, exec); JSValue value = JSValue::decode(encodedValue); JSValue baseVal = JSValue::decode(encodedBaseVal); if (baseVal.isObject()) { JSObject* baseObject = asObject(baseVal); - ASSERT(!baseObject->structure(vm)->typeInfo().implementsDefaultHasInstance()); - if (baseObject->structure(vm)->typeInfo().implementsHasInstance()) { - bool result = baseObject->methodTable(vm)->customHasInstance(baseObject, exec, value); + ASSERT(!baseObject->structure()->typeInfo().implementsDefaultHasInstance()); + if (baseObject->structure()->typeInfo().implementsHasInstance()) { + bool result = baseObject->methodTable()->customHasInstance(baseObject, exec, value); return JSValue::encode(jsBoolean(result)); } } - vm.throwException(exec, createInvalidInstanceofParameterError(exec, baseVal)); + vm->throwException(exec, createInvalidParameterError(exec, "instanceof", baseVal)); return JSValue::encode(JSValue()); } +JSCell* JIT_OPERATION operationCreateActivation(ExecState* exec, int32_t offset) +{ + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + JSActivation* activation = JSActivation::create(vm, exec, exec->registers() + offset, exec->codeBlock()); + exec->setScope(activation); + return activation; } -static bool canAccessArgumentIndexQuickly(JSObject& object, uint32_t index) +JSCell* JIT_OPERATION operationCreateArguments(ExecState* exec) { - switch (object.structure()->typeInfo().type()) { - case DirectArgumentsType: { - DirectArguments* directArguments = jsCast<DirectArguments*>(&object); - if (directArguments->canAccessArgumentIndexQuicklyInDFG(index)) - return true; - break; - } - case ScopedArgumentsType: { - ScopedArguments* scopedArguments = jsCast<ScopedArguments*>(&object); - if (scopedArguments->canAccessArgumentIndexQuicklyInDFG(index)) - return true; - break; - } - default: - break; - } - return false; + 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); + ASSERT(!vm.exception()); + return result; } -static JSValue getByVal(ExecState* exec, JSValue baseValue, JSValue subscript, ByValInfo* byValInfo, ReturnAddressPtr returnAddress) +EncodedJSValue JIT_OPERATION operationGetArgumentsLength(ExecState* exec, int32_t argumentsRegister) +{ + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + // Here we can assume that the argumernts were created. Because otherwise the JIT code would + // have not made this call. + Identifier ident(&vm, "length"); + JSValue baseValue = exec->uncheckedR(argumentsRegister).jsValue(); + PropertySlot slot(baseValue); + return JSValue::encode(baseValue.get(exec, ident, slot)); +} + +} + +static JSValue getByVal(ExecState* exec, JSValue baseValue, JSValue subscript, ReturnAddressPtr returnAddress) { if (LIKELY(baseValue.isCell() && subscript.isString())) { - VM& vm = exec->vm(); - Structure& structure = *baseValue.asCell()->structure(vm); - if (JSCell::canUseFastGetOwnProperty(structure)) { - if (RefPtr<AtomicStringImpl> existingAtomicString = asString(subscript)->toExistingAtomicString(exec)) { - if (JSValue result = baseValue.asCell()->fastGetOwnProperty(vm, structure, existingAtomicString.get())) { - ASSERT(exec->locationAsBytecodeOffset()); - if (byValInfo->stubInfo && byValInfo->cachedId.impl() != existingAtomicString) - byValInfo->tookSlowPath = true; - return result; - } - } - } + if (JSValue result = baseValue.asCell()->fastGetOwnProperty(exec, asString(subscript)->value(exec))) + return result; } if (subscript.isUInt32()) { - ASSERT(exec->locationAsBytecodeOffset()); - byValInfo->tookSlowPath = true; - uint32_t i = subscript.asUInt32(); - if (isJSString(baseValue)) { - if (asString(baseValue)->canGetIndex(i)) { - ctiPatchCallByReturnAddress(exec->codeBlock(), returnAddress, FunctionPtr(operationGetByValString)); - return asString(baseValue)->getIndex(exec, i); - } - byValInfo->arrayProfile->setOutOfBounds(); - } else if (baseValue.isObject()) { - JSObject* object = asObject(baseValue); - if (object->canGetIndexQuickly(i)) - return object->getIndexQuickly(i); - - if (!canAccessArgumentIndexQuickly(*object, i)) - byValInfo->arrayProfile->setOutOfBounds(); + if (isJSString(baseValue) && asString(baseValue)->canGetIndex(i)) { + ctiPatchCallByReturnAddress(exec->codeBlock(), returnAddress, FunctionPtr(operationGetByValString)); + return asString(baseValue)->getIndex(exec, i); } - return baseValue.get(exec, i); } - baseValue.requireObjectCoercible(exec); - if (exec->hadException()) - return jsUndefined(); - auto property = subscript.toPropertyKey(exec); - if (exec->hadException()) - return jsUndefined(); - - ASSERT(exec->locationAsBytecodeOffset()); - if (byValInfo->stubInfo && byValInfo->cachedId != property) - byValInfo->tookSlowPath = true; + if (isName(subscript)) + return baseValue.get(exec, jsCast<NameInstance*>(subscript.asCell())->privateName()); + Identifier property(exec, subscript.toString(exec)->value(exec)); return baseValue.get(exec, property); } extern "C" { -EncodedJSValue JIT_OPERATION operationGetByValGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ByValInfo* byValInfo) +EncodedJSValue JIT_OPERATION operationGetByValGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); JSValue baseValue = JSValue::decode(encodedBase); JSValue subscript = JSValue::decode(encodedSubscript); - JSValue result = getByVal(exec, baseValue, subscript, byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS)); + JSValue result = getByVal(exec, baseValue, subscript, ReturnAddressPtr(OUR_RETURN_ADDRESS)); return JSValue::encode(result); } -EncodedJSValue JIT_OPERATION operationGetByValOptimize(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ByValInfo* byValInfo) +EncodedJSValue JIT_OPERATION operationGetByValDefault(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); JSValue baseValue = JSValue::decode(encodedBase); JSValue subscript = JSValue::decode(encodedSubscript); - + if (baseValue.isObject() && subscript.isInt32()) { // See if it's worth optimizing this at all. JSObject* object = asObject(baseValue); bool didOptimize = false; - ASSERT(exec->locationAsBytecodeOffset()); - ASSERT(!byValInfo->stubRoutine); - - if (hasOptimizableIndexing(object->structure(vm))) { + unsigned bytecodeOffset = exec->locationAsBytecodeOffset(); + ASSERT(bytecodeOffset); + ByValInfo& byValInfo = exec->codeBlock()->getByValInfo(bytecodeOffset - 1); + ASSERT(!byValInfo.stubRoutine); + + if (hasOptimizableIndexing(object->structure())) { // Attempt to optimize. - Structure* structure = object->structure(vm); - JITArrayMode arrayMode = jitArrayModeForStructure(structure); - if (arrayMode != byValInfo->arrayMode) { - // If we reached this case, we got an interesting array mode we did not expect when we compiled. - // Let's update the profile to do better next time. - CodeBlock* codeBlock = exec->codeBlock(); - ConcurrentJITLocker locker(codeBlock->m_lock); - byValInfo->arrayProfile->computeUpdatedPrediction(locker, codeBlock, structure); - - JIT::compileGetByVal(&vm, exec->codeBlock(), byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode); + JITArrayMode arrayMode = jitArrayModeForStructure(object->structure()); + if (arrayMode != byValInfo.arrayMode) { + JIT::compileGetByVal(&vm, exec->codeBlock(), &byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode); didOptimize = true; } } - + if (!didOptimize) { // If we take slow path more than 10 times without patching then make sure we // never make that mistake again. Or, if we failed to patch and we have some object // that intercepts indexed get, then don't even wait until 10 times. For cases // where we see non-index-intercepting objects, this gives 10 iterations worth of // opportunity for us to observe that the get_by_val may be polymorphic. - if (++byValInfo->slowPathCount >= 10 - || object->structure(vm)->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) { + if (++byValInfo.slowPathCount >= 10 + || object->structure()->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) { // Don't ever try to optimize. - ctiPatchCallByReturnAddress(exec->codeBlock(), ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationGetByValGeneric)); + RepatchBuffer repatchBuffer(exec->codeBlock()); + repatchBuffer.relinkCallerToFunction(ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationGetByValGeneric)); } } } - - if (baseValue.isObject() && (subscript.isSymbol() || subscript.isString())) { - const Identifier propertyName = subscript.toPropertyKey(exec); - - if (!subscript.isString() || !parseIndex(propertyName)) { - ASSERT(exec->locationAsBytecodeOffset()); - ASSERT(!byValInfo->stubRoutine); - JIT::compileGetByValWithCachedId(&vm, exec->codeBlock(), byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), propertyName); - } - - PropertySlot slot(baseValue); - bool hasResult = baseValue.getPropertySlot(exec, propertyName, slot); - return JSValue::encode(hasResult ? slot.getValue(exec, propertyName) : jsUndefined()); - } - - JSValue result = getByVal(exec, baseValue, subscript, byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS)); - return JSValue::encode(result); -} - -EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ByValInfo* byValInfo) -{ - VM& vm = exec->vm(); - NativeCallFrameTracer tracer(&vm, exec); - JSValue baseValue = JSValue::decode(encodedBase); - JSValue subscript = JSValue::decode(encodedSubscript); - - ASSERT(baseValue.isObject()); - ASSERT(subscript.isUInt32()); - - JSObject* object = asObject(baseValue); - bool didOptimize = false; - - ASSERT(exec->locationAsBytecodeOffset()); - ASSERT(!byValInfo->stubRoutine); - - if (hasOptimizableIndexing(object->structure(vm))) { - // Attempt to optimize. - JITArrayMode arrayMode = jitArrayModeForStructure(object->structure(vm)); - if (arrayMode != byValInfo->arrayMode) { - JIT::compileHasIndexedProperty(&vm, exec->codeBlock(), byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode); - didOptimize = true; - } - } - - if (!didOptimize) { - // If we take slow path more than 10 times without patching then make sure we - // never make that mistake again. Or, if we failed to patch and we have some object - // that intercepts indexed get, then don't even wait until 10 times. For cases - // where we see non-index-intercepting objects, this gives 10 iterations worth of - // opportunity for us to observe that the get_by_val may be polymorphic. - if (++byValInfo->slowPathCount >= 10 - || object->structure(vm)->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) { - // Don't ever try to optimize. - ctiPatchCallByReturnAddress(exec->codeBlock(), ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationHasIndexedPropertyGeneric)); - } - } - - uint32_t index = subscript.asUInt32(); - if (object->canGetIndexQuickly(index)) - return JSValue::encode(JSValue(JSValue::JSTrue)); - - if (!canAccessArgumentIndexQuickly(*object, index)) - byValInfo->arrayProfile->setOutOfBounds(); - return JSValue::encode(jsBoolean(object->hasProperty(exec, index))); -} - -EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ByValInfo* byValInfo) -{ - VM& vm = exec->vm(); - NativeCallFrameTracer tracer(&vm, exec); - JSValue baseValue = JSValue::decode(encodedBase); - JSValue subscript = JSValue::decode(encodedSubscript); - ASSERT(baseValue.isObject()); - ASSERT(subscript.isUInt32()); - - JSObject* object = asObject(baseValue); - uint32_t index = subscript.asUInt32(); - if (object->canGetIndexQuickly(index)) - return JSValue::encode(JSValue(JSValue::JSTrue)); - - if (!canAccessArgumentIndexQuickly(*object, index)) - byValInfo->arrayProfile->setOutOfBounds(); - return JSValue::encode(jsBoolean(object->hasProperty(exec, subscript.asUInt32()))); + JSValue result = getByVal(exec, baseValue, subscript, ReturnAddressPtr(OUR_RETURN_ADDRESS)); + return JSValue::encode(result); } -EncodedJSValue JIT_OPERATION operationGetByValString(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ByValInfo* byValInfo) +EncodedJSValue JIT_OPERATION operationGetByValString(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); @@ -1622,23 +1456,37 @@ EncodedJSValue JIT_OPERATION operationGetByValString(ExecState* exec, EncodedJSV result = asString(baseValue)->getIndex(exec, i); else { result = baseValue.get(exec, i); - if (!isJSString(baseValue)) { - ASSERT(exec->locationAsBytecodeOffset()); - ctiPatchCallByReturnAddress(exec->codeBlock(), ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(byValInfo->stubRoutine ? operationGetByValGeneric : operationGetByValOptimize)); - } + if (!isJSString(baseValue)) + ctiPatchCallByReturnAddress(exec->codeBlock(), ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationGetByValDefault)); } - } else { - baseValue.requireObjectCoercible(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - auto property = subscript.toPropertyKey(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); + } else if (isName(subscript)) + result = baseValue.get(exec, jsCast<NameInstance*>(subscript.asCell())->privateName()); + else { + Identifier property(exec, subscript.toString(exec)->value(exec)); result = baseValue.get(exec, property); } return JSValue::encode(result); } + +void JIT_OPERATION operationTearOffActivation(ExecState* exec, JSCell* activationCell) +{ + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + + ASSERT(exec->codeBlock()->needsFullScopeChain()); + jsCast<JSActivation*>(activationCell)->tearOff(vm); +} + +void JIT_OPERATION operationTearOffArguments(ExecState* exec, JSCell* argumentsCell, JSCell* activationCell) +{ + ASSERT(exec->codeBlock()->usesArguments()); + if (activationCell) { + jsCast<Arguments*>(argumentsCell)->didTearOffActivation(exec, jsCast<JSActivation*>(activationCell)); + return; + } + jsCast<Arguments*>(argumentsCell)->tearOff(exec); +} EncodedJSValue JIT_OPERATION operationDeleteById(ExecState* exec, EncodedJSValue encodedBase, const Identifier* identifier) { @@ -1646,13 +1494,25 @@ EncodedJSValue JIT_OPERATION operationDeleteById(ExecState* exec, EncodedJSValue NativeCallFrameTracer tracer(&vm, exec); JSObject* baseObj = JSValue::decode(encodedBase).toObject(exec); - bool couldDelete = baseObj->methodTable(vm)->deleteProperty(baseObj, exec, *identifier); + bool couldDelete = baseObj->methodTable()->deleteProperty(baseObj, exec, *identifier); JSValue result = jsBoolean(couldDelete); if (!couldDelete && exec->codeBlock()->isStrictMode()) - vm.throwException(exec, createTypeError(exec, ASCIILiteral("Unable to delete property."))); + vm.throwException(exec, createTypeError(exec, "Unable to delete property.")); return JSValue::encode(result); } +JSCell* JIT_OPERATION operationGetPNames(ExecState* exec, JSObject* obj) +{ + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + + Structure* structure = obj->structure(); + JSPropertyNameIterator* jsPropertyNameIterator = structure->enumerationCache(); + if (!jsPropertyNameIterator || jsPropertyNameIterator->cachedPrototypeChain() != structure->prototypeChain(exec)) + jsPropertyNameIterator = JSPropertyNameIterator::create(exec, obj); + return jsPropertyNameIterator; +} + EncodedJSValue JIT_OPERATION operationInstanceOf(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedProto) { VM& vm = exec->vm(); @@ -1666,21 +1526,23 @@ EncodedJSValue JIT_OPERATION operationInstanceOf(ExecState* exec, EncodedJSValue return JSValue::encode(jsBoolean(result)); } -int32_t JIT_OPERATION operationSizeFrameForVarargs(ExecState* exec, EncodedJSValue encodedArguments, int32_t numUsedStackSlots, int32_t firstVarArgOffset) +CallFrame* JIT_OPERATION operationSizeAndAllocFrameForVarargs(ExecState* exec, EncodedJSValue encodedArguments, int32_t firstFreeRegister) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); JSStack* stack = &exec->interpreter()->stack(); JSValue arguments = JSValue::decode(encodedArguments); - return sizeFrameForVarargs(exec, stack, arguments, numUsedStackSlots, firstVarArgOffset); + CallFrame* newCallFrame = sizeAndAllocFrameForVarargs(exec, stack, arguments, firstFreeRegister); + return newCallFrame; } -CallFrame* JIT_OPERATION operationSetupVarargsFrame(ExecState* exec, CallFrame* newCallFrame, EncodedJSValue encodedArguments, int32_t firstVarArgOffset, int32_t length) +CallFrame* JIT_OPERATION operationLoadVarargs(ExecState* exec, CallFrame* newCallFrame, EncodedJSValue encodedThis, EncodedJSValue encodedArguments) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); + JSValue thisValue = JSValue::decode(encodedThis); JSValue arguments = JSValue::decode(encodedArguments); - setupVarargsFrame(exec, newCallFrame, arguments, firstVarArgOffset, length); + loadVarargs(exec, newCallFrame, thisValue, arguments); return newCallFrame; } @@ -1747,13 +1609,12 @@ char* JIT_OPERATION operationSwitchStringWithUnknownKeyType(ExecState* exec, Enc return reinterpret_cast<char*>(result); } -EncodedJSValue JIT_OPERATION operationResolveScope(ExecState* exec, int32_t scopeReg, int32_t identifierIndex) +EncodedJSValue JIT_OPERATION operationResolveScope(ExecState* exec, int32_t identifierIndex) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); const Identifier& ident = exec->codeBlock()->identifier(identifierIndex); - JSScope* scope = exec->uncheckedR(scopeReg).Register::scope(); - return JSValue::encode(JSScope::resolve(exec, scope, ident)); + return JSValue::encode(JSScope::resolve(exec, exec->scope(), ident)); } EncodedJSValue JIT_OPERATION operationGetFromScope(ExecState* exec, Instruction* bytecodePC) @@ -1775,15 +1636,11 @@ EncodedJSValue JIT_OPERATION operationGetFromScope(ExecState* exec, Instruction* } // Covers implicit globals. Since they don't exist until they first execute, we didn't know how to cache them at compile time. - if (slot.isCacheableValue() && slot.slotBase() == scope && scope->structure(vm)->propertyAccessesAreCacheable()) { + if (slot.isCacheableValue() && slot.slotBase() == scope && scope->structure()->propertyAccessesAreCacheable()) { if (modeAndType.type() == GlobalProperty || modeAndType.type() == GlobalPropertyWithVarInjectionChecks) { - Structure* structure = scope->structure(vm); - { - ConcurrentJITLocker locker(codeBlock->m_lock); - pc[5].u.structure.set(exec->vm(), codeBlock->ownerExecutable(), structure); - pc[6].u.operand = slot.cachedOffset(); - } - structure->startWatchingPropertyForReplacements(vm, slot.cachedOffset()); + ConcurrentJITLocker locker(codeBlock->m_lock); + pc[5].u.structure.set(exec->vm(), codeBlock->ownerExecutable(), scope->structure()); + pc[6].u.operand = slot.cachedOffset(); } } @@ -1801,13 +1658,7 @@ void JIT_OPERATION operationPutToScope(ExecState* exec, Instruction* bytecodePC) JSObject* scope = jsCast<JSObject*>(exec->uncheckedR(pc[1].u.operand).jsValue()); JSValue value = exec->r(pc[3].u.operand).jsValue(); ResolveModeAndType modeAndType = ResolveModeAndType(pc[4].u.operand); - if (modeAndType.type() == LocalClosureVar) { - JSLexicalEnvironment* environment = jsCast<JSLexicalEnvironment*>(scope); - environment->variableAt(ScopeOffset(pc[6].u.operand)).set(vm, environment, value); - if (WatchpointSet* set = pc[5].u.watchpointSet) - set->touch("Executed op_put_scope<LocalClosureVar>"); - return; - } + if (modeAndType.mode() == ThrowIfNotFound && !scope->hasProperty(exec, ident)) { exec->vm().throwException(exec, createUndefinedVariableError(exec, ident)); return; @@ -1819,7 +1670,14 @@ void JIT_OPERATION operationPutToScope(ExecState* exec, Instruction* bytecodePC) if (exec->vm().exception()) return; - CommonSlowPaths::tryCachePutToScopeGlobal(exec, codeBlock, pc, scope, modeAndType, slot); + // Covers implicit globals. Since they don't exist until they first execute, we didn't know how to cache them at compile time. + if (modeAndType.type() == GlobalProperty || modeAndType.type() == GlobalPropertyWithVarInjectionChecks) { + if (slot.isCacheable() && slot.base() == scope && scope->structure()->propertyAccessesAreCacheable()) { + ConcurrentJITLocker locker(codeBlock->m_lock); + pc[5].u.structure.set(exec->vm(), codeBlock->ownerExecutable(), scope->structure()); + pc[6].u.operand = slot.cachedOffset(); + } + } } void JIT_OPERATION operationThrow(ExecState* exec, EncodedJSValue encodedExceptionValue) @@ -1830,8 +1688,8 @@ void JIT_OPERATION operationThrow(ExecState* exec, EncodedJSValue encodedExcepti JSValue exceptionValue = JSValue::decode(encodedExceptionValue); vm->throwException(exec, exceptionValue); - // Results stored out-of-band in vm.targetMachinePCForThrow, vm.callFrameForThrow & vm.vmEntryFrameForThrow - genericUnwind(vm, exec); + // Results stored out-of-band in vm.targetMachinePCForThrow & vm.callFrameForThrow + genericUnwind(vm, exec, exceptionValue); } void JIT_OPERATION operationFlushWriteBarrierBuffer(ExecState* exec, JSCell* cell) @@ -1845,7 +1703,7 @@ void JIT_OPERATION operationOSRWriteBarrier(ExecState* exec, JSCell* cell) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - vm->heap.writeBarrier(cell); + exec->heap()->writeBarrier(cell); } // NB: We don't include the value as part of the barrier because the write barrier elision @@ -1855,7 +1713,7 @@ void JIT_OPERATION operationUnconditionalWriteBarrier(ExecState* exec, JSCell* c { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - vm->heap.writeBarrier(cell); + Heap::writeBarrier(cell); } void JIT_OPERATION operationInitGlobalConst(ExecState* exec, Instruction* pc) @@ -1864,24 +1722,18 @@ void JIT_OPERATION operationInitGlobalConst(ExecState* exec, Instruction* pc) NativeCallFrameTracer tracer(vm, exec); JSValue value = exec->r(pc[2].u.operand).jsValue(); - pc[1].u.variablePointer->set(*vm, exec->codeBlock()->globalObject(), value); + pc[1].u.registerPointer->set(*vm, exec->codeBlock()->globalObject(), value); } -void JIT_OPERATION lookupExceptionHandler(VM* vm, ExecState* exec) +void JIT_OPERATION lookupExceptionHandler(ExecState* exec) { + VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - genericUnwind(vm, exec); - ASSERT(vm->targetMachinePCForThrow); -} -void JIT_OPERATION lookupExceptionHandlerFromCallerFrame(VM* vm, ExecState* exec) -{ - VMEntryFrame* vmEntryFrame = vm->topVMEntryFrame; - CallFrame* callerFrame = exec->callerFrame(vmEntryFrame); - ASSERT(callerFrame); - - NativeCallFrameTracerWithRestore tracer(vm, vmEntryFrame, callerFrame); - genericUnwind(vm, callerFrame); + JSValue exceptionValue = exec->exception(); + ASSERT(exceptionValue); + + genericUnwind(vm, exec, exceptionValue); ASSERT(vm->targetMachinePCForThrow); } @@ -1889,72 +1741,9 @@ void JIT_OPERATION operationVMHandleException(ExecState* exec) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - genericUnwind(vm, exec); -} - -// This function "should" just take the ExecState*, but doing so would make it more difficult -// to call from exception check sites. So, unlike all of our other functions, we allow -// ourselves to play some gnarly ABI tricks just to simplify the calling convention. This is -// particularly safe here since this is never called on the critical path - it's only for -// testing. -void JIT_OPERATION operationExceptionFuzz() -{ -#if COMPILER(GCC_OR_CLANG) - ExecState* exec = static_cast<ExecState*>(__builtin_frame_address(1)); - void* returnPC = __builtin_return_address(0); - doExceptionFuzzing(exec, "JITOperations", returnPC); -#endif // COMPILER(GCC_OR_CLANG) -} - -EncodedJSValue JIT_OPERATION operationHasGenericProperty(ExecState* exec, EncodedJSValue encodedBaseValue, JSCell* propertyName) -{ - VM& vm = exec->vm(); - NativeCallFrameTracer tracer(&vm, exec); - JSValue baseValue = JSValue::decode(encodedBaseValue); - if (baseValue.isUndefinedOrNull()) - return JSValue::encode(jsBoolean(false)); - - JSObject* base = baseValue.toObject(exec); - return JSValue::encode(jsBoolean(base->hasProperty(exec, asString(propertyName)->toIdentifier(exec)))); -} - -EncodedJSValue JIT_OPERATION operationHasIndexedProperty(ExecState* exec, JSCell* baseCell, int32_t subscript) -{ - VM& vm = exec->vm(); - NativeCallFrameTracer tracer(&vm, exec); - JSObject* object = baseCell->toObject(exec, exec->lexicalGlobalObject()); - return JSValue::encode(jsBoolean(object->hasProperty(exec, subscript))); -} - -JSCell* JIT_OPERATION operationGetPropertyEnumerator(ExecState* exec, JSCell* cell) -{ - VM& vm = exec->vm(); - NativeCallFrameTracer tracer(&vm, exec); - - JSObject* base = cell->toObject(exec, exec->lexicalGlobalObject()); - return propertyNameEnumerator(exec, base); -} - -EncodedJSValue JIT_OPERATION operationNextEnumeratorPname(ExecState* exec, JSCell* enumeratorCell, int32_t index) -{ - VM& vm = exec->vm(); - NativeCallFrameTracer tracer(&vm, exec); - JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(enumeratorCell); - JSString* propertyName = enumerator->propertyNameAtIndex(index); - return JSValue::encode(propertyName ? propertyName : jsNull()); -} - -JSCell* JIT_OPERATION operationToIndexString(ExecState* exec, int32_t index) -{ - VM& vm = exec->vm(); - NativeCallFrameTracer tracer(&vm, exec); - return jsString(exec, Identifier::from(exec, index).string()); -} - -void JIT_OPERATION operationProcessTypeProfilerLog(ExecState* exec) -{ - exec->vm().typeProfilerLog()->processLogEntries(ASCIILiteral("Log Full, called from inside baseline JIT")); + ASSERT(!exec->isVMEntrySentinel()); + genericUnwind(vm, exec, vm->exception()); } } // extern "C" @@ -1969,31 +1758,28 @@ extern "C" EncodedJSValue HOST_CALL_RETURN_VALUE_OPTION getHostCallReturnValueWi return JSValue::encode(exec->vm().hostCallReturnValue); } -#if COMPILER(GCC_OR_CLANG) && CPU(X86_64) +#if COMPILER(GCC) && CPU(X86_64) asm ( ".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" HIDE_SYMBOL(getHostCallReturnValue) "\n" SYMBOL_STRING(getHostCallReturnValue) ":" "\n" + "mov 0(%rbp), %rbp\n" // CallerFrameAndPC::callerFrame "mov %rbp, %rdi\n" "jmp " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" ); -#elif COMPILER(GCC_OR_CLANG) && CPU(X86) +#elif COMPILER(GCC) && CPU(X86) asm ( ".text" "\n" \ ".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" HIDE_SYMBOL(getHostCallReturnValue) "\n" SYMBOL_STRING(getHostCallReturnValue) ":" "\n" - "push %ebp\n" - "leal -4(%esp), %esp\n" - "push %ebp\n" - "call " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" - "leal 8(%esp), %esp\n" - "pop %ebp\n" - "ret\n" + "mov 0(%ebp), %ebp\n" // CallerFrameAndPC::callerFrame + "mov %ebp, 4(%esp)\n" + "jmp " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" ); -#elif COMPILER(GCC_OR_CLANG) && CPU(ARM_THUMB2) +#elif COMPILER(GCC) && CPU(ARM_THUMB2) asm ( ".text" "\n" ".align 2" "\n" @@ -2002,17 +1788,19 @@ HIDE_SYMBOL(getHostCallReturnValue) "\n" ".thumb" "\n" ".thumb_func " THUMB_FUNC_PARAM(getHostCallReturnValue) "\n" SYMBOL_STRING(getHostCallReturnValue) ":" "\n" + "ldr r7, [r7, #0]" "\n" // CallerFrameAndPC::callerFrame "mov r0, r7" "\n" "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" ); -#elif COMPILER(GCC_OR_CLANG) && CPU(ARM_TRADITIONAL) +#elif COMPILER(GCC) && CPU(ARM_TRADITIONAL) asm ( ".text" "\n" ".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" HIDE_SYMBOL(getHostCallReturnValue) "\n" INLINE_ARM_FUNCTION(getHostCallReturnValue) SYMBOL_STRING(getHostCallReturnValue) ":" "\n" + "ldr r11, [r11, #0]" "\n" // CallerFrameAndPC::callerFrame "mov r0, r11" "\n" "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" ); @@ -2024,41 +1812,30 @@ asm ( ".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" HIDE_SYMBOL(getHostCallReturnValue) "\n" SYMBOL_STRING(getHostCallReturnValue) ":" "\n" + "ldur x29, [x29, #0]" "\n" "mov x0, x29" "\n" "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" ); -#elif COMPILER(GCC_OR_CLANG) && CPU(MIPS) - -#if WTF_MIPS_PIC -#define LOAD_FUNCTION_TO_T9(function) \ - ".set noreorder" "\n" \ - ".cpload $25" "\n" \ - ".set reorder" "\n" \ - "la $t9, " LOCAL_REFERENCE(function) "\n" -#else -#define LOAD_FUNCTION_TO_T9(function) "" "\n" -#endif - +#elif COMPILER(GCC) && CPU(MIPS) asm ( ".text" "\n" ".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" HIDE_SYMBOL(getHostCallReturnValue) "\n" SYMBOL_STRING(getHostCallReturnValue) ":" "\n" LOAD_FUNCTION_TO_T9(getHostCallReturnValueWithExecState) + "lw $fp, 0($fp)" "\n" // CallerFrameAndPC::callerFrame "move $a0, $fp" "\n" "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" ); -#elif COMPILER(GCC_OR_CLANG) && CPU(SH4) - -#define SH4_SCRATCH_REGISTER "r11" - +#elif COMPILER(GCC) && CPU(SH4) asm ( ".text" "\n" ".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" HIDE_SYMBOL(getHostCallReturnValue) "\n" SYMBOL_STRING(getHostCallReturnValue) ":" "\n" + "mov.l @r14, r14" "\n" // CallerFrameAndPC::callerFrame "mov r14, r4" "\n" "mov.l 2f, " SH4_SCRATCH_REGISTER "\n" "braf " SH4_SCRATCH_REGISTER "\n" @@ -2071,6 +1848,7 @@ SYMBOL_STRING(getHostCallReturnValue) ":" "\n" extern "C" { __declspec(naked) EncodedJSValue HOST_CALL_RETURN_VALUE_OPTION getHostCallReturnValue() { + __asm mov ebp, [ebp + 0]; // CallerFrameAndPC::callerFrame __asm mov [esp + 4], ebp; __asm jmp getHostCallReturnValueWithExecState } |