e7e36a660bbe535cbdd264f31c6e5dac97c99f62
[WebKit.git] / Source / JavaScriptCore / runtime / CommonSlowPaths.h
1 /*
2  * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #pragma once
27
28 #include "CodeBlock.h"
29 #include "CodeSpecializationKind.h"
30 #include "DirectArguments.h"
31 #include "ExceptionHelpers.h"
32 #include "FunctionCodeBlock.h"
33 #include "JSImmutableButterfly.h"
34 #include "ScopedArguments.h"
35 #include "SlowPathReturnType.h"
36 #include "StackAlignment.h"
37 #include "VMInlines.h"
38 #include <wtf/StdLibExtras.h>
39
40 namespace JSC {
41
42 // The purpose of this namespace is to include slow paths that are shared
43 // between the interpreter and baseline JIT. They are written to be agnostic
44 // with respect to the slow-path calling convention, but they do rely on the
45 // JS code being executed more-or-less directly from bytecode (so the call
46 // frame layout is unmodified, making it potentially awkward to use these
47 // from any optimizing JIT, like the DFG).
48
49 namespace CommonSlowPaths {
50
51 ALWAYS_INLINE int numberOfExtraSlots(int argumentCountIncludingThis)
52 {
53     int frameSize = argumentCountIncludingThis + CallFrame::headerSizeInRegisters;
54     int alignedFrameSize = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), frameSize);
55     return alignedFrameSize - frameSize;
56 }
57
58 ALWAYS_INLINE int numberOfStackPaddingSlots(CodeBlock* codeBlock, int argumentCountIncludingThis)
59 {
60     if (argumentCountIncludingThis >= codeBlock->numParameters())
61         return 0;
62     int alignedFrameSize = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), argumentCountIncludingThis + CallFrame::headerSizeInRegisters);
63     int alignedFrameSizeForParameters = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), codeBlock->numParameters() + CallFrame::headerSizeInRegisters);
64     return alignedFrameSizeForParameters - alignedFrameSize;
65 }
66
67 ALWAYS_INLINE int numberOfStackPaddingSlotsWithExtraSlots(CodeBlock* codeBlock, int argumentCountIncludingThis)
68 {
69     if (argumentCountIncludingThis >= codeBlock->numParameters())
70         return 0;
71     return numberOfStackPaddingSlots(codeBlock, argumentCountIncludingThis) + numberOfExtraSlots(argumentCountIncludingThis);
72 }
73
74 ALWAYS_INLINE int arityCheckFor(ExecState* exec, VM& vm, CodeSpecializationKind kind)
75 {
76     JSFunction* callee = jsCast<JSFunction*>(exec->jsCallee());
77     ASSERT(!callee->isHostFunction());
78     CodeBlock* newCodeBlock = callee->jsExecutable()->codeBlockFor(kind);
79     ASSERT(exec->argumentCountIncludingThis() < static_cast<unsigned>(newCodeBlock->numParameters()));
80     int padding = numberOfStackPaddingSlotsWithExtraSlots(newCodeBlock, exec->argumentCountIncludingThis());
81     
82     Register* newStack = exec->registers() - WTF::roundUpToMultipleOf(stackAlignmentRegisters(), padding);
83
84     if (UNLIKELY(!vm.ensureStackCapacityFor(newStack)))
85         return -1;
86     return padding;
87 }
88
89 inline bool opInByVal(ExecState* exec, JSValue baseVal, JSValue propName, ArrayProfile* arrayProfile = nullptr)
90 {
91     VM& vm = exec->vm();
92     auto scope = DECLARE_THROW_SCOPE(vm);
93     if (!baseVal.isObject()) {
94         throwException(exec, scope, createInvalidInParameterError(exec, baseVal));
95         return false;
96     }
97
98     JSObject* baseObj = asObject(baseVal);
99     if (arrayProfile)
100         arrayProfile->observeStructure(baseObj->structure(vm));
101
102     uint32_t i;
103     if (propName.getUInt32(i)) {
104         if (arrayProfile)
105             arrayProfile->observeIndexedRead(vm, baseObj, i);
106         scope.release();
107         return baseObj->hasProperty(exec, i);
108     }
109
110     auto property = propName.toPropertyKey(exec);
111     RETURN_IF_EXCEPTION(scope, false);
112     scope.release();
113     return baseObj->hasProperty(exec, property);
114 }
115
116 inline void tryCachePutToScopeGlobal(
117     ExecState* exec, CodeBlock* codeBlock, Instruction* pc, JSObject* scope,
118     GetPutInfo getPutInfo, PutPropertySlot& slot, const Identifier& ident)
119 {
120     // Covers implicit globals. Since they don't exist until they first execute, we didn't know how to cache them at compile time.
121     ResolveType resolveType = getPutInfo.resolveType();
122     if (resolveType != GlobalProperty && resolveType != GlobalPropertyWithVarInjectionChecks 
123         && resolveType != UnresolvedProperty && resolveType != UnresolvedPropertyWithVarInjectionChecks)
124         return;
125
126     if (resolveType == UnresolvedProperty || resolveType == UnresolvedPropertyWithVarInjectionChecks) {
127         if (scope->isGlobalObject()) {
128             ResolveType newResolveType = resolveType == UnresolvedProperty ? GlobalProperty : GlobalPropertyWithVarInjectionChecks;
129             resolveType = newResolveType;
130             getPutInfo = GetPutInfo(getPutInfo.resolveMode(), newResolveType, getPutInfo.initializationMode());
131             ConcurrentJSLocker locker(codeBlock->m_lock);
132             pc[4].u.operand = getPutInfo.operand();
133         } else if (scope->isGlobalLexicalEnvironment()) {
134             JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalLexicalEnvironment*>(scope);
135             ResolveType newResolveType = resolveType == UnresolvedProperty ? GlobalLexicalVar : GlobalLexicalVarWithVarInjectionChecks;
136             pc[4].u.operand = GetPutInfo(getPutInfo.resolveMode(), newResolveType, getPutInfo.initializationMode()).operand();
137             SymbolTableEntry entry = globalLexicalEnvironment->symbolTable()->get(ident.impl());
138             ASSERT(!entry.isNull());
139             ConcurrentJSLocker locker(codeBlock->m_lock);
140             pc[5].u.watchpointSet = entry.watchpointSet();
141             pc[6].u.pointer = static_cast<void*>(globalLexicalEnvironment->variableAt(entry.scopeOffset()).slot());
142         }
143     }
144     
145     if (resolveType == GlobalProperty || resolveType == GlobalPropertyWithVarInjectionChecks) {
146         JSGlobalObject* globalObject = codeBlock->globalObject();
147         ASSERT(globalObject == scope || globalObject->varInjectionWatchpoint()->hasBeenInvalidated());
148         if (!slot.isCacheablePut()
149             || slot.base() != scope
150             || scope != globalObject
151             || !scope->structure()->propertyAccessesAreCacheable())
152             return;
153         
154         if (slot.type() == PutPropertySlot::NewProperty) {
155             // Don't cache if we've done a transition. We want to detect the first replace so that we
156             // can invalidate the watchpoint.
157             return;
158         }
159         
160         VM& vm = exec->vm();
161         scope->structure()->didCachePropertyReplacement(vm, slot.cachedOffset());
162
163         ConcurrentJSLocker locker(codeBlock->m_lock);
164         pc[5].u.structure.set(vm, codeBlock, scope->structure());
165         pc[6].u.operand = slot.cachedOffset();
166     }
167 }
168
169 inline void tryCacheGetFromScopeGlobal(
170     ExecState* exec, VM& vm, Instruction* pc, JSObject* scope, PropertySlot& slot, const Identifier& ident)
171 {
172     GetPutInfo getPutInfo(pc[4].u.operand);
173     ResolveType resolveType = getPutInfo.resolveType();
174
175     if (resolveType == UnresolvedProperty || resolveType == UnresolvedPropertyWithVarInjectionChecks) {
176         if (scope->isGlobalObject()) {
177             ResolveType newResolveType = resolveType == UnresolvedProperty ? GlobalProperty : GlobalPropertyWithVarInjectionChecks;
178             resolveType = newResolveType; // Allow below caching mechanism to kick in.
179             ConcurrentJSLocker locker(exec->codeBlock()->m_lock);
180             pc[4].u.operand = GetPutInfo(getPutInfo.resolveMode(), newResolveType, getPutInfo.initializationMode()).operand();
181         } else if (scope->isGlobalLexicalEnvironment()) {
182             JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalLexicalEnvironment*>(scope);
183             ResolveType newResolveType = resolveType == UnresolvedProperty ? GlobalLexicalVar : GlobalLexicalVarWithVarInjectionChecks;
184             SymbolTableEntry entry = globalLexicalEnvironment->symbolTable()->get(ident.impl());
185             ASSERT(!entry.isNull());
186             ConcurrentJSLocker locker(exec->codeBlock()->m_lock);
187             pc[4].u.operand = GetPutInfo(getPutInfo.resolveMode(), newResolveType, getPutInfo.initializationMode()).operand();
188             pc[5].u.watchpointSet = entry.watchpointSet();
189             pc[6].u.pointer = static_cast<void*>(globalLexicalEnvironment->variableAt(entry.scopeOffset()).slot());
190         }
191     }
192
193     // Covers implicit globals. Since they don't exist until they first execute, we didn't know how to cache them at compile time.
194     if (resolveType == GlobalProperty || resolveType == GlobalPropertyWithVarInjectionChecks) {
195         CodeBlock* codeBlock = exec->codeBlock();
196         JSGlobalObject* globalObject = codeBlock->globalObject();
197         ASSERT(scope == globalObject || globalObject->varInjectionWatchpoint()->hasBeenInvalidated());
198         if (slot.isCacheableValue() && slot.slotBase() == scope && scope == globalObject && scope->structure()->propertyAccessesAreCacheable()) {
199             Structure* structure = scope->structure(vm);
200             {
201                 ConcurrentJSLocker locker(codeBlock->m_lock);
202                 pc[5].u.structure.set(vm, codeBlock, structure);
203                 pc[6].u.operand = slot.cachedOffset();
204             }
205             structure->startWatchingPropertyForReplacements(vm, slot.cachedOffset());
206         }
207     }
208 }
209
210 inline bool canAccessArgumentIndexQuickly(JSObject& object, uint32_t index)
211 {
212     switch (object.structure()->typeInfo().type()) {
213     case DirectArgumentsType: {
214         DirectArguments* directArguments = jsCast<DirectArguments*>(&object);
215         if (directArguments->isMappedArgumentInDFG(index))
216             return true;
217         break;
218     }
219     case ScopedArgumentsType: {
220         ScopedArguments* scopedArguments = jsCast<ScopedArguments*>(&object);
221         if (scopedArguments->isMappedArgumentInDFG(index))
222             return true;
223         break;
224     }
225     default:
226         break;
227     }
228     return false;
229 }
230
231 static ALWAYS_INLINE void putDirectWithReify(VM& vm, ExecState* exec, JSObject* baseObject, PropertyName propertyName, JSValue value, PutPropertySlot& slot, Structure** result = nullptr)
232 {
233     auto scope = DECLARE_THROW_SCOPE(vm);
234     if (baseObject->inherits<JSFunction>(vm)) {
235         jsCast<JSFunction*>(baseObject)->reifyLazyPropertyIfNeeded(vm, exec, propertyName);
236         RETURN_IF_EXCEPTION(scope, void());
237     }
238     if (result)
239         *result = baseObject->structure(vm);
240     scope.release();
241     baseObject->putDirect(vm, propertyName, value, slot);
242 }
243
244 static ALWAYS_INLINE void putDirectAccessorWithReify(VM& vm, ExecState* exec, JSObject* baseObject, PropertyName propertyName, GetterSetter* accessor, unsigned attribute)
245 {
246     auto scope = DECLARE_THROW_SCOPE(vm);
247     if (baseObject->inherits<JSFunction>(vm)) {
248         jsCast<JSFunction*>(baseObject)->reifyLazyPropertyIfNeeded(vm, exec, propertyName);
249         RETURN_IF_EXCEPTION(scope, void());
250     }
251     scope.release();
252     baseObject->putDirectAccessor(exec, propertyName, accessor, attribute);
253 }
254
255 inline JSArray* allocateNewArrayBuffer(VM& vm, Structure* structure, JSImmutableButterfly* immutableButterfly)
256 {
257     JSGlobalObject* globalObject = structure->globalObject();
258     Structure* originalStructure = globalObject->originalArrayStructureForIndexingType(immutableButterfly->indexingMode());
259     ASSERT(originalStructure->indexingMode() == immutableButterfly->indexingMode());
260     ASSERT(isCopyOnWrite(immutableButterfly->indexingMode()));
261     ASSERT(!structure->outOfLineCapacity());
262
263     JSArray* result = JSArray::createWithButterfly(vm, nullptr, originalStructure, immutableButterfly->toButterfly());
264     // FIXME: This works but it's slow. If we cared enough about the perf when having a bad time then we could fix it.
265     if (UNLIKELY(originalStructure != structure)) {
266         ASSERT(hasSlowPutArrayStorage(structure->indexingMode()));
267         ASSERT(globalObject->isHavingABadTime());
268
269         result->switchToSlowPutArrayStorage(vm);
270         ASSERT(result->butterfly() != immutableButterfly->toButterfly());
271         ASSERT(!result->butterfly()->arrayStorage()->m_sparseMap.get());
272         ASSERT(result->structureID() == structure->id());
273     }
274
275     return result;
276 }
277
278 } // namespace CommonSlowPaths
279
280 class ExecState;
281 struct Instruction;
282
283 #define SLOW_PATH
284     
285 #define SLOW_PATH_DECL(name) \
286 extern "C" SlowPathReturnType SLOW_PATH name(ExecState* exec, Instruction* pc)
287     
288 #define SLOW_PATH_HIDDEN_DECL(name) \
289 SLOW_PATH_DECL(name) WTF_INTERNAL
290     
291 SLOW_PATH_HIDDEN_DECL(slow_path_call_arityCheck);
292 SLOW_PATH_HIDDEN_DECL(slow_path_construct_arityCheck);
293 SLOW_PATH_HIDDEN_DECL(slow_path_create_direct_arguments);
294 SLOW_PATH_HIDDEN_DECL(slow_path_create_scoped_arguments);
295 SLOW_PATH_HIDDEN_DECL(slow_path_create_cloned_arguments);
296 SLOW_PATH_HIDDEN_DECL(slow_path_create_this);
297 SLOW_PATH_HIDDEN_DECL(slow_path_enter);
298 SLOW_PATH_HIDDEN_DECL(slow_path_get_callee);
299 SLOW_PATH_HIDDEN_DECL(slow_path_to_this);
300 SLOW_PATH_HIDDEN_DECL(slow_path_throw_tdz_error);
301 SLOW_PATH_HIDDEN_DECL(slow_path_check_tdz);
302 SLOW_PATH_HIDDEN_DECL(slow_path_throw_strict_mode_readonly_property_write_error);
303 SLOW_PATH_HIDDEN_DECL(slow_path_not);
304 SLOW_PATH_HIDDEN_DECL(slow_path_eq);
305 SLOW_PATH_HIDDEN_DECL(slow_path_neq);
306 SLOW_PATH_HIDDEN_DECL(slow_path_stricteq);
307 SLOW_PATH_HIDDEN_DECL(slow_path_nstricteq);
308 SLOW_PATH_HIDDEN_DECL(slow_path_less);
309 SLOW_PATH_HIDDEN_DECL(slow_path_lesseq);
310 SLOW_PATH_HIDDEN_DECL(slow_path_greater);
311 SLOW_PATH_HIDDEN_DECL(slow_path_greatereq);
312 SLOW_PATH_HIDDEN_DECL(slow_path_inc);
313 SLOW_PATH_HIDDEN_DECL(slow_path_dec);
314 SLOW_PATH_HIDDEN_DECL(slow_path_to_number);
315 SLOW_PATH_HIDDEN_DECL(slow_path_to_string);
316 SLOW_PATH_HIDDEN_DECL(slow_path_to_object);
317 SLOW_PATH_HIDDEN_DECL(slow_path_negate);
318 SLOW_PATH_HIDDEN_DECL(slow_path_add);
319 SLOW_PATH_HIDDEN_DECL(slow_path_mul);
320 SLOW_PATH_HIDDEN_DECL(slow_path_sub);
321 SLOW_PATH_HIDDEN_DECL(slow_path_div);
322 SLOW_PATH_HIDDEN_DECL(slow_path_mod);
323 SLOW_PATH_HIDDEN_DECL(slow_path_pow);
324 SLOW_PATH_HIDDEN_DECL(slow_path_lshift);
325 SLOW_PATH_HIDDEN_DECL(slow_path_rshift);
326 SLOW_PATH_HIDDEN_DECL(slow_path_urshift);
327 SLOW_PATH_HIDDEN_DECL(slow_path_unsigned);
328 SLOW_PATH_HIDDEN_DECL(slow_path_bitand);
329 SLOW_PATH_HIDDEN_DECL(slow_path_bitor);
330 SLOW_PATH_HIDDEN_DECL(slow_path_bitxor);
331 SLOW_PATH_HIDDEN_DECL(slow_path_typeof);
332 SLOW_PATH_HIDDEN_DECL(slow_path_is_object);
333 SLOW_PATH_HIDDEN_DECL(slow_path_is_object_or_null);
334 SLOW_PATH_HIDDEN_DECL(slow_path_is_function);
335 SLOW_PATH_HIDDEN_DECL(slow_path_in_by_id);
336 SLOW_PATH_HIDDEN_DECL(slow_path_in_by_val);
337 SLOW_PATH_HIDDEN_DECL(slow_path_del_by_val);
338 SLOW_PATH_HIDDEN_DECL(slow_path_strcat);
339 SLOW_PATH_HIDDEN_DECL(slow_path_to_primitive);
340 SLOW_PATH_HIDDEN_DECL(slow_path_get_enumerable_length);
341 SLOW_PATH_HIDDEN_DECL(slow_path_has_generic_property);
342 SLOW_PATH_HIDDEN_DECL(slow_path_has_structure_property);
343 SLOW_PATH_HIDDEN_DECL(slow_path_has_indexed_property);
344 SLOW_PATH_HIDDEN_DECL(slow_path_get_direct_pname);
345 SLOW_PATH_HIDDEN_DECL(slow_path_get_property_enumerator);
346 SLOW_PATH_HIDDEN_DECL(slow_path_next_structure_enumerator_pname);
347 SLOW_PATH_HIDDEN_DECL(slow_path_next_generic_enumerator_pname);
348 SLOW_PATH_HIDDEN_DECL(slow_path_to_index_string);
349 SLOW_PATH_HIDDEN_DECL(slow_path_profile_type_clear_log);
350 SLOW_PATH_HIDDEN_DECL(slow_path_unreachable);
351 SLOW_PATH_HIDDEN_DECL(slow_path_create_lexical_environment);
352 SLOW_PATH_HIDDEN_DECL(slow_path_push_with_scope);
353 SLOW_PATH_HIDDEN_DECL(slow_path_resolve_scope);
354 SLOW_PATH_HIDDEN_DECL(slow_path_is_var_scope);
355 SLOW_PATH_HIDDEN_DECL(slow_path_resolve_scope_for_hoisting_func_decl_in_eval);
356 SLOW_PATH_HIDDEN_DECL(slow_path_create_rest);
357 SLOW_PATH_HIDDEN_DECL(slow_path_get_by_id_with_this);
358 SLOW_PATH_HIDDEN_DECL(slow_path_get_by_val_with_this);
359 SLOW_PATH_HIDDEN_DECL(slow_path_put_by_id_with_this);
360 SLOW_PATH_HIDDEN_DECL(slow_path_put_by_val_with_this);
361 SLOW_PATH_HIDDEN_DECL(slow_path_define_data_property);
362 SLOW_PATH_HIDDEN_DECL(slow_path_define_accessor_property);
363 SLOW_PATH_HIDDEN_DECL(slow_path_throw_static_error);
364 SLOW_PATH_HIDDEN_DECL(slow_path_new_array_with_spread);
365 SLOW_PATH_HIDDEN_DECL(slow_path_new_array_buffer);
366 SLOW_PATH_HIDDEN_DECL(slow_path_spread);
367
368 using SlowPathFunction = SlowPathReturnType(SLOW_PATH *)(ExecState*, Instruction*);
369
370 } // namespace JSC