1/* 2 * Copyright (C) 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 "JITOperations.h" 28 29#if ENABLE(JIT) 30 31#include "Arguments.h" 32#include "ArrayConstructor.h" 33#include "DFGCompilationMode.h" 34#include "DFGDriver.h" 35#include "DFGOSREntry.h" 36#include "DFGThunks.h" 37#include "DFGWorklist.h" 38#include "Debugger.h" 39#include "Error.h" 40#include "ErrorHandlingScope.h" 41#include "GetterSetter.h" 42#include "HostCallReturnValue.h" 43#include "JIT.h" 44#include "JITToDFGDeferredCompilationCallback.h" 45#include "JSGlobalObjectFunctions.h" 46#include "JSNameScope.h" 47#include "JSPropertyNameIterator.h" 48#include "JSStackInlines.h" 49#include "JSWithScope.h" 50#include "ObjectConstructor.h" 51#include "JSCInlines.h" 52#include "Repatch.h" 53#include "RepatchBuffer.h" 54#include "TestRunnerUtils.h" 55#include <wtf/InlineASM.h> 56 57namespace JSC { 58 59static unsigned s_numberOfExceptionFuzzChecks; 60unsigned numberOfExceptionFuzzChecks() { return s_numberOfExceptionFuzzChecks; } 61 62extern "C" { 63 64#if COMPILER(MSVC) 65void * _ReturnAddress(void); 66#pragma intrinsic(_ReturnAddress) 67 68#define OUR_RETURN_ADDRESS _ReturnAddress() 69#else 70#define OUR_RETURN_ADDRESS __builtin_return_address(0) 71#endif 72 73#if ENABLE(OPCODE_SAMPLING) 74#define CTI_SAMPLER vm->interpreter->sampler() 75#else 76#define CTI_SAMPLER 0 77#endif 78 79 80void JIT_OPERATION operationThrowStackOverflowError(ExecState* exec, CodeBlock* codeBlock) 81{ 82 // We pass in our own code block, because the callframe hasn't been populated. 83 VM* vm = codeBlock->vm(); 84 CallFrame* callerFrame = exec->callerFrameSkippingVMEntrySentinel(); 85 if (!callerFrame) 86 callerFrame = exec; 87 88 NativeCallFrameTracer tracer(vm, callerFrame); 89 ErrorHandlingScope errorScope(*vm); 90 vm->throwException(callerFrame, createStackOverflowError(callerFrame)); 91} 92 93int32_t JIT_OPERATION operationCallArityCheck(ExecState* exec) 94{ 95 VM* vm = &exec->vm(); 96 CallFrame* callerFrame = exec->callerFrameSkippingVMEntrySentinel(); 97 NativeCallFrameTracer tracer(vm, callerFrame); 98 99 JSStack& stack = vm->interpreter->stack(); 100 101 int32_t missingArgCount = CommonSlowPaths::arityCheckFor(exec, &stack, CodeForCall); 102 if (missingArgCount < 0) 103 throwStackOverflowError(callerFrame); 104 105 return missingArgCount; 106} 107 108int32_t JIT_OPERATION operationConstructArityCheck(ExecState* exec) 109{ 110 VM* vm = &exec->vm(); 111 CallFrame* callerFrame = exec->callerFrameSkippingVMEntrySentinel(); 112 NativeCallFrameTracer tracer(vm, callerFrame); 113 114 JSStack& stack = vm->interpreter->stack(); 115 116 int32_t missingArgCount = CommonSlowPaths::arityCheckFor(exec, &stack, CodeForConstruct); 117 if (missingArgCount < 0) 118 throwStackOverflowError(callerFrame); 119 120 return missingArgCount; 121} 122 123EncodedJSValue JIT_OPERATION operationGetById(ExecState* exec, StructureStubInfo*, EncodedJSValue base, StringImpl* uid) 124{ 125 VM* vm = &exec->vm(); 126 NativeCallFrameTracer tracer(vm, exec); 127 128 JSValue baseValue = JSValue::decode(base); 129 PropertySlot slot(baseValue); 130 Identifier ident(vm, uid); 131 return JSValue::encode(baseValue.get(exec, ident, slot)); 132} 133 134EncodedJSValue JIT_OPERATION operationGetByIdBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, StringImpl* uid) 135{ 136 VM* vm = &exec->vm(); 137 NativeCallFrameTracer tracer(vm, exec); 138 139 Identifier ident(vm, uid); 140 AccessType accessType = static_cast<AccessType>(stubInfo->accessType); 141 142 JSValue baseValue = JSValue::decode(base); 143 PropertySlot slot(baseValue); 144 JSValue result = baseValue.get(exec, ident, slot); 145 146 if (accessType == static_cast<AccessType>(stubInfo->accessType)) 147 buildGetByIDList(exec, baseValue, ident, slot, *stubInfo); 148 149 return JSValue::encode(result); 150} 151 152EncodedJSValue JIT_OPERATION operationGetByIdOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, StringImpl* uid) 153{ 154 VM* vm = &exec->vm(); 155 NativeCallFrameTracer tracer(vm, exec); 156 Identifier ident = uid->isEmptyUnique() ? Identifier::from(PrivateName(uid)) : Identifier(vm, uid); 157 AccessType accessType = static_cast<AccessType>(stubInfo->accessType); 158 159 JSValue baseValue = JSValue::decode(base); 160 PropertySlot slot(baseValue); 161 JSValue result = baseValue.get(exec, ident, slot); 162 163 if (accessType == static_cast<AccessType>(stubInfo->accessType)) { 164 if (stubInfo->seen) 165 repatchGetByID(exec, baseValue, ident, slot, *stubInfo); 166 else 167 stubInfo->seen = true; 168 } 169 170 return JSValue::encode(result); 171} 172 173EncodedJSValue JIT_OPERATION operationInOptimize(ExecState* exec, StructureStubInfo* stubInfo, JSCell* base, StringImpl* key) 174{ 175 VM* vm = &exec->vm(); 176 NativeCallFrameTracer tracer(vm, exec); 177 178 if (!base->isObject()) { 179 vm->throwException(exec, createInvalidParameterError(exec, "in", base)); 180 return JSValue::encode(jsUndefined()); 181 } 182 183 AccessType accessType = static_cast<AccessType>(stubInfo->accessType); 184 185 Identifier ident(vm, key); 186 PropertySlot slot(base); 187 bool result = asObject(base)->getPropertySlot(exec, ident, slot); 188 189 RELEASE_ASSERT(accessType == stubInfo->accessType); 190 191 if (stubInfo->seen) 192 repatchIn(exec, base, ident, result, slot, *stubInfo); 193 else 194 stubInfo->seen = true; 195 196 return JSValue::encode(jsBoolean(result)); 197} 198 199EncodedJSValue JIT_OPERATION operationIn(ExecState* exec, StructureStubInfo*, JSCell* base, StringImpl* key) 200{ 201 VM* vm = &exec->vm(); 202 NativeCallFrameTracer tracer(vm, exec); 203 204 if (!base->isObject()) { 205 vm->throwException(exec, createInvalidParameterError(exec, "in", base)); 206 return JSValue::encode(jsUndefined()); 207 } 208 209 Identifier ident(vm, key); 210 return JSValue::encode(jsBoolean(asObject(base)->hasProperty(exec, ident))); 211} 212 213EncodedJSValue JIT_OPERATION operationGenericIn(ExecState* exec, JSCell* base, EncodedJSValue key) 214{ 215 VM* vm = &exec->vm(); 216 NativeCallFrameTracer tracer(vm, exec); 217 218 return JSValue::encode(jsBoolean(CommonSlowPaths::opIn(exec, JSValue::decode(key), base))); 219} 220 221void JIT_OPERATION operationPutByIdStrict(ExecState* exec, StructureStubInfo*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) 222{ 223 VM* vm = &exec->vm(); 224 NativeCallFrameTracer tracer(vm, exec); 225 226 Identifier ident(vm, uid); 227 PutPropertySlot slot(JSValue::decode(encodedBase), true, exec->codeBlock()->putByIdContext()); 228 JSValue::decode(encodedBase).put(exec, ident, JSValue::decode(encodedValue), slot); 229} 230 231void JIT_OPERATION operationPutByIdNonStrict(ExecState* exec, StructureStubInfo*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) 232{ 233 VM* vm = &exec->vm(); 234 NativeCallFrameTracer tracer(vm, exec); 235 236 Identifier ident(vm, uid); 237 PutPropertySlot slot(JSValue::decode(encodedBase), false, exec->codeBlock()->putByIdContext()); 238 JSValue::decode(encodedBase).put(exec, ident, JSValue::decode(encodedValue), slot); 239} 240 241void JIT_OPERATION operationPutByIdDirectStrict(ExecState* exec, StructureStubInfo*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) 242{ 243 VM* vm = &exec->vm(); 244 NativeCallFrameTracer tracer(vm, exec); 245 246 Identifier ident(vm, uid); 247 PutPropertySlot slot(JSValue::decode(encodedBase), true, exec->codeBlock()->putByIdContext()); 248 asObject(JSValue::decode(encodedBase))->putDirect(exec->vm(), ident, JSValue::decode(encodedValue), slot); 249} 250 251void JIT_OPERATION operationPutByIdDirectNonStrict(ExecState* exec, StructureStubInfo*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) 252{ 253 VM* vm = &exec->vm(); 254 NativeCallFrameTracer tracer(vm, exec); 255 256 Identifier ident(vm, uid); 257 PutPropertySlot slot(JSValue::decode(encodedBase), false, exec->codeBlock()->putByIdContext()); 258 asObject(JSValue::decode(encodedBase))->putDirect(exec->vm(), ident, JSValue::decode(encodedValue), slot); 259} 260 261void JIT_OPERATION operationPutByIdStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) 262{ 263 VM* vm = &exec->vm(); 264 NativeCallFrameTracer tracer(vm, exec); 265 266 Identifier ident(vm, uid); 267 AccessType accessType = static_cast<AccessType>(stubInfo->accessType); 268 269 JSValue value = JSValue::decode(encodedValue); 270 JSValue baseValue = JSValue::decode(encodedBase); 271 PutPropertySlot slot(baseValue, true, exec->codeBlock()->putByIdContext()); 272 273 baseValue.put(exec, ident, value, slot); 274 275 if (accessType != static_cast<AccessType>(stubInfo->accessType)) 276 return; 277 278 if (stubInfo->seen) 279 repatchPutByID(exec, baseValue, ident, slot, *stubInfo, NotDirect); 280 else 281 stubInfo->seen = true; 282} 283 284void JIT_OPERATION operationPutByIdNonStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) 285{ 286 VM* vm = &exec->vm(); 287 NativeCallFrameTracer tracer(vm, exec); 288 289 Identifier ident(vm, uid); 290 AccessType accessType = static_cast<AccessType>(stubInfo->accessType); 291 292 JSValue value = JSValue::decode(encodedValue); 293 JSValue baseValue = JSValue::decode(encodedBase); 294 PutPropertySlot slot(baseValue, false, exec->codeBlock()->putByIdContext()); 295 296 baseValue.put(exec, ident, value, slot); 297 298 if (accessType != static_cast<AccessType>(stubInfo->accessType)) 299 return; 300 301 if (stubInfo->seen) 302 repatchPutByID(exec, baseValue, ident, slot, *stubInfo, NotDirect); 303 else 304 stubInfo->seen = true; 305} 306 307void JIT_OPERATION operationPutByIdDirectStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) 308{ 309 VM* vm = &exec->vm(); 310 NativeCallFrameTracer tracer(vm, exec); 311 312 Identifier ident(vm, uid); 313 AccessType accessType = static_cast<AccessType>(stubInfo->accessType); 314 315 JSValue value = JSValue::decode(encodedValue); 316 JSObject* baseObject = asObject(JSValue::decode(encodedBase)); 317 PutPropertySlot slot(baseObject, true, exec->codeBlock()->putByIdContext()); 318 319 baseObject->putDirect(exec->vm(), ident, value, slot); 320 321 if (accessType != static_cast<AccessType>(stubInfo->accessType)) 322 return; 323 324 if (stubInfo->seen) 325 repatchPutByID(exec, baseObject, ident, slot, *stubInfo, Direct); 326 else 327 stubInfo->seen = true; 328} 329 330void JIT_OPERATION operationPutByIdDirectNonStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) 331{ 332 VM* vm = &exec->vm(); 333 NativeCallFrameTracer tracer(vm, exec); 334 335 Identifier ident(vm, uid); 336 AccessType accessType = static_cast<AccessType>(stubInfo->accessType); 337 338 JSValue value = JSValue::decode(encodedValue); 339 JSObject* baseObject = asObject(JSValue::decode(encodedBase)); 340 PutPropertySlot slot(baseObject, false, exec->codeBlock()->putByIdContext()); 341 342 baseObject->putDirect(exec->vm(), ident, value, slot); 343 344 if (accessType != static_cast<AccessType>(stubInfo->accessType)) 345 return; 346 347 if (stubInfo->seen) 348 repatchPutByID(exec, baseObject, ident, slot, *stubInfo, Direct); 349 else 350 stubInfo->seen = true; 351} 352 353void JIT_OPERATION operationPutByIdStrictBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) 354{ 355 VM* vm = &exec->vm(); 356 NativeCallFrameTracer tracer(vm, exec); 357 358 Identifier ident(vm, uid); 359 AccessType accessType = static_cast<AccessType>(stubInfo->accessType); 360 361 JSValue value = JSValue::decode(encodedValue); 362 JSValue baseValue = JSValue::decode(encodedBase); 363 PutPropertySlot slot(baseValue, true, exec->codeBlock()->putByIdContext()); 364 365 baseValue.put(exec, ident, value, slot); 366 367 if (accessType != static_cast<AccessType>(stubInfo->accessType)) 368 return; 369 370 buildPutByIdList(exec, baseValue, ident, slot, *stubInfo, NotDirect); 371} 372 373void JIT_OPERATION operationPutByIdNonStrictBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) 374{ 375 VM* vm = &exec->vm(); 376 NativeCallFrameTracer tracer(vm, exec); 377 378 Identifier ident(vm, uid); 379 AccessType accessType = static_cast<AccessType>(stubInfo->accessType); 380 381 JSValue value = JSValue::decode(encodedValue); 382 JSValue baseValue = JSValue::decode(encodedBase); 383 PutPropertySlot slot(baseValue, false, exec->codeBlock()->putByIdContext()); 384 385 baseValue.put(exec, ident, value, slot); 386 387 if (accessType != static_cast<AccessType>(stubInfo->accessType)) 388 return; 389 390 buildPutByIdList(exec, baseValue, ident, slot, *stubInfo, NotDirect); 391} 392 393void JIT_OPERATION operationPutByIdDirectStrictBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) 394{ 395 VM* vm = &exec->vm(); 396 NativeCallFrameTracer tracer(vm, exec); 397 398 Identifier ident(vm, uid); 399 AccessType accessType = static_cast<AccessType>(stubInfo->accessType); 400 401 JSValue value = JSValue::decode(encodedValue); 402 JSObject* baseObject = asObject(JSValue::decode(encodedBase)); 403 PutPropertySlot slot(baseObject, true, exec->codeBlock()->putByIdContext()); 404 405 baseObject->putDirect(exec->vm(), ident, value, slot); 406 407 if (accessType != static_cast<AccessType>(stubInfo->accessType)) 408 return; 409 410 buildPutByIdList(exec, baseObject, ident, slot, *stubInfo, Direct); 411} 412 413void JIT_OPERATION operationPutByIdDirectNonStrictBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, StringImpl* uid) 414{ 415 VM* vm = &exec->vm(); 416 NativeCallFrameTracer tracer(vm, exec); 417 418 Identifier ident(vm, uid); 419 AccessType accessType = static_cast<AccessType>(stubInfo->accessType); 420 421 JSValue value = JSValue::decode(encodedValue); 422 JSObject* baseObject = asObject(JSValue::decode(encodedBase)); 423 PutPropertySlot slot(baseObject, false, exec->codeBlock()->putByIdContext()); 424 425 baseObject ->putDirect(exec->vm(), ident, value, slot); 426 427 if (accessType != static_cast<AccessType>(stubInfo->accessType)) 428 return; 429 430 buildPutByIdList(exec, baseObject, ident, slot, *stubInfo, Direct); 431} 432 433void JIT_OPERATION operationReallocateStorageAndFinishPut(ExecState* exec, JSObject* base, Structure* structure, PropertyOffset offset, EncodedJSValue value) 434{ 435 VM& vm = exec->vm(); 436 NativeCallFrameTracer tracer(&vm, exec); 437 438 ASSERT(structure->outOfLineCapacity() > base->structure(vm)->outOfLineCapacity()); 439 ASSERT(!vm.heap.storageAllocator().fastPathShouldSucceed(structure->outOfLineCapacity() * sizeof(JSValue))); 440 base->setStructureAndReallocateStorageIfNecessary(vm, structure); 441 base->putDirect(vm, offset, JSValue::decode(value)); 442} 443 444static void putByVal(CallFrame* callFrame, JSValue baseValue, JSValue subscript, JSValue value) 445{ 446 VM& vm = callFrame->vm(); 447 if (LIKELY(subscript.isUInt32())) { 448 uint32_t i = subscript.asUInt32(); 449 if (baseValue.isObject()) { 450 JSObject* object = asObject(baseValue); 451 if (object->canSetIndexQuickly(i)) 452 object->setIndexQuickly(callFrame->vm(), i, value); 453 else 454 object->methodTable(vm)->putByIndex(object, callFrame, i, value, callFrame->codeBlock()->isStrictMode()); 455 } else 456 baseValue.putByIndex(callFrame, i, value, callFrame->codeBlock()->isStrictMode()); 457 } else if (isName(subscript)) { 458 PutPropertySlot slot(baseValue, callFrame->codeBlock()->isStrictMode()); 459 baseValue.put(callFrame, jsCast<NameInstance*>(subscript.asCell())->privateName(), value, slot); 460 } else { 461 Identifier property = subscript.toString(callFrame)->toIdentifier(callFrame); 462 if (!callFrame->vm().exception()) { // Don't put to an object if toString threw an exception. 463 PutPropertySlot slot(baseValue, callFrame->codeBlock()->isStrictMode()); 464 baseValue.put(callFrame, property, value, slot); 465 } 466 } 467} 468 469static void directPutByVal(CallFrame* callFrame, JSObject* baseObject, JSValue subscript, JSValue value) 470{ 471 if (LIKELY(subscript.isUInt32())) { 472 uint32_t i = subscript.asUInt32(); 473 baseObject->putDirectIndex(callFrame, i, value); 474 } else if (isName(subscript)) { 475 PutPropertySlot slot(baseObject, callFrame->codeBlock()->isStrictMode()); 476 baseObject->putDirect(callFrame->vm(), jsCast<NameInstance*>(subscript.asCell())->privateName(), value, slot); 477 } else { 478 Identifier property(callFrame, subscript.toString(callFrame)->value(callFrame)); 479 if (!callFrame->vm().exception()) { // Don't put to an object if toString threw an exception. 480 PutPropertySlot slot(baseObject, callFrame->codeBlock()->isStrictMode()); 481 baseObject->putDirect(callFrame->vm(), property, value, slot); 482 } 483 } 484} 485void JIT_OPERATION operationPutByVal(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue) 486{ 487 VM& vm = exec->vm(); 488 NativeCallFrameTracer tracer(&vm, exec); 489 490 JSValue baseValue = JSValue::decode(encodedBaseValue); 491 JSValue subscript = JSValue::decode(encodedSubscript); 492 JSValue value = JSValue::decode(encodedValue); 493 494 if (baseValue.isObject() && subscript.isInt32()) { 495 // See if it's worth optimizing at all. 496 JSObject* object = asObject(baseValue); 497 bool didOptimize = false; 498 499 unsigned bytecodeOffset = exec->locationAsBytecodeOffset(); 500 ASSERT(bytecodeOffset); 501 ByValInfo& byValInfo = exec->codeBlock()->getByValInfo(bytecodeOffset - 1); 502 ASSERT(!byValInfo.stubRoutine); 503 504 if (hasOptimizableIndexing(object->structure(vm))) { 505 // Attempt to optimize. 506 JITArrayMode arrayMode = jitArrayModeForStructure(object->structure(vm)); 507 if (arrayMode != byValInfo.arrayMode) { 508 JIT::compilePutByVal(&vm, exec->codeBlock(), &byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode); 509 didOptimize = true; 510 } 511 } 512 513 if (!didOptimize) { 514 // If we take slow path more than 10 times without patching then make sure we 515 // never make that mistake again. Or, if we failed to patch and we have some object 516 // that intercepts indexed get, then don't even wait until 10 times. For cases 517 // where we see non-index-intercepting objects, this gives 10 iterations worth of 518 // opportunity for us to observe that the get_by_val may be polymorphic. 519 if (++byValInfo.slowPathCount >= 10 520 || object->structure(vm)->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) { 521 // Don't ever try to optimize. 522 RepatchBuffer repatchBuffer(exec->codeBlock()); 523 repatchBuffer.relinkCallerToFunction(ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationPutByValGeneric)); 524 } 525 } 526 } 527 528 putByVal(exec, baseValue, subscript, value); 529} 530 531void JIT_OPERATION operationDirectPutByVal(ExecState* callFrame, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue) 532{ 533 VM& vm = callFrame->vm(); 534 NativeCallFrameTracer tracer(&vm, callFrame); 535 536 JSValue baseValue = JSValue::decode(encodedBaseValue); 537 JSValue subscript = JSValue::decode(encodedSubscript); 538 JSValue value = JSValue::decode(encodedValue); 539 RELEASE_ASSERT(baseValue.isObject()); 540 JSObject* object = asObject(baseValue); 541 if (subscript.isInt32()) { 542 // See if it's worth optimizing at all. 543 bool didOptimize = false; 544 545 unsigned bytecodeOffset = callFrame->locationAsBytecodeOffset(); 546 ASSERT(bytecodeOffset); 547 ByValInfo& byValInfo = callFrame->codeBlock()->getByValInfo(bytecodeOffset - 1); 548 ASSERT(!byValInfo.stubRoutine); 549 550 if (hasOptimizableIndexing(object->structure(vm))) { 551 // Attempt to optimize. 552 JITArrayMode arrayMode = jitArrayModeForStructure(object->structure(vm)); 553 if (arrayMode != byValInfo.arrayMode) { 554 JIT::compileDirectPutByVal(&vm, callFrame->codeBlock(), &byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode); 555 didOptimize = true; 556 } 557 } 558 559 if (!didOptimize) { 560 // If we take slow path more than 10 times without patching then make sure we 561 // never make that mistake again. Or, if we failed to patch and we have some object 562 // that intercepts indexed get, then don't even wait until 10 times. For cases 563 // where we see non-index-intercepting objects, this gives 10 iterations worth of 564 // opportunity for us to observe that the get_by_val may be polymorphic. 565 if (++byValInfo.slowPathCount >= 10 566 || object->structure(vm)->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) { 567 // Don't ever try to optimize. 568 RepatchBuffer repatchBuffer(callFrame->codeBlock()); 569 repatchBuffer.relinkCallerToFunction(ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationDirectPutByValGeneric)); 570 } 571 } 572 } 573 directPutByVal(callFrame, object, subscript, value); 574} 575 576void JIT_OPERATION operationPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue) 577{ 578 VM& vm = exec->vm(); 579 NativeCallFrameTracer tracer(&vm, exec); 580 581 JSValue baseValue = JSValue::decode(encodedBaseValue); 582 JSValue subscript = JSValue::decode(encodedSubscript); 583 JSValue value = JSValue::decode(encodedValue); 584 585 putByVal(exec, baseValue, subscript, value); 586} 587 588 589void JIT_OPERATION operationDirectPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue) 590{ 591 VM& vm = exec->vm(); 592 NativeCallFrameTracer tracer(&vm, exec); 593 594 JSValue baseValue = JSValue::decode(encodedBaseValue); 595 JSValue subscript = JSValue::decode(encodedSubscript); 596 JSValue value = JSValue::decode(encodedValue); 597 RELEASE_ASSERT(baseValue.isObject()); 598 directPutByVal(exec, asObject(baseValue), subscript, value); 599} 600 601EncodedJSValue JIT_OPERATION operationCallEval(ExecState* exec, ExecState* execCallee) 602{ 603 ASSERT(exec->codeBlock()->codeType() != FunctionCode 604 || !exec->codeBlock()->needsActivation() 605 || exec->hasActivation()); 606 607 execCallee->setScope(exec->scope()); 608 execCallee->setCodeBlock(0); 609 610 if (!isHostFunction(execCallee->calleeAsValue(), globalFuncEval)) 611 return JSValue::encode(JSValue()); 612 613 VM* vm = &execCallee->vm(); 614 JSValue result = eval(execCallee); 615 if (vm->exception()) 616 return EncodedJSValue(); 617 618 return JSValue::encode(result); 619} 620 621static void* handleHostCall(ExecState* execCallee, JSValue callee, CodeSpecializationKind kind) 622{ 623 ExecState* exec = execCallee->callerFrame(); 624 VM* vm = &exec->vm(); 625 626 execCallee->setScope(exec->scope()); 627 execCallee->setCodeBlock(0); 628 629 if (kind == CodeForCall) { 630 CallData callData; 631 CallType callType = getCallData(callee, callData); 632 633 ASSERT(callType != CallTypeJS); 634 635 if (callType == CallTypeHost) { 636 NativeCallFrameTracer tracer(vm, execCallee); 637 execCallee->setCallee(asObject(callee)); 638 vm->hostCallReturnValue = JSValue::decode(callData.native.function(execCallee)); 639 if (vm->exception()) 640 return vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); 641 642 return reinterpret_cast<void*>(getHostCallReturnValue); 643 } 644 645 ASSERT(callType == CallTypeNone); 646 exec->vm().throwException(exec, createNotAFunctionError(exec, callee)); 647 return vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); 648 } 649 650 ASSERT(kind == CodeForConstruct); 651 652 ConstructData constructData; 653 ConstructType constructType = getConstructData(callee, constructData); 654 655 ASSERT(constructType != ConstructTypeJS); 656 657 if (constructType == ConstructTypeHost) { 658 NativeCallFrameTracer tracer(vm, execCallee); 659 execCallee->setCallee(asObject(callee)); 660 vm->hostCallReturnValue = JSValue::decode(constructData.native.function(execCallee)); 661 if (vm->exception()) 662 return vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); 663 664 return reinterpret_cast<void*>(getHostCallReturnValue); 665 } 666 667 ASSERT(constructType == ConstructTypeNone); 668 exec->vm().throwException(exec, createNotAConstructorError(exec, callee)); 669 return vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); 670} 671 672inline char* linkFor( 673 ExecState* execCallee, CallLinkInfo* callLinkInfo, CodeSpecializationKind kind, 674 RegisterPreservationMode registers) 675{ 676 ExecState* exec = execCallee->callerFrame(); 677 VM* vm = &exec->vm(); 678 NativeCallFrameTracer tracer(vm, exec); 679 680 JSValue calleeAsValue = execCallee->calleeAsValue(); 681 JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue); 682 if (!calleeAsFunctionCell) 683 return reinterpret_cast<char*>(handleHostCall(execCallee, calleeAsValue, kind)); 684 685 JSFunction* callee = jsCast<JSFunction*>(calleeAsFunctionCell); 686 JSScope* scope = callee->scopeUnchecked(); 687 execCallee->setScope(scope); 688 ExecutableBase* executable = callee->executable(); 689 690 MacroAssemblerCodePtr codePtr; 691 CodeBlock* codeBlock = 0; 692 if (executable->isHostFunction()) 693 codePtr = executable->entrypointFor(*vm, kind, MustCheckArity, registers); 694 else { 695 FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable); 696 JSObject* error = functionExecutable->prepareForExecution(execCallee, callee, &scope, kind); 697 execCallee->setScope(scope); 698 if (error) { 699 throwStackOverflowError(exec); 700 return reinterpret_cast<char*>(vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress()); 701 } 702 codeBlock = functionExecutable->codeBlockFor(kind); 703 ArityCheckMode arity; 704 if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters()) || callLinkInfo->callType == CallLinkInfo::CallVarargs || callLinkInfo->callType == CallLinkInfo::ConstructVarargs) 705 arity = MustCheckArity; 706 else 707 arity = ArityCheckNotRequired; 708 codePtr = functionExecutable->entrypointFor(*vm, kind, arity, registers); 709 } 710 if (!callLinkInfo->seenOnce()) 711 callLinkInfo->setSeen(); 712 else 713 linkFor(execCallee, *callLinkInfo, codeBlock, callee, codePtr, kind, registers); 714 return reinterpret_cast<char*>(codePtr.executableAddress()); 715} 716 717char* JIT_OPERATION operationLinkCall(ExecState* execCallee, CallLinkInfo* callLinkInfo) 718{ 719 return linkFor(execCallee, callLinkInfo, CodeForCall, RegisterPreservationNotRequired); 720} 721 722char* JIT_OPERATION operationLinkConstruct(ExecState* execCallee, CallLinkInfo* callLinkInfo) 723{ 724 return linkFor(execCallee, callLinkInfo, CodeForConstruct, RegisterPreservationNotRequired); 725} 726 727char* JIT_OPERATION operationLinkCallThatPreservesRegs(ExecState* execCallee, CallLinkInfo* callLinkInfo) 728{ 729 return linkFor(execCallee, callLinkInfo, CodeForCall, MustPreserveRegisters); 730} 731 732char* JIT_OPERATION operationLinkConstructThatPreservesRegs(ExecState* execCallee, CallLinkInfo* callLinkInfo) 733{ 734 return linkFor(execCallee, callLinkInfo, CodeForConstruct, MustPreserveRegisters); 735} 736 737inline char* virtualForWithFunction( 738 ExecState* execCallee, CodeSpecializationKind kind, RegisterPreservationMode registers, 739 JSCell*& calleeAsFunctionCell) 740{ 741 ExecState* exec = execCallee->callerFrame(); 742 VM* vm = &exec->vm(); 743 NativeCallFrameTracer tracer(vm, exec); 744 745 JSValue calleeAsValue = execCallee->calleeAsValue(); 746 calleeAsFunctionCell = getJSFunction(calleeAsValue); 747 if (UNLIKELY(!calleeAsFunctionCell)) 748 return reinterpret_cast<char*>(handleHostCall(execCallee, calleeAsValue, kind)); 749 750 JSFunction* function = jsCast<JSFunction*>(calleeAsFunctionCell); 751 JSScope* scope = function->scopeUnchecked(); 752 execCallee->setScope(scope); 753 ExecutableBase* executable = function->executable(); 754 if (UNLIKELY(!executable->hasJITCodeFor(kind))) { 755 FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable); 756 JSObject* error = functionExecutable->prepareForExecution(execCallee, function, &scope, kind); 757 execCallee->setScope(scope); 758 if (error) { 759 exec->vm().throwException(exec, error); 760 return reinterpret_cast<char*>(vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress()); 761 } 762 } 763 return reinterpret_cast<char*>(executable->entrypointFor( 764 *vm, kind, MustCheckArity, registers).executableAddress()); 765} 766 767inline char* virtualFor( 768 ExecState* execCallee, CodeSpecializationKind kind, RegisterPreservationMode registers) 769{ 770 JSCell* calleeAsFunctionCellIgnored; 771 return virtualForWithFunction(execCallee, kind, registers, calleeAsFunctionCellIgnored); 772} 773 774static bool attemptToOptimizeClosureCall( 775 ExecState* execCallee, RegisterPreservationMode registers, JSCell* calleeAsFunctionCell, 776 CallLinkInfo& callLinkInfo) 777{ 778 if (!calleeAsFunctionCell) 779 return false; 780 781 VM& vm = execCallee->vm(); 782 JSFunction* callee = jsCast<JSFunction*>(calleeAsFunctionCell); 783 JSFunction* oldCallee = callLinkInfo.callee.get(); 784 785 if (!oldCallee 786 || oldCallee->structure(vm) != callee->structure(vm) 787 || oldCallee->executable() != callee->executable()) 788 return false; 789 790 ASSERT(callee->executable()->hasJITCodeForCall()); 791 MacroAssemblerCodePtr codePtr = 792 callee->executable()->generatedJITCodeForCall()->addressForCall( 793 *execCallee->callerFrame()->codeBlock()->vm(), callee->executable(), 794 ArityCheckNotRequired, registers); 795 796 CodeBlock* codeBlock; 797 if (callee->executable()->isHostFunction()) 798 codeBlock = 0; 799 else { 800 codeBlock = jsCast<FunctionExecutable*>(callee->executable())->codeBlockForCall(); 801 if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters()) || callLinkInfo.callType == CallLinkInfo::CallVarargs || callLinkInfo.callType == CallLinkInfo::ConstructVarargs) 802 return false; 803 } 804 805 linkClosureCall( 806 execCallee, callLinkInfo, codeBlock, 807 callee->structure(), callee->executable(), codePtr, registers); 808 809 return true; 810} 811 812char* JIT_OPERATION operationLinkClosureCall(ExecState* execCallee, CallLinkInfo* callLinkInfo) 813{ 814 JSCell* calleeAsFunctionCell; 815 char* result = virtualForWithFunction(execCallee, CodeForCall, RegisterPreservationNotRequired, calleeAsFunctionCell); 816 817 if (!attemptToOptimizeClosureCall(execCallee, RegisterPreservationNotRequired, calleeAsFunctionCell, *callLinkInfo)) 818 linkSlowFor(execCallee, *callLinkInfo, CodeForCall, RegisterPreservationNotRequired); 819 820 return result; 821} 822 823char* JIT_OPERATION operationVirtualCall(ExecState* execCallee, CallLinkInfo*) 824{ 825 return virtualFor(execCallee, CodeForCall, RegisterPreservationNotRequired); 826} 827 828char* JIT_OPERATION operationVirtualConstruct(ExecState* execCallee, CallLinkInfo*) 829{ 830 return virtualFor(execCallee, CodeForConstruct, RegisterPreservationNotRequired); 831} 832 833char* JIT_OPERATION operationLinkClosureCallThatPreservesRegs(ExecState* execCallee, CallLinkInfo* callLinkInfo) 834{ 835 JSCell* calleeAsFunctionCell; 836 char* result = virtualForWithFunction(execCallee, CodeForCall, MustPreserveRegisters, calleeAsFunctionCell); 837 838 if (!attemptToOptimizeClosureCall(execCallee, MustPreserveRegisters, calleeAsFunctionCell, *callLinkInfo)) 839 linkSlowFor(execCallee, *callLinkInfo, CodeForCall, MustPreserveRegisters); 840 841 return result; 842} 843 844char* JIT_OPERATION operationVirtualCallThatPreservesRegs(ExecState* execCallee, CallLinkInfo*) 845{ 846 return virtualFor(execCallee, CodeForCall, MustPreserveRegisters); 847} 848 849char* JIT_OPERATION operationVirtualConstructThatPreservesRegs(ExecState* execCallee, CallLinkInfo*) 850{ 851 return virtualFor(execCallee, CodeForConstruct, MustPreserveRegisters); 852} 853 854size_t JIT_OPERATION operationCompareLess(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) 855{ 856 VM* vm = &exec->vm(); 857 NativeCallFrameTracer tracer(vm, exec); 858 859 return jsLess<true>(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)); 860} 861 862size_t JIT_OPERATION operationCompareLessEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) 863{ 864 VM* vm = &exec->vm(); 865 NativeCallFrameTracer tracer(vm, exec); 866 867 return jsLessEq<true>(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)); 868} 869 870size_t JIT_OPERATION operationCompareGreater(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) 871{ 872 VM* vm = &exec->vm(); 873 NativeCallFrameTracer tracer(vm, exec); 874 875 return jsLess<false>(exec, JSValue::decode(encodedOp2), JSValue::decode(encodedOp1)); 876} 877 878size_t JIT_OPERATION operationCompareGreaterEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) 879{ 880 VM* vm = &exec->vm(); 881 NativeCallFrameTracer tracer(vm, exec); 882 883 return jsLessEq<false>(exec, JSValue::decode(encodedOp2), JSValue::decode(encodedOp1)); 884} 885 886size_t JIT_OPERATION operationConvertJSValueToBoolean(ExecState* exec, EncodedJSValue encodedOp) 887{ 888 VM* vm = &exec->vm(); 889 NativeCallFrameTracer tracer(vm, exec); 890 891 return JSValue::decode(encodedOp).toBoolean(exec); 892} 893 894size_t JIT_OPERATION operationCompareEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) 895{ 896 VM* vm = &exec->vm(); 897 NativeCallFrameTracer tracer(vm, exec); 898 899 return JSValue::equalSlowCaseInline(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)); 900} 901 902#if USE(JSVALUE64) 903EncodedJSValue JIT_OPERATION operationCompareStringEq(ExecState* exec, JSCell* left, JSCell* right) 904#else 905size_t JIT_OPERATION operationCompareStringEq(ExecState* exec, JSCell* left, JSCell* right) 906#endif 907{ 908 VM* vm = &exec->vm(); 909 NativeCallFrameTracer tracer(vm, exec); 910 911 bool result = WTF::equal(*asString(left)->value(exec).impl(), *asString(right)->value(exec).impl()); 912#if USE(JSVALUE64) 913 return JSValue::encode(jsBoolean(result)); 914#else 915 return result; 916#endif 917} 918 919size_t JIT_OPERATION operationHasProperty(ExecState* exec, JSObject* base, JSString* property) 920{ 921 int result = base->hasProperty(exec, Identifier(exec, property->value(exec))); 922 return result; 923} 924 925 926EncodedJSValue JIT_OPERATION operationNewArrayWithProfile(ExecState* exec, ArrayAllocationProfile* profile, const JSValue* values, int size) 927{ 928 VM* vm = &exec->vm(); 929 NativeCallFrameTracer tracer(vm, exec); 930 return JSValue::encode(constructArrayNegativeIndexed(exec, profile, values, size)); 931} 932 933EncodedJSValue JIT_OPERATION operationNewArrayBufferWithProfile(ExecState* exec, ArrayAllocationProfile* profile, const JSValue* values, int size) 934{ 935 VM* vm = &exec->vm(); 936 NativeCallFrameTracer tracer(vm, exec); 937 return JSValue::encode(constructArray(exec, profile, values, size)); 938} 939 940EncodedJSValue JIT_OPERATION operationNewArrayWithSizeAndProfile(ExecState* exec, ArrayAllocationProfile* profile, EncodedJSValue size) 941{ 942 VM* vm = &exec->vm(); 943 NativeCallFrameTracer tracer(vm, exec); 944 JSValue sizeValue = JSValue::decode(size); 945 return JSValue::encode(constructArrayWithSizeQuirk(exec, profile, exec->lexicalGlobalObject(), sizeValue)); 946} 947 948EncodedJSValue JIT_OPERATION operationNewFunction(ExecState* exec, JSCell* functionExecutable) 949{ 950 ASSERT(functionExecutable->inherits(FunctionExecutable::info())); 951 VM& vm = exec->vm(); 952 NativeCallFrameTracer tracer(&vm, exec); 953 return JSValue::encode(JSFunction::create(vm, static_cast<FunctionExecutable*>(functionExecutable), exec->scope())); 954} 955 956JSCell* JIT_OPERATION operationNewObject(ExecState* exec, Structure* structure) 957{ 958 VM* vm = &exec->vm(); 959 NativeCallFrameTracer tracer(vm, exec); 960 961 return constructEmptyObject(exec, structure); 962} 963 964EncodedJSValue JIT_OPERATION operationNewRegexp(ExecState* exec, void* regexpPtr) 965{ 966 VM& vm = exec->vm(); 967 NativeCallFrameTracer tracer(&vm, exec); 968 RegExp* regexp = static_cast<RegExp*>(regexpPtr); 969 if (!regexp->isValid()) { 970 vm.throwException(exec, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor.")); 971 return JSValue::encode(jsUndefined()); 972 } 973 974 return JSValue::encode(RegExpObject::create(vm, exec->lexicalGlobalObject()->regExpStructure(), regexp)); 975} 976 977void JIT_OPERATION operationHandleWatchdogTimer(ExecState* exec) 978{ 979 VM& vm = exec->vm(); 980 NativeCallFrameTracer tracer(&vm, exec); 981 982 if (UNLIKELY(vm.watchdog && vm.watchdog->didFire(exec))) 983 vm.throwException(exec, createTerminatedExecutionException(&vm)); 984} 985 986void JIT_OPERATION operationThrowStaticError(ExecState* exec, EncodedJSValue encodedValue, int32_t referenceErrorFlag) 987{ 988 VM& vm = exec->vm(); 989 NativeCallFrameTracer tracer(&vm, exec); 990 991 String message = errorDescriptionForValue(exec, JSValue::decode(encodedValue))->value(exec); 992 if (referenceErrorFlag) 993 vm.throwException(exec, createReferenceError(exec, message)); 994 else 995 vm.throwException(exec, createTypeError(exec, message)); 996} 997 998void JIT_OPERATION operationDebug(ExecState* exec, int32_t debugHookID) 999{ 1000 VM& vm = exec->vm(); 1001 NativeCallFrameTracer tracer(&vm, exec); 1002 1003 vm.interpreter->debug(exec, static_cast<DebugHookID>(debugHookID)); 1004} 1005 1006#if ENABLE(DFG_JIT) 1007static void updateAllPredictionsAndOptimizeAfterWarmUp(CodeBlock* codeBlock) 1008{ 1009 codeBlock->updateAllPredictions(); 1010 codeBlock->optimizeAfterWarmUp(); 1011} 1012 1013SlowPathReturnType JIT_OPERATION operationOptimize(ExecState* exec, int32_t bytecodeIndex) 1014{ 1015 VM& vm = exec->vm(); 1016 NativeCallFrameTracer tracer(&vm, exec); 1017 1018 // Defer GC for a while so that it doesn't run between when we enter into this 1019 // slow path and when we figure out the state of our code block. This prevents 1020 // a number of awkward reentrancy scenarios, including: 1021 // 1022 // - The optimized version of our code block being jettisoned by GC right after 1023 // we concluded that we wanted to use it, but have not planted it into the JS 1024 // stack yet. 1025 // 1026 // - An optimized version of our code block being installed just as we decided 1027 // that it wasn't ready yet. 1028 // 1029 // Note that jettisoning won't happen if we already initiated OSR, because in 1030 // that case we would have already planted the optimized code block into the JS 1031 // stack. 1032 DeferGCForAWhile deferGC(vm.heap); 1033 1034 CodeBlock* codeBlock = exec->codeBlock(); 1035 1036 if (bytecodeIndex) { 1037 // If we're attempting to OSR from a loop, assume that this should be 1038 // separately optimized. 1039 codeBlock->m_shouldAlwaysBeInlined = false; 1040 } 1041 1042 if (Options::verboseOSR()) { 1043 dataLog( 1044 *codeBlock, ": Entered optimize with bytecodeIndex = ", bytecodeIndex, 1045 ", executeCounter = ", codeBlock->jitExecuteCounter(), 1046 ", optimizationDelayCounter = ", codeBlock->reoptimizationRetryCounter(), 1047 ", exitCounter = "); 1048 if (codeBlock->hasOptimizedReplacement()) 1049 dataLog(codeBlock->replacement()->osrExitCounter()); 1050 else 1051 dataLog("N/A"); 1052 dataLog("\n"); 1053 } 1054 1055 if (!codeBlock->checkIfOptimizationThresholdReached()) { 1056 codeBlock->updateAllPredictions(); 1057 if (Options::verboseOSR()) 1058 dataLog("Choosing not to optimize ", *codeBlock, " yet, because the threshold hasn't been reached.\n"); 1059 return encodeResult(0, 0); 1060 } 1061 1062 if (vm.enabledProfiler()) { 1063 updateAllPredictionsAndOptimizeAfterWarmUp(codeBlock); 1064 return encodeResult(0, 0); 1065 } 1066 1067 Debugger* debugger = codeBlock->globalObject()->debugger(); 1068 if (debugger && (debugger->isStepping() || codeBlock->baselineAlternative()->hasDebuggerRequests())) { 1069 updateAllPredictionsAndOptimizeAfterWarmUp(codeBlock); 1070 return encodeResult(0, 0); 1071 } 1072 1073 if (codeBlock->m_shouldAlwaysBeInlined) { 1074 updateAllPredictionsAndOptimizeAfterWarmUp(codeBlock); 1075 if (Options::verboseOSR()) 1076 dataLog("Choosing not to optimize ", *codeBlock, " yet, because m_shouldAlwaysBeInlined == true.\n"); 1077 return encodeResult(0, 0); 1078 } 1079 1080 // We cannot be in the process of asynchronous compilation and also have an optimized 1081 // replacement. 1082 DFG::Worklist* worklist = DFG::existingGlobalDFGWorklistOrNull(); 1083 ASSERT( 1084 !worklist 1085 || !(worklist->compilationState(DFG::CompilationKey(codeBlock, DFG::DFGMode)) != DFG::Worklist::NotKnown 1086 && codeBlock->hasOptimizedReplacement())); 1087 1088 DFG::Worklist::State worklistState; 1089 if (worklist) { 1090 // The call to DFG::Worklist::completeAllReadyPlansForVM() will complete all ready 1091 // (i.e. compiled) code blocks. But if it completes ours, we also need to know 1092 // what the result was so that we don't plow ahead and attempt OSR or immediate 1093 // reoptimization. This will have already also set the appropriate JIT execution 1094 // count threshold depending on what happened, so if the compilation was anything 1095 // but successful we just want to return early. See the case for worklistState == 1096 // DFG::Worklist::Compiled, below. 1097 1098 // Note that we could have alternatively just called Worklist::compilationState() 1099 // here, and if it returned Compiled, we could have then called 1100 // completeAndScheduleOSR() below. But that would have meant that it could take 1101 // longer for code blocks to be completed: they would only complete when *their* 1102 // execution count trigger fired; but that could take a while since the firing is 1103 // racy. It could also mean that code blocks that never run again after being 1104 // compiled would sit on the worklist until next GC. That's fine, but it's 1105 // probably a waste of memory. Our goal here is to complete code blocks as soon as 1106 // possible in order to minimize the chances of us executing baseline code after 1107 // optimized code is already available. 1108 worklistState = worklist->completeAllReadyPlansForVM( 1109 vm, DFG::CompilationKey(codeBlock, DFG::DFGMode)); 1110 } else 1111 worklistState = DFG::Worklist::NotKnown; 1112 1113 if (worklistState == DFG::Worklist::Compiling) { 1114 // We cannot be in the process of asynchronous compilation and also have an optimized 1115 // replacement. 1116 RELEASE_ASSERT(!codeBlock->hasOptimizedReplacement()); 1117 codeBlock->setOptimizationThresholdBasedOnCompilationResult(CompilationDeferred); 1118 return encodeResult(0, 0); 1119 } 1120 1121 if (worklistState == DFG::Worklist::Compiled) { 1122 // If we don't have an optimized replacement but we did just get compiled, then 1123 // the compilation failed or was invalidated, in which case the execution count 1124 // thresholds have already been set appropriately by 1125 // CodeBlock::setOptimizationThresholdBasedOnCompilationResult() and we have 1126 // nothing left to do. 1127 if (!codeBlock->hasOptimizedReplacement()) { 1128 codeBlock->updateAllPredictions(); 1129 if (Options::verboseOSR()) 1130 dataLog("Code block ", *codeBlock, " was compiled but it doesn't have an optimized replacement.\n"); 1131 return encodeResult(0, 0); 1132 } 1133 } else if (codeBlock->hasOptimizedReplacement()) { 1134 if (Options::verboseOSR()) 1135 dataLog("Considering OSR ", *codeBlock, " -> ", *codeBlock->replacement(), ".\n"); 1136 // If we have an optimized replacement, then it must be the case that we entered 1137 // cti_optimize from a loop. That's because if there's an optimized replacement, 1138 // then all calls to this function will be relinked to the replacement and so 1139 // the prologue OSR will never fire. 1140 1141 // This is an interesting threshold check. Consider that a function OSR exits 1142 // in the middle of a loop, while having a relatively low exit count. The exit 1143 // will reset the execution counter to some target threshold, meaning that this 1144 // code won't be reached until that loop heats up for >=1000 executions. But then 1145 // we do a second check here, to see if we should either reoptimize, or just 1146 // attempt OSR entry. Hence it might even be correct for 1147 // shouldReoptimizeFromLoopNow() to always return true. But we make it do some 1148 // additional checking anyway, to reduce the amount of recompilation thrashing. 1149 if (codeBlock->replacement()->shouldReoptimizeFromLoopNow()) { 1150 if (Options::verboseOSR()) { 1151 dataLog( 1152 "Triggering reoptimization of ", *codeBlock, 1153 "(", *codeBlock->replacement(), ") (in loop).\n"); 1154 } 1155 codeBlock->replacement()->jettison(Profiler::JettisonDueToBaselineLoopReoptimizationTrigger, CountReoptimization); 1156 return encodeResult(0, 0); 1157 } 1158 } else { 1159 if (!codeBlock->shouldOptimizeNow()) { 1160 if (Options::verboseOSR()) { 1161 dataLog( 1162 "Delaying optimization for ", *codeBlock, 1163 " because of insufficient profiling.\n"); 1164 } 1165 return encodeResult(0, 0); 1166 } 1167 1168 if (Options::verboseOSR()) 1169 dataLog("Triggering optimized compilation of ", *codeBlock, "\n"); 1170 1171 unsigned numVarsWithValues; 1172 if (bytecodeIndex) 1173 numVarsWithValues = codeBlock->m_numVars; 1174 else 1175 numVarsWithValues = 0; 1176 Operands<JSValue> mustHandleValues(codeBlock->numParameters(), numVarsWithValues); 1177 for (size_t i = 0; i < mustHandleValues.size(); ++i) { 1178 int operand = mustHandleValues.operandForIndex(i); 1179 if (operandIsArgument(operand) 1180 && !VirtualRegister(operand).toArgument() 1181 && codeBlock->codeType() == FunctionCode 1182 && codeBlock->specializationKind() == CodeForConstruct) { 1183 // Ugh. If we're in a constructor, the 'this' argument may hold garbage. It will 1184 // also never be used. It doesn't matter what we put into the value for this, 1185 // but it has to be an actual value that can be grokked by subsequent DFG passes, 1186 // so we sanitize it here by turning it into Undefined. 1187 mustHandleValues[i] = jsUndefined(); 1188 } else 1189 mustHandleValues[i] = exec->uncheckedR(operand).jsValue(); 1190 } 1191 1192 RefPtr<CodeBlock> replacementCodeBlock = codeBlock->newReplacement(); 1193 CompilationResult result = DFG::compile( 1194 vm, replacementCodeBlock.get(), 0, DFG::DFGMode, bytecodeIndex, 1195 mustHandleValues, JITToDFGDeferredCompilationCallback::create()); 1196 1197 if (result != CompilationSuccessful) { 1198 ASSERT(result == CompilationDeferred || replacementCodeBlock->hasOneRef()); 1199 return encodeResult(0, 0); 1200 } 1201 } 1202 1203 CodeBlock* optimizedCodeBlock = codeBlock->replacement(); 1204 ASSERT(JITCode::isOptimizingJIT(optimizedCodeBlock->jitType())); 1205 1206 if (void* dataBuffer = DFG::prepareOSREntry(exec, optimizedCodeBlock, bytecodeIndex)) { 1207 if (Options::verboseOSR()) { 1208 dataLog( 1209 "Performing OSR ", *codeBlock, " -> ", *optimizedCodeBlock, ".\n"); 1210 } 1211 1212 codeBlock->optimizeSoon(); 1213 return encodeResult(vm.getCTIStub(DFG::osrEntryThunkGenerator).code().executableAddress(), dataBuffer); 1214 } 1215 1216 if (Options::verboseOSR()) { 1217 dataLog( 1218 "Optimizing ", *codeBlock, " -> ", *codeBlock->replacement(), 1219 " succeeded, OSR failed, after a delay of ", 1220 codeBlock->optimizationDelayCounter(), ".\n"); 1221 } 1222 1223 // Count the OSR failure as a speculation failure. If this happens a lot, then 1224 // reoptimize. 1225 optimizedCodeBlock->countOSRExit(); 1226 1227 // We are a lot more conservative about triggering reoptimization after OSR failure than 1228 // before it. If we enter the optimize_from_loop trigger with a bucket full of fail 1229 // already, then we really would like to reoptimize immediately. But this case covers 1230 // something else: there weren't many (or any) speculation failures before, but we just 1231 // failed to enter the speculative code because some variable had the wrong value or 1232 // because the OSR code decided for any spurious reason that it did not want to OSR 1233 // right now. So, we only trigger reoptimization only upon the more conservative (non-loop) 1234 // reoptimization trigger. 1235 if (optimizedCodeBlock->shouldReoptimizeNow()) { 1236 if (Options::verboseOSR()) { 1237 dataLog( 1238 "Triggering reoptimization of ", *codeBlock, " -> ", 1239 *codeBlock->replacement(), " (after OSR fail).\n"); 1240 } 1241 optimizedCodeBlock->jettison(Profiler::JettisonDueToBaselineLoopReoptimizationTriggerOnOSREntryFail, CountReoptimization); 1242 return encodeResult(0, 0); 1243 } 1244 1245 // OSR failed this time, but it might succeed next time! Let the code run a bit 1246 // longer and then try again. 1247 codeBlock->optimizeAfterWarmUp(); 1248 1249 return encodeResult(0, 0); 1250} 1251#endif 1252 1253void JIT_OPERATION operationPutByIndex(ExecState* exec, EncodedJSValue encodedArrayValue, int32_t index, EncodedJSValue encodedValue) 1254{ 1255 VM& vm = exec->vm(); 1256 NativeCallFrameTracer tracer(&vm, exec); 1257 1258 JSValue arrayValue = JSValue::decode(encodedArrayValue); 1259 ASSERT(isJSArray(arrayValue)); 1260 asArray(arrayValue)->putDirectIndex(exec, index, JSValue::decode(encodedValue)); 1261} 1262 1263#if USE(JSVALUE64) 1264void JIT_OPERATION operationPutGetterSetter(ExecState* exec, EncodedJSValue encodedObjectValue, Identifier* identifier, EncodedJSValue encodedGetterValue, EncodedJSValue encodedSetterValue) 1265{ 1266 VM& vm = exec->vm(); 1267 NativeCallFrameTracer tracer(&vm, exec); 1268 1269 ASSERT(JSValue::decode(encodedObjectValue).isObject()); 1270 JSObject* baseObj = asObject(JSValue::decode(encodedObjectValue)); 1271 1272 GetterSetter* accessor = GetterSetter::create(vm); 1273 1274 JSValue getter = JSValue::decode(encodedGetterValue); 1275 JSValue setter = JSValue::decode(encodedSetterValue); 1276 ASSERT(getter.isObject() || getter.isUndefined()); 1277 ASSERT(setter.isObject() || setter.isUndefined()); 1278 ASSERT(getter.isObject() || setter.isObject()); 1279 1280 if (!getter.isUndefined()) 1281 accessor->setGetter(vm, asObject(getter)); 1282 if (!setter.isUndefined()) 1283 accessor->setSetter(vm, asObject(setter)); 1284 baseObj->putDirectAccessor(exec, *identifier, accessor, Accessor); 1285} 1286#else 1287void JIT_OPERATION operationPutGetterSetter(ExecState* exec, JSCell* object, Identifier* identifier, JSCell* getter, JSCell* setter) 1288{ 1289 VM& vm = exec->vm(); 1290 NativeCallFrameTracer tracer(&vm, exec); 1291 1292 ASSERT(object && object->isObject()); 1293 JSObject* baseObj = object->getObject(); 1294 1295 GetterSetter* accessor = GetterSetter::create(vm); 1296 1297 ASSERT(!getter || getter->isObject()); 1298 ASSERT(!setter || setter->isObject()); 1299 ASSERT(getter || setter); 1300 1301 if (getter) 1302 accessor->setGetter(vm, getter->getObject()); 1303 if (setter) 1304 accessor->setSetter(vm, setter->getObject()); 1305 baseObj->putDirectAccessor(exec, *identifier, accessor, Accessor); 1306} 1307#endif 1308 1309void JIT_OPERATION operationPushNameScope(ExecState* exec, Identifier* identifier, EncodedJSValue encodedValue, int32_t attibutes) 1310{ 1311 VM& vm = exec->vm(); 1312 NativeCallFrameTracer tracer(&vm, exec); 1313 1314 JSNameScope* scope = JSNameScope::create(exec, *identifier, JSValue::decode(encodedValue), attibutes); 1315 1316 exec->setScope(scope); 1317} 1318 1319void JIT_OPERATION operationPushWithScope(ExecState* exec, EncodedJSValue encodedValue) 1320{ 1321 VM& vm = exec->vm(); 1322 NativeCallFrameTracer tracer(&vm, exec); 1323 1324 JSObject* o = JSValue::decode(encodedValue).toObject(exec); 1325 if (vm.exception()) 1326 return; 1327 1328 exec->setScope(JSWithScope::create(exec, o)); 1329} 1330 1331void JIT_OPERATION operationPopScope(ExecState* exec) 1332{ 1333 VM& vm = exec->vm(); 1334 NativeCallFrameTracer tracer(&vm, exec); 1335 1336 exec->setScope(exec->scope()->next()); 1337} 1338 1339void JIT_OPERATION operationProfileDidCall(ExecState* exec, EncodedJSValue encodedValue) 1340{ 1341 VM& vm = exec->vm(); 1342 NativeCallFrameTracer tracer(&vm, exec); 1343 1344 if (LegacyProfiler* profiler = vm.enabledProfiler()) 1345 profiler->didExecute(exec, JSValue::decode(encodedValue)); 1346} 1347 1348void JIT_OPERATION operationProfileWillCall(ExecState* exec, EncodedJSValue encodedValue) 1349{ 1350 VM& vm = exec->vm(); 1351 NativeCallFrameTracer tracer(&vm, exec); 1352 1353 if (LegacyProfiler* profiler = vm.enabledProfiler()) 1354 profiler->willExecute(exec, JSValue::decode(encodedValue)); 1355} 1356 1357EncodedJSValue JIT_OPERATION operationCheckHasInstance(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBaseVal) 1358{ 1359 VM& vm = exec->vm(); 1360 NativeCallFrameTracer tracer(&vm, exec); 1361 1362 JSValue value = JSValue::decode(encodedValue); 1363 JSValue baseVal = JSValue::decode(encodedBaseVal); 1364 1365 if (baseVal.isObject()) { 1366 JSObject* baseObject = asObject(baseVal); 1367 ASSERT(!baseObject->structure(vm)->typeInfo().implementsDefaultHasInstance()); 1368 if (baseObject->structure(vm)->typeInfo().implementsHasInstance()) { 1369 bool result = baseObject->methodTable(vm)->customHasInstance(baseObject, exec, value); 1370 return JSValue::encode(jsBoolean(result)); 1371 } 1372 } 1373 1374 vm.throwException(exec, createInvalidParameterError(exec, "instanceof", baseVal)); 1375 return JSValue::encode(JSValue()); 1376} 1377 1378JSCell* JIT_OPERATION operationCreateActivation(ExecState* exec, int32_t offset) 1379{ 1380 VM& vm = exec->vm(); 1381 NativeCallFrameTracer tracer(&vm, exec); 1382 JSActivation* activation = JSActivation::create(vm, exec, exec->registers() + offset, exec->codeBlock()); 1383 exec->setScope(activation); 1384 return activation; 1385} 1386 1387JSCell* JIT_OPERATION operationCreateArguments(ExecState* exec) 1388{ 1389 VM& vm = exec->vm(); 1390 NativeCallFrameTracer tracer(&vm, exec); 1391 // NB: This needs to be exceedingly careful with top call frame tracking, since it 1392 // may be called from OSR exit, while the state of the call stack is bizarre. 1393 Arguments* result = Arguments::create(vm, exec); 1394 ASSERT(!vm.exception()); 1395 return result; 1396} 1397 1398JSCell* JIT_OPERATION operationCreateArgumentsDuringOSRExit(ExecState* exec) 1399{ 1400 DeferGCForAWhile(exec->vm().heap); 1401 return operationCreateArguments(exec); 1402} 1403 1404EncodedJSValue JIT_OPERATION operationGetArgumentsLength(ExecState* exec, int32_t argumentsRegister) 1405{ 1406 VM& vm = exec->vm(); 1407 NativeCallFrameTracer tracer(&vm, exec); 1408 // Here we can assume that the argumernts were created. Because otherwise the JIT code would 1409 // have not made this call. 1410 Identifier ident(&vm, "length"); 1411 JSValue baseValue = exec->uncheckedR(argumentsRegister).jsValue(); 1412 PropertySlot slot(baseValue); 1413 return JSValue::encode(baseValue.get(exec, ident, slot)); 1414} 1415 1416} 1417 1418static JSValue getByVal(ExecState* exec, JSValue baseValue, JSValue subscript, ReturnAddressPtr returnAddress) 1419{ 1420 if (LIKELY(baseValue.isCell() && subscript.isString())) { 1421 VM& vm = exec->vm(); 1422 Structure& structure = *baseValue.asCell()->structure(vm); 1423 if (JSCell::canUseFastGetOwnProperty(structure)) { 1424 if (JSValue result = baseValue.asCell()->fastGetOwnProperty(vm, structure, asString(subscript)->value(exec))) 1425 return result; 1426 } 1427 } 1428 1429 if (subscript.isUInt32()) { 1430 uint32_t i = subscript.asUInt32(); 1431 if (isJSString(baseValue) && asString(baseValue)->canGetIndex(i)) { 1432 ctiPatchCallByReturnAddress(exec->codeBlock(), returnAddress, FunctionPtr(operationGetByValString)); 1433 return asString(baseValue)->getIndex(exec, i); 1434 } 1435 return baseValue.get(exec, i); 1436 } 1437 1438 if (isName(subscript)) 1439 return baseValue.get(exec, jsCast<NameInstance*>(subscript.asCell())->privateName()); 1440 1441 Identifier property = subscript.toString(exec)->toIdentifier(exec); 1442 return baseValue.get(exec, property); 1443} 1444 1445extern "C" { 1446 1447EncodedJSValue JIT_OPERATION operationGetByValGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) 1448{ 1449 VM& vm = exec->vm(); 1450 NativeCallFrameTracer tracer(&vm, exec); 1451 JSValue baseValue = JSValue::decode(encodedBase); 1452 JSValue subscript = JSValue::decode(encodedSubscript); 1453 1454 JSValue result = getByVal(exec, baseValue, subscript, ReturnAddressPtr(OUR_RETURN_ADDRESS)); 1455 return JSValue::encode(result); 1456} 1457 1458EncodedJSValue JIT_OPERATION operationGetByValDefault(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) 1459{ 1460 VM& vm = exec->vm(); 1461 NativeCallFrameTracer tracer(&vm, exec); 1462 JSValue baseValue = JSValue::decode(encodedBase); 1463 JSValue subscript = JSValue::decode(encodedSubscript); 1464 1465 if (baseValue.isObject() && subscript.isInt32()) { 1466 // See if it's worth optimizing this at all. 1467 JSObject* object = asObject(baseValue); 1468 bool didOptimize = false; 1469 1470 unsigned bytecodeOffset = exec->locationAsBytecodeOffset(); 1471 ASSERT(bytecodeOffset); 1472 ByValInfo& byValInfo = exec->codeBlock()->getByValInfo(bytecodeOffset - 1); 1473 ASSERT(!byValInfo.stubRoutine); 1474 1475 if (hasOptimizableIndexing(object->structure(vm))) { 1476 // Attempt to optimize. 1477 JITArrayMode arrayMode = jitArrayModeForStructure(object->structure(vm)); 1478 if (arrayMode != byValInfo.arrayMode) { 1479 JIT::compileGetByVal(&vm, exec->codeBlock(), &byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode); 1480 didOptimize = true; 1481 } 1482 } 1483 1484 if (!didOptimize) { 1485 // If we take slow path more than 10 times without patching then make sure we 1486 // never make that mistake again. Or, if we failed to patch and we have some object 1487 // that intercepts indexed get, then don't even wait until 10 times. For cases 1488 // where we see non-index-intercepting objects, this gives 10 iterations worth of 1489 // opportunity for us to observe that the get_by_val may be polymorphic. 1490 if (++byValInfo.slowPathCount >= 10 1491 || object->structure(vm)->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) { 1492 // Don't ever try to optimize. 1493 RepatchBuffer repatchBuffer(exec->codeBlock()); 1494 repatchBuffer.relinkCallerToFunction(ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationGetByValGeneric)); 1495 } 1496 } 1497 } 1498 1499 JSValue result = getByVal(exec, baseValue, subscript, ReturnAddressPtr(OUR_RETURN_ADDRESS)); 1500 return JSValue::encode(result); 1501} 1502 1503EncodedJSValue JIT_OPERATION operationGetByValString(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) 1504{ 1505 VM& vm = exec->vm(); 1506 NativeCallFrameTracer tracer(&vm, exec); 1507 JSValue baseValue = JSValue::decode(encodedBase); 1508 JSValue subscript = JSValue::decode(encodedSubscript); 1509 1510 JSValue result; 1511 if (LIKELY(subscript.isUInt32())) { 1512 uint32_t i = subscript.asUInt32(); 1513 if (isJSString(baseValue) && asString(baseValue)->canGetIndex(i)) 1514 result = asString(baseValue)->getIndex(exec, i); 1515 else { 1516 result = baseValue.get(exec, i); 1517 if (!isJSString(baseValue)) 1518 ctiPatchCallByReturnAddress(exec->codeBlock(), ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationGetByValDefault)); 1519 } 1520 } else if (isName(subscript)) 1521 result = baseValue.get(exec, jsCast<NameInstance*>(subscript.asCell())->privateName()); 1522 else { 1523 Identifier property = subscript.toString(exec)->toIdentifier(exec); 1524 result = baseValue.get(exec, property); 1525 } 1526 1527 return JSValue::encode(result); 1528} 1529 1530void JIT_OPERATION operationTearOffActivation(ExecState* exec, JSCell* activationCell) 1531{ 1532 VM& vm = exec->vm(); 1533 NativeCallFrameTracer tracer(&vm, exec); 1534 1535 ASSERT(exec->codeBlock()->needsActivation()); 1536 jsCast<JSActivation*>(activationCell)->tearOff(vm); 1537} 1538 1539void JIT_OPERATION operationTearOffArguments(ExecState* exec, JSCell* argumentsCell, JSCell* activationCell) 1540{ 1541 ASSERT(exec->codeBlock()->usesArguments()); 1542 if (activationCell) { 1543 jsCast<Arguments*>(argumentsCell)->didTearOffActivation(exec, jsCast<JSActivation*>(activationCell)); 1544 return; 1545 } 1546 jsCast<Arguments*>(argumentsCell)->tearOff(exec); 1547} 1548 1549EncodedJSValue JIT_OPERATION operationDeleteById(ExecState* exec, EncodedJSValue encodedBase, const Identifier* identifier) 1550{ 1551 VM& vm = exec->vm(); 1552 NativeCallFrameTracer tracer(&vm, exec); 1553 1554 JSObject* baseObj = JSValue::decode(encodedBase).toObject(exec); 1555 bool couldDelete = baseObj->methodTable(vm)->deleteProperty(baseObj, exec, *identifier); 1556 JSValue result = jsBoolean(couldDelete); 1557 if (!couldDelete && exec->codeBlock()->isStrictMode()) 1558 vm.throwException(exec, createTypeError(exec, "Unable to delete property.")); 1559 return JSValue::encode(result); 1560} 1561 1562JSCell* JIT_OPERATION operationGetPNames(ExecState* exec, JSObject* obj) 1563{ 1564 VM& vm = exec->vm(); 1565 NativeCallFrameTracer tracer(&vm, exec); 1566 1567 Structure* structure = obj->structure(vm); 1568 JSPropertyNameIterator* jsPropertyNameIterator = structure->enumerationCache(); 1569 if (!jsPropertyNameIterator || jsPropertyNameIterator->cachedPrototypeChain() != structure->prototypeChain(exec)) 1570 jsPropertyNameIterator = JSPropertyNameIterator::create(exec, obj); 1571 return jsPropertyNameIterator; 1572} 1573 1574EncodedJSValue JIT_OPERATION operationInstanceOf(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedProto) 1575{ 1576 VM& vm = exec->vm(); 1577 NativeCallFrameTracer tracer(&vm, exec); 1578 JSValue value = JSValue::decode(encodedValue); 1579 JSValue proto = JSValue::decode(encodedProto); 1580 1581 ASSERT(!value.isObject() || !proto.isObject()); 1582 1583 bool result = JSObject::defaultHasInstance(exec, value, proto); 1584 return JSValue::encode(jsBoolean(result)); 1585} 1586 1587CallFrame* JIT_OPERATION operationSizeFrameForVarargs(ExecState* exec, EncodedJSValue encodedArguments, int32_t firstFreeRegister, int32_t firstVarArgOffset) 1588{ 1589 VM& vm = exec->vm(); 1590 NativeCallFrameTracer tracer(&vm, exec); 1591 JSStack* stack = &exec->interpreter()->stack(); 1592 JSValue arguments = JSValue::decode(encodedArguments); 1593 CallFrame* newCallFrame = sizeFrameForVarargs(exec, stack, arguments, firstFreeRegister, firstVarArgOffset); 1594 return newCallFrame; 1595} 1596 1597CallFrame* JIT_OPERATION operationLoadVarargs(ExecState* exec, CallFrame* newCallFrame, EncodedJSValue encodedThis, EncodedJSValue encodedArguments, int32_t firstVarArgOffset) 1598{ 1599 VM& vm = exec->vm(); 1600 NativeCallFrameTracer tracer(&vm, exec); 1601 JSValue thisValue = JSValue::decode(encodedThis); 1602 JSValue arguments = JSValue::decode(encodedArguments); 1603 loadVarargs(exec, newCallFrame, thisValue, arguments, firstVarArgOffset); 1604 return newCallFrame; 1605} 1606 1607EncodedJSValue JIT_OPERATION operationToObject(ExecState* exec, EncodedJSValue value) 1608{ 1609 VM& vm = exec->vm(); 1610 NativeCallFrameTracer tracer(&vm, exec); 1611 return JSValue::encode(JSValue::decode(value).toObject(exec)); 1612} 1613 1614char* JIT_OPERATION operationSwitchCharWithUnknownKeyType(ExecState* exec, EncodedJSValue encodedKey, size_t tableIndex) 1615{ 1616 VM& vm = exec->vm(); 1617 NativeCallFrameTracer tracer(&vm, exec); 1618 JSValue key = JSValue::decode(encodedKey); 1619 CodeBlock* codeBlock = exec->codeBlock(); 1620 1621 SimpleJumpTable& jumpTable = codeBlock->switchJumpTable(tableIndex); 1622 void* result = jumpTable.ctiDefault.executableAddress(); 1623 1624 if (key.isString()) { 1625 StringImpl* value = asString(key)->value(exec).impl(); 1626 if (value->length() == 1) 1627 result = jumpTable.ctiForValue((*value)[0]).executableAddress(); 1628 } 1629 1630 return reinterpret_cast<char*>(result); 1631} 1632 1633char* JIT_OPERATION operationSwitchImmWithUnknownKeyType(ExecState* exec, EncodedJSValue encodedKey, size_t tableIndex) 1634{ 1635 VM& vm = exec->vm(); 1636 NativeCallFrameTracer tracer(&vm, exec); 1637 JSValue key = JSValue::decode(encodedKey); 1638 CodeBlock* codeBlock = exec->codeBlock(); 1639 1640 SimpleJumpTable& jumpTable = codeBlock->switchJumpTable(tableIndex); 1641 void* result; 1642 if (key.isInt32()) 1643 result = jumpTable.ctiForValue(key.asInt32()).executableAddress(); 1644 else if (key.isDouble() && key.asDouble() == static_cast<int32_t>(key.asDouble())) 1645 result = jumpTable.ctiForValue(static_cast<int32_t>(key.asDouble())).executableAddress(); 1646 else 1647 result = jumpTable.ctiDefault.executableAddress(); 1648 return reinterpret_cast<char*>(result); 1649} 1650 1651char* JIT_OPERATION operationSwitchStringWithUnknownKeyType(ExecState* exec, EncodedJSValue encodedKey, size_t tableIndex) 1652{ 1653 VM& vm = exec->vm(); 1654 NativeCallFrameTracer tracer(&vm, exec); 1655 JSValue key = JSValue::decode(encodedKey); 1656 CodeBlock* codeBlock = exec->codeBlock(); 1657 1658 void* result; 1659 StringJumpTable& jumpTable = codeBlock->stringSwitchJumpTable(tableIndex); 1660 1661 if (key.isString()) { 1662 StringImpl* value = asString(key)->value(exec).impl(); 1663 result = jumpTable.ctiForValue(value).executableAddress(); 1664 } else 1665 result = jumpTable.ctiDefault.executableAddress(); 1666 1667 return reinterpret_cast<char*>(result); 1668} 1669 1670EncodedJSValue JIT_OPERATION operationResolveScope(ExecState* exec, int32_t identifierIndex) 1671{ 1672 VM& vm = exec->vm(); 1673 NativeCallFrameTracer tracer(&vm, exec); 1674 const Identifier& ident = exec->codeBlock()->identifier(identifierIndex); 1675 return JSValue::encode(JSScope::resolve(exec, exec->scope(), ident)); 1676} 1677 1678EncodedJSValue JIT_OPERATION operationGetFromScope(ExecState* exec, Instruction* bytecodePC) 1679{ 1680 VM& vm = exec->vm(); 1681 NativeCallFrameTracer tracer(&vm, exec); 1682 CodeBlock* codeBlock = exec->codeBlock(); 1683 Instruction* pc = bytecodePC; 1684 1685 const Identifier& ident = codeBlock->identifier(pc[3].u.operand); 1686 JSObject* scope = jsCast<JSObject*>(exec->uncheckedR(pc[2].u.operand).jsValue()); 1687 ResolveModeAndType modeAndType(pc[4].u.operand); 1688 1689 PropertySlot slot(scope); 1690 if (!scope->getPropertySlot(exec, ident, slot)) { 1691 if (modeAndType.mode() == ThrowIfNotFound) 1692 vm.throwException(exec, createUndefinedVariableError(exec, ident)); 1693 return JSValue::encode(jsUndefined()); 1694 } 1695 1696 // Covers implicit globals. Since they don't exist until they first execute, we didn't know how to cache them at compile time. 1697 if (slot.isCacheableValue() && slot.slotBase() == scope && scope->structure(vm)->propertyAccessesAreCacheable()) { 1698 if (modeAndType.type() == GlobalProperty || modeAndType.type() == GlobalPropertyWithVarInjectionChecks) { 1699 ConcurrentJITLocker locker(codeBlock->m_lock); 1700 pc[5].u.structure.set(exec->vm(), codeBlock->ownerExecutable(), scope->structure(vm)); 1701 pc[6].u.operand = slot.cachedOffset(); 1702 } 1703 } 1704 1705 return JSValue::encode(slot.getValue(exec, ident)); 1706} 1707 1708void JIT_OPERATION operationPutToScope(ExecState* exec, Instruction* bytecodePC) 1709{ 1710 VM& vm = exec->vm(); 1711 NativeCallFrameTracer tracer(&vm, exec); 1712 Instruction* pc = bytecodePC; 1713 1714 CodeBlock* codeBlock = exec->codeBlock(); 1715 const Identifier& ident = codeBlock->identifier(pc[2].u.operand); 1716 JSObject* scope = jsCast<JSObject*>(exec->uncheckedR(pc[1].u.operand).jsValue()); 1717 JSValue value = exec->r(pc[3].u.operand).jsValue(); 1718 ResolveModeAndType modeAndType = ResolveModeAndType(pc[4].u.operand); 1719 1720 if (modeAndType.mode() == ThrowIfNotFound && !scope->hasProperty(exec, ident)) { 1721 exec->vm().throwException(exec, createUndefinedVariableError(exec, ident)); 1722 return; 1723 } 1724 1725 PutPropertySlot slot(scope, codeBlock->isStrictMode()); 1726 scope->methodTable()->put(scope, exec, ident, value, slot); 1727 1728 if (exec->vm().exception()) 1729 return; 1730 1731 // Covers implicit globals. Since they don't exist until they first execute, we didn't know how to cache them at compile time. 1732 if (modeAndType.type() == GlobalProperty || modeAndType.type() == GlobalPropertyWithVarInjectionChecks) { 1733 if (slot.isCacheablePut() && slot.base() == scope && scope->structure()->propertyAccessesAreCacheable()) { 1734 ConcurrentJITLocker locker(codeBlock->m_lock); 1735 pc[5].u.structure.set(exec->vm(), codeBlock->ownerExecutable(), scope->structure()); 1736 pc[6].u.operand = slot.cachedOffset(); 1737 } 1738 } 1739} 1740 1741void JIT_OPERATION operationThrow(ExecState* exec, EncodedJSValue encodedExceptionValue) 1742{ 1743 VM* vm = &exec->vm(); 1744 NativeCallFrameTracer tracer(vm, exec); 1745 1746 JSValue exceptionValue = JSValue::decode(encodedExceptionValue); 1747 vm->throwException(exec, exceptionValue); 1748 1749 // Results stored out-of-band in vm.targetMachinePCForThrow & vm.callFrameForThrow 1750 genericUnwind(vm, exec, exceptionValue); 1751} 1752 1753void JIT_OPERATION operationFlushWriteBarrierBuffer(ExecState* exec, JSCell* cell) 1754{ 1755 VM* vm = &exec->vm(); 1756 NativeCallFrameTracer tracer(vm, exec); 1757 vm->heap.flushWriteBarrierBuffer(cell); 1758} 1759 1760void JIT_OPERATION operationOSRWriteBarrier(ExecState* exec, JSCell* cell) 1761{ 1762 VM* vm = &exec->vm(); 1763 NativeCallFrameTracer tracer(vm, exec); 1764 vm->heap.writeBarrier(cell); 1765} 1766 1767// NB: We don't include the value as part of the barrier because the write barrier elision 1768// phase in the DFG only tracks whether the object being stored to has been barriered. It 1769// would be much more complicated to try to model the value being stored as well. 1770void JIT_OPERATION operationUnconditionalWriteBarrier(ExecState* exec, JSCell* cell) 1771{ 1772 VM* vm = &exec->vm(); 1773 NativeCallFrameTracer tracer(vm, exec); 1774 vm->heap.writeBarrier(cell); 1775} 1776 1777void JIT_OPERATION operationInitGlobalConst(ExecState* exec, Instruction* pc) 1778{ 1779 VM* vm = &exec->vm(); 1780 NativeCallFrameTracer tracer(vm, exec); 1781 1782 JSValue value = exec->r(pc[2].u.operand).jsValue(); 1783 pc[1].u.registerPointer->set(*vm, exec->codeBlock()->globalObject(), value); 1784} 1785 1786void JIT_OPERATION lookupExceptionHandler(VM* vm, ExecState* exec) 1787{ 1788 NativeCallFrameTracer tracer(vm, exec, NativeCallFrameTracer::VMEntrySentinelOK); 1789 1790 JSValue exceptionValue = vm->exception(); 1791 ASSERT(exceptionValue); 1792 1793 genericUnwind(vm, exec, exceptionValue); 1794 ASSERT(vm->targetMachinePCForThrow); 1795} 1796 1797void JIT_OPERATION operationVMHandleException(ExecState* exec) 1798{ 1799 VM* vm = &exec->vm(); 1800 NativeCallFrameTracer tracer(vm, exec); 1801 1802 ASSERT(!exec->isVMEntrySentinel()); 1803 genericUnwind(vm, exec, vm->exception()); 1804} 1805 1806// This function "should" just take the ExecState*, but doing so would make it more difficult 1807// to call from exception check sites. So, unlike all of our other functions, we allow 1808// ourselves to play some gnarly ABI tricks just to simplify the calling convention. This is 1809// particularly safe here since this is never called on the critical path - it's only for 1810// testing. 1811void JIT_OPERATION operationExceptionFuzz() 1812{ 1813 ASSERT(Options::enableExceptionFuzz()); 1814 1815 // This probably "just works" for GCC also, but I haven't tried. 1816#if COMPILER(CLANG) 1817 ExecState* exec = static_cast<ExecState*>(__builtin_frame_address(1)); 1818 DeferGCForAWhile deferGC(exec->vm().heap); 1819 1820 s_numberOfExceptionFuzzChecks++; 1821 1822 unsigned fireTarget = Options::fireExceptionFuzzAt(); 1823 if (fireTarget == s_numberOfExceptionFuzzChecks) { 1824 printf("JSC EXCEPTION FUZZ: Throwing fuzz exception with call frame %p and return address %p.\n", exec, __builtin_return_address(0)); 1825 exec->vm().throwException( 1826 exec, createError(exec->lexicalGlobalObject(), ASCIILiteral("Exception Fuzz"))); 1827 } 1828#endif // COMPILER(CLANG) 1829} 1830 1831} // extern "C" 1832 1833// Note: getHostCallReturnValueWithExecState() needs to be placed before the 1834// definition of getHostCallReturnValue() below because the Windows build 1835// requires it. 1836extern "C" EncodedJSValue HOST_CALL_RETURN_VALUE_OPTION getHostCallReturnValueWithExecState(ExecState* exec) 1837{ 1838 if (!exec) 1839 return JSValue::encode(JSValue()); 1840 return JSValue::encode(exec->vm().hostCallReturnValue); 1841} 1842 1843#if COMPILER(GCC) && CPU(X86_64) 1844asm ( 1845".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" 1846HIDE_SYMBOL(getHostCallReturnValue) "\n" 1847SYMBOL_STRING(getHostCallReturnValue) ":" "\n" 1848 "mov %rbp, %rdi\n" 1849 "jmp " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" 1850); 1851 1852#elif COMPILER(GCC) && CPU(X86) 1853asm ( 1854".text" "\n" \ 1855".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" 1856HIDE_SYMBOL(getHostCallReturnValue) "\n" 1857SYMBOL_STRING(getHostCallReturnValue) ":" "\n" 1858 "push %ebp\n" 1859 "leal -4(%esp), %esp\n" 1860 "push %ebp\n" 1861 "call " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" 1862 "leal 8(%esp), %esp\n" 1863 "pop %ebp\n" 1864 "ret\n" 1865); 1866 1867#elif COMPILER(GCC) && CPU(ARM_THUMB2) 1868asm ( 1869".text" "\n" 1870".align 2" "\n" 1871".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" 1872HIDE_SYMBOL(getHostCallReturnValue) "\n" 1873".thumb" "\n" 1874".thumb_func " THUMB_FUNC_PARAM(getHostCallReturnValue) "\n" 1875SYMBOL_STRING(getHostCallReturnValue) ":" "\n" 1876 "mov r0, r7" "\n" 1877 "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" 1878); 1879 1880#elif COMPILER(GCC) && CPU(ARM_TRADITIONAL) 1881asm ( 1882".text" "\n" 1883".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" 1884HIDE_SYMBOL(getHostCallReturnValue) "\n" 1885INLINE_ARM_FUNCTION(getHostCallReturnValue) 1886SYMBOL_STRING(getHostCallReturnValue) ":" "\n" 1887 "mov r0, r11" "\n" 1888 "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" 1889); 1890 1891#elif CPU(ARM64) 1892asm ( 1893".text" "\n" 1894".align 2" "\n" 1895".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" 1896HIDE_SYMBOL(getHostCallReturnValue) "\n" 1897SYMBOL_STRING(getHostCallReturnValue) ":" "\n" 1898 "mov x0, x29" "\n" 1899 "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" 1900); 1901 1902#elif COMPILER(GCC) && CPU(MIPS) 1903 1904#if WTF_MIPS_PIC 1905#define LOAD_FUNCTION_TO_T9(function) \ 1906 ".set noreorder" "\n" \ 1907 ".cpload $25" "\n" \ 1908 ".set reorder" "\n" \ 1909 "la $t9, " LOCAL_REFERENCE(function) "\n" 1910#else 1911#define LOAD_FUNCTION_TO_T9(function) "" "\n" 1912#endif 1913 1914asm ( 1915".text" "\n" 1916".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" 1917HIDE_SYMBOL(getHostCallReturnValue) "\n" 1918SYMBOL_STRING(getHostCallReturnValue) ":" "\n" 1919 LOAD_FUNCTION_TO_T9(getHostCallReturnValueWithExecState) 1920 "move $a0, $fp" "\n" 1921 "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" 1922); 1923 1924#elif COMPILER(GCC) && CPU(SH4) 1925 1926#define SH4_SCRATCH_REGISTER "r11" 1927 1928asm ( 1929".text" "\n" 1930".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" 1931HIDE_SYMBOL(getHostCallReturnValue) "\n" 1932SYMBOL_STRING(getHostCallReturnValue) ":" "\n" 1933 "mov r14, r4" "\n" 1934 "mov.l 2f, " SH4_SCRATCH_REGISTER "\n" 1935 "braf " SH4_SCRATCH_REGISTER "\n" 1936 "nop" "\n" 1937 "1: .balign 4" "\n" 1938 "2: .long " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "-1b\n" 1939); 1940 1941#elif COMPILER(MSVC) && CPU(X86) 1942extern "C" { 1943 __declspec(naked) EncodedJSValue HOST_CALL_RETURN_VALUE_OPTION getHostCallReturnValue() 1944 { 1945 __asm mov [esp + 4], ebp; 1946 __asm jmp getHostCallReturnValueWithExecState 1947 } 1948} 1949#endif 1950 1951} // namespace JSC 1952 1953#endif // ENABLE(JIT) 1954