1/* 2 * Copyright (C) 2011, 2012, 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 "DFGSpeculativeJIT.h" 28 29#if ENABLE(DFG_JIT) 30 31#include "Arguments.h" 32#include "DFGAbstractInterpreterInlines.h" 33#include "DFGArrayifySlowPathGenerator.h" 34#include "DFGBinarySwitch.h" 35#include "DFGCallArrayAllocatorSlowPathGenerator.h" 36#include "DFGSaneStringGetByValSlowPathGenerator.h" 37#include "DFGSlowPathGenerator.h" 38#include "LinkBuffer.h" 39#include "JSCInlines.h" 40#include "ScratchRegisterAllocator.h" 41#include "WriteBarrierBuffer.h" 42#include <wtf/MathExtras.h> 43 44namespace JSC { namespace DFG { 45 46SpeculativeJIT::SpeculativeJIT(JITCompiler& jit) 47 : m_compileOkay(true) 48 , m_jit(jit) 49 , m_currentNode(0) 50 , m_lastGeneratedNode(LastNodeType) 51 , m_indexInBlock(0) 52 , m_generationInfo(m_jit.graph().frameRegisterCount()) 53 , m_state(m_jit.graph()) 54 , m_interpreter(m_jit.graph(), m_state) 55 , m_stream(&jit.jitCode()->variableEventStream) 56 , m_minifiedGraph(&jit.jitCode()->minifiedDFG) 57 , m_isCheckingArgumentTypes(false) 58{ 59} 60 61SpeculativeJIT::~SpeculativeJIT() 62{ 63} 64 65void SpeculativeJIT::emitAllocateJSArray(GPRReg resultGPR, Structure* structure, GPRReg storageGPR, unsigned numElements) 66{ 67 ASSERT(hasUndecided(structure->indexingType()) || hasInt32(structure->indexingType()) || hasDouble(structure->indexingType()) || hasContiguous(structure->indexingType())); 68 69 GPRTemporary scratch(this); 70 GPRTemporary scratch2(this); 71 GPRReg scratchGPR = scratch.gpr(); 72 GPRReg scratch2GPR = scratch2.gpr(); 73 74 unsigned vectorLength = std::max(BASE_VECTOR_LEN, numElements); 75 76 JITCompiler::JumpList slowCases; 77 78 slowCases.append( 79 emitAllocateBasicStorage(TrustedImm32(vectorLength * sizeof(JSValue) + sizeof(IndexingHeader)), storageGPR)); 80 m_jit.subPtr(TrustedImm32(vectorLength * sizeof(JSValue)), storageGPR); 81 emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(structure), storageGPR, scratchGPR, scratch2GPR, slowCases); 82 83 m_jit.store32(TrustedImm32(numElements), MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength())); 84 m_jit.store32(TrustedImm32(vectorLength), MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength())); 85 86 if (hasDouble(structure->indexingType()) && numElements < vectorLength) { 87#if USE(JSVALUE64) 88 m_jit.move(TrustedImm64(bitwise_cast<int64_t>(PNaN)), scratchGPR); 89 for (unsigned i = numElements; i < vectorLength; ++i) 90 m_jit.store64(scratchGPR, MacroAssembler::Address(storageGPR, sizeof(double) * i)); 91#else 92 EncodedValueDescriptor value; 93 value.asInt64 = JSValue::encode(JSValue(JSValue::EncodeAsDouble, PNaN)); 94 for (unsigned i = numElements; i < vectorLength; ++i) { 95 m_jit.store32(TrustedImm32(value.asBits.tag), MacroAssembler::Address(storageGPR, sizeof(double) * i + OBJECT_OFFSETOF(JSValue, u.asBits.tag))); 96 m_jit.store32(TrustedImm32(value.asBits.payload), MacroAssembler::Address(storageGPR, sizeof(double) * i + OBJECT_OFFSETOF(JSValue, u.asBits.payload))); 97 } 98#endif 99 } 100 101 // I want a slow path that also loads out the storage pointer, and that's 102 // what this custom CallArrayAllocatorSlowPathGenerator gives me. It's a lot 103 // of work for a very small piece of functionality. :-/ 104 addSlowPathGenerator(adoptPtr( 105 new CallArrayAllocatorSlowPathGenerator( 106 slowCases, this, operationNewArrayWithSize, resultGPR, storageGPR, 107 structure, numElements))); 108} 109 110void SpeculativeJIT::emitAllocateArguments(GPRReg resultGPR, GPRReg scratchGPR1, GPRReg scratchGPR2, MacroAssembler::JumpList& slowPath) 111{ 112 Structure* structure = m_jit.graph().globalObjectFor(m_currentNode->origin.semantic)->argumentsStructure(); 113 emitAllocateDestructibleObject<Arguments>(resultGPR, structure, scratchGPR1, scratchGPR2, slowPath); 114 115 m_jit.storePtr(TrustedImmPtr(0), MacroAssembler::Address(resultGPR, Arguments::offsetOfActivation())); 116 117 m_jit.load32(JITCompiler::payloadFor(JSStack::ArgumentCount), scratchGPR1); 118 m_jit.sub32(TrustedImm32(1), scratchGPR1); 119 m_jit.store32(scratchGPR1, MacroAssembler::Address(resultGPR, Arguments::offsetOfNumArguments())); 120 121 m_jit.store32(TrustedImm32(0), MacroAssembler::Address(resultGPR, Arguments::offsetOfOverrodeLength())); 122 if (m_jit.isStrictModeFor(m_currentNode->origin.semantic)) 123 m_jit.store8(TrustedImm32(1), MacroAssembler::Address(resultGPR, Arguments::offsetOfIsStrictMode())); 124 125 m_jit.storePtr(GPRInfo::callFrameRegister, MacroAssembler::Address(resultGPR, Arguments::offsetOfRegisters())); 126 m_jit.storePtr(TrustedImmPtr(0), MacroAssembler::Address(resultGPR, Arguments::offsetOfRegisterArray())); 127 m_jit.storePtr(TrustedImmPtr(0), MacroAssembler::Address(resultGPR, Arguments::offsetOfSlowArgumentData())); 128 129 m_jit.loadPtr(JITCompiler::addressFor(JSStack::Callee), scratchGPR1); 130 m_jit.storePtr(scratchGPR1, MacroAssembler::Address(resultGPR, Arguments::offsetOfCallee())); 131} 132 133void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, MacroAssembler::Jump jumpToFail) 134{ 135 if (!m_compileOkay) 136 return; 137 ASSERT(m_isCheckingArgumentTypes || m_canExit); 138 m_jit.appendExitInfo(jumpToFail); 139 m_jit.jitCode()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(node), this, m_stream->size())); 140} 141 142void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, const MacroAssembler::JumpList& jumpsToFail) 143{ 144 if (!m_compileOkay) 145 return; 146 ASSERT(m_isCheckingArgumentTypes || m_canExit); 147 m_jit.appendExitInfo(jumpsToFail); 148 m_jit.jitCode()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(node), this, m_stream->size())); 149} 150 151OSRExitJumpPlaceholder SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node) 152{ 153 if (!m_compileOkay) 154 return OSRExitJumpPlaceholder(); 155 ASSERT(m_isCheckingArgumentTypes || m_canExit); 156 unsigned index = m_jit.jitCode()->osrExit.size(); 157 m_jit.appendExitInfo(); 158 m_jit.jitCode()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(node), this, m_stream->size())); 159 return OSRExitJumpPlaceholder(index); 160} 161 162OSRExitJumpPlaceholder SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse) 163{ 164 ASSERT(m_isCheckingArgumentTypes || m_canExit); 165 return speculationCheck(kind, jsValueSource, nodeUse.node()); 166} 167 168void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, MacroAssembler::Jump jumpToFail) 169{ 170 ASSERT(m_isCheckingArgumentTypes || m_canExit); 171 speculationCheck(kind, jsValueSource, nodeUse.node(), jumpToFail); 172} 173 174void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, const MacroAssembler::JumpList& jumpsToFail) 175{ 176 ASSERT(m_isCheckingArgumentTypes || m_canExit); 177 speculationCheck(kind, jsValueSource, nodeUse.node(), jumpsToFail); 178} 179 180void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery) 181{ 182 if (!m_compileOkay) 183 return; 184 ASSERT(m_isCheckingArgumentTypes || m_canExit); 185 unsigned recoveryIndex = m_jit.jitCode()->appendSpeculationRecovery(recovery); 186 m_jit.appendExitInfo(jumpToFail); 187 m_jit.jitCode()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(node), this, m_stream->size(), recoveryIndex)); 188} 189 190void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery) 191{ 192 ASSERT(m_isCheckingArgumentTypes || m_canExit); 193 speculationCheck(kind, jsValueSource, nodeUse.node(), jumpToFail, recovery); 194} 195 196void SpeculativeJIT::emitInvalidationPoint(Node* node) 197{ 198 if (!m_compileOkay) 199 return; 200 ASSERT(m_canExit); 201 OSRExitCompilationInfo& info = m_jit.appendExitInfo(JITCompiler::JumpList()); 202 m_jit.jitCode()->appendOSRExit(OSRExit( 203 UncountableInvalidation, JSValueSource(), 204 m_jit.graph().methodOfGettingAValueProfileFor(node), 205 this, m_stream->size())); 206 info.m_replacementSource = m_jit.watchpointLabel(); 207 ASSERT(info.m_replacementSource.isSet()); 208 noResult(node); 209} 210 211void SpeculativeJIT::terminateSpeculativeExecution(ExitKind kind, JSValueRegs jsValueRegs, Node* node) 212{ 213 ASSERT(m_isCheckingArgumentTypes || m_canExit); 214 if (!m_compileOkay) 215 return; 216 speculationCheck(kind, jsValueRegs, node, m_jit.jump()); 217 m_compileOkay = false; 218} 219 220void SpeculativeJIT::terminateSpeculativeExecution(ExitKind kind, JSValueRegs jsValueRegs, Edge nodeUse) 221{ 222 ASSERT(m_isCheckingArgumentTypes || m_canExit); 223 terminateSpeculativeExecution(kind, jsValueRegs, nodeUse.node()); 224} 225 226void SpeculativeJIT::typeCheck(JSValueSource source, Edge edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail) 227{ 228 ASSERT(needsTypeCheck(edge, typesPassedThrough)); 229 m_interpreter.filter(edge, typesPassedThrough); 230 speculationCheck(BadType, source, edge.node(), jumpToFail); 231} 232 233RegisterSet SpeculativeJIT::usedRegisters() 234{ 235 RegisterSet result; 236 237 for (unsigned i = GPRInfo::numberOfRegisters; i--;) { 238 GPRReg gpr = GPRInfo::toRegister(i); 239 if (m_gprs.isInUse(gpr)) 240 result.set(gpr); 241 } 242 for (unsigned i = FPRInfo::numberOfRegisters; i--;) { 243 FPRReg fpr = FPRInfo::toRegister(i); 244 if (m_fprs.isInUse(fpr)) 245 result.set(fpr); 246 } 247 248 result.merge(RegisterSet::specialRegisters()); 249 250 return result; 251} 252 253void SpeculativeJIT::addSlowPathGenerator(PassOwnPtr<SlowPathGenerator> slowPathGenerator) 254{ 255 m_slowPathGenerators.append(slowPathGenerator); 256} 257 258void SpeculativeJIT::runSlowPathGenerators() 259{ 260 for (unsigned i = 0; i < m_slowPathGenerators.size(); ++i) 261 m_slowPathGenerators[i]->generate(this); 262} 263 264// On Windows we need to wrap fmod; on other platforms we can call it directly. 265// On ARMv7 we assert that all function pointers have to low bit set (point to thumb code). 266#if CALLING_CONVENTION_IS_STDCALL || CPU(ARM_THUMB2) 267static double JIT_OPERATION fmodAsDFGOperation(double x, double y) 268{ 269 return fmod(x, y); 270} 271#else 272#define fmodAsDFGOperation fmod 273#endif 274 275void SpeculativeJIT::clearGenerationInfo() 276{ 277 for (unsigned i = 0; i < m_generationInfo.size(); ++i) 278 m_generationInfo[i] = GenerationInfo(); 279 m_gprs = RegisterBank<GPRInfo>(); 280 m_fprs = RegisterBank<FPRInfo>(); 281} 282 283SilentRegisterSavePlan SpeculativeJIT::silentSavePlanForGPR(VirtualRegister spillMe, GPRReg source) 284{ 285 GenerationInfo& info = generationInfoFromVirtualRegister(spillMe); 286 Node* node = info.node(); 287 DataFormat registerFormat = info.registerFormat(); 288 ASSERT(registerFormat != DataFormatNone); 289 ASSERT(registerFormat != DataFormatDouble); 290 291 SilentSpillAction spillAction; 292 SilentFillAction fillAction; 293 294 if (!info.needsSpill()) 295 spillAction = DoNothingForSpill; 296 else { 297#if USE(JSVALUE64) 298 ASSERT(info.gpr() == source); 299 if (registerFormat == DataFormatInt32) 300 spillAction = Store32Payload; 301 else if (registerFormat == DataFormatCell || registerFormat == DataFormatStorage) 302 spillAction = StorePtr; 303 else if (registerFormat == DataFormatInt52 || registerFormat == DataFormatStrictInt52) 304 spillAction = Store64; 305 else { 306 ASSERT(registerFormat & DataFormatJS); 307 spillAction = Store64; 308 } 309#elif USE(JSVALUE32_64) 310 if (registerFormat & DataFormatJS) { 311 ASSERT(info.tagGPR() == source || info.payloadGPR() == source); 312 spillAction = source == info.tagGPR() ? Store32Tag : Store32Payload; 313 } else { 314 ASSERT(info.gpr() == source); 315 spillAction = Store32Payload; 316 } 317#endif 318 } 319 320 if (registerFormat == DataFormatInt32) { 321 ASSERT(info.gpr() == source); 322 ASSERT(isJSInt32(info.registerFormat())); 323 if (node->hasConstant()) { 324 ASSERT(isInt32Constant(node)); 325 fillAction = SetInt32Constant; 326 } else 327 fillAction = Load32Payload; 328 } else if (registerFormat == DataFormatBoolean) { 329#if USE(JSVALUE64) 330 RELEASE_ASSERT_NOT_REACHED(); 331 fillAction = DoNothingForFill; 332#elif USE(JSVALUE32_64) 333 ASSERT(info.gpr() == source); 334 if (node->hasConstant()) { 335 ASSERT(isBooleanConstant(node)); 336 fillAction = SetBooleanConstant; 337 } else 338 fillAction = Load32Payload; 339#endif 340 } else if (registerFormat == DataFormatCell) { 341 ASSERT(info.gpr() == source); 342 if (node->hasConstant()) { 343 JSValue value = valueOfJSConstant(node); 344 ASSERT_UNUSED(value, value.isCell()); 345 fillAction = SetCellConstant; 346 } else { 347#if USE(JSVALUE64) 348 fillAction = LoadPtr; 349#else 350 fillAction = Load32Payload; 351#endif 352 } 353 } else if (registerFormat == DataFormatStorage) { 354 ASSERT(info.gpr() == source); 355 fillAction = LoadPtr; 356 } else if (registerFormat == DataFormatInt52) { 357 if (node->hasConstant()) 358 fillAction = SetInt52Constant; 359 else if (info.spillFormat() == DataFormatInt52) 360 fillAction = Load64; 361 else if (info.spillFormat() == DataFormatStrictInt52) 362 fillAction = Load64ShiftInt52Left; 363 else if (info.spillFormat() == DataFormatNone) 364 fillAction = Load64; 365 else { 366 RELEASE_ASSERT_NOT_REACHED(); 367 fillAction = Load64; // Make GCC happy. 368 } 369 } else if (registerFormat == DataFormatStrictInt52) { 370 if (node->hasConstant()) 371 fillAction = SetStrictInt52Constant; 372 else if (info.spillFormat() == DataFormatInt52) 373 fillAction = Load64ShiftInt52Right; 374 else if (info.spillFormat() == DataFormatStrictInt52) 375 fillAction = Load64; 376 else if (info.spillFormat() == DataFormatNone) 377 fillAction = Load64; 378 else { 379 RELEASE_ASSERT_NOT_REACHED(); 380 fillAction = Load64; // Make GCC happy. 381 } 382 } else { 383 ASSERT(registerFormat & DataFormatJS); 384#if USE(JSVALUE64) 385 ASSERT(info.gpr() == source); 386 if (node->hasConstant()) { 387 if (valueOfJSConstant(node).isCell()) 388 fillAction = SetTrustedJSConstant; 389 fillAction = SetJSConstant; 390 } else if (info.spillFormat() == DataFormatInt32) { 391 ASSERT(registerFormat == DataFormatJSInt32); 392 fillAction = Load32PayloadBoxInt; 393 } else 394 fillAction = Load64; 395#else 396 ASSERT(info.tagGPR() == source || info.payloadGPR() == source); 397 if (node->hasConstant()) 398 fillAction = info.tagGPR() == source ? SetJSConstantTag : SetJSConstantPayload; 399 else if (info.payloadGPR() == source) 400 fillAction = Load32Payload; 401 else { // Fill the Tag 402 switch (info.spillFormat()) { 403 case DataFormatInt32: 404 ASSERT(registerFormat == DataFormatJSInt32); 405 fillAction = SetInt32Tag; 406 break; 407 case DataFormatCell: 408 ASSERT(registerFormat == DataFormatJSCell); 409 fillAction = SetCellTag; 410 break; 411 case DataFormatBoolean: 412 ASSERT(registerFormat == DataFormatJSBoolean); 413 fillAction = SetBooleanTag; 414 break; 415 default: 416 fillAction = Load32Tag; 417 break; 418 } 419 } 420#endif 421 } 422 423 return SilentRegisterSavePlan(spillAction, fillAction, node, source); 424} 425 426SilentRegisterSavePlan SpeculativeJIT::silentSavePlanForFPR(VirtualRegister spillMe, FPRReg source) 427{ 428 GenerationInfo& info = generationInfoFromVirtualRegister(spillMe); 429 Node* node = info.node(); 430 ASSERT(info.registerFormat() == DataFormatDouble); 431 432 SilentSpillAction spillAction; 433 SilentFillAction fillAction; 434 435 if (!info.needsSpill()) 436 spillAction = DoNothingForSpill; 437 else { 438 ASSERT(!node->hasConstant()); 439 ASSERT(info.spillFormat() == DataFormatNone); 440 ASSERT(info.fpr() == source); 441 spillAction = StoreDouble; 442 } 443 444#if USE(JSVALUE64) 445 if (node->hasConstant()) { 446 ASSERT(isNumberConstant(node)); 447 fillAction = SetDoubleConstant; 448 } else { 449 ASSERT(info.spillFormat() == DataFormatNone || info.spillFormat() == DataFormatDouble); 450 fillAction = LoadDouble; 451 } 452#elif USE(JSVALUE32_64) 453 ASSERT(info.registerFormat() == DataFormatDouble); 454 if (node->hasConstant()) { 455 ASSERT(isNumberConstant(node)); 456 fillAction = SetDoubleConstant; 457 } else 458 fillAction = LoadDouble; 459#endif 460 461 return SilentRegisterSavePlan(spillAction, fillAction, node, source); 462} 463 464void SpeculativeJIT::silentSpill(const SilentRegisterSavePlan& plan) 465{ 466 switch (plan.spillAction()) { 467 case DoNothingForSpill: 468 break; 469 case Store32Tag: 470 m_jit.store32(plan.gpr(), JITCompiler::tagFor(plan.node()->virtualRegister())); 471 break; 472 case Store32Payload: 473 m_jit.store32(plan.gpr(), JITCompiler::payloadFor(plan.node()->virtualRegister())); 474 break; 475 case StorePtr: 476 m_jit.storePtr(plan.gpr(), JITCompiler::addressFor(plan.node()->virtualRegister())); 477 break; 478#if USE(JSVALUE64) 479 case Store64: 480 m_jit.store64(plan.gpr(), JITCompiler::addressFor(plan.node()->virtualRegister())); 481 break; 482#endif 483 case StoreDouble: 484 m_jit.storeDouble(plan.fpr(), JITCompiler::addressFor(plan.node()->virtualRegister())); 485 break; 486 default: 487 RELEASE_ASSERT_NOT_REACHED(); 488 } 489} 490 491void SpeculativeJIT::silentFill(const SilentRegisterSavePlan& plan, GPRReg canTrample) 492{ 493#if USE(JSVALUE32_64) 494 UNUSED_PARAM(canTrample); 495#endif 496 switch (plan.fillAction()) { 497 case DoNothingForFill: 498 break; 499 case SetInt32Constant: 500 m_jit.move(Imm32(valueOfInt32Constant(plan.node())), plan.gpr()); 501 break; 502#if USE(JSVALUE64) 503 case SetInt52Constant: 504 m_jit.move(Imm64(valueOfJSConstant(plan.node()).asMachineInt() << JSValue::int52ShiftAmount), plan.gpr()); 505 break; 506 case SetStrictInt52Constant: 507 m_jit.move(Imm64(valueOfJSConstant(plan.node()).asMachineInt()), plan.gpr()); 508 break; 509#endif // USE(JSVALUE64) 510 case SetBooleanConstant: 511 m_jit.move(TrustedImm32(valueOfBooleanConstant(plan.node())), plan.gpr()); 512 break; 513 case SetCellConstant: 514 m_jit.move(TrustedImmPtr(valueOfJSConstant(plan.node()).asCell()), plan.gpr()); 515 break; 516#if USE(JSVALUE64) 517 case SetTrustedJSConstant: 518 m_jit.move(valueOfJSConstantAsImm64(plan.node()).asTrustedImm64(), plan.gpr()); 519 break; 520 case SetJSConstant: 521 m_jit.move(valueOfJSConstantAsImm64(plan.node()), plan.gpr()); 522 break; 523 case SetDoubleConstant: 524 m_jit.move(Imm64(reinterpretDoubleToInt64(valueOfNumberConstant(plan.node()))), canTrample); 525 m_jit.move64ToDouble(canTrample, plan.fpr()); 526 break; 527 case Load32PayloadBoxInt: 528 m_jit.load32(JITCompiler::payloadFor(plan.node()->virtualRegister()), plan.gpr()); 529 m_jit.or64(GPRInfo::tagTypeNumberRegister, plan.gpr()); 530 break; 531 case Load32PayloadConvertToInt52: 532 m_jit.load32(JITCompiler::payloadFor(plan.node()->virtualRegister()), plan.gpr()); 533 m_jit.signExtend32ToPtr(plan.gpr(), plan.gpr()); 534 m_jit.lshift64(TrustedImm32(JSValue::int52ShiftAmount), plan.gpr()); 535 break; 536 case Load32PayloadSignExtend: 537 m_jit.load32(JITCompiler::payloadFor(plan.node()->virtualRegister()), plan.gpr()); 538 m_jit.signExtend32ToPtr(plan.gpr(), plan.gpr()); 539 break; 540#else 541 case SetJSConstantTag: 542 m_jit.move(Imm32(valueOfJSConstant(plan.node()).tag()), plan.gpr()); 543 break; 544 case SetJSConstantPayload: 545 m_jit.move(Imm32(valueOfJSConstant(plan.node()).payload()), plan.gpr()); 546 break; 547 case SetInt32Tag: 548 m_jit.move(TrustedImm32(JSValue::Int32Tag), plan.gpr()); 549 break; 550 case SetCellTag: 551 m_jit.move(TrustedImm32(JSValue::CellTag), plan.gpr()); 552 break; 553 case SetBooleanTag: 554 m_jit.move(TrustedImm32(JSValue::BooleanTag), plan.gpr()); 555 break; 556 case SetDoubleConstant: 557 m_jit.loadDouble(TrustedImmPtr(addressOfDoubleConstant(plan.node())), plan.fpr()); 558 break; 559#endif 560 case Load32Tag: 561 m_jit.load32(JITCompiler::tagFor(plan.node()->virtualRegister()), plan.gpr()); 562 break; 563 case Load32Payload: 564 m_jit.load32(JITCompiler::payloadFor(plan.node()->virtualRegister()), plan.gpr()); 565 break; 566 case LoadPtr: 567 m_jit.loadPtr(JITCompiler::addressFor(plan.node()->virtualRegister()), plan.gpr()); 568 break; 569#if USE(JSVALUE64) 570 case Load64: 571 m_jit.load64(JITCompiler::addressFor(plan.node()->virtualRegister()), plan.gpr()); 572 break; 573 case Load64ShiftInt52Right: 574 m_jit.load64(JITCompiler::addressFor(plan.node()->virtualRegister()), plan.gpr()); 575 m_jit.rshift64(TrustedImm32(JSValue::int52ShiftAmount), plan.gpr()); 576 break; 577 case Load64ShiftInt52Left: 578 m_jit.load64(JITCompiler::addressFor(plan.node()->virtualRegister()), plan.gpr()); 579 m_jit.lshift64(TrustedImm32(JSValue::int52ShiftAmount), plan.gpr()); 580 break; 581#endif 582 case LoadDouble: 583 m_jit.loadDouble(JITCompiler::addressFor(plan.node()->virtualRegister()), plan.fpr()); 584 break; 585 default: 586 RELEASE_ASSERT_NOT_REACHED(); 587 } 588} 589 590JITCompiler::Jump SpeculativeJIT::jumpSlowForUnwantedArrayMode(GPRReg tempGPR, ArrayMode arrayMode, IndexingType shape) 591{ 592 switch (arrayMode.arrayClass()) { 593 case Array::OriginalArray: { 594 CRASH(); 595 JITCompiler::Jump result; // I already know that VC++ takes unkindly to the expression "return Jump()", so I'm doing it this way in anticipation of someone eventually using VC++ to compile the DFG. 596 return result; 597 } 598 599 case Array::Array: 600 m_jit.and32(TrustedImm32(IsArray | IndexingShapeMask), tempGPR); 601 return m_jit.branch32( 602 MacroAssembler::NotEqual, tempGPR, TrustedImm32(IsArray | shape)); 603 604 case Array::NonArray: 605 case Array::OriginalNonArray: 606 m_jit.and32(TrustedImm32(IsArray | IndexingShapeMask), tempGPR); 607 return m_jit.branch32( 608 MacroAssembler::NotEqual, tempGPR, TrustedImm32(shape)); 609 610 case Array::PossiblyArray: 611 m_jit.and32(TrustedImm32(IndexingShapeMask), tempGPR); 612 return m_jit.branch32(MacroAssembler::NotEqual, tempGPR, TrustedImm32(shape)); 613 } 614 615 RELEASE_ASSERT_NOT_REACHED(); 616 return JITCompiler::Jump(); 617} 618 619JITCompiler::JumpList SpeculativeJIT::jumpSlowForUnwantedArrayMode(GPRReg tempGPR, ArrayMode arrayMode) 620{ 621 JITCompiler::JumpList result; 622 623 switch (arrayMode.type()) { 624 case Array::Int32: 625 return jumpSlowForUnwantedArrayMode(tempGPR, arrayMode, Int32Shape); 626 627 case Array::Double: 628 return jumpSlowForUnwantedArrayMode(tempGPR, arrayMode, DoubleShape); 629 630 case Array::Contiguous: 631 return jumpSlowForUnwantedArrayMode(tempGPR, arrayMode, ContiguousShape); 632 633 case Array::ArrayStorage: 634 case Array::SlowPutArrayStorage: { 635 ASSERT(!arrayMode.isJSArrayWithOriginalStructure()); 636 637 if (arrayMode.isJSArray()) { 638 if (arrayMode.isSlowPut()) { 639 result.append( 640 m_jit.branchTest32( 641 MacroAssembler::Zero, tempGPR, MacroAssembler::TrustedImm32(IsArray))); 642 m_jit.and32(TrustedImm32(IndexingShapeMask), tempGPR); 643 m_jit.sub32(TrustedImm32(ArrayStorageShape), tempGPR); 644 result.append( 645 m_jit.branch32( 646 MacroAssembler::Above, tempGPR, 647 TrustedImm32(SlowPutArrayStorageShape - ArrayStorageShape))); 648 break; 649 } 650 m_jit.and32(TrustedImm32(IsArray | IndexingShapeMask), tempGPR); 651 result.append( 652 m_jit.branch32(MacroAssembler::NotEqual, tempGPR, TrustedImm32(IsArray | ArrayStorageShape))); 653 break; 654 } 655 m_jit.and32(TrustedImm32(IndexingShapeMask), tempGPR); 656 if (arrayMode.isSlowPut()) { 657 m_jit.sub32(TrustedImm32(ArrayStorageShape), tempGPR); 658 result.append( 659 m_jit.branch32( 660 MacroAssembler::Above, tempGPR, 661 TrustedImm32(SlowPutArrayStorageShape - ArrayStorageShape))); 662 break; 663 } 664 result.append( 665 m_jit.branch32(MacroAssembler::NotEqual, tempGPR, TrustedImm32(ArrayStorageShape))); 666 break; 667 } 668 default: 669 CRASH(); 670 break; 671 } 672 673 return result; 674} 675 676void SpeculativeJIT::checkArray(Node* node) 677{ 678 ASSERT(node->arrayMode().isSpecific()); 679 ASSERT(!node->arrayMode().doesConversion()); 680 681 SpeculateCellOperand base(this, node->child1()); 682 GPRReg baseReg = base.gpr(); 683 684 if (node->arrayMode().alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1()))) { 685 noResult(m_currentNode); 686 return; 687 } 688 689 const ClassInfo* expectedClassInfo = 0; 690 691 switch (node->arrayMode().type()) { 692 case Array::String: 693 RELEASE_ASSERT_NOT_REACHED(); // Should have been a Phantom(String:) 694 break; 695 case Array::Int32: 696 case Array::Double: 697 case Array::Contiguous: 698 case Array::ArrayStorage: 699 case Array::SlowPutArrayStorage: { 700 GPRTemporary temp(this); 701 GPRReg tempGPR = temp.gpr(); 702 m_jit.load8(MacroAssembler::Address(baseReg, JSCell::indexingTypeOffset()), tempGPR); 703 speculationCheck( 704 BadIndexingType, JSValueSource::unboxedCell(baseReg), 0, 705 jumpSlowForUnwantedArrayMode(tempGPR, node->arrayMode())); 706 707 noResult(m_currentNode); 708 return; 709 } 710 case Array::Arguments: 711 speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node, 712 m_jit.branch8( 713 MacroAssembler::NotEqual, 714 MacroAssembler::Address(baseReg, JSCell::typeInfoTypeOffset()), 715 MacroAssembler::TrustedImm32(ArgumentsType))); 716 717 noResult(m_currentNode); 718 return; 719 default: 720 speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node, 721 m_jit.branch8( 722 MacroAssembler::NotEqual, 723 MacroAssembler::Address(baseReg, JSCell::typeInfoTypeOffset()), 724 MacroAssembler::TrustedImm32(typeForTypedArrayType(node->arrayMode().typedArrayType())))); 725 noResult(m_currentNode); 726 return; 727 } 728 729 RELEASE_ASSERT(expectedClassInfo); 730 731 GPRTemporary temp(this); 732 GPRTemporary temp2(this); 733 m_jit.emitLoadStructure(baseReg, temp.gpr(), temp2.gpr()); 734 speculationCheck( 735 BadType, JSValueSource::unboxedCell(baseReg), node, 736 m_jit.branchPtr( 737 MacroAssembler::NotEqual, 738 MacroAssembler::Address(temp.gpr(), Structure::classInfoOffset()), 739 MacroAssembler::TrustedImmPtr(expectedClassInfo))); 740 741 noResult(m_currentNode); 742} 743 744void SpeculativeJIT::arrayify(Node* node, GPRReg baseReg, GPRReg propertyReg) 745{ 746 ASSERT(node->arrayMode().doesConversion()); 747 748 GPRTemporary temp(this); 749 GPRTemporary structure; 750 GPRReg tempGPR = temp.gpr(); 751 GPRReg structureGPR = InvalidGPRReg; 752 753 if (node->op() != ArrayifyToStructure) { 754 GPRTemporary realStructure(this); 755 structure.adopt(realStructure); 756 structureGPR = structure.gpr(); 757 } 758 759 // We can skip all that comes next if we already have array storage. 760 MacroAssembler::JumpList slowPath; 761 762 if (node->op() == ArrayifyToStructure) { 763 slowPath.append(m_jit.branchWeakStructure( 764 JITCompiler::NotEqual, 765 JITCompiler::Address(baseReg, JSCell::structureIDOffset()), 766 node->structure())); 767 } else { 768 m_jit.load8( 769 MacroAssembler::Address(baseReg, JSCell::indexingTypeOffset()), tempGPR); 770 771 slowPath.append(jumpSlowForUnwantedArrayMode(tempGPR, node->arrayMode())); 772 } 773 774 addSlowPathGenerator(adoptPtr(new ArrayifySlowPathGenerator( 775 slowPath, this, node, baseReg, propertyReg, tempGPR, structureGPR))); 776 777 noResult(m_currentNode); 778} 779 780void SpeculativeJIT::arrayify(Node* node) 781{ 782 ASSERT(node->arrayMode().isSpecific()); 783 784 SpeculateCellOperand base(this, node->child1()); 785 786 if (!node->child2()) { 787 arrayify(node, base.gpr(), InvalidGPRReg); 788 return; 789 } 790 791 SpeculateInt32Operand property(this, node->child2()); 792 793 arrayify(node, base.gpr(), property.gpr()); 794} 795 796GPRReg SpeculativeJIT::fillStorage(Edge edge) 797{ 798 VirtualRegister virtualRegister = edge->virtualRegister(); 799 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister); 800 801 switch (info.registerFormat()) { 802 case DataFormatNone: { 803 if (info.spillFormat() == DataFormatStorage) { 804 GPRReg gpr = allocate(); 805 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); 806 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr); 807 info.fillStorage(*m_stream, gpr); 808 return gpr; 809 } 810 811 // Must be a cell; fill it as a cell and then return the pointer. 812 return fillSpeculateCell(edge); 813 } 814 815 case DataFormatStorage: { 816 GPRReg gpr = info.gpr(); 817 m_gprs.lock(gpr); 818 return gpr; 819 } 820 821 default: 822 return fillSpeculateCell(edge); 823 } 824} 825 826void SpeculativeJIT::useChildren(Node* node) 827{ 828 if (node->flags() & NodeHasVarArgs) { 829 for (unsigned childIdx = node->firstChild(); childIdx < node->firstChild() + node->numChildren(); childIdx++) { 830 if (!!m_jit.graph().m_varArgChildren[childIdx]) 831 use(m_jit.graph().m_varArgChildren[childIdx]); 832 } 833 } else { 834 Edge child1 = node->child1(); 835 if (!child1) { 836 ASSERT(!node->child2() && !node->child3()); 837 return; 838 } 839 use(child1); 840 841 Edge child2 = node->child2(); 842 if (!child2) { 843 ASSERT(!node->child3()); 844 return; 845 } 846 use(child2); 847 848 Edge child3 = node->child3(); 849 if (!child3) 850 return; 851 use(child3); 852 } 853} 854 855void SpeculativeJIT::compileIn(Node* node) 856{ 857 SpeculateCellOperand base(this, node->child2()); 858 GPRReg baseGPR = base.gpr(); 859 860 if (isConstant(node->child1().node())) { 861 JSString* string = 862 jsDynamicCast<JSString*>(valueOfJSConstant(node->child1().node())); 863 if (string && string->tryGetValueImpl() 864 && string->tryGetValueImpl()->isAtomic()) { 865 StructureStubInfo* stubInfo = m_jit.codeBlock()->addStubInfo(); 866 867 GPRTemporary result(this); 868 GPRReg resultGPR = result.gpr(); 869 870 use(node->child1()); 871 872 MacroAssembler::PatchableJump jump = m_jit.patchableJump(); 873 MacroAssembler::Label done = m_jit.label(); 874 875 OwnPtr<SlowPathGenerator> slowPath = slowPathCall( 876 jump.m_jump, this, operationInOptimize, 877 JSValueRegs::payloadOnly(resultGPR), stubInfo, baseGPR, 878 string->tryGetValueImpl()); 879 880 stubInfo->codeOrigin = node->origin.semantic; 881 stubInfo->patch.baseGPR = static_cast<int8_t>(baseGPR); 882 stubInfo->patch.valueGPR = static_cast<int8_t>(resultGPR); 883 stubInfo->patch.usedRegisters = usedRegisters(); 884 stubInfo->patch.spillMode = NeedToSpill; 885 886 m_jit.addIn(InRecord(jump, done, slowPath.get(), stubInfo)); 887 addSlowPathGenerator(slowPath.release()); 888 889 base.use(); 890 891 blessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly); 892 return; 893 } 894 } 895 896 JSValueOperand key(this, node->child1()); 897 JSValueRegs regs = key.jsValueRegs(); 898 899 GPRResult result(this); 900 GPRReg resultGPR = result.gpr(); 901 902 base.use(); 903 key.use(); 904 905 flushRegisters(); 906 callOperation( 907 operationGenericIn, extractResult(JSValueRegs::payloadOnly(resultGPR)), 908 baseGPR, regs); 909 blessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly); 910} 911 912bool SpeculativeJIT::nonSpeculativeCompare(Node* node, MacroAssembler::RelationalCondition cond, S_JITOperation_EJJ helperFunction) 913{ 914 unsigned branchIndexInBlock = detectPeepHoleBranch(); 915 if (branchIndexInBlock != UINT_MAX) { 916 Node* branchNode = m_block->at(branchIndexInBlock); 917 918 ASSERT(node->adjustedRefCount() == 1); 919 920 nonSpeculativePeepholeBranch(node, branchNode, cond, helperFunction); 921 922 m_indexInBlock = branchIndexInBlock; 923 m_currentNode = branchNode; 924 925 return true; 926 } 927 928 nonSpeculativeNonPeepholeCompare(node, cond, helperFunction); 929 930 return false; 931} 932 933bool SpeculativeJIT::nonSpeculativeStrictEq(Node* node, bool invert) 934{ 935 unsigned branchIndexInBlock = detectPeepHoleBranch(); 936 if (branchIndexInBlock != UINT_MAX) { 937 Node* branchNode = m_block->at(branchIndexInBlock); 938 939 ASSERT(node->adjustedRefCount() == 1); 940 941 nonSpeculativePeepholeStrictEq(node, branchNode, invert); 942 943 m_indexInBlock = branchIndexInBlock; 944 m_currentNode = branchNode; 945 946 return true; 947 } 948 949 nonSpeculativeNonPeepholeStrictEq(node, invert); 950 951 return false; 952} 953 954static const char* dataFormatString(DataFormat format) 955{ 956 // These values correspond to the DataFormat enum. 957 const char* strings[] = { 958 "[ ]", 959 "[ i]", 960 "[ d]", 961 "[ c]", 962 "Err!", 963 "Err!", 964 "Err!", 965 "Err!", 966 "[J ]", 967 "[Ji]", 968 "[Jd]", 969 "[Jc]", 970 "Err!", 971 "Err!", 972 "Err!", 973 "Err!", 974 }; 975 return strings[format]; 976} 977 978void SpeculativeJIT::dump(const char* label) 979{ 980 if (label) 981 dataLogF("<%s>\n", label); 982 983 dataLogF(" gprs:\n"); 984 m_gprs.dump(); 985 dataLogF(" fprs:\n"); 986 m_fprs.dump(); 987 dataLogF(" VirtualRegisters:\n"); 988 for (unsigned i = 0; i < m_generationInfo.size(); ++i) { 989 GenerationInfo& info = m_generationInfo[i]; 990 if (info.alive()) 991 dataLogF(" % 3d:%s%s", i, dataFormatString(info.registerFormat()), dataFormatString(info.spillFormat())); 992 else 993 dataLogF(" % 3d:[__][__]", i); 994 if (info.registerFormat() == DataFormatDouble) 995 dataLogF(":fpr%d\n", info.fpr()); 996 else if (info.registerFormat() != DataFormatNone 997#if USE(JSVALUE32_64) 998 && !(info.registerFormat() & DataFormatJS) 999#endif 1000 ) { 1001 ASSERT(info.gpr() != InvalidGPRReg); 1002 dataLogF(":%s\n", GPRInfo::debugName(info.gpr())); 1003 } else 1004 dataLogF("\n"); 1005 } 1006 if (label) 1007 dataLogF("</%s>\n", label); 1008} 1009 1010GPRTemporary::GPRTemporary() 1011 : m_jit(0) 1012 , m_gpr(InvalidGPRReg) 1013{ 1014} 1015 1016GPRTemporary::GPRTemporary(SpeculativeJIT* jit) 1017 : m_jit(jit) 1018 , m_gpr(InvalidGPRReg) 1019{ 1020 m_gpr = m_jit->allocate(); 1021} 1022 1023GPRTemporary::GPRTemporary(SpeculativeJIT* jit, GPRReg specific) 1024 : m_jit(jit) 1025 , m_gpr(InvalidGPRReg) 1026{ 1027 m_gpr = m_jit->allocate(specific); 1028} 1029 1030#if USE(JSVALUE32_64) 1031GPRTemporary::GPRTemporary( 1032 SpeculativeJIT* jit, ReuseTag, JSValueOperand& op1, WhichValueWord which) 1033 : m_jit(jit) 1034 , m_gpr(InvalidGPRReg) 1035{ 1036 if (!op1.isDouble() && m_jit->canReuse(op1.node())) 1037 m_gpr = m_jit->reuse(op1.gpr(which)); 1038 else 1039 m_gpr = m_jit->allocate(); 1040} 1041#endif // USE(JSVALUE32_64) 1042 1043JSValueRegsTemporary::JSValueRegsTemporary() { } 1044 1045JSValueRegsTemporary::JSValueRegsTemporary(SpeculativeJIT* jit) 1046#if USE(JSVALUE64) 1047 : m_gpr(jit) 1048#else 1049 : m_payloadGPR(jit) 1050 , m_tagGPR(jit) 1051#endif 1052{ 1053} 1054 1055JSValueRegsTemporary::~JSValueRegsTemporary() { } 1056 1057JSValueRegs JSValueRegsTemporary::regs() 1058{ 1059#if USE(JSVALUE64) 1060 return JSValueRegs(m_gpr.gpr()); 1061#else 1062 return JSValueRegs(m_tagGPR.gpr(), m_payloadGPR.gpr()); 1063#endif 1064} 1065 1066void GPRTemporary::adopt(GPRTemporary& other) 1067{ 1068 ASSERT(!m_jit); 1069 ASSERT(m_gpr == InvalidGPRReg); 1070 ASSERT(other.m_jit); 1071 ASSERT(other.m_gpr != InvalidGPRReg); 1072 m_jit = other.m_jit; 1073 m_gpr = other.m_gpr; 1074 other.m_jit = 0; 1075 other.m_gpr = InvalidGPRReg; 1076} 1077 1078FPRTemporary::FPRTemporary(SpeculativeJIT* jit) 1079 : m_jit(jit) 1080 , m_fpr(InvalidFPRReg) 1081{ 1082 m_fpr = m_jit->fprAllocate(); 1083} 1084 1085FPRTemporary::FPRTemporary(SpeculativeJIT* jit, SpeculateDoubleOperand& op1) 1086 : m_jit(jit) 1087 , m_fpr(InvalidFPRReg) 1088{ 1089 if (m_jit->canReuse(op1.node())) 1090 m_fpr = m_jit->reuse(op1.fpr()); 1091 else 1092 m_fpr = m_jit->fprAllocate(); 1093} 1094 1095FPRTemporary::FPRTemporary(SpeculativeJIT* jit, SpeculateDoubleOperand& op1, SpeculateDoubleOperand& op2) 1096 : m_jit(jit) 1097 , m_fpr(InvalidFPRReg) 1098{ 1099 if (m_jit->canReuse(op1.node())) 1100 m_fpr = m_jit->reuse(op1.fpr()); 1101 else if (m_jit->canReuse(op2.node())) 1102 m_fpr = m_jit->reuse(op2.fpr()); 1103 else 1104 m_fpr = m_jit->fprAllocate(); 1105} 1106 1107#if USE(JSVALUE32_64) 1108FPRTemporary::FPRTemporary(SpeculativeJIT* jit, JSValueOperand& op1) 1109 : m_jit(jit) 1110 , m_fpr(InvalidFPRReg) 1111{ 1112 if (op1.isDouble() && m_jit->canReuse(op1.node())) 1113 m_fpr = m_jit->reuse(op1.fpr()); 1114 else 1115 m_fpr = m_jit->fprAllocate(); 1116} 1117#endif 1118 1119void SpeculativeJIT::compilePeepHoleDoubleBranch(Node* node, Node* branchNode, JITCompiler::DoubleCondition condition) 1120{ 1121 BasicBlock* taken = branchNode->branchData()->taken.block; 1122 BasicBlock* notTaken = branchNode->branchData()->notTaken.block; 1123 1124 SpeculateDoubleOperand op1(this, node->child1()); 1125 SpeculateDoubleOperand op2(this, node->child2()); 1126 1127 branchDouble(condition, op1.fpr(), op2.fpr(), taken); 1128 jump(notTaken); 1129} 1130 1131void SpeculativeJIT::compilePeepHoleObjectEquality(Node* node, Node* branchNode) 1132{ 1133 BasicBlock* taken = branchNode->branchData()->taken.block; 1134 BasicBlock* notTaken = branchNode->branchData()->notTaken.block; 1135 1136 MacroAssembler::RelationalCondition condition = MacroAssembler::Equal; 1137 1138 if (taken == nextBlock()) { 1139 condition = MacroAssembler::NotEqual; 1140 BasicBlock* tmp = taken; 1141 taken = notTaken; 1142 notTaken = tmp; 1143 } 1144 1145 SpeculateCellOperand op1(this, node->child1()); 1146 SpeculateCellOperand op2(this, node->child2()); 1147 1148 GPRReg op1GPR = op1.gpr(); 1149 GPRReg op2GPR = op2.gpr(); 1150 1151 if (masqueradesAsUndefinedWatchpointIsStillValid()) { 1152 if (m_state.forNode(node->child1()).m_type & ~SpecObject) { 1153 speculationCheck( 1154 BadType, JSValueSource::unboxedCell(op1GPR), node->child1(), 1155 m_jit.branchStructurePtr( 1156 MacroAssembler::Equal, 1157 MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()), 1158 m_jit.vm()->stringStructure.get())); 1159 } 1160 if (m_state.forNode(node->child2()).m_type & ~SpecObject) { 1161 speculationCheck( 1162 BadType, JSValueSource::unboxedCell(op2GPR), node->child2(), 1163 m_jit.branchStructurePtr( 1164 MacroAssembler::Equal, 1165 MacroAssembler::Address(op2GPR, JSCell::structureIDOffset()), 1166 m_jit.vm()->stringStructure.get())); 1167 } 1168 } else { 1169 GPRTemporary structure(this); 1170 GPRTemporary temp(this); 1171 GPRReg structureGPR = structure.gpr(); 1172 1173 m_jit.emitLoadStructure(op1GPR, structureGPR, temp.gpr()); 1174 if (m_state.forNode(node->child1()).m_type & ~SpecObject) { 1175 speculationCheck( 1176 BadType, JSValueSource::unboxedCell(op1GPR), node->child1(), 1177 m_jit.branchPtr( 1178 MacroAssembler::Equal, 1179 structureGPR, 1180 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get()))); 1181 } 1182 speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node->child1(), 1183 m_jit.branchTest8( 1184 MacroAssembler::NonZero, 1185 MacroAssembler::Address(op1GPR, JSCell::typeInfoFlagsOffset()), 1186 MacroAssembler::TrustedImm32(MasqueradesAsUndefined))); 1187 1188 m_jit.emitLoadStructure(op2GPR, structureGPR, temp.gpr()); 1189 if (m_state.forNode(node->child2()).m_type & ~SpecObject) { 1190 speculationCheck( 1191 BadType, JSValueSource::unboxedCell(op2GPR), node->child2(), 1192 m_jit.branchPtr( 1193 MacroAssembler::Equal, 1194 structureGPR, 1195 MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get()))); 1196 } 1197 speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node->child2(), 1198 m_jit.branchTest8( 1199 MacroAssembler::NonZero, 1200 MacroAssembler::Address(op2GPR, JSCell::typeInfoFlagsOffset()), 1201 MacroAssembler::TrustedImm32(MasqueradesAsUndefined))); 1202 } 1203 1204 branchPtr(condition, op1GPR, op2GPR, taken); 1205 jump(notTaken); 1206} 1207 1208void SpeculativeJIT::compilePeepHoleBooleanBranch(Node* node, Node* branchNode, JITCompiler::RelationalCondition condition) 1209{ 1210 BasicBlock* taken = branchNode->branchData()->taken.block; 1211 BasicBlock* notTaken = branchNode->branchData()->notTaken.block; 1212 1213 // The branch instruction will branch to the taken block. 1214 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through. 1215 if (taken == nextBlock()) { 1216 condition = JITCompiler::invert(condition); 1217 BasicBlock* tmp = taken; 1218 taken = notTaken; 1219 notTaken = tmp; 1220 } 1221 1222 if (isBooleanConstant(node->child1().node())) { 1223 bool imm = valueOfBooleanConstant(node->child1().node()); 1224 SpeculateBooleanOperand op2(this, node->child2()); 1225 branch32(condition, JITCompiler::Imm32(static_cast<int32_t>(JSValue::encode(jsBoolean(imm)))), op2.gpr(), taken); 1226 } else if (isBooleanConstant(node->child2().node())) { 1227 SpeculateBooleanOperand op1(this, node->child1()); 1228 bool imm = valueOfBooleanConstant(node->child2().node()); 1229 branch32(condition, op1.gpr(), JITCompiler::Imm32(static_cast<int32_t>(JSValue::encode(jsBoolean(imm)))), taken); 1230 } else { 1231 SpeculateBooleanOperand op1(this, node->child1()); 1232 SpeculateBooleanOperand op2(this, node->child2()); 1233 branch32(condition, op1.gpr(), op2.gpr(), taken); 1234 } 1235 1236 jump(notTaken); 1237} 1238 1239void SpeculativeJIT::compilePeepHoleInt32Branch(Node* node, Node* branchNode, JITCompiler::RelationalCondition condition) 1240{ 1241 BasicBlock* taken = branchNode->branchData()->taken.block; 1242 BasicBlock* notTaken = branchNode->branchData()->notTaken.block; 1243 1244 // The branch instruction will branch to the taken block. 1245 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through. 1246 if (taken == nextBlock()) { 1247 condition = JITCompiler::invert(condition); 1248 BasicBlock* tmp = taken; 1249 taken = notTaken; 1250 notTaken = tmp; 1251 } 1252 1253 if (isInt32Constant(node->child1().node())) { 1254 int32_t imm = valueOfInt32Constant(node->child1().node()); 1255 SpeculateInt32Operand op2(this, node->child2()); 1256 branch32(condition, JITCompiler::Imm32(imm), op2.gpr(), taken); 1257 } else if (isInt32Constant(node->child2().node())) { 1258 SpeculateInt32Operand op1(this, node->child1()); 1259 int32_t imm = valueOfInt32Constant(node->child2().node()); 1260 branch32(condition, op1.gpr(), JITCompiler::Imm32(imm), taken); 1261 } else { 1262 SpeculateInt32Operand op1(this, node->child1()); 1263 SpeculateInt32Operand op2(this, node->child2()); 1264 branch32(condition, op1.gpr(), op2.gpr(), taken); 1265 } 1266 1267 jump(notTaken); 1268} 1269 1270// Returns true if the compare is fused with a subsequent branch. 1271bool SpeculativeJIT::compilePeepHoleBranch(Node* node, MacroAssembler::RelationalCondition condition, MacroAssembler::DoubleCondition doubleCondition, S_JITOperation_EJJ operation) 1272{ 1273 // Fused compare & branch. 1274 unsigned branchIndexInBlock = detectPeepHoleBranch(); 1275 if (branchIndexInBlock != UINT_MAX) { 1276 Node* branchNode = m_block->at(branchIndexInBlock); 1277 1278 // detectPeepHoleBranch currently only permits the branch to be the very next node, 1279 // so can be no intervening nodes to also reference the compare. 1280 ASSERT(node->adjustedRefCount() == 1); 1281 1282 if (node->isBinaryUseKind(Int32Use)) 1283 compilePeepHoleInt32Branch(node, branchNode, condition); 1284#if USE(JSVALUE64) 1285 else if (node->isBinaryUseKind(Int52RepUse)) 1286 compilePeepHoleInt52Branch(node, branchNode, condition); 1287#endif // USE(JSVALUE64) 1288 else if (node->isBinaryUseKind(DoubleRepUse)) 1289 compilePeepHoleDoubleBranch(node, branchNode, doubleCondition); 1290 else if (node->op() == CompareEq) { 1291 if (node->isBinaryUseKind(StringUse) || node->isBinaryUseKind(StringIdentUse)) { 1292 // Use non-peephole comparison, for now. 1293 return false; 1294 } 1295 if (node->isBinaryUseKind(BooleanUse)) 1296 compilePeepHoleBooleanBranch(node, branchNode, condition); 1297 else if (node->isBinaryUseKind(ObjectUse)) 1298 compilePeepHoleObjectEquality(node, branchNode); 1299 else if (node->isBinaryUseKind(ObjectUse, ObjectOrOtherUse)) 1300 compilePeepHoleObjectToObjectOrOtherEquality(node->child1(), node->child2(), branchNode); 1301 else if (node->isBinaryUseKind(ObjectOrOtherUse, ObjectUse)) 1302 compilePeepHoleObjectToObjectOrOtherEquality(node->child2(), node->child1(), branchNode); 1303 else { 1304 nonSpeculativePeepholeBranch(node, branchNode, condition, operation); 1305 return true; 1306 } 1307 } else { 1308 nonSpeculativePeepholeBranch(node, branchNode, condition, operation); 1309 return true; 1310 } 1311 1312 use(node->child1()); 1313 use(node->child2()); 1314 m_indexInBlock = branchIndexInBlock; 1315 m_currentNode = branchNode; 1316 return true; 1317 } 1318 return false; 1319} 1320 1321void SpeculativeJIT::noticeOSRBirth(Node* node) 1322{ 1323 if (!node->hasVirtualRegister()) 1324 return; 1325 1326 VirtualRegister virtualRegister = node->virtualRegister(); 1327 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister); 1328 1329 info.noticeOSRBirth(*m_stream, node, virtualRegister); 1330} 1331 1332void SpeculativeJIT::compileMovHint(Node* node) 1333{ 1334 ASSERT(node->containsMovHint() && node->op() != ZombieHint); 1335 1336 Node* child = node->child1().node(); 1337 noticeOSRBirth(child); 1338 1339 m_stream->appendAndLog(VariableEvent::movHint(MinifiedID(child), node->unlinkedLocal())); 1340} 1341 1342void SpeculativeJIT::bail(AbortReason reason) 1343{ 1344 m_compileOkay = true; 1345 m_jit.abortWithReason(reason, m_lastGeneratedNode); 1346 clearGenerationInfo(); 1347} 1348 1349void SpeculativeJIT::compileCurrentBlock() 1350{ 1351 ASSERT(m_compileOkay); 1352 1353 if (!m_block) 1354 return; 1355 1356 ASSERT(m_block->isReachable); 1357 1358 m_jit.blockHeads()[m_block->index] = m_jit.label(); 1359 1360 if (!m_block->cfaHasVisited) { 1361 // Don't generate code for basic blocks that are unreachable according to CFA. 1362 // But to be sure that nobody has generated a jump to this block, drop in a 1363 // breakpoint here. 1364 m_jit.abortWithReason(DFGUnreachableBasicBlock); 1365 return; 1366 } 1367 1368 m_stream->appendAndLog(VariableEvent::reset()); 1369 1370 m_jit.jitAssertHasValidCallFrame(); 1371 m_jit.jitAssertTagsInPlace(); 1372 m_jit.jitAssertArgumentCountSane(); 1373 1374 m_state.reset(); 1375 m_state.beginBasicBlock(m_block); 1376 1377 for (size_t i = m_block->variablesAtHead.size(); i--;) { 1378 int operand = m_block->variablesAtHead.operandForIndex(i); 1379 Node* node = m_block->variablesAtHead[i]; 1380 if (!node) 1381 continue; // No need to record dead SetLocal's. 1382 1383 VariableAccessData* variable = node->variableAccessData(); 1384 DataFormat format; 1385 if (!node->refCount()) 1386 continue; // No need to record dead SetLocal's. 1387 format = dataFormatFor(variable->flushFormat()); 1388 m_stream->appendAndLog( 1389 VariableEvent::setLocal( 1390 VirtualRegister(operand), 1391 variable->machineLocal(), 1392 format)); 1393 } 1394 1395 m_codeOriginForExitTarget = CodeOrigin(); 1396 m_codeOriginForExitProfile = CodeOrigin(); 1397 1398 for (m_indexInBlock = 0; m_indexInBlock < m_block->size(); ++m_indexInBlock) { 1399 m_currentNode = m_block->at(m_indexInBlock); 1400 1401 // We may have hit a contradiction that the CFA was aware of but that the JIT 1402 // didn't cause directly. 1403 if (!m_state.isValid()) { 1404 bail(DFGBailedAtTopOfBlock); 1405 return; 1406 } 1407 1408 m_canExit = m_currentNode->canExit(); 1409 bool shouldExecuteEffects = m_interpreter.startExecuting(m_currentNode); 1410 m_jit.setForNode(m_currentNode); 1411 m_codeOriginForExitTarget = m_currentNode->origin.forExit; 1412 m_codeOriginForExitProfile = m_currentNode->origin.semantic; 1413 m_lastGeneratedNode = m_currentNode->op(); 1414 if (!m_currentNode->shouldGenerate()) { 1415 switch (m_currentNode->op()) { 1416 case JSConstant: 1417 m_minifiedGraph->append(MinifiedNode::fromNode(m_currentNode)); 1418 break; 1419 1420 case WeakJSConstant: 1421 m_jit.addWeakReference(m_currentNode->weakConstant()); 1422 m_minifiedGraph->append(MinifiedNode::fromNode(m_currentNode)); 1423 break; 1424 1425 case SetLocal: 1426 RELEASE_ASSERT_NOT_REACHED(); 1427 break; 1428 1429 case MovHint: 1430 compileMovHint(m_currentNode); 1431 break; 1432 1433 case ZombieHint: { 1434 recordSetLocal(m_currentNode->unlinkedLocal(), VirtualRegister(), DataFormatDead); 1435 break; 1436 } 1437 1438 default: 1439 if (belongsInMinifiedGraph(m_currentNode->op())) 1440 m_minifiedGraph->append(MinifiedNode::fromNode(m_currentNode)); 1441 break; 1442 } 1443 } else { 1444 1445 if (verboseCompilationEnabled()) { 1446 dataLogF( 1447 "SpeculativeJIT generating Node @%d (bc#%u) at JIT offset 0x%x", 1448 (int)m_currentNode->index(), 1449 m_currentNode->origin.semantic.bytecodeIndex, m_jit.debugOffset()); 1450 dataLog("\n"); 1451 } 1452 1453 compile(m_currentNode); 1454 1455#if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION) 1456 m_jit.clearRegisterAllocationOffsets(); 1457#endif 1458 1459 if (!m_compileOkay) { 1460 bail(DFGBailedAtEndOfNode); 1461 return; 1462 } 1463 1464 if (belongsInMinifiedGraph(m_currentNode->op())) { 1465 m_minifiedGraph->append(MinifiedNode::fromNode(m_currentNode)); 1466 noticeOSRBirth(m_currentNode); 1467 } 1468 } 1469 1470 // Make sure that the abstract state is rematerialized for the next node. 1471 if (shouldExecuteEffects) 1472 m_interpreter.executeEffects(m_indexInBlock); 1473 } 1474 1475 // Perform the most basic verification that children have been used correctly. 1476 if (!ASSERT_DISABLED) { 1477 for (unsigned index = 0; index < m_generationInfo.size(); ++index) { 1478 GenerationInfo& info = m_generationInfo[index]; 1479 RELEASE_ASSERT(!info.alive()); 1480 } 1481 } 1482} 1483 1484// If we are making type predictions about our arguments then 1485// we need to check that they are correct on function entry. 1486void SpeculativeJIT::checkArgumentTypes() 1487{ 1488 ASSERT(!m_currentNode); 1489 m_isCheckingArgumentTypes = true; 1490 m_codeOriginForExitTarget = CodeOrigin(0); 1491 m_codeOriginForExitProfile = CodeOrigin(0); 1492 1493 for (int i = 0; i < m_jit.codeBlock()->numParameters(); ++i) { 1494 Node* node = m_jit.graph().m_arguments[i]; 1495 if (!node) { 1496 // The argument is dead. We don't do any checks for such arguments. 1497 continue; 1498 } 1499 1500 ASSERT(node->op() == SetArgument); 1501 ASSERT(node->shouldGenerate()); 1502 1503 VariableAccessData* variableAccessData = node->variableAccessData(); 1504 FlushFormat format = variableAccessData->flushFormat(); 1505 1506 if (format == FlushedJSValue) 1507 continue; 1508 1509 VirtualRegister virtualRegister = variableAccessData->local(); 1510 1511 JSValueSource valueSource = JSValueSource(JITCompiler::addressFor(virtualRegister)); 1512 1513#if USE(JSVALUE64) 1514 switch (format) { 1515 case FlushedInt32: { 1516 speculationCheck(BadType, valueSource, node, m_jit.branch64(MacroAssembler::Below, JITCompiler::addressFor(virtualRegister), GPRInfo::tagTypeNumberRegister)); 1517 break; 1518 } 1519 case FlushedBoolean: { 1520 GPRTemporary temp(this); 1521 m_jit.load64(JITCompiler::addressFor(virtualRegister), temp.gpr()); 1522 m_jit.xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), temp.gpr()); 1523 speculationCheck(BadType, valueSource, node, m_jit.branchTest64(MacroAssembler::NonZero, temp.gpr(), TrustedImm32(static_cast<int32_t>(~1)))); 1524 break; 1525 } 1526 case FlushedCell: { 1527 speculationCheck(BadType, valueSource, node, m_jit.branchTest64(MacroAssembler::NonZero, JITCompiler::addressFor(virtualRegister), GPRInfo::tagMaskRegister)); 1528 break; 1529 } 1530 default: 1531 RELEASE_ASSERT_NOT_REACHED(); 1532 break; 1533 } 1534#else 1535 switch (format) { 1536 case FlushedInt32: { 1537 speculationCheck(BadType, valueSource, node, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag))); 1538 break; 1539 } 1540 case FlushedBoolean: { 1541 speculationCheck(BadType, valueSource, node, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::BooleanTag))); 1542 break; 1543 } 1544 case FlushedCell: { 1545 speculationCheck(BadType, valueSource, node, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::CellTag))); 1546 break; 1547 } 1548 default: 1549 RELEASE_ASSERT_NOT_REACHED(); 1550 break; 1551 } 1552#endif 1553 } 1554 m_isCheckingArgumentTypes = false; 1555} 1556 1557bool SpeculativeJIT::compile() 1558{ 1559 checkArgumentTypes(); 1560 1561 ASSERT(!m_currentNode); 1562 for (BlockIndex blockIndex = 0; blockIndex < m_jit.graph().numBlocks(); ++blockIndex) { 1563 m_jit.setForBlockIndex(blockIndex); 1564 m_block = m_jit.graph().block(blockIndex); 1565 compileCurrentBlock(); 1566 } 1567 linkBranches(); 1568 return true; 1569} 1570 1571void SpeculativeJIT::createOSREntries() 1572{ 1573 for (BlockIndex blockIndex = 0; blockIndex < m_jit.graph().numBlocks(); ++blockIndex) { 1574 BasicBlock* block = m_jit.graph().block(blockIndex); 1575 if (!block) 1576 continue; 1577 if (!block->isOSRTarget) 1578 continue; 1579 1580 // Currently we don't have OSR entry trampolines. We could add them 1581 // here if need be. 1582 m_osrEntryHeads.append(m_jit.blockHeads()[blockIndex]); 1583 } 1584} 1585 1586void SpeculativeJIT::linkOSREntries(LinkBuffer& linkBuffer) 1587{ 1588 unsigned osrEntryIndex = 0; 1589 for (BlockIndex blockIndex = 0; blockIndex < m_jit.graph().numBlocks(); ++blockIndex) { 1590 BasicBlock* block = m_jit.graph().block(blockIndex); 1591 if (!block) 1592 continue; 1593 if (!block->isOSRTarget) 1594 continue; 1595 m_jit.noticeOSREntry(*block, m_osrEntryHeads[osrEntryIndex++], linkBuffer); 1596 } 1597 ASSERT(osrEntryIndex == m_osrEntryHeads.size()); 1598} 1599 1600void SpeculativeJIT::compileDoublePutByVal(Node* node, SpeculateCellOperand& base, SpeculateStrictInt32Operand& property) 1601{ 1602 Edge child3 = m_jit.graph().varArgChild(node, 2); 1603 Edge child4 = m_jit.graph().varArgChild(node, 3); 1604 1605 ArrayMode arrayMode = node->arrayMode(); 1606 1607 GPRReg baseReg = base.gpr(); 1608 GPRReg propertyReg = property.gpr(); 1609 1610 SpeculateDoubleOperand value(this, child3); 1611 1612 FPRReg valueReg = value.fpr(); 1613 1614 DFG_TYPE_CHECK( 1615 JSValueRegs(), child3, SpecFullRealNumber, 1616 m_jit.branchDouble( 1617 MacroAssembler::DoubleNotEqualOrUnordered, valueReg, valueReg)); 1618 1619 if (!m_compileOkay) 1620 return; 1621 1622 StorageOperand storage(this, child4); 1623 GPRReg storageReg = storage.gpr(); 1624 1625 if (node->op() == PutByValAlias) { 1626 // Store the value to the array. 1627 GPRReg propertyReg = property.gpr(); 1628 FPRReg valueReg = value.fpr(); 1629 m_jit.storeDouble(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight)); 1630 1631 noResult(m_currentNode); 1632 return; 1633 } 1634 1635 GPRTemporary temporary; 1636 GPRReg temporaryReg = temporaryRegisterForPutByVal(temporary, node); 1637 1638 MacroAssembler::Jump slowCase; 1639 1640 if (arrayMode.isInBounds()) { 1641 speculationCheck( 1642 OutOfBounds, JSValueRegs(), 0, 1643 m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()))); 1644 } else { 1645 MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())); 1646 1647 slowCase = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfVectorLength())); 1648 1649 if (!arrayMode.isOutOfBounds()) 1650 speculationCheck(OutOfBounds, JSValueRegs(), 0, slowCase); 1651 1652 m_jit.add32(TrustedImm32(1), propertyReg, temporaryReg); 1653 m_jit.store32(temporaryReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())); 1654 1655 inBounds.link(&m_jit); 1656 } 1657 1658 m_jit.storeDouble(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight)); 1659 1660 base.use(); 1661 property.use(); 1662 value.use(); 1663 storage.use(); 1664 1665 if (arrayMode.isOutOfBounds()) { 1666 addSlowPathGenerator( 1667 slowPathCall( 1668 slowCase, this, 1669 m_jit.codeBlock()->isStrictMode() ? operationPutDoubleByValBeyondArrayBoundsStrict : operationPutDoubleByValBeyondArrayBoundsNonStrict, 1670 NoResult, baseReg, propertyReg, valueReg)); 1671 } 1672 1673 noResult(m_currentNode, UseChildrenCalledExplicitly); 1674} 1675 1676void SpeculativeJIT::compileGetCharCodeAt(Node* node) 1677{ 1678 SpeculateCellOperand string(this, node->child1()); 1679 SpeculateStrictInt32Operand index(this, node->child2()); 1680 StorageOperand storage(this, node->child3()); 1681 1682 GPRReg stringReg = string.gpr(); 1683 GPRReg indexReg = index.gpr(); 1684 GPRReg storageReg = storage.gpr(); 1685 1686 ASSERT(speculationChecked(m_state.forNode(node->child1()).m_type, SpecString)); 1687 1688 // unsigned comparison so we can filter out negative indices and indices that are too large 1689 speculationCheck(Uncountable, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::AboveOrEqual, indexReg, MacroAssembler::Address(stringReg, JSString::offsetOfLength()))); 1690 1691 GPRTemporary scratch(this); 1692 GPRReg scratchReg = scratch.gpr(); 1693 1694 m_jit.loadPtr(MacroAssembler::Address(stringReg, JSString::offsetOfValue()), scratchReg); 1695 1696 // Load the character into scratchReg 1697 JITCompiler::Jump is16Bit = m_jit.branchTest32(MacroAssembler::Zero, MacroAssembler::Address(scratchReg, StringImpl::flagsOffset()), TrustedImm32(StringImpl::flagIs8Bit())); 1698 1699 m_jit.load8(MacroAssembler::BaseIndex(storageReg, indexReg, MacroAssembler::TimesOne, 0), scratchReg); 1700 JITCompiler::Jump cont8Bit = m_jit.jump(); 1701 1702 is16Bit.link(&m_jit); 1703 1704 m_jit.load16(MacroAssembler::BaseIndex(storageReg, indexReg, MacroAssembler::TimesTwo, 0), scratchReg); 1705 1706 cont8Bit.link(&m_jit); 1707 1708 int32Result(scratchReg, m_currentNode); 1709} 1710 1711void SpeculativeJIT::compileGetByValOnString(Node* node) 1712{ 1713 SpeculateCellOperand base(this, node->child1()); 1714 SpeculateStrictInt32Operand property(this, node->child2()); 1715 StorageOperand storage(this, node->child3()); 1716 GPRReg baseReg = base.gpr(); 1717 GPRReg propertyReg = property.gpr(); 1718 GPRReg storageReg = storage.gpr(); 1719 1720 GPRTemporary scratch(this); 1721 GPRReg scratchReg = scratch.gpr(); 1722#if USE(JSVALUE32_64) 1723 GPRTemporary resultTag; 1724 GPRReg resultTagReg = InvalidGPRReg; 1725 if (node->arrayMode().isOutOfBounds()) { 1726 GPRTemporary realResultTag(this); 1727 resultTag.adopt(realResultTag); 1728 resultTagReg = resultTag.gpr(); 1729 } 1730#endif 1731 1732 ASSERT(ArrayMode(Array::String).alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1()))); 1733 1734 // unsigned comparison so we can filter out negative indices and indices that are too large 1735 JITCompiler::Jump outOfBounds = m_jit.branch32( 1736 MacroAssembler::AboveOrEqual, propertyReg, 1737 MacroAssembler::Address(baseReg, JSString::offsetOfLength())); 1738 if (node->arrayMode().isInBounds()) 1739 speculationCheck(OutOfBounds, JSValueRegs(), 0, outOfBounds); 1740 1741 m_jit.loadPtr(MacroAssembler::Address(baseReg, JSString::offsetOfValue()), scratchReg); 1742 1743 // Load the character into scratchReg 1744 JITCompiler::Jump is16Bit = m_jit.branchTest32(MacroAssembler::Zero, MacroAssembler::Address(scratchReg, StringImpl::flagsOffset()), TrustedImm32(StringImpl::flagIs8Bit())); 1745 1746 m_jit.load8(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesOne, 0), scratchReg); 1747 JITCompiler::Jump cont8Bit = m_jit.jump(); 1748 1749 is16Bit.link(&m_jit); 1750 1751 m_jit.load16(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesTwo, 0), scratchReg); 1752 1753 JITCompiler::Jump bigCharacter = 1754 m_jit.branch32(MacroAssembler::AboveOrEqual, scratchReg, TrustedImm32(0x100)); 1755 1756 // 8 bit string values don't need the isASCII check. 1757 cont8Bit.link(&m_jit); 1758 1759 m_jit.lshift32(MacroAssembler::TrustedImm32(sizeof(void*) == 4 ? 2 : 3), scratchReg); 1760 m_jit.addPtr(MacroAssembler::TrustedImmPtr(m_jit.vm()->smallStrings.singleCharacterStrings()), scratchReg); 1761 m_jit.loadPtr(scratchReg, scratchReg); 1762 1763 addSlowPathGenerator( 1764 slowPathCall( 1765 bigCharacter, this, operationSingleCharacterString, scratchReg, scratchReg)); 1766 1767 if (node->arrayMode().isOutOfBounds()) { 1768#if USE(JSVALUE32_64) 1769 m_jit.move(TrustedImm32(JSValue::CellTag), resultTagReg); 1770#endif 1771 1772 JSGlobalObject* globalObject = m_jit.globalObjectFor(node->origin.semantic); 1773 if (globalObject->stringPrototypeChainIsSane()) { 1774#if USE(JSVALUE64) 1775 addSlowPathGenerator(adoptPtr(new SaneStringGetByValSlowPathGenerator( 1776 outOfBounds, this, JSValueRegs(scratchReg), baseReg, propertyReg))); 1777#else 1778 addSlowPathGenerator(adoptPtr(new SaneStringGetByValSlowPathGenerator( 1779 outOfBounds, this, JSValueRegs(resultTagReg, scratchReg), 1780 baseReg, propertyReg))); 1781#endif 1782 } else { 1783#if USE(JSVALUE64) 1784 addSlowPathGenerator( 1785 slowPathCall( 1786 outOfBounds, this, operationGetByValStringInt, 1787 scratchReg, baseReg, propertyReg)); 1788#else 1789 addSlowPathGenerator( 1790 slowPathCall( 1791 outOfBounds, this, operationGetByValStringInt, 1792 resultTagReg, scratchReg, baseReg, propertyReg)); 1793#endif 1794 } 1795 1796#if USE(JSVALUE64) 1797 jsValueResult(scratchReg, m_currentNode); 1798#else 1799 jsValueResult(resultTagReg, scratchReg, m_currentNode); 1800#endif 1801 } else 1802 cellResult(scratchReg, m_currentNode); 1803} 1804 1805void SpeculativeJIT::compileFromCharCode(Node* node) 1806{ 1807 SpeculateStrictInt32Operand property(this, node->child1()); 1808 GPRReg propertyReg = property.gpr(); 1809 GPRTemporary smallStrings(this); 1810 GPRTemporary scratch(this); 1811 GPRReg scratchReg = scratch.gpr(); 1812 GPRReg smallStringsReg = smallStrings.gpr(); 1813 1814 JITCompiler::JumpList slowCases; 1815 slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, TrustedImm32(0xff))); 1816 m_jit.move(MacroAssembler::TrustedImmPtr(m_jit.vm()->smallStrings.singleCharacterStrings()), smallStringsReg); 1817 m_jit.loadPtr(MacroAssembler::BaseIndex(smallStringsReg, propertyReg, MacroAssembler::ScalePtr, 0), scratchReg); 1818 1819 slowCases.append(m_jit.branchTest32(MacroAssembler::Zero, scratchReg)); 1820 addSlowPathGenerator(slowPathCall(slowCases, this, operationStringFromCharCode, scratchReg, propertyReg)); 1821 cellResult(scratchReg, m_currentNode); 1822} 1823 1824GeneratedOperandType SpeculativeJIT::checkGeneratedTypeForToInt32(Node* node) 1825{ 1826 VirtualRegister virtualRegister = node->virtualRegister(); 1827 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister); 1828 1829 switch (info.registerFormat()) { 1830 case DataFormatStorage: 1831 RELEASE_ASSERT_NOT_REACHED(); 1832 1833 case DataFormatBoolean: 1834 case DataFormatCell: 1835 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); 1836 return GeneratedOperandTypeUnknown; 1837 1838 case DataFormatNone: 1839 case DataFormatJSCell: 1840 case DataFormatJS: 1841 case DataFormatJSBoolean: 1842 case DataFormatJSDouble: 1843 return GeneratedOperandJSValue; 1844 1845 case DataFormatJSInt32: 1846 case DataFormatInt32: 1847 return GeneratedOperandInteger; 1848 1849 default: 1850 RELEASE_ASSERT_NOT_REACHED(); 1851 return GeneratedOperandTypeUnknown; 1852 } 1853} 1854 1855void SpeculativeJIT::compileValueToInt32(Node* node) 1856{ 1857 switch (node->child1().useKind()) { 1858#if USE(JSVALUE64) 1859 case Int52RepUse: { 1860 SpeculateStrictInt52Operand op1(this, node->child1()); 1861 GPRTemporary result(this, Reuse, op1); 1862 GPRReg op1GPR = op1.gpr(); 1863 GPRReg resultGPR = result.gpr(); 1864 m_jit.zeroExtend32ToPtr(op1GPR, resultGPR); 1865 int32Result(resultGPR, node, DataFormatInt32); 1866 return; 1867 } 1868#endif // USE(JSVALUE64) 1869 1870 case DoubleRepUse: { 1871 GPRTemporary result(this); 1872 SpeculateDoubleOperand op1(this, node->child1()); 1873 FPRReg fpr = op1.fpr(); 1874 GPRReg gpr = result.gpr(); 1875 JITCompiler::Jump notTruncatedToInteger = m_jit.branchTruncateDoubleToInt32(fpr, gpr, JITCompiler::BranchIfTruncateFailed); 1876 1877 addSlowPathGenerator(slowPathCall(notTruncatedToInteger, this, toInt32, gpr, fpr)); 1878 1879 int32Result(gpr, node); 1880 return; 1881 } 1882 1883 case NumberUse: 1884 case NotCellUse: { 1885 switch (checkGeneratedTypeForToInt32(node->child1().node())) { 1886 case GeneratedOperandInteger: { 1887 SpeculateInt32Operand op1(this, node->child1(), ManualOperandSpeculation); 1888 GPRTemporary result(this, Reuse, op1); 1889 m_jit.move(op1.gpr(), result.gpr()); 1890 int32Result(result.gpr(), node, op1.format()); 1891 return; 1892 } 1893 case GeneratedOperandJSValue: { 1894 GPRTemporary result(this); 1895#if USE(JSVALUE64) 1896 JSValueOperand op1(this, node->child1(), ManualOperandSpeculation); 1897 1898 GPRReg gpr = op1.gpr(); 1899 GPRReg resultGpr = result.gpr(); 1900 FPRTemporary tempFpr(this); 1901 FPRReg fpr = tempFpr.fpr(); 1902 1903 JITCompiler::Jump isInteger = m_jit.branch64(MacroAssembler::AboveOrEqual, gpr, GPRInfo::tagTypeNumberRegister); 1904 JITCompiler::JumpList converted; 1905 1906 if (node->child1().useKind() == NumberUse) { 1907 DFG_TYPE_CHECK( 1908 JSValueRegs(gpr), node->child1(), SpecBytecodeNumber, 1909 m_jit.branchTest64( 1910 MacroAssembler::Zero, gpr, GPRInfo::tagTypeNumberRegister)); 1911 } else { 1912 JITCompiler::Jump isNumber = m_jit.branchTest64(MacroAssembler::NonZero, gpr, GPRInfo::tagTypeNumberRegister); 1913 1914 DFG_TYPE_CHECK( 1915 JSValueRegs(gpr), node->child1(), ~SpecCell, branchIsCell(JSValueRegs(gpr))); 1916 1917 // It's not a cell: so true turns into 1 and all else turns into 0. 1918 m_jit.compare64(JITCompiler::Equal, gpr, TrustedImm32(ValueTrue), resultGpr); 1919 converted.append(m_jit.jump()); 1920 1921 isNumber.link(&m_jit); 1922 } 1923 1924 // First, if we get here we have a double encoded as a JSValue 1925 m_jit.move(gpr, resultGpr); 1926 unboxDouble(resultGpr, fpr); 1927 1928 silentSpillAllRegisters(resultGpr); 1929 callOperation(toInt32, resultGpr, fpr); 1930 silentFillAllRegisters(resultGpr); 1931 1932 converted.append(m_jit.jump()); 1933 1934 isInteger.link(&m_jit); 1935 m_jit.zeroExtend32ToPtr(gpr, resultGpr); 1936 1937 converted.link(&m_jit); 1938#else 1939 Node* childNode = node->child1().node(); 1940 VirtualRegister virtualRegister = childNode->virtualRegister(); 1941 GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister); 1942 1943 JSValueOperand op1(this, node->child1(), ManualOperandSpeculation); 1944 1945 GPRReg payloadGPR = op1.payloadGPR(); 1946 GPRReg resultGpr = result.gpr(); 1947 1948 JITCompiler::JumpList converted; 1949 1950 if (info.registerFormat() == DataFormatJSInt32) 1951 m_jit.move(payloadGPR, resultGpr); 1952 else { 1953 GPRReg tagGPR = op1.tagGPR(); 1954 FPRTemporary tempFpr(this); 1955 FPRReg fpr = tempFpr.fpr(); 1956 FPRTemporary scratch(this); 1957 1958 JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, tagGPR, TrustedImm32(JSValue::Int32Tag)); 1959 1960 if (node->child1().useKind() == NumberUse) { 1961 DFG_TYPE_CHECK( 1962 op1.jsValueRegs(), node->child1(), SpecBytecodeNumber, 1963 m_jit.branch32( 1964 MacroAssembler::AboveOrEqual, tagGPR, 1965 TrustedImm32(JSValue::LowestTag))); 1966 } else { 1967 JITCompiler::Jump isNumber = m_jit.branch32(MacroAssembler::Below, tagGPR, TrustedImm32(JSValue::LowestTag)); 1968 1969 DFG_TYPE_CHECK( 1970 op1.jsValueRegs(), node->child1(), ~SpecCell, 1971 branchIsCell(op1.jsValueRegs())); 1972 1973 // It's not a cell: so true turns into 1 and all else turns into 0. 1974 JITCompiler::Jump isBoolean = m_jit.branch32(JITCompiler::Equal, tagGPR, TrustedImm32(JSValue::BooleanTag)); 1975 m_jit.move(TrustedImm32(0), resultGpr); 1976 converted.append(m_jit.jump()); 1977 1978 isBoolean.link(&m_jit); 1979 m_jit.move(payloadGPR, resultGpr); 1980 converted.append(m_jit.jump()); 1981 1982 isNumber.link(&m_jit); 1983 } 1984 1985 unboxDouble(tagGPR, payloadGPR, fpr, scratch.fpr()); 1986 1987 silentSpillAllRegisters(resultGpr); 1988 callOperation(toInt32, resultGpr, fpr); 1989 silentFillAllRegisters(resultGpr); 1990 1991 converted.append(m_jit.jump()); 1992 1993 isInteger.link(&m_jit); 1994 m_jit.move(payloadGPR, resultGpr); 1995 1996 converted.link(&m_jit); 1997 } 1998#endif 1999 int32Result(resultGpr, node); 2000 return; 2001 } 2002 case GeneratedOperandTypeUnknown: 2003 RELEASE_ASSERT(!m_compileOkay); 2004 return; 2005 } 2006 RELEASE_ASSERT_NOT_REACHED(); 2007 return; 2008 } 2009 2010 default: 2011 ASSERT(!m_compileOkay); 2012 return; 2013 } 2014} 2015 2016void SpeculativeJIT::compileUInt32ToNumber(Node* node) 2017{ 2018 if (doesOverflow(node->arithMode())) { 2019 // We know that this sometimes produces doubles. So produce a double every 2020 // time. This at least allows subsequent code to not have weird conditionals. 2021 2022 SpeculateInt32Operand op1(this, node->child1()); 2023 FPRTemporary result(this); 2024 2025 GPRReg inputGPR = op1.gpr(); 2026 FPRReg outputFPR = result.fpr(); 2027 2028 m_jit.convertInt32ToDouble(inputGPR, outputFPR); 2029 2030 JITCompiler::Jump positive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, inputGPR, TrustedImm32(0)); 2031 m_jit.addDouble(JITCompiler::AbsoluteAddress(&AssemblyHelpers::twoToThe32), outputFPR); 2032 positive.link(&m_jit); 2033 2034 doubleResult(outputFPR, node); 2035 return; 2036 } 2037 2038 RELEASE_ASSERT(node->arithMode() == Arith::CheckOverflow); 2039 2040 SpeculateInt32Operand op1(this, node->child1()); 2041 GPRTemporary result(this); 2042 2043 m_jit.move(op1.gpr(), result.gpr()); 2044 2045 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::LessThan, result.gpr(), TrustedImm32(0))); 2046 2047 int32Result(result.gpr(), node, op1.format()); 2048} 2049 2050void SpeculativeJIT::compileDoubleAsInt32(Node* node) 2051{ 2052 SpeculateDoubleOperand op1(this, node->child1()); 2053 FPRTemporary scratch(this); 2054 GPRTemporary result(this); 2055 2056 FPRReg valueFPR = op1.fpr(); 2057 FPRReg scratchFPR = scratch.fpr(); 2058 GPRReg resultGPR = result.gpr(); 2059 2060 JITCompiler::JumpList failureCases; 2061 RELEASE_ASSERT(shouldCheckOverflow(node->arithMode())); 2062 m_jit.branchConvertDoubleToInt32( 2063 valueFPR, resultGPR, failureCases, scratchFPR, 2064 shouldCheckNegativeZero(node->arithMode())); 2065 speculationCheck(Overflow, JSValueRegs(), 0, failureCases); 2066 2067 int32Result(resultGPR, node); 2068} 2069 2070void SpeculativeJIT::compileDoubleRep(Node* node) 2071{ 2072 switch (node->child1().useKind()) { 2073 case NumberUse: { 2074 ASSERT(!isNumberConstant(node->child1().node())); // This should have been constant folded. 2075 2076 if (isInt32Speculation(m_state.forNode(node->child1()).m_type)) { 2077 SpeculateInt32Operand op1(this, node->child1(), ManualOperandSpeculation); 2078 FPRTemporary result(this); 2079 m_jit.convertInt32ToDouble(op1.gpr(), result.fpr()); 2080 doubleResult(result.fpr(), node); 2081 return; 2082 } 2083 2084 JSValueOperand op1(this, node->child1(), ManualOperandSpeculation); 2085 FPRTemporary result(this); 2086 2087#if USE(JSVALUE64) 2088 GPRTemporary temp(this); 2089 2090 GPRReg op1GPR = op1.gpr(); 2091 GPRReg tempGPR = temp.gpr(); 2092 FPRReg resultFPR = result.fpr(); 2093 2094 JITCompiler::Jump isInteger = m_jit.branch64( 2095 MacroAssembler::AboveOrEqual, op1GPR, GPRInfo::tagTypeNumberRegister); 2096 2097 if (needsTypeCheck(node->child1(), SpecBytecodeNumber)) { 2098 typeCheck( 2099 JSValueRegs(op1GPR), node->child1(), SpecBytecodeNumber, 2100 m_jit.branchTest64(MacroAssembler::Zero, op1GPR, GPRInfo::tagTypeNumberRegister)); 2101 } 2102 2103 m_jit.move(op1GPR, tempGPR); 2104 unboxDouble(tempGPR, resultFPR); 2105 JITCompiler::Jump done = m_jit.jump(); 2106 2107 isInteger.link(&m_jit); 2108 m_jit.convertInt32ToDouble(op1GPR, resultFPR); 2109 done.link(&m_jit); 2110#else // USE(JSVALUE64) -> this is the 32_64 case 2111 FPRTemporary temp(this); 2112 2113 GPRReg op1TagGPR = op1.tagGPR(); 2114 GPRReg op1PayloadGPR = op1.payloadGPR(); 2115 FPRReg tempFPR = temp.fpr(); 2116 FPRReg resultFPR = result.fpr(); 2117 2118 JITCompiler::Jump isInteger = m_jit.branch32( 2119 MacroAssembler::Equal, op1TagGPR, TrustedImm32(JSValue::Int32Tag)); 2120 2121 if (needsTypeCheck(node->child1(), SpecBytecodeNumber)) { 2122 typeCheck( 2123 JSValueRegs(op1TagGPR, op1PayloadGPR), node->child1(), SpecBytecodeNumber, 2124 m_jit.branch32(MacroAssembler::AboveOrEqual, op1TagGPR, TrustedImm32(JSValue::LowestTag))); 2125 } 2126 2127 unboxDouble(op1TagGPR, op1PayloadGPR, resultFPR, tempFPR); 2128 JITCompiler::Jump done = m_jit.jump(); 2129 2130 isInteger.link(&m_jit); 2131 m_jit.convertInt32ToDouble(op1PayloadGPR, resultFPR); 2132 done.link(&m_jit); 2133#endif // USE(JSVALUE64) 2134 2135 doubleResult(resultFPR, node); 2136 return; 2137 } 2138 2139#if USE(JSVALUE64) 2140 case Int52RepUse: { 2141 SpeculateStrictInt52Operand value(this, node->child1()); 2142 FPRTemporary result(this); 2143 2144 GPRReg valueGPR = value.gpr(); 2145 FPRReg resultFPR = result.fpr(); 2146 2147 m_jit.convertInt64ToDouble(valueGPR, resultFPR); 2148 2149 doubleResult(resultFPR, node); 2150 return; 2151 } 2152#endif // USE(JSVALUE64) 2153 2154 default: 2155 RELEASE_ASSERT_NOT_REACHED(); 2156 return; 2157 } 2158} 2159 2160void SpeculativeJIT::compileValueRep(Node* node) 2161{ 2162 switch (node->child1().useKind()) { 2163 case DoubleRepUse: { 2164 SpeculateDoubleOperand value(this, node->child1()); 2165 JSValueRegsTemporary result(this); 2166 2167 FPRReg valueFPR = value.fpr(); 2168 JSValueRegs resultRegs = result.regs(); 2169 2170 // It's very tempting to in-place filter the value to indicate that it's not impure NaN 2171 // anymore. Unfortunately, this would be unsound. If it's a GetLocal or if the value was 2172 // subject to a prior SetLocal, filtering the value would imply that the corresponding 2173 // local was purified. 2174 if (needsTypeCheck(node->child1(), ~SpecDoubleImpureNaN)) 2175 m_jit.purifyNaN(valueFPR); 2176 2177#if CPU(X86) 2178 // boxDouble() on X86 clobbers the source, so we need to copy. 2179 // FIXME: Don't do that! https://bugs.webkit.org/show_bug.cgi?id=131690 2180 FPRTemporary temp(this); 2181 m_jit.moveDouble(valueFPR, temp.fpr()); 2182 valueFPR = temp.fpr(); 2183#endif 2184 2185 boxDouble(valueFPR, resultRegs); 2186 2187 jsValueResult(resultRegs, node); 2188 return; 2189 } 2190 2191#if USE(JSVALUE64) 2192 case Int52RepUse: { 2193 SpeculateStrictInt52Operand value(this, node->child1()); 2194 GPRTemporary result(this); 2195 2196 GPRReg valueGPR = value.gpr(); 2197 GPRReg resultGPR = result.gpr(); 2198 2199 boxInt52(valueGPR, resultGPR, DataFormatStrictInt52); 2200 2201 jsValueResult(resultGPR, node); 2202 return; 2203 } 2204#endif // USE(JSVALUE64) 2205 2206 default: 2207 RELEASE_ASSERT_NOT_REACHED(); 2208 return; 2209 } 2210} 2211 2212static double clampDoubleToByte(double d) 2213{ 2214 d += 0.5; 2215 if (!(d > 0)) 2216 d = 0; 2217 else if (d > 255) 2218 d = 255; 2219 return d; 2220} 2221 2222static void compileClampIntegerToByte(JITCompiler& jit, GPRReg result) 2223{ 2224 MacroAssembler::Jump inBounds = jit.branch32(MacroAssembler::BelowOrEqual, result, JITCompiler::TrustedImm32(0xff)); 2225 MacroAssembler::Jump tooBig = jit.branch32(MacroAssembler::GreaterThan, result, JITCompiler::TrustedImm32(0xff)); 2226 jit.xorPtr(result, result); 2227 MacroAssembler::Jump clamped = jit.jump(); 2228 tooBig.link(&jit); 2229 jit.move(JITCompiler::TrustedImm32(255), result); 2230 clamped.link(&jit); 2231 inBounds.link(&jit); 2232} 2233 2234static void compileClampDoubleToByte(JITCompiler& jit, GPRReg result, FPRReg source, FPRReg scratch) 2235{ 2236 // Unordered compare so we pick up NaN 2237 static const double zero = 0; 2238 static const double byteMax = 255; 2239 static const double half = 0.5; 2240 jit.loadDouble(MacroAssembler::TrustedImmPtr(&zero), scratch); 2241 MacroAssembler::Jump tooSmall = jit.branchDouble(MacroAssembler::DoubleLessThanOrEqualOrUnordered, source, scratch); 2242 jit.loadDouble(MacroAssembler::TrustedImmPtr(&byteMax), scratch); 2243 MacroAssembler::Jump tooBig = jit.branchDouble(MacroAssembler::DoubleGreaterThan, source, scratch); 2244 2245 jit.loadDouble(MacroAssembler::TrustedImmPtr(&half), scratch); 2246 // FIXME: This should probably just use a floating point round! 2247 // https://bugs.webkit.org/show_bug.cgi?id=72054 2248 jit.addDouble(source, scratch); 2249 jit.truncateDoubleToInt32(scratch, result); 2250 MacroAssembler::Jump truncatedInt = jit.jump(); 2251 2252 tooSmall.link(&jit); 2253 jit.xorPtr(result, result); 2254 MacroAssembler::Jump zeroed = jit.jump(); 2255 2256 tooBig.link(&jit); 2257 jit.move(JITCompiler::TrustedImm32(255), result); 2258 2259 truncatedInt.link(&jit); 2260 zeroed.link(&jit); 2261 2262} 2263 2264JITCompiler::Jump SpeculativeJIT::jumpForTypedArrayOutOfBounds(Node* node, GPRReg baseGPR, GPRReg indexGPR) 2265{ 2266 if (node->op() == PutByValAlias) 2267 return JITCompiler::Jump(); 2268 if (JSArrayBufferView* view = m_jit.graph().tryGetFoldableViewForChild1(node)) { 2269 uint32_t length = view->length(); 2270 Node* indexNode = m_jit.graph().child(node, 1).node(); 2271 if (m_jit.graph().isInt32Constant(indexNode) && static_cast<uint32_t>(m_jit.graph().valueOfInt32Constant(indexNode)) < length) 2272 return JITCompiler::Jump(); 2273 return m_jit.branch32( 2274 MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Imm32(length)); 2275 } 2276 return m_jit.branch32( 2277 MacroAssembler::AboveOrEqual, indexGPR, 2278 MacroAssembler::Address(baseGPR, JSArrayBufferView::offsetOfLength())); 2279} 2280 2281void SpeculativeJIT::emitTypedArrayBoundsCheck(Node* node, GPRReg baseGPR, GPRReg indexGPR) 2282{ 2283 JITCompiler::Jump jump = jumpForTypedArrayOutOfBounds(node, baseGPR, indexGPR); 2284 if (!jump.isSet()) 2285 return; 2286 speculationCheck(OutOfBounds, JSValueRegs(), 0, jump); 2287} 2288 2289void SpeculativeJIT::compileGetByValOnIntTypedArray(Node* node, TypedArrayType type) 2290{ 2291 ASSERT(isInt(type)); 2292 2293 SpeculateCellOperand base(this, node->child1()); 2294 SpeculateStrictInt32Operand property(this, node->child2()); 2295 StorageOperand storage(this, node->child3()); 2296 2297 GPRReg baseReg = base.gpr(); 2298 GPRReg propertyReg = property.gpr(); 2299 GPRReg storageReg = storage.gpr(); 2300 2301 GPRTemporary result(this); 2302 GPRReg resultReg = result.gpr(); 2303 2304 ASSERT(node->arrayMode().alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1()))); 2305 2306 emitTypedArrayBoundsCheck(node, baseReg, propertyReg); 2307 switch (elementSize(type)) { 2308 case 1: 2309 if (isSigned(type)) 2310 m_jit.load8Signed(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesOne), resultReg); 2311 else 2312 m_jit.load8(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesOne), resultReg); 2313 break; 2314 case 2: 2315 if (isSigned(type)) 2316 m_jit.load16Signed(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesTwo), resultReg); 2317 else 2318 m_jit.load16(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesTwo), resultReg); 2319 break; 2320 case 4: 2321 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesFour), resultReg); 2322 break; 2323 default: 2324 CRASH(); 2325 } 2326 if (elementSize(type) < 4 || isSigned(type)) { 2327 int32Result(resultReg, node); 2328 return; 2329 } 2330 2331 ASSERT(elementSize(type) == 4 && !isSigned(type)); 2332 if (node->shouldSpeculateInt32()) { 2333 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::LessThan, resultReg, TrustedImm32(0))); 2334 int32Result(resultReg, node); 2335 return; 2336 } 2337 2338#if USE(JSVALUE64) 2339 if (node->shouldSpeculateMachineInt()) { 2340 m_jit.zeroExtend32ToPtr(resultReg, resultReg); 2341 strictInt52Result(resultReg, node); 2342 return; 2343 } 2344#endif 2345 2346 FPRTemporary fresult(this); 2347 m_jit.convertInt32ToDouble(resultReg, fresult.fpr()); 2348 JITCompiler::Jump positive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, resultReg, TrustedImm32(0)); 2349 m_jit.addDouble(JITCompiler::AbsoluteAddress(&AssemblyHelpers::twoToThe32), fresult.fpr()); 2350 positive.link(&m_jit); 2351 doubleResult(fresult.fpr(), node); 2352} 2353 2354void SpeculativeJIT::compilePutByValForIntTypedArray(GPRReg base, GPRReg property, Node* node, TypedArrayType type) 2355{ 2356 ASSERT(isInt(type)); 2357 2358 StorageOperand storage(this, m_jit.graph().varArgChild(node, 3)); 2359 GPRReg storageReg = storage.gpr(); 2360 2361 Edge valueUse = m_jit.graph().varArgChild(node, 2); 2362 2363 GPRTemporary value; 2364 GPRReg valueGPR = InvalidGPRReg; 2365 2366 if (valueUse->isConstant()) { 2367 JSValue jsValue = valueOfJSConstant(valueUse.node()); 2368 if (!jsValue.isNumber()) { 2369 terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); 2370 noResult(node); 2371 return; 2372 } 2373 double d = jsValue.asNumber(); 2374 if (isClamped(type)) { 2375 ASSERT(elementSize(type) == 1); 2376 d = clampDoubleToByte(d); 2377 } 2378 GPRTemporary scratch(this); 2379 GPRReg scratchReg = scratch.gpr(); 2380 m_jit.move(Imm32(toInt32(d)), scratchReg); 2381 value.adopt(scratch); 2382 valueGPR = scratchReg; 2383 } else { 2384 switch (valueUse.useKind()) { 2385 case Int32Use: { 2386 SpeculateInt32Operand valueOp(this, valueUse); 2387 GPRTemporary scratch(this); 2388 GPRReg scratchReg = scratch.gpr(); 2389 m_jit.move(valueOp.gpr(), scratchReg); 2390 if (isClamped(type)) { 2391 ASSERT(elementSize(type) == 1); 2392 compileClampIntegerToByte(m_jit, scratchReg); 2393 } 2394 value.adopt(scratch); 2395 valueGPR = scratchReg; 2396 break; 2397 } 2398 2399#if USE(JSVALUE64) 2400 case Int52RepUse: { 2401 SpeculateStrictInt52Operand valueOp(this, valueUse); 2402 GPRTemporary scratch(this); 2403 GPRReg scratchReg = scratch.gpr(); 2404 m_jit.move(valueOp.gpr(), scratchReg); 2405 if (isClamped(type)) { 2406 ASSERT(elementSize(type) == 1); 2407 MacroAssembler::Jump inBounds = m_jit.branch64( 2408 MacroAssembler::BelowOrEqual, scratchReg, JITCompiler::TrustedImm64(0xff)); 2409 MacroAssembler::Jump tooBig = m_jit.branch64( 2410 MacroAssembler::GreaterThan, scratchReg, JITCompiler::TrustedImm64(0xff)); 2411 m_jit.move(TrustedImm32(0), scratchReg); 2412 MacroAssembler::Jump clamped = m_jit.jump(); 2413 tooBig.link(&m_jit); 2414 m_jit.move(JITCompiler::TrustedImm32(255), scratchReg); 2415 clamped.link(&m_jit); 2416 inBounds.link(&m_jit); 2417 } 2418 value.adopt(scratch); 2419 valueGPR = scratchReg; 2420 break; 2421 } 2422#endif // USE(JSVALUE64) 2423 2424 case DoubleRepUse: { 2425 if (isClamped(type)) { 2426 ASSERT(elementSize(type) == 1); 2427 SpeculateDoubleOperand valueOp(this, valueUse); 2428 GPRTemporary result(this); 2429 FPRTemporary floatScratch(this); 2430 FPRReg fpr = valueOp.fpr(); 2431 GPRReg gpr = result.gpr(); 2432 compileClampDoubleToByte(m_jit, gpr, fpr, floatScratch.fpr()); 2433 value.adopt(result); 2434 valueGPR = gpr; 2435 } else { 2436 SpeculateDoubleOperand valueOp(this, valueUse); 2437 GPRTemporary result(this); 2438 FPRReg fpr = valueOp.fpr(); 2439 GPRReg gpr = result.gpr(); 2440 MacroAssembler::Jump notNaN = m_jit.branchDouble(MacroAssembler::DoubleEqual, fpr, fpr); 2441 m_jit.xorPtr(gpr, gpr); 2442 MacroAssembler::Jump fixed = m_jit.jump(); 2443 notNaN.link(&m_jit); 2444 2445 MacroAssembler::Jump failed = m_jit.branchTruncateDoubleToInt32( 2446 fpr, gpr, MacroAssembler::BranchIfTruncateFailed); 2447 2448 addSlowPathGenerator(slowPathCall(failed, this, toInt32, gpr, fpr)); 2449 2450 fixed.link(&m_jit); 2451 value.adopt(result); 2452 valueGPR = gpr; 2453 } 2454 break; 2455 } 2456 2457 default: 2458 RELEASE_ASSERT_NOT_REACHED(); 2459 break; 2460 } 2461 } 2462 2463 ASSERT_UNUSED(valueGPR, valueGPR != property); 2464 ASSERT(valueGPR != base); 2465 ASSERT(valueGPR != storageReg); 2466 MacroAssembler::Jump outOfBounds = jumpForTypedArrayOutOfBounds(node, base, property); 2467 if (node->arrayMode().isInBounds() && outOfBounds.isSet()) { 2468 speculationCheck(OutOfBounds, JSValueSource(), 0, outOfBounds); 2469 outOfBounds = MacroAssembler::Jump(); 2470 } 2471 2472 switch (elementSize(type)) { 2473 case 1: 2474 m_jit.store8(value.gpr(), MacroAssembler::BaseIndex(storageReg, property, MacroAssembler::TimesOne)); 2475 break; 2476 case 2: 2477 m_jit.store16(value.gpr(), MacroAssembler::BaseIndex(storageReg, property, MacroAssembler::TimesTwo)); 2478 break; 2479 case 4: 2480 m_jit.store32(value.gpr(), MacroAssembler::BaseIndex(storageReg, property, MacroAssembler::TimesFour)); 2481 break; 2482 default: 2483 CRASH(); 2484 } 2485 if (outOfBounds.isSet()) 2486 outOfBounds.link(&m_jit); 2487 noResult(node); 2488} 2489 2490void SpeculativeJIT::compileGetByValOnFloatTypedArray(Node* node, TypedArrayType type) 2491{ 2492 ASSERT(isFloat(type)); 2493 2494 SpeculateCellOperand base(this, node->child1()); 2495 SpeculateStrictInt32Operand property(this, node->child2()); 2496 StorageOperand storage(this, node->child3()); 2497 2498 GPRReg baseReg = base.gpr(); 2499 GPRReg propertyReg = property.gpr(); 2500 GPRReg storageReg = storage.gpr(); 2501 2502 ASSERT(node->arrayMode().alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1()))); 2503 2504 FPRTemporary result(this); 2505 FPRReg resultReg = result.fpr(); 2506 emitTypedArrayBoundsCheck(node, baseReg, propertyReg); 2507 switch (elementSize(type)) { 2508 case 4: 2509 m_jit.loadFloat(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesFour), resultReg); 2510 m_jit.convertFloatToDouble(resultReg, resultReg); 2511 break; 2512 case 8: { 2513 m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), resultReg); 2514 break; 2515 } 2516 default: 2517 RELEASE_ASSERT_NOT_REACHED(); 2518 } 2519 2520 doubleResult(resultReg, node); 2521} 2522 2523void SpeculativeJIT::compilePutByValForFloatTypedArray(GPRReg base, GPRReg property, Node* node, TypedArrayType type) 2524{ 2525 ASSERT(isFloat(type)); 2526 2527 StorageOperand storage(this, m_jit.graph().varArgChild(node, 3)); 2528 GPRReg storageReg = storage.gpr(); 2529 2530 Edge baseUse = m_jit.graph().varArgChild(node, 0); 2531 Edge valueUse = m_jit.graph().varArgChild(node, 2); 2532 2533 SpeculateDoubleOperand valueOp(this, valueUse); 2534 FPRTemporary scratch(this); 2535 FPRReg valueFPR = valueOp.fpr(); 2536 FPRReg scratchFPR = scratch.fpr(); 2537 2538 ASSERT_UNUSED(baseUse, node->arrayMode().alreadyChecked(m_jit.graph(), node, m_state.forNode(baseUse))); 2539 2540 MacroAssembler::Jump outOfBounds = jumpForTypedArrayOutOfBounds(node, base, property); 2541 if (node->arrayMode().isInBounds() && outOfBounds.isSet()) { 2542 speculationCheck(OutOfBounds, JSValueSource(), 0, outOfBounds); 2543 outOfBounds = MacroAssembler::Jump(); 2544 } 2545 2546 switch (elementSize(type)) { 2547 case 4: { 2548 m_jit.moveDouble(valueFPR, scratchFPR); 2549 m_jit.convertDoubleToFloat(valueFPR, scratchFPR); 2550 m_jit.storeFloat(scratchFPR, MacroAssembler::BaseIndex(storageReg, property, MacroAssembler::TimesFour)); 2551 break; 2552 } 2553 case 8: 2554 m_jit.storeDouble(valueFPR, MacroAssembler::BaseIndex(storageReg, property, MacroAssembler::TimesEight)); 2555 break; 2556 default: 2557 RELEASE_ASSERT_NOT_REACHED(); 2558 } 2559 if (outOfBounds.isSet()) 2560 outOfBounds.link(&m_jit); 2561 noResult(node); 2562} 2563 2564void SpeculativeJIT::compileInstanceOfForObject(Node*, GPRReg valueReg, GPRReg prototypeReg, GPRReg scratchReg, GPRReg scratch2Reg) 2565{ 2566 // Check that prototype is an object. 2567 speculationCheck(BadType, JSValueRegs(), 0, m_jit.branchIfCellNotObject(prototypeReg)); 2568 2569 // Initialize scratchReg with the value being checked. 2570 m_jit.move(valueReg, scratchReg); 2571 2572 // Walk up the prototype chain of the value (in scratchReg), comparing to prototypeReg. 2573 MacroAssembler::Label loop(&m_jit); 2574 m_jit.emitLoadStructure(scratchReg, scratchReg, scratch2Reg); 2575 m_jit.loadPtr(MacroAssembler::Address(scratchReg, Structure::prototypeOffset() + CellPayloadOffset), scratchReg); 2576 MacroAssembler::Jump isInstance = m_jit.branchPtr(MacroAssembler::Equal, scratchReg, prototypeReg); 2577#if USE(JSVALUE64) 2578 branchIsCell(JSValueRegs(scratchReg)).linkTo(loop, &m_jit); 2579#else 2580 m_jit.branchTestPtr(MacroAssembler::NonZero, scratchReg).linkTo(loop, &m_jit); 2581#endif 2582 2583 // No match - result is false. 2584#if USE(JSVALUE64) 2585 m_jit.move(MacroAssembler::TrustedImm64(JSValue::encode(jsBoolean(false))), scratchReg); 2586#else 2587 m_jit.move(MacroAssembler::TrustedImm32(0), scratchReg); 2588#endif 2589 MacroAssembler::Jump putResult = m_jit.jump(); 2590 2591 isInstance.link(&m_jit); 2592#if USE(JSVALUE64) 2593 m_jit.move(MacroAssembler::TrustedImm64(JSValue::encode(jsBoolean(true))), scratchReg); 2594#else 2595 m_jit.move(MacroAssembler::TrustedImm32(1), scratchReg); 2596#endif 2597 2598 putResult.link(&m_jit); 2599} 2600 2601void SpeculativeJIT::compileInstanceOf(Node* node) 2602{ 2603 if (node->child1().useKind() == UntypedUse) { 2604 // It might not be a cell. Speculate less aggressively. 2605 // Or: it might only be used once (i.e. by us), so we get zero benefit 2606 // from speculating any more aggressively than we absolutely need to. 2607 2608 JSValueOperand value(this, node->child1()); 2609 SpeculateCellOperand prototype(this, node->child2()); 2610 GPRTemporary scratch(this); 2611 GPRTemporary scratch2(this); 2612 2613 GPRReg prototypeReg = prototype.gpr(); 2614 GPRReg scratchReg = scratch.gpr(); 2615 GPRReg scratch2Reg = scratch2.gpr(); 2616 2617 MacroAssembler::Jump isCell = branchIsCell(value.jsValueRegs()); 2618 GPRReg valueReg = value.jsValueRegs().payloadGPR(); 2619 moveFalseTo(scratchReg); 2620 2621 MacroAssembler::Jump done = m_jit.jump(); 2622 2623 isCell.link(&m_jit); 2624 2625 compileInstanceOfForObject(node, valueReg, prototypeReg, scratchReg, scratch2Reg); 2626 2627 done.link(&m_jit); 2628 2629 blessedBooleanResult(scratchReg, node); 2630 return; 2631 } 2632 2633 SpeculateCellOperand value(this, node->child1()); 2634 SpeculateCellOperand prototype(this, node->child2()); 2635 2636 GPRTemporary scratch(this); 2637 GPRTemporary scratch2(this); 2638 2639 GPRReg valueReg = value.gpr(); 2640 GPRReg prototypeReg = prototype.gpr(); 2641 GPRReg scratchReg = scratch.gpr(); 2642 GPRReg scratch2Reg = scratch2.gpr(); 2643 2644 compileInstanceOfForObject(node, valueReg, prototypeReg, scratchReg, scratch2Reg); 2645 2646 blessedBooleanResult(scratchReg, node); 2647} 2648 2649void SpeculativeJIT::compileAdd(Node* node) 2650{ 2651 switch (node->binaryUseKind()) { 2652 case Int32Use: { 2653 ASSERT(!shouldCheckNegativeZero(node->arithMode())); 2654 2655 if (isInt32Constant(node->child1().node())) { 2656 int32_t imm1 = valueOfInt32Constant(node->child1().node()); 2657 SpeculateInt32Operand op2(this, node->child2()); 2658 GPRTemporary result(this); 2659 2660 if (!shouldCheckOverflow(node->arithMode())) { 2661 m_jit.move(op2.gpr(), result.gpr()); 2662 m_jit.add32(Imm32(imm1), result.gpr()); 2663 } else 2664 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchAdd32(MacroAssembler::Overflow, op2.gpr(), Imm32(imm1), result.gpr())); 2665 2666 int32Result(result.gpr(), node); 2667 return; 2668 } 2669 2670 if (isInt32Constant(node->child2().node())) { 2671 SpeculateInt32Operand op1(this, node->child1()); 2672 int32_t imm2 = valueOfInt32Constant(node->child2().node()); 2673 GPRTemporary result(this); 2674 2675 if (!shouldCheckOverflow(node->arithMode())) { 2676 m_jit.move(op1.gpr(), result.gpr()); 2677 m_jit.add32(Imm32(imm2), result.gpr()); 2678 } else 2679 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchAdd32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr())); 2680 2681 int32Result(result.gpr(), node); 2682 return; 2683 } 2684 2685 SpeculateInt32Operand op1(this, node->child1()); 2686 SpeculateInt32Operand op2(this, node->child2()); 2687 GPRTemporary result(this, Reuse, op1, op2); 2688 2689 GPRReg gpr1 = op1.gpr(); 2690 GPRReg gpr2 = op2.gpr(); 2691 GPRReg gprResult = result.gpr(); 2692 2693 if (!shouldCheckOverflow(node->arithMode())) { 2694 if (gpr1 == gprResult) 2695 m_jit.add32(gpr2, gprResult); 2696 else { 2697 m_jit.move(gpr2, gprResult); 2698 m_jit.add32(gpr1, gprResult); 2699 } 2700 } else { 2701 MacroAssembler::Jump check = m_jit.branchAdd32(MacroAssembler::Overflow, gpr1, gpr2, gprResult); 2702 2703 if (gpr1 == gprResult) 2704 speculationCheck(Overflow, JSValueRegs(), 0, check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr2)); 2705 else if (gpr2 == gprResult) 2706 speculationCheck(Overflow, JSValueRegs(), 0, check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr1)); 2707 else 2708 speculationCheck(Overflow, JSValueRegs(), 0, check); 2709 } 2710 2711 int32Result(gprResult, node); 2712 return; 2713 } 2714 2715#if USE(JSVALUE64) 2716 case Int52RepUse: { 2717 ASSERT(shouldCheckOverflow(node->arithMode())); 2718 ASSERT(!shouldCheckNegativeZero(node->arithMode())); 2719 2720 // Will we need an overflow check? If we can prove that neither input can be 2721 // Int52 then the overflow check will not be necessary. 2722 if (!m_state.forNode(node->child1()).couldBeType(SpecInt52) 2723 && !m_state.forNode(node->child2()).couldBeType(SpecInt52)) { 2724 SpeculateWhicheverInt52Operand op1(this, node->child1()); 2725 SpeculateWhicheverInt52Operand op2(this, node->child2(), op1); 2726 GPRTemporary result(this, Reuse, op1); 2727 m_jit.move(op1.gpr(), result.gpr()); 2728 m_jit.add64(op2.gpr(), result.gpr()); 2729 int52Result(result.gpr(), node, op1.format()); 2730 return; 2731 } 2732 2733 SpeculateInt52Operand op1(this, node->child1()); 2734 SpeculateInt52Operand op2(this, node->child2()); 2735 GPRTemporary result(this); 2736 m_jit.move(op1.gpr(), result.gpr()); 2737 speculationCheck( 2738 Int52Overflow, JSValueRegs(), 0, 2739 m_jit.branchAdd64(MacroAssembler::Overflow, op2.gpr(), result.gpr())); 2740 int52Result(result.gpr(), node); 2741 return; 2742 } 2743#endif // USE(JSVALUE64) 2744 2745 case DoubleRepUse: { 2746 SpeculateDoubleOperand op1(this, node->child1()); 2747 SpeculateDoubleOperand op2(this, node->child2()); 2748 FPRTemporary result(this, op1, op2); 2749 2750 FPRReg reg1 = op1.fpr(); 2751 FPRReg reg2 = op2.fpr(); 2752 m_jit.addDouble(reg1, reg2, result.fpr()); 2753 2754 doubleResult(result.fpr(), node); 2755 return; 2756 } 2757 2758 default: 2759 RELEASE_ASSERT_NOT_REACHED(); 2760 break; 2761 } 2762} 2763 2764void SpeculativeJIT::compileMakeRope(Node* node) 2765{ 2766 ASSERT(node->child1().useKind() == KnownStringUse); 2767 ASSERT(node->child2().useKind() == KnownStringUse); 2768 ASSERT(!node->child3() || node->child3().useKind() == KnownStringUse); 2769 2770 SpeculateCellOperand op1(this, node->child1()); 2771 SpeculateCellOperand op2(this, node->child2()); 2772 SpeculateCellOperand op3(this, node->child3()); 2773 GPRTemporary result(this); 2774 GPRTemporary allocator(this); 2775 GPRTemporary scratch(this); 2776 2777 GPRReg opGPRs[3]; 2778 unsigned numOpGPRs; 2779 opGPRs[0] = op1.gpr(); 2780 opGPRs[1] = op2.gpr(); 2781 if (node->child3()) { 2782 opGPRs[2] = op3.gpr(); 2783 numOpGPRs = 3; 2784 } else { 2785 opGPRs[2] = InvalidGPRReg; 2786 numOpGPRs = 2; 2787 } 2788 GPRReg resultGPR = result.gpr(); 2789 GPRReg allocatorGPR = allocator.gpr(); 2790 GPRReg scratchGPR = scratch.gpr(); 2791 2792 JITCompiler::JumpList slowPath; 2793 MarkedAllocator& markedAllocator = m_jit.vm()->heap.allocatorForObjectWithImmortalStructureDestructor(sizeof(JSRopeString)); 2794 m_jit.move(TrustedImmPtr(&markedAllocator), allocatorGPR); 2795 emitAllocateJSCell(resultGPR, allocatorGPR, TrustedImmPtr(m_jit.vm()->stringStructure.get()), scratchGPR, slowPath); 2796 2797 m_jit.storePtr(TrustedImmPtr(0), JITCompiler::Address(resultGPR, JSString::offsetOfValue())); 2798 for (unsigned i = 0; i < numOpGPRs; ++i) 2799 m_jit.storePtr(opGPRs[i], JITCompiler::Address(resultGPR, JSRopeString::offsetOfFibers() + sizeof(WriteBarrier<JSString>) * i)); 2800 for (unsigned i = numOpGPRs; i < JSRopeString::s_maxInternalRopeLength; ++i) 2801 m_jit.storePtr(TrustedImmPtr(0), JITCompiler::Address(resultGPR, JSRopeString::offsetOfFibers() + sizeof(WriteBarrier<JSString>) * i)); 2802 m_jit.load32(JITCompiler::Address(opGPRs[0], JSString::offsetOfFlags()), scratchGPR); 2803 m_jit.load32(JITCompiler::Address(opGPRs[0], JSString::offsetOfLength()), allocatorGPR); 2804 if (!ASSERT_DISABLED) { 2805 JITCompiler::Jump ok = m_jit.branch32( 2806 JITCompiler::GreaterThanOrEqual, allocatorGPR, TrustedImm32(0)); 2807 m_jit.abortWithReason(DFGNegativeStringLength); 2808 ok.link(&m_jit); 2809 } 2810 for (unsigned i = 1; i < numOpGPRs; ++i) { 2811 m_jit.and32(JITCompiler::Address(opGPRs[i], JSString::offsetOfFlags()), scratchGPR); 2812 speculationCheck( 2813 Uncountable, JSValueSource(), nullptr, 2814 m_jit.branchAdd32( 2815 JITCompiler::Overflow, 2816 JITCompiler::Address(opGPRs[i], JSString::offsetOfLength()), allocatorGPR)); 2817 } 2818 m_jit.and32(JITCompiler::TrustedImm32(JSString::Is8Bit), scratchGPR); 2819 m_jit.store32(scratchGPR, JITCompiler::Address(resultGPR, JSString::offsetOfFlags())); 2820 if (!ASSERT_DISABLED) { 2821 JITCompiler::Jump ok = m_jit.branch32( 2822 JITCompiler::GreaterThanOrEqual, allocatorGPR, TrustedImm32(0)); 2823 m_jit.abortWithReason(DFGNegativeStringLength); 2824 ok.link(&m_jit); 2825 } 2826 m_jit.store32(allocatorGPR, JITCompiler::Address(resultGPR, JSString::offsetOfLength())); 2827 2828 switch (numOpGPRs) { 2829 case 2: 2830 addSlowPathGenerator(slowPathCall( 2831 slowPath, this, operationMakeRope2, resultGPR, opGPRs[0], opGPRs[1])); 2832 break; 2833 case 3: 2834 addSlowPathGenerator(slowPathCall( 2835 slowPath, this, operationMakeRope3, resultGPR, opGPRs[0], opGPRs[1], opGPRs[2])); 2836 break; 2837 default: 2838 RELEASE_ASSERT_NOT_REACHED(); 2839 break; 2840 } 2841 2842 cellResult(resultGPR, node); 2843} 2844 2845void SpeculativeJIT::compileArithSub(Node* node) 2846{ 2847 switch (node->binaryUseKind()) { 2848 case Int32Use: { 2849 ASSERT(!shouldCheckNegativeZero(node->arithMode())); 2850 2851 if (isNumberConstant(node->child2().node())) { 2852 SpeculateInt32Operand op1(this, node->child1()); 2853 int32_t imm2 = valueOfInt32Constant(node->child2().node()); 2854 GPRTemporary result(this); 2855 2856 if (!shouldCheckOverflow(node->arithMode())) { 2857 m_jit.move(op1.gpr(), result.gpr()); 2858 m_jit.sub32(Imm32(imm2), result.gpr()); 2859 } else { 2860 GPRTemporary scratch(this); 2861 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr(), scratch.gpr())); 2862 } 2863 2864 int32Result(result.gpr(), node); 2865 return; 2866 } 2867 2868 if (isNumberConstant(node->child1().node())) { 2869 int32_t imm1 = valueOfInt32Constant(node->child1().node()); 2870 SpeculateInt32Operand op2(this, node->child2()); 2871 GPRTemporary result(this); 2872 2873 m_jit.move(Imm32(imm1), result.gpr()); 2874 if (!shouldCheckOverflow(node->arithMode())) 2875 m_jit.sub32(op2.gpr(), result.gpr()); 2876 else 2877 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchSub32(MacroAssembler::Overflow, op2.gpr(), result.gpr())); 2878 2879 int32Result(result.gpr(), node); 2880 return; 2881 } 2882 2883 SpeculateInt32Operand op1(this, node->child1()); 2884 SpeculateInt32Operand op2(this, node->child2()); 2885 GPRTemporary result(this); 2886 2887 if (!shouldCheckOverflow(node->arithMode())) { 2888 m_jit.move(op1.gpr(), result.gpr()); 2889 m_jit.sub32(op2.gpr(), result.gpr()); 2890 } else 2891 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), op2.gpr(), result.gpr())); 2892 2893 int32Result(result.gpr(), node); 2894 return; 2895 } 2896 2897#if USE(JSVALUE64) 2898 case Int52RepUse: { 2899 ASSERT(shouldCheckOverflow(node->arithMode())); 2900 ASSERT(!shouldCheckNegativeZero(node->arithMode())); 2901 2902 // Will we need an overflow check? If we can prove that neither input can be 2903 // Int52 then the overflow check will not be necessary. 2904 if (!m_state.forNode(node->child1()).couldBeType(SpecInt52) 2905 && !m_state.forNode(node->child2()).couldBeType(SpecInt52)) { 2906 SpeculateWhicheverInt52Operand op1(this, node->child1()); 2907 SpeculateWhicheverInt52Operand op2(this, node->child2(), op1); 2908 GPRTemporary result(this, Reuse, op1); 2909 m_jit.move(op1.gpr(), result.gpr()); 2910 m_jit.sub64(op2.gpr(), result.gpr()); 2911 int52Result(result.gpr(), node, op1.format()); 2912 return; 2913 } 2914 2915 SpeculateInt52Operand op1(this, node->child1()); 2916 SpeculateInt52Operand op2(this, node->child2()); 2917 GPRTemporary result(this); 2918 m_jit.move(op1.gpr(), result.gpr()); 2919 speculationCheck( 2920 Int52Overflow, JSValueRegs(), 0, 2921 m_jit.branchSub64(MacroAssembler::Overflow, op2.gpr(), result.gpr())); 2922 int52Result(result.gpr(), node); 2923 return; 2924 } 2925#endif // USE(JSVALUE64) 2926 2927 case DoubleRepUse: { 2928 SpeculateDoubleOperand op1(this, node->child1()); 2929 SpeculateDoubleOperand op2(this, node->child2()); 2930 FPRTemporary result(this, op1); 2931 2932 FPRReg reg1 = op1.fpr(); 2933 FPRReg reg2 = op2.fpr(); 2934 m_jit.subDouble(reg1, reg2, result.fpr()); 2935 2936 doubleResult(result.fpr(), node); 2937 return; 2938 } 2939 2940 default: 2941 RELEASE_ASSERT_NOT_REACHED(); 2942 return; 2943 } 2944} 2945 2946void SpeculativeJIT::compileArithNegate(Node* node) 2947{ 2948 switch (node->child1().useKind()) { 2949 case Int32Use: { 2950 SpeculateInt32Operand op1(this, node->child1()); 2951 GPRTemporary result(this); 2952 2953 m_jit.move(op1.gpr(), result.gpr()); 2954 2955 // Note: there is no notion of being not used as a number, but someone 2956 // caring about negative zero. 2957 2958 if (!shouldCheckOverflow(node->arithMode())) 2959 m_jit.neg32(result.gpr()); 2960 else if (!shouldCheckNegativeZero(node->arithMode())) 2961 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchNeg32(MacroAssembler::Overflow, result.gpr())); 2962 else { 2963 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(MacroAssembler::Zero, result.gpr(), TrustedImm32(0x7fffffff))); 2964 m_jit.neg32(result.gpr()); 2965 } 2966 2967 int32Result(result.gpr(), node); 2968 return; 2969 } 2970 2971#if USE(JSVALUE64) 2972 case Int52RepUse: { 2973 ASSERT(shouldCheckOverflow(node->arithMode())); 2974 2975 if (!m_state.forNode(node->child1()).couldBeType(SpecInt52)) { 2976 SpeculateWhicheverInt52Operand op1(this, node->child1()); 2977 GPRTemporary result(this); 2978 GPRReg op1GPR = op1.gpr(); 2979 GPRReg resultGPR = result.gpr(); 2980 m_jit.move(op1GPR, resultGPR); 2981 m_jit.neg64(resultGPR); 2982 if (shouldCheckNegativeZero(node->arithMode())) { 2983 speculationCheck( 2984 NegativeZero, JSValueRegs(), 0, 2985 m_jit.branchTest64(MacroAssembler::Zero, resultGPR)); 2986 } 2987 int52Result(resultGPR, node, op1.format()); 2988 return; 2989 } 2990 2991 SpeculateInt52Operand op1(this, node->child1()); 2992 GPRTemporary result(this); 2993 GPRReg op1GPR = op1.gpr(); 2994 GPRReg resultGPR = result.gpr(); 2995 m_jit.move(op1GPR, resultGPR); 2996 speculationCheck( 2997 Int52Overflow, JSValueRegs(), 0, 2998 m_jit.branchNeg64(MacroAssembler::Overflow, resultGPR)); 2999 if (shouldCheckNegativeZero(node->arithMode())) { 3000 speculationCheck( 3001 NegativeZero, JSValueRegs(), 0, 3002 m_jit.branchTest64(MacroAssembler::Zero, resultGPR)); 3003 } 3004 int52Result(resultGPR, node); 3005 return; 3006 } 3007#endif // USE(JSVALUE64) 3008 3009 case DoubleRepUse: { 3010 SpeculateDoubleOperand op1(this, node->child1()); 3011 FPRTemporary result(this); 3012 3013 m_jit.negateDouble(op1.fpr(), result.fpr()); 3014 3015 doubleResult(result.fpr(), node); 3016 return; 3017 } 3018 3019 default: 3020 RELEASE_ASSERT_NOT_REACHED(); 3021 return; 3022 } 3023} 3024void SpeculativeJIT::compileArithMul(Node* node) 3025{ 3026 switch (node->binaryUseKind()) { 3027 case Int32Use: { 3028 SpeculateInt32Operand op1(this, node->child1()); 3029 SpeculateInt32Operand op2(this, node->child2()); 3030 GPRTemporary result(this); 3031 3032 GPRReg reg1 = op1.gpr(); 3033 GPRReg reg2 = op2.gpr(); 3034 3035 // We can perform truncated multiplications if we get to this point, because if the 3036 // fixup phase could not prove that it would be safe, it would have turned us into 3037 // a double multiplication. 3038 if (!shouldCheckOverflow(node->arithMode())) { 3039 m_jit.move(reg1, result.gpr()); 3040 m_jit.mul32(reg2, result.gpr()); 3041 } else { 3042 speculationCheck( 3043 Overflow, JSValueRegs(), 0, 3044 m_jit.branchMul32(MacroAssembler::Overflow, reg1, reg2, result.gpr())); 3045 } 3046 3047 // Check for negative zero, if the users of this node care about such things. 3048 if (shouldCheckNegativeZero(node->arithMode())) { 3049 MacroAssembler::Jump resultNonZero = m_jit.branchTest32(MacroAssembler::NonZero, result.gpr()); 3050 speculationCheck(NegativeZero, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::LessThan, reg1, TrustedImm32(0))); 3051 speculationCheck(NegativeZero, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::LessThan, reg2, TrustedImm32(0))); 3052 resultNonZero.link(&m_jit); 3053 } 3054 3055 int32Result(result.gpr(), node); 3056 return; 3057 } 3058 3059#if USE(JSVALUE64) 3060 case Int52RepUse: { 3061 ASSERT(shouldCheckOverflow(node->arithMode())); 3062 3063 // This is super clever. We want to do an int52 multiplication and check the 3064 // int52 overflow bit. There is no direct hardware support for this, but we do 3065 // have the ability to do an int64 multiplication and check the int64 overflow 3066 // bit. We leverage that. Consider that a, b are int52 numbers inside int64 3067 // registers, with the high 12 bits being sign-extended. We can do: 3068 // 3069 // (a * (b << 12)) 3070 // 3071 // This will give us a left-shifted int52 (value is in high 52 bits, low 16 3072 // bits are zero) plus the int52 overflow bit. I.e. whether this 64-bit 3073 // multiplication overflows is identical to whether the 'a * b' 52-bit 3074 // multiplication overflows. 3075 // 3076 // In our nomenclature, this is: 3077 // 3078 // strictInt52(a) * int52(b) => int52 3079 // 3080 // That is "strictInt52" means unshifted and "int52" means left-shifted by 16 3081 // bits. 3082 // 3083 // We don't care which of op1 or op2 serves as the left-shifted operand, so 3084 // we just do whatever is more convenient for op1 and have op2 do the 3085 // opposite. This ensures that we do at most one shift. 3086 3087 SpeculateWhicheverInt52Operand op1(this, node->child1()); 3088 SpeculateWhicheverInt52Operand op2(this, node->child2(), OppositeShift, op1); 3089 GPRTemporary result(this); 3090 3091 GPRReg op1GPR = op1.gpr(); 3092 GPRReg op2GPR = op2.gpr(); 3093 GPRReg resultGPR = result.gpr(); 3094 3095 m_jit.move(op1GPR, resultGPR); 3096 speculationCheck( 3097 Int52Overflow, JSValueRegs(), 0, 3098 m_jit.branchMul64(MacroAssembler::Overflow, op2GPR, resultGPR)); 3099 3100 if (shouldCheckNegativeZero(node->arithMode())) { 3101 MacroAssembler::Jump resultNonZero = m_jit.branchTest64( 3102 MacroAssembler::NonZero, resultGPR); 3103 speculationCheck( 3104 NegativeZero, JSValueRegs(), 0, 3105 m_jit.branch64(MacroAssembler::LessThan, op1GPR, TrustedImm64(0))); 3106 speculationCheck( 3107 NegativeZero, JSValueRegs(), 0, 3108 m_jit.branch64(MacroAssembler::LessThan, op2GPR, TrustedImm64(0))); 3109 resultNonZero.link(&m_jit); 3110 } 3111 3112 int52Result(resultGPR, node); 3113 return; 3114 } 3115#endif // USE(JSVALUE64) 3116 3117 case DoubleRepUse: { 3118 SpeculateDoubleOperand op1(this, node->child1()); 3119 SpeculateDoubleOperand op2(this, node->child2()); 3120 FPRTemporary result(this, op1, op2); 3121 3122 FPRReg reg1 = op1.fpr(); 3123 FPRReg reg2 = op2.fpr(); 3124 3125 m_jit.mulDouble(reg1, reg2, result.fpr()); 3126 3127 doubleResult(result.fpr(), node); 3128 return; 3129 } 3130 3131 default: 3132 RELEASE_ASSERT_NOT_REACHED(); 3133 return; 3134 } 3135} 3136 3137void SpeculativeJIT::compileArithDiv(Node* node) 3138{ 3139 switch (node->binaryUseKind()) { 3140 case Int32Use: { 3141#if CPU(X86) || CPU(X86_64) 3142 SpeculateInt32Operand op1(this, node->child1()); 3143 SpeculateInt32Operand op2(this, node->child2()); 3144 GPRTemporary eax(this, X86Registers::eax); 3145 GPRTemporary edx(this, X86Registers::edx); 3146 GPRReg op1GPR = op1.gpr(); 3147 GPRReg op2GPR = op2.gpr(); 3148 3149 GPRReg op2TempGPR; 3150 GPRReg temp; 3151 if (op2GPR == X86Registers::eax || op2GPR == X86Registers::edx) { 3152 op2TempGPR = allocate(); 3153 temp = op2TempGPR; 3154 } else { 3155 op2TempGPR = InvalidGPRReg; 3156 if (op1GPR == X86Registers::eax) 3157 temp = X86Registers::edx; 3158 else 3159 temp = X86Registers::eax; 3160 } 3161 3162 ASSERT(temp != op1GPR); 3163 ASSERT(temp != op2GPR); 3164 3165 m_jit.add32(JITCompiler::TrustedImm32(1), op2GPR, temp); 3166 3167 JITCompiler::Jump safeDenominator = m_jit.branch32(JITCompiler::Above, temp, JITCompiler::TrustedImm32(1)); 3168 3169 JITCompiler::JumpList done; 3170 if (shouldCheckOverflow(node->arithMode())) { 3171 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(JITCompiler::Zero, op2GPR)); 3172 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branch32(JITCompiler::Equal, op1GPR, TrustedImm32(-2147483647-1))); 3173 } else { 3174 // This is the case where we convert the result to an int after we're done, and we 3175 // already know that the denominator is either -1 or 0. So, if the denominator is 3176 // zero, then the result should be zero. If the denominator is not zero (i.e. it's 3177 // -1) and the numerator is -2^31 then the result should be -2^31. Otherwise we 3178 // are happy to fall through to a normal division, since we're just dividing 3179 // something by negative 1. 3180 3181 JITCompiler::Jump notZero = m_jit.branchTest32(JITCompiler::NonZero, op2GPR); 3182 m_jit.move(TrustedImm32(0), eax.gpr()); 3183 done.append(m_jit.jump()); 3184 3185 notZero.link(&m_jit); 3186 JITCompiler::Jump notNeg2ToThe31 = 3187 m_jit.branch32(JITCompiler::NotEqual, op1GPR, TrustedImm32(-2147483647-1)); 3188 m_jit.zeroExtend32ToPtr(op1GPR, eax.gpr()); 3189 done.append(m_jit.jump()); 3190 3191 notNeg2ToThe31.link(&m_jit); 3192 } 3193 3194 safeDenominator.link(&m_jit); 3195 3196 // If the user cares about negative zero, then speculate that we're not about 3197 // to produce negative zero. 3198 if (shouldCheckNegativeZero(node->arithMode())) { 3199 MacroAssembler::Jump numeratorNonZero = m_jit.branchTest32(MacroAssembler::NonZero, op1GPR); 3200 speculationCheck(NegativeZero, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::LessThan, op2GPR, TrustedImm32(0))); 3201 numeratorNonZero.link(&m_jit); 3202 } 3203 3204 if (op2TempGPR != InvalidGPRReg) { 3205 m_jit.move(op2GPR, op2TempGPR); 3206 op2GPR = op2TempGPR; 3207 } 3208 3209 m_jit.move(op1GPR, eax.gpr()); 3210 m_jit.assembler().cdq(); 3211 m_jit.assembler().idivl_r(op2GPR); 3212 3213 if (op2TempGPR != InvalidGPRReg) 3214 unlock(op2TempGPR); 3215 3216 // Check that there was no remainder. If there had been, then we'd be obligated to 3217 // produce a double result instead. 3218 if (shouldCheckOverflow(node->arithMode())) 3219 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(JITCompiler::NonZero, edx.gpr())); 3220 3221 done.link(&m_jit); 3222 int32Result(eax.gpr(), node); 3223#elif CPU(APPLE_ARMV7S) || CPU(ARM64) 3224 SpeculateInt32Operand op1(this, node->child1()); 3225 SpeculateInt32Operand op2(this, node->child2()); 3226 GPRReg op1GPR = op1.gpr(); 3227 GPRReg op2GPR = op2.gpr(); 3228 GPRTemporary quotient(this); 3229 GPRTemporary multiplyAnswer(this); 3230 3231 // If the user cares about negative zero, then speculate that we're not about 3232 // to produce negative zero. 3233 if (shouldCheckNegativeZero(node->arithMode())) { 3234 MacroAssembler::Jump numeratorNonZero = m_jit.branchTest32(MacroAssembler::NonZero, op1GPR); 3235 speculationCheck(NegativeZero, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::LessThan, op2GPR, TrustedImm32(0))); 3236 numeratorNonZero.link(&m_jit); 3237 } 3238 3239 m_jit.assembler().sdiv<32>(quotient.gpr(), op1GPR, op2GPR); 3240 3241 // Check that there was no remainder. If there had been, then we'd be obligated to 3242 // produce a double result instead. 3243 if (shouldCheckOverflow(node->arithMode())) { 3244 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchMul32(JITCompiler::Overflow, quotient.gpr(), op2GPR, multiplyAnswer.gpr())); 3245 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branch32(JITCompiler::NotEqual, multiplyAnswer.gpr(), op1GPR)); 3246 } 3247 3248 int32Result(quotient.gpr(), node); 3249#else 3250 RELEASE_ASSERT_NOT_REACHED(); 3251#endif 3252 break; 3253 } 3254 3255 case DoubleRepUse: { 3256 SpeculateDoubleOperand op1(this, node->child1()); 3257 SpeculateDoubleOperand op2(this, node->child2()); 3258 FPRTemporary result(this, op1); 3259 3260 FPRReg reg1 = op1.fpr(); 3261 FPRReg reg2 = op2.fpr(); 3262 m_jit.divDouble(reg1, reg2, result.fpr()); 3263 3264 doubleResult(result.fpr(), node); 3265 break; 3266 } 3267 3268 default: 3269 RELEASE_ASSERT_NOT_REACHED(); 3270 break; 3271 } 3272} 3273 3274void SpeculativeJIT::compileArithMod(Node* node) 3275{ 3276 switch (node->binaryUseKind()) { 3277 case Int32Use: { 3278 // In the fast path, the dividend value could be the final result 3279 // (in case of |dividend| < |divisor|), so we speculate it as strict int32. 3280 SpeculateStrictInt32Operand op1(this, node->child1()); 3281 3282 if (isInt32Constant(node->child2().node())) { 3283 int32_t divisor = valueOfInt32Constant(node->child2().node()); 3284 if (divisor > 1 && hasOneBitSet(divisor)) { 3285 unsigned logarithm = WTF::fastLog2(divisor); 3286 GPRReg dividendGPR = op1.gpr(); 3287 GPRTemporary result(this); 3288 GPRReg resultGPR = result.gpr(); 3289 3290 // This is what LLVM generates. It's pretty crazy. Here's my 3291 // attempt at understanding it. 3292 3293 // First, compute either divisor - 1, or 0, depending on whether 3294 // the dividend is negative: 3295 // 3296 // If dividend < 0: resultGPR = divisor - 1 3297 // If dividend >= 0: resultGPR = 0 3298 m_jit.move(dividendGPR, resultGPR); 3299 m_jit.rshift32(TrustedImm32(31), resultGPR); 3300 m_jit.urshift32(TrustedImm32(32 - logarithm), resultGPR); 3301 3302 // Add in the dividend, so that: 3303 // 3304 // If dividend < 0: resultGPR = dividend + divisor - 1 3305 // If dividend >= 0: resultGPR = dividend 3306 m_jit.add32(dividendGPR, resultGPR); 3307 3308 // Mask so as to only get the *high* bits. This rounds down 3309 // (towards negative infinity) resultGPR to the nearest multiple 3310 // of divisor, so that: 3311 // 3312 // If dividend < 0: resultGPR = floor((dividend + divisor - 1) / divisor) 3313 // If dividend >= 0: resultGPR = floor(dividend / divisor) 3314 // 3315 // Note that this can be simplified to: 3316 // 3317 // If dividend < 0: resultGPR = ceil(dividend / divisor) 3318 // If dividend >= 0: resultGPR = floor(dividend / divisor) 3319 // 3320 // Note that if the dividend is negative, resultGPR will also be negative. 3321 // Regardless of the sign of dividend, resultGPR will be rounded towards 3322 // zero, because of how things are conditionalized. 3323 m_jit.and32(TrustedImm32(-divisor), resultGPR); 3324 3325 // Subtract resultGPR from dividendGPR, which yields the remainder: 3326 // 3327 // resultGPR = dividendGPR - resultGPR 3328 m_jit.neg32(resultGPR); 3329 m_jit.add32(dividendGPR, resultGPR); 3330 3331 if (shouldCheckNegativeZero(node->arithMode())) { 3332 // Check that we're not about to create negative zero. 3333 JITCompiler::Jump numeratorPositive = m_jit.branch32(JITCompiler::GreaterThanOrEqual, dividendGPR, TrustedImm32(0)); 3334 speculationCheck(NegativeZero, JSValueRegs(), 0, m_jit.branchTest32(JITCompiler::Zero, resultGPR)); 3335 numeratorPositive.link(&m_jit); 3336 } 3337 3338 int32Result(resultGPR, node); 3339 return; 3340 } 3341 } 3342 3343#if CPU(X86) || CPU(X86_64) 3344 if (isInt32Constant(node->child2().node())) { 3345 int32_t divisor = valueOfInt32Constant(node->child2().node()); 3346 if (divisor && divisor != -1) { 3347 GPRReg op1Gpr = op1.gpr(); 3348 3349 GPRTemporary eax(this, X86Registers::eax); 3350 GPRTemporary edx(this, X86Registers::edx); 3351 GPRTemporary scratch(this); 3352 GPRReg scratchGPR = scratch.gpr(); 3353 3354 GPRReg op1SaveGPR; 3355 if (op1Gpr == X86Registers::eax || op1Gpr == X86Registers::edx) { 3356 op1SaveGPR = allocate(); 3357 ASSERT(op1Gpr != op1SaveGPR); 3358 m_jit.move(op1Gpr, op1SaveGPR); 3359 } else 3360 op1SaveGPR = op1Gpr; 3361 ASSERT(op1SaveGPR != X86Registers::eax); 3362 ASSERT(op1SaveGPR != X86Registers::edx); 3363 3364 m_jit.move(op1Gpr, eax.gpr()); 3365 m_jit.move(TrustedImm32(divisor), scratchGPR); 3366 m_jit.assembler().cdq(); 3367 m_jit.assembler().idivl_r(scratchGPR); 3368 if (shouldCheckNegativeZero(node->arithMode())) { 3369 JITCompiler::Jump numeratorPositive = m_jit.branch32(JITCompiler::GreaterThanOrEqual, op1SaveGPR, TrustedImm32(0)); 3370 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(JITCompiler::Zero, edx.gpr())); 3371 numeratorPositive.link(&m_jit); 3372 } 3373 3374 if (op1SaveGPR != op1Gpr) 3375 unlock(op1SaveGPR); 3376 3377 int32Result(edx.gpr(), node); 3378 return; 3379 } 3380 } 3381#endif 3382 3383 SpeculateInt32Operand op2(this, node->child2()); 3384#if CPU(X86) || CPU(X86_64) 3385 GPRTemporary eax(this, X86Registers::eax); 3386 GPRTemporary edx(this, X86Registers::edx); 3387 GPRReg op1GPR = op1.gpr(); 3388 GPRReg op2GPR = op2.gpr(); 3389 3390 GPRReg op2TempGPR; 3391 GPRReg temp; 3392 GPRReg op1SaveGPR; 3393 3394 if (op2GPR == X86Registers::eax || op2GPR == X86Registers::edx) { 3395 op2TempGPR = allocate(); 3396 temp = op2TempGPR; 3397 } else { 3398 op2TempGPR = InvalidGPRReg; 3399 if (op1GPR == X86Registers::eax) 3400 temp = X86Registers::edx; 3401 else 3402 temp = X86Registers::eax; 3403 } 3404 3405 if (op1GPR == X86Registers::eax || op1GPR == X86Registers::edx) { 3406 op1SaveGPR = allocate(); 3407 ASSERT(op1GPR != op1SaveGPR); 3408 m_jit.move(op1GPR, op1SaveGPR); 3409 } else 3410 op1SaveGPR = op1GPR; 3411 3412 ASSERT(temp != op1GPR); 3413 ASSERT(temp != op2GPR); 3414 ASSERT(op1SaveGPR != X86Registers::eax); 3415 ASSERT(op1SaveGPR != X86Registers::edx); 3416 3417 m_jit.add32(JITCompiler::TrustedImm32(1), op2GPR, temp); 3418 3419 JITCompiler::Jump safeDenominator = m_jit.branch32(JITCompiler::Above, temp, JITCompiler::TrustedImm32(1)); 3420 3421 JITCompiler::JumpList done; 3422 3423 // FIXME: -2^31 / -1 will actually yield negative zero, so we could have a 3424 // separate case for that. But it probably doesn't matter so much. 3425 if (shouldCheckOverflow(node->arithMode())) { 3426 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(JITCompiler::Zero, op2GPR)); 3427 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branch32(JITCompiler::Equal, op1GPR, TrustedImm32(-2147483647-1))); 3428 } else { 3429 // This is the case where we convert the result to an int after we're done, and we 3430 // already know that the denominator is either -1 or 0. So, if the denominator is 3431 // zero, then the result should be zero. If the denominator is not zero (i.e. it's 3432 // -1) and the numerator is -2^31 then the result should be 0. Otherwise we are 3433 // happy to fall through to a normal division, since we're just dividing something 3434 // by negative 1. 3435 3436 JITCompiler::Jump notZero = m_jit.branchTest32(JITCompiler::NonZero, op2GPR); 3437 m_jit.move(TrustedImm32(0), edx.gpr()); 3438 done.append(m_jit.jump()); 3439 3440 notZero.link(&m_jit); 3441 JITCompiler::Jump notNeg2ToThe31 = 3442 m_jit.branch32(JITCompiler::NotEqual, op1GPR, TrustedImm32(-2147483647-1)); 3443 m_jit.move(TrustedImm32(0), edx.gpr()); 3444 done.append(m_jit.jump()); 3445 3446 notNeg2ToThe31.link(&m_jit); 3447 } 3448 3449 safeDenominator.link(&m_jit); 3450 3451 if (op2TempGPR != InvalidGPRReg) { 3452 m_jit.move(op2GPR, op2TempGPR); 3453 op2GPR = op2TempGPR; 3454 } 3455 3456 m_jit.move(op1GPR, eax.gpr()); 3457 m_jit.assembler().cdq(); 3458 m_jit.assembler().idivl_r(op2GPR); 3459 3460 if (op2TempGPR != InvalidGPRReg) 3461 unlock(op2TempGPR); 3462 3463 // Check that we're not about to create negative zero. 3464 if (shouldCheckNegativeZero(node->arithMode())) { 3465 JITCompiler::Jump numeratorPositive = m_jit.branch32(JITCompiler::GreaterThanOrEqual, op1SaveGPR, TrustedImm32(0)); 3466 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(JITCompiler::Zero, edx.gpr())); 3467 numeratorPositive.link(&m_jit); 3468 } 3469 3470 if (op1SaveGPR != op1GPR) 3471 unlock(op1SaveGPR); 3472 3473 done.link(&m_jit); 3474 int32Result(edx.gpr(), node); 3475 3476#elif CPU(ARM64) || CPU(APPLE_ARMV7S) 3477 GPRTemporary temp(this); 3478 GPRTemporary quotientThenRemainder(this); 3479 GPRTemporary multiplyAnswer(this); 3480 GPRReg dividendGPR = op1.gpr(); 3481 GPRReg divisorGPR = op2.gpr(); 3482 GPRReg quotientThenRemainderGPR = quotientThenRemainder.gpr(); 3483 GPRReg multiplyAnswerGPR = multiplyAnswer.gpr(); 3484 3485 JITCompiler::JumpList done; 3486 3487 if (shouldCheckOverflow(node->arithMode())) 3488 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(JITCompiler::Zero, divisorGPR)); 3489 else { 3490 JITCompiler::Jump denominatorNotZero = m_jit.branchTest32(JITCompiler::NonZero, divisorGPR); 3491 m_jit.move(divisorGPR, quotientThenRemainderGPR); 3492 done.append(m_jit.jump()); 3493 denominatorNotZero.link(&m_jit); 3494 } 3495 3496 m_jit.assembler().sdiv<32>(quotientThenRemainderGPR, dividendGPR, divisorGPR); 3497 // FIXME: It seems like there are cases where we don't need this? What if we have 3498 // arithMode() == Arith::Unchecked? 3499 // https://bugs.webkit.org/show_bug.cgi?id=126444 3500 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchMul32(JITCompiler::Overflow, quotientThenRemainderGPR, divisorGPR, multiplyAnswerGPR)); 3501#if CPU(APPLE_ARMV7S) 3502 m_jit.assembler().sub(quotientThenRemainderGPR, dividendGPR, multiplyAnswerGPR); 3503#else 3504 m_jit.assembler().sub<32>(quotientThenRemainderGPR, dividendGPR, multiplyAnswerGPR); 3505#endif 3506 3507 // If the user cares about negative zero, then speculate that we're not about 3508 // to produce negative zero. 3509 if (shouldCheckNegativeZero(node->arithMode())) { 3510 // Check that we're not about to create negative zero. 3511 JITCompiler::Jump numeratorPositive = m_jit.branch32(JITCompiler::GreaterThanOrEqual, dividendGPR, TrustedImm32(0)); 3512 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchTest32(JITCompiler::Zero, quotientThenRemainderGPR)); 3513 numeratorPositive.link(&m_jit); 3514 } 3515 3516 done.link(&m_jit); 3517 3518 int32Result(quotientThenRemainderGPR, node); 3519#else // not architecture that can do integer division 3520 RELEASE_ASSERT_NOT_REACHED(); 3521#endif 3522 return; 3523 } 3524 3525 case DoubleRepUse: { 3526 SpeculateDoubleOperand op1(this, node->child1()); 3527 SpeculateDoubleOperand op2(this, node->child2()); 3528 3529 FPRReg op1FPR = op1.fpr(); 3530 FPRReg op2FPR = op2.fpr(); 3531 3532 flushRegisters(); 3533 3534 FPRResult result(this); 3535 3536 callOperation(fmodAsDFGOperation, result.fpr(), op1FPR, op2FPR); 3537 3538 doubleResult(result.fpr(), node); 3539 return; 3540 } 3541 3542 default: 3543 RELEASE_ASSERT_NOT_REACHED(); 3544 return; 3545 } 3546} 3547 3548// Returns true if the compare is fused with a subsequent branch. 3549bool SpeculativeJIT::compare(Node* node, MacroAssembler::RelationalCondition condition, MacroAssembler::DoubleCondition doubleCondition, S_JITOperation_EJJ operation) 3550{ 3551 if (compilePeepHoleBranch(node, condition, doubleCondition, operation)) 3552 return true; 3553 3554 if (node->isBinaryUseKind(Int32Use)) { 3555 compileInt32Compare(node, condition); 3556 return false; 3557 } 3558 3559#if USE(JSVALUE64) 3560 if (node->isBinaryUseKind(Int52RepUse)) { 3561 compileInt52Compare(node, condition); 3562 return false; 3563 } 3564#endif // USE(JSVALUE64) 3565 3566 if (node->isBinaryUseKind(DoubleRepUse)) { 3567 compileDoubleCompare(node, doubleCondition); 3568 return false; 3569 } 3570 3571 if (node->op() == CompareEq) { 3572 if (node->isBinaryUseKind(StringUse)) { 3573 compileStringEquality(node); 3574 return false; 3575 } 3576 3577 if (node->isBinaryUseKind(BooleanUse)) { 3578 compileBooleanCompare(node, condition); 3579 return false; 3580 } 3581 3582 if (node->isBinaryUseKind(StringIdentUse)) { 3583 compileStringIdentEquality(node); 3584 return false; 3585 } 3586 3587 if (node->isBinaryUseKind(ObjectUse)) { 3588 compileObjectEquality(node); 3589 return false; 3590 } 3591 3592 if (node->isBinaryUseKind(ObjectUse, ObjectOrOtherUse)) { 3593 compileObjectToObjectOrOtherEquality(node->child1(), node->child2()); 3594 return false; 3595 } 3596 3597 if (node->isBinaryUseKind(ObjectOrOtherUse, ObjectUse)) { 3598 compileObjectToObjectOrOtherEquality(node->child2(), node->child1()); 3599 return false; 3600 } 3601 } 3602 3603 nonSpeculativeNonPeepholeCompare(node, condition, operation); 3604 return false; 3605} 3606 3607bool SpeculativeJIT::compileStrictEq(Node* node) 3608{ 3609 if (node->isBinaryUseKind(BooleanUse)) { 3610 unsigned branchIndexInBlock = detectPeepHoleBranch(); 3611 if (branchIndexInBlock != UINT_MAX) { 3612 Node* branchNode = m_block->at(branchIndexInBlock); 3613 compilePeepHoleBooleanBranch(node, branchNode, MacroAssembler::Equal); 3614 use(node->child1()); 3615 use(node->child2()); 3616 m_indexInBlock = branchIndexInBlock; 3617 m_currentNode = branchNode; 3618 return true; 3619 } 3620 compileBooleanCompare(node, MacroAssembler::Equal); 3621 return false; 3622 } 3623 3624 if (node->isBinaryUseKind(Int32Use)) { 3625 unsigned branchIndexInBlock = detectPeepHoleBranch(); 3626 if (branchIndexInBlock != UINT_MAX) { 3627 Node* branchNode = m_block->at(branchIndexInBlock); 3628 compilePeepHoleInt32Branch(node, branchNode, MacroAssembler::Equal); 3629 use(node->child1()); 3630 use(node->child2()); 3631 m_indexInBlock = branchIndexInBlock; 3632 m_currentNode = branchNode; 3633 return true; 3634 } 3635 compileInt32Compare(node, MacroAssembler::Equal); 3636 return false; 3637 } 3638 3639#if USE(JSVALUE64) 3640 if (node->isBinaryUseKind(Int52RepUse)) { 3641 unsigned branchIndexInBlock = detectPeepHoleBranch(); 3642 if (branchIndexInBlock != UINT_MAX) { 3643 Node* branchNode = m_block->at(branchIndexInBlock); 3644 compilePeepHoleInt52Branch(node, branchNode, MacroAssembler::Equal); 3645 use(node->child1()); 3646 use(node->child2()); 3647 m_indexInBlock = branchIndexInBlock; 3648 m_currentNode = branchNode; 3649 return true; 3650 } 3651 compileInt52Compare(node, MacroAssembler::Equal); 3652 return false; 3653 } 3654#endif // USE(JSVALUE64) 3655 3656 if (node->isBinaryUseKind(DoubleRepUse)) { 3657 unsigned branchIndexInBlock = detectPeepHoleBranch(); 3658 if (branchIndexInBlock != UINT_MAX) { 3659 Node* branchNode = m_block->at(branchIndexInBlock); 3660 compilePeepHoleDoubleBranch(node, branchNode, MacroAssembler::DoubleEqual); 3661 use(node->child1()); 3662 use(node->child2()); 3663 m_indexInBlock = branchIndexInBlock; 3664 m_currentNode = branchNode; 3665 return true; 3666 } 3667 compileDoubleCompare(node, MacroAssembler::DoubleEqual); 3668 return false; 3669 } 3670 3671 if (node->isBinaryUseKind(StringUse)) { 3672 compileStringEquality(node); 3673 return false; 3674 } 3675 3676 if (node->isBinaryUseKind(StringIdentUse)) { 3677 compileStringIdentEquality(node); 3678 return false; 3679 } 3680 3681 if (node->isBinaryUseKind(ObjectUse)) { 3682 unsigned branchIndexInBlock = detectPeepHoleBranch(); 3683 if (branchIndexInBlock != UINT_MAX) { 3684 Node* branchNode = m_block->at(branchIndexInBlock); 3685 compilePeepHoleObjectEquality(node, branchNode); 3686 use(node->child1()); 3687 use(node->child2()); 3688 m_indexInBlock = branchIndexInBlock; 3689 m_currentNode = branchNode; 3690 return true; 3691 } 3692 compileObjectEquality(node); 3693 return false; 3694 } 3695 3696 if (node->isBinaryUseKind(MiscUse, UntypedUse) 3697 || node->isBinaryUseKind(UntypedUse, MiscUse)) { 3698 compileMiscStrictEq(node); 3699 return false; 3700 } 3701 3702 if (node->isBinaryUseKind(StringIdentUse, NotStringVarUse)) { 3703 compileStringIdentToNotStringVarEquality(node, node->child1(), node->child2()); 3704 return false; 3705 } 3706 3707 if (node->isBinaryUseKind(NotStringVarUse, StringIdentUse)) { 3708 compileStringIdentToNotStringVarEquality(node, node->child2(), node->child1()); 3709 return false; 3710 } 3711 3712 if (node->isBinaryUseKind(StringUse, UntypedUse)) { 3713 compileStringToUntypedEquality(node, node->child1(), node->child2()); 3714 return false; 3715 } 3716 3717 if (node->isBinaryUseKind(UntypedUse, StringUse)) { 3718 compileStringToUntypedEquality(node, node->child2(), node->child1()); 3719 return false; 3720 } 3721 3722 RELEASE_ASSERT(node->isBinaryUseKind(UntypedUse)); 3723 return nonSpeculativeStrictEq(node); 3724} 3725 3726void SpeculativeJIT::compileBooleanCompare(Node* node, MacroAssembler::RelationalCondition condition) 3727{ 3728 SpeculateBooleanOperand op1(this, node->child1()); 3729 SpeculateBooleanOperand op2(this, node->child2()); 3730 GPRTemporary result(this); 3731 3732 m_jit.compare32(condition, op1.gpr(), op2.gpr(), result.gpr()); 3733 3734 unblessedBooleanResult(result.gpr(), node); 3735} 3736 3737void SpeculativeJIT::compileStringEquality( 3738 Node* node, GPRReg leftGPR, GPRReg rightGPR, GPRReg lengthGPR, GPRReg leftTempGPR, 3739 GPRReg rightTempGPR, GPRReg leftTemp2GPR, GPRReg rightTemp2GPR, 3740 JITCompiler::JumpList fastTrue, JITCompiler::JumpList fastFalse) 3741{ 3742 JITCompiler::JumpList trueCase; 3743 JITCompiler::JumpList falseCase; 3744 JITCompiler::JumpList slowCase; 3745 3746 trueCase.append(fastTrue); 3747 falseCase.append(fastFalse); 3748 3749 m_jit.load32(MacroAssembler::Address(leftGPR, JSString::offsetOfLength()), lengthGPR); 3750 3751 falseCase.append(m_jit.branch32( 3752 MacroAssembler::NotEqual, 3753 MacroAssembler::Address(rightGPR, JSString::offsetOfLength()), 3754 lengthGPR)); 3755 3756 trueCase.append(m_jit.branchTest32(MacroAssembler::Zero, lengthGPR)); 3757 3758 m_jit.loadPtr(MacroAssembler::Address(leftGPR, JSString::offsetOfValue()), leftTempGPR); 3759 m_jit.loadPtr(MacroAssembler::Address(rightGPR, JSString::offsetOfValue()), rightTempGPR); 3760 3761 slowCase.append(m_jit.branchTestPtr(MacroAssembler::Zero, leftTempGPR)); 3762 slowCase.append(m_jit.branchTestPtr(MacroAssembler::Zero, rightTempGPR)); 3763 3764 slowCase.append(m_jit.branchTest32( 3765 MacroAssembler::Zero, 3766 MacroAssembler::Address(leftTempGPR, StringImpl::flagsOffset()), 3767 TrustedImm32(StringImpl::flagIs8Bit()))); 3768 slowCase.append(m_jit.branchTest32( 3769 MacroAssembler::Zero, 3770 MacroAssembler::Address(rightTempGPR, StringImpl::flagsOffset()), 3771 TrustedImm32(StringImpl::flagIs8Bit()))); 3772 3773 m_jit.loadPtr(MacroAssembler::Address(leftTempGPR, StringImpl::dataOffset()), leftTempGPR); 3774 m_jit.loadPtr(MacroAssembler::Address(rightTempGPR, StringImpl::dataOffset()), rightTempGPR); 3775 3776 MacroAssembler::Label loop = m_jit.label(); 3777 3778 m_jit.sub32(TrustedImm32(1), lengthGPR); 3779 3780 // This isn't going to generate the best code on x86. But that's OK, it's still better 3781 // than not inlining. 3782 m_jit.load8(MacroAssembler::BaseIndex(leftTempGPR, lengthGPR, MacroAssembler::TimesOne), leftTemp2GPR); 3783 m_jit.load8(MacroAssembler::BaseIndex(rightTempGPR, lengthGPR, MacroAssembler::TimesOne), rightTemp2GPR); 3784 falseCase.append(m_jit.branch32(MacroAssembler::NotEqual, leftTemp2GPR, rightTemp2GPR)); 3785 3786 m_jit.branchTest32(MacroAssembler::NonZero, lengthGPR).linkTo(loop, &m_jit); 3787 3788 trueCase.link(&m_jit); 3789 moveTrueTo(leftTempGPR); 3790 3791 JITCompiler::Jump done = m_jit.jump(); 3792 3793 falseCase.link(&m_jit); 3794 moveFalseTo(leftTempGPR); 3795 3796 done.link(&m_jit); 3797 addSlowPathGenerator( 3798 slowPathCall( 3799 slowCase, this, operationCompareStringEq, leftTempGPR, leftGPR, rightGPR)); 3800 3801 blessedBooleanResult(leftTempGPR, node); 3802} 3803 3804void SpeculativeJIT::compileStringEquality(Node* node) 3805{ 3806 SpeculateCellOperand left(this, node->child1()); 3807 SpeculateCellOperand right(this, node->child2()); 3808 GPRTemporary length(this); 3809 GPRTemporary leftTemp(this); 3810 GPRTemporary rightTemp(this); 3811 GPRTemporary leftTemp2(this, Reuse, left); 3812 GPRTemporary rightTemp2(this, Reuse, right); 3813 3814 GPRReg leftGPR = left.gpr(); 3815 GPRReg rightGPR = right.gpr(); 3816 GPRReg lengthGPR = length.gpr(); 3817 GPRReg leftTempGPR = leftTemp.gpr(); 3818 GPRReg rightTempGPR = rightTemp.gpr(); 3819 GPRReg leftTemp2GPR = leftTemp2.gpr(); 3820 GPRReg rightTemp2GPR = rightTemp2.gpr(); 3821 3822 speculateString(node->child1(), leftGPR); 3823 3824 // It's safe to branch around the type check below, since proving that the values are 3825 // equal does indeed prove that the right value is a string. 3826 JITCompiler::Jump fastTrue = m_jit.branchPtr(MacroAssembler::Equal, leftGPR, rightGPR); 3827 3828 speculateString(node->child2(), rightGPR); 3829 3830 compileStringEquality( 3831 node, leftGPR, rightGPR, lengthGPR, leftTempGPR, rightTempGPR, leftTemp2GPR, 3832 rightTemp2GPR, fastTrue, JITCompiler::Jump()); 3833} 3834 3835void SpeculativeJIT::compileStringToUntypedEquality(Node* node, Edge stringEdge, Edge untypedEdge) 3836{ 3837 SpeculateCellOperand left(this, stringEdge); 3838 JSValueOperand right(this, untypedEdge, ManualOperandSpeculation); 3839 GPRTemporary length(this); 3840 GPRTemporary leftTemp(this); 3841 GPRTemporary rightTemp(this); 3842 GPRTemporary leftTemp2(this, Reuse, left); 3843 GPRTemporary rightTemp2(this); 3844 3845 GPRReg leftGPR = left.gpr(); 3846 JSValueRegs rightRegs = right.jsValueRegs(); 3847 GPRReg lengthGPR = length.gpr(); 3848 GPRReg leftTempGPR = leftTemp.gpr(); 3849 GPRReg rightTempGPR = rightTemp.gpr(); 3850 GPRReg leftTemp2GPR = leftTemp2.gpr(); 3851 GPRReg rightTemp2GPR = rightTemp2.gpr(); 3852 3853 speculateString(stringEdge, leftGPR); 3854 3855 JITCompiler::JumpList fastTrue; 3856 JITCompiler::JumpList fastFalse; 3857 3858 fastFalse.append(branchNotCell(rightRegs)); 3859 3860 // It's safe to branch around the type check below, since proving that the values are 3861 // equal does indeed prove that the right value is a string. 3862 fastTrue.append(m_jit.branchPtr( 3863 MacroAssembler::Equal, leftGPR, rightRegs.payloadGPR())); 3864 3865 fastFalse.append(m_jit.branchStructurePtr( 3866 MacroAssembler::NotEqual, 3867 MacroAssembler::Address(rightRegs.payloadGPR(), JSCell::structureIDOffset()), 3868 m_jit.vm()->stringStructure.get())); 3869 3870 compileStringEquality( 3871 node, leftGPR, rightRegs.payloadGPR(), lengthGPR, leftTempGPR, rightTempGPR, leftTemp2GPR, 3872 rightTemp2GPR, fastTrue, fastFalse); 3873} 3874 3875void SpeculativeJIT::compileStringIdentEquality(Node* node) 3876{ 3877 SpeculateCellOperand left(this, node->child1()); 3878 SpeculateCellOperand right(this, node->child2()); 3879 GPRTemporary leftTemp(this); 3880 GPRTemporary rightTemp(this); 3881 3882 GPRReg leftGPR = left.gpr(); 3883 GPRReg rightGPR = right.gpr(); 3884 GPRReg leftTempGPR = leftTemp.gpr(); 3885 GPRReg rightTempGPR = rightTemp.gpr(); 3886 3887 speculateString(node->child1(), leftGPR); 3888 speculateString(node->child2(), rightGPR); 3889 3890 speculateStringIdentAndLoadStorage(node->child1(), leftGPR, leftTempGPR); 3891 speculateStringIdentAndLoadStorage(node->child2(), rightGPR, rightTempGPR); 3892 3893 m_jit.comparePtr(MacroAssembler::Equal, leftTempGPR, rightTempGPR, leftTempGPR); 3894 3895 unblessedBooleanResult(leftTempGPR, node); 3896} 3897 3898void SpeculativeJIT::compileStringIdentToNotStringVarEquality( 3899 Node* node, Edge stringEdge, Edge notStringVarEdge) 3900{ 3901 SpeculateCellOperand left(this, stringEdge); 3902 JSValueOperand right(this, notStringVarEdge, ManualOperandSpeculation); 3903 GPRTemporary leftTemp(this); 3904 GPRTemporary rightTemp(this); 3905 GPRReg leftTempGPR = leftTemp.gpr(); 3906 GPRReg rightTempGPR = rightTemp.gpr(); 3907 GPRReg leftGPR = left.gpr(); 3908 JSValueRegs rightRegs = right.jsValueRegs(); 3909 3910 speculateString(stringEdge, leftGPR); 3911 speculateStringIdentAndLoadStorage(stringEdge, leftGPR, leftTempGPR); 3912 3913 moveFalseTo(rightTempGPR); 3914 JITCompiler::JumpList notString; 3915 notString.append(branchNotCell(rightRegs)); 3916 notString.append(m_jit.branchStructurePtr( 3917 MacroAssembler::NotEqual, 3918 MacroAssembler::Address(rightRegs.payloadGPR(), JSCell::structureIDOffset()), 3919 m_jit.vm()->stringStructure.get())); 3920 3921 speculateStringIdentAndLoadStorage(notStringVarEdge, rightRegs.payloadGPR(), rightTempGPR); 3922 3923 m_jit.comparePtr(MacroAssembler::Equal, leftTempGPR, rightTempGPR, rightTempGPR); 3924 notString.link(&m_jit); 3925 3926 unblessedBooleanResult(rightTempGPR, node); 3927} 3928 3929void SpeculativeJIT::compileStringZeroLength(Node* node) 3930{ 3931 SpeculateCellOperand str(this, node->child1()); 3932 GPRReg strGPR = str.gpr(); 3933 3934 // Make sure that this is a string. 3935 speculateString(node->child1(), strGPR); 3936 3937 GPRTemporary eq(this); 3938 GPRReg eqGPR = eq.gpr(); 3939 3940 // Fetch the length field from the string object. 3941 m_jit.test32(MacroAssembler::Zero, MacroAssembler::Address(strGPR, JSString::offsetOfLength()), MacroAssembler::TrustedImm32(-1), eqGPR); 3942 3943 unblessedBooleanResult(eqGPR, node); 3944} 3945 3946void SpeculativeJIT::compileConstantStoragePointer(Node* node) 3947{ 3948 GPRTemporary storage(this); 3949 GPRReg storageGPR = storage.gpr(); 3950 m_jit.move(TrustedImmPtr(node->storagePointer()), storageGPR); 3951 storageResult(storageGPR, node); 3952} 3953 3954void SpeculativeJIT::compileGetIndexedPropertyStorage(Node* node) 3955{ 3956 SpeculateCellOperand base(this, node->child1()); 3957 GPRReg baseReg = base.gpr(); 3958 3959 GPRTemporary storage(this); 3960 GPRReg storageReg = storage.gpr(); 3961 3962 switch (node->arrayMode().type()) { 3963 case Array::String: 3964 m_jit.loadPtr(MacroAssembler::Address(baseReg, JSString::offsetOfValue()), storageReg); 3965 3966 addSlowPathGenerator( 3967 slowPathCall( 3968 m_jit.branchTest32(MacroAssembler::Zero, storageReg), 3969 this, operationResolveRope, storageReg, baseReg)); 3970 3971 m_jit.loadPtr(MacroAssembler::Address(storageReg, StringImpl::dataOffset()), storageReg); 3972 break; 3973 3974 default: 3975 ASSERT(isTypedView(node->arrayMode().typedArrayType())); 3976 m_jit.loadPtr( 3977 MacroAssembler::Address(baseReg, JSArrayBufferView::offsetOfVector()), 3978 storageReg); 3979 break; 3980 } 3981 3982 storageResult(storageReg, node); 3983} 3984 3985void SpeculativeJIT::compileGetTypedArrayByteOffset(Node* node) 3986{ 3987 SpeculateCellOperand base(this, node->child1()); 3988 GPRTemporary vector(this); 3989 GPRTemporary data(this); 3990 3991 GPRReg baseGPR = base.gpr(); 3992 GPRReg vectorGPR = vector.gpr(); 3993 GPRReg dataGPR = data.gpr(); 3994 3995 JITCompiler::Jump emptyByteOffset = m_jit.branch32( 3996 MacroAssembler::NotEqual, 3997 MacroAssembler::Address(baseGPR, JSArrayBufferView::offsetOfMode()), 3998 TrustedImm32(WastefulTypedArray)); 3999 4000 m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::butterflyOffset()), dataGPR); 4001 m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArrayBufferView::offsetOfVector()), vectorGPR); 4002 m_jit.loadPtr(MacroAssembler::Address(dataGPR, Butterfly::offsetOfArrayBuffer()), dataGPR); 4003 m_jit.loadPtr(MacroAssembler::Address(dataGPR, ArrayBuffer::offsetOfData()), dataGPR); 4004 m_jit.subPtr(dataGPR, vectorGPR); 4005 4006 JITCompiler::Jump done = m_jit.jump(); 4007 4008 emptyByteOffset.link(&m_jit); 4009 m_jit.move(TrustedImmPtr(0), vectorGPR); 4010 4011 done.link(&m_jit); 4012 4013 int32Result(vectorGPR, node); 4014} 4015 4016void SpeculativeJIT::compileGetByValOnArguments(Node* node) 4017{ 4018 SpeculateCellOperand base(this, node->child1()); 4019 SpeculateStrictInt32Operand property(this, node->child2()); 4020 GPRTemporary result(this); 4021#if USE(JSVALUE32_64) 4022 GPRTemporary resultTag(this); 4023#endif 4024 GPRTemporary scratch(this); 4025 4026 GPRReg baseReg = base.gpr(); 4027 GPRReg propertyReg = property.gpr(); 4028 GPRReg resultReg = result.gpr(); 4029#if USE(JSVALUE32_64) 4030 GPRReg resultTagReg = resultTag.gpr(); 4031#endif 4032 GPRReg scratchReg = scratch.gpr(); 4033 4034 if (!m_compileOkay) 4035 return; 4036 4037 ASSERT(ArrayMode(Array::Arguments).alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1()))); 4038 4039 // Two really lame checks. 4040 speculationCheck( 4041 Uncountable, JSValueSource(), 0, 4042 m_jit.branch32( 4043 MacroAssembler::AboveOrEqual, propertyReg, 4044 MacroAssembler::Address(baseReg, Arguments::offsetOfNumArguments()))); 4045 speculationCheck( 4046 Uncountable, JSValueSource(), 0, 4047 m_jit.branchTestPtr( 4048 MacroAssembler::NonZero, 4049 MacroAssembler::Address( 4050 baseReg, Arguments::offsetOfSlowArgumentData()))); 4051 4052 m_jit.move(propertyReg, resultReg); 4053 m_jit.signExtend32ToPtr(resultReg, resultReg); 4054 m_jit.loadPtr( 4055 MacroAssembler::Address(baseReg, Arguments::offsetOfRegisters()), 4056 scratchReg); 4057 4058#if USE(JSVALUE32_64) 4059 m_jit.load32( 4060 MacroAssembler::BaseIndex( 4061 scratchReg, resultReg, MacroAssembler::TimesEight, 4062 CallFrame::thisArgumentOffset() * sizeof(Register) + sizeof(Register) + 4063 OBJECT_OFFSETOF(JSValue, u.asBits.tag)), 4064 resultTagReg); 4065 m_jit.load32( 4066 MacroAssembler::BaseIndex( 4067 scratchReg, resultReg, MacroAssembler::TimesEight, 4068 CallFrame::thisArgumentOffset() * sizeof(Register) + sizeof(Register) + 4069 OBJECT_OFFSETOF(JSValue, u.asBits.payload)), 4070 resultReg); 4071 jsValueResult(resultTagReg, resultReg, node); 4072#else 4073 m_jit.load64( 4074 MacroAssembler::BaseIndex( 4075 scratchReg, resultReg, MacroAssembler::TimesEight, 4076 CallFrame::thisArgumentOffset() * sizeof(Register) + sizeof(Register)), 4077 resultReg); 4078 jsValueResult(resultReg, node); 4079#endif 4080} 4081 4082void SpeculativeJIT::compileGetArgumentsLength(Node* node) 4083{ 4084 SpeculateCellOperand base(this, node->child1()); 4085 GPRTemporary result(this, Reuse, base); 4086 4087 GPRReg baseReg = base.gpr(); 4088 GPRReg resultReg = result.gpr(); 4089 4090 if (!m_compileOkay) 4091 return; 4092 4093 ASSERT(ArrayMode(Array::Arguments).alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1()))); 4094 4095 speculationCheck( 4096 Uncountable, JSValueSource(), 0, 4097 m_jit.branchTest8( 4098 MacroAssembler::NonZero, 4099 MacroAssembler::Address(baseReg, Arguments::offsetOfOverrodeLength()))); 4100 4101 m_jit.load32( 4102 MacroAssembler::Address(baseReg, Arguments::offsetOfNumArguments()), 4103 resultReg); 4104 int32Result(resultReg, node); 4105} 4106 4107void SpeculativeJIT::compileGetArrayLength(Node* node) 4108{ 4109 switch (node->arrayMode().type()) { 4110 case Array::Int32: 4111 case Array::Double: 4112 case Array::Contiguous: { 4113 StorageOperand storage(this, node->child2()); 4114 GPRTemporary result(this, Reuse, storage); 4115 GPRReg storageReg = storage.gpr(); 4116 GPRReg resultReg = result.gpr(); 4117 m_jit.load32(MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()), resultReg); 4118 4119 int32Result(resultReg, node); 4120 break; 4121 } 4122 case Array::ArrayStorage: 4123 case Array::SlowPutArrayStorage: { 4124 StorageOperand storage(this, node->child2()); 4125 GPRTemporary result(this, Reuse, storage); 4126 GPRReg storageReg = storage.gpr(); 4127 GPRReg resultReg = result.gpr(); 4128 m_jit.load32(MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength()), resultReg); 4129 4130 speculationCheck(Uncountable, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::LessThan, resultReg, MacroAssembler::TrustedImm32(0))); 4131 4132 int32Result(resultReg, node); 4133 break; 4134 } 4135 case Array::String: { 4136 SpeculateCellOperand base(this, node->child1()); 4137 GPRTemporary result(this, Reuse, base); 4138 GPRReg baseGPR = base.gpr(); 4139 GPRReg resultGPR = result.gpr(); 4140 m_jit.load32(MacroAssembler::Address(baseGPR, JSString::offsetOfLength()), resultGPR); 4141 int32Result(resultGPR, node); 4142 break; 4143 } 4144 case Array::Arguments: { 4145 compileGetArgumentsLength(node); 4146 break; 4147 } 4148 default: { 4149 ASSERT(isTypedView(node->arrayMode().typedArrayType())); 4150 SpeculateCellOperand base(this, node->child1()); 4151 GPRTemporary result(this, Reuse, base); 4152 GPRReg baseGPR = base.gpr(); 4153 GPRReg resultGPR = result.gpr(); 4154 m_jit.load32(MacroAssembler::Address(baseGPR, JSArrayBufferView::offsetOfLength()), resultGPR); 4155 int32Result(resultGPR, node); 4156 break; 4157 } } 4158} 4159 4160void SpeculativeJIT::compileNewFunctionNoCheck(Node* node) 4161{ 4162 GPRResult result(this); 4163 GPRReg resultGPR = result.gpr(); 4164 flushRegisters(); 4165 callOperation( 4166 operationNewFunctionNoCheck, resultGPR, m_jit.codeBlock()->functionDecl(node->functionDeclIndex())); 4167 cellResult(resultGPR, node); 4168} 4169 4170void SpeculativeJIT::compileNewFunctionExpression(Node* node) 4171{ 4172 GPRResult result(this); 4173 GPRReg resultGPR = result.gpr(); 4174 flushRegisters(); 4175 callOperation( 4176 operationNewFunctionNoCheck, 4177 resultGPR, 4178 m_jit.codeBlock()->functionExpr(node->functionExprIndex())); 4179 cellResult(resultGPR, node); 4180} 4181 4182bool SpeculativeJIT::compileRegExpExec(Node* node) 4183{ 4184 unsigned branchIndexInBlock = detectPeepHoleBranch(); 4185 if (branchIndexInBlock == UINT_MAX) 4186 return false; 4187 Node* branchNode = m_block->at(branchIndexInBlock); 4188 ASSERT(node->adjustedRefCount() == 1); 4189 4190 BasicBlock* taken = branchNode->branchData()->taken.block; 4191 BasicBlock* notTaken = branchNode->branchData()->notTaken.block; 4192 4193 bool invert = false; 4194 if (taken == nextBlock()) { 4195 invert = true; 4196 BasicBlock* tmp = taken; 4197 taken = notTaken; 4198 notTaken = tmp; 4199 } 4200 4201 SpeculateCellOperand base(this, node->child1()); 4202 SpeculateCellOperand argument(this, node->child2()); 4203 GPRReg baseGPR = base.gpr(); 4204 GPRReg argumentGPR = argument.gpr(); 4205 4206 flushRegisters(); 4207 GPRResult result(this); 4208 callOperation(operationRegExpTest, result.gpr(), baseGPR, argumentGPR); 4209 4210 branchTest32(invert ? JITCompiler::Zero : JITCompiler::NonZero, result.gpr(), taken); 4211 jump(notTaken); 4212 4213 use(node->child1()); 4214 use(node->child2()); 4215 m_indexInBlock = branchIndexInBlock; 4216 m_currentNode = branchNode; 4217 4218 return true; 4219} 4220 4221void SpeculativeJIT::compileAllocatePropertyStorage(Node* node) 4222{ 4223 if (node->structureTransitionData().previousStructure->couldHaveIndexingHeader()) { 4224 SpeculateCellOperand base(this, node->child1()); 4225 4226 GPRReg baseGPR = base.gpr(); 4227 4228 flushRegisters(); 4229 4230 GPRResult result(this); 4231 callOperation(operationReallocateButterflyToHavePropertyStorageWithInitialCapacity, result.gpr(), baseGPR); 4232 4233 storageResult(result.gpr(), node); 4234 return; 4235 } 4236 4237 SpeculateCellOperand base(this, node->child1()); 4238 GPRTemporary scratch1(this); 4239 4240 GPRReg baseGPR = base.gpr(); 4241 GPRReg scratchGPR1 = scratch1.gpr(); 4242 4243 ASSERT(!node->structureTransitionData().previousStructure->outOfLineCapacity()); 4244 ASSERT(initialOutOfLineCapacity == node->structureTransitionData().newStructure->outOfLineCapacity()); 4245 4246 JITCompiler::Jump slowPath = 4247 emitAllocateBasicStorage( 4248 TrustedImm32(initialOutOfLineCapacity * sizeof(JSValue)), scratchGPR1); 4249 4250 m_jit.addPtr(JITCompiler::TrustedImm32(sizeof(IndexingHeader)), scratchGPR1); 4251 4252 addSlowPathGenerator( 4253 slowPathCall(slowPath, this, operationAllocatePropertyStorageWithInitialCapacity, scratchGPR1)); 4254 4255 m_jit.storePtr(scratchGPR1, JITCompiler::Address(baseGPR, JSObject::butterflyOffset())); 4256 4257 storageResult(scratchGPR1, node); 4258} 4259 4260void SpeculativeJIT::compileReallocatePropertyStorage(Node* node) 4261{ 4262 size_t oldSize = node->structureTransitionData().previousStructure->outOfLineCapacity() * sizeof(JSValue); 4263 size_t newSize = oldSize * outOfLineGrowthFactor; 4264 ASSERT(newSize == node->structureTransitionData().newStructure->outOfLineCapacity() * sizeof(JSValue)); 4265 4266 if (node->structureTransitionData().previousStructure->couldHaveIndexingHeader()) { 4267 SpeculateCellOperand base(this, node->child1()); 4268 4269 GPRReg baseGPR = base.gpr(); 4270 4271 flushRegisters(); 4272 4273 GPRResult result(this); 4274 callOperation(operationReallocateButterflyToGrowPropertyStorage, result.gpr(), baseGPR, newSize / sizeof(JSValue)); 4275 4276 storageResult(result.gpr(), node); 4277 return; 4278 } 4279 4280 SpeculateCellOperand base(this, node->child1()); 4281 StorageOperand oldStorage(this, node->child2()); 4282 GPRTemporary scratch1(this); 4283 GPRTemporary scratch2(this); 4284 4285 GPRReg baseGPR = base.gpr(); 4286 GPRReg oldStorageGPR = oldStorage.gpr(); 4287 GPRReg scratchGPR1 = scratch1.gpr(); 4288 GPRReg scratchGPR2 = scratch2.gpr(); 4289 4290 JITCompiler::Jump slowPath = 4291 emitAllocateBasicStorage(TrustedImm32(newSize), scratchGPR1); 4292 4293 m_jit.addPtr(JITCompiler::TrustedImm32(sizeof(IndexingHeader)), scratchGPR1); 4294 4295 addSlowPathGenerator( 4296 slowPathCall(slowPath, this, operationAllocatePropertyStorage, scratchGPR1, newSize / sizeof(JSValue))); 4297 4298 // We have scratchGPR1 = new storage, scratchGPR2 = scratch 4299 for (ptrdiff_t offset = 0; offset < static_cast<ptrdiff_t>(oldSize); offset += sizeof(void*)) { 4300 m_jit.loadPtr(JITCompiler::Address(oldStorageGPR, -(offset + sizeof(JSValue) + sizeof(void*))), scratchGPR2); 4301 m_jit.storePtr(scratchGPR2, JITCompiler::Address(scratchGPR1, -(offset + sizeof(JSValue) + sizeof(void*)))); 4302 } 4303 m_jit.storePtr(scratchGPR1, JITCompiler::Address(baseGPR, JSObject::butterflyOffset())); 4304 4305 storageResult(scratchGPR1, node); 4306} 4307 4308GPRReg SpeculativeJIT::temporaryRegisterForPutByVal(GPRTemporary& temporary, ArrayMode arrayMode) 4309{ 4310 if (!putByValWillNeedExtraRegister(arrayMode)) 4311 return InvalidGPRReg; 4312 4313 GPRTemporary realTemporary(this); 4314 temporary.adopt(realTemporary); 4315 return temporary.gpr(); 4316} 4317 4318void SpeculativeJIT::compileToStringOnCell(Node* node) 4319{ 4320 SpeculateCellOperand op1(this, node->child1()); 4321 GPRReg op1GPR = op1.gpr(); 4322 4323 switch (node->child1().useKind()) { 4324 case StringObjectUse: { 4325 GPRTemporary result(this); 4326 GPRReg resultGPR = result.gpr(); 4327 4328 speculateStringObject(node->child1(), op1GPR); 4329 m_interpreter.filter(node->child1(), SpecStringObject); 4330 4331 m_jit.loadPtr(JITCompiler::Address(op1GPR, JSWrapperObject::internalValueCellOffset()), resultGPR); 4332 cellResult(resultGPR, node); 4333 break; 4334 } 4335 4336 case StringOrStringObjectUse: { 4337 GPRTemporary result(this); 4338 GPRReg resultGPR = result.gpr(); 4339 4340 m_jit.load32(JITCompiler::Address(op1GPR, JSCell::structureIDOffset()), resultGPR); 4341 JITCompiler::Jump isString = m_jit.branchStructurePtr( 4342 JITCompiler::Equal, 4343 resultGPR, 4344 m_jit.vm()->stringStructure.get()); 4345 4346 speculateStringObjectForStructure(node->child1(), resultGPR); 4347 4348 m_jit.loadPtr(JITCompiler::Address(op1GPR, JSWrapperObject::internalValueCellOffset()), resultGPR); 4349 4350 JITCompiler::Jump done = m_jit.jump(); 4351 isString.link(&m_jit); 4352 m_jit.move(op1GPR, resultGPR); 4353 done.link(&m_jit); 4354 4355 m_interpreter.filter(node->child1(), SpecString | SpecStringObject); 4356 4357 cellResult(resultGPR, node); 4358 break; 4359 } 4360 4361 case CellUse: { 4362 GPRResult result(this); 4363 GPRReg resultGPR = result.gpr(); 4364 4365 // We flush registers instead of silent spill/fill because in this mode we 4366 // believe that most likely the input is not a string, and we need to take 4367 // slow path. 4368 flushRegisters(); 4369 JITCompiler::Jump done; 4370 if (node->child1()->prediction() & SpecString) { 4371 JITCompiler::Jump needCall = m_jit.branchStructurePtr( 4372 JITCompiler::NotEqual, 4373 JITCompiler::Address(op1GPR, JSCell::structureIDOffset()), 4374 m_jit.vm()->stringStructure.get()); 4375 m_jit.move(op1GPR, resultGPR); 4376 done = m_jit.jump(); 4377 needCall.link(&m_jit); 4378 } 4379 callOperation(operationToStringOnCell, resultGPR, op1GPR); 4380 if (done.isSet()) 4381 done.link(&m_jit); 4382 cellResult(resultGPR, node); 4383 break; 4384 } 4385 4386 default: 4387 RELEASE_ASSERT_NOT_REACHED(); 4388 } 4389} 4390 4391void SpeculativeJIT::compileNewStringObject(Node* node) 4392{ 4393 SpeculateCellOperand operand(this, node->child1()); 4394 4395 GPRTemporary result(this); 4396 GPRTemporary scratch1(this); 4397 GPRTemporary scratch2(this); 4398 4399 GPRReg operandGPR = operand.gpr(); 4400 GPRReg resultGPR = result.gpr(); 4401 GPRReg scratch1GPR = scratch1.gpr(); 4402 GPRReg scratch2GPR = scratch2.gpr(); 4403 4404 JITCompiler::JumpList slowPath; 4405 4406 emitAllocateJSObject<StringObject>( 4407 resultGPR, TrustedImmPtr(node->structure()), TrustedImmPtr(0), scratch1GPR, scratch2GPR, 4408 slowPath); 4409 4410 m_jit.storePtr( 4411 TrustedImmPtr(StringObject::info()), 4412 JITCompiler::Address(resultGPR, JSDestructibleObject::classInfoOffset())); 4413#if USE(JSVALUE64) 4414 m_jit.store64( 4415 operandGPR, JITCompiler::Address(resultGPR, JSWrapperObject::internalValueOffset())); 4416#else 4417 m_jit.store32( 4418 TrustedImm32(JSValue::CellTag), 4419 JITCompiler::Address(resultGPR, JSWrapperObject::internalValueOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag))); 4420 m_jit.store32( 4421 operandGPR, 4422 JITCompiler::Address(resultGPR, JSWrapperObject::internalValueOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload))); 4423#endif 4424 4425 addSlowPathGenerator(slowPathCall( 4426 slowPath, this, operationNewStringObject, resultGPR, operandGPR, node->structure())); 4427 4428 cellResult(resultGPR, node); 4429} 4430 4431void SpeculativeJIT::compileNewTypedArray(Node* node) 4432{ 4433 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic); 4434 TypedArrayType type = node->typedArrayType(); 4435 Structure* structure = globalObject->typedArrayStructure(type); 4436 4437 SpeculateInt32Operand size(this, node->child1()); 4438 GPRReg sizeGPR = size.gpr(); 4439 4440 GPRTemporary result(this); 4441 GPRTemporary storage(this); 4442 GPRTemporary scratch(this); 4443 GPRTemporary scratch2(this); 4444 GPRReg resultGPR = result.gpr(); 4445 GPRReg storageGPR = storage.gpr(); 4446 GPRReg scratchGPR = scratch.gpr(); 4447 GPRReg scratchGPR2 = scratch2.gpr(); 4448 4449 JITCompiler::JumpList slowCases; 4450 4451 slowCases.append(m_jit.branch32( 4452 MacroAssembler::Above, sizeGPR, TrustedImm32(JSArrayBufferView::fastSizeLimit))); 4453 slowCases.append(m_jit.branchTest32(MacroAssembler::Zero, sizeGPR)); 4454 4455 m_jit.move(sizeGPR, scratchGPR); 4456 m_jit.lshift32(TrustedImm32(logElementSize(type)), scratchGPR); 4457 if (elementSize(type) < 8) { 4458 m_jit.add32(TrustedImm32(7), scratchGPR); 4459 m_jit.and32(TrustedImm32(~7), scratchGPR); 4460 } 4461 slowCases.append( 4462 emitAllocateBasicStorage(scratchGPR, storageGPR)); 4463 4464 m_jit.subPtr(scratchGPR, storageGPR); 4465 4466 emitAllocateJSObject<JSArrayBufferView>( 4467 resultGPR, TrustedImmPtr(structure), TrustedImmPtr(0), scratchGPR, scratchGPR2, 4468 slowCases); 4469 4470 m_jit.storePtr( 4471 storageGPR, 4472 MacroAssembler::Address(resultGPR, JSArrayBufferView::offsetOfVector())); 4473 m_jit.store32( 4474 sizeGPR, 4475 MacroAssembler::Address(resultGPR, JSArrayBufferView::offsetOfLength())); 4476 m_jit.store32( 4477 TrustedImm32(FastTypedArray), 4478 MacroAssembler::Address(resultGPR, JSArrayBufferView::offsetOfMode())); 4479 4480#if USE(JSVALUE32_64) 4481 MacroAssembler::Jump done = m_jit.branchTest32(MacroAssembler::Zero, sizeGPR); 4482 m_jit.move(sizeGPR, scratchGPR); 4483 if (elementSize(type) != 4) { 4484 if (elementSize(type) > 4) 4485 m_jit.lshift32(TrustedImm32(logElementSize(type) - 2), scratchGPR); 4486 else { 4487 if (elementSize(type) > 1) 4488 m_jit.lshift32(TrustedImm32(logElementSize(type)), scratchGPR); 4489 m_jit.add32(TrustedImm32(3), scratchGPR); 4490 m_jit.urshift32(TrustedImm32(2), scratchGPR); 4491 } 4492 } 4493 MacroAssembler::Label loop = m_jit.label(); 4494 m_jit.sub32(TrustedImm32(1), scratchGPR); 4495 m_jit.store32( 4496 TrustedImm32(0), 4497 MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesFour)); 4498 m_jit.branchTest32(MacroAssembler::NonZero, scratchGPR).linkTo(loop, &m_jit); 4499 done.link(&m_jit); 4500#endif // USE(JSVALUE32_64) 4501 4502 addSlowPathGenerator(slowPathCall( 4503 slowCases, this, operationNewTypedArrayWithSizeForType(type), 4504 resultGPR, structure, sizeGPR)); 4505 4506 cellResult(resultGPR, node); 4507} 4508 4509void SpeculativeJIT::speculateInt32(Edge edge) 4510{ 4511 if (!needsTypeCheck(edge, SpecInt32)) 4512 return; 4513 4514 (SpeculateInt32Operand(this, edge)).gpr(); 4515} 4516 4517void SpeculativeJIT::speculateNumber(Edge edge) 4518{ 4519 if (!needsTypeCheck(edge, SpecBytecodeNumber)) 4520 return; 4521 4522 JSValueOperand value(this, edge, ManualOperandSpeculation); 4523#if USE(JSVALUE64) 4524 GPRReg gpr = value.gpr(); 4525 typeCheck( 4526 JSValueRegs(gpr), edge, SpecBytecodeNumber, 4527 m_jit.branchTest64(MacroAssembler::Zero, gpr, GPRInfo::tagTypeNumberRegister)); 4528#else 4529 GPRReg tagGPR = value.tagGPR(); 4530 DFG_TYPE_CHECK( 4531 value.jsValueRegs(), edge, ~SpecInt32, 4532 m_jit.branch32(MacroAssembler::Equal, tagGPR, TrustedImm32(JSValue::Int32Tag))); 4533 DFG_TYPE_CHECK( 4534 value.jsValueRegs(), edge, SpecBytecodeNumber, 4535 m_jit.branch32(MacroAssembler::AboveOrEqual, tagGPR, TrustedImm32(JSValue::LowestTag))); 4536#endif 4537} 4538 4539void SpeculativeJIT::speculateDoubleReal(Edge edge) 4540{ 4541 if (!needsTypeCheck(edge, SpecDoubleReal)) 4542 return; 4543 4544 SpeculateDoubleOperand operand(this, edge); 4545 FPRReg fpr = operand.fpr(); 4546 typeCheck( 4547 JSValueRegs(), edge, SpecDoubleReal, 4548 m_jit.branchDouble( 4549 MacroAssembler::DoubleNotEqualOrUnordered, fpr, fpr)); 4550} 4551 4552void SpeculativeJIT::speculateBoolean(Edge edge) 4553{ 4554 if (!needsTypeCheck(edge, SpecBoolean)) 4555 return; 4556 4557 (SpeculateBooleanOperand(this, edge)).gpr(); 4558} 4559 4560void SpeculativeJIT::speculateCell(Edge edge) 4561{ 4562 if (!needsTypeCheck(edge, SpecCell)) 4563 return; 4564 4565 (SpeculateCellOperand(this, edge)).gpr(); 4566} 4567 4568void SpeculativeJIT::speculateObject(Edge edge) 4569{ 4570 if (!needsTypeCheck(edge, SpecObject)) 4571 return; 4572 4573 SpeculateCellOperand operand(this, edge); 4574 GPRReg gpr = operand.gpr(); 4575 DFG_TYPE_CHECK( 4576 JSValueSource::unboxedCell(gpr), edge, SpecObject, m_jit.branchStructurePtr( 4577 MacroAssembler::Equal, 4578 MacroAssembler::Address(gpr, JSCell::structureIDOffset()), 4579 m_jit.vm()->stringStructure.get())); 4580} 4581 4582void SpeculativeJIT::speculateFinalObject(Edge edge) 4583{ 4584 if (!needsTypeCheck(edge, SpecFinalObject)) 4585 return; 4586 4587 SpeculateCellOperand operand(this, edge); 4588 GPRReg gpr = operand.gpr(); 4589 DFG_TYPE_CHECK( 4590 JSValueSource::unboxedCell(gpr), edge, SpecFinalObject, m_jit.branch8( 4591 MacroAssembler::NotEqual, 4592 MacroAssembler::Address(gpr, JSCell::typeInfoTypeOffset()), 4593 TrustedImm32(FinalObjectType))); 4594} 4595 4596void SpeculativeJIT::speculateObjectOrOther(Edge edge) 4597{ 4598 if (!needsTypeCheck(edge, SpecObject | SpecOther)) 4599 return; 4600 4601 JSValueOperand operand(this, edge, ManualOperandSpeculation); 4602 GPRTemporary temp(this); 4603 GPRReg tempGPR = temp.gpr(); 4604 MacroAssembler::Jump notCell = branchNotCell(operand.jsValueRegs()); 4605 GPRReg gpr = operand.jsValueRegs().payloadGPR(); 4606 DFG_TYPE_CHECK( 4607 operand.jsValueRegs(), edge, (~SpecCell) | SpecObject, m_jit.branchStructurePtr( 4608 MacroAssembler::Equal, 4609 MacroAssembler::Address(gpr, JSCell::structureIDOffset()), 4610 m_jit.vm()->stringStructure.get())); 4611 MacroAssembler::Jump done = m_jit.jump(); 4612 notCell.link(&m_jit); 4613 if (needsTypeCheck(edge, SpecCell | SpecOther)) { 4614 typeCheck( 4615 operand.jsValueRegs(), edge, SpecCell | SpecOther, 4616 branchNotOther(operand.jsValueRegs(), tempGPR)); 4617 } 4618 done.link(&m_jit); 4619} 4620 4621void SpeculativeJIT::speculateString(Edge edge, GPRReg cell) 4622{ 4623 DFG_TYPE_CHECK( 4624 JSValueSource::unboxedCell(cell), edge, SpecString | ~SpecCell, 4625 m_jit.branchStructurePtr( 4626 MacroAssembler::NotEqual, 4627 MacroAssembler::Address(cell, JSCell::structureIDOffset()), 4628 m_jit.vm()->stringStructure.get())); 4629} 4630 4631void SpeculativeJIT::speculateStringIdentAndLoadStorage(Edge edge, GPRReg string, GPRReg storage) 4632{ 4633 m_jit.loadPtr(MacroAssembler::Address(string, JSString::offsetOfValue()), storage); 4634 4635 if (!needsTypeCheck(edge, SpecStringIdent | ~SpecString)) 4636 return; 4637 4638 speculationCheck( 4639 BadType, JSValueSource::unboxedCell(string), edge, 4640 m_jit.branchTestPtr(MacroAssembler::Zero, storage)); 4641 speculationCheck( 4642 BadType, JSValueSource::unboxedCell(string), edge, m_jit.branchTest32( 4643 MacroAssembler::Zero, 4644 MacroAssembler::Address(storage, StringImpl::flagsOffset()), 4645 MacroAssembler::TrustedImm32(StringImpl::flagIsAtomic()))); 4646 4647 m_interpreter.filter(edge, SpecStringIdent | ~SpecString); 4648} 4649 4650void SpeculativeJIT::speculateStringIdent(Edge edge, GPRReg string) 4651{ 4652 if (!needsTypeCheck(edge, SpecStringIdent)) 4653 return; 4654 4655 GPRTemporary temp(this); 4656 speculateStringIdentAndLoadStorage(edge, string, temp.gpr()); 4657} 4658 4659void SpeculativeJIT::speculateStringIdent(Edge edge) 4660{ 4661 if (!needsTypeCheck(edge, SpecStringIdent)) 4662 return; 4663 4664 SpeculateCellOperand operand(this, edge); 4665 GPRReg gpr = operand.gpr(); 4666 speculateString(edge, gpr); 4667 speculateStringIdent(edge, gpr); 4668} 4669 4670void SpeculativeJIT::speculateString(Edge edge) 4671{ 4672 if (!needsTypeCheck(edge, SpecString)) 4673 return; 4674 4675 SpeculateCellOperand operand(this, edge); 4676 speculateString(edge, operand.gpr()); 4677} 4678 4679void SpeculativeJIT::speculateStringObject(Edge edge, GPRReg gpr) 4680{ 4681 speculateStringObjectForStructure(edge, JITCompiler::Address(gpr, JSCell::structureIDOffset())); 4682} 4683 4684void SpeculativeJIT::speculateStringObject(Edge edge) 4685{ 4686 if (!needsTypeCheck(edge, SpecStringObject)) 4687 return; 4688 4689 SpeculateCellOperand operand(this, edge); 4690 GPRReg gpr = operand.gpr(); 4691 if (!needsTypeCheck(edge, SpecStringObject)) 4692 return; 4693 4694 speculateStringObject(edge, gpr); 4695 m_interpreter.filter(edge, SpecStringObject); 4696} 4697 4698void SpeculativeJIT::speculateStringOrStringObject(Edge edge) 4699{ 4700 if (!needsTypeCheck(edge, SpecString | SpecStringObject)) 4701 return; 4702 4703 SpeculateCellOperand operand(this, edge); 4704 GPRReg gpr = operand.gpr(); 4705 if (!needsTypeCheck(edge, SpecString | SpecStringObject)) 4706 return; 4707 4708 GPRTemporary structureID(this); 4709 GPRReg structureIDGPR = structureID.gpr(); 4710 4711 m_jit.load32(JITCompiler::Address(gpr, JSCell::structureIDOffset()), structureIDGPR); 4712 JITCompiler::Jump isString = m_jit.branchStructurePtr( 4713 JITCompiler::Equal, 4714 structureIDGPR, 4715 m_jit.vm()->stringStructure.get()); 4716 4717 speculateStringObjectForStructure(edge, structureIDGPR); 4718 4719 isString.link(&m_jit); 4720 4721 m_interpreter.filter(edge, SpecString | SpecStringObject); 4722} 4723 4724void SpeculativeJIT::speculateNotStringVar(Edge edge) 4725{ 4726 JSValueOperand operand(this, edge, ManualOperandSpeculation); 4727 GPRTemporary temp(this); 4728 GPRReg tempGPR = temp.gpr(); 4729 4730 JITCompiler::Jump notCell = branchNotCell(operand.jsValueRegs()); 4731 GPRReg cell = operand.jsValueRegs().payloadGPR(); 4732 4733 JITCompiler::Jump notString = m_jit.branchStructurePtr( 4734 MacroAssembler::NotEqual, 4735 MacroAssembler::Address(cell, JSCell::structureIDOffset()), 4736 m_jit.vm()->stringStructure.get()); 4737 4738 speculateStringIdentAndLoadStorage(edge, cell, tempGPR); 4739 4740 notString.link(&m_jit); 4741 notCell.link(&m_jit); 4742} 4743 4744void SpeculativeJIT::speculateNotCell(Edge edge) 4745{ 4746 if (!needsTypeCheck(edge, ~SpecCell)) 4747 return; 4748 4749 JSValueOperand operand(this, edge, ManualOperandSpeculation); 4750 typeCheck(operand.jsValueRegs(), edge, ~SpecCell, branchIsCell(operand.jsValueRegs())); 4751} 4752 4753void SpeculativeJIT::speculateOther(Edge edge) 4754{ 4755 if (!needsTypeCheck(edge, SpecOther)) 4756 return; 4757 4758 JSValueOperand operand(this, edge, ManualOperandSpeculation); 4759 GPRTemporary temp(this); 4760 GPRReg tempGPR = temp.gpr(); 4761 typeCheck( 4762 operand.jsValueRegs(), edge, SpecOther, 4763 branchNotOther(operand.jsValueRegs(), tempGPR)); 4764} 4765 4766void SpeculativeJIT::speculateMisc(Edge edge, JSValueRegs regs) 4767{ 4768#if USE(JSVALUE64) 4769 DFG_TYPE_CHECK( 4770 regs, edge, SpecMisc, 4771 m_jit.branch64(MacroAssembler::Above, regs.gpr(), MacroAssembler::TrustedImm64(TagBitTypeOther | TagBitBool | TagBitUndefined))); 4772#else 4773 DFG_TYPE_CHECK( 4774 regs, edge, ~SpecInt32, 4775 m_jit.branch32(MacroAssembler::Equal, regs.tagGPR(), MacroAssembler::TrustedImm32(JSValue::Int32Tag))); 4776 DFG_TYPE_CHECK( 4777 regs, edge, SpecMisc, 4778 m_jit.branch32(MacroAssembler::Below, regs.tagGPR(), MacroAssembler::TrustedImm32(JSValue::UndefinedTag))); 4779#endif 4780} 4781 4782void SpeculativeJIT::speculateMisc(Edge edge) 4783{ 4784 if (!needsTypeCheck(edge, SpecMisc)) 4785 return; 4786 4787 JSValueOperand operand(this, edge, ManualOperandSpeculation); 4788 speculateMisc(edge, operand.jsValueRegs()); 4789} 4790 4791void SpeculativeJIT::speculate(Node*, Edge edge) 4792{ 4793 switch (edge.useKind()) { 4794 case UntypedUse: 4795 break; 4796 case KnownInt32Use: 4797 ASSERT(!needsTypeCheck(edge, SpecInt32)); 4798 break; 4799 case DoubleRepUse: 4800 ASSERT(!needsTypeCheck(edge, SpecFullDouble)); 4801 break; 4802 case Int52RepUse: 4803 ASSERT(!needsTypeCheck(edge, SpecMachineInt)); 4804 break; 4805 case KnownCellUse: 4806 ASSERT(!needsTypeCheck(edge, SpecCell)); 4807 break; 4808 case KnownStringUse: 4809 ASSERT(!needsTypeCheck(edge, SpecString)); 4810 break; 4811 case Int32Use: 4812 speculateInt32(edge); 4813 break; 4814 case NumberUse: 4815 speculateNumber(edge); 4816 break; 4817 case DoubleRepRealUse: 4818 speculateDoubleReal(edge); 4819 break; 4820#if USE(JSVALUE64) 4821 case MachineIntUse: 4822 speculateMachineInt(edge); 4823 break; 4824 case DoubleRepMachineIntUse: 4825 speculateDoubleRepMachineInt(edge); 4826 break; 4827#endif 4828 case BooleanUse: 4829 speculateBoolean(edge); 4830 break; 4831 case CellUse: 4832 speculateCell(edge); 4833 break; 4834 case ObjectUse: 4835 speculateObject(edge); 4836 break; 4837 case FinalObjectUse: 4838 speculateFinalObject(edge); 4839 break; 4840 case ObjectOrOtherUse: 4841 speculateObjectOrOther(edge); 4842 break; 4843 case StringIdentUse: 4844 speculateStringIdent(edge); 4845 break; 4846 case StringUse: 4847 speculateString(edge); 4848 break; 4849 case StringObjectUse: 4850 speculateStringObject(edge); 4851 break; 4852 case StringOrStringObjectUse: 4853 speculateStringOrStringObject(edge); 4854 break; 4855 case NotStringVarUse: 4856 speculateNotStringVar(edge); 4857 break; 4858 case NotCellUse: 4859 speculateNotCell(edge); 4860 break; 4861 case OtherUse: 4862 speculateOther(edge); 4863 break; 4864 case MiscUse: 4865 speculateMisc(edge); 4866 break; 4867 default: 4868 RELEASE_ASSERT_NOT_REACHED(); 4869 break; 4870 } 4871} 4872 4873void SpeculativeJIT::emitSwitchIntJump( 4874 SwitchData* data, GPRReg value, GPRReg scratch) 4875{ 4876 SimpleJumpTable& table = m_jit.codeBlock()->switchJumpTable(data->switchTableIndex); 4877 table.ensureCTITable(); 4878 m_jit.sub32(Imm32(table.min), value); 4879 addBranch( 4880 m_jit.branch32(JITCompiler::AboveOrEqual, value, Imm32(table.ctiOffsets.size())), 4881 data->fallThrough.block); 4882 m_jit.move(TrustedImmPtr(table.ctiOffsets.begin()), scratch); 4883 m_jit.loadPtr(JITCompiler::BaseIndex(scratch, value, JITCompiler::timesPtr()), scratch); 4884 m_jit.jump(scratch); 4885 data->didUseJumpTable = true; 4886} 4887 4888void SpeculativeJIT::emitSwitchImm(Node* node, SwitchData* data) 4889{ 4890 switch (node->child1().useKind()) { 4891 case Int32Use: { 4892 SpeculateInt32Operand value(this, node->child1()); 4893 GPRTemporary temp(this); 4894 emitSwitchIntJump(data, value.gpr(), temp.gpr()); 4895 noResult(node); 4896 break; 4897 } 4898 4899 case UntypedUse: { 4900 JSValueOperand value(this, node->child1()); 4901 GPRTemporary temp(this); 4902 JSValueRegs valueRegs = value.jsValueRegs(); 4903 GPRReg scratch = temp.gpr(); 4904 4905 value.use(); 4906 4907#if USE(JSVALUE64) 4908 JITCompiler::Jump notInt = m_jit.branch64( 4909 JITCompiler::Below, valueRegs.gpr(), GPRInfo::tagTypeNumberRegister); 4910 emitSwitchIntJump(data, valueRegs.gpr(), scratch); 4911 notInt.link(&m_jit); 4912 addBranch( 4913 m_jit.branchTest64( 4914 JITCompiler::Zero, valueRegs.gpr(), GPRInfo::tagTypeNumberRegister), 4915 data->fallThrough.block); 4916 silentSpillAllRegisters(scratch); 4917 callOperation(operationFindSwitchImmTargetForDouble, scratch, valueRegs.gpr(), data->switchTableIndex); 4918 silentFillAllRegisters(scratch); 4919 m_jit.jump(scratch); 4920#else 4921 JITCompiler::Jump notInt = m_jit.branch32( 4922 JITCompiler::NotEqual, valueRegs.tagGPR(), TrustedImm32(JSValue::Int32Tag)); 4923 emitSwitchIntJump(data, valueRegs.payloadGPR(), scratch); 4924 notInt.link(&m_jit); 4925 addBranch( 4926 m_jit.branch32( 4927 JITCompiler::AboveOrEqual, valueRegs.tagGPR(), 4928 TrustedImm32(JSValue::LowestTag)), 4929 data->fallThrough.block); 4930 silentSpillAllRegisters(scratch); 4931 callOperation(operationFindSwitchImmTargetForDouble, scratch, valueRegs, data->switchTableIndex); 4932 silentFillAllRegisters(scratch); 4933 m_jit.jump(scratch); 4934#endif 4935 noResult(node, UseChildrenCalledExplicitly); 4936 break; 4937 } 4938 4939 default: 4940 RELEASE_ASSERT_NOT_REACHED(); 4941 break; 4942 } 4943} 4944 4945void SpeculativeJIT::emitSwitchCharStringJump( 4946 SwitchData* data, GPRReg value, GPRReg scratch) 4947{ 4948 addBranch( 4949 m_jit.branch32( 4950 MacroAssembler::NotEqual, 4951 MacroAssembler::Address(value, JSString::offsetOfLength()), 4952 TrustedImm32(1)), 4953 data->fallThrough.block); 4954 4955 m_jit.loadPtr(MacroAssembler::Address(value, JSString::offsetOfValue()), scratch); 4956 4957 addSlowPathGenerator( 4958 slowPathCall( 4959 m_jit.branchTestPtr(MacroAssembler::Zero, scratch), 4960 this, operationResolveRope, scratch, value)); 4961 4962 m_jit.loadPtr(MacroAssembler::Address(scratch, StringImpl::dataOffset()), value); 4963 4964 JITCompiler::Jump is8Bit = m_jit.branchTest32( 4965 MacroAssembler::NonZero, 4966 MacroAssembler::Address(scratch, StringImpl::flagsOffset()), 4967 TrustedImm32(StringImpl::flagIs8Bit())); 4968 4969 m_jit.load16(MacroAssembler::Address(value), scratch); 4970 4971 JITCompiler::Jump ready = m_jit.jump(); 4972 4973 is8Bit.link(&m_jit); 4974 m_jit.load8(MacroAssembler::Address(value), scratch); 4975 4976 ready.link(&m_jit); 4977 emitSwitchIntJump(data, scratch, value); 4978} 4979 4980void SpeculativeJIT::emitSwitchChar(Node* node, SwitchData* data) 4981{ 4982 switch (node->child1().useKind()) { 4983 case StringUse: { 4984 SpeculateCellOperand op1(this, node->child1()); 4985 GPRTemporary temp(this); 4986 4987 GPRReg op1GPR = op1.gpr(); 4988 GPRReg tempGPR = temp.gpr(); 4989 4990 op1.use(); 4991 4992 speculateString(node->child1(), op1GPR); 4993 emitSwitchCharStringJump(data, op1GPR, tempGPR); 4994 noResult(node, UseChildrenCalledExplicitly); 4995 break; 4996 } 4997 4998 case UntypedUse: { 4999 JSValueOperand op1(this, node->child1()); 5000 GPRTemporary temp(this); 5001 5002 JSValueRegs op1Regs = op1.jsValueRegs(); 5003 GPRReg tempGPR = temp.gpr(); 5004 5005 op1.use(); 5006 5007 addBranch(branchNotCell(op1Regs), data->fallThrough.block); 5008 5009 addBranch( 5010 m_jit.branchStructurePtr( 5011 MacroAssembler::NotEqual, 5012 MacroAssembler::Address(op1Regs.payloadGPR(), JSCell::structureIDOffset()), 5013 m_jit.vm()->stringStructure.get()), 5014 data->fallThrough.block); 5015 5016 emitSwitchCharStringJump(data, op1Regs.payloadGPR(), tempGPR); 5017 noResult(node, UseChildrenCalledExplicitly); 5018 break; 5019 } 5020 5021 default: 5022 RELEASE_ASSERT_NOT_REACHED(); 5023 break; 5024 } 5025} 5026 5027bool SpeculativeJIT::StringSwitchCase::operator<( 5028 const SpeculativeJIT::StringSwitchCase& other) const 5029{ 5030 unsigned minLength = std::min(string->length(), other.string->length()); 5031 for (unsigned i = 0; i < minLength; ++i) { 5032 if (string->at(i) == other.string->at(i)) 5033 continue; 5034 return string->at(i) < other.string->at(i); 5035 } 5036 return string->length() < other.string->length(); 5037} 5038 5039namespace { 5040 5041struct CharacterCase { 5042 bool operator<(const CharacterCase& other) const 5043 { 5044 return character < other.character; 5045 } 5046 5047 LChar character; 5048 unsigned begin; 5049 unsigned end; 5050}; 5051 5052} // anonymous namespace 5053 5054void SpeculativeJIT::emitBinarySwitchStringRecurse( 5055 SwitchData* data, const Vector<SpeculativeJIT::StringSwitchCase>& cases, 5056 unsigned numChecked, unsigned begin, unsigned end, GPRReg buffer, GPRReg length, 5057 GPRReg temp, unsigned alreadyCheckedLength, bool checkedExactLength) 5058{ 5059 static const bool verbose = false; 5060 5061 if (verbose) { 5062 dataLog("We're down to the following cases, alreadyCheckedLength = ", alreadyCheckedLength, ":\n"); 5063 for (unsigned i = begin; i < end; ++i) { 5064 dataLog(" ", cases[i].string, "\n"); 5065 } 5066 } 5067 5068 if (begin == end) { 5069 jump(data->fallThrough.block, ForceJump); 5070 return; 5071 } 5072 5073 unsigned minLength = cases[begin].string->length(); 5074 unsigned commonChars = minLength; 5075 bool allLengthsEqual = true; 5076 for (unsigned i = begin + 1; i < end; ++i) { 5077 unsigned myCommonChars = numChecked; 5078 for (unsigned j = numChecked; 5079 j < std::min(cases[begin].string->length(), cases[i].string->length()); 5080 ++j) { 5081 if (cases[begin].string->at(j) != cases[i].string->at(j)) { 5082 if (verbose) 5083 dataLog("string(", cases[i].string, ")[", j, "] != string(", cases[begin].string, ")[", j, "]\n"); 5084 break; 5085 } 5086 myCommonChars++; 5087 } 5088 commonChars = std::min(commonChars, myCommonChars); 5089 if (minLength != cases[i].string->length()) 5090 allLengthsEqual = false; 5091 minLength = std::min(minLength, cases[i].string->length()); 5092 } 5093 5094 if (checkedExactLength) { 5095 RELEASE_ASSERT(alreadyCheckedLength == minLength); 5096 RELEASE_ASSERT(allLengthsEqual); 5097 } 5098 5099 RELEASE_ASSERT(minLength >= commonChars); 5100 5101 if (verbose) 5102 dataLog("length = ", minLength, ", commonChars = ", commonChars, ", allLengthsEqual = ", allLengthsEqual, "\n"); 5103 5104 if (!allLengthsEqual && alreadyCheckedLength < minLength) 5105 branch32(MacroAssembler::Below, length, Imm32(minLength), data->fallThrough.block); 5106 if (allLengthsEqual && (alreadyCheckedLength < minLength || !checkedExactLength)) 5107 branch32(MacroAssembler::NotEqual, length, Imm32(minLength), data->fallThrough.block); 5108 5109 for (unsigned i = numChecked; i < commonChars; ++i) { 5110 branch8( 5111 MacroAssembler::NotEqual, MacroAssembler::Address(buffer, i), 5112 TrustedImm32(cases[begin].string->at(i)), data->fallThrough.block); 5113 } 5114 5115 if (minLength == commonChars) { 5116 // This is the case where one of the cases is a prefix of all of the other cases. 5117 // We've already checked that the input string is a prefix of all of the cases, 5118 // so we just check length to jump to that case. 5119 5120 if (!ASSERT_DISABLED) { 5121 ASSERT(cases[begin].string->length() == commonChars); 5122 for (unsigned i = begin + 1; i < end; ++i) 5123 ASSERT(cases[i].string->length() > commonChars); 5124 } 5125 5126 if (allLengthsEqual) { 5127 RELEASE_ASSERT(end == begin + 1); 5128 jump(cases[begin].target, ForceJump); 5129 return; 5130 } 5131 5132 branch32(MacroAssembler::Equal, length, Imm32(commonChars), cases[begin].target); 5133 5134 // We've checked if the length is >= minLength, and then we checked if the 5135 // length is == commonChars. We get to this point if it is >= minLength but not 5136 // == commonChars. Hence we know that it now must be > minLength, i.e., that 5137 // it's >= minLength + 1. 5138 emitBinarySwitchStringRecurse( 5139 data, cases, commonChars, begin + 1, end, buffer, length, temp, minLength + 1, false); 5140 return; 5141 } 5142 5143 // At this point we know that the string is longer than commonChars, and we've only 5144 // verified commonChars. Use a binary switch on the next unchecked character, i.e. 5145 // string[commonChars]. 5146 5147 RELEASE_ASSERT(end >= begin + 2); 5148 5149 m_jit.load8(MacroAssembler::Address(buffer, commonChars), temp); 5150 5151 Vector<CharacterCase> characterCases; 5152 CharacterCase currentCase; 5153 currentCase.character = cases[begin].string->at(commonChars); 5154 currentCase.begin = begin; 5155 currentCase.end = begin + 1; 5156 for (unsigned i = begin + 1; i < end; ++i) { 5157 if (cases[i].string->at(commonChars) != currentCase.character) { 5158 if (verbose) 5159 dataLog("string(", cases[i].string, ")[", commonChars, "] != string(", cases[begin].string, ")[", commonChars, "]\n"); 5160 currentCase.end = i; 5161 characterCases.append(currentCase); 5162 currentCase.character = cases[i].string->at(commonChars); 5163 currentCase.begin = i; 5164 currentCase.end = i + 1; 5165 } else 5166 currentCase.end = i + 1; 5167 } 5168 characterCases.append(currentCase); 5169 5170 Vector<int64_t> characterCaseValues; 5171 for (unsigned i = 0; i < characterCases.size(); ++i) 5172 characterCaseValues.append(characterCases[i].character); 5173 5174 BinarySwitch binarySwitch(temp, characterCaseValues, BinarySwitch::Int32); 5175 while (binarySwitch.advance(m_jit)) { 5176 const CharacterCase& myCase = characterCases[binarySwitch.caseIndex()]; 5177 emitBinarySwitchStringRecurse( 5178 data, cases, commonChars + 1, myCase.begin, myCase.end, buffer, length, 5179 temp, minLength, allLengthsEqual); 5180 } 5181 5182 addBranch(binarySwitch.fallThrough(), data->fallThrough.block); 5183} 5184 5185void SpeculativeJIT::emitSwitchStringOnString(SwitchData* data, GPRReg string) 5186{ 5187 data->didUseJumpTable = true; 5188 5189 bool canDoBinarySwitch = true; 5190 unsigned totalLength = 0; 5191 5192 for (unsigned i = data->cases.size(); i--;) { 5193 StringImpl* string = data->cases[i].value.stringImpl(); 5194 if (!string->is8Bit()) { 5195 canDoBinarySwitch = false; 5196 break; 5197 } 5198 if (string->length() > Options::maximumBinaryStringSwitchCaseLength()) { 5199 canDoBinarySwitch = false; 5200 break; 5201 } 5202 totalLength += string->length(); 5203 } 5204 5205 if (!canDoBinarySwitch || totalLength > Options::maximumBinaryStringSwitchTotalLength()) { 5206 flushRegisters(); 5207 callOperation( 5208 operationSwitchString, string, data->switchTableIndex, string); 5209 m_jit.jump(string); 5210 return; 5211 } 5212 5213 GPRTemporary length(this); 5214 GPRTemporary temp(this); 5215 5216 GPRReg lengthGPR = length.gpr(); 5217 GPRReg tempGPR = temp.gpr(); 5218 5219 m_jit.load32(MacroAssembler::Address(string, JSString::offsetOfLength()), lengthGPR); 5220 m_jit.loadPtr(MacroAssembler::Address(string, JSString::offsetOfValue()), tempGPR); 5221 5222 MacroAssembler::JumpList slowCases; 5223 slowCases.append(m_jit.branchTestPtr(MacroAssembler::Zero, tempGPR)); 5224 slowCases.append(m_jit.branchTest32( 5225 MacroAssembler::Zero, 5226 MacroAssembler::Address(tempGPR, StringImpl::flagsOffset()), 5227 TrustedImm32(StringImpl::flagIs8Bit()))); 5228 5229 m_jit.loadPtr(MacroAssembler::Address(tempGPR, StringImpl::dataOffset()), string); 5230 5231 Vector<StringSwitchCase> cases; 5232 for (unsigned i = 0; i < data->cases.size(); ++i) { 5233 cases.append( 5234 StringSwitchCase(data->cases[i].value.stringImpl(), data->cases[i].target.block)); 5235 } 5236 5237 std::sort(cases.begin(), cases.end()); 5238 5239 emitBinarySwitchStringRecurse( 5240 data, cases, 0, 0, cases.size(), string, lengthGPR, tempGPR, 0, false); 5241 5242 slowCases.link(&m_jit); 5243 silentSpillAllRegisters(string); 5244 callOperation(operationSwitchString, string, data->switchTableIndex, string); 5245 silentFillAllRegisters(string); 5246 m_jit.jump(string); 5247} 5248 5249void SpeculativeJIT::emitSwitchString(Node* node, SwitchData* data) 5250{ 5251 switch (node->child1().useKind()) { 5252 case StringIdentUse: { 5253 SpeculateCellOperand op1(this, node->child1()); 5254 GPRTemporary temp(this); 5255 5256 GPRReg op1GPR = op1.gpr(); 5257 GPRReg tempGPR = temp.gpr(); 5258 5259 speculateString(node->child1(), op1GPR); 5260 speculateStringIdentAndLoadStorage(node->child1(), op1GPR, tempGPR); 5261 5262 Vector<int64_t> identifierCaseValues; 5263 for (unsigned i = 0; i < data->cases.size(); ++i) { 5264 identifierCaseValues.append( 5265 static_cast<int64_t>(bitwise_cast<intptr_t>(data->cases[i].value.stringImpl()))); 5266 } 5267 5268 BinarySwitch binarySwitch(tempGPR, identifierCaseValues, BinarySwitch::IntPtr); 5269 while (binarySwitch.advance(m_jit)) 5270 jump(data->cases[binarySwitch.caseIndex()].target.block, ForceJump); 5271 addBranch(binarySwitch.fallThrough(), data->fallThrough.block); 5272 5273 noResult(node); 5274 break; 5275 } 5276 5277 case StringUse: { 5278 SpeculateCellOperand op1(this, node->child1()); 5279 5280 GPRReg op1GPR = op1.gpr(); 5281 5282 op1.use(); 5283 5284 speculateString(node->child1(), op1GPR); 5285 emitSwitchStringOnString(data, op1GPR); 5286 noResult(node, UseChildrenCalledExplicitly); 5287 break; 5288 } 5289 5290 case UntypedUse: { 5291 JSValueOperand op1(this, node->child1()); 5292 5293 JSValueRegs op1Regs = op1.jsValueRegs(); 5294 5295 op1.use(); 5296 5297 addBranch(branchNotCell(op1Regs), data->fallThrough.block); 5298 5299 addBranch( 5300 m_jit.branchStructurePtr( 5301 MacroAssembler::NotEqual, 5302 MacroAssembler::Address(op1Regs.payloadGPR(), JSCell::structureIDOffset()), 5303 m_jit.vm()->stringStructure.get()), 5304 data->fallThrough.block); 5305 5306 emitSwitchStringOnString(data, op1Regs.payloadGPR()); 5307 noResult(node, UseChildrenCalledExplicitly); 5308 break; 5309 } 5310 5311 default: 5312 RELEASE_ASSERT_NOT_REACHED(); 5313 break; 5314 } 5315} 5316 5317void SpeculativeJIT::emitSwitch(Node* node) 5318{ 5319 SwitchData* data = node->switchData(); 5320 switch (data->kind) { 5321 case SwitchImm: { 5322 emitSwitchImm(node, data); 5323 return; 5324 } 5325 case SwitchChar: { 5326 emitSwitchChar(node, data); 5327 return; 5328 } 5329 case SwitchString: { 5330 emitSwitchString(node, data); 5331 return; 5332 } } 5333 RELEASE_ASSERT_NOT_REACHED(); 5334} 5335 5336void SpeculativeJIT::addBranch(const MacroAssembler::JumpList& jump, BasicBlock* destination) 5337{ 5338 for (unsigned i = jump.jumps().size(); i--;) 5339 addBranch(jump.jumps()[i], destination); 5340} 5341 5342void SpeculativeJIT::linkBranches() 5343{ 5344 for (size_t i = 0; i < m_branches.size(); ++i) { 5345 BranchRecord& branch = m_branches[i]; 5346 branch.jump.linkTo(m_jit.blockHeads()[branch.destination->index], &m_jit); 5347 } 5348} 5349 5350#if ENABLE(GGC) 5351void SpeculativeJIT::compileStoreBarrier(Node* node) 5352{ 5353 switch (node->op()) { 5354 case StoreBarrier: { 5355 SpeculateCellOperand base(this, node->child1()); 5356 GPRTemporary scratch1(this); 5357 GPRTemporary scratch2(this); 5358 5359 writeBarrier(base.gpr(), scratch1.gpr(), scratch2.gpr()); 5360 break; 5361 } 5362 5363 case StoreBarrierWithNullCheck: { 5364 JSValueOperand base(this, node->child1()); 5365 GPRTemporary scratch1(this); 5366 GPRTemporary scratch2(this); 5367 5368#if USE(JSVALUE64) 5369 JITCompiler::Jump isNull = m_jit.branchTest64(JITCompiler::Zero, base.gpr()); 5370 writeBarrier(base.gpr(), scratch1.gpr(), scratch2.gpr()); 5371#else 5372 JITCompiler::Jump isNull = m_jit.branch32(JITCompiler::Equal, base.tagGPR(), TrustedImm32(JSValue::EmptyValueTag)); 5373 writeBarrier(base.payloadGPR(), scratch1.gpr(), scratch2.gpr()); 5374#endif 5375 isNull.link(&m_jit); 5376 break; 5377 } 5378 5379 default: 5380 RELEASE_ASSERT_NOT_REACHED(); 5381 break; 5382 } 5383 5384 noResult(node); 5385} 5386 5387void SpeculativeJIT::storeToWriteBarrierBuffer(GPRReg cell, GPRReg scratch1, GPRReg scratch2) 5388{ 5389 ASSERT(scratch1 != scratch2); 5390 WriteBarrierBuffer* writeBarrierBuffer = &m_jit.vm()->heap.m_writeBarrierBuffer; 5391 m_jit.move(TrustedImmPtr(writeBarrierBuffer), scratch1); 5392 m_jit.load32(MacroAssembler::Address(scratch1, WriteBarrierBuffer::currentIndexOffset()), scratch2); 5393 JITCompiler::Jump needToFlush = m_jit.branch32(MacroAssembler::AboveOrEqual, scratch2, MacroAssembler::Address(scratch1, WriteBarrierBuffer::capacityOffset())); 5394 5395 m_jit.add32(TrustedImm32(1), scratch2); 5396 m_jit.store32(scratch2, MacroAssembler::Address(scratch1, WriteBarrierBuffer::currentIndexOffset())); 5397 5398 m_jit.loadPtr(MacroAssembler::Address(scratch1, WriteBarrierBuffer::bufferOffset()), scratch1); 5399 // We use an offset of -sizeof(void*) because we already added 1 to scratch2. 5400 m_jit.storePtr(cell, MacroAssembler::BaseIndex(scratch1, scratch2, MacroAssembler::ScalePtr, static_cast<int32_t>(-sizeof(void*)))); 5401 5402 JITCompiler::Jump done = m_jit.jump(); 5403 needToFlush.link(&m_jit); 5404 5405 silentSpillAllRegisters(InvalidGPRReg); 5406 callOperation(operationFlushWriteBarrierBuffer, cell); 5407 silentFillAllRegisters(InvalidGPRReg); 5408 5409 done.link(&m_jit); 5410} 5411 5412void SpeculativeJIT::storeToWriteBarrierBuffer(JSCell* cell, GPRReg scratch1, GPRReg scratch2) 5413{ 5414 ASSERT(scratch1 != scratch2); 5415 WriteBarrierBuffer* writeBarrierBuffer = &m_jit.vm()->heap.m_writeBarrierBuffer; 5416 m_jit.move(TrustedImmPtr(writeBarrierBuffer), scratch1); 5417 m_jit.load32(MacroAssembler::Address(scratch1, WriteBarrierBuffer::currentIndexOffset()), scratch2); 5418 JITCompiler::Jump needToFlush = m_jit.branch32(MacroAssembler::AboveOrEqual, scratch2, MacroAssembler::Address(scratch1, WriteBarrierBuffer::capacityOffset())); 5419 5420 m_jit.add32(TrustedImm32(1), scratch2); 5421 m_jit.store32(scratch2, MacroAssembler::Address(scratch1, WriteBarrierBuffer::currentIndexOffset())); 5422 5423 m_jit.loadPtr(MacroAssembler::Address(scratch1, WriteBarrierBuffer::bufferOffset()), scratch1); 5424 // We use an offset of -sizeof(void*) because we already added 1 to scratch2. 5425 m_jit.storePtr(TrustedImmPtr(cell), MacroAssembler::BaseIndex(scratch1, scratch2, MacroAssembler::ScalePtr, static_cast<int32_t>(-sizeof(void*)))); 5426 5427 JITCompiler::Jump done = m_jit.jump(); 5428 needToFlush.link(&m_jit); 5429 5430 // Call C slow path 5431 silentSpillAllRegisters(InvalidGPRReg); 5432 callOperation(operationFlushWriteBarrierBuffer, cell); 5433 silentFillAllRegisters(InvalidGPRReg); 5434 5435 done.link(&m_jit); 5436} 5437 5438void SpeculativeJIT::writeBarrier(GPRReg ownerGPR, JSCell* value, GPRReg scratch1, GPRReg scratch2) 5439{ 5440 if (Heap::isMarked(value)) 5441 return; 5442 5443 JITCompiler::Jump ownerNotMarkedOrAlreadyRemembered = m_jit.checkMarkByte(ownerGPR); 5444 storeToWriteBarrierBuffer(ownerGPR, scratch1, scratch2); 5445 ownerNotMarkedOrAlreadyRemembered.link(&m_jit); 5446} 5447 5448void SpeculativeJIT::writeBarrier(GPRReg ownerGPR, GPRReg scratch1, GPRReg scratch2) 5449{ 5450 JITCompiler::Jump ownerNotMarkedOrAlreadyRemembered = m_jit.checkMarkByte(ownerGPR); 5451 storeToWriteBarrierBuffer(ownerGPR, scratch1, scratch2); 5452 ownerNotMarkedOrAlreadyRemembered.link(&m_jit); 5453} 5454#else 5455void SpeculativeJIT::compileStoreBarrier(Node* node) 5456{ 5457 DFG_NODE_DO_TO_CHILDREN(m_jit.graph(), node, speculate); 5458 noResult(node); 5459} 5460#endif // ENABLE(GGC) 5461 5462} } // namespace JSC::DFG 5463 5464#endif 5465