diff options
Diffstat (limited to 'Source/JavaScriptCore/runtime/CommonSlowPaths.h')
-rw-r--r-- | Source/JavaScriptCore/runtime/CommonSlowPaths.h | 235 |
1 files changed, 149 insertions, 86 deletions
diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.h b/Source/JavaScriptCore/runtime/CommonSlowPaths.h index cfc8bdbb7..7a62728f8 100644 --- a/Source/JavaScriptCore/runtime/CommonSlowPaths.h +++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2011-2013, 2015-2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,21 +23,18 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CommonSlowPaths_h -#define CommonSlowPaths_h +#pragma once #include "CodeBlock.h" #include "CodeSpecializationKind.h" #include "ExceptionHelpers.h" -#include "JSStackInlines.h" -#include "NameInstance.h" +#include "FunctionCodeBlock.h" +#include "SlowPathReturnType.h" #include "StackAlignment.h" -#include "VM.h" -#include <wtf/Platform.h> +#include "Symbol.h" +#include "VMInlines.h" #include <wtf/StdLibExtras.h> -#if ENABLE(JIT) || ENABLE(LLINT) - namespace JSC { // The purpose of this namespace is to include slow paths that are shared @@ -49,107 +46,149 @@ namespace JSC { namespace CommonSlowPaths { -ALWAYS_INLINE int arityCheckFor(ExecState* exec, JSStack* stack, CodeSpecializationKind kind) +struct ArityCheckData { + unsigned paddedStackSpace; + void* thunkToCall; +}; + +ALWAYS_INLINE int arityCheckFor(ExecState* exec, VM& vm, CodeSpecializationKind kind) { - JSFunction* callee = jsCast<JSFunction*>(exec->callee()); + JSFunction* callee = jsCast<JSFunction*>(exec->jsCallee()); ASSERT(!callee->isHostFunction()); CodeBlock* newCodeBlock = callee->jsExecutable()->codeBlockFor(kind); int argumentCountIncludingThis = exec->argumentCountIncludingThis(); ASSERT(argumentCountIncludingThis < newCodeBlock->numParameters()); - int missingArgumentCount = newCodeBlock->numParameters() - argumentCountIncludingThis; - int paddedMissingArgumentCount = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), missingArgumentCount); + int frameSize = argumentCountIncludingThis + CallFrame::headerSizeInRegisters; + int alignedFrameSizeForParameters = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), + newCodeBlock->numParameters() + CallFrame::headerSizeInRegisters); + int paddedStackSpace = alignedFrameSizeForParameters - frameSize; + + Register* newStack = exec->registers() - WTF::roundUpToMultipleOf(stackAlignmentRegisters(), paddedStackSpace); -#if USE(SEPARATE_C_AND_JS_STACK) - if (!stack->grow(exec->registers() - paddedMissingArgumentCount)) - return -1; -#else - UNUSED_PARAM(stack); - if (!exec->vm().isSafeToRecurse(paddedMissingArgumentCount * sizeof(Register))) + if (UNLIKELY(!vm.ensureStackCapacityFor(newStack))) return -1; -#endif // USE(SEPARATE_C_AND_JS_STACK) - - return paddedMissingArgumentCount; + return paddedStackSpace; } -inline bool opIn(ExecState* exec, JSValue propName, JSValue baseVal) +inline bool opIn(ExecState* exec, JSValue baseVal, JSValue propName, ArrayProfile* arrayProfile = nullptr) { + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); if (!baseVal.isObject()) { - exec->vm().throwException(exec, createInvalidParameterError(exec, "in", baseVal)); + throwException(exec, scope, createInvalidInParameterError(exec, baseVal)); return false; } JSObject* baseObj = asObject(baseVal); + if (arrayProfile) + arrayProfile->observeStructure(baseObj->structure(vm)); uint32_t i; - if (propName.getUInt32(i)) + if (propName.getUInt32(i)) { + scope.release(); return baseObj->hasProperty(exec, i); + } - if (isName(propName)) - return baseObj->hasProperty(exec, jsCast<NameInstance*>(propName.asCell())->privateName()); - - Identifier property(exec, propName.toString(exec)->value(exec)); - if (exec->vm().exception()) - return false; + auto property = propName.toPropertyKey(exec); + RETURN_IF_EXCEPTION(scope, false); + scope.release(); return baseObj->hasProperty(exec, property); } -} // namespace CommonSlowPaths - -class ExecState; -struct Instruction; +inline void tryCachePutToScopeGlobal( + ExecState* exec, CodeBlock* codeBlock, Instruction* pc, JSObject* scope, + GetPutInfo getPutInfo, PutPropertySlot& slot, const Identifier& ident) +{ + // Covers implicit globals. Since they don't exist until they first execute, we didn't know how to cache them at compile time. + ResolveType resolveType = getPutInfo.resolveType(); + if (resolveType != GlobalProperty && resolveType != GlobalPropertyWithVarInjectionChecks + && resolveType != UnresolvedProperty && resolveType != UnresolvedPropertyWithVarInjectionChecks) + return; -#if USE(JSVALUE64) -// According to C++ rules, a type used for the return signature of function with C linkage (i.e. -// 'extern "C"') needs to be POD; hence putting any constructors into it could cause either compiler -// warnings, or worse, a change in the ABI used to return these types. -struct SlowPathReturnType { - void* a; - void* b; -}; + if (resolveType == UnresolvedProperty || resolveType == UnresolvedPropertyWithVarInjectionChecks) { + if (scope->isGlobalObject()) { + ResolveType newResolveType = resolveType == UnresolvedProperty ? GlobalProperty : GlobalPropertyWithVarInjectionChecks; + resolveType = newResolveType; + getPutInfo = GetPutInfo(getPutInfo.resolveMode(), newResolveType, getPutInfo.initializationMode()); + ConcurrentJSLocker locker(codeBlock->m_lock); + pc[4].u.operand = getPutInfo.operand(); + } else if (scope->isGlobalLexicalEnvironment()) { + JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalLexicalEnvironment*>(scope); + ResolveType newResolveType = resolveType == UnresolvedProperty ? GlobalLexicalVar : GlobalLexicalVarWithVarInjectionChecks; + pc[4].u.operand = GetPutInfo(getPutInfo.resolveMode(), newResolveType, getPutInfo.initializationMode()).operand(); + SymbolTableEntry entry = globalLexicalEnvironment->symbolTable()->get(ident.impl()); + ASSERT(!entry.isNull()); + ConcurrentJSLocker locker(codeBlock->m_lock); + pc[5].u.watchpointSet = entry.watchpointSet(); + pc[6].u.pointer = static_cast<void*>(globalLexicalEnvironment->variableAt(entry.scopeOffset()).slot()); + } + } + + if (resolveType == GlobalProperty || resolveType == GlobalPropertyWithVarInjectionChecks) { + if (!slot.isCacheablePut() + || slot.base() != scope + || !scope->structure()->propertyAccessesAreCacheable()) + return; + + if (slot.type() == PutPropertySlot::NewProperty) { + // Don't cache if we've done a transition. We want to detect the first replace so that we + // can invalidate the watchpoint. + return; + } + + scope->structure()->didCachePropertyReplacement(exec->vm(), slot.cachedOffset()); -inline SlowPathReturnType encodeResult(void* a, void* b) -{ - SlowPathReturnType result; - result.a = a; - result.b = b; - return result; + ConcurrentJSLocker locker(codeBlock->m_lock); + pc[5].u.structure.set(exec->vm(), codeBlock, scope->structure()); + pc[6].u.operand = slot.cachedOffset(); + } } -inline void decodeResult(SlowPathReturnType result, void*& a, void*& b) +inline void tryCacheGetFromScopeGlobal( + ExecState* exec, VM& vm, Instruction* pc, JSObject* scope, PropertySlot& slot, const Identifier& ident) { - a = result.a; - b = result.b; -} + GetPutInfo getPutInfo(pc[4].u.operand); + ResolveType resolveType = getPutInfo.resolveType(); -#else // USE(JSVALUE32_64) -typedef int64_t SlowPathReturnType; - -typedef union { - struct { - void* a; - void* b; - } pair; - int64_t i; -} SlowPathReturnTypeEncoding; + if (resolveType == UnresolvedProperty || resolveType == UnresolvedPropertyWithVarInjectionChecks) { + if (scope->isGlobalObject()) { + ResolveType newResolveType = resolveType == UnresolvedProperty ? GlobalProperty : GlobalPropertyWithVarInjectionChecks; + resolveType = newResolveType; // Allow below caching mechanism to kick in. + ConcurrentJSLocker locker(exec->codeBlock()->m_lock); + pc[4].u.operand = GetPutInfo(getPutInfo.resolveMode(), newResolveType, getPutInfo.initializationMode()).operand(); + } else if (scope->isGlobalLexicalEnvironment()) { + JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalLexicalEnvironment*>(scope); + ResolveType newResolveType = resolveType == UnresolvedProperty ? GlobalLexicalVar : GlobalLexicalVarWithVarInjectionChecks; + SymbolTableEntry entry = globalLexicalEnvironment->symbolTable()->get(ident.impl()); + ASSERT(!entry.isNull()); + ConcurrentJSLocker locker(exec->codeBlock()->m_lock); + pc[4].u.operand = GetPutInfo(getPutInfo.resolveMode(), newResolveType, getPutInfo.initializationMode()).operand(); + pc[5].u.watchpointSet = entry.watchpointSet(); + pc[6].u.pointer = static_cast<void*>(globalLexicalEnvironment->variableAt(entry.scopeOffset()).slot()); + } + } -inline SlowPathReturnType encodeResult(void* a, void* b) -{ - SlowPathReturnTypeEncoding u; - u.pair.a = a; - u.pair.b = b; - return u.i; + // 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()->propertyAccessesAreCacheable()) { + if (resolveType == GlobalProperty || resolveType == GlobalPropertyWithVarInjectionChecks) { + CodeBlock* codeBlock = exec->codeBlock(); + Structure* structure = scope->structure(vm); + { + ConcurrentJSLocker locker(codeBlock->m_lock); + pc[5].u.structure.set(exec->vm(), codeBlock, structure); + pc[6].u.operand = slot.cachedOffset(); + } + structure->startWatchingPropertyForReplacements(vm, slot.cachedOffset()); + } + } } -inline void decodeResult(SlowPathReturnType result, void*& a, void*& b) -{ - SlowPathReturnTypeEncoding u; - u.i = result; - a = u.pair.a; - b = u.pair.b; -} -#endif // USE(JSVALUE32_64) - +} // namespace CommonSlowPaths + +class ExecState; +struct Instruction; + #define SLOW_PATH #define SLOW_PATH_DECL(name) \ @@ -160,14 +199,15 @@ SLOW_PATH_DECL(name) WTF_INTERNAL SLOW_PATH_HIDDEN_DECL(slow_path_call_arityCheck); SLOW_PATH_HIDDEN_DECL(slow_path_construct_arityCheck); -SLOW_PATH_HIDDEN_DECL(slow_path_touch_entry); -SLOW_PATH_HIDDEN_DECL(slow_path_create_arguments); +SLOW_PATH_HIDDEN_DECL(slow_path_create_direct_arguments); +SLOW_PATH_HIDDEN_DECL(slow_path_create_scoped_arguments); +SLOW_PATH_HIDDEN_DECL(slow_path_create_cloned_arguments); SLOW_PATH_HIDDEN_DECL(slow_path_create_this); SLOW_PATH_HIDDEN_DECL(slow_path_enter); SLOW_PATH_HIDDEN_DECL(slow_path_get_callee); SLOW_PATH_HIDDEN_DECL(slow_path_to_this); -SLOW_PATH_HIDDEN_DECL(slow_path_captured_mov); -SLOW_PATH_HIDDEN_DECL(slow_path_new_captured_func); +SLOW_PATH_HIDDEN_DECL(slow_path_throw_tdz_error); +SLOW_PATH_HIDDEN_DECL(slow_path_throw_strict_mode_readonly_property_write_error); SLOW_PATH_HIDDEN_DECL(slow_path_not); SLOW_PATH_HIDDEN_DECL(slow_path_eq); SLOW_PATH_HIDDEN_DECL(slow_path_neq); @@ -180,12 +220,14 @@ SLOW_PATH_HIDDEN_DECL(slow_path_greatereq); SLOW_PATH_HIDDEN_DECL(slow_path_inc); SLOW_PATH_HIDDEN_DECL(slow_path_dec); SLOW_PATH_HIDDEN_DECL(slow_path_to_number); +SLOW_PATH_HIDDEN_DECL(slow_path_to_string); SLOW_PATH_HIDDEN_DECL(slow_path_negate); SLOW_PATH_HIDDEN_DECL(slow_path_add); SLOW_PATH_HIDDEN_DECL(slow_path_mul); SLOW_PATH_HIDDEN_DECL(slow_path_sub); SLOW_PATH_HIDDEN_DECL(slow_path_div); SLOW_PATH_HIDDEN_DECL(slow_path_mod); +SLOW_PATH_HIDDEN_DECL(slow_path_pow); SLOW_PATH_HIDDEN_DECL(slow_path_lshift); SLOW_PATH_HIDDEN_DECL(slow_path_rshift); SLOW_PATH_HIDDEN_DECL(slow_path_urshift); @@ -195,14 +237,35 @@ SLOW_PATH_HIDDEN_DECL(slow_path_bitor); SLOW_PATH_HIDDEN_DECL(slow_path_bitxor); SLOW_PATH_HIDDEN_DECL(slow_path_typeof); SLOW_PATH_HIDDEN_DECL(slow_path_is_object); +SLOW_PATH_HIDDEN_DECL(slow_path_is_object_or_null); SLOW_PATH_HIDDEN_DECL(slow_path_is_function); SLOW_PATH_HIDDEN_DECL(slow_path_in); SLOW_PATH_HIDDEN_DECL(slow_path_del_by_val); SLOW_PATH_HIDDEN_DECL(slow_path_strcat); SLOW_PATH_HIDDEN_DECL(slow_path_to_primitive); +SLOW_PATH_HIDDEN_DECL(slow_path_get_enumerable_length); +SLOW_PATH_HIDDEN_DECL(slow_path_has_generic_property); +SLOW_PATH_HIDDEN_DECL(slow_path_has_structure_property); +SLOW_PATH_HIDDEN_DECL(slow_path_has_indexed_property); +SLOW_PATH_HIDDEN_DECL(slow_path_get_direct_pname); +SLOW_PATH_HIDDEN_DECL(slow_path_get_property_enumerator); +SLOW_PATH_HIDDEN_DECL(slow_path_next_structure_enumerator_pname); +SLOW_PATH_HIDDEN_DECL(slow_path_next_generic_enumerator_pname); +SLOW_PATH_HIDDEN_DECL(slow_path_to_index_string); +SLOW_PATH_HIDDEN_DECL(slow_path_profile_type_clear_log); +SLOW_PATH_HIDDEN_DECL(slow_path_assert); +SLOW_PATH_HIDDEN_DECL(slow_path_create_lexical_environment); +SLOW_PATH_HIDDEN_DECL(slow_path_push_with_scope); +SLOW_PATH_HIDDEN_DECL(slow_path_resolve_scope); +SLOW_PATH_HIDDEN_DECL(slow_path_create_rest); +SLOW_PATH_HIDDEN_DECL(slow_path_get_by_id_with_this); +SLOW_PATH_HIDDEN_DECL(slow_path_get_by_val_with_this); +SLOW_PATH_HIDDEN_DECL(slow_path_put_by_id_with_this); +SLOW_PATH_HIDDEN_DECL(slow_path_put_by_val_with_this); +SLOW_PATH_HIDDEN_DECL(slow_path_define_data_property); +SLOW_PATH_HIDDEN_DECL(slow_path_define_accessor_property); +SLOW_PATH_HIDDEN_DECL(slow_path_throw_static_error); +SLOW_PATH_HIDDEN_DECL(slow_path_new_array_with_spread); +SLOW_PATH_HIDDEN_DECL(slow_path_spread); } // namespace JSC - -#endif // ENABLE(JIT) || ENABLE(LLINT) - -#endif // CommonSlowPaths_h |