]> git.saurik.com Git - apple/javascriptcore.git/blob - dfg/DFGOperations.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / dfg / DFGOperations.cpp
1 /*
2 * Copyright (C) 2011, 2013-2015 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 "DFGOperations.h"
28
29 #include "ButterflyInlines.h"
30 #include "ClonedArguments.h"
31 #include "CodeBlock.h"
32 #include "CommonSlowPaths.h"
33 #include "CopiedSpaceInlines.h"
34 #include "DFGDriver.h"
35 #include "DFGJITCode.h"
36 #include "DFGOSRExit.h"
37 #include "DFGThunks.h"
38 #include "DFGToFTLDeferredCompilationCallback.h"
39 #include "DFGToFTLForOSREntryDeferredCompilationCallback.h"
40 #include "DFGWorklist.h"
41 #include "DirectArguments.h"
42 #include "FTLForOSREntryJITCode.h"
43 #include "FTLOSREntry.h"
44 #include "HostCallReturnValue.h"
45 #include "GetterSetter.h"
46 #include "Interpreter.h"
47 #include "JIT.h"
48 #include "JITExceptions.h"
49 #include "JSCInlines.h"
50 #include "JSLexicalEnvironment.h"
51 #include "JSNameScope.h"
52 #include "ObjectConstructor.h"
53 #include "Repatch.h"
54 #include "ScopedArguments.h"
55 #include "StringConstructor.h"
56 #include "Symbol.h"
57 #include "TypeProfilerLog.h"
58 #include "TypedArrayInlines.h"
59 #include "VM.h"
60 #include <wtf/InlineASM.h>
61
62 #if ENABLE(JIT)
63 #if ENABLE(DFG_JIT)
64
65 namespace JSC { namespace DFG {
66
67 template<bool strict, bool direct>
68 static inline void putByVal(ExecState* exec, JSValue baseValue, uint32_t index, JSValue value)
69 {
70 VM& vm = exec->vm();
71 NativeCallFrameTracer tracer(&vm, exec);
72 ASSERT(isIndex(index));
73 if (direct) {
74 RELEASE_ASSERT(baseValue.isObject());
75 asObject(baseValue)->putDirectIndex(exec, index, value, 0, strict ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
76 return;
77 }
78 if (baseValue.isObject()) {
79 JSObject* object = asObject(baseValue);
80 if (object->canSetIndexQuickly(index)) {
81 object->setIndexQuickly(vm, index, value);
82 return;
83 }
84
85 object->methodTable(vm)->putByIndex(object, exec, index, value, strict);
86 return;
87 }
88
89 baseValue.putByIndex(exec, index, value, strict);
90 }
91
92 template<bool strict, bool direct>
93 ALWAYS_INLINE static void JIT_OPERATION operationPutByValInternal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
94 {
95 VM* vm = &exec->vm();
96 NativeCallFrameTracer tracer(vm, exec);
97
98 JSValue baseValue = JSValue::decode(encodedBase);
99 JSValue property = JSValue::decode(encodedProperty);
100 JSValue value = JSValue::decode(encodedValue);
101
102 if (LIKELY(property.isUInt32())) {
103 // Despite its name, JSValue::isUInt32 will return true only for positive boxed int32_t; all those values are valid array indices.
104 ASSERT(isIndex(property.asUInt32()));
105 putByVal<strict, direct>(exec, baseValue, property.asUInt32(), value);
106 return;
107 }
108
109 if (property.isDouble()) {
110 double propertyAsDouble = property.asDouble();
111 uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
112 if (propertyAsDouble == propertyAsUInt32 && isIndex(propertyAsUInt32)) {
113 putByVal<strict, direct>(exec, baseValue, propertyAsUInt32, value);
114 return;
115 }
116 }
117
118 // Don't put to an object if toString throws an exception.
119 auto propertyName = property.toPropertyKey(exec);
120 if (vm->exception())
121 return;
122
123 PutPropertySlot slot(baseValue, strict);
124 if (direct) {
125 RELEASE_ASSERT(baseValue.isObject());
126 if (Optional<uint32_t> index = parseIndex(propertyName))
127 asObject(baseValue)->putDirectIndex(exec, index.value(), value, 0, strict ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
128 else
129 asObject(baseValue)->putDirect(*vm, propertyName, value, slot);
130 } else
131 baseValue.put(exec, propertyName, value, slot);
132 }
133
134 template<typename ViewClass>
135 char* newTypedArrayWithSize(ExecState* exec, Structure* structure, int32_t size)
136 {
137 VM& vm = exec->vm();
138 NativeCallFrameTracer tracer(&vm, exec);
139 if (size < 0) {
140 vm.throwException(exec, createRangeError(exec, ASCIILiteral("Requested length is negative")));
141 return 0;
142 }
143 return bitwise_cast<char*>(ViewClass::create(exec, structure, size));
144 }
145
146 template<typename ViewClass>
147 char* newTypedArrayWithOneArgument(
148 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
149 {
150 VM& vm = exec->vm();
151 NativeCallFrameTracer tracer(&vm, exec);
152
153 JSValue value = JSValue::decode(encodedValue);
154
155 if (JSArrayBuffer* jsBuffer = jsDynamicCast<JSArrayBuffer*>(value)) {
156 RefPtr<ArrayBuffer> buffer = jsBuffer->impl();
157
158 if (buffer->byteLength() % ViewClass::elementSize) {
159 vm.throwException(exec, createRangeError(exec, ASCIILiteral("ArrayBuffer length minus the byteOffset is not a multiple of the element size")));
160 return 0;
161 }
162 return bitwise_cast<char*>(
163 ViewClass::create(
164 exec, structure, buffer, 0, buffer->byteLength() / ViewClass::elementSize));
165 }
166
167 if (JSObject* object = jsDynamicCast<JSObject*>(value)) {
168 unsigned length = object->get(exec, vm.propertyNames->length).toUInt32(exec);
169 if (exec->hadException())
170 return 0;
171
172 ViewClass* result = ViewClass::createUninitialized(exec, structure, length);
173 if (!result)
174 return 0;
175
176 if (!result->set(exec, object, 0, length))
177 return 0;
178
179 return bitwise_cast<char*>(result);
180 }
181
182 int length;
183 if (value.isInt32())
184 length = value.asInt32();
185 else if (!value.isNumber()) {
186 vm.throwException(exec, createTypeError(exec, ASCIILiteral("Invalid array length argument")));
187 return 0;
188 } else {
189 length = static_cast<int>(value.asNumber());
190 if (length != value.asNumber()) {
191 vm.throwException(exec, createTypeError(exec, ASCIILiteral("Invalid array length argument (fractional lengths not allowed)")));
192 return 0;
193 }
194 }
195
196 if (length < 0) {
197 vm.throwException(exec, createRangeError(exec, ASCIILiteral("Requested length is negative")));
198 return 0;
199 }
200
201 return bitwise_cast<char*>(ViewClass::create(exec, structure, length));
202 }
203
204 extern "C" {
205
206 EncodedJSValue JIT_OPERATION operationToThis(ExecState* exec, EncodedJSValue encodedOp)
207 {
208 VM* vm = &exec->vm();
209 NativeCallFrameTracer tracer(vm, exec);
210
211 return JSValue::encode(JSValue::decode(encodedOp).toThis(exec, NotStrictMode));
212 }
213
214 EncodedJSValue JIT_OPERATION operationToThisStrict(ExecState* exec, EncodedJSValue encodedOp)
215 {
216 VM* vm = &exec->vm();
217 NativeCallFrameTracer tracer(vm, exec);
218
219 return JSValue::encode(JSValue::decode(encodedOp).toThis(exec, StrictMode));
220 }
221
222 JSCell* JIT_OPERATION operationCreateThis(ExecState* exec, JSObject* constructor, int32_t inlineCapacity)
223 {
224 VM& vm = exec->vm();
225 NativeCallFrameTracer tracer(&vm, exec);
226
227 #if !ASSERT_DISABLED
228 ConstructData constructData;
229 ASSERT(jsCast<JSFunction*>(constructor)->methodTable(vm)->getConstructData(jsCast<JSFunction*>(constructor), constructData) == ConstructTypeJS);
230 #endif
231
232 return constructEmptyObject(exec, jsCast<JSFunction*>(constructor)->rareData(exec, inlineCapacity)->allocationProfile()->structure());
233 }
234
235 EncodedJSValue JIT_OPERATION operationValueAdd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
236 {
237 VM* vm = &exec->vm();
238 NativeCallFrameTracer tracer(vm, exec);
239
240 JSValue op1 = JSValue::decode(encodedOp1);
241 JSValue op2 = JSValue::decode(encodedOp2);
242
243 return JSValue::encode(jsAdd(exec, op1, op2));
244 }
245
246 EncodedJSValue JIT_OPERATION operationValueAddNotNumber(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
247 {
248 VM* vm = &exec->vm();
249 NativeCallFrameTracer tracer(vm, exec);
250
251 JSValue op1 = JSValue::decode(encodedOp1);
252 JSValue op2 = JSValue::decode(encodedOp2);
253
254 ASSERT(!op1.isNumber() || !op2.isNumber());
255
256 if (op1.isString() && !op2.isObject())
257 return JSValue::encode(jsString(exec, asString(op1), op2.toString(exec)));
258
259 return JSValue::encode(jsAddSlowCase(exec, op1, op2));
260 }
261
262 static ALWAYS_INLINE EncodedJSValue getByVal(ExecState* exec, JSCell* base, uint32_t index)
263 {
264 VM& vm = exec->vm();
265 NativeCallFrameTracer tracer(&vm, exec);
266
267 if (base->isObject()) {
268 JSObject* object = asObject(base);
269 if (object->canGetIndexQuickly(index))
270 return JSValue::encode(object->getIndexQuickly(index));
271 }
272
273 if (isJSString(base) && asString(base)->canGetIndex(index))
274 return JSValue::encode(asString(base)->getIndex(exec, index));
275
276 return JSValue::encode(JSValue(base).get(exec, index));
277 }
278
279 EncodedJSValue JIT_OPERATION operationGetByVal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty)
280 {
281 VM& vm = exec->vm();
282 NativeCallFrameTracer tracer(&vm, exec);
283
284 JSValue baseValue = JSValue::decode(encodedBase);
285 JSValue property = JSValue::decode(encodedProperty);
286
287 if (LIKELY(baseValue.isCell())) {
288 JSCell* base = baseValue.asCell();
289
290 if (property.isUInt32()) {
291 return getByVal(exec, base, property.asUInt32());
292 } else if (property.isDouble()) {
293 double propertyAsDouble = property.asDouble();
294 uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
295 if (propertyAsUInt32 == propertyAsDouble && isIndex(propertyAsUInt32))
296 return getByVal(exec, base, propertyAsUInt32);
297 } else if (property.isString()) {
298 Structure& structure = *base->structure(vm);
299 if (JSCell::canUseFastGetOwnProperty(structure)) {
300 if (RefPtr<AtomicStringImpl> existingAtomicString = asString(property)->toExistingAtomicString(exec)) {
301 if (JSValue result = base->fastGetOwnProperty(vm, structure, existingAtomicString.get()))
302 return JSValue::encode(result);
303 }
304 }
305 }
306 }
307
308 baseValue.requireObjectCoercible(exec);
309 if (exec->hadException())
310 return JSValue::encode(jsUndefined());
311 auto propertyName = property.toPropertyKey(exec);
312 if (exec->hadException())
313 return JSValue::encode(jsUndefined());
314 return JSValue::encode(baseValue.get(exec, propertyName));
315 }
316
317 EncodedJSValue JIT_OPERATION operationGetByValCell(ExecState* exec, JSCell* base, EncodedJSValue encodedProperty)
318 {
319 VM& vm = exec->vm();
320 NativeCallFrameTracer tracer(&vm, exec);
321
322 JSValue property = JSValue::decode(encodedProperty);
323
324 if (property.isUInt32())
325 return getByVal(exec, base, property.asUInt32());
326 if (property.isDouble()) {
327 double propertyAsDouble = property.asDouble();
328 uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
329 if (propertyAsUInt32 == propertyAsDouble)
330 return getByVal(exec, base, propertyAsUInt32);
331 } else if (property.isString()) {
332 Structure& structure = *base->structure(vm);
333 if (JSCell::canUseFastGetOwnProperty(structure)) {
334 if (RefPtr<AtomicStringImpl> existingAtomicString = asString(property)->toExistingAtomicString(exec)) {
335 if (JSValue result = base->fastGetOwnProperty(vm, structure, existingAtomicString.get()))
336 return JSValue::encode(result);
337 }
338 }
339 }
340
341 auto propertyName = property.toPropertyKey(exec);
342 if (exec->hadException())
343 return JSValue::encode(jsUndefined());
344 return JSValue::encode(JSValue(base).get(exec, propertyName));
345 }
346
347 ALWAYS_INLINE EncodedJSValue getByValCellInt(ExecState* exec, JSCell* base, int32_t index)
348 {
349 VM* vm = &exec->vm();
350 NativeCallFrameTracer tracer(vm, exec);
351
352 if (index < 0) {
353 // Go the slowest way possible becase negative indices don't use indexed storage.
354 return JSValue::encode(JSValue(base).get(exec, Identifier::from(exec, index)));
355 }
356
357 // Use this since we know that the value is out of bounds.
358 return JSValue::encode(JSValue(base).get(exec, index));
359 }
360
361 EncodedJSValue JIT_OPERATION operationGetByValArrayInt(ExecState* exec, JSArray* base, int32_t index)
362 {
363 return getByValCellInt(exec, base, index);
364 }
365
366 EncodedJSValue JIT_OPERATION operationGetByValStringInt(ExecState* exec, JSString* base, int32_t index)
367 {
368 return getByValCellInt(exec, base, index);
369 }
370
371 void JIT_OPERATION operationPutByValStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
372 {
373 VM* vm = &exec->vm();
374 NativeCallFrameTracer tracer(vm, exec);
375
376 operationPutByValInternal<true, false>(exec, encodedBase, encodedProperty, encodedValue);
377 }
378
379 void JIT_OPERATION operationPutByValNonStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
380 {
381 VM* vm = &exec->vm();
382 NativeCallFrameTracer tracer(vm, exec);
383
384 operationPutByValInternal<false, false>(exec, encodedBase, encodedProperty, encodedValue);
385 }
386
387 void JIT_OPERATION operationPutByValCellStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
388 {
389 VM* vm = &exec->vm();
390 NativeCallFrameTracer tracer(vm, exec);
391
392 operationPutByValInternal<true, false>(exec, JSValue::encode(cell), encodedProperty, encodedValue);
393 }
394
395 void JIT_OPERATION operationPutByValCellNonStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
396 {
397 VM* vm = &exec->vm();
398 NativeCallFrameTracer tracer(vm, exec);
399
400 operationPutByValInternal<false, false>(exec, JSValue::encode(cell), encodedProperty, encodedValue);
401 }
402
403 void JIT_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue)
404 {
405 VM& vm = exec->vm();
406 NativeCallFrameTracer tracer(&vm, exec);
407
408 if (index >= 0) {
409 array->putByIndexInline(exec, index, JSValue::decode(encodedValue), true);
410 return;
411 }
412
413 PutPropertySlot slot(array, true);
414 array->methodTable()->put(
415 array, exec, Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
416 }
417
418 void JIT_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue)
419 {
420 VM* vm = &exec->vm();
421 NativeCallFrameTracer tracer(vm, exec);
422
423 if (index >= 0) {
424 array->putByIndexInline(exec, index, JSValue::decode(encodedValue), false);
425 return;
426 }
427
428 PutPropertySlot slot(array, false);
429 array->methodTable()->put(
430 array, exec, Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
431 }
432
433 void JIT_OPERATION operationPutDoubleByValBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, double value)
434 {
435 VM* vm = &exec->vm();
436 NativeCallFrameTracer tracer(vm, exec);
437
438 JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value);
439
440 if (index >= 0) {
441 array->putByIndexInline(exec, index, jsValue, true);
442 return;
443 }
444
445 PutPropertySlot slot(array, true);
446 array->methodTable()->put(
447 array, exec, Identifier::from(exec, index), jsValue, slot);
448 }
449
450 void JIT_OPERATION operationPutDoubleByValBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* array, int32_t index, double value)
451 {
452 VM* vm = &exec->vm();
453 NativeCallFrameTracer tracer(vm, exec);
454
455 JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value);
456
457 if (index >= 0) {
458 array->putByIndexInline(exec, index, jsValue, false);
459 return;
460 }
461
462 PutPropertySlot slot(array, false);
463 array->methodTable()->put(
464 array, exec, Identifier::from(exec, index), jsValue, slot);
465 }
466
467 void JIT_OPERATION operationPutByValDirectStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
468 {
469 VM* vm = &exec->vm();
470 NativeCallFrameTracer tracer(vm, exec);
471
472 operationPutByValInternal<true, true>(exec, encodedBase, encodedProperty, encodedValue);
473 }
474
475 void JIT_OPERATION operationPutByValDirectNonStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
476 {
477 VM* vm = &exec->vm();
478 NativeCallFrameTracer tracer(vm, exec);
479
480 operationPutByValInternal<false, true>(exec, encodedBase, encodedProperty, encodedValue);
481 }
482
483 void JIT_OPERATION operationPutByValDirectCellStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
484 {
485 VM* vm = &exec->vm();
486 NativeCallFrameTracer tracer(vm, exec);
487
488 operationPutByValInternal<true, true>(exec, JSValue::encode(cell), encodedProperty, encodedValue);
489 }
490
491 void JIT_OPERATION operationPutByValDirectCellNonStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
492 {
493 VM* vm = &exec->vm();
494 NativeCallFrameTracer tracer(vm, exec);
495
496 operationPutByValInternal<false, true>(exec, JSValue::encode(cell), encodedProperty, encodedValue);
497 }
498
499 void JIT_OPERATION operationPutByValDirectBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue)
500 {
501 VM* vm = &exec->vm();
502 NativeCallFrameTracer tracer(vm, exec);
503 if (index >= 0) {
504 array->putDirectIndex(exec, index, JSValue::decode(encodedValue), 0, PutDirectIndexShouldThrow);
505 return;
506 }
507
508 PutPropertySlot slot(array, true);
509 array->putDirect(exec->vm(), Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
510 }
511
512 void JIT_OPERATION operationPutByValDirectBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue)
513 {
514 VM* vm = &exec->vm();
515 NativeCallFrameTracer tracer(vm, exec);
516
517 if (index >= 0) {
518 array->putDirectIndex(exec, index, JSValue::decode(encodedValue));
519 return;
520 }
521
522 PutPropertySlot slot(array, false);
523 array->putDirect(exec->vm(), Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
524 }
525
526 EncodedJSValue JIT_OPERATION operationArrayPush(ExecState* exec, EncodedJSValue encodedValue, JSArray* array)
527 {
528 VM* vm = &exec->vm();
529 NativeCallFrameTracer tracer(vm, exec);
530
531 array->push(exec, JSValue::decode(encodedValue));
532 return JSValue::encode(jsNumber(array->length()));
533 }
534
535 EncodedJSValue JIT_OPERATION operationArrayPushDouble(ExecState* exec, double value, JSArray* array)
536 {
537 VM* vm = &exec->vm();
538 NativeCallFrameTracer tracer(vm, exec);
539
540 array->push(exec, JSValue(JSValue::EncodeAsDouble, value));
541 return JSValue::encode(jsNumber(array->length()));
542 }
543
544 EncodedJSValue JIT_OPERATION operationArrayPop(ExecState* exec, JSArray* array)
545 {
546 VM* vm = &exec->vm();
547 NativeCallFrameTracer tracer(vm, exec);
548
549 return JSValue::encode(array->pop(exec));
550 }
551
552 EncodedJSValue JIT_OPERATION operationArrayPopAndRecoverLength(ExecState* exec, JSArray* array)
553 {
554 VM* vm = &exec->vm();
555 NativeCallFrameTracer tracer(vm, exec);
556
557 array->butterfly()->setPublicLength(array->butterfly()->publicLength() + 1);
558
559 return JSValue::encode(array->pop(exec));
560 }
561
562 EncodedJSValue JIT_OPERATION operationRegExpExec(ExecState* exec, JSCell* base, JSCell* argument)
563 {
564 VM& vm = exec->vm();
565 NativeCallFrameTracer tracer(&vm, exec);
566
567 if (!base->inherits(RegExpObject::info()))
568 return throwVMTypeError(exec);
569
570 ASSERT(argument->isString() || argument->isObject());
571 JSString* input = argument->isString() ? asString(argument) : asObject(argument)->toString(exec);
572 return JSValue::encode(asRegExpObject(base)->exec(exec, input));
573 }
574
575 size_t JIT_OPERATION operationRegExpTest(ExecState* exec, JSCell* base, JSCell* argument)
576 {
577 VM& vm = exec->vm();
578 NativeCallFrameTracer tracer(&vm, exec);
579
580 if (!base->inherits(RegExpObject::info())) {
581 throwTypeError(exec);
582 return false;
583 }
584
585 ASSERT(argument->isString() || argument->isObject());
586 JSString* input = argument->isString() ? asString(argument) : asObject(argument)->toString(exec);
587 return asRegExpObject(base)->test(exec, input);
588 }
589
590 size_t JIT_OPERATION operationCompareStrictEqCell(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
591 {
592 VM* vm = &exec->vm();
593 NativeCallFrameTracer tracer(vm, exec);
594
595 JSValue op1 = JSValue::decode(encodedOp1);
596 JSValue op2 = JSValue::decode(encodedOp2);
597
598 ASSERT(op1.isCell());
599 ASSERT(op2.isCell());
600
601 return JSValue::strictEqualSlowCaseInline(exec, op1, op2);
602 }
603
604 size_t JIT_OPERATION operationCompareStrictEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
605 {
606 VM* vm = &exec->vm();
607 NativeCallFrameTracer tracer(vm, exec);
608
609 JSValue src1 = JSValue::decode(encodedOp1);
610 JSValue src2 = JSValue::decode(encodedOp2);
611
612 return JSValue::strictEqual(exec, src1, src2);
613 }
614
615 EncodedJSValue JIT_OPERATION operationToPrimitive(ExecState* exec, EncodedJSValue value)
616 {
617 VM* vm = &exec->vm();
618 NativeCallFrameTracer tracer(vm, exec);
619
620 return JSValue::encode(JSValue::decode(value).toPrimitive(exec));
621 }
622
623 char* JIT_OPERATION operationNewArray(ExecState* exec, Structure* arrayStructure, void* buffer, size_t size)
624 {
625 VM* vm = &exec->vm();
626 NativeCallFrameTracer tracer(vm, exec);
627
628 return bitwise_cast<char*>(constructArray(exec, arrayStructure, static_cast<JSValue*>(buffer), size));
629 }
630
631 char* JIT_OPERATION operationNewEmptyArray(ExecState* exec, Structure* arrayStructure)
632 {
633 VM* vm = &exec->vm();
634 NativeCallFrameTracer tracer(vm, exec);
635
636 return bitwise_cast<char*>(JSArray::create(*vm, arrayStructure));
637 }
638
639 char* JIT_OPERATION operationNewArrayWithSize(ExecState* exec, Structure* arrayStructure, int32_t size)
640 {
641 VM* vm = &exec->vm();
642 NativeCallFrameTracer tracer(vm, exec);
643
644 if (UNLIKELY(size < 0))
645 return bitwise_cast<char*>(exec->vm().throwException(exec, createRangeError(exec, ASCIILiteral("Array size is not a small enough positive integer."))));
646
647 return bitwise_cast<char*>(JSArray::create(*vm, arrayStructure, size));
648 }
649
650 char* JIT_OPERATION operationNewArrayBuffer(ExecState* exec, Structure* arrayStructure, size_t start, size_t size)
651 {
652 VM& vm = exec->vm();
653 NativeCallFrameTracer tracer(&vm, exec);
654 return bitwise_cast<char*>(constructArray(exec, arrayStructure, exec->codeBlock()->constantBuffer(start), size));
655 }
656
657 char* JIT_OPERATION operationNewInt8ArrayWithSize(
658 ExecState* exec, Structure* structure, int32_t length)
659 {
660 return newTypedArrayWithSize<JSInt8Array>(exec, structure, length);
661 }
662
663 char* JIT_OPERATION operationNewInt8ArrayWithOneArgument(
664 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
665 {
666 return newTypedArrayWithOneArgument<JSInt8Array>(exec, structure, encodedValue);
667 }
668
669 char* JIT_OPERATION operationNewInt16ArrayWithSize(
670 ExecState* exec, Structure* structure, int32_t length)
671 {
672 return newTypedArrayWithSize<JSInt16Array>(exec, structure, length);
673 }
674
675 char* JIT_OPERATION operationNewInt16ArrayWithOneArgument(
676 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
677 {
678 return newTypedArrayWithOneArgument<JSInt16Array>(exec, structure, encodedValue);
679 }
680
681 char* JIT_OPERATION operationNewInt32ArrayWithSize(
682 ExecState* exec, Structure* structure, int32_t length)
683 {
684 return newTypedArrayWithSize<JSInt32Array>(exec, structure, length);
685 }
686
687 char* JIT_OPERATION operationNewInt32ArrayWithOneArgument(
688 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
689 {
690 return newTypedArrayWithOneArgument<JSInt32Array>(exec, structure, encodedValue);
691 }
692
693 char* JIT_OPERATION operationNewUint8ArrayWithSize(
694 ExecState* exec, Structure* structure, int32_t length)
695 {
696 return newTypedArrayWithSize<JSUint8Array>(exec, structure, length);
697 }
698
699 char* JIT_OPERATION operationNewUint8ArrayWithOneArgument(
700 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
701 {
702 return newTypedArrayWithOneArgument<JSUint8Array>(exec, structure, encodedValue);
703 }
704
705 char* JIT_OPERATION operationNewUint8ClampedArrayWithSize(
706 ExecState* exec, Structure* structure, int32_t length)
707 {
708 return newTypedArrayWithSize<JSUint8ClampedArray>(exec, structure, length);
709 }
710
711 char* JIT_OPERATION operationNewUint8ClampedArrayWithOneArgument(
712 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
713 {
714 return newTypedArrayWithOneArgument<JSUint8ClampedArray>(exec, structure, encodedValue);
715 }
716
717 char* JIT_OPERATION operationNewUint16ArrayWithSize(
718 ExecState* exec, Structure* structure, int32_t length)
719 {
720 return newTypedArrayWithSize<JSUint16Array>(exec, structure, length);
721 }
722
723 char* JIT_OPERATION operationNewUint16ArrayWithOneArgument(
724 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
725 {
726 return newTypedArrayWithOneArgument<JSUint16Array>(exec, structure, encodedValue);
727 }
728
729 char* JIT_OPERATION operationNewUint32ArrayWithSize(
730 ExecState* exec, Structure* structure, int32_t length)
731 {
732 return newTypedArrayWithSize<JSUint32Array>(exec, structure, length);
733 }
734
735 char* JIT_OPERATION operationNewUint32ArrayWithOneArgument(
736 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
737 {
738 return newTypedArrayWithOneArgument<JSUint32Array>(exec, structure, encodedValue);
739 }
740
741 char* JIT_OPERATION operationNewFloat32ArrayWithSize(
742 ExecState* exec, Structure* structure, int32_t length)
743 {
744 return newTypedArrayWithSize<JSFloat32Array>(exec, structure, length);
745 }
746
747 char* JIT_OPERATION operationNewFloat32ArrayWithOneArgument(
748 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
749 {
750 return newTypedArrayWithOneArgument<JSFloat32Array>(exec, structure, encodedValue);
751 }
752
753 char* JIT_OPERATION operationNewFloat64ArrayWithSize(
754 ExecState* exec, Structure* structure, int32_t length)
755 {
756 return newTypedArrayWithSize<JSFloat64Array>(exec, structure, length);
757 }
758
759 char* JIT_OPERATION operationNewFloat64ArrayWithOneArgument(
760 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
761 {
762 return newTypedArrayWithOneArgument<JSFloat64Array>(exec, structure, encodedValue);
763 }
764
765 JSCell* JIT_OPERATION operationCreateActivationDirect(ExecState* exec, Structure* structure, JSScope* scope, SymbolTable* table)
766 {
767 VM& vm = exec->vm();
768 NativeCallFrameTracer tracer(&vm, exec);
769 return JSLexicalEnvironment::create(vm, structure, scope, table);
770 }
771
772 JSCell* JIT_OPERATION operationCreateDirectArguments(ExecState* exec, Structure* structure, int32_t length, int32_t minCapacity)
773 {
774 VM& vm = exec->vm();
775 NativeCallFrameTracer target(&vm, exec);
776 DirectArguments* result = DirectArguments::create(
777 vm, structure, length, std::max(length, minCapacity));
778 // The caller will store to this object without barriers. Most likely, at this point, this is
779 // still a young object and so no barriers are needed. But it's good to be careful anyway,
780 // since the GC should be allowed to do crazy (like pretenuring, for example).
781 vm.heap.writeBarrier(result);
782 return result;
783 }
784
785 JSCell* JIT_OPERATION operationCreateScopedArguments(ExecState* exec, Structure* structure, Register* argumentStart, int32_t length, JSFunction* callee, JSLexicalEnvironment* scope)
786 {
787 VM& vm = exec->vm();
788 NativeCallFrameTracer target(&vm, exec);
789
790 // We could pass the ScopedArgumentsTable* as an argument. We currently don't because I
791 // didn't feel like changing the max number of arguments for a slow path call from 6 to 7.
792 ScopedArgumentsTable* table = scope->symbolTable()->arguments();
793
794 return ScopedArguments::createByCopyingFrom(
795 vm, structure, argumentStart, length, callee, table, scope);
796 }
797
798 JSCell* JIT_OPERATION operationCreateClonedArguments(ExecState* exec, Structure* structure, Register* argumentStart, int32_t length, JSFunction* callee)
799 {
800 VM& vm = exec->vm();
801 NativeCallFrameTracer target(&vm, exec);
802 return ClonedArguments::createByCopyingFrom(
803 exec, structure, argumentStart, length, callee);
804 }
805
806 JSCell* JIT_OPERATION operationCreateDirectArgumentsDuringExit(ExecState* exec, InlineCallFrame* inlineCallFrame, JSFunction* callee, int32_t argumentCount)
807 {
808 VM& vm = exec->vm();
809 NativeCallFrameTracer target(&vm, exec);
810
811 DeferGCForAWhile deferGC(vm.heap);
812
813 CodeBlock* codeBlock;
814 if (inlineCallFrame)
815 codeBlock = baselineCodeBlockForInlineCallFrame(inlineCallFrame);
816 else
817 codeBlock = exec->codeBlock();
818
819 unsigned length = argumentCount - 1;
820 unsigned capacity = std::max(length, static_cast<unsigned>(codeBlock->numParameters() - 1));
821 DirectArguments* result = DirectArguments::create(
822 vm, codeBlock->globalObject()->directArgumentsStructure(), length, capacity);
823
824 result->callee().set(vm, result, callee);
825
826 Register* arguments =
827 exec->registers() + (inlineCallFrame ? inlineCallFrame->stackOffset : 0) +
828 CallFrame::argumentOffset(0);
829 for (unsigned i = length; i--;)
830 result->setIndexQuickly(vm, i, arguments[i].jsValue());
831
832 return result;
833 }
834
835 JSCell* JIT_OPERATION operationCreateClonedArgumentsDuringExit(ExecState* exec, InlineCallFrame* inlineCallFrame, JSFunction* callee, int32_t argumentCount)
836 {
837 VM& vm = exec->vm();
838 NativeCallFrameTracer target(&vm, exec);
839
840 DeferGCForAWhile deferGC(vm.heap);
841
842 CodeBlock* codeBlock;
843 if (inlineCallFrame)
844 codeBlock = baselineCodeBlockForInlineCallFrame(inlineCallFrame);
845 else
846 codeBlock = exec->codeBlock();
847
848 unsigned length = argumentCount - 1;
849 ClonedArguments* result = ClonedArguments::createEmpty(
850 vm, codeBlock->globalObject()->outOfBandArgumentsStructure(), callee);
851
852 Register* arguments =
853 exec->registers() + (inlineCallFrame ? inlineCallFrame->stackOffset : 0) +
854 CallFrame::argumentOffset(0);
855 for (unsigned i = length; i--;)
856 result->putDirectIndex(exec, i, arguments[i].jsValue());
857
858 result->putDirect(vm, vm.propertyNames->length, jsNumber(length));
859
860 return result;
861 }
862
863 size_t JIT_OPERATION operationObjectIsObject(ExecState* exec, JSGlobalObject* globalObject, JSCell* object)
864 {
865 VM& vm = exec->vm();
866 NativeCallFrameTracer tracer(&vm, exec);
867
868 ASSERT(jsDynamicCast<JSObject*>(object));
869
870 if (object->structure(vm)->masqueradesAsUndefined(globalObject))
871 return false;
872 if (object->type() == JSFunctionType)
873 return false;
874 if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) {
875 CallData callData;
876 if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone)
877 return false;
878 }
879
880 return true;
881 }
882
883 size_t JIT_OPERATION operationObjectIsFunction(ExecState* exec, JSGlobalObject* globalObject, JSCell* object)
884 {
885 VM& vm = exec->vm();
886 NativeCallFrameTracer tracer(&vm, exec);
887
888 ASSERT(jsDynamicCast<JSObject*>(object));
889
890 if (object->structure(vm)->masqueradesAsUndefined(globalObject))
891 return false;
892 if (object->type() == JSFunctionType)
893 return true;
894 if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) {
895 CallData callData;
896 if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone)
897 return true;
898 }
899
900 return false;
901 }
902
903 JSCell* JIT_OPERATION operationTypeOfObject(ExecState* exec, JSGlobalObject* globalObject, JSCell* object)
904 {
905 VM& vm = exec->vm();
906 NativeCallFrameTracer tracer(&vm, exec);
907
908 ASSERT(jsDynamicCast<JSObject*>(object));
909
910 if (object->structure(vm)->masqueradesAsUndefined(globalObject))
911 return vm.smallStrings.undefinedString();
912 if (object->type() == JSFunctionType)
913 return vm.smallStrings.functionString();
914 if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) {
915 CallData callData;
916 if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone)
917 return vm.smallStrings.functionString();
918 }
919
920 return vm.smallStrings.objectString();
921 }
922
923 int32_t JIT_OPERATION operationTypeOfObjectAsTypeofType(ExecState* exec, JSGlobalObject* globalObject, JSCell* object)
924 {
925 VM& vm = exec->vm();
926 NativeCallFrameTracer tracer(&vm, exec);
927
928 ASSERT(jsDynamicCast<JSObject*>(object));
929
930 if (object->structure(vm)->masqueradesAsUndefined(globalObject))
931 return static_cast<int32_t>(TypeofType::Undefined);
932 if (object->type() == JSFunctionType)
933 return static_cast<int32_t>(TypeofType::Function);
934 if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) {
935 CallData callData;
936 if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone)
937 return static_cast<int32_t>(TypeofType::Function);
938 }
939
940 return static_cast<int32_t>(TypeofType::Object);
941 }
942
943 char* JIT_OPERATION operationAllocatePropertyStorageWithInitialCapacity(ExecState* exec)
944 {
945 VM& vm = exec->vm();
946 NativeCallFrameTracer tracer(&vm, exec);
947
948 return reinterpret_cast<char*>(
949 Butterfly::createUninitialized(vm, 0, 0, initialOutOfLineCapacity, false, 0));
950 }
951
952 char* JIT_OPERATION operationAllocatePropertyStorage(ExecState* exec, size_t newSize)
953 {
954 VM& vm = exec->vm();
955 NativeCallFrameTracer tracer(&vm, exec);
956
957 return reinterpret_cast<char*>(
958 Butterfly::createUninitialized(vm, 0, 0, newSize, false, 0));
959 }
960
961 char* JIT_OPERATION operationReallocateButterflyToHavePropertyStorageWithInitialCapacity(ExecState* exec, JSObject* object)
962 {
963 VM& vm = exec->vm();
964 NativeCallFrameTracer tracer(&vm, exec);
965
966 ASSERT(!object->structure()->outOfLineCapacity());
967 DeferGC deferGC(vm.heap);
968 Butterfly* result = object->growOutOfLineStorage(vm, 0, initialOutOfLineCapacity);
969 object->setButterflyWithoutChangingStructure(vm, result);
970 return reinterpret_cast<char*>(result);
971 }
972
973 char* JIT_OPERATION operationReallocateButterflyToGrowPropertyStorage(ExecState* exec, JSObject* object, size_t newSize)
974 {
975 VM& vm = exec->vm();
976 NativeCallFrameTracer tracer(&vm, exec);
977
978 DeferGC deferGC(vm.heap);
979 Butterfly* result = object->growOutOfLineStorage(vm, object->structure()->outOfLineCapacity(), newSize);
980 object->setButterflyWithoutChangingStructure(vm, result);
981 return reinterpret_cast<char*>(result);
982 }
983
984 char* JIT_OPERATION operationEnsureInt32(ExecState* exec, JSCell* cell)
985 {
986 VM& vm = exec->vm();
987 NativeCallFrameTracer tracer(&vm, exec);
988
989 if (!cell->isObject())
990 return 0;
991
992 return reinterpret_cast<char*>(asObject(cell)->ensureInt32(vm).data());
993 }
994
995 char* JIT_OPERATION operationEnsureDouble(ExecState* exec, JSCell* cell)
996 {
997 VM& vm = exec->vm();
998 NativeCallFrameTracer tracer(&vm, exec);
999
1000 if (!cell->isObject())
1001 return 0;
1002
1003 return reinterpret_cast<char*>(asObject(cell)->ensureDouble(vm).data());
1004 }
1005
1006 char* JIT_OPERATION operationEnsureContiguous(ExecState* exec, JSCell* cell)
1007 {
1008 VM& vm = exec->vm();
1009 NativeCallFrameTracer tracer(&vm, exec);
1010
1011 if (!cell->isObject())
1012 return 0;
1013
1014 return reinterpret_cast<char*>(asObject(cell)->ensureContiguous(vm).data());
1015 }
1016
1017 char* JIT_OPERATION operationEnsureArrayStorage(ExecState* exec, JSCell* cell)
1018 {
1019 VM& vm = exec->vm();
1020 NativeCallFrameTracer tracer(&vm, exec);
1021
1022 if (!cell->isObject())
1023 return 0;
1024
1025 return reinterpret_cast<char*>(asObject(cell)->ensureArrayStorage(vm));
1026 }
1027
1028 StringImpl* JIT_OPERATION operationResolveRope(ExecState* exec, JSString* string)
1029 {
1030 VM& vm = exec->vm();
1031 NativeCallFrameTracer tracer(&vm, exec);
1032
1033 return string->value(exec).impl();
1034 }
1035
1036 JSString* JIT_OPERATION operationSingleCharacterString(ExecState* exec, int32_t character)
1037 {
1038 VM& vm = exec->vm();
1039 NativeCallFrameTracer tracer(&vm, exec);
1040
1041 return jsSingleCharacterString(exec, static_cast<UChar>(character));
1042 }
1043
1044 JSCell* JIT_OPERATION operationNewStringObject(ExecState* exec, JSString* string, Structure* structure)
1045 {
1046 VM& vm = exec->vm();
1047 NativeCallFrameTracer tracer(&vm, exec);
1048
1049 return StringObject::create(vm, structure, string);
1050 }
1051
1052 JSCell* JIT_OPERATION operationToStringOnCell(ExecState* exec, JSCell* cell)
1053 {
1054 VM& vm = exec->vm();
1055 NativeCallFrameTracer tracer(&vm, exec);
1056
1057 return JSValue(cell).toString(exec);
1058 }
1059
1060 JSCell* JIT_OPERATION operationToString(ExecState* exec, EncodedJSValue value)
1061 {
1062 VM& vm = exec->vm();
1063 NativeCallFrameTracer tracer(&vm, exec);
1064
1065 return JSValue::decode(value).toString(exec);
1066 }
1067
1068 JSCell* JIT_OPERATION operationCallStringConstructorOnCell(ExecState* exec, JSCell* cell)
1069 {
1070 VM& vm = exec->vm();
1071 NativeCallFrameTracer tracer(&vm, exec);
1072
1073 return stringConstructor(exec, cell);
1074 }
1075
1076 JSCell* JIT_OPERATION operationCallStringConstructor(ExecState* exec, EncodedJSValue value)
1077 {
1078 VM& vm = exec->vm();
1079 NativeCallFrameTracer tracer(&vm, exec);
1080
1081 return stringConstructor(exec, JSValue::decode(value));
1082 }
1083
1084 JSCell* JIT_OPERATION operationMakeRope2(ExecState* exec, JSString* left, JSString* right)
1085 {
1086 VM& vm = exec->vm();
1087 NativeCallFrameTracer tracer(&vm, exec);
1088
1089 if (sumOverflows<int32_t>(left->length(), right->length())) {
1090 throwOutOfMemoryError(exec);
1091 return nullptr;
1092 }
1093
1094 return JSRopeString::create(vm, left, right);
1095 }
1096
1097 JSCell* JIT_OPERATION operationMakeRope3(ExecState* exec, JSString* a, JSString* b, JSString* c)
1098 {
1099 VM& vm = exec->vm();
1100 NativeCallFrameTracer tracer(&vm, exec);
1101
1102 if (sumOverflows<int32_t>(a->length(), b->length(), c->length())) {
1103 throwOutOfMemoryError(exec);
1104 return nullptr;
1105 }
1106
1107 return JSRopeString::create(vm, a, b, c);
1108 }
1109
1110 char* JIT_OPERATION operationFindSwitchImmTargetForDouble(
1111 ExecState* exec, EncodedJSValue encodedValue, size_t tableIndex)
1112 {
1113 CodeBlock* codeBlock = exec->codeBlock();
1114 SimpleJumpTable& table = codeBlock->switchJumpTable(tableIndex);
1115 JSValue value = JSValue::decode(encodedValue);
1116 ASSERT(value.isDouble());
1117 double asDouble = value.asDouble();
1118 int32_t asInt32 = static_cast<int32_t>(asDouble);
1119 if (asDouble == asInt32)
1120 return static_cast<char*>(table.ctiForValue(asInt32).executableAddress());
1121 return static_cast<char*>(table.ctiDefault.executableAddress());
1122 }
1123
1124 char* JIT_OPERATION operationSwitchString(ExecState* exec, size_t tableIndex, JSString* string)
1125 {
1126 VM& vm = exec->vm();
1127 NativeCallFrameTracer tracer(&vm, exec);
1128
1129 return static_cast<char*>(exec->codeBlock()->stringSwitchJumpTable(tableIndex).ctiForValue(string->value(exec).impl()).executableAddress());
1130 }
1131
1132 int32_t JIT_OPERATION operationSwitchStringAndGetBranchOffset(ExecState* exec, size_t tableIndex, JSString* string)
1133 {
1134 VM& vm = exec->vm();
1135 NativeCallFrameTracer tracer(&vm, exec);
1136
1137 return exec->codeBlock()->stringSwitchJumpTable(tableIndex).offsetForValue(string->value(exec).impl(), std::numeric_limits<int32_t>::min());
1138 }
1139
1140 void JIT_OPERATION operationNotifyWrite(ExecState* exec, WatchpointSet* set)
1141 {
1142 VM& vm = exec->vm();
1143 NativeCallFrameTracer tracer(&vm, exec);
1144
1145 set->touch("Executed NotifyWrite");
1146 }
1147
1148 void JIT_OPERATION operationThrowStackOverflowForVarargs(ExecState* exec)
1149 {
1150 VM& vm = exec->vm();
1151 NativeCallFrameTracer tracer(&vm, exec);
1152 throwStackOverflowError(exec);
1153 }
1154
1155 int32_t JIT_OPERATION operationSizeOfVarargs(ExecState* exec, EncodedJSValue encodedArguments, int32_t firstVarArgOffset)
1156 {
1157 VM& vm = exec->vm();
1158 NativeCallFrameTracer tracer(&vm, exec);
1159 JSValue arguments = JSValue::decode(encodedArguments);
1160
1161 return sizeOfVarargs(exec, arguments, firstVarArgOffset);
1162 }
1163
1164 void JIT_OPERATION operationLoadVarargs(ExecState* exec, int32_t firstElementDest, EncodedJSValue encodedArguments, int32_t offset, int32_t length, int32_t mandatoryMinimum)
1165 {
1166 VM& vm = exec->vm();
1167 NativeCallFrameTracer tracer(&vm, exec);
1168 JSValue arguments = JSValue::decode(encodedArguments);
1169
1170 loadVarargs(exec, VirtualRegister(firstElementDest), arguments, offset, length);
1171
1172 for (int32_t i = length; i < mandatoryMinimum; ++i)
1173 exec->r(firstElementDest + i) = jsUndefined();
1174 }
1175
1176 double JIT_OPERATION operationFModOnInts(int32_t a, int32_t b)
1177 {
1178 return fmod(a, b);
1179 }
1180
1181 JSCell* JIT_OPERATION operationStringFromCharCode(ExecState* exec, int32_t op1)
1182 {
1183 VM* vm = &exec->vm();
1184 NativeCallFrameTracer tracer(vm, exec);
1185 return JSC::stringFromCharCode(exec, op1);
1186 }
1187
1188 int64_t JIT_OPERATION operationConvertBoxedDoubleToInt52(EncodedJSValue encodedValue)
1189 {
1190 JSValue value = JSValue::decode(encodedValue);
1191 if (!value.isDouble())
1192 return JSValue::notInt52;
1193 return tryConvertToInt52(value.asDouble());
1194 }
1195
1196 int64_t JIT_OPERATION operationConvertDoubleToInt52(double value)
1197 {
1198 return tryConvertToInt52(value);
1199 }
1200
1201 void JIT_OPERATION operationProcessTypeProfilerLogDFG(ExecState* exec)
1202 {
1203 exec->vm().typeProfilerLog()->processLogEntries(ASCIILiteral("Log Full, called from inside DFG."));
1204 }
1205
1206 size_t JIT_OPERATION dfgConvertJSValueToInt32(ExecState* exec, EncodedJSValue value)
1207 {
1208 VM* vm = &exec->vm();
1209 NativeCallFrameTracer tracer(vm, exec);
1210
1211 // toInt32/toUInt32 return the same value; we want the value zero extended to fill the register.
1212 return JSValue::decode(value).toUInt32(exec);
1213 }
1214
1215 void JIT_OPERATION debugOperationPrintSpeculationFailure(ExecState* exec, void* debugInfoRaw, void* scratch)
1216 {
1217 VM* vm = &exec->vm();
1218 NativeCallFrameTracer tracer(vm, exec);
1219
1220 SpeculationFailureDebugInfo* debugInfo = static_cast<SpeculationFailureDebugInfo*>(debugInfoRaw);
1221 CodeBlock* codeBlock = debugInfo->codeBlock;
1222 CodeBlock* alternative = codeBlock->alternative();
1223 dataLog("Speculation failure in ", *codeBlock);
1224 dataLog(" @ exit #", vm->osrExitIndex, " (bc#", debugInfo->bytecodeOffset, ", ", exitKindToString(debugInfo->kind), ") with ");
1225 if (alternative) {
1226 dataLog(
1227 "executeCounter = ", alternative->jitExecuteCounter(),
1228 ", reoptimizationRetryCounter = ", alternative->reoptimizationRetryCounter(),
1229 ", optimizationDelayCounter = ", alternative->optimizationDelayCounter());
1230 } else
1231 dataLog("no alternative code block (i.e. we've been jettisoned)");
1232 dataLog(", osrExitCounter = ", codeBlock->osrExitCounter(), "\n");
1233 dataLog(" GPRs at time of exit:");
1234 char* scratchPointer = static_cast<char*>(scratch);
1235 for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) {
1236 GPRReg gpr = GPRInfo::toRegister(i);
1237 dataLog(" ", GPRInfo::debugName(gpr), ":", RawPointer(*reinterpret_cast_ptr<void**>(scratchPointer)));
1238 scratchPointer += sizeof(EncodedJSValue);
1239 }
1240 dataLog("\n");
1241 dataLog(" FPRs at time of exit:");
1242 for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) {
1243 FPRReg fpr = FPRInfo::toRegister(i);
1244 dataLog(" ", FPRInfo::debugName(fpr), ":");
1245 uint64_t bits = *reinterpret_cast_ptr<uint64_t*>(scratchPointer);
1246 double value = *reinterpret_cast_ptr<double*>(scratchPointer);
1247 dataLogF("%llx:%lf", static_cast<long long>(bits), value);
1248 scratchPointer += sizeof(EncodedJSValue);
1249 }
1250 dataLog("\n");
1251 }
1252
1253 extern "C" void JIT_OPERATION triggerReoptimizationNow(CodeBlock* codeBlock, OSRExitBase* exit)
1254 {
1255 // It's sort of preferable that we don't GC while in here. Anyways, doing so wouldn't
1256 // really be profitable.
1257 DeferGCForAWhile deferGC(codeBlock->vm()->heap);
1258
1259 if (Options::verboseOSR())
1260 dataLog(*codeBlock, ": Entered reoptimize\n");
1261 // We must be called with the baseline code block.
1262 ASSERT(JITCode::isBaselineCode(codeBlock->jitType()));
1263
1264 // If I am my own replacement, then reoptimization has already been triggered.
1265 // This can happen in recursive functions.
1266 if (codeBlock->replacement() == codeBlock) {
1267 if (Options::verboseOSR())
1268 dataLog(*codeBlock, ": Not reoptimizing because we've already been jettisoned.\n");
1269 return;
1270 }
1271
1272 // Otherwise, the replacement must be optimized code. Use this as an opportunity
1273 // to check our logic.
1274 ASSERT(codeBlock->hasOptimizedReplacement());
1275 CodeBlock* optimizedCodeBlock = codeBlock->replacement();
1276 ASSERT(JITCode::isOptimizingJIT(optimizedCodeBlock->jitType()));
1277
1278 bool didTryToEnterIntoInlinedLoops = false;
1279 for (InlineCallFrame* inlineCallFrame = exit->m_codeOrigin.inlineCallFrame; inlineCallFrame; inlineCallFrame = inlineCallFrame->caller.inlineCallFrame) {
1280 if (inlineCallFrame->executable->didTryToEnterInLoop()) {
1281 didTryToEnterIntoInlinedLoops = true;
1282 break;
1283 }
1284 }
1285
1286 // In order to trigger reoptimization, one of two things must have happened:
1287 // 1) We exited more than some number of times.
1288 // 2) We exited and got stuck in a loop, and now we're exiting again.
1289 bool didExitABunch = optimizedCodeBlock->shouldReoptimizeNow();
1290 bool didGetStuckInLoop =
1291 (codeBlock->checkIfOptimizationThresholdReached() || didTryToEnterIntoInlinedLoops)
1292 && optimizedCodeBlock->shouldReoptimizeFromLoopNow();
1293
1294 if (!didExitABunch && !didGetStuckInLoop) {
1295 if (Options::verboseOSR())
1296 dataLog(*codeBlock, ": Not reoptimizing ", *optimizedCodeBlock, " because it either didn't exit enough or didn't loop enough after exit.\n");
1297 codeBlock->optimizeAfterLongWarmUp();
1298 return;
1299 }
1300
1301 optimizedCodeBlock->jettison(Profiler::JettisonDueToOSRExit, CountReoptimization);
1302 }
1303
1304 #if ENABLE(FTL_JIT)
1305 static void triggerFTLReplacementCompile(VM* vm, CodeBlock* codeBlock, JITCode* jitCode)
1306 {
1307 if (codeBlock->baselineVersion()->m_didFailFTLCompilation) {
1308 if (Options::verboseOSR())
1309 dataLog("Deferring FTL-optimization of ", *codeBlock, " indefinitely because there was an FTL failure.\n");
1310 jitCode->dontOptimizeAnytimeSoon(codeBlock);
1311 return;
1312 }
1313
1314 if (!jitCode->checkIfOptimizationThresholdReached(codeBlock)) {
1315 if (Options::verboseOSR())
1316 dataLog("Choosing not to FTL-optimize ", *codeBlock, " yet.\n");
1317 return;
1318 }
1319
1320 Worklist::State worklistState;
1321 if (Worklist* worklist = existingGlobalFTLWorklistOrNull()) {
1322 worklistState = worklist->completeAllReadyPlansForVM(
1323 *vm, CompilationKey(codeBlock->baselineVersion(), FTLMode));
1324 } else
1325 worklistState = Worklist::NotKnown;
1326
1327 if (worklistState == Worklist::Compiling) {
1328 jitCode->setOptimizationThresholdBasedOnCompilationResult(
1329 codeBlock, CompilationDeferred);
1330 return;
1331 }
1332
1333 if (codeBlock->hasOptimizedReplacement()) {
1334 // That's great, we've compiled the code - next time we call this function,
1335 // we'll enter that replacement.
1336 jitCode->optimizeSoon(codeBlock);
1337 return;
1338 }
1339
1340 if (worklistState == Worklist::Compiled) {
1341 // This means that we finished compiling, but failed somehow; in that case the
1342 // thresholds will be set appropriately.
1343 if (Options::verboseOSR())
1344 dataLog("Code block ", *codeBlock, " was compiled but it doesn't have an optimized replacement.\n");
1345 return;
1346 }
1347
1348 // We need to compile the code.
1349 compile(
1350 *vm, codeBlock->newReplacement().get(), codeBlock, FTLMode, UINT_MAX,
1351 Operands<JSValue>(), ToFTLDeferredCompilationCallback::create(codeBlock));
1352 }
1353
1354 static void triggerTierUpNowCommon(ExecState* exec, bool inLoop)
1355 {
1356 VM* vm = &exec->vm();
1357 NativeCallFrameTracer tracer(vm, exec);
1358 DeferGC deferGC(vm->heap);
1359 CodeBlock* codeBlock = exec->codeBlock();
1360
1361 if (codeBlock->jitType() != JITCode::DFGJIT) {
1362 dataLog("Unexpected code block in DFG->FTL tier-up: ", *codeBlock, "\n");
1363 RELEASE_ASSERT_NOT_REACHED();
1364 }
1365
1366 JITCode* jitCode = codeBlock->jitCode()->dfg();
1367
1368 if (Options::verboseOSR()) {
1369 dataLog(
1370 *codeBlock, ": Entered triggerTierUpNow with executeCounter = ",
1371 jitCode->tierUpCounter, "\n");
1372 }
1373 if (inLoop)
1374 jitCode->nestedTriggerIsSet = 1;
1375
1376 triggerFTLReplacementCompile(vm, codeBlock, jitCode);
1377 }
1378
1379 void JIT_OPERATION triggerTierUpNow(ExecState* exec)
1380 {
1381 triggerTierUpNowCommon(exec, false);
1382 }
1383
1384 void JIT_OPERATION triggerTierUpNowInLoop(ExecState* exec)
1385 {
1386 triggerTierUpNowCommon(exec, true);
1387 }
1388
1389 char* JIT_OPERATION triggerOSREntryNow(
1390 ExecState* exec, int32_t bytecodeIndex, int32_t streamIndex)
1391 {
1392 VM* vm = &exec->vm();
1393 NativeCallFrameTracer tracer(vm, exec);
1394 DeferGC deferGC(vm->heap);
1395 CodeBlock* codeBlock = exec->codeBlock();
1396
1397 if (codeBlock->jitType() != JITCode::DFGJIT) {
1398 dataLog("Unexpected code block in DFG->FTL tier-up: ", *codeBlock, "\n");
1399 RELEASE_ASSERT_NOT_REACHED();
1400 }
1401
1402 JITCode* jitCode = codeBlock->jitCode()->dfg();
1403 jitCode->nestedTriggerIsSet = 0;
1404
1405 if (Options::verboseOSR()) {
1406 dataLog(
1407 *codeBlock, ": Entered triggerOSREntryNow with executeCounter = ",
1408 jitCode->tierUpCounter, "\n");
1409 }
1410
1411 // - If we don't have an FTL code block, then try to compile one.
1412 // - If we do have an FTL code block, then try to enter for a while.
1413 // - If we couldn't enter for a while, then trigger OSR entry.
1414
1415 triggerFTLReplacementCompile(vm, codeBlock, jitCode);
1416
1417 if (!codeBlock->hasOptimizedReplacement())
1418 return 0;
1419
1420 if (jitCode->osrEntryRetry < Options::ftlOSREntryRetryThreshold()) {
1421 jitCode->osrEntryRetry++;
1422 return 0;
1423 }
1424
1425 // It's time to try to compile code for OSR entry.
1426 Worklist::State worklistState;
1427 if (Worklist* worklist = existingGlobalFTLWorklistOrNull()) {
1428 worklistState = worklist->completeAllReadyPlansForVM(
1429 *vm, CompilationKey(codeBlock->baselineVersion(), FTLForOSREntryMode));
1430 } else
1431 worklistState = Worklist::NotKnown;
1432
1433 if (worklistState == Worklist::Compiling)
1434 return 0;
1435
1436 if (CodeBlock* entryBlock = jitCode->osrEntryBlock.get()) {
1437 void* address = FTL::prepareOSREntry(
1438 exec, codeBlock, entryBlock, bytecodeIndex, streamIndex);
1439 if (address)
1440 return static_cast<char*>(address);
1441
1442 FTL::ForOSREntryJITCode* entryCode = entryBlock->jitCode()->ftlForOSREntry();
1443 entryCode->countEntryFailure();
1444 if (entryCode->entryFailureCount() <
1445 Options::ftlOSREntryFailureCountForReoptimization())
1446 return 0;
1447
1448 // OSR entry failed. Oh no! This implies that we need to retry. We retry
1449 // without exponential backoff and we only do this for the entry code block.
1450 jitCode->osrEntryBlock = nullptr;
1451 jitCode->osrEntryRetry = 0;
1452 return 0;
1453 }
1454
1455 if (worklistState == Worklist::Compiled) {
1456 // This means that compilation failed and we already set the thresholds.
1457 if (Options::verboseOSR())
1458 dataLog("Code block ", *codeBlock, " was compiled but it doesn't have an optimized replacement.\n");
1459 return 0;
1460 }
1461
1462 // We aren't compiling and haven't compiled anything for OSR entry. So, try to compile
1463 // something.
1464 Operands<JSValue> mustHandleValues;
1465 jitCode->reconstruct(
1466 exec, codeBlock, CodeOrigin(bytecodeIndex), streamIndex, mustHandleValues);
1467 RefPtr<CodeBlock> replacementCodeBlock = codeBlock->newReplacement();
1468 CompilationResult forEntryResult = compile(
1469 *vm, replacementCodeBlock.get(), codeBlock, FTLForOSREntryMode, bytecodeIndex,
1470 mustHandleValues, ToFTLForOSREntryDeferredCompilationCallback::create(codeBlock));
1471
1472 if (forEntryResult != CompilationSuccessful) {
1473 ASSERT(forEntryResult == CompilationDeferred || replacementCodeBlock->hasOneRef());
1474 return 0;
1475 }
1476
1477 // It's possible that the for-entry compile already succeeded. In that case OSR
1478 // entry will succeed unless we ran out of stack. It's not clear what we should do.
1479 // We signal to try again after a while if that happens.
1480 void* address = FTL::prepareOSREntry(
1481 exec, codeBlock, jitCode->osrEntryBlock.get(), bytecodeIndex, streamIndex);
1482 return static_cast<char*>(address);
1483 }
1484 #endif // ENABLE(FTL_JIT)
1485
1486 } // extern "C"
1487 } } // namespace JSC::DFG
1488
1489 #endif // ENABLE(DFG_JIT)
1490
1491 #endif // ENABLE(JIT)