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 62namespace JSC { namespace DFG { 63 64template<bool strict, bool direct> 65static 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 88template<bool strict, bool direct> 89ALWAYS_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 134template<typename ViewClass> 135char* 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 146template<typename ViewClass> 147char* 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 204extern "C" { 205 206EncodedJSValue 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 214EncodedJSValue 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 222JSCell* 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 235EncodedJSValue 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 246EncodedJSValue 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 262static 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 279EncodedJSValue 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 313EncodedJSValue 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 342ALWAYS_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 356EncodedJSValue JIT_OPERATION operationGetByValArrayInt(ExecState* exec, JSArray* base, int32_t index) 357{ 358 return getByValCellInt(exec, base, index); 359} 360 361EncodedJSValue JIT_OPERATION operationGetByValStringInt(ExecState* exec, JSString* base, int32_t index) 362{ 363 return getByValCellInt(exec, base, index); 364} 365 366void 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 374void 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 382void 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 390void 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 398void 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 413void 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 428void 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 445void 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 462void 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 470void 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 478void 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 486void 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 494void 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 507void 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 521EncodedJSValue 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 530EncodedJSValue 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 539EncodedJSValue 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 547EncodedJSValue 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 557EncodedJSValue 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 570size_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 585size_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 599size_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 610EncodedJSValue 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 618char* 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 626char* 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 634char* 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 645char* 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 652char* JIT_OPERATION operationNewInt8ArrayWithSize( 653 ExecState* exec, Structure* structure, int32_t length) 654{ 655 return newTypedArrayWithSize<JSInt8Array>(exec, structure, length); 656} 657 658char* JIT_OPERATION operationNewInt8ArrayWithOneArgument( 659 ExecState* exec, Structure* structure, EncodedJSValue encodedValue) 660{ 661 return newTypedArrayWithOneArgument<JSInt8Array>(exec, structure, encodedValue); 662} 663 664char* JIT_OPERATION operationNewInt16ArrayWithSize( 665 ExecState* exec, Structure* structure, int32_t length) 666{ 667 return newTypedArrayWithSize<JSInt16Array>(exec, structure, length); 668} 669 670char* JIT_OPERATION operationNewInt16ArrayWithOneArgument( 671 ExecState* exec, Structure* structure, EncodedJSValue encodedValue) 672{ 673 return newTypedArrayWithOneArgument<JSInt16Array>(exec, structure, encodedValue); 674} 675 676char* JIT_OPERATION operationNewInt32ArrayWithSize( 677 ExecState* exec, Structure* structure, int32_t length) 678{ 679 return newTypedArrayWithSize<JSInt32Array>(exec, structure, length); 680} 681 682char* JIT_OPERATION operationNewInt32ArrayWithOneArgument( 683 ExecState* exec, Structure* structure, EncodedJSValue encodedValue) 684{ 685 return newTypedArrayWithOneArgument<JSInt32Array>(exec, structure, encodedValue); 686} 687 688char* JIT_OPERATION operationNewUint8ArrayWithSize( 689 ExecState* exec, Structure* structure, int32_t length) 690{ 691 return newTypedArrayWithSize<JSUint8Array>(exec, structure, length); 692} 693 694char* JIT_OPERATION operationNewUint8ArrayWithOneArgument( 695 ExecState* exec, Structure* structure, EncodedJSValue encodedValue) 696{ 697 return newTypedArrayWithOneArgument<JSUint8Array>(exec, structure, encodedValue); 698} 699 700char* JIT_OPERATION operationNewUint8ClampedArrayWithSize( 701 ExecState* exec, Structure* structure, int32_t length) 702{ 703 return newTypedArrayWithSize<JSUint8ClampedArray>(exec, structure, length); 704} 705 706char* JIT_OPERATION operationNewUint8ClampedArrayWithOneArgument( 707 ExecState* exec, Structure* structure, EncodedJSValue encodedValue) 708{ 709 return newTypedArrayWithOneArgument<JSUint8ClampedArray>(exec, structure, encodedValue); 710} 711 712char* JIT_OPERATION operationNewUint16ArrayWithSize( 713 ExecState* exec, Structure* structure, int32_t length) 714{ 715 return newTypedArrayWithSize<JSUint16Array>(exec, structure, length); 716} 717 718char* JIT_OPERATION operationNewUint16ArrayWithOneArgument( 719 ExecState* exec, Structure* structure, EncodedJSValue encodedValue) 720{ 721 return newTypedArrayWithOneArgument<JSUint16Array>(exec, structure, encodedValue); 722} 723 724char* JIT_OPERATION operationNewUint32ArrayWithSize( 725 ExecState* exec, Structure* structure, int32_t length) 726{ 727 return newTypedArrayWithSize<JSUint32Array>(exec, structure, length); 728} 729 730char* JIT_OPERATION operationNewUint32ArrayWithOneArgument( 731 ExecState* exec, Structure* structure, EncodedJSValue encodedValue) 732{ 733 return newTypedArrayWithOneArgument<JSUint32Array>(exec, structure, encodedValue); 734} 735 736char* JIT_OPERATION operationNewFloat32ArrayWithSize( 737 ExecState* exec, Structure* structure, int32_t length) 738{ 739 return newTypedArrayWithSize<JSFloat32Array>(exec, structure, length); 740} 741 742char* JIT_OPERATION operationNewFloat32ArrayWithOneArgument( 743 ExecState* exec, Structure* structure, EncodedJSValue encodedValue) 744{ 745 return newTypedArrayWithOneArgument<JSFloat32Array>(exec, structure, encodedValue); 746} 747 748char* JIT_OPERATION operationNewFloat64ArrayWithSize( 749 ExecState* exec, Structure* structure, int32_t length) 750{ 751 return newTypedArrayWithSize<JSFloat64Array>(exec, structure, length); 752} 753 754char* JIT_OPERATION operationNewFloat64ArrayWithOneArgument( 755 ExecState* exec, Structure* structure, EncodedJSValue encodedValue) 756{ 757 return newTypedArrayWithOneArgument<JSFloat64Array>(exec, structure, encodedValue); 758} 759 760JSCell* 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 772JSCell* JIT_OPERATION operationCreateInlinedArgumentsDuringOSRExit(ExecState* exec, InlineCallFrame* inlineCallFrame) 773{ 774 DeferGCForAWhile(exec->vm().heap); 775 return operationCreateInlinedArguments(exec, inlineCallFrame); 776} 777 778void 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 785EncodedJSValue 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 800EncodedJSValue 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 818JSCell* 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 826size_t JIT_OPERATION operationIsObject(ExecState* exec, EncodedJSValue value) 827{ 828 return jsIsObjectType(exec, JSValue::decode(value)); 829} 830 831size_t JIT_OPERATION operationIsFunction(EncodedJSValue value) 832{ 833 return jsIsFunctionType(JSValue::decode(value)); 834} 835 836JSCell* 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 843char* 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 852char* 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 861char* 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 873char* 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 884char* 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 895char* 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 906char* 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 917char* 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 928char* 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 939StringImpl* 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 947JSString* 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 955JSCell* 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 963JSCell* 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 971JSCell* 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 979JSCell* 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 992JSCell* 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 1005char* 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 1019char* 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 1027void 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 1036double JIT_OPERATION operationFModOnInts(int32_t a, int32_t b) 1037{ 1038 return fmod(a, b); 1039} 1040 1041JSCell* 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 1048int64_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 1056int64_t JIT_OPERATION operationConvertDoubleToInt52(double value) 1057{ 1058 return tryConvertToInt52(value); 1059} 1060 1061size_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 1070void 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 1108extern "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) 1152static 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 1201void 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 1219char* 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) 1316