diff options
Diffstat (limited to 'Source/JavaScriptCore/runtime/CommonSlowPaths.h')
-rw-r--r-- | Source/JavaScriptCore/runtime/CommonSlowPaths.h | 220 |
1 files changed, 185 insertions, 35 deletions
diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.h b/Source/JavaScriptCore/runtime/CommonSlowPaths.h index 731b773f0..98fe5db26 100644 --- a/Source/JavaScriptCore/runtime/CommonSlowPaths.h +++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2012 Apple Inc. All rights reserved. + * Copyright (C) 2011-2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,8 +29,12 @@ #include "CodeBlock.h" #include "CodeSpecializationKind.h" #include "ExceptionHelpers.h" -#include "JSArray.h" -#include "NameInstance.h" +#include "JSStackInlines.h" +#include "SlowPathReturnType.h" +#include "StackAlignment.h" +#include "Symbol.h" +#include "VM.h" +#include <wtf/StdLibExtras.h> namespace JSC { @@ -43,42 +47,33 @@ namespace JSC { namespace CommonSlowPaths { -ALWAYS_INLINE ExecState* arityCheckFor(ExecState* exec, JSStack* stack, CodeSpecializationKind kind) +struct ArityCheckData { + unsigned paddedStackSpace; + void* thunkToCall; +}; + +ALWAYS_INLINE int arityCheckFor(ExecState* exec, JSStack* stack, CodeSpecializationKind kind) { JSFunction* callee = jsCast<JSFunction*>(exec->callee()); ASSERT(!callee->isHostFunction()); - CodeBlock* newCodeBlock = &callee->jsExecutable()->generatedBytecodeFor(kind); + CodeBlock* newCodeBlock = callee->jsExecutable()->codeBlockFor(kind); int argumentCountIncludingThis = exec->argumentCountIncludingThis(); - - // This ensures enough space for the worst case scenario of zero arguments passed by the caller. - if (!stack->grow(exec->registers() + newCodeBlock->numParameters() + newCodeBlock->m_numCalleeRegisters)) - return 0; - + ASSERT(argumentCountIncludingThis < newCodeBlock->numParameters()); - - // Too few arguments -- copy call frame and arguments, then fill in missing arguments with undefined. - size_t delta = newCodeBlock->numParameters() - argumentCountIncludingThis; - Register* src = exec->registers(); - Register* dst = exec->registers() + delta; - - int i; - int end = -ExecState::offsetFor(argumentCountIncludingThis); - for (i = -1; i >= end; --i) - dst[i] = src[i]; - - end -= delta; - for ( ; i >= end; --i) - dst[i] = jsUndefined(); - - ExecState* newExec = ExecState::create(dst); - ASSERT((void*)newExec <= stack->end()); - return newExec; + int frameSize = argumentCountIncludingThis + JSStack::CallFrameHeaderSize; + int alignedFrameSizeForParameters = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), + newCodeBlock->numParameters() + JSStack::CallFrameHeaderSize); + int paddedStackSpace = alignedFrameSizeForParameters - frameSize; + + if (!stack->ensureCapacityFor(exec->registers() - paddedStackSpace % stackAlignmentRegisters())) + return -1; + return paddedStackSpace; } inline bool opIn(ExecState* exec, JSValue propName, JSValue baseVal) { if (!baseVal.isObject()) { - exec->vm().exception = createInvalidParameterError(exec, "in", baseVal); + exec->vm().throwException(exec, createInvalidInParameterError(exec, baseVal)); return false; } @@ -88,15 +83,170 @@ inline bool opIn(ExecState* exec, JSValue propName, JSValue baseVal) if (propName.getUInt32(i)) 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) + auto property = propName.toPropertyKey(exec); + if (exec->vm().exception()) return false; return baseObj->hasProperty(exec, property); } -} } // namespace JSC::CommonSlowPaths +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 (resolveType == UnresolvedProperty || resolveType == UnresolvedPropertyWithVarInjectionChecks) { + if (JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsDynamicCast<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()); + pc[5].u.watchpointSet = entry.watchpointSet(); + pc[6].u.pointer = static_cast<void*>(globalLexicalEnvironment->variableAt(entry.scopeOffset()).slot()); + } else if (jsDynamicCast<JSGlobalObject*>(scope)) { + ResolveType newResolveType = resolveType == UnresolvedProperty ? GlobalProperty : GlobalPropertyWithVarInjectionChecks; + resolveType = newResolveType; + getPutInfo = GetPutInfo(getPutInfo.resolveMode(), newResolveType, getPutInfo.initializationMode()); + pc[4].u.operand = getPutInfo.operand(); + } + } + + 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()); + + ConcurrentJITLocker locker(codeBlock->m_lock); + pc[5].u.structure.set(exec->vm(), codeBlock, scope->structure()); + pc[6].u.operand = slot.cachedOffset(); + } +} + +inline void tryCacheGetFromScopeGlobal( + ExecState* exec, VM& vm, Instruction* pc, JSObject* scope, PropertySlot& slot, const Identifier& ident) +{ + GetPutInfo getPutInfo(pc[4].u.operand); + ResolveType resolveType = getPutInfo.resolveType(); + + if (resolveType == UnresolvedProperty || resolveType == UnresolvedPropertyWithVarInjectionChecks) { + if (JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsDynamicCast<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()); + pc[5].u.watchpointSet = entry.watchpointSet(); + pc[6].u.pointer = static_cast<void*>(globalLexicalEnvironment->variableAt(entry.scopeOffset()).slot()); + } else if (jsDynamicCast<JSGlobalObject*>(scope)) { + ResolveType newResolveType = resolveType == UnresolvedProperty ? GlobalProperty : GlobalPropertyWithVarInjectionChecks; + resolveType = newResolveType; // Allow below caching mechanism to kick in. + pc[4].u.operand = GetPutInfo(getPutInfo.resolveMode(), newResolveType, getPutInfo.initializationMode()).operand(); + } + } + + // 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); + { + ConcurrentJITLocker locker(codeBlock->m_lock); + pc[5].u.structure.set(exec->vm(), codeBlock, structure); + pc[6].u.operand = slot.cachedOffset(); + } + structure->startWatchingPropertyForReplacements(vm, slot.cachedOffset()); + } + } +} + +} // namespace CommonSlowPaths + +class ExecState; +struct Instruction; + +#define SLOW_PATH + +#define SLOW_PATH_DECL(name) \ +extern "C" SlowPathReturnType SLOW_PATH name(ExecState* exec, Instruction* pc) + +#define SLOW_PATH_HIDDEN_DECL(name) \ +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_create_direct_arguments); +SLOW_PATH_HIDDEN_DECL(slow_path_create_scoped_arguments); +SLOW_PATH_HIDDEN_DECL(slow_path_create_out_of_band_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_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); +SLOW_PATH_HIDDEN_DECL(slow_path_stricteq); +SLOW_PATH_HIDDEN_DECL(slow_path_nstricteq); +SLOW_PATH_HIDDEN_DECL(slow_path_less); +SLOW_PATH_HIDDEN_DECL(slow_path_lesseq); +SLOW_PATH_HIDDEN_DECL(slow_path_greater); +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_lshift); +SLOW_PATH_HIDDEN_DECL(slow_path_rshift); +SLOW_PATH_HIDDEN_DECL(slow_path_urshift); +SLOW_PATH_HIDDEN_DECL(slow_path_unsigned); +SLOW_PATH_HIDDEN_DECL(slow_path_bitand); +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_save); +SLOW_PATH_HIDDEN_DECL(slow_path_resume); +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_copy_rest); + +} // namespace JSC #endif // CommonSlowPaths_h |