X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/81345200c95645a1b0d2635520f96ad55dfde63f..ed1e77d3adeb83d26fd1dfb16dd84cabdcefd250:/jit/JITOperations.cpp?ds=inline diff --git a/jit/JITOperations.cpp b/jit/JITOperations.cpp index 3aaef52..38015d2 100644 --- a/jit/JITOperations.cpp +++ b/jit/JITOperations.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 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 @@ -28,7 +28,6 @@ #if ENABLE(JIT) -#include "Arguments.h" #include "ArrayConstructor.h" #include "DFGCompilationMode.h" #include "DFGDriver.h" @@ -36,28 +35,52 @@ #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 "JITToDFGDeferredCompilationCallback.h" +#include "JSCInlines.h" +#include "JSCatchScope.h" +#include "JSFunctionNameScope.h" #include "JSGlobalObjectFunctions.h" +#include "JSLexicalEnvironment.h" #include "JSNameScope.h" -#include "JSPropertyNameIterator.h" +#include "JSPropertyNameEnumerator.h" #include "JSStackInlines.h" #include "JSWithScope.h" +#include "LegacyProfiler.h" #include "ObjectConstructor.h" -#include "JSCInlines.h" +#include "PropertyName.h" #include "Repatch.h" #include "RepatchBuffer.h" +#include "ScopedArguments.h" #include "TestRunnerUtils.h" +#include "TypeProfilerLog.h" #include namespace JSC { -static unsigned s_numberOfExceptionFuzzChecks; -unsigned numberOfExceptionFuzzChecks() { return s_numberOfExceptionFuzzChecks; } +template +void pushNameScope(ExecState* exec, int32_t dst, SymbolTable* symbolTable, EncodedJSValue encodedValue) +{ + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + + ASSERT(!JITCode::isOptimizingJIT(exec->codeBlock()->jitType())); + + // FIXME: This won't work if this operation is called from the DFG or FTL. + // This should be changed to pass in the new scope. + JSScope* currentScope = exec->uncheckedR(dst).Register::scope(); + JSNameScope* scope = ScopeType::create(vm, exec->lexicalGlobalObject(), currentScope, symbolTable, JSValue::decode(encodedValue)); + + // FIXME: This won't work if this operation is called from the DFG or FTL. + // This should be changed to return the new scope. + exec->uncheckedR(dst) = scope; +} extern "C" { @@ -81,11 +104,13 @@ void JIT_OPERATION operationThrowStackOverflowError(ExecState* exec, CodeBlock* { // We pass in our own code block, because the callframe hasn't been populated. VM* vm = codeBlock->vm(); - CallFrame* callerFrame = exec->callerFrameSkippingVMEntrySentinel(); + + VMEntryFrame* vmEntryFrame = vm->topVMEntryFrame; + CallFrame* callerFrame = exec->callerFrame(vmEntryFrame); if (!callerFrame) callerFrame = exec; - NativeCallFrameTracer tracer(vm, callerFrame); + NativeCallFrameTracerWithRestore tracer(vm, vmEntryFrame, callerFrame); ErrorHandlingScope errorScope(*vm); vm->throwException(callerFrame, createStackOverflowError(callerFrame)); } @@ -93,14 +118,16 @@ void JIT_OPERATION operationThrowStackOverflowError(ExecState* exec, CodeBlock* int32_t JIT_OPERATION operationCallArityCheck(ExecState* exec) { VM* vm = &exec->vm(); - CallFrame* callerFrame = exec->callerFrameSkippingVMEntrySentinel(); - NativeCallFrameTracer tracer(vm, callerFrame); + VMEntryFrame* vmEntryFrame = vm->topVMEntryFrame; + CallFrame* callerFrame = exec->callerFrame(vmEntryFrame); JSStack& stack = vm->interpreter->stack(); int32_t missingArgCount = CommonSlowPaths::arityCheckFor(exec, &stack, CodeForCall); - if (missingArgCount < 0) + if (missingArgCount < 0) { + NativeCallFrameTracerWithRestore tracer(vm, vmEntryFrame, callerFrame); throwStackOverflowError(callerFrame); + } return missingArgCount; } @@ -108,81 +135,94 @@ int32_t JIT_OPERATION operationCallArityCheck(ExecState* exec) int32_t JIT_OPERATION operationConstructArityCheck(ExecState* exec) { VM* vm = &exec->vm(); - CallFrame* callerFrame = exec->callerFrameSkippingVMEntrySentinel(); - NativeCallFrameTracer tracer(vm, callerFrame); + VMEntryFrame* vmEntryFrame = vm->topVMEntryFrame; + CallFrame* callerFrame = exec->callerFrame(vmEntryFrame); JSStack& stack = vm->interpreter->stack(); int32_t missingArgCount = CommonSlowPaths::arityCheckFor(exec, &stack, CodeForConstruct); - if (missingArgCount < 0) + if (missingArgCount < 0) { + NativeCallFrameTracerWithRestore tracer(vm, vmEntryFrame, callerFrame); throwStackOverflowError(callerFrame); + } return missingArgCount; } -EncodedJSValue JIT_OPERATION operationGetById(ExecState* exec, StructureStubInfo*, EncodedJSValue base, StringImpl* uid) +EncodedJSValue JIT_OPERATION operationGetById(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* 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); + 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(vm, uid); + Identifier ident = Identifier::fromUid(vm, uid); return JSValue::encode(baseValue.get(exec, ident, slot)); } -EncodedJSValue JIT_OPERATION operationGetByIdBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, StringImpl* uid) +EncodedJSValue JIT_OPERATION operationGetByIdBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - Identifier ident(vm, uid); + Identifier ident = Identifier::fromUid(vm, uid); AccessType accessType = static_cast(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 (accessType == static_cast(stubInfo->accessType)) buildGetByIDList(exec, baseValue, ident, slot, *stubInfo); - return JSValue::encode(result); + return JSValue::encode(hasResult? slot.getValue(exec, ident) : jsUndefined()); } -EncodedJSValue JIT_OPERATION operationGetByIdOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, StringImpl* uid) +EncodedJSValue JIT_OPERATION operationGetByIdOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - Identifier ident = uid->isEmptyUnique() ? Identifier::from(PrivateName(uid)) : Identifier(vm, uid); - AccessType accessType = static_cast(stubInfo->accessType); + Identifier ident = Identifier::fromUid(vm, uid); JSValue baseValue = JSValue::decode(base); PropertySlot slot(baseValue); - JSValue result = baseValue.get(exec, ident, slot); - if (accessType == static_cast(stubInfo->accessType)) { - if (stubInfo->seen) - repatchGetByID(exec, baseValue, ident, slot, *stubInfo); - else - stubInfo->seen = true; - } + 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()); - return JSValue::encode(result); } -EncodedJSValue JIT_OPERATION operationInOptimize(ExecState* exec, StructureStubInfo* stubInfo, JSCell* base, StringImpl* key) +EncodedJSValue JIT_OPERATION operationInOptimize(ExecState* exec, StructureStubInfo* stubInfo, JSCell* base, UniquedStringImpl* key) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); if (!base->isObject()) { - vm->throwException(exec, createInvalidParameterError(exec, "in", base)); + vm->throwException(exec, createInvalidInParameterError(exec, base)); return JSValue::encode(jsUndefined()); } AccessType accessType = static_cast(stubInfo->accessType); - Identifier ident(vm, key); + Identifier ident = Identifier::fromUid(vm, key); PropertySlot slot(base); bool result = asObject(base)->getPropertySlot(exec, ident, slot); @@ -196,17 +236,19 @@ EncodedJSValue JIT_OPERATION operationInOptimize(ExecState* exec, StructureStubI return JSValue::encode(jsBoolean(result)); } -EncodedJSValue JIT_OPERATION operationIn(ExecState* exec, StructureStubInfo*, JSCell* base, StringImpl* key) +EncodedJSValue JIT_OPERATION operationIn(ExecState* exec, StructureStubInfo* stubInfo, JSCell* base, UniquedStringImpl* key) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); + + stubInfo->tookSlowPath = true; if (!base->isObject()) { - vm->throwException(exec, createInvalidParameterError(exec, "in", base)); + vm->throwException(exec, createInvalidInParameterError(exec, base)); return JSValue::encode(jsUndefined()); } - Identifier ident(vm, key); + Identifier ident = Identifier::fromUid(vm, key); return JSValue::encode(jsBoolean(asObject(base)->hasProperty(exec, ident))); } @@ -218,216 +260,232 @@ 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*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) +void JIT_OPERATION operationPutByIdStrict(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - Identifier ident(vm, uid); + stubInfo->tookSlowPath = true; + + Identifier ident = Identifier::fromUid(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*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) +void JIT_OPERATION operationPutByIdNonStrict(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - Identifier ident(vm, uid); + stubInfo->tookSlowPath = true; + + Identifier ident = Identifier::fromUid(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*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) +void JIT_OPERATION operationPutByIdDirectStrict(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - Identifier ident(vm, uid); + stubInfo->tookSlowPath = true; + + Identifier ident = Identifier::fromUid(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*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) +void JIT_OPERATION operationPutByIdDirectNonStrict(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - Identifier ident(vm, uid); + stubInfo->tookSlowPath = true; + + Identifier ident = Identifier::fromUid(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, StringImpl* uid) +void JIT_OPERATION operationPutByIdStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - Identifier ident(vm, uid); + Identifier ident = Identifier::fromUid(vm, uid); AccessType accessType = static_cast(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(stubInfo->accessType)) return; if (stubInfo->seen) - repatchPutByID(exec, baseValue, ident, slot, *stubInfo, NotDirect); + repatchPutByID(exec, baseValue, structure, ident, slot, *stubInfo, NotDirect); else stubInfo->seen = true; } -void JIT_OPERATION operationPutByIdNonStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) +void JIT_OPERATION operationPutByIdNonStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - Identifier ident(vm, uid); + Identifier ident = Identifier::fromUid(vm, uid); AccessType accessType = static_cast(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(stubInfo->accessType)) return; if (stubInfo->seen) - repatchPutByID(exec, baseValue, ident, slot, *stubInfo, NotDirect); + repatchPutByID(exec, baseValue, structure, ident, slot, *stubInfo, NotDirect); else stubInfo->seen = true; } -void JIT_OPERATION operationPutByIdDirectStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) +void JIT_OPERATION operationPutByIdDirectStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - Identifier ident(vm, uid); + Identifier ident = Identifier::fromUid(vm, uid); AccessType accessType = static_cast(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(stubInfo->accessType)) return; if (stubInfo->seen) - repatchPutByID(exec, baseObject, ident, slot, *stubInfo, Direct); + repatchPutByID(exec, baseObject, structure, ident, slot, *stubInfo, Direct); else stubInfo->seen = true; } -void JIT_OPERATION operationPutByIdDirectNonStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) +void JIT_OPERATION operationPutByIdDirectNonStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - Identifier ident(vm, uid); + Identifier ident = Identifier::fromUid(vm, uid); AccessType accessType = static_cast(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(stubInfo->accessType)) return; if (stubInfo->seen) - repatchPutByID(exec, baseObject, ident, slot, *stubInfo, Direct); + repatchPutByID(exec, baseObject, structure, ident, slot, *stubInfo, Direct); else stubInfo->seen = true; } -void JIT_OPERATION operationPutByIdStrictBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) +void JIT_OPERATION operationPutByIdStrictBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - Identifier ident(vm, uid); + Identifier ident = Identifier::fromUid(vm, uid); AccessType accessType = static_cast(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(stubInfo->accessType)) return; - - buildPutByIdList(exec, baseValue, ident, slot, *stubInfo, NotDirect); + + buildPutByIdList(exec, baseValue, structure, ident, slot, *stubInfo, NotDirect); } -void JIT_OPERATION operationPutByIdNonStrictBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) +void JIT_OPERATION operationPutByIdNonStrictBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - Identifier ident(vm, uid); + Identifier ident = Identifier::fromUid(vm, uid); AccessType accessType = static_cast(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(stubInfo->accessType)) return; - buildPutByIdList(exec, baseValue, ident, slot, *stubInfo, NotDirect); + buildPutByIdList(exec, baseValue, structure, ident, slot, *stubInfo, NotDirect); } -void JIT_OPERATION operationPutByIdDirectStrictBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) +void JIT_OPERATION operationPutByIdDirectStrictBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - Identifier ident(vm, uid); + Identifier ident = Identifier::fromUid(vm, uid); AccessType accessType = static_cast(stubInfo->accessType); JSValue value = JSValue::decode(encodedValue); JSObject* baseObject = asObject(JSValue::decode(encodedBase)); PutPropertySlot slot(baseObject, true, exec->codeBlock()->putByIdContext()); - - baseObject->putDirect(exec->vm(), ident, value, slot); + + Structure* structure = baseObject->structure(*vm); + baseObject->putDirect(*vm, ident, value, slot); if (accessType != static_cast(stubInfo->accessType)) return; - buildPutByIdList(exec, baseObject, ident, slot, *stubInfo, Direct); + buildPutByIdList(exec, baseObject, structure, ident, slot, *stubInfo, Direct); } -void JIT_OPERATION operationPutByIdDirectNonStrictBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) +void JIT_OPERATION operationPutByIdDirectNonStrictBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - Identifier ident(vm, uid); + Identifier ident = Identifier::fromUid(vm, uid); AccessType accessType = static_cast(stubInfo->accessType); JSValue value = JSValue::decode(encodedValue); JSObject* baseObject = asObject(JSValue::decode(encodedBase)); PutPropertySlot slot(baseObject, false, exec->codeBlock()->putByIdContext()); - - baseObject ->putDirect(exec->vm(), ident, value, slot); - + + Structure* structure = baseObject->structure(*vm); + baseObject->putDirect(*vm, ident, value, slot); + if (accessType != static_cast(stubInfo->accessType)) return; - buildPutByIdList(exec, baseObject, ident, slot, *stubInfo, Direct); + buildPutByIdList(exec, baseObject, structure, ident, slot, *stubInfo, Direct); } void JIT_OPERATION operationReallocateStorageAndFinishPut(ExecState* exec, JSObject* base, Structure* structure, PropertyOffset offset, EncodedJSValue value) @@ -441,7 +499,7 @@ void JIT_OPERATION operationReallocateStorageAndFinishPut(ExecState* exec, JSObj base->putDirect(vm, offset, JSValue::decode(value)); } -static void putByVal(CallFrame* callFrame, JSValue baseValue, JSValue subscript, JSValue value) +static void putByVal(CallFrame* callFrame, JSValue baseValue, JSValue subscript, JSValue value, ArrayProfile* arrayProfile) { VM& vm = callFrame->vm(); if (LIKELY(subscript.isUInt32())) { @@ -450,15 +508,14 @@ static void putByVal(CallFrame* callFrame, JSValue baseValue, JSValue subscript, JSObject* object = asObject(baseValue); if (object->canSetIndexQuickly(i)) object->setIndexQuickly(callFrame->vm(), i, value); - else + else { + arrayProfile->setOutOfBounds(); object->methodTable(vm)->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(subscript.asCell())->privateName(), value, slot); } else { - Identifier property = subscript.toString(callFrame)->toIdentifier(callFrame); + auto property = subscript.toPropertyKey(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); @@ -466,23 +523,45 @@ static void putByVal(CallFrame* callFrame, JSValue baseValue, JSValue subscript, } } -static void directPutByVal(CallFrame* callFrame, JSObject* baseObject, JSValue subscript, JSValue value) +static void directPutByVal(CallFrame* callFrame, JSObject* baseObject, JSValue subscript, JSValue value, ArrayProfile* arrayProfile) { + bool isStrictMode = callFrame->codeBlock()->isStrictMode(); if (LIKELY(subscript.isUInt32())) { - 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(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); + // 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; + } + + arrayProfile->setOutOfBounds(); + baseObject->putDirectIndex(callFrame, index, value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow); + return; + } + + if (subscript.isDouble()) { + double subscriptAsDouble = subscript.asDouble(); + uint32_t subscriptAsUInt32 = static_cast(subscriptAsDouble); + if (subscriptAsDouble == subscriptAsUInt32 && isIndex(subscriptAsUInt32)) { + baseObject->putDirectIndex(callFrame, subscriptAsUInt32, value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow); + return; } } + + // Don't put to an object if toString threw an exception. + auto property = subscript.toPropertyKey(callFrame); + if (callFrame->vm().exception()) + return; + + if (Optional 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) +void JIT_OPERATION operationPutByVal(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ArrayProfile* arrayProfile) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); @@ -501,10 +580,15 @@ void JIT_OPERATION operationPutByVal(ExecState* exec, EncodedJSValue encodedBase ByValInfo& byValInfo = exec->codeBlock()->getByValInfo(bytecodeOffset - 1); ASSERT(!byValInfo.stubRoutine); - if (hasOptimizableIndexing(object->structure(vm))) { + Structure* structure = object->structure(vm); + if (hasOptimizableIndexing(structure)) { // Attempt to optimize. - JITArrayMode arrayMode = jitArrayModeForStructure(object->structure(vm)); - if (arrayMode != byValInfo.arrayMode) { + JITArrayMode arrayMode = jitArrayModeForStructure(structure); + if (jitArrayModePermitsPut(arrayMode) && arrayMode != byValInfo.arrayMode) { + CodeBlock* codeBlock = exec->codeBlock(); + ConcurrentJITLocker locker(codeBlock->m_lock); + arrayProfile->computeUpdatedPrediction(locker, codeBlock, structure); + JIT::compilePutByVal(&vm, exec->codeBlock(), &byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode); didOptimize = true; } @@ -519,16 +603,15 @@ void JIT_OPERATION operationPutByVal(ExecState* exec, EncodedJSValue encodedBase if (++byValInfo.slowPathCount >= 10 || object->structure(vm)->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) { // Don't ever try to optimize. - RepatchBuffer repatchBuffer(exec->codeBlock()); - repatchBuffer.relinkCallerToFunction(ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationPutByValGeneric)); + ctiPatchCallByReturnAddress(exec->codeBlock(), ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationPutByValGeneric)); } } } - putByVal(exec, baseValue, subscript, value); + putByVal(exec, baseValue, subscript, value, arrayProfile); } -void JIT_OPERATION operationDirectPutByVal(ExecState* callFrame, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue) +void JIT_OPERATION operationDirectPutByVal(ExecState* callFrame, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ArrayProfile* arrayProfile) { VM& vm = callFrame->vm(); NativeCallFrameTracer tracer(&vm, callFrame); @@ -546,11 +629,16 @@ void JIT_OPERATION operationDirectPutByVal(ExecState* callFrame, EncodedJSValue ASSERT(bytecodeOffset); ByValInfo& byValInfo = callFrame->codeBlock()->getByValInfo(bytecodeOffset - 1); ASSERT(!byValInfo.stubRoutine); - - if (hasOptimizableIndexing(object->structure(vm))) { + + Structure* structure = object->structure(vm); + if (hasOptimizableIndexing(structure)) { // Attempt to optimize. - JITArrayMode arrayMode = jitArrayModeForStructure(object->structure(vm)); - if (arrayMode != byValInfo.arrayMode) { + JITArrayMode arrayMode = jitArrayModeForStructure(structure); + if (jitArrayModePermitsPut(arrayMode) && arrayMode != byValInfo.arrayMode) { + CodeBlock* codeBlock = callFrame->codeBlock(); + ConcurrentJITLocker locker(codeBlock->m_lock); + arrayProfile->computeUpdatedPrediction(locker, codeBlock, structure); + JIT::compileDirectPutByVal(&vm, callFrame->codeBlock(), &byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode); didOptimize = true; } @@ -565,15 +653,14 @@ void JIT_OPERATION operationDirectPutByVal(ExecState* callFrame, EncodedJSValue if (++byValInfo.slowPathCount >= 10 || object->structure(vm)->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) { // Don't ever try to optimize. - RepatchBuffer repatchBuffer(callFrame->codeBlock()); - repatchBuffer.relinkCallerToFunction(ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationDirectPutByValGeneric)); + ctiPatchCallByReturnAddress(callFrame->codeBlock(), ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationDirectPutByValGeneric)); } } } - directPutByVal(callFrame, object, subscript, value); + directPutByVal(callFrame, object, subscript, value, arrayProfile); } -void JIT_OPERATION operationPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue) +void JIT_OPERATION operationPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ArrayProfile* arrayProfile) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); @@ -582,11 +669,11 @@ void JIT_OPERATION operationPutByValGeneric(ExecState* exec, EncodedJSValue enco JSValue subscript = JSValue::decode(encodedSubscript); JSValue value = JSValue::decode(encodedValue); - putByVal(exec, baseValue, subscript, value); + putByVal(exec, baseValue, subscript, value, arrayProfile); } -void JIT_OPERATION operationDirectPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue) +void JIT_OPERATION operationDirectPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ArrayProfile* arrayProfile) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); @@ -595,16 +682,16 @@ 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); + directPutByVal(exec, asObject(baseValue), subscript, value, arrayProfile); } EncodedJSValue JIT_OPERATION operationCallEval(ExecState* exec, ExecState* execCallee) { - ASSERT(exec->codeBlock()->codeType() != FunctionCode + + ASSERT_UNUSED(exec, exec->codeBlock()->codeType() != FunctionCode || !exec->codeBlock()->needsActivation() || exec->hasActivation()); - execCallee->setScope(exec->scope()); execCallee->setCodeBlock(0); if (!isHostFunction(execCallee->calleeAsValue(), globalFuncEval)) @@ -623,7 +710,6 @@ 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) { @@ -679,12 +765,15 @@ inline char* linkFor( JSValue calleeAsValue = execCallee->calleeAsValue(); JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue); - if (!calleeAsFunctionCell) + 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 return reinterpret_cast(handleHostCall(execCallee, calleeAsValue, kind)); + } JSFunction* callee = jsCast(calleeAsFunctionCell); JSScope* scope = callee->scopeUnchecked(); - execCallee->setScope(scope); ExecutableBase* executable = callee->executable(); MacroAssemblerCodePtr codePtr; @@ -693,15 +782,20 @@ inline char* linkFor( codePtr = executable->entrypointFor(*vm, kind, MustCheckArity, registers); else { FunctionExecutable* functionExecutable = static_cast(executable); - JSObject* error = functionExecutable->prepareForExecution(execCallee, callee, &scope, kind); - execCallee->setScope(scope); + + if (!isCall(kind) && functionExecutable->isBuiltinFunction()) { + exec->vm().throwException(exec, createNotAConstructorError(exec, callee)); + return reinterpret_cast(vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress()); + } + + JSObject* error = functionExecutable->prepareForExecution(execCallee, callee, scope, kind); if (error) { - throwStackOverflowError(exec); + exec->vm().throwException(exec, error); return reinterpret_cast(vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress()); } codeBlock = functionExecutable->codeBlockFor(kind); ArityCheckMode arity; - if (execCallee->argumentCountIncludingThis() < static_cast(codeBlock->numParameters()) || callLinkInfo->callType == CallLinkInfo::CallVarargs || callLinkInfo->callType == CallLinkInfo::ConstructVarargs) + if (execCallee->argumentCountIncludingThis() < static_cast(codeBlock->numParameters()) || callLinkInfo->callType() == CallLinkInfo::CallVarargs || callLinkInfo->callType() == CallLinkInfo::ConstructVarargs) arity = MustCheckArity; else arity = ArityCheckNotRequired; @@ -711,6 +805,7 @@ inline char* linkFor( callLinkInfo->setSeen(); else linkFor(execCallee, *callLinkInfo, codeBlock, callee, codePtr, kind, registers); + return reinterpret_cast(codePtr.executableAddress()); } @@ -749,12 +844,16 @@ inline char* virtualForWithFunction( JSFunction* function = jsCast(calleeAsFunctionCell); JSScope* scope = function->scopeUnchecked(); - execCallee->setScope(scope); ExecutableBase* executable = function->executable(); if (UNLIKELY(!executable->hasJITCodeFor(kind))) { FunctionExecutable* functionExecutable = static_cast(executable); - JSObject* error = functionExecutable->prepareForExecution(execCallee, function, &scope, kind); - execCallee->setScope(scope); + + if (!isCall(kind) && functionExecutable->isBuiltinFunction()) { + exec->vm().throwException(exec, createNotAConstructorError(exec, function)); + return reinterpret_cast(vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress()); + } + + JSObject* error = functionExecutable->prepareForExecution(execCallee, function, scope, kind); if (error) { exec->vm().throwException(exec, error); return reinterpret_cast(vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress()); @@ -771,51 +870,12 @@ inline char* virtualFor( return virtualForWithFunction(execCallee, kind, registers, calleeAsFunctionCellIgnored); } -static bool attemptToOptimizeClosureCall( - ExecState* execCallee, RegisterPreservationMode registers, JSCell* calleeAsFunctionCell, - CallLinkInfo& callLinkInfo) -{ - if (!calleeAsFunctionCell) - return false; - - VM& vm = execCallee->vm(); - JSFunction* callee = jsCast(calleeAsFunctionCell); - JSFunction* oldCallee = callLinkInfo.callee.get(); - - if (!oldCallee - || oldCallee->structure(vm) != callee->structure(vm) - || oldCallee->executable() != callee->executable()) - return false; - - ASSERT(callee->executable()->hasJITCodeForCall()); - MacroAssemblerCodePtr codePtr = - callee->executable()->generatedJITCodeForCall()->addressForCall( - *execCallee->callerFrame()->codeBlock()->vm(), callee->executable(), - ArityCheckNotRequired, registers); - - CodeBlock* codeBlock; - if (callee->executable()->isHostFunction()) - codeBlock = 0; - else { - codeBlock = jsCast(callee->executable())->codeBlockForCall(); - if (execCallee->argumentCountIncludingThis() < static_cast(codeBlock->numParameters()) || callLinkInfo.callType == CallLinkInfo::CallVarargs || callLinkInfo.callType == CallLinkInfo::ConstructVarargs) - return false; - } - - linkClosureCall( - execCallee, callLinkInfo, codeBlock, - callee->structure(), callee->executable(), codePtr, registers); - - return true; -} - -char* JIT_OPERATION operationLinkClosureCall(ExecState* execCallee, CallLinkInfo* callLinkInfo) +char* JIT_OPERATION operationLinkPolymorphicCall(ExecState* execCallee, CallLinkInfo* callLinkInfo) { JSCell* calleeAsFunctionCell; char* result = virtualForWithFunction(execCallee, CodeForCall, RegisterPreservationNotRequired, calleeAsFunctionCell); - if (!attemptToOptimizeClosureCall(execCallee, RegisterPreservationNotRequired, calleeAsFunctionCell, *callLinkInfo)) - linkSlowFor(execCallee, *callLinkInfo, CodeForCall, RegisterPreservationNotRequired); + linkPolymorphicCall(execCallee, *callLinkInfo, CallVariant(calleeAsFunctionCell), RegisterPreservationNotRequired); return result; } @@ -830,13 +890,12 @@ char* JIT_OPERATION operationVirtualConstruct(ExecState* execCallee, CallLinkInf return virtualFor(execCallee, CodeForConstruct, RegisterPreservationNotRequired); } -char* JIT_OPERATION operationLinkClosureCallThatPreservesRegs(ExecState* execCallee, CallLinkInfo* callLinkInfo) +char* JIT_OPERATION operationLinkPolymorphicCallThatPreservesRegs(ExecState* execCallee, CallLinkInfo* callLinkInfo) { JSCell* calleeAsFunctionCell; char* result = virtualForWithFunction(execCallee, CodeForCall, MustPreserveRegisters, calleeAsFunctionCell); - if (!attemptToOptimizeClosureCall(execCallee, MustPreserveRegisters, calleeAsFunctionCell, *callLinkInfo)) - linkSlowFor(execCallee, *callLinkInfo, CodeForCall, MustPreserveRegisters); + linkPolymorphicCall(execCallee, *callLinkInfo, CallVariant(calleeAsFunctionCell), MustPreserveRegisters); return result; } @@ -918,7 +977,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, Identifier(exec, property->value(exec))); + int result = base->hasProperty(exec, property->toIdentifier(exec)); return result; } @@ -945,12 +1004,20 @@ EncodedJSValue JIT_OPERATION operationNewArrayWithSizeAndProfile(ExecState* exec return JSValue::encode(constructArrayWithSizeQuirk(exec, profile, exec->lexicalGlobalObject(), sizeValue)); } -EncodedJSValue JIT_OPERATION operationNewFunction(ExecState* exec, JSCell* functionExecutable) +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), exec->scope())); + return JSValue::encode(JSFunction::create(vm, static_cast(functionExecutable), scope)); +} + +EncodedJSValue JIT_OPERATION operationNewFunctionWithInvalidatedReallocationWatchpoint(ExecState* exec, JSScope* scope, JSCell* functionExecutable) +{ + ASSERT(functionExecutable->inherits(FunctionExecutable::info())); + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + return JSValue::encode(JSFunction::createWithInvalidatedReallocationWatchpoint(vm, static_cast(functionExecutable), scope)); } JSCell* JIT_OPERATION operationNewObject(ExecState* exec, Structure* structure) @@ -967,7 +1034,7 @@ EncodedJSValue JIT_OPERATION operationNewRegexp(ExecState* exec, void* regexpPtr NativeCallFrameTracer tracer(&vm, exec); RegExp* regexp = static_cast(regexpPtr); if (!regexp->isValid()) { - vm.throwException(exec, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor.")); + vm.throwException(exec, createSyntaxError(exec, ASCIILiteral("Invalid flags supplied to RegExp constructor."))); return JSValue::encode(jsUndefined()); } @@ -987,12 +1054,13 @@ void JIT_OPERATION operationThrowStaticError(ExecState* exec, EncodedJSValue enc { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); - - String message = errorDescriptionForValue(exec, JSValue::decode(encodedValue))->value(exec); + JSValue errorMessageValue = JSValue::decode(encodedValue); + RELEASE_ASSERT(errorMessageValue.isString()); + String errorMessage = asString(errorMessageValue)->value(exec); if (referenceErrorFlag) - vm.throwException(exec, createReferenceError(exec, message)); + vm.throwException(exec, createReferenceError(exec, errorMessage)); else - vm.throwException(exec, createTypeError(exec, message)); + vm.throwException(exec, createTypeError(exec, errorMessage)); } void JIT_OPERATION operationDebug(ExecState* exec, int32_t debugHookID) @@ -1032,6 +1100,10 @@ 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 @@ -1176,17 +1248,7 @@ SlowPathReturnType JIT_OPERATION operationOptimize(ExecState* exec, int32_t byte Operands mustHandleValues(codeBlock->numParameters(), numVarsWithValues); for (size_t i = 0; i < mustHandleValues.size(); ++i) { int operand = mustHandleValues.operandForIndex(i); - 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(); + mustHandleValues[i] = exec->uncheckedR(operand).jsValue(); } RefPtr replacementCodeBlock = codeBlock->newReplacement(); @@ -1261,6 +1323,32 @@ 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(); @@ -1269,7 +1357,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); + GetterSetter* accessor = GetterSetter::create(vm, exec->lexicalGlobalObject()); JSValue getter = JSValue::decode(encodedGetterValue); JSValue setter = JSValue::decode(encodedSetterValue); @@ -1278,12 +1366,36 @@ void JIT_OPERATION operationPutGetterSetter(ExecState* exec, EncodedJSValue enco ASSERT(getter.isObject() || setter.isObject()); if (!getter.isUndefined()) - accessor->setGetter(vm, asObject(getter)); + accessor->setGetter(vm, exec->lexicalGlobalObject(), asObject(getter)); if (!setter.isUndefined()) - accessor->setSetter(vm, asObject(setter)); + accessor->setSetter(vm, exec->lexicalGlobalObject(), asObject(setter)); baseObj->putDirectAccessor(exec, *identifier, accessor, Accessor); } #else +void JIT_OPERATION operationPutGetterById(ExecState* exec, JSCell* object, Identifier* identifier, JSCell* getter) +{ + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + + ASSERT(object && object->isObject()); + JSObject* baseObj = object->getObject(); + + ASSERT(getter->isObject()); + baseObj->putGetter(exec, *identifier, getter); +} + +void JIT_OPERATION operationPutSetterById(ExecState* exec, JSCell* object, Identifier* identifier, JSCell* setter) +{ + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + + ASSERT(object && object->isObject()); + JSObject* baseObj = object->getObject(); + + ASSERT(setter->isObject()); + baseObj->putSetter(exec, *identifier, setter); +} + void JIT_OPERATION operationPutGetterSetter(ExecState* exec, JSCell* object, Identifier* identifier, JSCell* getter, JSCell* setter) { VM& vm = exec->vm(); @@ -1292,31 +1404,31 @@ void JIT_OPERATION operationPutGetterSetter(ExecState* exec, JSCell* object, Ide ASSERT(object && object->isObject()); JSObject* baseObj = object->getObject(); - GetterSetter* accessor = GetterSetter::create(vm); + GetterSetter* accessor = GetterSetter::create(vm, exec->lexicalGlobalObject()); ASSERT(!getter || getter->isObject()); ASSERT(!setter || setter->isObject()); ASSERT(getter || setter); if (getter) - accessor->setGetter(vm, getter->getObject()); + accessor->setGetter(vm, exec->lexicalGlobalObject(), getter->getObject()); if (setter) - accessor->setSetter(vm, setter->getObject()); + accessor->setSetter(vm, exec->lexicalGlobalObject(), setter->getObject()); baseObj->putDirectAccessor(exec, *identifier, accessor, Accessor); } #endif -void JIT_OPERATION operationPushNameScope(ExecState* exec, Identifier* identifier, EncodedJSValue encodedValue, int32_t attibutes) +void JIT_OPERATION operationPushCatchScope(ExecState* exec, int32_t dst, SymbolTable* symbolTable, EncodedJSValue encodedValue) { - VM& vm = exec->vm(); - NativeCallFrameTracer tracer(&vm, exec); - - JSNameScope* scope = JSNameScope::create(exec, *identifier, JSValue::decode(encodedValue), attibutes); + pushNameScope(exec, dst, symbolTable, encodedValue); +} - exec->setScope(scope); +void JIT_OPERATION operationPushFunctionNameScope(ExecState* exec, int32_t dst, SymbolTable* symbolTable, EncodedJSValue encodedValue) +{ + pushNameScope(exec, dst, symbolTable, encodedValue); } -void JIT_OPERATION operationPushWithScope(ExecState* exec, EncodedJSValue encodedValue) +void JIT_OPERATION operationPushWithScope(ExecState* exec, int32_t dst, EncodedJSValue encodedValue) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); @@ -1325,15 +1437,19 @@ void JIT_OPERATION operationPushWithScope(ExecState* exec, EncodedJSValue encode if (vm.exception()) return; - exec->setScope(JSWithScope::create(exec, o)); + // FIXME: This won't work if this operation is called from the DFG or FTL. + // This should be changed to pass in the old scope and return the new scope. + JSScope* currentScope = exec->uncheckedR(dst).Register::scope(); + exec->uncheckedR(dst) = JSWithScope::create(exec, o, currentScope); } -void JIT_OPERATION operationPopScope(ExecState* exec) +void JIT_OPERATION operationPopScope(ExecState* exec, int32_t scopeReg) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); - exec->setScope(exec->scope()->next()); + JSScope* scope = exec->uncheckedR(scopeReg).Register::scope(); + exec->uncheckedR(scopeReg) = scope->next(); } void JIT_OPERATION operationProfileDidCall(ExecState* exec, EncodedJSValue encodedValue) @@ -1371,91 +1487,97 @@ EncodedJSValue JIT_OPERATION operationCheckHasInstance(ExecState* exec, EncodedJ } } - vm.throwException(exec, createInvalidParameterError(exec, "instanceof", baseVal)); + vm.throwException(exec, createInvalidInstanceofParameterError(exec, 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; -} - -JSCell* JIT_OPERATION operationCreateArguments(ExecState* exec) +JSCell* JIT_OPERATION operationCreateActivation(ExecState* exec, JSScope* currentScope) { 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; + JSLexicalEnvironment* lexicalEnvironment = JSLexicalEnvironment::create(vm, exec, currentScope, exec->codeBlock()); + return lexicalEnvironment; } -JSCell* JIT_OPERATION operationCreateArgumentsDuringOSRExit(ExecState* exec) -{ - DeferGCForAWhile(exec->vm().heap); - return operationCreateArguments(exec); } -EncodedJSValue JIT_OPERATION operationGetArgumentsLength(ExecState* exec, int32_t argumentsRegister) +static bool canAccessArgumentIndexQuickly(JSObject& object, uint32_t index) { - 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)); -} - + switch (object.structure()->typeInfo().type()) { + case DirectArgumentsType: { + DirectArguments* directArguments = jsCast(&object); + if (directArguments->canAccessArgumentIndexQuicklyInDFG(index)) + return true; + break; + } + case ScopedArgumentsType: { + ScopedArguments* scopedArguments = jsCast(&object); + if (scopedArguments->canAccessArgumentIndexQuicklyInDFG(index)) + return true; + break; + } + default: + break; + } + return false; } -static JSValue getByVal(ExecState* exec, JSValue baseValue, JSValue subscript, ReturnAddressPtr returnAddress) +static JSValue getByVal(ExecState* exec, JSValue baseValue, JSValue subscript, ArrayProfile* arrayProfile, ReturnAddressPtr returnAddress) { if (LIKELY(baseValue.isCell() && subscript.isString())) { VM& vm = exec->vm(); Structure& structure = *baseValue.asCell()->structure(vm); if (JSCell::canUseFastGetOwnProperty(structure)) { - if (JSValue result = baseValue.asCell()->fastGetOwnProperty(vm, structure, asString(subscript)->value(exec))) - return result; + if (RefPtr existingAtomicString = asString(subscript)->toExistingAtomicString(exec)) { + if (JSValue result = baseValue.asCell()->fastGetOwnProperty(vm, structure, existingAtomicString.get())) + return result; + } } } if (subscript.isUInt32()) { uint32_t i = subscript.asUInt32(); - if (isJSString(baseValue) && asString(baseValue)->canGetIndex(i)) { - ctiPatchCallByReturnAddress(exec->codeBlock(), returnAddress, FunctionPtr(operationGetByValString)); - return asString(baseValue)->getIndex(exec, i); + if (isJSString(baseValue)) { + if (asString(baseValue)->canGetIndex(i)) { + ctiPatchCallByReturnAddress(exec->codeBlock(), returnAddress, FunctionPtr(operationGetByValString)); + return asString(baseValue)->getIndex(exec, i); + } + arrayProfile->setOutOfBounds(); + } else if (baseValue.isObject()) { + JSObject* object = asObject(baseValue); + if (object->canGetIndexQuickly(i)) + return object->getIndexQuickly(i); + + if (!canAccessArgumentIndexQuickly(*object, i)) + arrayProfile->setOutOfBounds(); } + return baseValue.get(exec, i); } - if (isName(subscript)) - return baseValue.get(exec, jsCast(subscript.asCell())->privateName()); - - Identifier property = subscript.toString(exec)->toIdentifier(exec); + baseValue.requireObjectCoercible(exec); + if (exec->hadException()) + return jsUndefined(); + auto property = subscript.toPropertyKey(exec); + if (exec->hadException()) + return jsUndefined(); return baseValue.get(exec, property); } extern "C" { -EncodedJSValue JIT_OPERATION operationGetByValGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) +EncodedJSValue JIT_OPERATION operationGetByValGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile* arrayProfile) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); JSValue baseValue = JSValue::decode(encodedBase); JSValue subscript = JSValue::decode(encodedSubscript); - JSValue result = getByVal(exec, baseValue, subscript, ReturnAddressPtr(OUR_RETURN_ADDRESS)); + JSValue result = getByVal(exec, baseValue, subscript, arrayProfile, ReturnAddressPtr(OUR_RETURN_ADDRESS)); return JSValue::encode(result); } -EncodedJSValue JIT_OPERATION operationGetByValDefault(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) +EncodedJSValue JIT_OPERATION operationGetByValDefault(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile* arrayProfile) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); @@ -1474,8 +1596,15 @@ EncodedJSValue JIT_OPERATION operationGetByValDefault(ExecState* exec, EncodedJS if (hasOptimizableIndexing(object->structure(vm))) { // Attempt to optimize. - JITArrayMode arrayMode = jitArrayModeForStructure(object->structure(vm)); + 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); + arrayProfile->computeUpdatedPrediction(locker, codeBlock, structure); + JIT::compileGetByVal(&vm, exec->codeBlock(), &byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode); didOptimize = true; } @@ -1490,16 +1619,84 @@ EncodedJSValue JIT_OPERATION operationGetByValDefault(ExecState* exec, EncodedJS if (++byValInfo.slowPathCount >= 10 || object->structure(vm)->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) { // Don't ever try to optimize. - RepatchBuffer repatchBuffer(exec->codeBlock()); - repatchBuffer.relinkCallerToFunction(ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationGetByValGeneric)); + ctiPatchCallByReturnAddress(exec->codeBlock(), ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationGetByValGeneric)); } } } - JSValue result = getByVal(exec, baseValue, subscript, ReturnAddressPtr(OUR_RETURN_ADDRESS)); + JSValue result = getByVal(exec, baseValue, subscript, arrayProfile, ReturnAddressPtr(OUR_RETURN_ADDRESS)); return JSValue::encode(result); } +EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile* arrayProfile) +{ + 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; + + unsigned bytecodeOffset = exec->locationAsBytecodeOffset(); + ASSERT(bytecodeOffset); + ByValInfo& byValInfo = exec->codeBlock()->getByValInfo(bytecodeOffset - 1); + 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)) + arrayProfile->setOutOfBounds(); + return JSValue::encode(jsBoolean(object->hasProperty(exec, index))); +} + +EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile* arrayProfile) +{ + 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)) + arrayProfile->setOutOfBounds(); + return JSValue::encode(jsBoolean(object->hasProperty(exec, subscript.asUInt32()))); +} + EncodedJSValue JIT_OPERATION operationGetByValString(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) { VM& vm = exec->vm(); @@ -1517,34 +1714,18 @@ EncodedJSValue JIT_OPERATION operationGetByValString(ExecState* exec, EncodedJSV if (!isJSString(baseValue)) ctiPatchCallByReturnAddress(exec->codeBlock(), ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationGetByValDefault)); } - } else if (isName(subscript)) - result = baseValue.get(exec, jsCast(subscript.asCell())->privateName()); - else { - Identifier property = subscript.toString(exec)->toIdentifier(exec); + } else { + baseValue.requireObjectCoercible(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + auto property = subscript.toPropertyKey(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); 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()->needsActivation()); - jsCast(activationCell)->tearOff(vm); -} - -void JIT_OPERATION operationTearOffArguments(ExecState* exec, JSCell* argumentsCell, JSCell* activationCell) -{ - ASSERT(exec->codeBlock()->usesArguments()); - if (activationCell) { - jsCast(argumentsCell)->didTearOffActivation(exec, jsCast(activationCell)); - return; - } - jsCast(argumentsCell)->tearOff(exec); -} EncodedJSValue JIT_OPERATION operationDeleteById(ExecState* exec, EncodedJSValue encodedBase, const Identifier* identifier) { @@ -1555,22 +1736,10 @@ EncodedJSValue JIT_OPERATION operationDeleteById(ExecState* exec, EncodedJSValue bool couldDelete = baseObj->methodTable(vm)->deleteProperty(baseObj, exec, *identifier); JSValue result = jsBoolean(couldDelete); if (!couldDelete && exec->codeBlock()->isStrictMode()) - vm.throwException(exec, createTypeError(exec, "Unable to delete property.")); + vm.throwException(exec, createTypeError(exec, ASCIILiteral("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(vm); - 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(); @@ -1584,23 +1753,21 @@ EncodedJSValue JIT_OPERATION operationInstanceOf(ExecState* exec, EncodedJSValue return JSValue::encode(jsBoolean(result)); } -CallFrame* JIT_OPERATION operationSizeFrameForVarargs(ExecState* exec, EncodedJSValue encodedArguments, int32_t firstFreeRegister, int32_t firstVarArgOffset) +int32_t JIT_OPERATION operationSizeFrameForVarargs(ExecState* exec, EncodedJSValue encodedArguments, int32_t numUsedStackSlots, int32_t firstVarArgOffset) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); JSStack* stack = &exec->interpreter()->stack(); JSValue arguments = JSValue::decode(encodedArguments); - CallFrame* newCallFrame = sizeFrameForVarargs(exec, stack, arguments, firstFreeRegister, firstVarArgOffset); - return newCallFrame; + return sizeFrameForVarargs(exec, stack, arguments, numUsedStackSlots, firstVarArgOffset); } -CallFrame* JIT_OPERATION operationLoadVarargs(ExecState* exec, CallFrame* newCallFrame, EncodedJSValue encodedThis, EncodedJSValue encodedArguments, int32_t firstVarArgOffset) +CallFrame* JIT_OPERATION operationSetupVarargsFrame(ExecState* exec, CallFrame* newCallFrame, EncodedJSValue encodedArguments, int32_t firstVarArgOffset, int32_t length) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); - JSValue thisValue = JSValue::decode(encodedThis); JSValue arguments = JSValue::decode(encodedArguments); - loadVarargs(exec, newCallFrame, thisValue, arguments, firstVarArgOffset); + setupVarargsFrame(exec, newCallFrame, arguments, firstVarArgOffset, length); return newCallFrame; } @@ -1667,12 +1834,13 @@ char* JIT_OPERATION operationSwitchStringWithUnknownKeyType(ExecState* exec, Enc return reinterpret_cast(result); } -EncodedJSValue JIT_OPERATION operationResolveScope(ExecState* exec, int32_t identifierIndex) +EncodedJSValue JIT_OPERATION operationResolveScope(ExecState* exec, int32_t scopeReg, int32_t identifierIndex) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); const Identifier& ident = exec->codeBlock()->identifier(identifierIndex); - return JSValue::encode(JSScope::resolve(exec, exec->scope(), ident)); + JSScope* scope = exec->uncheckedR(scopeReg).Register::scope(); + return JSValue::encode(JSScope::resolve(exec, scope, ident)); } EncodedJSValue JIT_OPERATION operationGetFromScope(ExecState* exec, Instruction* bytecodePC) @@ -1696,9 +1864,13 @@ 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 (modeAndType.type() == GlobalProperty || modeAndType.type() == GlobalPropertyWithVarInjectionChecks) { - ConcurrentJITLocker locker(codeBlock->m_lock); - pc[5].u.structure.set(exec->vm(), codeBlock->ownerExecutable(), scope->structure(vm)); - pc[6].u.operand = slot.cachedOffset(); + 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()); } } @@ -1716,7 +1888,13 @@ void JIT_OPERATION operationPutToScope(ExecState* exec, Instruction* bytecodePC) JSObject* scope = jsCast(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(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"); + return; + } if (modeAndType.mode() == ThrowIfNotFound && !scope->hasProperty(exec, ident)) { exec->vm().throwException(exec, createUndefinedVariableError(exec, ident)); return; @@ -1728,14 +1906,7 @@ void JIT_OPERATION operationPutToScope(ExecState* exec, Instruction* bytecodePC) if (exec->vm().exception()) return; - // 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.isCacheablePut() && 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(); - } - } + CommonSlowPaths::tryCachePutToScopeGlobal(exec, codeBlock, pc, scope, modeAndType, slot); } void JIT_OPERATION operationThrow(ExecState* exec, EncodedJSValue encodedExceptionValue) @@ -1746,8 +1917,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 - genericUnwind(vm, exec, exceptionValue); + // Results stored out-of-band in vm.targetMachinePCForThrow, vm.callFrameForThrow & vm.vmEntryFrameForThrow + genericUnwind(vm, exec); } void JIT_OPERATION operationFlushWriteBarrierBuffer(ExecState* exec, JSCell* cell) @@ -1780,17 +1951,24 @@ void JIT_OPERATION operationInitGlobalConst(ExecState* exec, Instruction* pc) NativeCallFrameTracer tracer(vm, exec); JSValue value = exec->r(pc[2].u.operand).jsValue(); - pc[1].u.registerPointer->set(*vm, exec->codeBlock()->globalObject(), value); + pc[1].u.variablePointer->set(*vm, exec->codeBlock()->globalObject(), value); } void JIT_OPERATION lookupExceptionHandler(VM* vm, ExecState* exec) { - NativeCallFrameTracer tracer(vm, exec, NativeCallFrameTracer::VMEntrySentinelOK); + NativeCallFrameTracer tracer(vm, exec); + genericUnwind(vm, exec); + ASSERT(vm->targetMachinePCForThrow); +} - JSValue exceptionValue = vm->exception(); - ASSERT(exceptionValue); - - genericUnwind(vm, exec, exceptionValue); +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); ASSERT(vm->targetMachinePCForThrow); } @@ -1798,9 +1976,7 @@ void JIT_OPERATION operationVMHandleException(ExecState* exec) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - - ASSERT(!exec->isVMEntrySentinel()); - genericUnwind(vm, exec, vm->exception()); + genericUnwind(vm, exec); } // This function "should" just take the ExecState*, but doing so would make it more difficult @@ -1810,24 +1986,65 @@ void JIT_OPERATION operationVMHandleException(ExecState* exec) // testing. void JIT_OPERATION operationExceptionFuzz() { - ASSERT(Options::enableExceptionFuzz()); - // This probably "just works" for GCC also, but I haven't tried. #if COMPILER(CLANG) ExecState* exec = static_cast(__builtin_frame_address(1)); - DeferGCForAWhile deferGC(exec->vm().heap); - - s_numberOfExceptionFuzzChecks++; - - unsigned fireTarget = Options::fireExceptionFuzzAt(); - if (fireTarget == s_numberOfExceptionFuzzChecks) { - printf("JSC EXCEPTION FUZZ: Throwing fuzz exception with call frame %p and return address %p.\n", exec, __builtin_return_address(0)); - exec->vm().throwException( - exec, createError(exec->lexicalGlobalObject(), ASCIILiteral("Exception Fuzz"))); - } + void* returnPC = __builtin_return_address(0); + doExceptionFuzzing(exec, "JITOperations", returnPC); #endif // COMPILER(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(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")); +} + } // extern "C" // Note: getHostCallReturnValueWithExecState() needs to be placed before the