1/*
2 * Copyright (C) 2013-2019 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#include "config.h"
27#include "JITOperations.h"
28
29#if ENABLE(JIT)
30
31#include "ArithProfile.h"
32#include "ArrayConstructor.h"
33#include "CommonSlowPaths.h"
34#include "DFGCompilationMode.h"
35#include "DFGDriver.h"
36#include "DFGOSREntry.h"
37#include "DFGThunks.h"
38#include "DFGWorklist.h"
39#include "Debugger.h"
40#include "DirectArguments.h"
41#include "Error.h"
42#include "ErrorHandlingScope.h"
43#include "EvalCodeBlock.h"
44#include "ExceptionFuzz.h"
45#include "ExecutableBaseInlines.h"
46#include "FTLOSREntry.h"
47#include "FrameTracers.h"
48#include "FunctionCodeBlock.h"
49#include "GetterSetter.h"
50#include "HostCallReturnValue.h"
51#include "ICStats.h"
52#include "Interpreter.h"
53#include "JIT.h"
54#include "JITExceptions.h"
55#include "JITToDFGDeferredCompilationCallback.h"
56#include "JSAsyncFunction.h"
57#include "JSAsyncGenerator.h"
58#include "JSAsyncGeneratorFunction.h"
59#include "JSCInlines.h"
60#include "JSCPtrTag.h"
61#include "JSGeneratorFunction.h"
62#include "JSGlobalObjectFunctions.h"
63#include "JSInternalPromise.h"
64#include "JSLexicalEnvironment.h"
65#include "JSWithScope.h"
66#include "ModuleProgramCodeBlock.h"
67#include "ObjectConstructor.h"
68#include "PolymorphicAccess.h"
69#include "ProgramCodeBlock.h"
70#include "PropertyName.h"
71#include "RegExpObject.h"
72#include "Repatch.h"
73#include "ScopedArguments.h"
74#include "ShadowChicken.h"
75#include "StructureStubInfo.h"
76#include "SuperSampler.h"
77#include "TestRunnerUtils.h"
78#include "ThunkGenerators.h"
79#include "TypeProfilerLog.h"
80#include "VMInlines.h"
81#include "WebAssemblyFunction.h"
82#include <wtf/InlineASM.h>
83
84IGNORE_WARNINGS_BEGIN("frame-address")
85
86namespace JSC {
87
88ALWAYS_INLINE JSValue profiledAdd(JSGlobalObject* globalObject, JSValue op1, JSValue op2, BinaryArithProfile& arithProfile)
89{
90 arithProfile.observeLHSAndRHS(op1, op2);
91 JSValue result = jsAdd(globalObject, op1, op2);
92 arithProfile.observeResult(result);
93 return result;
94}
95
96extern "C" {
97
98#if COMPILER(MSVC)
99void * _ReturnAddress(void);
100#pragma intrinsic(_ReturnAddress)
101
102#define OUR_RETURN_ADDRESS _ReturnAddress()
103#else
104#define OUR_RETURN_ADDRESS __builtin_return_address(0)
105#endif
106
107#if ENABLE(OPCODE_SAMPLING)
108#define CTI_SAMPLER vm.interpreter->sampler()
109#else
110#define CTI_SAMPLER 0
111#endif
112
113
114void JIT_OPERATION operationThrowStackOverflowError(CodeBlock* codeBlock)
115{
116 // We pass in our own code block, because the callframe hasn't been populated.
117 VM& vm = codeBlock->vm();
118 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
119 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
120 auto scope = DECLARE_THROW_SCOPE(vm);
121 callFrame->convertToStackOverflowFrame(vm, codeBlock);
122 throwStackOverflowError(codeBlock->globalObject(), scope);
123}
124
125void JIT_OPERATION operationThrowStackOverflowErrorFromThunk(JSGlobalObject* globalObject)
126{
127 VM& vm = globalObject->vm();
128 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
129 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
130 auto scope = DECLARE_THROW_SCOPE(vm);
131 throwStackOverflowError(globalObject, scope);
132 genericUnwind(vm, callFrame);
133 ASSERT(vm.targetMachinePCForThrow);
134}
135
136int32_t JIT_OPERATION operationCallArityCheck(JSGlobalObject* globalObject)
137{
138 VM& vm = globalObject->vm();
139 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
140 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
141 auto scope = DECLARE_THROW_SCOPE(vm);
142
143 int32_t missingArgCount = CommonSlowPaths::arityCheckFor(vm, callFrame, CodeForCall);
144 if (UNLIKELY(missingArgCount < 0)) {
145 CodeBlock* codeBlock = CommonSlowPaths::codeBlockFromCallFrameCallee(callFrame, CodeForCall);
146 callFrame->convertToStackOverflowFrame(vm, codeBlock);
147 throwStackOverflowError(globalObject, scope);
148 }
149
150 return missingArgCount;
151}
152
153int32_t JIT_OPERATION operationConstructArityCheck(JSGlobalObject* globalObject)
154{
155 VM& vm = globalObject->vm();
156 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
157 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
158 auto scope = DECLARE_THROW_SCOPE(vm);
159
160 int32_t missingArgCount = CommonSlowPaths::arityCheckFor(vm, callFrame, CodeForConstruct);
161 if (UNLIKELY(missingArgCount < 0)) {
162 CodeBlock* codeBlock = CommonSlowPaths::codeBlockFromCallFrameCallee(callFrame, CodeForConstruct);
163 callFrame->convertToStackOverflowFrame(vm, codeBlock);
164 throwStackOverflowError(globalObject, scope);
165 }
166
167 return missingArgCount;
168}
169
170EncodedJSValue JIT_OPERATION operationTryGetById(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid)
171{
172 VM& vm = globalObject->vm();
173 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
174 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
175 Identifier ident = Identifier::fromUid(vm, uid);
176 stubInfo->tookSlowPath = true;
177
178 JSValue baseValue = JSValue::decode(base);
179 PropertySlot slot(baseValue, PropertySlot::InternalMethodType::VMInquiry);
180 baseValue.getPropertySlot(globalObject, ident, slot);
181
182 return JSValue::encode(slot.getPureResult());
183}
184
185
186EncodedJSValue JIT_OPERATION operationTryGetByIdGeneric(JSGlobalObject* globalObject, EncodedJSValue base, UniquedStringImpl* uid)
187{
188 VM& vm = globalObject->vm();
189 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
190 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
191 Identifier ident = Identifier::fromUid(vm, uid);
192
193 JSValue baseValue = JSValue::decode(base);
194 PropertySlot slot(baseValue, PropertySlot::InternalMethodType::VMInquiry);
195 baseValue.getPropertySlot(globalObject, ident, slot);
196
197 return JSValue::encode(slot.getPureResult());
198}
199
200EncodedJSValue JIT_OPERATION operationTryGetByIdOptimize(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid)
201{
202 VM& vm = globalObject->vm();
203 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
204 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
205 auto scope = DECLARE_THROW_SCOPE(vm);
206 Identifier ident = Identifier::fromUid(vm, uid);
207
208 JSValue baseValue = JSValue::decode(base);
209 PropertySlot slot(baseValue, PropertySlot::InternalMethodType::VMInquiry);
210
211 baseValue.getPropertySlot(globalObject, ident, slot);
212 RETURN_IF_EXCEPTION(scope, encodedJSValue());
213
214 CodeBlock* codeBlock = callFrame->codeBlock();
215 if (stubInfo->considerCaching(vm, codeBlock, baseValue.structureOrNull()) && !slot.isTaintedByOpaqueObject() && (slot.isCacheableValue() || slot.isCacheableGetter() || slot.isUnset()))
216 repatchGetBy(globalObject, codeBlock, baseValue, ident, slot, *stubInfo, GetByKind::Try);
217
218 return JSValue::encode(slot.getPureResult());
219}
220
221EncodedJSValue JIT_OPERATION operationGetByIdDirect(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid)
222{
223 VM& vm = globalObject->vm();
224 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
225 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
226 auto scope = DECLARE_THROW_SCOPE(vm);
227 Identifier ident = Identifier::fromUid(vm, uid);
228 stubInfo->tookSlowPath = true;
229
230 JSValue baseValue = JSValue::decode(base);
231 PropertySlot slot(baseValue, PropertySlot::InternalMethodType::GetOwnProperty);
232
233 bool found = baseValue.getOwnPropertySlot(globalObject, ident, slot);
234 RETURN_IF_EXCEPTION(scope, encodedJSValue());
235
236 RELEASE_AND_RETURN(scope, JSValue::encode(found ? slot.getValue(globalObject, ident) : jsUndefined()));
237}
238
239EncodedJSValue JIT_OPERATION operationGetByIdDirectGeneric(JSGlobalObject* globalObject, EncodedJSValue base, UniquedStringImpl* uid)
240{
241 VM& vm = globalObject->vm();
242 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
243 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
244 auto scope = DECLARE_THROW_SCOPE(vm);
245 Identifier ident = Identifier::fromUid(vm, uid);
246
247 JSValue baseValue = JSValue::decode(base);
248 PropertySlot slot(baseValue, PropertySlot::InternalMethodType::GetOwnProperty);
249
250 bool found = baseValue.getOwnPropertySlot(globalObject, ident, slot);
251 RETURN_IF_EXCEPTION(scope, encodedJSValue());
252
253 RELEASE_AND_RETURN(scope, JSValue::encode(found ? slot.getValue(globalObject, ident) : jsUndefined()));
254}
255
256EncodedJSValue JIT_OPERATION operationGetByIdDirectOptimize(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid)
257{
258 VM& vm = globalObject->vm();
259 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
260 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
261 auto scope = DECLARE_THROW_SCOPE(vm);
262 Identifier ident = Identifier::fromUid(vm, uid);
263
264 JSValue baseValue = JSValue::decode(base);
265 PropertySlot slot(baseValue, PropertySlot::InternalMethodType::GetOwnProperty);
266
267 bool found = baseValue.getOwnPropertySlot(globalObject, ident, slot);
268 RETURN_IF_EXCEPTION(scope, encodedJSValue());
269
270 CodeBlock* codeBlock = callFrame->codeBlock();
271 if (stubInfo->considerCaching(vm, codeBlock, baseValue.structureOrNull()))
272 repatchGetBy(globalObject, codeBlock, baseValue, ident, slot, *stubInfo, GetByKind::Direct);
273
274 RELEASE_AND_RETURN(scope, JSValue::encode(found ? slot.getValue(globalObject, ident) : jsUndefined()));
275}
276
277EncodedJSValue JIT_OPERATION operationGetById(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid)
278{
279 SuperSamplerScope superSamplerScope(false);
280
281 VM& vm = globalObject->vm();
282 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
283 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
284
285 stubInfo->tookSlowPath = true;
286
287 JSValue baseValue = JSValue::decode(base);
288 PropertySlot slot(baseValue, PropertySlot::InternalMethodType::Get);
289 Identifier ident = Identifier::fromUid(vm, uid);
290 JSValue result = baseValue.get(globalObject, ident, slot);
291
292 LOG_IC((ICEvent::OperationGetById, baseValue.classInfoOrNull(vm), ident, baseValue == slot.slotBase()));
293
294 return JSValue::encode(result);
295}
296
297EncodedJSValue JIT_OPERATION operationGetByIdGeneric(JSGlobalObject* globalObject, EncodedJSValue base, UniquedStringImpl* uid)
298{
299 SuperSamplerScope superSamplerScope(false);
300
301 VM& vm = globalObject->vm();
302 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
303 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
304
305 JSValue baseValue = JSValue::decode(base);
306 PropertySlot slot(baseValue, PropertySlot::InternalMethodType::Get);
307 Identifier ident = Identifier::fromUid(vm, uid);
308 JSValue result = baseValue.get(globalObject, ident, slot);
309
310 LOG_IC((ICEvent::OperationGetByIdGeneric, baseValue.classInfoOrNull(vm), ident, baseValue == slot.slotBase()));
311
312 return JSValue::encode(result);
313}
314
315EncodedJSValue JIT_OPERATION operationGetByIdOptimize(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid)
316{
317 SuperSamplerScope superSamplerScope(false);
318
319 VM& vm = globalObject->vm();
320 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
321 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
322 Identifier ident = Identifier::fromUid(vm, uid);
323
324 JSValue baseValue = JSValue::decode(base);
325
326 return JSValue::encode(baseValue.getPropertySlot(globalObject, ident, [&] (bool found, PropertySlot& slot) -> JSValue {
327
328 LOG_IC((ICEvent::OperationGetByIdOptimize, baseValue.classInfoOrNull(vm), ident, baseValue == slot.slotBase()));
329
330 CodeBlock* codeBlock = callFrame->codeBlock();
331 if (stubInfo->considerCaching(vm, codeBlock, baseValue.structureOrNull()))
332 repatchGetBy(globalObject, codeBlock, baseValue, ident, slot, *stubInfo, GetByKind::Normal);
333 return found ? slot.getValue(globalObject, ident) : jsUndefined();
334 }));
335}
336
337EncodedJSValue JIT_OPERATION operationGetByIdWithThis(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, EncodedJSValue base, EncodedJSValue thisEncoded, UniquedStringImpl* uid)
338{
339 SuperSamplerScope superSamplerScope(false);
340
341 VM& vm = globalObject->vm();
342 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
343 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
344 Identifier ident = Identifier::fromUid(vm, uid);
345
346 stubInfo->tookSlowPath = true;
347
348 JSValue baseValue = JSValue::decode(base);
349 JSValue thisValue = JSValue::decode(thisEncoded);
350 PropertySlot slot(thisValue, PropertySlot::InternalMethodType::Get);
351
352 return JSValue::encode(baseValue.get(globalObject, ident, slot));
353}
354
355EncodedJSValue JIT_OPERATION operationGetByIdWithThisGeneric(JSGlobalObject* globalObject, EncodedJSValue base, EncodedJSValue thisEncoded, UniquedStringImpl* uid)
356{
357 SuperSamplerScope superSamplerScope(false);
358
359 VM& vm = globalObject->vm();
360 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
361 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
362 Identifier ident = Identifier::fromUid(vm, uid);
363
364 JSValue baseValue = JSValue::decode(base);
365 JSValue thisValue = JSValue::decode(thisEncoded);
366 PropertySlot slot(thisValue, PropertySlot::InternalMethodType::Get);
367
368 return JSValue::encode(baseValue.get(globalObject, ident, slot));
369}
370
371EncodedJSValue JIT_OPERATION operationGetByIdWithThisOptimize(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, EncodedJSValue base, EncodedJSValue thisEncoded, UniquedStringImpl* uid)
372{
373 SuperSamplerScope superSamplerScope(false);
374
375 VM& vm = globalObject->vm();
376 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
377 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
378 Identifier ident = Identifier::fromUid(vm, uid);
379
380 JSValue baseValue = JSValue::decode(base);
381 JSValue thisValue = JSValue::decode(thisEncoded);
382
383 PropertySlot slot(thisValue, PropertySlot::InternalMethodType::Get);
384 return JSValue::encode(baseValue.getPropertySlot(globalObject, ident, slot, [&] (bool found, PropertySlot& slot) -> JSValue {
385 LOG_IC((ICEvent::OperationGetByIdWithThisOptimize, baseValue.classInfoOrNull(vm), ident, baseValue == slot.slotBase()));
386
387 CodeBlock* codeBlock = callFrame->codeBlock();
388 if (stubInfo->considerCaching(vm, codeBlock, baseValue.structureOrNull()))
389 repatchGetBy(globalObject, codeBlock, baseValue, ident, slot, *stubInfo, GetByKind::WithThis);
390 return found ? slot.getValue(globalObject, ident) : jsUndefined();
391 }));
392}
393
394EncodedJSValue JIT_OPERATION operationInById(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid)
395{
396 SuperSamplerScope superSamplerScope(false);
397
398 VM& vm = globalObject->vm();
399 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
400 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
401 auto scope = DECLARE_THROW_SCOPE(vm);
402
403 stubInfo->tookSlowPath = true;
404
405 Identifier ident = Identifier::fromUid(vm, uid);
406
407 JSValue baseValue = JSValue::decode(base);
408 if (!baseValue.isObject()) {
409 throwException(globalObject, scope, createInvalidInParameterError(globalObject, baseValue));
410 return JSValue::encode(jsUndefined());
411 }
412 JSObject* baseObject = asObject(baseValue);
413
414 LOG_IC((ICEvent::OperationInById, baseObject->classInfo(vm), ident));
415
416 scope.release();
417 PropertySlot slot(baseObject, PropertySlot::InternalMethodType::HasProperty);
418 return JSValue::encode(jsBoolean(baseObject->getPropertySlot(globalObject, ident, slot)));
419}
420
421EncodedJSValue JIT_OPERATION operationInByIdGeneric(JSGlobalObject* globalObject, EncodedJSValue base, UniquedStringImpl* uid)
422{
423 SuperSamplerScope superSamplerScope(false);
424
425 VM& vm = globalObject->vm();
426 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
427 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
428 auto scope = DECLARE_THROW_SCOPE(vm);
429
430 Identifier ident = Identifier::fromUid(vm, uid);
431
432 JSValue baseValue = JSValue::decode(base);
433 if (!baseValue.isObject()) {
434 throwException(globalObject, scope, createInvalidInParameterError(globalObject, baseValue));
435 return JSValue::encode(jsUndefined());
436 }
437 JSObject* baseObject = asObject(baseValue);
438
439 LOG_IC((ICEvent::OperationInByIdGeneric, baseObject->classInfo(vm), ident));
440
441 scope.release();
442 PropertySlot slot(baseObject, PropertySlot::InternalMethodType::HasProperty);
443 return JSValue::encode(jsBoolean(baseObject->getPropertySlot(globalObject, ident, slot)));
444}
445
446EncodedJSValue JIT_OPERATION operationInByIdOptimize(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid)
447{
448 SuperSamplerScope superSamplerScope(false);
449
450 VM& vm = globalObject->vm();
451 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
452 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
453 auto scope = DECLARE_THROW_SCOPE(vm);
454
455 Identifier ident = Identifier::fromUid(vm, uid);
456
457 JSValue baseValue = JSValue::decode(base);
458 if (!baseValue.isObject()) {
459 throwException(globalObject, scope, createInvalidInParameterError(globalObject, baseValue));
460 return JSValue::encode(jsUndefined());
461 }
462 JSObject* baseObject = asObject(baseValue);
463
464 LOG_IC((ICEvent::OperationInByIdOptimize, baseObject->classInfo(vm), ident));
465
466 scope.release();
467 PropertySlot slot(baseObject, PropertySlot::InternalMethodType::HasProperty);
468 bool found = baseObject->getPropertySlot(globalObject, ident, slot);
469 CodeBlock* codeBlock = callFrame->codeBlock();
470 if (stubInfo->considerCaching(vm, codeBlock, baseObject->structure(vm)))
471 repatchInByID(globalObject, codeBlock, baseObject, ident, found, slot, *stubInfo);
472 return JSValue::encode(jsBoolean(found));
473}
474
475EncodedJSValue JIT_OPERATION operationInByVal(JSGlobalObject* globalObject, JSCell* base, EncodedJSValue key)
476{
477 SuperSamplerScope superSamplerScope(false);
478
479 VM& vm = globalObject->vm();
480 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
481 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
482
483 return JSValue::encode(jsBoolean(CommonSlowPaths::opInByVal(globalObject, base, JSValue::decode(key))));
484}
485
486void JIT_OPERATION operationPutByIdStrict(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
487{
488 SuperSamplerScope superSamplerScope(false);
489
490 VM& vm = globalObject->vm();
491 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
492 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
493
494 stubInfo->tookSlowPath = true;
495
496 JSValue baseValue = JSValue::decode(encodedBase);
497 Identifier ident = Identifier::fromUid(vm, uid);
498 PutPropertySlot slot(baseValue, true, callFrame->codeBlock()->putByIdContext());
499 baseValue.putInline(globalObject, ident, JSValue::decode(encodedValue), slot);
500
501 LOG_IC((ICEvent::OperationPutByIdStrict, baseValue.classInfoOrNull(vm), ident, slot.base() == baseValue));
502}
503
504void JIT_OPERATION operationPutByIdNonStrict(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
505{
506 SuperSamplerScope superSamplerScope(false);
507
508 VM& vm = globalObject->vm();
509 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
510 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
511
512 stubInfo->tookSlowPath = true;
513
514 JSValue baseValue = JSValue::decode(encodedBase);
515 Identifier ident = Identifier::fromUid(vm, uid);
516 PutPropertySlot slot(baseValue, false, callFrame->codeBlock()->putByIdContext());
517 baseValue.putInline(globalObject, ident, JSValue::decode(encodedValue), slot);
518
519 LOG_IC((ICEvent::OperationPutByIdNonStrict, baseValue.classInfoOrNull(vm), ident, slot.base() == baseValue));
520}
521
522void JIT_OPERATION operationPutByIdDirectStrict(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
523{
524 SuperSamplerScope superSamplerScope(false);
525
526 VM& vm = globalObject->vm();
527 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
528 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
529
530 stubInfo->tookSlowPath = true;
531
532 JSValue baseValue = JSValue::decode(encodedBase);
533 Identifier ident = Identifier::fromUid(vm, uid);
534 PutPropertySlot slot(baseValue, true, callFrame->codeBlock()->putByIdContext());
535 CommonSlowPaths::putDirectWithReify(vm, globalObject, asObject(baseValue), ident, JSValue::decode(encodedValue), slot);
536
537 LOG_IC((ICEvent::OperationPutByIdDirectStrict, baseValue.classInfoOrNull(vm), ident, slot.base() == baseValue));
538}
539
540void JIT_OPERATION operationPutByIdDirectNonStrict(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
541{
542 SuperSamplerScope superSamplerScope(false);
543
544 VM& vm = globalObject->vm();
545 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
546 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
547
548 stubInfo->tookSlowPath = true;
549
550 JSValue baseValue = JSValue::decode(encodedBase);
551 Identifier ident = Identifier::fromUid(vm, uid);
552 PutPropertySlot slot(baseValue, false, callFrame->codeBlock()->putByIdContext());
553 CommonSlowPaths::putDirectWithReify(vm, globalObject, asObject(baseValue), ident, JSValue::decode(encodedValue), slot);
554
555 LOG_IC((ICEvent::OperationPutByIdDirectNonStrict, baseValue.classInfoOrNull(vm), ident, slot.base() == baseValue));
556}
557
558void JIT_OPERATION operationPutByIdStrictOptimize(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
559{
560 SuperSamplerScope superSamplerScope(false);
561
562 VM& vm = globalObject->vm();
563 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
564 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
565 auto scope = DECLARE_THROW_SCOPE(vm);
566
567 Identifier ident = Identifier::fromUid(vm, uid);
568 AccessType accessType = static_cast<AccessType>(stubInfo->accessType);
569
570 JSValue value = JSValue::decode(encodedValue);
571 JSValue baseValue = JSValue::decode(encodedBase);
572 CodeBlock* codeBlock = callFrame->codeBlock();
573 PutPropertySlot slot(baseValue, true, codeBlock->putByIdContext());
574
575 Structure* structure = baseValue.isCell() ? baseValue.asCell()->structure(vm) : nullptr;
576 baseValue.putInline(globalObject, ident, value, slot);
577
578 LOG_IC((ICEvent::OperationPutByIdStrictOptimize, baseValue.classInfoOrNull(vm), ident, slot.base() == baseValue));
579
580 RETURN_IF_EXCEPTION(scope, void());
581
582 if (accessType != static_cast<AccessType>(stubInfo->accessType))
583 return;
584
585 if (stubInfo->considerCaching(vm, codeBlock, structure))
586 repatchPutByID(globalObject, codeBlock, baseValue, structure, ident, slot, *stubInfo, NotDirect);
587}
588
589void JIT_OPERATION operationPutByIdNonStrictOptimize(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
590{
591 SuperSamplerScope superSamplerScope(false);
592
593 VM& vm = globalObject->vm();
594 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
595 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
596 auto scope = DECLARE_THROW_SCOPE(vm);
597
598 Identifier ident = Identifier::fromUid(vm, uid);
599 AccessType accessType = static_cast<AccessType>(stubInfo->accessType);
600
601 JSValue value = JSValue::decode(encodedValue);
602 JSValue baseValue = JSValue::decode(encodedBase);
603 CodeBlock* codeBlock = callFrame->codeBlock();
604 PutPropertySlot slot(baseValue, false, codeBlock->putByIdContext());
605
606 Structure* structure = baseValue.isCell() ? baseValue.asCell()->structure(vm) : nullptr;
607 baseValue.putInline(globalObject, ident, value, slot);
608
609 LOG_IC((ICEvent::OperationPutByIdNonStrictOptimize, baseValue.classInfoOrNull(vm), ident, slot.base() == baseValue));
610
611 RETURN_IF_EXCEPTION(scope, void());
612
613 if (accessType != static_cast<AccessType>(stubInfo->accessType))
614 return;
615
616 if (stubInfo->considerCaching(vm, codeBlock, structure))
617 repatchPutByID(globalObject, codeBlock, baseValue, structure, ident, slot, *stubInfo, NotDirect);
618}
619
620void JIT_OPERATION operationPutByIdDirectStrictOptimize(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
621{
622 SuperSamplerScope superSamplerScope(false);
623
624 VM& vm = globalObject->vm();
625 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
626 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
627 auto scope = DECLARE_THROW_SCOPE(vm);
628
629 Identifier ident = Identifier::fromUid(vm, uid);
630 AccessType accessType = static_cast<AccessType>(stubInfo->accessType);
631
632 JSValue value = JSValue::decode(encodedValue);
633 JSObject* baseObject = asObject(JSValue::decode(encodedBase));
634 CodeBlock* codeBlock = callFrame->codeBlock();
635 PutPropertySlot slot(baseObject, true, codeBlock->putByIdContext());
636 Structure* structure = nullptr;
637 CommonSlowPaths::putDirectWithReify(vm, globalObject, baseObject, ident, value, slot, &structure);
638
639 LOG_IC((ICEvent::OperationPutByIdDirectStrictOptimize, baseObject->classInfo(vm), ident, slot.base() == baseObject));
640
641 RETURN_IF_EXCEPTION(scope, void());
642
643 if (accessType != static_cast<AccessType>(stubInfo->accessType))
644 return;
645
646 if (stubInfo->considerCaching(vm, codeBlock, structure))
647 repatchPutByID(globalObject, codeBlock, baseObject, structure, ident, slot, *stubInfo, Direct);
648}
649
650void JIT_OPERATION operationPutByIdDirectNonStrictOptimize(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
651{
652 SuperSamplerScope superSamplerScope(false);
653
654 VM& vm = globalObject->vm();
655 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
656 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
657 auto scope = DECLARE_THROW_SCOPE(vm);
658
659 Identifier ident = Identifier::fromUid(vm, uid);
660 AccessType accessType = static_cast<AccessType>(stubInfo->accessType);
661
662 JSValue value = JSValue::decode(encodedValue);
663 JSObject* baseObject = asObject(JSValue::decode(encodedBase));
664 CodeBlock* codeBlock = callFrame->codeBlock();
665 PutPropertySlot slot(baseObject, false, codeBlock->putByIdContext());
666 Structure* structure = nullptr;
667 CommonSlowPaths::putDirectWithReify(vm, globalObject, baseObject, ident, value, slot, &structure);
668
669 LOG_IC((ICEvent::OperationPutByIdDirectNonStrictOptimize, baseObject->classInfo(vm), ident, slot.base() == baseObject));
670
671 RETURN_IF_EXCEPTION(scope, void());
672
673 if (accessType != static_cast<AccessType>(stubInfo->accessType))
674 return;
675
676 if (stubInfo->considerCaching(vm, codeBlock, structure))
677 repatchPutByID(globalObject, codeBlock, baseObject, structure, ident, slot, *stubInfo, Direct);
678}
679
680ALWAYS_INLINE static bool isStringOrSymbol(JSValue value)
681{
682 return value.isString() || value.isSymbol();
683}
684
685static void putByVal(JSGlobalObject* globalObject, CodeBlock* codeBlock, JSValue baseValue, JSValue subscript, JSValue value, ByValInfo* byValInfo)
686{
687 VM& vm = globalObject->vm();
688 auto scope = DECLARE_THROW_SCOPE(vm);
689 if (LIKELY(subscript.isUInt32())) {
690 byValInfo->tookSlowPath = true;
691 uint32_t i = subscript.asUInt32();
692 if (baseValue.isObject()) {
693 JSObject* object = asObject(baseValue);
694 if (object->canSetIndexQuickly(i, value)) {
695 object->setIndexQuickly(vm, i, value);
696 return;
697 }
698
699 byValInfo->arrayProfile->setOutOfBounds();
700 scope.release();
701 object->methodTable(vm)->putByIndex(object, globalObject, i, value, codeBlock->isStrictMode());
702 return;
703 }
704
705 scope.release();
706 baseValue.putByIndex(globalObject, i, value, codeBlock->isStrictMode());
707 return;
708 } else if (subscript.isInt32()) {
709 byValInfo->tookSlowPath = true;
710 if (baseValue.isObject())
711 byValInfo->arrayProfile->setOutOfBounds();
712 }
713
714 auto property = subscript.toPropertyKey(globalObject);
715 // Don't put to an object if toString threw an exception.
716 RETURN_IF_EXCEPTION(scope, void());
717
718 if (byValInfo->stubInfo && (!isStringOrSymbol(subscript) || byValInfo->cachedId != property))
719 byValInfo->tookSlowPath = true;
720
721 scope.release();
722 PutPropertySlot slot(baseValue, codeBlock->isStrictMode());
723 baseValue.putInline(globalObject, property, value, slot);
724}
725
726static void directPutByVal(JSGlobalObject* globalObject, CodeBlock* codeBlock, JSObject* baseObject, JSValue subscript, JSValue value, ByValInfo* byValInfo)
727{
728 VM& vm = globalObject->vm();
729 auto scope = DECLARE_THROW_SCOPE(vm);
730 bool isStrictMode = codeBlock->isStrictMode();
731
732 if (LIKELY(subscript.isUInt32())) {
733 // Despite its name, JSValue::isUInt32 will return true only for positive boxed int32_t; all those values are valid array indices.
734 byValInfo->tookSlowPath = true;
735 uint32_t index = subscript.asUInt32();
736 ASSERT(isIndex(index));
737
738 switch (baseObject->indexingType()) {
739 case ALL_INT32_INDEXING_TYPES:
740 case ALL_DOUBLE_INDEXING_TYPES:
741 case ALL_CONTIGUOUS_INDEXING_TYPES:
742 case ALL_ARRAY_STORAGE_INDEXING_TYPES:
743 if (index < baseObject->butterfly()->vectorLength())
744 break;
745 FALLTHROUGH;
746 default:
747 byValInfo->arrayProfile->setOutOfBounds();
748 break;
749 }
750
751 scope.release();
752 baseObject->putDirectIndex(globalObject, index, value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
753 return;
754 }
755
756 if (subscript.isDouble()) {
757 double subscriptAsDouble = subscript.asDouble();
758 uint32_t subscriptAsUInt32 = static_cast<uint32_t>(subscriptAsDouble);
759 if (subscriptAsDouble == subscriptAsUInt32 && isIndex(subscriptAsUInt32)) {
760 byValInfo->tookSlowPath = true;
761 scope.release();
762 baseObject->putDirectIndex(globalObject, subscriptAsUInt32, value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
763 return;
764 }
765 }
766
767 // Don't put to an object if toString threw an exception.
768 auto property = subscript.toPropertyKey(globalObject);
769 RETURN_IF_EXCEPTION(scope, void());
770
771 if (Optional<uint32_t> index = parseIndex(property)) {
772 byValInfo->tookSlowPath = true;
773 scope.release();
774 baseObject->putDirectIndex(globalObject, index.value(), value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
775 return;
776 }
777
778 if (byValInfo->stubInfo && (!isStringOrSymbol(subscript) || byValInfo->cachedId != property))
779 byValInfo->tookSlowPath = true;
780
781 scope.release();
782 PutPropertySlot slot(baseObject, isStrictMode);
783 CommonSlowPaths::putDirectWithReify(vm, globalObject, baseObject, property, value, slot);
784}
785
786enum class OptimizationResult {
787 NotOptimized,
788 SeenOnce,
789 Optimized,
790 GiveUp,
791};
792
793static OptimizationResult tryPutByValOptimize(JSGlobalObject* globalObject, CallFrame* callFrame, CodeBlock* codeBlock, JSValue baseValue, JSValue subscript, ByValInfo* byValInfo, ReturnAddressPtr returnAddress)
794{
795 UNUSED_PARAM(callFrame);
796
797 // See if it's worth optimizing at all.
798 OptimizationResult optimizationResult = OptimizationResult::NotOptimized;
799
800 VM& vm = globalObject->vm();
801 auto scope = DECLARE_THROW_SCOPE(vm);
802
803 if (baseValue.isObject() && isCopyOnWrite(baseValue.getObject()->indexingMode()))
804 return OptimizationResult::GiveUp;
805
806 if (baseValue.isObject() && subscript.isInt32()) {
807 JSObject* object = asObject(baseValue);
808
809 ASSERT(callFrame->bytecodeIndex() != BytecodeIndex(0));
810 ASSERT(!byValInfo->stubRoutine);
811
812 Structure* structure = object->structure(vm);
813 if (hasOptimizableIndexing(structure)) {
814 // Attempt to optimize.
815 JITArrayMode arrayMode = jitArrayModeForStructure(structure);
816 if (jitArrayModePermitsPut(arrayMode) && arrayMode != byValInfo->arrayMode) {
817 ConcurrentJSLocker locker(codeBlock->m_lock);
818 byValInfo->arrayProfile->computeUpdatedPrediction(locker, codeBlock, structure);
819 JIT::compilePutByVal(locker, vm, codeBlock, byValInfo, returnAddress, arrayMode);
820 optimizationResult = OptimizationResult::Optimized;
821 }
822 }
823
824 // If we failed to patch and we have some object that intercepts indexed get, then don't even wait until 10 times.
825 if (optimizationResult != OptimizationResult::Optimized && object->structure(vm)->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero())
826 optimizationResult = OptimizationResult::GiveUp;
827 }
828
829 if (baseValue.isObject() && isStringOrSymbol(subscript)) {
830 const Identifier propertyName = subscript.toPropertyKey(globalObject);
831 RETURN_IF_EXCEPTION(scope, OptimizationResult::GiveUp);
832 if (subscript.isSymbol() || !parseIndex(propertyName)) {
833 ASSERT(callFrame->bytecodeIndex() != BytecodeIndex(0));
834 ASSERT(!byValInfo->stubRoutine);
835 if (byValInfo->seen) {
836 if (byValInfo->cachedId == propertyName) {
837 JIT::compilePutByValWithCachedId<OpPutByVal>(vm, codeBlock, byValInfo, returnAddress, NotDirect, propertyName);
838 optimizationResult = OptimizationResult::Optimized;
839 } else {
840 // Seem like a generic property access site.
841 optimizationResult = OptimizationResult::GiveUp;
842 }
843 } else {
844 ConcurrentJSLocker locker(codeBlock->m_lock);
845 byValInfo->seen = true;
846 byValInfo->cachedId = propertyName;
847 if (subscript.isSymbol())
848 byValInfo->cachedSymbol.set(vm, codeBlock, asSymbol(subscript));
849 optimizationResult = OptimizationResult::SeenOnce;
850 }
851 }
852 }
853
854 if (optimizationResult != OptimizationResult::Optimized && optimizationResult != OptimizationResult::SeenOnce) {
855 // If we take slow path more than 10 times without patching then make sure we
856 // never make that mistake again. For cases where we see non-index-intercepting
857 // objects, this gives 10 iterations worth of opportunity for us to observe
858 // that the put_by_val may be polymorphic. We count up slowPathCount even if
859 // the result is GiveUp.
860 if (++byValInfo->slowPathCount >= 10)
861 optimizationResult = OptimizationResult::GiveUp;
862 }
863
864 return optimizationResult;
865}
866
867void JIT_OPERATION operationPutByValOptimize(JSGlobalObject* globalObject, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ByValInfo* byValInfo)
868{
869 VM& vm = globalObject->vm();
870 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
871 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
872 auto scope = DECLARE_THROW_SCOPE(vm);
873
874 JSValue baseValue = JSValue::decode(encodedBaseValue);
875 JSValue subscript = JSValue::decode(encodedSubscript);
876 JSValue value = JSValue::decode(encodedValue);
877 CodeBlock* codeBlock = callFrame->codeBlock();
878 OptimizationResult result = tryPutByValOptimize(globalObject, callFrame, codeBlock, baseValue, subscript, byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS));
879 RETURN_IF_EXCEPTION(scope, void());
880 if (result == OptimizationResult::GiveUp) {
881 // Don't ever try to optimize.
882 byValInfo->tookSlowPath = true;
883 ctiPatchCallByReturnAddress(ReturnAddressPtr(OUR_RETURN_ADDRESS), operationPutByValGeneric);
884 }
885 RELEASE_AND_RETURN(scope, putByVal(globalObject, codeBlock, baseValue, subscript, value, byValInfo));
886}
887
888static OptimizationResult tryDirectPutByValOptimize(JSGlobalObject* globalObject, CallFrame* callFrame, CodeBlock* codeBlock, JSObject* object, JSValue subscript, ByValInfo* byValInfo, ReturnAddressPtr returnAddress)
889{
890 UNUSED_PARAM(callFrame);
891
892 // See if it's worth optimizing at all.
893 OptimizationResult optimizationResult = OptimizationResult::NotOptimized;
894
895 VM& vm = globalObject->vm();
896 auto scope = DECLARE_THROW_SCOPE(vm);
897
898 if (subscript.isInt32()) {
899 ASSERT(callFrame->bytecodeIndex() != BytecodeIndex(0));
900 ASSERT(!byValInfo->stubRoutine);
901
902 Structure* structure = object->structure(vm);
903 if (hasOptimizableIndexing(structure)) {
904 // Attempt to optimize.
905 JITArrayMode arrayMode = jitArrayModeForStructure(structure);
906 if (jitArrayModePermitsPutDirect(arrayMode) && arrayMode != byValInfo->arrayMode) {
907 ConcurrentJSLocker locker(codeBlock->m_lock);
908 byValInfo->arrayProfile->computeUpdatedPrediction(locker, codeBlock, structure);
909
910 JIT::compileDirectPutByVal(locker, vm, codeBlock, byValInfo, returnAddress, arrayMode);
911 optimizationResult = OptimizationResult::Optimized;
912 }
913 }
914
915 // If we failed to patch and we have some object that intercepts indexed get, then don't even wait until 10 times.
916 if (optimizationResult != OptimizationResult::Optimized && object->structure(vm)->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero())
917 optimizationResult = OptimizationResult::GiveUp;
918 } else if (isStringOrSymbol(subscript)) {
919 const Identifier propertyName = subscript.toPropertyKey(globalObject);
920 RETURN_IF_EXCEPTION(scope, OptimizationResult::GiveUp);
921 if (subscript.isSymbol() || !parseIndex(propertyName)) {
922 ASSERT(callFrame->bytecodeIndex() != BytecodeIndex(0));
923 ASSERT(!byValInfo->stubRoutine);
924 if (byValInfo->seen) {
925 if (byValInfo->cachedId == propertyName) {
926 JIT::compilePutByValWithCachedId<OpPutByValDirect>(vm, codeBlock, byValInfo, returnAddress, Direct, propertyName);
927 optimizationResult = OptimizationResult::Optimized;
928 } else {
929 // Seem like a generic property access site.
930 optimizationResult = OptimizationResult::GiveUp;
931 }
932 } else {
933 ConcurrentJSLocker locker(codeBlock->m_lock);
934 byValInfo->seen = true;
935 byValInfo->cachedId = propertyName;
936 if (subscript.isSymbol())
937 byValInfo->cachedSymbol.set(vm, codeBlock, asSymbol(subscript));
938 optimizationResult = OptimizationResult::SeenOnce;
939 }
940 }
941 }
942
943 if (optimizationResult != OptimizationResult::Optimized && optimizationResult != OptimizationResult::SeenOnce) {
944 // If we take slow path more than 10 times without patching then make sure we
945 // never make that mistake again. For cases where we see non-index-intercepting
946 // objects, this gives 10 iterations worth of opportunity for us to observe
947 // that the get_by_val may be polymorphic. We count up slowPathCount even if
948 // the result is GiveUp.
949 if (++byValInfo->slowPathCount >= 10)
950 optimizationResult = OptimizationResult::GiveUp;
951 }
952
953 return optimizationResult;
954}
955
956void JIT_OPERATION operationDirectPutByValOptimize(JSGlobalObject* globalObject, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ByValInfo* byValInfo)
957{
958 VM& vm = globalObject->vm();
959 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
960 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
961 auto scope = DECLARE_THROW_SCOPE(vm);
962
963 JSValue baseValue = JSValue::decode(encodedBaseValue);
964 JSValue subscript = JSValue::decode(encodedSubscript);
965 JSValue value = JSValue::decode(encodedValue);
966 RELEASE_ASSERT(baseValue.isObject());
967 JSObject* object = asObject(baseValue);
968 CodeBlock* codeBlock = callFrame->codeBlock();
969 OptimizationResult result = tryDirectPutByValOptimize(globalObject, callFrame, codeBlock, object, subscript, byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS));
970 RETURN_IF_EXCEPTION(scope, void());
971 if (result == OptimizationResult::GiveUp) {
972 // Don't ever try to optimize.
973 byValInfo->tookSlowPath = true;
974 ctiPatchCallByReturnAddress(ReturnAddressPtr(OUR_RETURN_ADDRESS), operationDirectPutByValGeneric);
975 }
976
977 RELEASE_AND_RETURN(scope, directPutByVal(globalObject, codeBlock, object, subscript, value, byValInfo));
978}
979
980void JIT_OPERATION operationPutByValGeneric(JSGlobalObject* globalObject, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ByValInfo* byValInfo)
981{
982 VM& vm = globalObject->vm();
983 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
984 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
985
986 JSValue baseValue = JSValue::decode(encodedBaseValue);
987 JSValue subscript = JSValue::decode(encodedSubscript);
988 JSValue value = JSValue::decode(encodedValue);
989
990 putByVal(globalObject, callFrame->codeBlock(), baseValue, subscript, value, byValInfo);
991}
992
993
994void JIT_OPERATION operationDirectPutByValGeneric(JSGlobalObject* globalObject, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ByValInfo* byValInfo)
995{
996 VM& vm = globalObject->vm();
997 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
998 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
999
1000 JSValue baseValue = JSValue::decode(encodedBaseValue);
1001 JSValue subscript = JSValue::decode(encodedSubscript);
1002 JSValue value = JSValue::decode(encodedValue);
1003 RELEASE_ASSERT(baseValue.isObject());
1004 directPutByVal(globalObject, callFrame->codeBlock(), asObject(baseValue), subscript, value, byValInfo);
1005}
1006
1007EncodedJSValue JIT_OPERATION operationCallEval(JSGlobalObject* globalObject, CallFrame* calleeFrame)
1008{
1009 VM& vm = globalObject->vm();
1010 auto scope = DECLARE_THROW_SCOPE(vm);
1011
1012 calleeFrame->setCodeBlock(0);
1013
1014 if (!isHostFunction(calleeFrame->guaranteedJSValueCallee(), globalFuncEval))
1015 return JSValue::encode(JSValue());
1016
1017 JSValue result = eval(globalObject, calleeFrame);
1018 RETURN_IF_EXCEPTION(scope, encodedJSValue());
1019
1020 return JSValue::encode(result);
1021}
1022
1023static SlowPathReturnType handleHostCall(JSGlobalObject* globalObject, CallFrame* calleeFrame, JSValue callee, CallLinkInfo* callLinkInfo)
1024{
1025 VM& vm = globalObject->vm();
1026 auto scope = DECLARE_THROW_SCOPE(vm);
1027
1028 calleeFrame->setCodeBlock(0);
1029
1030 if (callLinkInfo->specializationKind() == CodeForCall) {
1031 CallData callData;
1032 CallType callType = getCallData(vm, callee, callData);
1033
1034 ASSERT(callType != CallType::JS);
1035
1036 if (callType == CallType::Host) {
1037 NativeCallFrameTracer tracer(vm, calleeFrame);
1038 calleeFrame->setCallee(asObject(callee));
1039 vm.hostCallReturnValue = JSValue::decode(callData.native.function(asObject(callee)->globalObject(vm), calleeFrame));
1040 if (UNLIKELY(scope.exception())) {
1041 return encodeResult(
1042 vm.getCTIStub(throwExceptionFromCallSlowPathGenerator).retaggedCode<JSEntryPtrTag>().executableAddress(),
1043 reinterpret_cast<void*>(KeepTheFrame));
1044 }
1045
1046 return encodeResult(
1047 tagCFunctionPtr<void*, JSEntryPtrTag>(getHostCallReturnValue),
1048 reinterpret_cast<void*>(callLinkInfo->callMode() == CallMode::Tail ? ReuseTheFrame : KeepTheFrame));
1049 }
1050
1051 ASSERT(callType == CallType::None);
1052 throwException(globalObject, scope, createNotAFunctionError(globalObject, callee));
1053 return encodeResult(
1054 vm.getCTIStub(throwExceptionFromCallSlowPathGenerator).retaggedCode<JSEntryPtrTag>().executableAddress(),
1055 reinterpret_cast<void*>(KeepTheFrame));
1056 }
1057
1058 ASSERT(callLinkInfo->specializationKind() == CodeForConstruct);
1059
1060 ConstructData constructData;
1061 ConstructType constructType = getConstructData(vm, callee, constructData);
1062
1063 ASSERT(constructType != ConstructType::JS);
1064
1065 if (constructType == ConstructType::Host) {
1066 NativeCallFrameTracer tracer(vm, calleeFrame);
1067 calleeFrame->setCallee(asObject(callee));
1068 vm.hostCallReturnValue = JSValue::decode(constructData.native.function(asObject(callee)->globalObject(vm), calleeFrame));
1069 if (UNLIKELY(scope.exception())) {
1070 return encodeResult(
1071 vm.getCTIStub(throwExceptionFromCallSlowPathGenerator).retaggedCode<JSEntryPtrTag>().executableAddress(),
1072 reinterpret_cast<void*>(KeepTheFrame));
1073 }
1074
1075 return encodeResult(tagCFunctionPtr<void*, JSEntryPtrTag>(getHostCallReturnValue), reinterpret_cast<void*>(KeepTheFrame));
1076 }
1077
1078 ASSERT(constructType == ConstructType::None);
1079 throwException(globalObject, scope, createNotAConstructorError(globalObject, callee));
1080 return encodeResult(
1081 vm.getCTIStub(throwExceptionFromCallSlowPathGenerator).retaggedCode<JSEntryPtrTag>().executableAddress(),
1082 reinterpret_cast<void*>(KeepTheFrame));
1083}
1084
1085SlowPathReturnType JIT_OPERATION operationLinkCall(CallFrame* calleeFrame, JSGlobalObject* globalObject, CallLinkInfo* callLinkInfo)
1086{
1087 CallFrame* callFrame = calleeFrame->callerFrame();
1088 VM& vm = globalObject->vm();
1089 auto throwScope = DECLARE_THROW_SCOPE(vm);
1090
1091 CodeSpecializationKind kind = callLinkInfo->specializationKind();
1092 NativeCallFrameTracer tracer(vm, callFrame);
1093
1094 RELEASE_ASSERT(!callLinkInfo->isDirect());
1095
1096 JSValue calleeAsValue = calleeFrame->guaranteedJSValueCallee();
1097 JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue);
1098 if (!calleeAsFunctionCell) {
1099 if (auto* internalFunction = jsDynamicCast<InternalFunction*>(vm, calleeAsValue)) {
1100 MacroAssemblerCodePtr<JSEntryPtrTag> codePtr = vm.getCTIInternalFunctionTrampolineFor(kind);
1101 RELEASE_ASSERT(!!codePtr);
1102
1103 if (!callLinkInfo->seenOnce())
1104 callLinkInfo->setSeen();
1105 else
1106 linkFor(vm, calleeFrame, *callLinkInfo, nullptr, internalFunction, codePtr);
1107
1108 void* linkedTarget = codePtr.executableAddress();
1109 return encodeResult(linkedTarget, reinterpret_cast<void*>(callLinkInfo->callMode() == CallMode::Tail ? ReuseTheFrame : KeepTheFrame));
1110 }
1111 RELEASE_AND_RETURN(throwScope, handleHostCall(globalObject, calleeFrame, calleeAsValue, callLinkInfo));
1112 }
1113
1114 JSFunction* callee = jsCast<JSFunction*>(calleeAsFunctionCell);
1115 JSScope* scope = callee->scopeUnchecked();
1116 ExecutableBase* executable = callee->executable();
1117
1118 MacroAssemblerCodePtr<JSEntryPtrTag> codePtr;
1119 CodeBlock* codeBlock = nullptr;
1120 if (executable->isHostFunction()) {
1121 codePtr = jsToWasmICCodePtr(vm, kind, callee);
1122 if (!codePtr)
1123 codePtr = executable->entrypointFor(kind, MustCheckArity);
1124 } else {
1125 FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
1126
1127 auto handleThrowException = [&] () {
1128 void* throwTarget = vm.getCTIStub(throwExceptionFromCallSlowPathGenerator).retaggedCode<JSEntryPtrTag>().executableAddress();
1129 return encodeResult(throwTarget, reinterpret_cast<void*>(KeepTheFrame));
1130 };
1131
1132 if (!isCall(kind) && functionExecutable->constructAbility() == ConstructAbility::CannotConstruct) {
1133 throwException(globalObject, throwScope, createNotAConstructorError(globalObject, callee));
1134 return handleThrowException();
1135 }
1136
1137 CodeBlock** codeBlockSlot = calleeFrame->addressOfCodeBlock();
1138 Exception* error = functionExecutable->prepareForExecution<FunctionExecutable>(vm, callee, scope, kind, *codeBlockSlot);
1139 EXCEPTION_ASSERT(throwScope.exception() == error);
1140 if (UNLIKELY(error))
1141 return handleThrowException();
1142 codeBlock = *codeBlockSlot;
1143 ArityCheckMode arity;
1144 if (calleeFrame->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters()) || callLinkInfo->isVarargs())
1145 arity = MustCheckArity;
1146 else
1147 arity = ArityCheckNotRequired;
1148 codePtr = functionExecutable->entrypointFor(kind, arity);
1149 }
1150
1151 if (!callLinkInfo->seenOnce())
1152 callLinkInfo->setSeen();
1153 else
1154 linkFor(vm, calleeFrame, *callLinkInfo, codeBlock, callee, codePtr);
1155
1156 return encodeResult(codePtr.executableAddress(), reinterpret_cast<void*>(callLinkInfo->callMode() == CallMode::Tail ? ReuseTheFrame : KeepTheFrame));
1157}
1158
1159inline SlowPathReturnType virtualForWithFunction(JSGlobalObject* globalObject, CallFrame* calleeFrame, CallLinkInfo* callLinkInfo, JSCell*& calleeAsFunctionCell)
1160{
1161 CallFrame* callFrame = calleeFrame->callerFrame();
1162 VM& vm = globalObject->vm();
1163 auto throwScope = DECLARE_THROW_SCOPE(vm);
1164
1165 CodeSpecializationKind kind = callLinkInfo->specializationKind();
1166 NativeCallFrameTracer tracer(vm, callFrame);
1167
1168 JSValue calleeAsValue = calleeFrame->guaranteedJSValueCallee();
1169 calleeAsFunctionCell = getJSFunction(calleeAsValue);
1170 if (UNLIKELY(!calleeAsFunctionCell)) {
1171 if (jsDynamicCast<InternalFunction*>(vm, calleeAsValue)) {
1172 MacroAssemblerCodePtr<JSEntryPtrTag> codePtr = vm.getCTIInternalFunctionTrampolineFor(kind);
1173 ASSERT(!!codePtr);
1174 return encodeResult(codePtr.executableAddress(), reinterpret_cast<void*>(callLinkInfo->callMode() == CallMode::Tail ? ReuseTheFrame : KeepTheFrame));
1175 }
1176 RELEASE_AND_RETURN(throwScope, handleHostCall(globalObject, calleeFrame, calleeAsValue, callLinkInfo));
1177 }
1178
1179 JSFunction* function = jsCast<JSFunction*>(calleeAsFunctionCell);
1180 JSScope* scope = function->scopeUnchecked();
1181 ExecutableBase* executable = function->executable();
1182 if (UNLIKELY(!executable->hasJITCodeFor(kind))) {
1183 FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
1184
1185 if (!isCall(kind) && functionExecutable->constructAbility() == ConstructAbility::CannotConstruct) {
1186 throwException(globalObject, throwScope, createNotAConstructorError(globalObject, function));
1187 return encodeResult(
1188 vm.getCTIStub(throwExceptionFromCallSlowPathGenerator).retaggedCode<JSEntryPtrTag>().executableAddress(),
1189 reinterpret_cast<void*>(KeepTheFrame));
1190 }
1191
1192 CodeBlock** codeBlockSlot = calleeFrame->addressOfCodeBlock();
1193 Exception* error = functionExecutable->prepareForExecution<FunctionExecutable>(vm, function, scope, kind, *codeBlockSlot);
1194 EXCEPTION_ASSERT(throwScope.exception() == error);
1195 if (UNLIKELY(error)) {
1196 return encodeResult(
1197 vm.getCTIStub(throwExceptionFromCallSlowPathGenerator).retaggedCode<JSEntryPtrTag>().executableAddress(),
1198 reinterpret_cast<void*>(KeepTheFrame));
1199 }
1200 }
1201 return encodeResult(executable->entrypointFor(
1202 kind, MustCheckArity).executableAddress(),
1203 reinterpret_cast<void*>(callLinkInfo->callMode() == CallMode::Tail ? ReuseTheFrame : KeepTheFrame));
1204}
1205
1206SlowPathReturnType JIT_OPERATION operationLinkPolymorphicCall(CallFrame* calleeFrame, JSGlobalObject* globalObject, CallLinkInfo* callLinkInfo)
1207{
1208 ASSERT(callLinkInfo->specializationKind() == CodeForCall);
1209 JSCell* calleeAsFunctionCell;
1210 SlowPathReturnType result = virtualForWithFunction(globalObject, calleeFrame, callLinkInfo, calleeAsFunctionCell);
1211
1212 linkPolymorphicCall(globalObject, calleeFrame, *callLinkInfo, CallVariant(calleeAsFunctionCell));
1213
1214 return result;
1215}
1216
1217SlowPathReturnType JIT_OPERATION operationVirtualCall(CallFrame* calleeFrame, JSGlobalObject* globalObject, CallLinkInfo* callLinkInfo)
1218{
1219 JSCell* calleeAsFunctionCellIgnored;
1220 return virtualForWithFunction(globalObject, calleeFrame, callLinkInfo, calleeAsFunctionCellIgnored);
1221}
1222
1223size_t JIT_OPERATION operationCompareLess(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
1224{
1225 VM& vm = globalObject->vm();
1226 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1227 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1228
1229 return jsLess<true>(globalObject, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
1230}
1231
1232size_t JIT_OPERATION operationCompareLessEq(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
1233{
1234 VM& vm = globalObject->vm();
1235 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1236 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1237
1238 return jsLessEq<true>(globalObject, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
1239}
1240
1241size_t JIT_OPERATION operationCompareGreater(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
1242{
1243 VM& vm = globalObject->vm();
1244 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1245 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1246
1247 return jsLess<false>(globalObject, JSValue::decode(encodedOp2), JSValue::decode(encodedOp1));
1248}
1249
1250size_t JIT_OPERATION operationCompareGreaterEq(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
1251{
1252 VM& vm = globalObject->vm();
1253 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1254 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1255
1256 return jsLessEq<false>(globalObject, JSValue::decode(encodedOp2), JSValue::decode(encodedOp1));
1257}
1258
1259size_t JIT_OPERATION operationCompareEq(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
1260{
1261 VM& vm = globalObject->vm();
1262 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1263 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1264
1265 return JSValue::equalSlowCaseInline(globalObject, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
1266}
1267
1268#if USE(JSVALUE64)
1269EncodedJSValue JIT_OPERATION operationCompareStringEq(JSGlobalObject* globalObject, JSCell* left, JSCell* right)
1270#else
1271size_t JIT_OPERATION operationCompareStringEq(JSGlobalObject* globalObject, JSCell* left, JSCell* right)
1272#endif
1273{
1274 VM& vm = globalObject->vm();
1275 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1276 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1277
1278 bool result = asString(left)->equal(globalObject, asString(right));
1279#if USE(JSVALUE64)
1280 return JSValue::encode(jsBoolean(result));
1281#else
1282 return result;
1283#endif
1284}
1285
1286size_t JIT_OPERATION operationCompareStrictEq(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
1287{
1288 VM& vm = globalObject->vm();
1289 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1290 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1291
1292 JSValue src1 = JSValue::decode(encodedOp1);
1293 JSValue src2 = JSValue::decode(encodedOp2);
1294
1295 return JSValue::strictEqual(globalObject, src1, src2);
1296}
1297
1298EncodedJSValue JIT_OPERATION operationNewArrayWithProfile(JSGlobalObject* globalObject, ArrayAllocationProfile* profile, const JSValue* values, int size)
1299{
1300 VM& vm = globalObject->vm();
1301 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1302 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1303 return JSValue::encode(constructArrayNegativeIndexed(globalObject, profile, values, size));
1304}
1305
1306EncodedJSValue JIT_OPERATION operationNewArrayWithSizeAndProfile(JSGlobalObject* globalObject, ArrayAllocationProfile* profile, EncodedJSValue size)
1307{
1308 VM& vm = globalObject->vm();
1309 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1310 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1311 JSValue sizeValue = JSValue::decode(size);
1312 return JSValue::encode(constructArrayWithSizeQuirk(globalObject, profile, sizeValue));
1313}
1314
1315}
1316
1317template<typename FunctionType>
1318static EncodedJSValue newFunctionCommon(VM& vm, JSScope* scope, JSCell* functionExecutable, bool isInvalidated)
1319{
1320 ASSERT(functionExecutable->inherits<FunctionExecutable>(vm));
1321 if (isInvalidated)
1322 return JSValue::encode(FunctionType::createWithInvalidatedReallocationWatchpoint(vm, static_cast<FunctionExecutable*>(functionExecutable), scope));
1323 return JSValue::encode(FunctionType::create(vm, static_cast<FunctionExecutable*>(functionExecutable), scope));
1324}
1325
1326extern "C" {
1327
1328EncodedJSValue JIT_OPERATION operationNewFunction(VM* vmPointer, JSScope* scope, JSCell* functionExecutable)
1329{
1330 VM& vm = *vmPointer;
1331 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1332 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1333 return newFunctionCommon<JSFunction>(vm, scope, functionExecutable, false);
1334}
1335
1336EncodedJSValue JIT_OPERATION operationNewFunctionWithInvalidatedReallocationWatchpoint(VM* vmPointer, JSScope* scope, JSCell* functionExecutable)
1337{
1338 VM& vm = *vmPointer;
1339 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1340 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1341 return newFunctionCommon<JSFunction>(vm, scope, functionExecutable, true);
1342}
1343
1344EncodedJSValue JIT_OPERATION operationNewGeneratorFunction(VM* vmPointer, JSScope* scope, JSCell* functionExecutable)
1345{
1346 VM& vm = *vmPointer;
1347 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1348 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1349 return newFunctionCommon<JSGeneratorFunction>(vm, scope, functionExecutable, false);
1350}
1351
1352EncodedJSValue JIT_OPERATION operationNewGeneratorFunctionWithInvalidatedReallocationWatchpoint(VM* vmPointer, JSScope* scope, JSCell* functionExecutable)
1353{
1354 VM& vm = *vmPointer;
1355 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1356 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1357 return newFunctionCommon<JSGeneratorFunction>(vm, scope, functionExecutable, true);
1358}
1359
1360EncodedJSValue JIT_OPERATION operationNewAsyncFunction(VM* vmPointer, JSScope* scope, JSCell* functionExecutable)
1361{
1362 VM& vm = *vmPointer;
1363 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1364 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1365 return newFunctionCommon<JSAsyncFunction>(vm, scope, functionExecutable, false);
1366}
1367
1368EncodedJSValue JIT_OPERATION operationNewAsyncFunctionWithInvalidatedReallocationWatchpoint(VM* vmPointer, JSScope* scope, JSCell* functionExecutable)
1369{
1370 VM& vm = *vmPointer;
1371 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1372 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1373 return newFunctionCommon<JSAsyncFunction>(vm, scope, functionExecutable, true);
1374}
1375
1376EncodedJSValue JIT_OPERATION operationNewAsyncGeneratorFunction(VM* vmPointer, JSScope* scope, JSCell* functionExecutable)
1377{
1378 VM& vm = *vmPointer;
1379 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1380 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1381 return newFunctionCommon<JSAsyncGeneratorFunction>(vm, scope, functionExecutable, false);
1382}
1383
1384EncodedJSValue JIT_OPERATION operationNewAsyncGeneratorFunctionWithInvalidatedReallocationWatchpoint(VM* vmPointer, JSScope* scope, JSCell* functionExecutable)
1385{
1386 VM& vm = *vmPointer;
1387 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1388 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1389 return newFunctionCommon<JSAsyncGeneratorFunction>(vm, scope, functionExecutable, true);
1390}
1391
1392void JIT_OPERATION operationSetFunctionName(JSGlobalObject* globalObject, JSCell* funcCell, EncodedJSValue encodedName)
1393{
1394 VM& vm = globalObject->vm();
1395 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1396 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1397
1398 JSFunction* func = jsCast<JSFunction*>(funcCell);
1399 JSValue name = JSValue::decode(encodedName);
1400 func->setFunctionName(globalObject, name);
1401}
1402
1403JSCell* JIT_OPERATION operationNewObject(VM* vmPointer, Structure* structure)
1404{
1405 VM& vm = *vmPointer;
1406 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1407 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1408
1409 return constructEmptyObject(vm, structure);
1410}
1411
1412JSCell* JIT_OPERATION operationNewPromise(VM* vmPointer, Structure* structure)
1413{
1414 VM& vm = *vmPointer;
1415 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1416 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1417
1418 return JSPromise::create(vm, structure);
1419}
1420
1421JSCell* JIT_OPERATION operationNewInternalPromise(VM* vmPointer, Structure* structure)
1422{
1423 VM& vm = *vmPointer;
1424 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1425 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1426
1427 return JSInternalPromise::create(vm, structure);
1428}
1429
1430JSCell* JIT_OPERATION operationNewGenerator(VM* vmPointer, Structure* structure)
1431{
1432 VM& vm = *vmPointer;
1433 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1434 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1435
1436 return JSGenerator::create(vm, structure);
1437}
1438
1439JSCell* JIT_OPERATION operationNewAsyncGenerator(VM* vmPointer, Structure* structure)
1440{
1441 VM& vm = *vmPointer;
1442 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1443 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1444
1445 return JSAsyncGenerator::create(vm, structure);
1446}
1447
1448JSCell* JIT_OPERATION operationNewRegexp(JSGlobalObject* globalObject, JSCell* regexpPtr)
1449{
1450 SuperSamplerScope superSamplerScope(false);
1451 VM& vm = globalObject->vm();
1452 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1453 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1454
1455 RegExp* regexp = static_cast<RegExp*>(regexpPtr);
1456 ASSERT(regexp->isValid());
1457 return RegExpObject::create(vm, globalObject->regExpStructure(), regexp);
1458}
1459
1460// The only reason for returning an UnusedPtr (instead of void) is so that we can reuse the
1461// existing DFG slow path generator machinery when creating the slow path for CheckTraps
1462// in the DFG. If a DFG slow path generator that supports a void return type is added in the
1463// future, we can switch to using that then.
1464UnusedPtr JIT_OPERATION operationHandleTraps(JSGlobalObject* globalObject)
1465{
1466 VM& vm = globalObject->vm();
1467 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1468 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1469 ASSERT(vm.needTrapHandling());
1470 vm.handleTraps(globalObject, callFrame);
1471 return nullptr;
1472}
1473
1474void JIT_OPERATION operationDebug(VM* vmPointer, int32_t debugHookType)
1475{
1476 VM& vm = *vmPointer;
1477 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1478 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1479
1480 vm.interpreter->debug(callFrame, static_cast<DebugHookType>(debugHookType));
1481}
1482
1483#if ENABLE(DFG_JIT)
1484static void updateAllPredictionsAndOptimizeAfterWarmUp(CodeBlock* codeBlock)
1485{
1486 codeBlock->updateAllPredictions();
1487 codeBlock->optimizeAfterWarmUp();
1488}
1489
1490SlowPathReturnType JIT_OPERATION operationOptimize(VM* vmPointer, uint32_t bytecodeIndexBits)
1491{
1492 VM& vm = *vmPointer;
1493 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1494 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1495 BytecodeIndex bytecodeIndex = BytecodeIndex::fromBits(bytecodeIndexBits);
1496
1497 // Defer GC for a while so that it doesn't run between when we enter into this
1498 // slow path and when we figure out the state of our code block. This prevents
1499 // a number of awkward reentrancy scenarios, including:
1500 //
1501 // - The optimized version of our code block being jettisoned by GC right after
1502 // we concluded that we wanted to use it, but have not planted it into the JS
1503 // stack yet.
1504 //
1505 // - An optimized version of our code block being installed just as we decided
1506 // that it wasn't ready yet.
1507 //
1508 // Note that jettisoning won't happen if we already initiated OSR, because in
1509 // that case we would have already planted the optimized code block into the JS
1510 // stack.
1511 DeferGCForAWhile deferGC(vm.heap);
1512
1513 CodeBlock* codeBlock = callFrame->codeBlock();
1514 if (UNLIKELY(codeBlock->jitType() != JITType::BaselineJIT)) {
1515 dataLog("Unexpected code block in Baseline->DFG tier-up: ", *codeBlock, "\n");
1516 RELEASE_ASSERT_NOT_REACHED();
1517 }
1518
1519 if (bytecodeIndex) {
1520 // If we're attempting to OSR from a loop, assume that this should be
1521 // separately optimized.
1522 codeBlock->m_shouldAlwaysBeInlined = false;
1523 }
1524
1525 if (UNLIKELY(Options::verboseOSR())) {
1526 dataLog(
1527 *codeBlock, ": Entered optimize with bytecodeIndex = ", bytecodeIndex,
1528 ", executeCounter = ", codeBlock->jitExecuteCounter(),
1529 ", optimizationDelayCounter = ", codeBlock->reoptimizationRetryCounter(),
1530 ", exitCounter = ");
1531 if (codeBlock->hasOptimizedReplacement())
1532 dataLog(codeBlock->replacement()->osrExitCounter());
1533 else
1534 dataLog("N/A");
1535 dataLog("\n");
1536 }
1537
1538 if (!codeBlock->checkIfOptimizationThresholdReached()) {
1539 CODEBLOCK_LOG_EVENT(codeBlock, "delayOptimizeToDFG", ("counter = ", codeBlock->jitExecuteCounter()));
1540 codeBlock->updateAllPredictions();
1541 if (UNLIKELY(Options::verboseOSR()))
1542 dataLog("Choosing not to optimize ", *codeBlock, " yet, because the threshold hasn't been reached.\n");
1543 return encodeResult(0, 0);
1544 }
1545
1546 Debugger* debugger = codeBlock->globalObject()->debugger();
1547 if (UNLIKELY(debugger && (debugger->isStepping() || codeBlock->baselineAlternative()->hasDebuggerRequests()))) {
1548 CODEBLOCK_LOG_EVENT(codeBlock, "delayOptimizeToDFG", ("debugger is stepping or has requests"));
1549 updateAllPredictionsAndOptimizeAfterWarmUp(codeBlock);
1550 return encodeResult(0, 0);
1551 }
1552
1553 if (codeBlock->m_shouldAlwaysBeInlined) {
1554 CODEBLOCK_LOG_EVENT(codeBlock, "delayOptimizeToDFG", ("should always be inlined"));
1555 updateAllPredictionsAndOptimizeAfterWarmUp(codeBlock);
1556 if (UNLIKELY(Options::verboseOSR()))
1557 dataLog("Choosing not to optimize ", *codeBlock, " yet, because m_shouldAlwaysBeInlined == true.\n");
1558 return encodeResult(0, 0);
1559 }
1560
1561 // We cannot be in the process of asynchronous compilation and also have an optimized
1562 // replacement.
1563 DFG::Worklist* worklist = DFG::existingGlobalDFGWorklistOrNull();
1564 ASSERT(
1565 !worklist
1566 || !(worklist->compilationState(DFG::CompilationKey(codeBlock, DFG::DFGMode)) != DFG::Worklist::NotKnown
1567 && codeBlock->hasOptimizedReplacement()));
1568
1569 DFG::Worklist::State worklistState;
1570 if (worklist) {
1571 // The call to DFG::Worklist::completeAllReadyPlansForVM() will complete all ready
1572 // (i.e. compiled) code blocks. But if it completes ours, we also need to know
1573 // what the result was so that we don't plow ahead and attempt OSR or immediate
1574 // reoptimization. This will have already also set the appropriate JIT execution
1575 // count threshold depending on what happened, so if the compilation was anything
1576 // but successful we just want to return early. See the case for worklistState ==
1577 // DFG::Worklist::Compiled, below.
1578
1579 // Note that we could have alternatively just called Worklist::compilationState()
1580 // here, and if it returned Compiled, we could have then called
1581 // completeAndScheduleOSR() below. But that would have meant that it could take
1582 // longer for code blocks to be completed: they would only complete when *their*
1583 // execution count trigger fired; but that could take a while since the firing is
1584 // racy. It could also mean that code blocks that never run again after being
1585 // compiled would sit on the worklist until next GC. That's fine, but it's
1586 // probably a waste of memory. Our goal here is to complete code blocks as soon as
1587 // possible in order to minimize the chances of us executing baseline code after
1588 // optimized code is already available.
1589 worklistState = worklist->completeAllReadyPlansForVM(
1590 vm, DFG::CompilationKey(codeBlock, DFG::DFGMode));
1591 } else
1592 worklistState = DFG::Worklist::NotKnown;
1593
1594 if (worklistState == DFG::Worklist::Compiling) {
1595 CODEBLOCK_LOG_EVENT(codeBlock, "delayOptimizeToDFG", ("compiling"));
1596 // We cannot be in the process of asynchronous compilation and also have an optimized
1597 // replacement.
1598 RELEASE_ASSERT(!codeBlock->hasOptimizedReplacement());
1599 codeBlock->setOptimizationThresholdBasedOnCompilationResult(CompilationDeferred);
1600 return encodeResult(0, 0);
1601 }
1602
1603 if (worklistState == DFG::Worklist::Compiled) {
1604 // If we don't have an optimized replacement but we did just get compiled, then
1605 // the compilation failed or was invalidated, in which case the execution count
1606 // thresholds have already been set appropriately by
1607 // CodeBlock::setOptimizationThresholdBasedOnCompilationResult() and we have
1608 // nothing left to do.
1609 if (!codeBlock->hasOptimizedReplacement()) {
1610 CODEBLOCK_LOG_EVENT(codeBlock, "delayOptimizeToDFG", ("compiled and failed"));
1611 codeBlock->updateAllPredictions();
1612 if (UNLIKELY(Options::verboseOSR()))
1613 dataLog("Code block ", *codeBlock, " was compiled but it doesn't have an optimized replacement.\n");
1614 return encodeResult(0, 0);
1615 }
1616 } else if (codeBlock->hasOptimizedReplacement()) {
1617 CodeBlock* replacement = codeBlock->replacement();
1618 if (UNLIKELY(Options::verboseOSR()))
1619 dataLog("Considering OSR ", codeBlock, " -> ", replacement, ".\n");
1620 // If we have an optimized replacement, then it must be the case that we entered
1621 // cti_optimize from a loop. That's because if there's an optimized replacement,
1622 // then all calls to this function will be relinked to the replacement and so
1623 // the prologue OSR will never fire.
1624
1625 // This is an interesting threshold check. Consider that a function OSR exits
1626 // in the middle of a loop, while having a relatively low exit count. The exit
1627 // will reset the execution counter to some target threshold, meaning that this
1628 // code won't be reached until that loop heats up for >=1000 executions. But then
1629 // we do a second check here, to see if we should either reoptimize, or just
1630 // attempt OSR entry. Hence it might even be correct for
1631 // shouldReoptimizeFromLoopNow() to always return true. But we make it do some
1632 // additional checking anyway, to reduce the amount of recompilation thrashing.
1633 if (replacement->shouldReoptimizeFromLoopNow()) {
1634 CODEBLOCK_LOG_EVENT(codeBlock, "delayOptimizeToDFG", ("should reoptimize from loop now"));
1635 if (UNLIKELY(Options::verboseOSR())) {
1636 dataLog(
1637 "Triggering reoptimization of ", codeBlock,
1638 "(", replacement, ") (in loop).\n");
1639 }
1640 replacement->jettison(Profiler::JettisonDueToBaselineLoopReoptimizationTrigger, CountReoptimization);
1641 return encodeResult(0, 0);
1642 }
1643 } else {
1644 if (!codeBlock->shouldOptimizeNow()) {
1645 CODEBLOCK_LOG_EVENT(codeBlock, "delayOptimizeToDFG", ("insufficient profiling"));
1646 if (UNLIKELY(Options::verboseOSR())) {
1647 dataLog(
1648 "Delaying optimization for ", *codeBlock,
1649 " because of insufficient profiling.\n");
1650 }
1651 return encodeResult(0, 0);
1652 }
1653
1654 if (UNLIKELY(Options::verboseOSR()))
1655 dataLog("Triggering optimized compilation of ", *codeBlock, "\n");
1656
1657 unsigned numVarsWithValues;
1658 if (bytecodeIndex)
1659 numVarsWithValues = codeBlock->numCalleeLocals();
1660 else
1661 numVarsWithValues = 0;
1662 Operands<Optional<JSValue>> mustHandleValues(codeBlock->numParameters(), numVarsWithValues);
1663 int localsUsedForCalleeSaves = static_cast<int>(CodeBlock::llintBaselineCalleeSaveSpaceAsVirtualRegisters());
1664 for (size_t i = 0; i < mustHandleValues.size(); ++i) {
1665 int operand = mustHandleValues.operandForIndex(i);
1666 if (operandIsLocal(operand) && VirtualRegister(operand).toLocal() < localsUsedForCalleeSaves)
1667 continue;
1668 mustHandleValues[i] = callFrame->uncheckedR(operand).jsValue();
1669 }
1670
1671 CodeBlock* replacementCodeBlock = codeBlock->newReplacement();
1672 CompilationResult result = DFG::compile(
1673 vm, replacementCodeBlock, nullptr, DFG::DFGMode, bytecodeIndex,
1674 mustHandleValues, JITToDFGDeferredCompilationCallback::create());
1675
1676 if (result != CompilationSuccessful) {
1677 CODEBLOCK_LOG_EVENT(codeBlock, "delayOptimizeToDFG", ("compilation failed"));
1678 return encodeResult(0, 0);
1679 }
1680 }
1681
1682 CodeBlock* optimizedCodeBlock = codeBlock->replacement();
1683 ASSERT(optimizedCodeBlock && JITCode::isOptimizingJIT(optimizedCodeBlock->jitType()));
1684
1685 if (void* dataBuffer = DFG::prepareOSREntry(vm, callFrame, optimizedCodeBlock, bytecodeIndex)) {
1686 CODEBLOCK_LOG_EVENT(optimizedCodeBlock, "osrEntry", ("at bc#", bytecodeIndex));
1687 if (UNLIKELY(Options::verboseOSR())) {
1688 dataLog(
1689 "Performing OSR ", codeBlock, " -> ", optimizedCodeBlock, ".\n");
1690 }
1691
1692 codeBlock->optimizeSoon();
1693 codeBlock->unlinkedCodeBlock()->setDidOptimize(TrueTriState);
1694 void* targetPC = vm.getCTIStub(DFG::osrEntryThunkGenerator).code().executableAddress();
1695 targetPC = retagCodePtr(targetPC, JITThunkPtrTag, bitwise_cast<PtrTag>(callFrame));
1696 return encodeResult(targetPC, dataBuffer);
1697 }
1698
1699 if (UNLIKELY(Options::verboseOSR())) {
1700 dataLog(
1701 "Optimizing ", codeBlock, " -> ", codeBlock->replacement(),
1702 " succeeded, OSR failed, after a delay of ",
1703 codeBlock->optimizationDelayCounter(), ".\n");
1704 }
1705
1706 // Count the OSR failure as a speculation failure. If this happens a lot, then
1707 // reoptimize.
1708 optimizedCodeBlock->countOSRExit();
1709
1710 // We are a lot more conservative about triggering reoptimization after OSR failure than
1711 // before it. If we enter the optimize_from_loop trigger with a bucket full of fail
1712 // already, then we really would like to reoptimize immediately. But this case covers
1713 // something else: there weren't many (or any) speculation failures before, but we just
1714 // failed to enter the speculative code because some variable had the wrong value or
1715 // because the OSR code decided for any spurious reason that it did not want to OSR
1716 // right now. So, we only trigger reoptimization only upon the more conservative (non-loop)
1717 // reoptimization trigger.
1718 if (optimizedCodeBlock->shouldReoptimizeNow()) {
1719 CODEBLOCK_LOG_EVENT(codeBlock, "delayOptimizeToDFG", ("should reoptimize now"));
1720 if (UNLIKELY(Options::verboseOSR())) {
1721 dataLog(
1722 "Triggering reoptimization of ", codeBlock, " -> ",
1723 codeBlock->replacement(), " (after OSR fail).\n");
1724 }
1725 optimizedCodeBlock->jettison(Profiler::JettisonDueToBaselineLoopReoptimizationTriggerOnOSREntryFail, CountReoptimization);
1726 return encodeResult(0, 0);
1727 }
1728
1729 // OSR failed this time, but it might succeed next time! Let the code run a bit
1730 // longer and then try again.
1731 codeBlock->optimizeAfterWarmUp();
1732
1733 CODEBLOCK_LOG_EVENT(codeBlock, "delayOptimizeToDFG", ("OSR failed"));
1734 return encodeResult(0, 0);
1735}
1736
1737char* JIT_OPERATION operationTryOSREnterAtCatch(VM* vmPointer, uint32_t bytecodeIndexBits)
1738{
1739 VM& vm = *vmPointer;
1740 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1741 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1742 BytecodeIndex bytecodeIndex = BytecodeIndex::fromBits(bytecodeIndexBits);
1743
1744 CodeBlock* codeBlock = callFrame->codeBlock();
1745 CodeBlock* optimizedReplacement = codeBlock->replacement();
1746 if (UNLIKELY(!optimizedReplacement))
1747 return nullptr;
1748
1749 switch (optimizedReplacement->jitType()) {
1750 case JITType::DFGJIT:
1751 case JITType::FTLJIT: {
1752 MacroAssemblerCodePtr<ExceptionHandlerPtrTag> entry = DFG::prepareCatchOSREntry(vm, callFrame, codeBlock, optimizedReplacement, bytecodeIndex);
1753 return entry.executableAddress<char*>();
1754 }
1755 default:
1756 break;
1757 }
1758 return nullptr;
1759}
1760
1761char* JIT_OPERATION operationTryOSREnterAtCatchAndValueProfile(VM* vmPointer, uint32_t bytecodeIndexBits)
1762{
1763 VM& vm = *vmPointer;
1764 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1765 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1766 BytecodeIndex bytecodeIndex = BytecodeIndex::fromBits(bytecodeIndexBits);
1767
1768 CodeBlock* codeBlock = callFrame->codeBlock();
1769 CodeBlock* optimizedReplacement = codeBlock->replacement();
1770 if (UNLIKELY(!optimizedReplacement))
1771 return nullptr;
1772
1773 switch (optimizedReplacement->jitType()) {
1774 case JITType::DFGJIT:
1775 case JITType::FTLJIT: {
1776 MacroAssemblerCodePtr<ExceptionHandlerPtrTag> entry = DFG::prepareCatchOSREntry(vm, callFrame, codeBlock, optimizedReplacement, bytecodeIndex);
1777 return entry.executableAddress<char*>();
1778 }
1779 default:
1780 break;
1781 }
1782
1783 codeBlock->ensureCatchLivenessIsComputedForBytecodeIndex(bytecodeIndex);
1784 auto bytecode = codeBlock->instructions().at(bytecodeIndex)->as<OpCatch>();
1785 auto& metadata = bytecode.metadata(codeBlock);
1786 metadata.m_buffer->forEach([&] (ValueProfileAndOperand& profile) {
1787 profile.m_buckets[0] = JSValue::encode(callFrame->uncheckedR(profile.m_operand).jsValue());
1788 });
1789
1790 return nullptr;
1791}
1792
1793#endif
1794
1795void JIT_OPERATION operationPutByIndex(JSGlobalObject* globalObject, EncodedJSValue encodedArrayValue, int32_t index, EncodedJSValue encodedValue)
1796{
1797 VM& vm = globalObject->vm();
1798 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1799 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1800
1801 JSValue arrayValue = JSValue::decode(encodedArrayValue);
1802 ASSERT(isJSArray(arrayValue));
1803 asArray(arrayValue)->putDirectIndex(globalObject, index, JSValue::decode(encodedValue));
1804}
1805
1806enum class AccessorType {
1807 Getter,
1808 Setter
1809};
1810
1811static void putAccessorByVal(JSGlobalObject* globalObject, JSObject* base, JSValue subscript, int32_t attribute, JSObject* accessor, AccessorType accessorType)
1812{
1813 VM& vm = globalObject->vm();
1814 auto scope = DECLARE_THROW_SCOPE(vm);
1815 auto propertyKey = subscript.toPropertyKey(globalObject);
1816 RETURN_IF_EXCEPTION(scope, void());
1817
1818 scope.release();
1819 if (accessorType == AccessorType::Getter)
1820 base->putGetter(globalObject, propertyKey, accessor, attribute);
1821 else
1822 base->putSetter(globalObject, propertyKey, accessor, attribute);
1823}
1824
1825void JIT_OPERATION operationPutGetterById(JSGlobalObject* globalObject, JSCell* object, UniquedStringImpl* uid, int32_t options, JSCell* getter)
1826{
1827 VM& vm = globalObject->vm();
1828 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1829 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1830
1831 ASSERT(object && object->isObject());
1832 JSObject* baseObj = object->getObject();
1833
1834 ASSERT(getter->isObject());
1835 baseObj->putGetter(globalObject, uid, getter, options);
1836}
1837
1838void JIT_OPERATION operationPutSetterById(JSGlobalObject* globalObject, JSCell* object, UniquedStringImpl* uid, int32_t options, JSCell* setter)
1839{
1840 VM& vm = globalObject->vm();
1841 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1842 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1843
1844 ASSERT(object && object->isObject());
1845 JSObject* baseObj = object->getObject();
1846
1847 ASSERT(setter->isObject());
1848 baseObj->putSetter(globalObject, uid, setter, options);
1849}
1850
1851void JIT_OPERATION operationPutGetterByVal(JSGlobalObject* globalObject, JSCell* base, EncodedJSValue encodedSubscript, int32_t attribute, JSCell* getter)
1852{
1853 VM& vm = globalObject->vm();
1854 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1855 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1856
1857 putAccessorByVal(globalObject, asObject(base), JSValue::decode(encodedSubscript), attribute, asObject(getter), AccessorType::Getter);
1858}
1859
1860void JIT_OPERATION operationPutSetterByVal(JSGlobalObject* globalObject, JSCell* base, EncodedJSValue encodedSubscript, int32_t attribute, JSCell* setter)
1861{
1862 VM& vm = globalObject->vm();
1863 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1864 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1865
1866 putAccessorByVal(globalObject, asObject(base), JSValue::decode(encodedSubscript), attribute, asObject(setter), AccessorType::Setter);
1867}
1868
1869#if USE(JSVALUE64)
1870void JIT_OPERATION operationPutGetterSetter(JSGlobalObject* globalObject, JSCell* object, UniquedStringImpl* uid, int32_t attribute, EncodedJSValue encodedGetterValue, EncodedJSValue encodedSetterValue)
1871{
1872 VM& vm = globalObject->vm();
1873 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1874 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1875
1876 ASSERT(object && object->isObject());
1877 JSObject* baseObject = asObject(object);
1878
1879 JSValue getter = JSValue::decode(encodedGetterValue);
1880 JSValue setter = JSValue::decode(encodedSetterValue);
1881 ASSERT(getter.isObject() || setter.isObject());
1882 GetterSetter* accessor = GetterSetter::create(vm, globalObject, getter, setter);
1883 CommonSlowPaths::putDirectAccessorWithReify(vm, globalObject, baseObject, uid, accessor, attribute);
1884}
1885
1886#else
1887void JIT_OPERATION operationPutGetterSetter(JSGlobalObject* globalObject, JSCell* object, UniquedStringImpl* uid, int32_t attribute, JSCell* getterCell, JSCell* setterCell)
1888{
1889 VM& vm = globalObject->vm();
1890 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1891 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1892
1893 ASSERT(object && object->isObject());
1894 JSObject* baseObject = asObject(object);
1895
1896 ASSERT(getterCell || setterCell);
1897 JSObject* getter = getterCell ? getterCell->getObject() : nullptr;
1898 JSObject* setter = setterCell ? setterCell->getObject() : nullptr;
1899 GetterSetter* accessor = GetterSetter::create(vm, globalObject, getter, setter);
1900 CommonSlowPaths::putDirectAccessorWithReify(vm, globalObject, baseObject, uid, accessor, attribute);
1901}
1902#endif
1903
1904void JIT_OPERATION operationPopScope(JSGlobalObject* globalObject, int32_t scopeReg)
1905{
1906 VM& vm = globalObject->vm();
1907 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1908 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1909
1910 JSScope* scope = callFrame->uncheckedR(scopeReg).Register::scope();
1911 callFrame->uncheckedR(scopeReg) = scope->next();
1912}
1913
1914int32_t JIT_OPERATION operationInstanceOfCustom(JSGlobalObject* globalObject, EncodedJSValue encodedValue, JSObject* constructor, EncodedJSValue encodedHasInstance)
1915{
1916 VM& vm = globalObject->vm();
1917 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1918 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
1919
1920 JSValue value = JSValue::decode(encodedValue);
1921 JSValue hasInstanceValue = JSValue::decode(encodedHasInstance);
1922
1923 if (constructor->hasInstance(globalObject, value, hasInstanceValue))
1924 return 1;
1925 return 0;
1926}
1927
1928}
1929
1930ALWAYS_INLINE static JSValue getByVal(JSGlobalObject* globalObject, CallFrame* callFrame, ArrayProfile* arrayProfile, JSValue baseValue, JSValue subscript)
1931{
1932 UNUSED_PARAM(callFrame);
1933 VM& vm = globalObject->vm();
1934 auto scope = DECLARE_THROW_SCOPE(vm);
1935
1936 if (LIKELY(baseValue.isCell() && subscript.isString())) {
1937 Structure& structure = *baseValue.asCell()->structure(vm);
1938 if (JSCell::canUseFastGetOwnProperty(structure)) {
1939 RefPtr<AtomStringImpl> existingAtomString = asString(subscript)->toExistingAtomString(globalObject);
1940 RETURN_IF_EXCEPTION(scope, JSValue());
1941 if (existingAtomString) {
1942 if (JSValue result = baseValue.asCell()->fastGetOwnProperty(vm, structure, existingAtomString.get())) {
1943 ASSERT(callFrame->bytecodeIndex() != BytecodeIndex(0));
1944 return result;
1945 }
1946 }
1947 }
1948 }
1949
1950 if (subscript.isInt32()) {
1951 int32_t i = subscript.asInt32();
1952 if (isJSString(baseValue)) {
1953 if (i >= 0 && asString(baseValue)->canGetIndex(i))
1954 RELEASE_AND_RETURN(scope, asString(baseValue)->getIndex(globalObject, i));
1955 if (arrayProfile)
1956 arrayProfile->setOutOfBounds();
1957 } else if (baseValue.isObject()) {
1958 JSObject* object = asObject(baseValue);
1959 if (object->canGetIndexQuickly(i))
1960 return object->getIndexQuickly(i);
1961
1962 bool skipMarkingOutOfBounds = false;
1963
1964 if (object->indexingType() == ArrayWithContiguous && i >= 0 && static_cast<uint32_t>(i) < object->butterfly()->publicLength()) {
1965 // FIXME: expand this to ArrayStorage, Int32, and maybe Double:
1966 // https://bugs.webkit.org/show_bug.cgi?id=182940
1967 auto* globalObject = object->globalObject(vm);
1968 skipMarkingOutOfBounds = globalObject->isOriginalArrayStructure(object->structure(vm)) && globalObject->arrayPrototypeChainIsSane();
1969 }
1970
1971 if (!skipMarkingOutOfBounds && !CommonSlowPaths::canAccessArgumentIndexQuickly(*object, i)) {
1972 // FIXME: This will make us think that in-bounds typed array accesses are actually
1973 // out-of-bounds.
1974 // https://bugs.webkit.org/show_bug.cgi?id=149886
1975 if (arrayProfile)
1976 arrayProfile->setOutOfBounds();
1977 }
1978 }
1979
1980 if (i >= 0)
1981 RELEASE_AND_RETURN(scope, baseValue.get(globalObject, static_cast<uint32_t>(i)));
1982 }
1983
1984 baseValue.requireObjectCoercible(globalObject);
1985 RETURN_IF_EXCEPTION(scope, JSValue());
1986 auto property = subscript.toPropertyKey(globalObject);
1987 RETURN_IF_EXCEPTION(scope, JSValue());
1988
1989 ASSERT(callFrame->bytecodeIndex() != BytecodeIndex(0));
1990 RELEASE_AND_RETURN(scope, baseValue.get(globalObject, property));
1991}
1992
1993extern "C" {
1994
1995EncodedJSValue JIT_OPERATION operationGetByValGeneric(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, ArrayProfile* profile, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript)
1996{
1997 VM& vm = globalObject->vm();
1998 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
1999 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2000 JSValue baseValue = JSValue::decode(encodedBase);
2001 JSValue subscript = JSValue::decode(encodedSubscript);
2002
2003 stubInfo->tookSlowPath = true;
2004
2005 return JSValue::encode(getByVal(globalObject, callFrame, profile, baseValue, subscript));
2006}
2007
2008EncodedJSValue JIT_OPERATION operationGetByValOptimize(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, ArrayProfile* profile, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript)
2009{
2010 VM& vm = globalObject->vm();
2011 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2012 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2013 auto scope = DECLARE_THROW_SCOPE(vm);
2014
2015 JSValue baseValue = JSValue::decode(encodedBase);
2016 JSValue subscript = JSValue::decode(encodedSubscript);
2017
2018 CodeBlock* codeBlock = callFrame->codeBlock();
2019
2020 if (baseValue.isCell() && subscript.isInt32()) {
2021 Structure* structure = baseValue.asCell()->structure(vm);
2022 if (stubInfo->considerCaching(vm, codeBlock, structure)) {
2023 if (profile) {
2024 ConcurrentJSLocker locker(codeBlock->m_lock);
2025 profile->computeUpdatedPrediction(locker, codeBlock, structure);
2026 }
2027 repatchArrayGetByVal(globalObject, codeBlock, baseValue, subscript, *stubInfo);
2028 }
2029 }
2030
2031 if (baseValue.isCell() && isStringOrSymbol(subscript)) {
2032 const Identifier propertyName = subscript.toPropertyKey(globalObject);
2033 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2034 if (subscript.isSymbol() || !parseIndex(propertyName)) {
2035 scope.release();
2036 return JSValue::encode(baseValue.getPropertySlot(globalObject, propertyName, [&] (bool found, PropertySlot& slot) -> JSValue {
2037 LOG_IC((ICEvent::OperationGetByValOptimize, baseValue.classInfoOrNull(vm), propertyName, baseValue == slot.slotBase()));
2038
2039 if (stubInfo->considerCaching(vm, codeBlock, baseValue.structureOrNull(), propertyName.impl()))
2040 repatchGetBy(globalObject, codeBlock, baseValue, propertyName, slot, *stubInfo, GetByKind::NormalByVal);
2041 return found ? slot.getValue(globalObject, propertyName) : jsUndefined();
2042 }));
2043 }
2044 }
2045
2046 RELEASE_AND_RETURN(scope, JSValue::encode(getByVal(globalObject, callFrame, profile, baseValue, subscript)));
2047}
2048
2049EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(JSGlobalObject* globalObject, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ByValInfo* byValInfo)
2050{
2051 VM& vm = globalObject->vm();
2052 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2053 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2054 JSValue baseValue = JSValue::decode(encodedBase);
2055 JSValue subscript = JSValue::decode(encodedSubscript);
2056
2057 ASSERT(baseValue.isObject());
2058 ASSERT(subscript.isUInt32AsAnyInt());
2059
2060 JSObject* object = asObject(baseValue);
2061 bool didOptimize = false;
2062
2063 ASSERT(callFrame->bytecodeIndex() != BytecodeIndex(0));
2064 ASSERT(!byValInfo->stubRoutine);
2065
2066 if (hasOptimizableIndexing(object->structure(vm))) {
2067 // Attempt to optimize.
2068 JITArrayMode arrayMode = jitArrayModeForStructure(object->structure(vm));
2069 if (arrayMode != byValInfo->arrayMode) {
2070 JIT::compileHasIndexedProperty(vm, callFrame->codeBlock(), byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode);
2071 didOptimize = true;
2072 }
2073 }
2074
2075 if (!didOptimize) {
2076 // If we take slow path more than 10 times without patching then make sure we
2077 // never make that mistake again. Or, if we failed to patch and we have some object
2078 // that intercepts indexed get, then don't even wait until 10 times. For cases
2079 // where we see non-index-intercepting objects, this gives 10 iterations worth of
2080 // opportunity for us to observe that the get_by_val may be polymorphic.
2081 if (++byValInfo->slowPathCount >= 10
2082 || object->structure(vm)->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) {
2083 // Don't ever try to optimize.
2084 ctiPatchCallByReturnAddress(ReturnAddressPtr(OUR_RETURN_ADDRESS), operationHasIndexedPropertyGeneric);
2085 }
2086 }
2087
2088 uint32_t index = subscript.asUInt32AsAnyInt();
2089 if (object->canGetIndexQuickly(index))
2090 return JSValue::encode(JSValue(JSValue::JSTrue));
2091
2092 if (!CommonSlowPaths::canAccessArgumentIndexQuickly(*object, index))
2093 byValInfo->arrayProfile->setOutOfBounds();
2094 return JSValue::encode(jsBoolean(object->hasPropertyGeneric(globalObject, index, PropertySlot::InternalMethodType::GetOwnProperty)));
2095}
2096
2097EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(JSGlobalObject* globalObject, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ByValInfo* byValInfo)
2098{
2099 VM& vm = globalObject->vm();
2100 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2101 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2102 JSValue baseValue = JSValue::decode(encodedBase);
2103 JSValue subscript = JSValue::decode(encodedSubscript);
2104
2105 ASSERT(baseValue.isObject());
2106 ASSERT(subscript.isUInt32AsAnyInt());
2107
2108 JSObject* object = asObject(baseValue);
2109 uint32_t index = subscript.asUInt32AsAnyInt();
2110 if (object->canGetIndexQuickly(index))
2111 return JSValue::encode(JSValue(JSValue::JSTrue));
2112
2113 if (!CommonSlowPaths::canAccessArgumentIndexQuickly(*object, index))
2114 byValInfo->arrayProfile->setOutOfBounds();
2115 return JSValue::encode(jsBoolean(object->hasPropertyGeneric(globalObject, index, PropertySlot::InternalMethodType::GetOwnProperty)));
2116}
2117
2118static bool deleteById(JSGlobalObject* globalObject, CallFrame* callFrame, VM& vm, JSValue base, UniquedStringImpl* uid)
2119{
2120 auto scope = DECLARE_THROW_SCOPE(vm);
2121
2122 JSObject* baseObj = base.toObject(globalObject);
2123 RETURN_IF_EXCEPTION(scope, false);
2124 if (!baseObj)
2125 return false;
2126 bool couldDelete = baseObj->methodTable(vm)->deleteProperty(baseObj, globalObject, Identifier::fromUid(vm, uid));
2127 RETURN_IF_EXCEPTION(scope, false);
2128 if (!couldDelete && callFrame->codeBlock()->isStrictMode())
2129 throwTypeError(globalObject, scope, UnableToDeletePropertyError);
2130 return couldDelete;
2131}
2132
2133
2134EncodedJSValue JIT_OPERATION operationDeleteByIdJSResult(JSGlobalObject* globalObject, EncodedJSValue encodedBase, UniquedStringImpl* uid)
2135{
2136 VM& vm = globalObject->vm();
2137 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2138 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2139 return JSValue::encode(jsBoolean(deleteById(globalObject, callFrame, vm, JSValue::decode(encodedBase), uid)));
2140}
2141
2142size_t JIT_OPERATION operationDeleteById(JSGlobalObject* globalObject, EncodedJSValue encodedBase, UniquedStringImpl* uid)
2143{
2144 VM& vm = globalObject->vm();
2145 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2146 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2147 return deleteById(globalObject, callFrame, vm, JSValue::decode(encodedBase), uid);
2148}
2149
2150static bool deleteByVal(JSGlobalObject* globalObject, CallFrame* callFrame, VM& vm, JSValue base, JSValue key)
2151{
2152 auto scope = DECLARE_THROW_SCOPE(vm);
2153
2154 JSObject* baseObj = base.toObject(globalObject);
2155 RETURN_IF_EXCEPTION(scope, false);
2156 if (!baseObj)
2157 return false;
2158
2159 bool couldDelete;
2160 uint32_t index;
2161 if (key.getUInt32(index))
2162 couldDelete = baseObj->methodTable(vm)->deletePropertyByIndex(baseObj, globalObject, index);
2163 else {
2164 Identifier property = key.toPropertyKey(globalObject);
2165 RETURN_IF_EXCEPTION(scope, false);
2166 couldDelete = baseObj->methodTable(vm)->deleteProperty(baseObj, globalObject, property);
2167 }
2168 RETURN_IF_EXCEPTION(scope, false);
2169 if (!couldDelete && callFrame->codeBlock()->isStrictMode())
2170 throwTypeError(globalObject, scope, UnableToDeletePropertyError);
2171 return couldDelete;
2172}
2173
2174EncodedJSValue JIT_OPERATION operationDeleteByValJSResult(JSGlobalObject* globalObject, EncodedJSValue encodedBase, EncodedJSValue encodedKey)
2175{
2176 VM& vm = globalObject->vm();
2177 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2178 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2179 return JSValue::encode(jsBoolean(deleteByVal(globalObject, callFrame, vm, JSValue::decode(encodedBase), JSValue::decode(encodedKey))));
2180}
2181
2182size_t JIT_OPERATION operationDeleteByVal(JSGlobalObject* globalObject, EncodedJSValue encodedBase, EncodedJSValue encodedKey)
2183{
2184 VM& vm = globalObject->vm();
2185 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2186 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2187 return deleteByVal(globalObject, callFrame, vm, JSValue::decode(encodedBase), JSValue::decode(encodedKey));
2188}
2189
2190JSCell* JIT_OPERATION operationPushWithScope(JSGlobalObject* globalObject, JSCell* currentScopeCell, EncodedJSValue objectValue)
2191{
2192 VM& vm = globalObject->vm();
2193 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2194 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2195 auto scope = DECLARE_THROW_SCOPE(vm);
2196
2197 JSObject* object = JSValue::decode(objectValue).toObject(globalObject);
2198 RETURN_IF_EXCEPTION(scope, nullptr);
2199
2200 JSScope* currentScope = jsCast<JSScope*>(currentScopeCell);
2201
2202 return JSWithScope::create(vm, globalObject, currentScope, object);
2203}
2204
2205JSCell* JIT_OPERATION operationPushWithScopeObject(JSGlobalObject* globalObject, JSCell* currentScopeCell, JSObject* object)
2206{
2207 VM& vm = globalObject->vm();
2208 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2209 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2210 JSScope* currentScope = jsCast<JSScope*>(currentScopeCell);
2211 return JSWithScope::create(vm, globalObject, currentScope, object);
2212}
2213
2214EncodedJSValue JIT_OPERATION operationInstanceOf(JSGlobalObject* globalObject, EncodedJSValue encodedValue, EncodedJSValue encodedProto)
2215{
2216 VM& vm = globalObject->vm();
2217 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2218 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2219 JSValue value = JSValue::decode(encodedValue);
2220 JSValue proto = JSValue::decode(encodedProto);
2221
2222 bool result = JSObject::defaultHasInstance(globalObject, value, proto);
2223 return JSValue::encode(jsBoolean(result));
2224}
2225
2226EncodedJSValue JIT_OPERATION operationInstanceOfGeneric(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedProto)
2227{
2228 VM& vm = globalObject->vm();
2229 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2230 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2231 JSValue value = JSValue::decode(encodedValue);
2232 JSValue proto = JSValue::decode(encodedProto);
2233
2234 stubInfo->tookSlowPath = true;
2235
2236 bool result = JSObject::defaultHasInstance(globalObject, value, proto);
2237 return JSValue::encode(jsBoolean(result));
2238}
2239
2240EncodedJSValue JIT_OPERATION operationInstanceOfOptimize(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedProto)
2241{
2242 VM& vm = globalObject->vm();
2243 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2244 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2245 auto scope = DECLARE_THROW_SCOPE(vm);
2246 JSValue value = JSValue::decode(encodedValue);
2247 JSValue proto = JSValue::decode(encodedProto);
2248
2249 bool result = JSObject::defaultHasInstance(globalObject, value, proto);
2250 RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined()));
2251
2252 CodeBlock* codeBlock = callFrame->codeBlock();
2253 if (stubInfo->considerCaching(vm, codeBlock, value.structureOrNull()))
2254 repatchInstanceOf(globalObject, codeBlock, value, proto, *stubInfo, result);
2255
2256 return JSValue::encode(jsBoolean(result));
2257}
2258
2259int32_t JIT_OPERATION operationSizeFrameForForwardArguments(JSGlobalObject* globalObject, EncodedJSValue, int32_t numUsedStackSlots, int32_t)
2260{
2261 VM& vm = globalObject->vm();
2262 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2263 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2264 return sizeFrameForForwardArguments(globalObject, callFrame, vm, numUsedStackSlots);
2265}
2266
2267int32_t JIT_OPERATION operationSizeFrameForVarargs(JSGlobalObject* globalObject, EncodedJSValue encodedArguments, int32_t numUsedStackSlots, int32_t firstVarArgOffset)
2268{
2269 VM& vm = globalObject->vm();
2270 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2271 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2272 JSValue arguments = JSValue::decode(encodedArguments);
2273 return sizeFrameForVarargs(globalObject, callFrame, vm, arguments, numUsedStackSlots, firstVarArgOffset);
2274}
2275
2276CallFrame* JIT_OPERATION operationSetupForwardArgumentsFrame(JSGlobalObject* globalObject, CallFrame* newCallFrame, EncodedJSValue, int32_t, int32_t length)
2277{
2278 VM& vm = globalObject->vm();
2279 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2280 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2281 setupForwardArgumentsFrame(globalObject, callFrame, newCallFrame, length);
2282 return newCallFrame;
2283}
2284
2285CallFrame* JIT_OPERATION operationSetupVarargsFrame(JSGlobalObject* globalObject, CallFrame* newCallFrame, EncodedJSValue encodedArguments, int32_t firstVarArgOffset, int32_t length)
2286{
2287 VM& vm = globalObject->vm();
2288 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2289 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2290 JSValue arguments = JSValue::decode(encodedArguments);
2291 setupVarargsFrame(globalObject, callFrame, newCallFrame, arguments, firstVarArgOffset, length);
2292 return newCallFrame;
2293}
2294
2295char* JIT_OPERATION operationSwitchCharWithUnknownKeyType(JSGlobalObject* globalObject, EncodedJSValue encodedKey, size_t tableIndex)
2296{
2297 VM& vm = globalObject->vm();
2298 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2299 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2300 auto throwScope = DECLARE_THROW_SCOPE(vm);
2301
2302 JSValue key = JSValue::decode(encodedKey);
2303 CodeBlock* codeBlock = callFrame->codeBlock();
2304
2305 SimpleJumpTable& jumpTable = codeBlock->switchJumpTable(tableIndex);
2306 void* result = jumpTable.ctiDefault.executableAddress();
2307
2308 if (key.isString()) {
2309 JSString* string = asString(key);
2310 if (string->length() == 1) {
2311 String value = string->value(globalObject);
2312 RETURN_IF_EXCEPTION(throwScope, nullptr);
2313 result = jumpTable.ctiForValue(value[0]).executableAddress();
2314 }
2315 }
2316
2317 assertIsTaggedWith(result, JSSwitchPtrTag);
2318 return reinterpret_cast<char*>(result);
2319}
2320
2321char* JIT_OPERATION operationSwitchImmWithUnknownKeyType(VM* vmPointer, EncodedJSValue encodedKey, size_t tableIndex)
2322{
2323 VM& vm = *vmPointer;
2324 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2325 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2326 JSValue key = JSValue::decode(encodedKey);
2327 CodeBlock* codeBlock = callFrame->codeBlock();
2328
2329 SimpleJumpTable& jumpTable = codeBlock->switchJumpTable(tableIndex);
2330 void* result;
2331 if (key.isInt32())
2332 result = jumpTable.ctiForValue(key.asInt32()).executableAddress();
2333 else if (key.isDouble() && key.asDouble() == static_cast<int32_t>(key.asDouble()))
2334 result = jumpTable.ctiForValue(static_cast<int32_t>(key.asDouble())).executableAddress();
2335 else
2336 result = jumpTable.ctiDefault.executableAddress();
2337 assertIsTaggedWith(result, JSSwitchPtrTag);
2338 return reinterpret_cast<char*>(result);
2339}
2340
2341char* JIT_OPERATION operationSwitchStringWithUnknownKeyType(JSGlobalObject* globalObject, EncodedJSValue encodedKey, size_t tableIndex)
2342{
2343 VM& vm = globalObject->vm();
2344 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2345 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2346 JSValue key = JSValue::decode(encodedKey);
2347 CodeBlock* codeBlock = callFrame->codeBlock();
2348 auto throwScope = DECLARE_THROW_SCOPE(vm);
2349
2350 void* result;
2351 StringJumpTable& jumpTable = codeBlock->stringSwitchJumpTable(tableIndex);
2352
2353 if (key.isString()) {
2354 StringImpl* value = asString(key)->value(globalObject).impl();
2355
2356 RETURN_IF_EXCEPTION(throwScope, nullptr);
2357
2358 result = jumpTable.ctiForValue(value).executableAddress();
2359 } else
2360 result = jumpTable.ctiDefault.executableAddress();
2361
2362 assertIsTaggedWith(result, JSSwitchPtrTag);
2363 return reinterpret_cast<char*>(result);
2364}
2365
2366EncodedJSValue JIT_OPERATION operationGetFromScope(JSGlobalObject* globalObject, const Instruction* pc)
2367{
2368 VM& vm = globalObject->vm();
2369 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2370 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2371 auto throwScope = DECLARE_THROW_SCOPE(vm);
2372
2373 CodeBlock* codeBlock = callFrame->codeBlock();
2374
2375 auto bytecode = pc->as<OpGetFromScope>();
2376 const Identifier& ident = codeBlock->identifier(bytecode.m_var);
2377 JSObject* scope = jsCast<JSObject*>(callFrame->uncheckedR(bytecode.m_scope.offset()).jsValue());
2378 GetPutInfo& getPutInfo = bytecode.metadata(codeBlock).m_getPutInfo;
2379
2380 // ModuleVar is always converted to ClosureVar for get_from_scope.
2381 ASSERT(getPutInfo.resolveType() != ModuleVar);
2382
2383 RELEASE_AND_RETURN(throwScope, JSValue::encode(scope->getPropertySlot(globalObject, ident, [&] (bool found, PropertySlot& slot) -> JSValue {
2384 if (!found) {
2385 if (getPutInfo.resolveMode() == ThrowIfNotFound)
2386 throwException(globalObject, throwScope, createUndefinedVariableError(globalObject, ident));
2387 return jsUndefined();
2388 }
2389
2390 JSValue result = JSValue();
2391 if (scope->isGlobalLexicalEnvironment()) {
2392 // When we can't statically prove we need a TDZ check, we must perform the check on the slow path.
2393 result = slot.getValue(globalObject, ident);
2394 if (result == jsTDZValue()) {
2395 throwException(globalObject, throwScope, createTDZError(globalObject));
2396 return jsUndefined();
2397 }
2398 }
2399
2400 CommonSlowPaths::tryCacheGetFromScopeGlobal(globalObject, codeBlock, vm, bytecode, scope, slot, ident);
2401
2402 if (!result)
2403 return slot.getValue(globalObject, ident);
2404 return result;
2405 })));
2406}
2407
2408void JIT_OPERATION operationPutToScope(JSGlobalObject* globalObject, const Instruction* pc)
2409{
2410 VM& vm = globalObject->vm();
2411 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2412 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2413 auto throwScope = DECLARE_THROW_SCOPE(vm);
2414
2415 CodeBlock* codeBlock = callFrame->codeBlock();
2416 auto bytecode = pc->as<OpPutToScope>();
2417 auto& metadata = bytecode.metadata(codeBlock);
2418
2419 const Identifier& ident = codeBlock->identifier(bytecode.m_var);
2420 JSObject* scope = jsCast<JSObject*>(callFrame->uncheckedR(bytecode.m_scope.offset()).jsValue());
2421 JSValue value = callFrame->r(bytecode.m_value.offset()).jsValue();
2422 GetPutInfo& getPutInfo = metadata.m_getPutInfo;
2423
2424 // ModuleVar does not keep the scope register value alive in DFG.
2425 ASSERT(getPutInfo.resolveType() != ModuleVar);
2426
2427 if (getPutInfo.resolveType() == LocalClosureVar) {
2428 JSLexicalEnvironment* environment = jsCast<JSLexicalEnvironment*>(scope);
2429 environment->variableAt(ScopeOffset(metadata.m_operand)).set(vm, environment, value);
2430 if (WatchpointSet* set = metadata.m_watchpointSet)
2431 set->touch(vm, "Executed op_put_scope<LocalClosureVar>");
2432 return;
2433 }
2434
2435 bool hasProperty = scope->hasProperty(globalObject, ident);
2436 RETURN_IF_EXCEPTION(throwScope, void());
2437 if (hasProperty
2438 && scope->isGlobalLexicalEnvironment()
2439 && !isInitialization(getPutInfo.initializationMode())) {
2440 // When we can't statically prove we need a TDZ check, we must perform the check on the slow path.
2441 PropertySlot slot(scope, PropertySlot::InternalMethodType::Get);
2442 JSGlobalLexicalEnvironment::getOwnPropertySlot(scope, globalObject, ident, slot);
2443 if (slot.getValue(globalObject, ident) == jsTDZValue()) {
2444 throwException(globalObject, throwScope, createTDZError(globalObject));
2445 return;
2446 }
2447 }
2448
2449 if (getPutInfo.resolveMode() == ThrowIfNotFound && !hasProperty) {
2450 throwException(globalObject, throwScope, createUndefinedVariableError(globalObject, ident));
2451 return;
2452 }
2453
2454 PutPropertySlot slot(scope, codeBlock->isStrictMode(), PutPropertySlot::UnknownContext, isInitialization(getPutInfo.initializationMode()));
2455 scope->methodTable(vm)->put(scope, globalObject, ident, value, slot);
2456
2457 RETURN_IF_EXCEPTION(throwScope, void());
2458
2459 CommonSlowPaths::tryCachePutToScopeGlobal(globalObject, codeBlock, bytecode, scope, slot, ident);
2460}
2461
2462void JIT_OPERATION operationThrow(JSGlobalObject* globalObject, EncodedJSValue encodedExceptionValue)
2463{
2464 VM& vm = globalObject->vm();
2465 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2466 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2467 auto scope = DECLARE_THROW_SCOPE(vm);
2468
2469 JSValue exceptionValue = JSValue::decode(encodedExceptionValue);
2470 throwException(globalObject, scope, exceptionValue);
2471
2472 // Results stored out-of-band in vm.targetMachinePCForThrow & vm.callFrameForCatch
2473 genericUnwind(vm, callFrame);
2474}
2475
2476char* JIT_OPERATION operationReallocateButterflyToHavePropertyStorageWithInitialCapacity(VM* vmPointer, JSObject* object)
2477{
2478 VM& vm = *vmPointer;
2479 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2480 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2481
2482 ASSERT(!object->structure(vm)->outOfLineCapacity());
2483 Butterfly* result = object->allocateMoreOutOfLineStorage(vm, 0, initialOutOfLineCapacity);
2484 object->nukeStructureAndSetButterfly(vm, object->structureID(), result);
2485 return reinterpret_cast<char*>(result);
2486}
2487
2488char* JIT_OPERATION operationReallocateButterflyToGrowPropertyStorage(VM* vmPointer, JSObject* object, size_t newSize)
2489{
2490 VM& vm = *vmPointer;
2491 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2492 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2493
2494 Butterfly* result = object->allocateMoreOutOfLineStorage(vm, object->structure(vm)->outOfLineCapacity(), newSize);
2495 object->nukeStructureAndSetButterfly(vm, object->structureID(), result);
2496 return reinterpret_cast<char*>(result);
2497}
2498
2499void JIT_OPERATION operationOSRWriteBarrier(VM* vmPointer, JSCell* cell)
2500{
2501 VM& vm = *vmPointer;
2502 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2503 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2504 vm.heap.writeBarrier(cell);
2505}
2506
2507void JIT_OPERATION operationWriteBarrierSlowPath(VM* vmPointer, JSCell* cell)
2508{
2509 VM& vm = *vmPointer;
2510 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2511 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2512 vm.heap.writeBarrierSlowPath(cell);
2513}
2514
2515void JIT_OPERATION operationLookupExceptionHandler(VM* vmPointer)
2516{
2517 VM& vm = *vmPointer;
2518 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2519 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2520 genericUnwind(vm, callFrame);
2521 ASSERT(vm.targetMachinePCForThrow);
2522}
2523
2524void JIT_OPERATION operationLookupExceptionHandlerFromCallerFrame(VM* vmPointer)
2525{
2526 VM& vm = *vmPointer;
2527 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2528 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2529 ASSERT(callFrame->isStackOverflowFrame());
2530 ASSERT(jsCast<ErrorInstance*>(vm.exceptionForInspection()->value().asCell())->isStackOverflowError());
2531 genericUnwind(vm, callFrame);
2532 ASSERT(vm.targetMachinePCForThrow);
2533}
2534
2535void JIT_OPERATION operationVMHandleException(VM* vmPointer)
2536{
2537 VM& vm = *vmPointer;
2538 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2539 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2540 genericUnwind(vm, callFrame);
2541}
2542
2543// This function "should" just take the JSGlobalObject*, but doing so would make it more difficult
2544// to call from exception check sites. So, unlike all of our other functions, we allow
2545// ourselves to play some gnarly ABI tricks just to simplify the calling convention. This is
2546// particularly safe here since this is never called on the critical path - it's only for
2547// testing.
2548void JIT_OPERATION operationExceptionFuzz(JSGlobalObject* globalObject)
2549{
2550 VM& vm = globalObject->vm();
2551 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2552 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2553 auto scope = DECLARE_THROW_SCOPE(vm);
2554 UNUSED_PARAM(scope);
2555#if COMPILER(GCC_COMPATIBLE)
2556 void* returnPC = __builtin_return_address(0);
2557 doExceptionFuzzing(globalObject, scope, "JITOperations", returnPC);
2558#endif // COMPILER(GCC_COMPATIBLE)
2559}
2560
2561EncodedJSValue JIT_OPERATION operationValueAdd(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
2562{
2563 VM& vm = globalObject->vm();
2564 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2565 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2566 return JSValue::encode(jsAdd(globalObject, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)));
2567}
2568
2569EncodedJSValue JIT_OPERATION operationValueAddProfiled(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, BinaryArithProfile* arithProfile)
2570{
2571 ASSERT(arithProfile);
2572 VM& vm = globalObject->vm();
2573 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2574 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2575 return JSValue::encode(profiledAdd(globalObject, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2), *arithProfile));
2576}
2577
2578EncodedJSValue JIT_OPERATION operationValueAddProfiledOptimize(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITAddIC* addIC)
2579{
2580 VM& vm = globalObject->vm();
2581 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2582 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2583
2584 JSValue op1 = JSValue::decode(encodedOp1);
2585 JSValue op2 = JSValue::decode(encodedOp2);
2586
2587 BinaryArithProfile* arithProfile = addIC->arithProfile();
2588 ASSERT(arithProfile);
2589 arithProfile->observeLHSAndRHS(op1, op2);
2590 auto nonOptimizeVariant = operationValueAddProfiledNoOptimize;
2591 addIC->generateOutOfLine(callFrame->codeBlock(), nonOptimizeVariant);
2592
2593#if ENABLE(MATH_IC_STATS)
2594 callFrame->codeBlock()->dumpMathICStats();
2595#endif
2596
2597 JSValue result = jsAdd(globalObject, op1, op2);
2598 arithProfile->observeResult(result);
2599
2600 return JSValue::encode(result);
2601}
2602
2603EncodedJSValue JIT_OPERATION operationValueAddProfiledNoOptimize(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITAddIC* addIC)
2604{
2605 VM& vm = globalObject->vm();
2606 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2607 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2608
2609 BinaryArithProfile* arithProfile = addIC->arithProfile();
2610 ASSERT(arithProfile);
2611 return JSValue::encode(profiledAdd(globalObject, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2), *arithProfile));
2612}
2613
2614EncodedJSValue JIT_OPERATION operationValueAddOptimize(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITAddIC* addIC)
2615{
2616 VM& vm = globalObject->vm();
2617 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2618 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2619
2620 JSValue op1 = JSValue::decode(encodedOp1);
2621 JSValue op2 = JSValue::decode(encodedOp2);
2622
2623 auto nonOptimizeVariant = operationValueAddNoOptimize;
2624 if (BinaryArithProfile* arithProfile = addIC->arithProfile())
2625 arithProfile->observeLHSAndRHS(op1, op2);
2626 addIC->generateOutOfLine(callFrame->codeBlock(), nonOptimizeVariant);
2627
2628#if ENABLE(MATH_IC_STATS)
2629 callFrame->codeBlock()->dumpMathICStats();
2630#endif
2631
2632 return JSValue::encode(jsAdd(globalObject, op1, op2));
2633}
2634
2635EncodedJSValue JIT_OPERATION operationValueAddNoOptimize(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITAddIC*)
2636{
2637 VM& vm = globalObject->vm();
2638 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2639 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2640
2641 JSValue op1 = JSValue::decode(encodedOp1);
2642 JSValue op2 = JSValue::decode(encodedOp2);
2643
2644 JSValue result = jsAdd(globalObject, op1, op2);
2645
2646 return JSValue::encode(result);
2647}
2648
2649ALWAYS_INLINE static EncodedJSValue unprofiledMul(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
2650{
2651 JSValue op1 = JSValue::decode(encodedOp1);
2652 JSValue op2 = JSValue::decode(encodedOp2);
2653
2654 return JSValue::encode(jsMul(globalObject, op1, op2));
2655}
2656
2657ALWAYS_INLINE static EncodedJSValue profiledMul(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, BinaryArithProfile& arithProfile, bool shouldObserveLHSAndRHSTypes = true)
2658{
2659 VM& vm = globalObject->vm();
2660 auto scope = DECLARE_THROW_SCOPE(vm);
2661 JSValue op1 = JSValue::decode(encodedOp1);
2662 JSValue op2 = JSValue::decode(encodedOp2);
2663
2664 if (shouldObserveLHSAndRHSTypes)
2665 arithProfile.observeLHSAndRHS(op1, op2);
2666
2667 JSValue result = jsMul(globalObject, op1, op2);
2668 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2669 arithProfile.observeResult(result);
2670 return JSValue::encode(result);
2671}
2672
2673EncodedJSValue JIT_OPERATION operationValueMul(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
2674{
2675 VM& vm = globalObject->vm();
2676 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2677 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2678
2679 return unprofiledMul(globalObject, encodedOp1, encodedOp2);
2680}
2681
2682EncodedJSValue JIT_OPERATION operationValueMulNoOptimize(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITMulIC*)
2683{
2684 VM& vm = globalObject->vm();
2685 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2686 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2687
2688 return unprofiledMul(globalObject, encodedOp1, encodedOp2);
2689}
2690
2691EncodedJSValue JIT_OPERATION operationValueMulOptimize(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITMulIC* mulIC)
2692{
2693 VM& vm = globalObject->vm();
2694 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2695 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2696
2697 auto nonOptimizeVariant = operationValueMulNoOptimize;
2698 if (BinaryArithProfile* arithProfile = mulIC->arithProfile())
2699 arithProfile->observeLHSAndRHS(JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
2700 mulIC->generateOutOfLine(callFrame->codeBlock(), nonOptimizeVariant);
2701
2702#if ENABLE(MATH_IC_STATS)
2703 callFrame->codeBlock()->dumpMathICStats();
2704#endif
2705
2706 return unprofiledMul(globalObject, encodedOp1, encodedOp2);
2707}
2708
2709EncodedJSValue JIT_OPERATION operationValueMulProfiled(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, BinaryArithProfile* arithProfile)
2710{
2711 VM& vm = globalObject->vm();
2712 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2713 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2714
2715 ASSERT(arithProfile);
2716 return profiledMul(globalObject, encodedOp1, encodedOp2, *arithProfile);
2717}
2718
2719EncodedJSValue JIT_OPERATION operationValueMulProfiledOptimize(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITMulIC* mulIC)
2720{
2721 VM& vm = globalObject->vm();
2722 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2723 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2724
2725 BinaryArithProfile* arithProfile = mulIC->arithProfile();
2726 ASSERT(arithProfile);
2727 arithProfile->observeLHSAndRHS(JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
2728 auto nonOptimizeVariant = operationValueMulProfiledNoOptimize;
2729 mulIC->generateOutOfLine(callFrame->codeBlock(), nonOptimizeVariant);
2730
2731#if ENABLE(MATH_IC_STATS)
2732 callFrame->codeBlock()->dumpMathICStats();
2733#endif
2734
2735 return profiledMul(globalObject, encodedOp1, encodedOp2, *arithProfile, false);
2736}
2737
2738EncodedJSValue JIT_OPERATION operationValueMulProfiledNoOptimize(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITMulIC* mulIC)
2739{
2740 VM& vm = globalObject->vm();
2741 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2742 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2743
2744 BinaryArithProfile* arithProfile = mulIC->arithProfile();
2745 ASSERT(arithProfile);
2746 return profiledMul(globalObject, encodedOp1, encodedOp2, *arithProfile);
2747}
2748
2749EncodedJSValue JIT_OPERATION operationArithNegate(JSGlobalObject* globalObject, EncodedJSValue encodedOperand)
2750{
2751 VM& vm = globalObject->vm();
2752 auto scope = DECLARE_THROW_SCOPE(vm);
2753 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2754 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2755
2756 JSValue operand = JSValue::decode(encodedOperand);
2757
2758 JSValue primValue = operand.toPrimitive(globalObject, PreferNumber);
2759 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2760
2761 if (primValue.isBigInt())
2762 return JSValue::encode(JSBigInt::unaryMinus(vm, asBigInt(primValue)));
2763
2764 double number = primValue.toNumber(globalObject);
2765 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2766 return JSValue::encode(jsNumber(-number));
2767
2768}
2769
2770EncodedJSValue JIT_OPERATION operationArithNegateProfiled(JSGlobalObject* globalObject, EncodedJSValue encodedOperand, UnaryArithProfile* arithProfile)
2771{
2772 ASSERT(arithProfile);
2773 VM& vm = globalObject->vm();
2774 auto scope = DECLARE_THROW_SCOPE(vm);
2775 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2776 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2777
2778 JSValue operand = JSValue::decode(encodedOperand);
2779 arithProfile->observeArg(operand);
2780
2781 JSValue primValue = operand.toPrimitive(globalObject);
2782 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2783
2784 if (primValue.isBigInt()) {
2785 JSBigInt* result = JSBigInt::unaryMinus(vm, asBigInt(primValue));
2786 arithProfile->observeResult(result);
2787
2788 return JSValue::encode(result);
2789 }
2790
2791 double number = primValue.toNumber(globalObject);
2792 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2793 JSValue result = jsNumber(-number);
2794 arithProfile->observeResult(result);
2795 return JSValue::encode(result);
2796}
2797
2798EncodedJSValue JIT_OPERATION operationArithNegateProfiledOptimize(JSGlobalObject* globalObject, EncodedJSValue encodedOperand, JITNegIC* negIC)
2799{
2800 VM& vm = globalObject->vm();
2801 auto scope = DECLARE_THROW_SCOPE(vm);
2802 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2803 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2804
2805 JSValue operand = JSValue::decode(encodedOperand);
2806
2807 UnaryArithProfile* arithProfile = negIC->arithProfile();
2808 ASSERT(arithProfile);
2809 arithProfile->observeArg(operand);
2810 negIC->generateOutOfLine(callFrame->codeBlock(), operationArithNegateProfiled);
2811
2812#if ENABLE(MATH_IC_STATS)
2813 callFrame->codeBlock()->dumpMathICStats();
2814#endif
2815
2816 JSValue primValue = operand.toPrimitive(globalObject);
2817 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2818
2819 if (primValue.isBigInt()) {
2820 JSBigInt* result = JSBigInt::unaryMinus(vm, asBigInt(primValue));
2821 arithProfile->observeResult(result);
2822 return JSValue::encode(result);
2823 }
2824
2825 double number = primValue.toNumber(globalObject);
2826 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2827 JSValue result = jsNumber(-number);
2828 arithProfile->observeResult(result);
2829 return JSValue::encode(result);
2830}
2831
2832EncodedJSValue JIT_OPERATION operationArithNegateOptimize(JSGlobalObject* globalObject, EncodedJSValue encodedOperand, JITNegIC* negIC)
2833{
2834 VM& vm = globalObject->vm();
2835 auto scope = DECLARE_THROW_SCOPE(vm);
2836 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2837 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2838
2839 JSValue operand = JSValue::decode(encodedOperand);
2840
2841 if (UnaryArithProfile* arithProfile = negIC->arithProfile())
2842 arithProfile->observeArg(operand);
2843 negIC->generateOutOfLine(callFrame->codeBlock(), operationArithNegate);
2844
2845#if ENABLE(MATH_IC_STATS)
2846 callFrame->codeBlock()->dumpMathICStats();
2847#endif
2848
2849 JSValue primValue = operand.toPrimitive(globalObject);
2850 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2851
2852 if (primValue.isBigInt())
2853 return JSValue::encode(JSBigInt::unaryMinus(vm, asBigInt(primValue)));
2854
2855 double number = primValue.toNumber(globalObject);
2856 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2857 return JSValue::encode(jsNumber(-number));
2858}
2859
2860ALWAYS_INLINE static EncodedJSValue unprofiledSub(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
2861{
2862 JSValue op1 = JSValue::decode(encodedOp1);
2863 JSValue op2 = JSValue::decode(encodedOp2);
2864
2865 return JSValue::encode(jsSub(globalObject, op1, op2));
2866}
2867
2868ALWAYS_INLINE static EncodedJSValue profiledSub(VM& vm, JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, BinaryArithProfile& arithProfile, bool shouldObserveLHSAndRHSTypes = true)
2869{
2870 auto scope = DECLARE_THROW_SCOPE(vm);
2871
2872 JSValue op1 = JSValue::decode(encodedOp1);
2873 JSValue op2 = JSValue::decode(encodedOp2);
2874
2875 if (shouldObserveLHSAndRHSTypes)
2876 arithProfile.observeLHSAndRHS(op1, op2);
2877
2878 JSValue result = jsSub(globalObject, op1, op2);
2879 RETURN_IF_EXCEPTION(scope, encodedJSValue());
2880 arithProfile.observeResult(result);
2881 return JSValue::encode(result);
2882}
2883
2884EncodedJSValue JIT_OPERATION operationValueSub(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
2885{
2886 VM& vm = globalObject->vm();
2887 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2888 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2889 return unprofiledSub(globalObject, encodedOp1, encodedOp2);
2890}
2891
2892EncodedJSValue JIT_OPERATION operationValueSubProfiled(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, BinaryArithProfile* arithProfile)
2893{
2894 ASSERT(arithProfile);
2895
2896 VM& vm = globalObject->vm();
2897 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2898 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2899
2900 return profiledSub(vm, globalObject, encodedOp1, encodedOp2, *arithProfile);
2901}
2902
2903EncodedJSValue JIT_OPERATION operationValueSubOptimize(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITSubIC* subIC)
2904{
2905 VM& vm = globalObject->vm();
2906 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2907 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2908
2909 auto nonOptimizeVariant = operationValueSubNoOptimize;
2910 if (BinaryArithProfile* arithProfile = subIC->arithProfile())
2911 arithProfile->observeLHSAndRHS(JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
2912 subIC->generateOutOfLine(callFrame->codeBlock(), nonOptimizeVariant);
2913
2914#if ENABLE(MATH_IC_STATS)
2915 callFrame->codeBlock()->dumpMathICStats();
2916#endif
2917
2918 return unprofiledSub(globalObject, encodedOp1, encodedOp2);
2919}
2920
2921EncodedJSValue JIT_OPERATION operationValueSubNoOptimize(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITSubIC*)
2922{
2923 VM& vm = globalObject->vm();
2924 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2925 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2926
2927 return unprofiledSub(globalObject, encodedOp1, encodedOp2);
2928}
2929
2930EncodedJSValue JIT_OPERATION operationValueSubProfiledOptimize(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITSubIC* subIC)
2931{
2932 VM& vm = globalObject->vm();
2933 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2934 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2935
2936 BinaryArithProfile* arithProfile = subIC->arithProfile();
2937 ASSERT(arithProfile);
2938 arithProfile->observeLHSAndRHS(JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
2939 auto nonOptimizeVariant = operationValueSubProfiledNoOptimize;
2940 subIC->generateOutOfLine(callFrame->codeBlock(), nonOptimizeVariant);
2941
2942#if ENABLE(MATH_IC_STATS)
2943 callFrame->codeBlock()->dumpMathICStats();
2944#endif
2945
2946 return profiledSub(vm, globalObject, encodedOp1, encodedOp2, *arithProfile, false);
2947}
2948
2949EncodedJSValue JIT_OPERATION operationValueSubProfiledNoOptimize(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITSubIC* subIC)
2950{
2951 VM& vm = globalObject->vm();
2952 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2953 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2954
2955 BinaryArithProfile* arithProfile = subIC->arithProfile();
2956 ASSERT(arithProfile);
2957 return profiledSub(vm, globalObject, encodedOp1, encodedOp2, *arithProfile);
2958}
2959
2960void JIT_OPERATION operationProcessTypeProfilerLog(VM* vmPointer)
2961{
2962 VM& vm = *vmPointer;
2963 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2964 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2965 vm.typeProfilerLog()->processLogEntries(vm, "Log Full, called from inside baseline JIT"_s);
2966}
2967
2968void JIT_OPERATION operationProcessShadowChickenLog(VM* vmPointer)
2969{
2970 VM& vm = *vmPointer;
2971 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2972 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2973 RELEASE_ASSERT(vm.shadowChicken());
2974 vm.shadowChicken()->update(vm, callFrame);
2975}
2976
2977int32_t JIT_OPERATION operationCheckIfExceptionIsUncatchableAndNotifyProfiler(VM* vmPointer)
2978{
2979 VM& vm = *vmPointer;
2980 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2981 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2982 auto scope = DECLARE_THROW_SCOPE(vm);
2983 RELEASE_ASSERT(!!scope.exception());
2984
2985 if (isTerminatedExecutionException(vm, scope.exception())) {
2986 genericUnwind(vm, callFrame);
2987 return 1;
2988 }
2989 return 0;
2990}
2991
2992} // extern "C"
2993
2994} // namespace JSC
2995
2996IGNORE_WARNINGS_END
2997
2998#endif // ENABLE(JIT)
2999