DFGOSRExitCompiler.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. /*
  2. * Copyright (C) 2011, 2012 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. #include "config.h"
  26. #include "DFGOSRExitCompiler.h"
  27. #if ENABLE(DFG_JIT)
  28. #if !(ENABLE(DETACHED_JIT) && !BUILDING_DETACHED_JIT)
  29. #include "CallFrame.h"
  30. #include "DFGCommon.h"
  31. #include "LinkBuffer.h"
  32. #include "Operations.h"
  33. #include "RepatchBuffer.h"
  34. #include <wtf/StringPrintStream.h>
  35. namespace JSC { namespace DFG {
  36. extern "C" {
  37. void compileOSRExit(ExecState* exec)
  38. {
  39. SamplingRegion samplingRegion("DFG OSR Exit Compilation");
  40. CodeBlock* codeBlock = exec->codeBlock();
  41. ASSERT(codeBlock);
  42. ASSERT(codeBlock->getJITType() == JITCode::DFGJIT);
  43. VM* vm = &exec->vm();
  44. uint32_t exitIndex = vm->osrExitIndex;
  45. OSRExit& exit = codeBlock->osrExit(exitIndex);
  46. #if !ENABLE(DETACHED_JIT) || !BUILDING_DETACHED_JIT
  47. // NOTE: when detached JIT is enabled, we perform this step in the VM process just
  48. // before it crosses the JIT bridge. basically, we want to avoid calling
  49. // jitCompile() from inside the compiler itself since we already handle
  50. // the call from the JIT bridge. otherwise, we need to bring in a lot more
  51. // code into the compiler process...
  52. // Make sure all code on our inline stack is JIT compiled. This is necessary since
  53. // we may opt to inline a code block even before it had ever been compiled by the
  54. // JIT, but our OSR exit infrastructure currently only works if the target of the
  55. // OSR exit is JIT code. This could be changed since there is nothing particularly
  56. // hard about doing an OSR exit into the interpreter, but for now this seems to make
  57. // sense in that if we're OSR exiting from inlined code of a DFG code block, then
  58. // probably it's a good sign that the thing we're exiting into is hot. Even more
  59. // interestingly, since the code was inlined, it may never otherwise get JIT
  60. // compiled since the act of inlining it may ensure that it otherwise never runs.
  61. for (CodeOrigin codeOrigin = exit.m_codeOrigin; codeOrigin.inlineCallFrame; codeOrigin = codeOrigin.inlineCallFrame->caller) {
  62. static_cast<FunctionExecutable*>(codeOrigin.inlineCallFrame->executable.get())
  63. ->baselineCodeBlockFor(codeOrigin.inlineCallFrame->isCall ? CodeForCall : CodeForConstruct)
  64. ->jitCompile(exec);
  65. }
  66. #endif
  67. // Compute the value recoveries.
  68. Operands<ValueRecovery> operands;
  69. codeBlock->variableEventStream().reconstruct(codeBlock, exit.m_codeOrigin, codeBlock->minifiedDFG(), exit.m_streamIndex, operands);
  70. // There may be an override, for forward speculations.
  71. if (!!exit.m_valueRecoveryOverride) {
  72. operands.setOperand(
  73. exit.m_valueRecoveryOverride->operand, exit.m_valueRecoveryOverride->recovery);
  74. }
  75. SpeculationRecovery* recovery = 0;
  76. if (exit.m_recoveryIndex)
  77. recovery = &codeBlock->speculationRecovery(exit.m_recoveryIndex - 1);
  78. #if DFG_ENABLE(DEBUG_VERBOSE)
  79. dataLog(
  80. "Generating OSR exit #", exitIndex, " (seq#", exit.m_streamIndex,
  81. ", bc#", exit.m_codeOrigin.bytecodeIndex, ", ",
  82. exit.m_kind, ") for ", *codeBlock, ".\n");
  83. #endif
  84. {
  85. CCallHelpers jit(vm, codeBlock);
  86. OSRExitCompiler exitCompiler(jit);
  87. jit.jitAssertHasValidCallFrame();
  88. #if ENABLE(DETACHED_JIT)
  89. #pragma message "per bytecode profiler not supported in secure JSCore"
  90. #else
  91. if (vm->m_perBytecodeProfiler && codeBlock->compilation()) {
  92. Profiler::Database& database = *vm->m_perBytecodeProfiler;
  93. Profiler::Compilation* compilation = codeBlock->compilation();
  94. Profiler::OSRExit* profilerExit = compilation->addOSRExit(
  95. exitIndex, Profiler::OriginStack(database, codeBlock, exit.m_codeOrigin),
  96. exit.m_kind,
  97. exit.m_watchpointIndex != std::numeric_limits<unsigned>::max());
  98. jit.add64(CCallHelpers::TrustedImm32(1), CCallHelpers::AbsoluteAddress(profilerExit->counterAddress()));
  99. }
  100. #endif
  101. exitCompiler.compileExit(exit, operands, recovery);
  102. LinkBuffer patchBuffer(*vm, &jit, codeBlock);
  103. exit.m_code = FINALIZE_CODE_IF(
  104. shouldShowDisassembly(),
  105. patchBuffer,
  106. ("DFG OSR exit #%u (bc#%u, %s) from %s",
  107. exitIndex, exit.m_codeOrigin.bytecodeIndex,
  108. exitKindToString(exit.m_kind), toCString(*codeBlock).data()));
  109. }
  110. {
  111. RepatchBuffer repatchBuffer(codeBlock);
  112. repatchBuffer.relink(exit.codeLocationForRepatch(codeBlock), CodeLocationLabel(exit.m_code.code()));
  113. }
  114. vm->osrExitJumpDestination = exit.m_code.code().executableAddress();
  115. }
  116. } // extern "C"
  117. void OSRExitCompiler::handleExitCounts(const OSRExit& exit)
  118. {
  119. m_jit.add32(AssemblyHelpers::TrustedImm32(1), AssemblyHelpers::AbsoluteAddress(&exit.m_count));
  120. m_jit.move(AssemblyHelpers::TrustedImmPtr(m_jit.codeBlock()), GPRInfo::regT0);
  121. AssemblyHelpers::Jump tooFewFails;
  122. m_jit.load32(AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfOSRExitCounter()), GPRInfo::regT2);
  123. m_jit.add32(AssemblyHelpers::TrustedImm32(1), GPRInfo::regT2);
  124. m_jit.store32(GPRInfo::regT2, AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfOSRExitCounter()));
  125. m_jit.move(AssemblyHelpers::TrustedImmPtr(m_jit.baselineCodeBlock()), GPRInfo::regT0);
  126. tooFewFails = m_jit.branch32(AssemblyHelpers::BelowOrEqual, GPRInfo::regT2, AssemblyHelpers::TrustedImm32(m_jit.codeBlock()->exitCountThresholdForReoptimization()));
  127. // Reoptimize as soon as possible.
  128. #if !NUMBER_OF_ARGUMENT_REGISTERS
  129. m_jit.poke(GPRInfo::regT0);
  130. #else
  131. m_jit.move(GPRInfo::regT0, GPRInfo::argumentGPR0);
  132. ASSERT(GPRInfo::argumentGPR0 != GPRInfo::regT1);
  133. #endif
  134. m_jit.move(AssemblyHelpers::TrustedImmPtr(bitwise_cast<void*>(triggerReoptimizationNow)), GPRInfo::regT1);
  135. m_jit.call(GPRInfo::regT1);
  136. AssemblyHelpers::Jump doneAdjusting = m_jit.jump();
  137. tooFewFails.link(&m_jit);
  138. // Adjust the execution counter such that the target is to only optimize after a while.
  139. int32_t activeThreshold =
  140. m_jit.baselineCodeBlock()->counterValueForOptimizeAfterLongWarmUp();
  141. int32_t targetValue = ExecutionCounter::applyMemoryUsageHeuristicsAndConvertToInt(
  142. activeThreshold, m_jit.baselineCodeBlock());
  143. int32_t clippedValue =
  144. ExecutionCounter::clippedThreshold(m_jit.codeBlock()->globalObject(), targetValue);
  145. m_jit.store32(AssemblyHelpers::TrustedImm32(-clippedValue), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecuteCounter()));
  146. m_jit.store32(AssemblyHelpers::TrustedImm32(activeThreshold), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecutionActiveThreshold()));
  147. m_jit.store32(AssemblyHelpers::TrustedImm32(ExecutionCounter::formattedTotalCount(clippedValue)), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecutionTotalCount()));
  148. doneAdjusting.link(&m_jit);
  149. }
  150. } } // namespace JSC::DFG
  151. #endif // #if !(ENABLE(DETACHED_JIT) && !BUILDING_DETACHED_JIT)
  152. #endif // ENABLE(DFG_JIT)