summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime/CommonSlowPaths.h
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/runtime/CommonSlowPaths.h')
-rw-r--r--Source/JavaScriptCore/runtime/CommonSlowPaths.h235
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