]> git.saurik.com Git - apple/javascriptcore.git/blob - dfg/DFGOperations.cpp
15cb4f5c45caa1d282da2c7e874bfcf0cd62d910
[apple/javascriptcore.git] / dfg / DFGOperations.cpp
1 /*
2 * Copyright (C) 2011, 2013, 2014 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 "Arguments.h"
30 #include "ButterflyInlines.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 "FTLForOSREntryJITCode.h"
42 #include "FTLOSREntry.h"
43 #include "HostCallReturnValue.h"
44 #include "GetterSetter.h"
45 #include "Interpreter.h"
46 #include "JIT.h"
47 #include "JITExceptions.h"
48 #include "JSActivation.h"
49 #include "VM.h"
50 #include "JSNameScope.h"
51 #include "NameInstance.h"
52 #include "ObjectConstructor.h"
53 #include "JSCInlines.h"
54 #include "Repatch.h"
55 #include "StringConstructor.h"
56 #include "TypedArrayInlines.h"
57 #include <wtf/InlineASM.h>
58
59 #if ENABLE(JIT)
60 #if ENABLE(DFG_JIT)
61
62 namespace JSC { namespace DFG {
63
64 template<bool strict, bool direct>
65 static inline void putByVal(ExecState* exec, JSValue baseValue, uint32_t index, JSValue value)
66 {
67 VM& vm = exec->vm();
68 NativeCallFrameTracer tracer(&vm, exec);
69 if (direct) {
70 RELEASE_ASSERT(baseValue.isObject());
71 asObject(baseValue)->putDirectIndex(exec, index, value, 0, strict ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
72 return;
73 }
74 if (baseValue.isObject()) {
75 JSObject* object = asObject(baseValue);
76 if (object->canSetIndexQuickly(index)) {
77 object->setIndexQuickly(vm, index, value);
78 return;
79 }
80
81 object->methodTable(vm)->putByIndex(object, exec, index, value, strict);
82 return;
83 }
84
85 baseValue.putByIndex(exec, index, value, strict);
86 }
87
88 template<bool strict, bool direct>
89 ALWAYS_INLINE static void JIT_OPERATION operationPutByValInternal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
90 {
91 VM* vm = &exec->vm();
92 NativeCallFrameTracer tracer(vm, exec);
93
94 JSValue baseValue = JSValue::decode(encodedBase);
95 JSValue property = JSValue::decode(encodedProperty);
96 JSValue value = JSValue::decode(encodedValue);
97
98 if (LIKELY(property.isUInt32())) {
99 putByVal<strict, direct>(exec, baseValue, property.asUInt32(), value);
100 return;
101 }
102
103 if (property.isDouble()) {
104 double propertyAsDouble = property.asDouble();
105 uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
106 if (propertyAsDouble == propertyAsUInt32) {
107 putByVal<strict, direct>(exec, baseValue, propertyAsUInt32, value);
108 return;
109 }
110 }
111
112 if (isName(property)) {
113 PutPropertySlot slot(baseValue, strict);
114 if (direct) {
115 RELEASE_ASSERT(baseValue.isObject());
116 asObject(baseValue)->putDirect(*vm, jsCast<NameInstance*>(property.asCell())->privateName(), value, slot);
117 } else
118 baseValue.put(exec, jsCast<NameInstance*>(property.asCell())->privateName(), value, slot);
119 return;
120 }
121
122 // Don't put to an object if toString throws an exception.
123 Identifier ident = property.toString(exec)->toIdentifier(exec);
124 if (!vm->exception()) {
125 PutPropertySlot slot(baseValue, strict);
126 if (direct) {
127 RELEASE_ASSERT(baseValue.isObject());
128 asObject(baseValue)->putDirect(*vm, jsCast<NameInstance*>(property.asCell())->privateName(), value, slot);
129 } else
130 baseValue.put(exec, ident, value, slot);
131 }
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, "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, "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, "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, "Invalid array length argument (fractional lengths not allowed)"));
192 return 0;
193 }
194 }
195
196 if (length < 0) {
197 vm.throwException(exec, createRangeError(exec, "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)->allocationProfile(exec, inlineCapacity)->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)
296 return getByVal(exec, base, propertyAsUInt32);
297 } else if (property.isString()) {
298 Structure& structure = *base->structure(vm);
299 if (JSCell::canUseFastGetOwnProperty(structure)) {
300 if (JSValue result = base->fastGetOwnProperty(vm, structure, asString(property)->value(exec)))
301 return JSValue::encode(result);
302 }
303 }
304 }
305
306 if (isName(property))
307 return JSValue::encode(baseValue.get(exec, jsCast<NameInstance*>(property.asCell())->privateName()));
308
309 Identifier ident = property.toString(exec)->toIdentifier(exec);
310 return JSValue::encode(baseValue.get(exec, ident));
311 }
312
313 EncodedJSValue JIT_OPERATION operationGetByValCell(ExecState* exec, JSCell* base, EncodedJSValue encodedProperty)
314 {
315 VM& vm = exec->vm();
316 NativeCallFrameTracer tracer(&vm, exec);
317
318 JSValue property = JSValue::decode(encodedProperty);
319
320 if (property.isUInt32())
321 return getByVal(exec, base, property.asUInt32());
322 if (property.isDouble()) {
323 double propertyAsDouble = property.asDouble();
324 uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
325 if (propertyAsUInt32 == propertyAsDouble)
326 return getByVal(exec, base, propertyAsUInt32);
327 } else if (property.isString()) {
328 Structure& structure = *base->structure(vm);
329 if (JSCell::canUseFastGetOwnProperty(structure)) {
330 if (JSValue result = base->fastGetOwnProperty(vm, structure, asString(property)->value(exec)))
331 return JSValue::encode(result);
332 }
333 }
334
335 if (isName(property))
336 return JSValue::encode(JSValue(base).get(exec, jsCast<NameInstance*>(property.asCell())->privateName()));
337
338 Identifier ident = property.toString(exec)->toIdentifier(exec);
339 return JSValue::encode(JSValue(base).get(exec, ident));
340 }
341
342 ALWAYS_INLINE EncodedJSValue getByValCellInt(ExecState* exec, JSCell* base, int32_t index)
343 {
344 VM* vm = &exec->vm();
345 NativeCallFrameTracer tracer(vm, exec);
346
347 if (index < 0) {
348 // Go the slowest way possible becase negative indices don't use indexed storage.
349 return JSValue::encode(JSValue(base).get(exec, Identifier::from(exec, index)));
350 }
351
352 // Use this since we know that the value is out of bounds.
353 return JSValue::encode(JSValue(base).get(exec, index));
354 }
355
356 EncodedJSValue JIT_OPERATION operationGetByValArrayInt(ExecState* exec, JSArray* base, int32_t index)
357 {
358 return getByValCellInt(exec, base, index);
359 }
360
361 EncodedJSValue JIT_OPERATION operationGetByValStringInt(ExecState* exec, JSString* base, int32_t index)
362 {
363 return getByValCellInt(exec, base, index);
364 }
365
366 void JIT_OPERATION operationPutByValStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
367 {
368 VM* vm = &exec->vm();
369 NativeCallFrameTracer tracer(vm, exec);
370
371 operationPutByValInternal<true, false>(exec, encodedBase, encodedProperty, encodedValue);
372 }
373
374 void JIT_OPERATION operationPutByValNonStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
375 {
376 VM* vm = &exec->vm();
377 NativeCallFrameTracer tracer(vm, exec);
378
379 operationPutByValInternal<false, false>(exec, encodedBase, encodedProperty, encodedValue);
380 }
381
382 void JIT_OPERATION operationPutByValCellStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
383 {
384 VM* vm = &exec->vm();
385 NativeCallFrameTracer tracer(vm, exec);
386
387 operationPutByValInternal<true, false>(exec, JSValue::encode(cell), encodedProperty, encodedValue);
388 }
389
390 void JIT_OPERATION operationPutByValCellNonStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
391 {
392 VM* vm = &exec->vm();
393 NativeCallFrameTracer tracer(vm, exec);
394
395 operationPutByValInternal<false, false>(exec, JSValue::encode(cell), encodedProperty, encodedValue);
396 }
397
398 void JIT_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue)
399 {
400 VM& vm = exec->vm();
401 NativeCallFrameTracer tracer(&vm, exec);
402
403 if (index >= 0) {
404 array->putByIndexInline(exec, index, JSValue::decode(encodedValue), true);
405 return;
406 }
407
408 PutPropertySlot slot(array, true);
409 array->methodTable()->put(
410 array, exec, Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
411 }
412
413 void JIT_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue)
414 {
415 VM* vm = &exec->vm();
416 NativeCallFrameTracer tracer(vm, exec);
417
418 if (index >= 0) {
419 array->putByIndexInline(exec, index, JSValue::decode(encodedValue), false);
420 return;
421 }
422
423 PutPropertySlot slot(array, false);
424 array->methodTable()->put(
425 array, exec, Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
426 }
427
428 void JIT_OPERATION operationPutDoubleByValBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, double value)
429 {
430 VM* vm = &exec->vm();
431 NativeCallFrameTracer tracer(vm, exec);
432
433 JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value);
434
435 if (index >= 0) {
436 array->putByIndexInline(exec, index, jsValue, true);
437 return;
438 }
439
440 PutPropertySlot slot(array, true);
441 array->methodTable()->put(
442 array, exec, Identifier::from(exec, index), jsValue, slot);
443 }
444
445 void JIT_OPERATION operationPutDoubleByValBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* array, int32_t index, double value)
446 {
447 VM* vm = &exec->vm();
448 NativeCallFrameTracer tracer(vm, exec);
449
450 JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value);
451
452 if (index >= 0) {
453 array->putByIndexInline(exec, index, jsValue, false);
454 return;
455 }
456
457 PutPropertySlot slot(array, false);
458 array->methodTable()->put(
459 array, exec, Identifier::from(exec, index), jsValue, slot);
460 }
461
462 void JIT_OPERATION operationPutByValDirectStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
463 {
464 VM* vm = &exec->vm();
465 NativeCallFrameTracer tracer(vm, exec);
466
467 operationPutByValInternal<true, true>(exec, encodedBase, encodedProperty, encodedValue);
468 }
469
470 void JIT_OPERATION operationPutByValDirectNonStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
471 {
472 VM* vm = &exec->vm();
473 NativeCallFrameTracer tracer(vm, exec);
474
475 operationPutByValInternal<false, true>(exec, encodedBase, encodedProperty, encodedValue);
476 }
477
478 void JIT_OPERATION operationPutByValDirectCellStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
479 {
480 VM* vm = &exec->vm();
481 NativeCallFrameTracer tracer(vm, exec);
482
483 operationPutByValInternal<true, true>(exec, JSValue::encode(cell), encodedProperty, encodedValue);
484 }
485
486 void JIT_OPERATION operationPutByValDirectCellNonStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
487 {
488 VM* vm = &exec->vm();
489 NativeCallFrameTracer tracer(vm, exec);
490
491 operationPutByValInternal<false, true>(exec, JSValue::encode(cell), encodedProperty, encodedValue);
492 }
493
494 void JIT_OPERATION operationPutByValDirectBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue)
495 {
496 VM* vm = &exec->vm();
497 NativeCallFrameTracer tracer(vm, exec);
498 if (index >= 0) {
499 array->putDirectIndex(exec, index, JSValue::decode(encodedValue), 0, PutDirectIndexShouldThrow);
500 return;
501 }
502
503 PutPropertySlot slot(array, true);
504 array->putDirect(exec->vm(), Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
505 }
506
507 void JIT_OPERATION operationPutByValDirectBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue)
508 {
509 VM* vm = &exec->vm();
510 NativeCallFrameTracer tracer(vm, exec);
511
512 if (index >= 0) {
513 array->putDirectIndex(exec, index, JSValue::decode(encodedValue));
514 return;
515 }
516
517 PutPropertySlot slot(array, false);
518 array->putDirect(exec->vm(), Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
519 }
520
521 EncodedJSValue JIT_OPERATION operationArrayPush(ExecState* exec, EncodedJSValue encodedValue, JSArray* array)
522 {
523 VM* vm = &exec->vm();
524 NativeCallFrameTracer tracer(vm, exec);
525
526 array->push(exec, JSValue::decode(encodedValue));
527 return JSValue::encode(jsNumber(array->length()));
528 }
529
530 EncodedJSValue JIT_OPERATION operationArrayPushDouble(ExecState* exec, double value, JSArray* array)
531 {
532 VM* vm = &exec->vm();
533 NativeCallFrameTracer tracer(vm, exec);
534
535 array->push(exec, JSValue(JSValue::EncodeAsDouble, value));
536 return JSValue::encode(jsNumber(array->length()));
537 }
538
539 EncodedJSValue JIT_OPERATION operationArrayPop(ExecState* exec, JSArray* array)
540 {
541 VM* vm = &exec->vm();
542 NativeCallFrameTracer tracer(vm, exec);
543
544 return JSValue::encode(array->pop(exec));
545 }
546
547 EncodedJSValue JIT_OPERATION operationArrayPopAndRecoverLength(ExecState* exec, JSArray* array)
548 {
549 VM* vm = &exec->vm();
550 NativeCallFrameTracer tracer(vm, exec);
551
552 array->butterfly()->setPublicLength(array->butterfly()->publicLength() + 1);
553
554 return JSValue::encode(array->pop(exec));
555 }
556
557 EncodedJSValue JIT_OPERATION operationRegExpExec(ExecState* exec, JSCell* base, JSCell* argument)
558 {
559 VM& vm = exec->vm();
560 NativeCallFrameTracer tracer(&vm, exec);
561
562 if (!base->inherits(RegExpObject::info()))
563 return throwVMTypeError(exec);
564
565 ASSERT(argument->isString() || argument->isObject());
566 JSString* input = argument->isString() ? asString(argument) : asObject(argument)->toString(exec);
567 return JSValue::encode(asRegExpObject(base)->exec(exec, input));
568 }
569
570 size_t JIT_OPERATION operationRegExpTest(ExecState* exec, JSCell* base, JSCell* argument)
571 {
572 VM& vm = exec->vm();
573 NativeCallFrameTracer tracer(&vm, exec);
574
575 if (!base->inherits(RegExpObject::info())) {
576 throwTypeError(exec);
577 return false;
578 }
579
580 ASSERT(argument->isString() || argument->isObject());
581 JSString* input = argument->isString() ? asString(argument) : asObject(argument)->toString(exec);
582 return asRegExpObject(base)->test(exec, input);
583 }
584
585 size_t JIT_OPERATION operationCompareStrictEqCell(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
586 {
587 VM* vm = &exec->vm();
588 NativeCallFrameTracer tracer(vm, exec);
589
590 JSValue op1 = JSValue::decode(encodedOp1);
591 JSValue op2 = JSValue::decode(encodedOp2);
592
593 ASSERT(op1.isCell());
594 ASSERT(op2.isCell());
595
596 return JSValue::strictEqualSlowCaseInline(exec, op1, op2);
597 }
598
599 size_t JIT_OPERATION operationCompareStrictEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
600 {
601 VM* vm = &exec->vm();
602 NativeCallFrameTracer tracer(vm, exec);
603
604 JSValue src1 = JSValue::decode(encodedOp1);
605 JSValue src2 = JSValue::decode(encodedOp2);
606
607 return JSValue::strictEqual(exec, src1, src2);
608 }
609
610 EncodedJSValue JIT_OPERATION operationToPrimitive(ExecState* exec, EncodedJSValue value)
611 {
612 VM* vm = &exec->vm();
613 NativeCallFrameTracer tracer(vm, exec);
614
615 return JSValue::encode(JSValue::decode(value).toPrimitive(exec));
616 }
617
618 char* JIT_OPERATION operationNewArray(ExecState* exec, Structure* arrayStructure, void* buffer, size_t size)
619 {
620 VM* vm = &exec->vm();
621 NativeCallFrameTracer tracer(vm, exec);
622
623 return bitwise_cast<char*>(constructArray(exec, arrayStructure, static_cast<JSValue*>(buffer), size));
624 }
625
626 char* JIT_OPERATION operationNewEmptyArray(ExecState* exec, Structure* arrayStructure)
627 {
628 VM* vm = &exec->vm();
629 NativeCallFrameTracer tracer(vm, exec);
630
631 return bitwise_cast<char*>(JSArray::create(*vm, arrayStructure));
632 }
633
634 char* JIT_OPERATION operationNewArrayWithSize(ExecState* exec, Structure* arrayStructure, int32_t size)
635 {
636 VM* vm = &exec->vm();
637 NativeCallFrameTracer tracer(vm, exec);
638
639 if (UNLIKELY(size < 0))
640 return bitwise_cast<char*>(exec->vm().throwException(exec, createRangeError(exec, ASCIILiteral("Array size is not a small enough positive integer."))));
641
642 return bitwise_cast<char*>(JSArray::create(*vm, arrayStructure, size));
643 }
644
645 char* JIT_OPERATION operationNewArrayBuffer(ExecState* exec, Structure* arrayStructure, size_t start, size_t size)
646 {
647 VM& vm = exec->vm();
648 NativeCallFrameTracer tracer(&vm, exec);
649 return bitwise_cast<char*>(constructArray(exec, arrayStructure, exec->codeBlock()->constantBuffer(start), size));
650 }
651
652 char* JIT_OPERATION operationNewInt8ArrayWithSize(
653 ExecState* exec, Structure* structure, int32_t length)
654 {
655 return newTypedArrayWithSize<JSInt8Array>(exec, structure, length);
656 }
657
658 char* JIT_OPERATION operationNewInt8ArrayWithOneArgument(
659 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
660 {
661 return newTypedArrayWithOneArgument<JSInt8Array>(exec, structure, encodedValue);
662 }
663
664 char* JIT_OPERATION operationNewInt16ArrayWithSize(
665 ExecState* exec, Structure* structure, int32_t length)
666 {
667 return newTypedArrayWithSize<JSInt16Array>(exec, structure, length);
668 }
669
670 char* JIT_OPERATION operationNewInt16ArrayWithOneArgument(
671 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
672 {
673 return newTypedArrayWithOneArgument<JSInt16Array>(exec, structure, encodedValue);
674 }
675
676 char* JIT_OPERATION operationNewInt32ArrayWithSize(
677 ExecState* exec, Structure* structure, int32_t length)
678 {
679 return newTypedArrayWithSize<JSInt32Array>(exec, structure, length);
680 }
681
682 char* JIT_OPERATION operationNewInt32ArrayWithOneArgument(
683 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
684 {
685 return newTypedArrayWithOneArgument<JSInt32Array>(exec, structure, encodedValue);
686 }
687
688 char* JIT_OPERATION operationNewUint8ArrayWithSize(
689 ExecState* exec, Structure* structure, int32_t length)
690 {
691 return newTypedArrayWithSize<JSUint8Array>(exec, structure, length);
692 }
693
694 char* JIT_OPERATION operationNewUint8ArrayWithOneArgument(
695 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
696 {
697 return newTypedArrayWithOneArgument<JSUint8Array>(exec, structure, encodedValue);
698 }
699
700 char* JIT_OPERATION operationNewUint8ClampedArrayWithSize(
701 ExecState* exec, Structure* structure, int32_t length)
702 {
703 return newTypedArrayWithSize<JSUint8ClampedArray>(exec, structure, length);
704 }
705
706 char* JIT_OPERATION operationNewUint8ClampedArrayWithOneArgument(
707 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
708 {
709 return newTypedArrayWithOneArgument<JSUint8ClampedArray>(exec, structure, encodedValue);
710 }
711
712 char* JIT_OPERATION operationNewUint16ArrayWithSize(
713 ExecState* exec, Structure* structure, int32_t length)
714 {
715 return newTypedArrayWithSize<JSUint16Array>(exec, structure, length);
716 }
717
718 char* JIT_OPERATION operationNewUint16ArrayWithOneArgument(
719 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
720 {
721 return newTypedArrayWithOneArgument<JSUint16Array>(exec, structure, encodedValue);
722 }
723
724 char* JIT_OPERATION operationNewUint32ArrayWithSize(
725 ExecState* exec, Structure* structure, int32_t length)
726 {
727 return newTypedArrayWithSize<JSUint32Array>(exec, structure, length);
728 }
729
730 char* JIT_OPERATION operationNewUint32ArrayWithOneArgument(
731 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
732 {
733 return newTypedArrayWithOneArgument<JSUint32Array>(exec, structure, encodedValue);
734 }
735
736 char* JIT_OPERATION operationNewFloat32ArrayWithSize(
737 ExecState* exec, Structure* structure, int32_t length)
738 {
739 return newTypedArrayWithSize<JSFloat32Array>(exec, structure, length);
740 }
741
742 char* JIT_OPERATION operationNewFloat32ArrayWithOneArgument(
743 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
744 {
745 return newTypedArrayWithOneArgument<JSFloat32Array>(exec, structure, encodedValue);
746 }
747
748 char* JIT_OPERATION operationNewFloat64ArrayWithSize(
749 ExecState* exec, Structure* structure, int32_t length)
750 {
751 return newTypedArrayWithSize<JSFloat64Array>(exec, structure, length);
752 }
753
754 char* JIT_OPERATION operationNewFloat64ArrayWithOneArgument(
755 ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
756 {
757 return newTypedArrayWithOneArgument<JSFloat64Array>(exec, structure, encodedValue);
758 }
759
760 JSCell* JIT_OPERATION operationCreateInlinedArguments(
761 ExecState* exec, InlineCallFrame* inlineCallFrame)
762 {
763 VM& vm = exec->vm();
764 NativeCallFrameTracer tracer(&vm, exec);
765 // NB: This needs to be exceedingly careful with top call frame tracking, since it
766 // may be called from OSR exit, while the state of the call stack is bizarre.
767 Arguments* result = Arguments::create(vm, exec, inlineCallFrame);
768 ASSERT(!vm.exception());
769 return result;
770 }
771
772 JSCell* JIT_OPERATION operationCreateInlinedArgumentsDuringOSRExit(ExecState* exec, InlineCallFrame* inlineCallFrame)
773 {
774 DeferGCForAWhile(exec->vm().heap);
775 return operationCreateInlinedArguments(exec, inlineCallFrame);
776 }
777
778 void JIT_OPERATION operationTearOffInlinedArguments(
779 ExecState* exec, JSCell* argumentsCell, JSCell* activationCell, InlineCallFrame* inlineCallFrame)
780 {
781 ASSERT_UNUSED(activationCell, !activationCell); // Currently, we don't inline functions with activations.
782 jsCast<Arguments*>(argumentsCell)->tearOff(exec, inlineCallFrame);
783 }
784
785 EncodedJSValue JIT_OPERATION operationGetArgumentByVal(ExecState* exec, int32_t argumentsRegister, int32_t index)
786 {
787 VM& vm = exec->vm();
788 NativeCallFrameTracer tracer(&vm, exec);
789
790 JSValue argumentsValue = exec->uncheckedR(argumentsRegister).jsValue();
791
792 // If there are no arguments, and we're accessing out of bounds, then we have to create the
793 // arguments in case someone has installed a getter on a numeric property.
794 if (!argumentsValue)
795 exec->uncheckedR(argumentsRegister) = argumentsValue = Arguments::create(exec->vm(), exec);
796
797 return JSValue::encode(argumentsValue.get(exec, index));
798 }
799
800 EncodedJSValue JIT_OPERATION operationGetInlinedArgumentByVal(
801 ExecState* exec, int32_t argumentsRegister, InlineCallFrame* inlineCallFrame, int32_t index)
802 {
803 VM& vm = exec->vm();
804 NativeCallFrameTracer tracer(&vm, exec);
805
806 JSValue argumentsValue = exec->uncheckedR(argumentsRegister).jsValue();
807
808 // If there are no arguments, and we're accessing out of bounds, then we have to create the
809 // arguments in case someone has installed a getter on a numeric property.
810 if (!argumentsValue) {
811 exec->uncheckedR(argumentsRegister) = argumentsValue =
812 Arguments::create(exec->vm(), exec, inlineCallFrame);
813 }
814
815 return JSValue::encode(argumentsValue.get(exec, index));
816 }
817
818 JSCell* JIT_OPERATION operationNewFunctionNoCheck(ExecState* exec, JSCell* functionExecutable)
819 {
820 ASSERT(functionExecutable->inherits(FunctionExecutable::info()));
821 VM& vm = exec->vm();
822 NativeCallFrameTracer tracer(&vm, exec);
823 return JSFunction::create(vm, static_cast<FunctionExecutable*>(functionExecutable), exec->scope());
824 }
825
826 size_t JIT_OPERATION operationIsObject(ExecState* exec, EncodedJSValue value)
827 {
828 return jsIsObjectType(exec, JSValue::decode(value));
829 }
830
831 size_t JIT_OPERATION operationIsFunction(EncodedJSValue value)
832 {
833 return jsIsFunctionType(JSValue::decode(value));
834 }
835
836 JSCell* JIT_OPERATION operationTypeOf(ExecState* exec, JSCell* value)
837 {
838 VM& vm = exec->vm();
839 NativeCallFrameTracer tracer(&vm, exec);
840 return jsTypeStringForValue(exec, JSValue(value)).asCell();
841 }
842
843 char* JIT_OPERATION operationAllocatePropertyStorageWithInitialCapacity(ExecState* exec)
844 {
845 VM& vm = exec->vm();
846 NativeCallFrameTracer tracer(&vm, exec);
847
848 return reinterpret_cast<char*>(
849 Butterfly::createUninitialized(vm, 0, 0, initialOutOfLineCapacity, false, 0));
850 }
851
852 char* JIT_OPERATION operationAllocatePropertyStorage(ExecState* exec, size_t newSize)
853 {
854 VM& vm = exec->vm();
855 NativeCallFrameTracer tracer(&vm, exec);
856
857 return reinterpret_cast<char*>(
858 Butterfly::createUninitialized(vm, 0, 0, newSize, false, 0));
859 }
860
861 char* JIT_OPERATION operationReallocateButterflyToHavePropertyStorageWithInitialCapacity(ExecState* exec, JSObject* object)
862 {
863 VM& vm = exec->vm();
864 NativeCallFrameTracer tracer(&vm, exec);
865
866 ASSERT(!object->structure()->outOfLineCapacity());
867 DeferGC deferGC(vm.heap);
868 Butterfly* result = object->growOutOfLineStorage(vm, 0, initialOutOfLineCapacity);
869 object->setButterflyWithoutChangingStructure(vm, result);
870 return reinterpret_cast<char*>(result);
871 }
872
873 char* JIT_OPERATION operationReallocateButterflyToGrowPropertyStorage(ExecState* exec, JSObject* object, size_t newSize)
874 {
875 VM& vm = exec->vm();
876 NativeCallFrameTracer tracer(&vm, exec);
877
878 DeferGC deferGC(vm.heap);
879 Butterfly* result = object->growOutOfLineStorage(vm, object->structure()->outOfLineCapacity(), newSize);
880 object->setButterflyWithoutChangingStructure(vm, result);
881 return reinterpret_cast<char*>(result);
882 }
883
884 char* JIT_OPERATION operationEnsureInt32(ExecState* exec, JSCell* cell)
885 {
886 VM& vm = exec->vm();
887 NativeCallFrameTracer tracer(&vm, exec);
888
889 if (!cell->isObject())
890 return 0;
891
892 return reinterpret_cast<char*>(asObject(cell)->ensureInt32(vm).data());
893 }
894
895 char* JIT_OPERATION operationEnsureDouble(ExecState* exec, JSCell* cell)
896 {
897 VM& vm = exec->vm();
898 NativeCallFrameTracer tracer(&vm, exec);
899
900 if (!cell->isObject())
901 return 0;
902
903 return reinterpret_cast<char*>(asObject(cell)->ensureDouble(vm).data());
904 }
905
906 char* JIT_OPERATION operationEnsureContiguous(ExecState* exec, JSCell* cell)
907 {
908 VM& vm = exec->vm();
909 NativeCallFrameTracer tracer(&vm, exec);
910
911 if (!cell->isObject())
912 return 0;
913
914 return reinterpret_cast<char*>(asObject(cell)->ensureContiguous(vm).data());
915 }
916
917 char* JIT_OPERATION operationRageEnsureContiguous(ExecState* exec, JSCell* cell)
918 {
919 VM& vm = exec->vm();
920 NativeCallFrameTracer tracer(&vm, exec);
921
922 if (!cell->isObject())
923 return 0;
924
925 return reinterpret_cast<char*>(asObject(cell)->rageEnsureContiguous(vm).data());
926 }
927
928 char* JIT_OPERATION operationEnsureArrayStorage(ExecState* exec, JSCell* cell)
929 {
930 VM& vm = exec->vm();
931 NativeCallFrameTracer tracer(&vm, exec);
932
933 if (!cell->isObject())
934 return 0;
935
936 return reinterpret_cast<char*>(asObject(cell)->ensureArrayStorage(vm));
937 }
938
939 StringImpl* JIT_OPERATION operationResolveRope(ExecState* exec, JSString* string)
940 {
941 VM& vm = exec->vm();
942 NativeCallFrameTracer tracer(&vm, exec);
943
944 return string->value(exec).impl();
945 }
946
947 JSString* JIT_OPERATION operationSingleCharacterString(ExecState* exec, int32_t character)
948 {
949 VM& vm = exec->vm();
950 NativeCallFrameTracer tracer(&vm, exec);
951
952 return jsSingleCharacterString(exec, static_cast<UChar>(character));
953 }
954
955 JSCell* JIT_OPERATION operationNewStringObject(ExecState* exec, JSString* string, Structure* structure)
956 {
957 VM& vm = exec->vm();
958 NativeCallFrameTracer tracer(&vm, exec);
959
960 return StringObject::create(vm, structure, string);
961 }
962
963 JSCell* JIT_OPERATION operationToStringOnCell(ExecState* exec, JSCell* cell)
964 {
965 VM& vm = exec->vm();
966 NativeCallFrameTracer tracer(&vm, exec);
967
968 return JSValue(cell).toString(exec);
969 }
970
971 JSCell* JIT_OPERATION operationToString(ExecState* exec, EncodedJSValue value)
972 {
973 VM& vm = exec->vm();
974 NativeCallFrameTracer tracer(&vm, exec);
975
976 return JSValue::decode(value).toString(exec);
977 }
978
979 JSCell* JIT_OPERATION operationMakeRope2(ExecState* exec, JSString* left, JSString* right)
980 {
981 VM& vm = exec->vm();
982 NativeCallFrameTracer tracer(&vm, exec);
983
984 if (sumOverflows<int32_t>(left->length(), right->length())) {
985 throwOutOfMemoryError(exec);
986 return nullptr;
987 }
988
989 return JSRopeString::create(vm, left, right);
990 }
991
992 JSCell* JIT_OPERATION operationMakeRope3(ExecState* exec, JSString* a, JSString* b, JSString* c)
993 {
994 VM& vm = exec->vm();
995 NativeCallFrameTracer tracer(&vm, exec);
996
997 if (sumOverflows<int32_t>(a->length(), b->length(), c->length())) {
998 throwOutOfMemoryError(exec);
999 return nullptr;
1000 }
1001
1002 return JSRopeString::create(vm, a, b, c);
1003 }
1004
1005 char* JIT_OPERATION operationFindSwitchImmTargetForDouble(
1006 ExecState* exec, EncodedJSValue encodedValue, size_t tableIndex)
1007 {
1008 CodeBlock* codeBlock = exec->codeBlock();
1009 SimpleJumpTable& table = codeBlock->switchJumpTable(tableIndex);
1010 JSValue value = JSValue::decode(encodedValue);
1011 ASSERT(value.isDouble());
1012 double asDouble = value.asDouble();
1013 int32_t asInt32 = static_cast<int32_t>(asDouble);
1014 if (asDouble == asInt32)
1015 return static_cast<char*>(table.ctiForValue(asInt32).executableAddress());
1016 return static_cast<char*>(table.ctiDefault.executableAddress());
1017 }
1018
1019 char* JIT_OPERATION operationSwitchString(ExecState* exec, size_t tableIndex, JSString* string)
1020 {
1021 VM& vm = exec->vm();
1022 NativeCallFrameTracer tracer(&vm, exec);
1023
1024 return static_cast<char*>(exec->codeBlock()->stringSwitchJumpTable(tableIndex).ctiForValue(string->value(exec).impl()).executableAddress());
1025 }
1026
1027 void JIT_OPERATION operationNotifyWrite(ExecState* exec, VariableWatchpointSet* set, EncodedJSValue encodedValue)
1028 {
1029 VM& vm = exec->vm();
1030 NativeCallFrameTracer tracer(&vm, exec);
1031 JSValue value = JSValue::decode(encodedValue);
1032
1033 set->notifyWrite(vm, value);
1034 }
1035
1036 double JIT_OPERATION operationFModOnInts(int32_t a, int32_t b)
1037 {
1038 return fmod(a, b);
1039 }
1040
1041 JSCell* JIT_OPERATION operationStringFromCharCode(ExecState* exec, int32_t op1)
1042 {
1043 VM* vm = &exec->vm();
1044 NativeCallFrameTracer tracer(vm, exec);
1045 return JSC::stringFromCharCode(exec, op1);
1046 }
1047
1048 int64_t JIT_OPERATION operationConvertBoxedDoubleToInt52(EncodedJSValue encodedValue)
1049 {
1050 JSValue value = JSValue::decode(encodedValue);
1051 if (!value.isDouble())
1052 return JSValue::notInt52;
1053 return tryConvertToInt52(value.asDouble());
1054 }
1055
1056 int64_t JIT_OPERATION operationConvertDoubleToInt52(double value)
1057 {
1058 return tryConvertToInt52(value);
1059 }
1060
1061 size_t JIT_OPERATION dfgConvertJSValueToInt32(ExecState* exec, EncodedJSValue value)
1062 {
1063 VM* vm = &exec->vm();
1064 NativeCallFrameTracer tracer(vm, exec);
1065
1066 // toInt32/toUInt32 return the same value; we want the value zero extended to fill the register.
1067 return JSValue::decode(value).toUInt32(exec);
1068 }
1069
1070 void JIT_OPERATION debugOperationPrintSpeculationFailure(ExecState* exec, void* debugInfoRaw, void* scratch)
1071 {
1072 VM* vm = &exec->vm();
1073 NativeCallFrameTracer tracer(vm, exec);
1074
1075 SpeculationFailureDebugInfo* debugInfo = static_cast<SpeculationFailureDebugInfo*>(debugInfoRaw);
1076 CodeBlock* codeBlock = debugInfo->codeBlock;
1077 CodeBlock* alternative = codeBlock->alternative();
1078 dataLog("Speculation failure in ", *codeBlock);
1079 dataLog(" @ exit #", vm->osrExitIndex, " (bc#", debugInfo->bytecodeOffset, ", ", exitKindToString(debugInfo->kind), ") with ");
1080 if (alternative) {
1081 dataLog(
1082 "executeCounter = ", alternative->jitExecuteCounter(),
1083 ", reoptimizationRetryCounter = ", alternative->reoptimizationRetryCounter(),
1084 ", optimizationDelayCounter = ", alternative->optimizationDelayCounter());
1085 } else
1086 dataLog("no alternative code block (i.e. we've been jettisoned)");
1087 dataLog(", osrExitCounter = ", codeBlock->osrExitCounter(), "\n");
1088 dataLog(" GPRs at time of exit:");
1089 char* scratchPointer = static_cast<char*>(scratch);
1090 for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) {
1091 GPRReg gpr = GPRInfo::toRegister(i);
1092 dataLog(" ", GPRInfo::debugName(gpr), ":", RawPointer(*reinterpret_cast_ptr<void**>(scratchPointer)));
1093 scratchPointer += sizeof(EncodedJSValue);
1094 }
1095 dataLog("\n");
1096 dataLog(" FPRs at time of exit:");
1097 for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) {
1098 FPRReg fpr = FPRInfo::toRegister(i);
1099 dataLog(" ", FPRInfo::debugName(fpr), ":");
1100 uint64_t bits = *reinterpret_cast_ptr<uint64_t*>(scratchPointer);
1101 double value = *reinterpret_cast_ptr<double*>(scratchPointer);
1102 dataLogF("%llx:%lf", static_cast<long long>(bits), value);
1103 scratchPointer += sizeof(EncodedJSValue);
1104 }
1105 dataLog("\n");
1106 }
1107
1108 extern "C" void JIT_OPERATION triggerReoptimizationNow(CodeBlock* codeBlock)
1109 {
1110 // It's sort of preferable that we don't GC while in here. Anyways, doing so wouldn't
1111 // really be profitable.
1112 DeferGCForAWhile deferGC(codeBlock->vm()->heap);
1113
1114 if (Options::verboseOSR())
1115 dataLog(*codeBlock, ": Entered reoptimize\n");
1116 // We must be called with the baseline code block.
1117 ASSERT(JITCode::isBaselineCode(codeBlock->jitType()));
1118
1119 // If I am my own replacement, then reoptimization has already been triggered.
1120 // This can happen in recursive functions.
1121 if (codeBlock->replacement() == codeBlock) {
1122 if (Options::verboseOSR())
1123 dataLog(*codeBlock, ": Not reoptimizing because we've already been jettisoned.\n");
1124 return;
1125 }
1126
1127 // Otherwise, the replacement must be optimized code. Use this as an opportunity
1128 // to check our logic.
1129 ASSERT(codeBlock->hasOptimizedReplacement());
1130 CodeBlock* optimizedCodeBlock = codeBlock->replacement();
1131 ASSERT(JITCode::isOptimizingJIT(optimizedCodeBlock->jitType()));
1132
1133 // In order to trigger reoptimization, one of two things must have happened:
1134 // 1) We exited more than some number of times.
1135 // 2) We exited and got stuck in a loop, and now we're exiting again.
1136 bool didExitABunch = optimizedCodeBlock->shouldReoptimizeNow();
1137 bool didGetStuckInLoop =
1138 codeBlock->checkIfOptimizationThresholdReached()
1139 && optimizedCodeBlock->shouldReoptimizeFromLoopNow();
1140
1141 if (!didExitABunch && !didGetStuckInLoop) {
1142 if (Options::verboseOSR())
1143 dataLog(*codeBlock, ": Not reoptimizing ", *optimizedCodeBlock, " because it either didn't exit enough or didn't loop enough after exit.\n");
1144 codeBlock->optimizeAfterLongWarmUp();
1145 return;
1146 }
1147
1148 optimizedCodeBlock->jettison(Profiler::JettisonDueToOSRExit, CountReoptimization);
1149 }
1150
1151 #if ENABLE(FTL_JIT)
1152 static void triggerFTLReplacementCompile(VM* vm, CodeBlock* codeBlock, JITCode* jitCode)
1153 {
1154 if (codeBlock->baselineVersion()->m_didFailFTLCompilation) {
1155 if (Options::verboseOSR())
1156 dataLog("Deferring FTL-optimization of ", *codeBlock, " indefinitely because there was an FTL failure.\n");
1157 jitCode->dontOptimizeAnytimeSoon(codeBlock);
1158 return;
1159 }
1160
1161 if (!jitCode->checkIfOptimizationThresholdReached(codeBlock)) {
1162 if (Options::verboseOSR())
1163 dataLog("Choosing not to FTL-optimize ", *codeBlock, " yet.\n");
1164 return;
1165 }
1166
1167 Worklist::State worklistState;
1168 if (Worklist* worklist = existingGlobalFTLWorklistOrNull()) {
1169 worklistState = worklist->completeAllReadyPlansForVM(
1170 *vm, CompilationKey(codeBlock->baselineVersion(), FTLMode));
1171 } else
1172 worklistState = Worklist::NotKnown;
1173
1174 if (worklistState == Worklist::Compiling) {
1175 jitCode->setOptimizationThresholdBasedOnCompilationResult(
1176 codeBlock, CompilationDeferred);
1177 return;
1178 }
1179
1180 if (codeBlock->hasOptimizedReplacement()) {
1181 // That's great, we've compiled the code - next time we call this function,
1182 // we'll enter that replacement.
1183 jitCode->optimizeSoon(codeBlock);
1184 return;
1185 }
1186
1187 if (worklistState == Worklist::Compiled) {
1188 // This means that we finished compiling, but failed somehow; in that case the
1189 // thresholds will be set appropriately.
1190 if (Options::verboseOSR())
1191 dataLog("Code block ", *codeBlock, " was compiled but it doesn't have an optimized replacement.\n");
1192 return;
1193 }
1194
1195 // We need to compile the code.
1196 compile(
1197 *vm, codeBlock->newReplacement().get(), codeBlock, FTLMode, UINT_MAX,
1198 Operands<JSValue>(), ToFTLDeferredCompilationCallback::create(codeBlock));
1199 }
1200
1201 void JIT_OPERATION triggerTierUpNow(ExecState* exec)
1202 {
1203 VM* vm = &exec->vm();
1204 NativeCallFrameTracer tracer(vm, exec);
1205 DeferGC deferGC(vm->heap);
1206 CodeBlock* codeBlock = exec->codeBlock();
1207
1208 JITCode* jitCode = codeBlock->jitCode()->dfg();
1209
1210 if (Options::verboseOSR()) {
1211 dataLog(
1212 *codeBlock, ": Entered triggerTierUpNow with executeCounter = ",
1213 jitCode->tierUpCounter, "\n");
1214 }
1215
1216 triggerFTLReplacementCompile(vm, codeBlock, jitCode);
1217 }
1218
1219 char* JIT_OPERATION triggerOSREntryNow(
1220 ExecState* exec, int32_t bytecodeIndex, int32_t streamIndex)
1221 {
1222 VM* vm = &exec->vm();
1223 NativeCallFrameTracer tracer(vm, exec);
1224 DeferGC deferGC(vm->heap);
1225 CodeBlock* codeBlock = exec->codeBlock();
1226
1227 JITCode* jitCode = codeBlock->jitCode()->dfg();
1228
1229 if (Options::verboseOSR()) {
1230 dataLog(
1231 *codeBlock, ": Entered triggerTierUpNow with executeCounter = ",
1232 jitCode->tierUpCounter, "\n");
1233 }
1234
1235 // - If we don't have an FTL code block, then try to compile one.
1236 // - If we do have an FTL code block, then try to enter for a while.
1237 // - If we couldn't enter for a while, then trigger OSR entry.
1238
1239 triggerFTLReplacementCompile(vm, codeBlock, jitCode);
1240
1241 if (!codeBlock->hasOptimizedReplacement())
1242 return 0;
1243
1244 if (jitCode->osrEntryRetry < Options::ftlOSREntryRetryThreshold()) {
1245 jitCode->osrEntryRetry++;
1246 return 0;
1247 }
1248
1249 // It's time to try to compile code for OSR entry.
1250 Worklist::State worklistState;
1251 if (Worklist* worklist = existingGlobalFTLWorklistOrNull()) {
1252 worklistState = worklist->completeAllReadyPlansForVM(
1253 *vm, CompilationKey(codeBlock->baselineVersion(), FTLForOSREntryMode));
1254 } else
1255 worklistState = Worklist::NotKnown;
1256
1257 if (worklistState == Worklist::Compiling)
1258 return 0;
1259
1260 if (CodeBlock* entryBlock = jitCode->osrEntryBlock.get()) {
1261 void* address = FTL::prepareOSREntry(
1262 exec, codeBlock, entryBlock, bytecodeIndex, streamIndex);
1263 if (address)
1264 return static_cast<char*>(address);
1265
1266 FTL::ForOSREntryJITCode* entryCode = entryBlock->jitCode()->ftlForOSREntry();
1267 entryCode->countEntryFailure();
1268 if (entryCode->entryFailureCount() <
1269 Options::ftlOSREntryFailureCountForReoptimization())
1270 return 0;
1271
1272 // OSR entry failed. Oh no! This implies that we need to retry. We retry
1273 // without exponential backoff and we only do this for the entry code block.
1274 jitCode->osrEntryBlock.clear();
1275 jitCode->osrEntryRetry = 0;
1276 return 0;
1277 }
1278
1279 if (worklistState == Worklist::Compiled) {
1280 // This means that compilation failed and we already set the thresholds.
1281 if (Options::verboseOSR())
1282 dataLog("Code block ", *codeBlock, " was compiled but it doesn't have an optimized replacement.\n");
1283 return 0;
1284 }
1285
1286 // We aren't compiling and haven't compiled anything for OSR entry. So, try to compile
1287 // something.
1288 Operands<JSValue> mustHandleValues;
1289 jitCode->reconstruct(
1290 exec, codeBlock, CodeOrigin(bytecodeIndex), streamIndex, mustHandleValues);
1291 RefPtr<CodeBlock> replacementCodeBlock = codeBlock->newReplacement();
1292 CompilationResult forEntryResult = compile(
1293 *vm, replacementCodeBlock.get(), codeBlock, FTLForOSREntryMode, bytecodeIndex,
1294 mustHandleValues, ToFTLForOSREntryDeferredCompilationCallback::create(codeBlock));
1295
1296 if (forEntryResult != CompilationSuccessful) {
1297 ASSERT(forEntryResult == CompilationDeferred || replacementCodeBlock->hasOneRef());
1298 return 0;
1299 }
1300
1301 // It's possible that the for-entry compile already succeeded. In that case OSR
1302 // entry will succeed unless we ran out of stack. It's not clear what we should do.
1303 // We signal to try again after a while if that happens.
1304 void* address = FTL::prepareOSREntry(
1305 exec, codeBlock, jitCode->osrEntryBlock.get(), bytecodeIndex, streamIndex);
1306 return static_cast<char*>(address);
1307 }
1308 #endif // ENABLE(FTL_JIT)
1309
1310 } // extern "C"
1311 } } // namespace JSC::DFG
1312
1313 #endif // ENABLE(DFG_JIT)
1314
1315 #endif // ENABLE(JIT)