Ignore:
Timestamp:
Jul 24, 2013, 9:02:07 PM (12 years ago)
Author:
[email protected]
Message:

fourthTier: CallFrame::trueCallFrame() should populate the bytecodeOffset field
when reifying inlined frames..
https://bugs.webkit.org/show_bug.cgi?id=117209.

Reviewed by Geoffrey Garen.

When reifying an inlined frame, we fill in its CodeBlock, and
bytecodeOffset. We also set the InlinedFrame bit in the location field.
This is needed in order to iterate the stack correctly. Here's why:

Let's say we have the following stack trace:

X calls A inlines B inlines C calls D

Based on the above scenario,

  1. D's callerFrame points to A (not C).
  2. A has a codeOriginIndex that points to C.

When iterating the stack (from D back towards X), we will encounter A
twice:

t1. when trying to find C as D's caller.

This is the time when we reify B and C using the
codeOriginIndex in A, and return C as the caller frame of D.

t2. when getting's the reified B's caller.

This time, we don't run the reification process, and
just take A as the caller frame of B.

To discern which treatment of the DFG frame (i.e. A) we need to apply,
we check if the callee is an inlined frame:

If callee is NOT an inlined frame (e.g. frame D), apply treatment t1.
If callee is an inlined frame (e.g. frame B), apply treatment t2.

Why not just reify A by replacing its codeOriginIndex with A's
bytecodeOffset?

We can't do this because D's callerFrame pointer still points to A, and
needs to remain that way because we did not deopt A. It remains a DFG
frame which inlined B and C.

If we replace the codeOriginIndex in A with A's bytecodeOffset, we will
only get to iterate the stack correctly once. If we try to iterate the
stack a second time, we will not have the information from the
codeOriginIndex to tell us that D's caller is actually the inlined C,
and not A.

To recap, when reifying frames for stack iteration purposes, the DFG
frame needs to hold on to its codeOriginIndex. This in turn means the
DFG frame will need to be treated in 2 possible ways, and we need to
know if a callee frame is an inlined frame in order to choose the
correct treatment for the DFG frame.

Other changes:

  • Simplified Interpreter::getCallerInfo().
  • Removed CodeBlock::codeOriginForReturn() and supporting code which is now unneeded.
  • Moved CallFrame location bit encoding from the CodeOrigin to the new CallFrame::Location class.
  • Explicitly tagged inlined frames. This is necessary in order to iterate the stack correctly as explained above.
  • bytecode/CodeBlock.cpp:
  • bytecode/CodeBlock.h:

(JSC::CodeBlock::codeOrigins):
(CodeBlock):
(JSC::CodeBlock::codeOrigin):
(RareData):

  • bytecode/CodeOrigin.h:

(CodeOrigin):

  • dfg/DFGJITCompiler.cpp:

(JSC::DFG::JITCompiler::link):

  • dfg/DFGJITCompiler.h:

(JSC::DFG::JITCompiler::beginCall):

  • interpreter/CallFrame.cpp:

(JSC::CallFrame::trueCallFrame):
(JSC::CallFrame::trueCallerFrame):
(JSC::CallFrame::bytecodeOffsetFromCodeOriginIndex):

  • interpreter/CallFrame.h:

(Location):
(ExecState):
(JSC::ExecState::trueCallerFrame):
(JSC::ExecState::callerFrameNoFlags):

  • interpreter/CallFrameInlines.h:

(JSC::CallFrame::Location::encode):
(JSC::CallFrame::Location::decode):
(JSC::CallFrame::Location::isBytecodeOffset):
(JSC::CallFrame::Location::isCodeOriginIndex):
(JSC::CallFrame::Location::isInlinedFrame):
(JSC::CallFrame::isInlinedFrame):
(JSC::CallFrame::setIsInlinedFrame):
(JSC::CallFrame::hasLocationAsBytecodeOffset):
(JSC::CallFrame::hasLocationAsCodeOriginIndex):
(JSC::CallFrame::locationAsBytecodeOffset):
(JSC::CallFrame::setLocationAsBytecodeOffset):
(JSC::CallFrame::locationAsCodeOriginIndex):

  • interpreter/Interpreter.cpp:

(JSC::getCallerInfo):
(JSC::Interpreter::getStackTrace):
(JSC::Interpreter::findFunctionCallFrameFromVMCode):

  • runtime/Arguments.cpp:

(JSC::Arguments::tearOff):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/interpreter/CallFrame.h

    r153209 r153211  
    115115        AbstractPC abstractReturnPC(VM& vm) { return AbstractPC(vm, this); }
    116116
     117        class Location {
     118        public:
     119            enum Type {
     120                BytecodeOffset = 0,
     121                CodeOriginIndex = (1 << 0),
     122                IsInlinedCode = (1 << 1),
     123            };
     124
     125            static inline uint32_t encode(Type, uint32_t bits);
     126            static inline uint32_t decode(uint32_t bits);
     127            static inline bool isBytecodeOffset(uint32_t bits);
     128            static inline bool isCodeOriginIndex(uint32_t bits);
     129            static inline bool isInlinedCode(uint32_t bits);
     130
     131        private:
     132            static const uint32_t s_mask = 0x3;
     133#if USE(JSVALUE64)
     134            static const uint32_t s_shift = 30;
     135            static const uint32_t s_shiftedMask = s_mask << s_shift;
     136#else
     137            static const uint32_t s_shift = 2;
     138#endif
     139        };
     140
     141        bool isInlinedFrame() const;
     142        void setIsInlinedFrame();
     143
    117144        bool hasLocationAsBytecodeOffset() const;
    118145        bool hasLocationAsCodeOriginIndex() const;
     
    124151        void setLocationAsRawBits(unsigned);
    125152        void setLocationAsBytecodeOffset(unsigned);
     153
     154        unsigned bytecodeOffsetFromCodeOriginIndex();
    126155
    127156        Register* frameExtent()
     
    138167#else
    139168        // This will never be called if !ENABLE(DFG_JIT) since all calls should be guarded by
    140         // isInlineCallFrame(). But to make it easier to write code without having a bunch of
     169        // isInlinedFrame(). But to make it easier to write code without having a bunch of
    141170        // #if's, we make a dummy implementation available anyway.
    142171        InlineCallFrame* inlineCallFrame() const
     
    232261       
    233262#if ENABLE(DFG_JIT)
    234         bool isInlineCallFrame();
    235        
    236263        void setInlineCallFrame(InlineCallFrame* inlineCallFrame) { static_cast<Register*>(this)[JSStack::ReturnPC] = inlineCallFrame; }
    237        
     264
    238265        // Call this to get the semantically correct JS CallFrame* for the
    239266        // currently executing function.
    240         CallFrame* trueCallFrame(AbstractPC);
    241        
     267        CallFrame* trueCallFrame();
     268
    242269        // Call this to get the semantically correct JS CallFrame* corresponding
    243270        // to the caller. This resolves issues surrounding inlining and the
    244271        // HostCallFrameFlag stuff.
    245272        CallFrame* trueCallerFrame();
    246        
    247         CodeBlock* someCodeBlockForPossiblyInlinedCode();
    248273#else
    249         bool isInlineCallFrame() { return false; }
    250        
    251274        CallFrame* trueCallFrame(AbstractPC) { return this; }
    252275        CallFrame* trueCallerFrame() { return callerFrame()->removeHostCallFrameFlag(); }
    253        
    254         CodeBlock* someCodeBlockForPossiblyInlinedCode() { return codeBlock(); }
    255276#endif
    256277        CallFrame* callerFrameNoFlags() { return callerFrame()->removeHostCallFrameFlag(); }
    257        
    258         // Call this to get the true call frame (accounted for inlining and any
    259         // other optimizations), when you have entered into VM code through one
    260         // of the "blessed" entrypoints (JITStubs or DFGOperations). This means
    261         // that if you're pretty much anywhere in the VM you can safely call this;
    262         // though if you were to magically get an ExecState* by, say, interrupting
    263         // a thread that is running JS code and brutishly scraped the call frame
    264         // register, calling this method would probably lead to horrible things
    265         // happening.
    266         CallFrame* trueCallFrameFromVMCode() { return trueCallFrame(AbstractPC()); }
    267278
    268279    private:
     
    273284#ifndef NDEBUG
    274285        JSStack* stack();
    275 #endif
    276 #if ENABLE(DFG_JIT)
    277         bool isInlineCallFrameSlow();
    278286#endif
    279287        ExecState();
Note: See TracChangeset for help on using the changeset viewer.