⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 164205 in webkit


Ignore:
Timestamp:
Feb 16, 2014, 10:25:05 PM (13 years ago)
Author:
fpizlo@apple.com
Message:

DFG::prepareOSREntry should be nice to the stack
https://bugs.webkit.org/show_bug.cgi?id=128883

Reviewed by Oliver Hunt.

Previously OSR entry had some FIXME's and some really badly commented-out code for
clearing stack entries to help GC. It also did some permutations on a stack frame
above us, in such a way that it wasn't obviously that we wouldn't clobber our own
stack frame. This function also crashed in ASan.

It just seems like there was too much badness to the whole idea of prepareOSREntry
directly editing the stack. So, I changed it to create a stack frame in a scratch
buffer on the side and then have some assembly code just copy it into place. This
works fine, fixes a FIXME, possibly fixes some stack clobbering, and might help us
make more progress with ASan.

  • dfg/DFGOSREntry.cpp:

(JSC::DFG::prepareOSREntry):

  • dfg/DFGOSREntry.h:
  • dfg/DFGThunks.cpp:

(JSC::DFG::osrEntryThunkGenerator):

  • dfg/DFGThunks.h:
  • jit/JITOpcodes.cpp:

(JSC::JIT::emitSlow_op_loop_hint):

  • jit/JITOperations.cpp:
Location:
trunk/Source/JavaScriptCore
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r164185 r164205  
     12014-02-16  Filip Pizlo  <fpizlo@apple.com>
     2
     3        DFG::prepareOSREntry should be nice to the stack
     4        https://bugs.webkit.org/show_bug.cgi?id=128883
     5
     6        Reviewed by Oliver Hunt.
     7       
     8        Previously OSR entry had some FIXME's and some really badly commented-out code for
     9        clearing stack entries to help GC. It also did some permutations on a stack frame
     10        above us, in such a way that it wasn't obviously that we wouldn't clobber our own
     11        stack frame. This function also crashed in ASan.
     12       
     13        It just seems like there was too much badness to the whole idea of prepareOSREntry
     14        directly editing the stack. So, I changed it to create a stack frame in a scratch
     15        buffer on the side and then have some assembly code just copy it into place. This
     16        works fine, fixes a FIXME, possibly fixes some stack clobbering, and might help us
     17        make more progress with ASan.
     18
     19        * dfg/DFGOSREntry.cpp:
     20        (JSC::DFG::prepareOSREntry):
     21        * dfg/DFGOSREntry.h:
     22        * dfg/DFGThunks.cpp:
     23        (JSC::DFG::osrEntryThunkGenerator):
     24        * dfg/DFGThunks.h:
     25        * jit/JITOpcodes.cpp:
     26        (JSC::JIT::emitSlow_op_loop_hint):
     27        * jit/JITOperations.cpp:
     28
    1292014-02-15  Filip Pizlo  <fpizlo@apple.com>
    230
  • trunk/Source/JavaScriptCore/dfg/DFGOSREntry.cpp

    r163844 r164205  
    11/*
    2  * Copyright (C) 2011, 2013 Apple Inc. All rights reserved.
     2 * Copyright (C) 2011, 2013, 2014 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    189189    //    would have otherwise just kept running albeit less quickly.
    190190   
    191     unsigned frameSize = jitCode->common.requiredRegisterCountForExecutionAndExit();
    192     if (!vm->interpreter->stack().ensureCapacityFor(&exec->registers()[virtualRegisterForLocal(frameSize - 1).offset()])) {
     191    unsigned frameSizeForCheck = jitCode->common.requiredRegisterCountForExecutionAndExit();
     192    if (!vm->interpreter->stack().ensureCapacityFor(&exec->registers()[virtualRegisterForLocal(frameSizeForCheck - 1).offset()])) {
    193193        if (Options::verboseOSR())
    194194            dataLogF("    OSR failed because stack growth failed.\n");
     
    198198    if (Options::verboseOSR())
    199199        dataLogF("    OSR should succeed.\n");
    200    
    201     // 3) Perform data format conversions.
    202     for (size_t local = 0; local < entry->m_expectedValues.numberOfLocals(); ++local) {
    203         if (entry->m_localsForcedDouble.get(local))
    204             *bitwise_cast<double*>(exec->registers() + virtualRegisterForLocal(local).offset()) = exec->registers()[virtualRegisterForLocal(local).offset()].jsValue().asNumber();
    205         if (entry->m_localsForcedMachineInt.get(local))
    206             *bitwise_cast<int64_t*>(exec->registers() + virtualRegisterForLocal(local).offset()) = exec->registers()[virtualRegisterForLocal(local).offset()].jsValue().asMachineInt() << JSValue::int52ShiftAmount;
     200
     201    // At this point we're committed to entering. We will do some work to set things up,
     202    // but we also rely on our caller recognizing that when we return a non-null pointer,
     203    // that means that we're already past the point of no return and we must succeed at
     204    // entering.
     205   
     206    // 3) Set up the data in the scratch buffer and perform data format conversions.
     207
     208    unsigned frameSize = jitCode->common.frameRegisterCount;
     209   
     210    Register* scratch = bitwise_cast<Register*>(vm->scratchBufferForSize(sizeof(Register) * (2 + JSStack::CallFrameHeaderSize + frameSize))->dataBuffer());
     211   
     212    *bitwise_cast<size_t*>(scratch + 0) = frameSize;
     213   
     214    void* targetPC = codeBlock->jitCode()->executableAddressAtOffset(entry->m_machineCodeOffset);
     215    if (Options::verboseOSR())
     216        dataLogF("    OSR using target PC %p.\n", targetPC);
     217    RELEASE_ASSERT(targetPC);
     218    *bitwise_cast<void**>(scratch + 1) = targetPC;
     219   
     220    Register* pivot = scratch + 2 + JSStack::CallFrameHeaderSize;
     221   
     222    for (int index = -JSStack::CallFrameHeaderSize; index < static_cast<int>(frameSize); ++index) {
     223        VirtualRegister reg(-1 - index);
     224       
     225        if (reg.isLocal()) {
     226            if (entry->m_localsForcedDouble.get(reg.toLocal())) {
     227                *bitwise_cast<double*>(pivot + index) = exec->registers()[reg.offset()].jsValue().asNumber();
     228                continue;
     229            }
     230           
     231            if (entry->m_localsForcedMachineInt.get(reg.toLocal())) {
     232                *bitwise_cast<int64_t*>(pivot + index) = exec->registers()[reg.offset()].jsValue().asMachineInt() << JSValue::int52ShiftAmount;
     233                continue;
     234            }
     235        }
     236       
     237        pivot[index] = exec->registers()[reg.offset()].jsValue();
    207238    }
    208239   
    209240    // 4) Reshuffle those registers that need reshuffling.
    210    
    211     Vector<EncodedJSValue> temporaryLocals(entry->m_reshufflings.size());
    212     EncodedJSValue* registers = bitwise_cast<EncodedJSValue*>(exec->registers());
     241    Vector<JSValue> temporaryLocals(entry->m_reshufflings.size());
    213242    for (unsigned i = entry->m_reshufflings.size(); i--;)
    214         temporaryLocals[i] = registers[entry->m_reshufflings[i].fromOffset];
     243        temporaryLocals[i] = pivot[VirtualRegister(entry->m_reshufflings[i].fromOffset).toLocal()].jsValue();
    215244    for (unsigned i = entry->m_reshufflings.size(); i--;)
    216         registers[entry->m_reshufflings[i].toOffset] = temporaryLocals[i];
    217    
    218     // 5) Clear those parts of the call frame that the DFG ain't using. This helps GC on some
    219     //    programs by eliminating some stale pointer pathologies.
    220 
    221 #if 0 // FIXME: CStack - This needs to be verified before being enabled
     245        pivot[VirtualRegister(entry->m_reshufflings[i].toOffset).toLocal()] = temporaryLocals[i];
     246   
     247    // 5) Clear those parts of the call frame that the DFG ain't using. This helps GC on
     248    //    some programs by eliminating some stale pointer pathologies.
    222249    for (unsigned i = frameSize; i--;) {
    223250        if (entry->m_machineStackUsed.get(i))
    224251            continue;
    225         registers[virtualRegisterForLocal(i).offset()] = JSValue::encode(JSValue());
    226     }
    227 #endif
    228    
    229     // 6) Fix the call frame.
    230    
    231     exec->setCodeBlock(codeBlock);
    232    
    233     // 7) Find and return the destination machine code address.
    234    
    235     void* result = codeBlock->jitCode()->executableAddressAtOffset(entry->m_machineCodeOffset);
     252        pivot[i] = JSValue();
     253    }
     254   
     255    // 6) Fix the call frame to have the right code block.
     256   
     257    *bitwise_cast<CodeBlock**>(pivot - 1 - JSStack::CodeBlock) = codeBlock;
    236258   
    237259    if (Options::verboseOSR())
    238         dataLogF("    OSR returning machine code address %p.\n", result);
    239    
    240     return result;
     260        dataLogF("    OSR returning data buffer %p.\n", scratch);
     261    return scratch;
    241262}
    242263
  • trunk/Source/JavaScriptCore/dfg/DFGOSREntry.h

    r159826 r164205  
    6868}
    6969
     70// Returns a pointer to a data buffer that the OSR entry thunk will recognize and
     71// parse. If this returns null, it means
    7072void* prepareOSREntry(ExecState*, CodeBlock*, unsigned bytecodeIndex);
    7173#else
  • trunk/Source/JavaScriptCore/dfg/DFGThunks.cpp

    r163844 r164205  
    11/*
    2  * Copyright (C) 2011 Apple Inc. All rights reserved.
     2 * Copyright (C) 2011, 2014 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    9797}
    9898
     99MacroAssemblerCodeRef osrEntryThunkGenerator(VM* vm)
     100{
     101    MacroAssembler jit;
     102   
     103    // We get passed the address of a scratch buffer. The first 8-byte slot of the buffer
     104    // is the frame size. The second 8-byte slot is the pointer to where we are supposed to
     105    // jump. The remaining bytes are the new call frame header followed by the locals.
     106   
     107    ptrdiff_t offsetOfFrameSize = 0; // This is the DFG frame count.
     108    ptrdiff_t offsetOfTargetPC = offsetOfFrameSize + sizeof(EncodedJSValue);
     109    ptrdiff_t offsetOfPayload = offsetOfTargetPC + sizeof(EncodedJSValue);
     110    ptrdiff_t offsetOfLocals = offsetOfPayload + sizeof(Register) * JSStack::CallFrameHeaderSize;
     111   
     112    jit.move(GPRInfo::returnValueGPR2, GPRInfo::regT0);
     113    jit.loadPtr(MacroAssembler::Address(GPRInfo::regT0, offsetOfFrameSize), GPRInfo::regT1); // Load the frame size.
     114    jit.move(GPRInfo::regT1, GPRInfo::regT2);
     115    jit.lshiftPtr(MacroAssembler::Imm32(3), GPRInfo::regT2);
     116    jit.move(GPRInfo::callFrameRegister, MacroAssembler::stackPointerRegister);
     117    jit.subPtr(GPRInfo::regT2, MacroAssembler::stackPointerRegister);
     118   
     119    MacroAssembler::Label loop = jit.label();
     120    jit.subPtr(MacroAssembler::TrustedImm32(1), GPRInfo::regT1);
     121    jit.move(GPRInfo::regT1, GPRInfo::regT4);
     122    jit.negPtr(GPRInfo::regT4);
     123    jit.load32(MacroAssembler::BaseIndex(GPRInfo::regT0, GPRInfo::regT1, MacroAssembler::TimesEight, offsetOfLocals), GPRInfo::regT2);
     124    jit.load32(MacroAssembler::BaseIndex(GPRInfo::regT0, GPRInfo::regT1, MacroAssembler::TimesEight, offsetOfLocals + sizeof(int32_t)), GPRInfo::regT3);
     125    jit.store32(GPRInfo::regT2, MacroAssembler::BaseIndex(GPRInfo::callFrameRegister, GPRInfo::regT4, MacroAssembler::TimesEight, -static_cast<intptr_t>(sizeof(Register))));
     126    jit.store32(GPRInfo::regT3, MacroAssembler::BaseIndex(GPRInfo::callFrameRegister, GPRInfo::regT4, MacroAssembler::TimesEight, -static_cast<intptr_t>(sizeof(Register)) + static_cast<intptr_t>(sizeof(int32_t))));
     127    jit.branchPtr(MacroAssembler::NotEqual, GPRInfo::regT1, MacroAssembler::TrustedImmPtr(bitwise_cast<void*>(-static_cast<intptr_t>(JSStack::CallFrameHeaderSize)))).linkTo(loop, &jit);
     128   
     129    jit.loadPtr(MacroAssembler::Address(GPRInfo::regT0, offsetOfTargetPC), GPRInfo::regT1);
     130    MacroAssembler::Jump ok = jit.branchPtr(MacroAssembler::Above, GPRInfo::regT1, MacroAssembler::TrustedImmPtr(bitwise_cast<void*>(static_cast<intptr_t>(1000))));
     131    jit.breakpoint();
     132    ok.link(&jit);
     133    jit.jump(GPRInfo::regT1);
     134   
     135    LinkBuffer patchBuffer(*vm, &jit, GLOBAL_THUNK_ID);
     136    return FINALIZE_CODE(patchBuffer, ("DFG OSR entry thunk"));
     137}
     138
    99139} } // namespace JSC::DFG
    100140
  • trunk/Source/JavaScriptCore/dfg/DFGThunks.h

    r156490 r164205  
    11/*
    2  * Copyright (C) 2011 Apple Inc. All rights reserved.
     2 * Copyright (C) 2011, 2014 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    4040
    4141MacroAssemblerCodeRef osrExitGenerationThunkGenerator(VM*);
     42MacroAssemblerCodeRef osrEntryThunkGenerator(VM*);
    4243
    4344} } // namespace JSC::DFG
  • trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp

    r164128 r164205  
    11071107        callOperation(operationOptimize, m_bytecodeOffset);
    11081108        Jump noOptimizedEntry = branchTestPtr(Zero, returnValueGPR);
    1109         move(returnValueGPR2, stackPointerRegister);
     1109        if (!ASSERT_DISABLED) {
     1110            Jump ok = branchPtr(MacroAssembler::Above, regT0, TrustedImmPtr(bitwise_cast<void*>(static_cast<intptr_t>(1000))));
     1111            breakpoint();
     1112            ok.link(this);
     1113        }
    11101114        jump(returnValueGPR);
    11111115        noOptimizedEntry.link(this);
  • trunk/Source/JavaScriptCore/jit/JITOperations.cpp

    r164119 r164205  
    3333#include "DFGDriver.h"
    3434#include "DFGOSREntry.h"
     35#include "DFGThunks.h"
    3536#include "DFGWorklist.h"
    3637#include "Error.h"
     
    11901191    ASSERT(JITCode::isOptimizingJIT(optimizedCodeBlock->jitType()));
    11911192   
    1192     if (void* address = DFG::prepareOSREntry(exec, optimizedCodeBlock, bytecodeIndex)) {
     1193    if (void* dataBuffer = DFG::prepareOSREntry(exec, optimizedCodeBlock, bytecodeIndex)) {
    11931194        if (Options::verboseOSR()) {
    11941195            dataLog(
    1195                 "Performing OSR ", *codeBlock, " -> ", *optimizedCodeBlock, ", address ",
    1196                 RawPointer(OUR_RETURN_ADDRESS), " -> ", RawPointer(address), ".\n");
     1196                "Performing OSR ", *codeBlock, " -> ", *optimizedCodeBlock, ".\n");
    11971197        }
    11981198
    11991199        codeBlock->optimizeSoon();
    1200         ASSERT(exec->codeBlock() == optimizedCodeBlock);
    1201         return encodeResult(address, exec->topOfFrame());
     1200        return encodeResult(vm.getCTIStub(DFG::osrEntryThunkGenerator).code().executableAddress(), dataBuffer);
    12021201    }
    12031202
Note: See TracChangeset for help on using the changeset viewer.