Object* const_missing(STATE, Symbol* sym) { Module* under; CallFrame* call_frame = state->vm()->get_ruby_frame(); LexicalScope* scope = call_frame->lexical_scope(); if(scope->nil_p()) { under = G(object); } else { under = scope->module(); } Array* args = Array::create(state, 1); args->set(state, 0, sym); return under->send(state, G(sym_const_missing), args); }
/// getMachineBasicBlocks - Populate given set using machine basic blocks which /// have machine instructions that belong to lexical scope identified by /// DebugLoc. void LexicalScopes::getMachineBasicBlocks( const DILocation *DL, SmallPtrSetImpl<const MachineBasicBlock *> &MBBs) { MBBs.clear(); LexicalScope *Scope = getOrCreateLexicalScope(DL); if (!Scope) return; if (Scope == CurrentFnLexicalScope) { for (const auto &MBB : *MF) MBBs.insert(&MBB); return; } SmallVectorImpl<InsnRange> &InsnRanges = Scope->getRanges(); for (auto &R : InsnRanges) MBBs.insert(R.first->getParent()); }
/// dominates - Return true if DebugLoc's lexical scope dominates at least one /// machine instruction's lexical scope in a given machine basic block. bool LexicalScopes::dominates(const DILocation *DL, MachineBasicBlock *MBB) { LexicalScope *Scope = getOrCreateLexicalScope(DL); if (!Scope) return false; // Current function scope covers all basic blocks in the function. if (Scope == CurrentFnLexicalScope && MBB->getParent() == MF) return true; bool Result = false; for (auto &I : *MBB) { if (const DILocation *IDL = I.getDebugLoc()) if (LexicalScope *IScope = getOrCreateLexicalScope(IDL)) if (Scope->dominates(IScope)) return true; } return Result; }
/// dominates - Return true if DebugLoc's lexical scope dominates at least one /// machine instruction's lexical scope in a given machine basic block. bool LexicalScopes::dominates(const MDLocation *DL, MachineBasicBlock *MBB) { LexicalScope *Scope = getOrCreateLexicalScope(DL); if (!Scope) return false; // Current function scope covers all basic blocks in the function. if (Scope == CurrentFnLexicalScope && MBB->getParent() == MF) return true; bool Result = false; for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end(); I != E; ++I) { if (const MDLocation *IDL = I->getDebugLoc()) if (LexicalScope *IScope = getOrCreateLexicalScope(IDL)) if (Scope->dominates(IScope)) return true; } return Result; }
// Each LexicalScope has first instruction and last instruction to mark // beginning and end of a scope respectively. Create an inverse map that list // scopes starts (and ends) with an instruction. One instruction may start (or // end) multiple scopes. Ignore scopes that are not reachable. void DebugHandlerBase::identifyScopeMarkers() { SmallVector<LexicalScope *, 4> WorkList; WorkList.push_back(LScopes.getCurrentFunctionScope()); while (!WorkList.empty()) { LexicalScope *S = WorkList.pop_back_val(); const SmallVectorImpl<LexicalScope *> &Children = S->getChildren(); if (!Children.empty()) WorkList.append(Children.begin(), Children.end()); if (S->isAbstractScope()) continue; for (const InsnRange &R : S->getRanges()) { assert(R.first && "InsnRange does not have first instruction!"); assert(R.second && "InsnRange does not have second instruction!"); requestLabelBeforeInsn(R.first); requestLabelAfterInsn(R.second); } } }
/// getMachineBasicBlocks - Populate given set using machine basic blocks which /// have machine instructions that belong to lexical scope identified by /// DebugLoc. void LexicalScopes::getMachineBasicBlocks( const MDLocation *DL, SmallPtrSetImpl<const MachineBasicBlock *> &MBBs) { MBBs.clear(); LexicalScope *Scope = getOrCreateLexicalScope(DL); if (!Scope) return; if (Scope == CurrentFnLexicalScope) { for (const auto &MBB : *MF) MBBs.insert(&MBB); return; } SmallVectorImpl<InsnRange> &InsnRanges = Scope->getRanges(); for (SmallVectorImpl<InsnRange>::iterator I = InsnRanges.begin(), E = InsnRanges.end(); I != E; ++I) { InsnRange &R = *I; MBBs.insert(R.first->getParent()); } }
/// constructScopeNest void LexicalScopes::constructScopeNest(LexicalScope *Scope) { assert (Scope && "Unable to calculate scop edominance graph!"); SmallVector<LexicalScope *, 4> WorkStack; WorkStack.push_back(Scope); unsigned Counter = 0; while (!WorkStack.empty()) { LexicalScope *WS = WorkStack.back(); const SmallVector<LexicalScope *, 4> &Children = WS->getChildren(); bool visitedChildren = false; for (SmallVector<LexicalScope *, 4>::const_iterator SI = Children.begin(), SE = Children.end(); SI != SE; ++SI) { LexicalScope *ChildScope = *SI; if (!ChildScope->getDFSOut()) { WorkStack.push_back(ChildScope); visitedChildren = true; ChildScope->setDFSIn(++Counter); break; } } if (!visitedChildren) { WorkStack.pop_back(); WS->setDFSOut(++Counter); } } }
void CodeViewDebug::collectVariableInfoFromMMITable( DenseSet<InlinedVariable> &Processed) { const TargetSubtargetInfo &TSI = Asm->MF->getSubtarget(); const TargetFrameLowering *TFI = TSI.getFrameLowering(); const TargetRegisterInfo *TRI = TSI.getRegisterInfo(); for (const MachineModuleInfo::VariableDbgInfo &VI : MMI->getVariableDbgInfo()) { if (!VI.Var) continue; assert(VI.Var->isValidLocationForIntrinsic(VI.Loc) && "Expected inlined-at fields to agree"); Processed.insert(InlinedVariable(VI.Var, VI.Loc->getInlinedAt())); LexicalScope *Scope = LScopes.findLexicalScope(VI.Loc); // If variable scope is not found then skip this variable. if (!Scope) continue; // Get the frame register used and the offset. unsigned FrameReg = 0; int FrameOffset = TFI->getFrameIndexReference(*Asm->MF, VI.Slot, FrameReg); uint16_t CVReg = TRI->getCodeViewRegNum(FrameReg); // Calculate the label ranges. LocalVarDefRange DefRange = createDefRangeMem(CVReg, FrameOffset); for (const InsnRange &Range : Scope->getRanges()) { const MCSymbol *Begin = getLabelBeforeInsn(Range.first); const MCSymbol *End = getLabelAfterInsn(Range.second); End = End ? End : Asm->getFunctionEnd(); DefRange.Ranges.emplace_back(Begin, End); } LocalVariable Var; Var.DIVar = VI.Var; Var.DefRanges.emplace_back(std::move(DefRange)); recordLocalVariable(std::move(Var), VI.Loc->getInlinedAt()); } }
/// constructScopeNest void LexicalScopes::constructScopeNest(LexicalScope *Scope) { assert(Scope && "Unable to calculate scope dominance graph!"); SmallVector<LexicalScope *, 4> WorkStack; WorkStack.push_back(Scope); unsigned Counter = 0; while (!WorkStack.empty()) { LexicalScope *WS = WorkStack.back(); const SmallVectorImpl<LexicalScope *> &Children = WS->getChildren(); bool visitedChildren = false; for (auto &ChildScope : Children) if (!ChildScope->getDFSOut()) { WorkStack.push_back(ChildScope); visitedChildren = true; ChildScope->setDFSIn(++Counter); break; } if (!visitedChildren) { WorkStack.pop_back(); WS->setDFSOut(++Counter); } } }
/// getMachineBasicBlocks - Populate given set using machine basic blocks which /// have machine instructions that belong to lexical scope identified by /// DebugLoc. void LexicalScopes:: getMachineBasicBlocks(DebugLoc DL, SmallPtrSet<const MachineBasicBlock*, 4> &MBBs) { MBBs.clear(); LexicalScope *Scope = getOrCreateLexicalScope(DL); if (!Scope) return; if (Scope == CurrentFnLexicalScope) { for (MachineFunction::const_iterator I = MF->begin(), E = MF->end(); I != E; ++I) MBBs.insert(I); return; } SmallVector<InsnRange, 4> &InsnRanges = Scope->getRanges(); for (SmallVector<InsnRange, 4>::iterator I = InsnRanges.begin(), E = InsnRanges.end(); I != E; ++I) { InsnRange &R = *I; MBBs.insert(R.first->getParent()); } }
/// assignInstructionRanges - Find ranges of instructions covered by each /// lexical scope. void LexicalScopes::assignInstructionRanges( SmallVectorImpl<InsnRange> &MIRanges, DenseMap<const MachineInstr *, LexicalScope *> &MI2ScopeMap) { LexicalScope *PrevLexicalScope = nullptr; for (const auto &R : MIRanges) { LexicalScope *S = MI2ScopeMap.lookup(R.first); assert(S && "Lost LexicalScope for a machine instruction!"); if (PrevLexicalScope && !PrevLexicalScope->dominates(S)) PrevLexicalScope->closeInsnRange(S); S->openInsnRange(R.first); S->extendInsnRange(R.second); PrevLexicalScope = S; } if (PrevLexicalScope) PrevLexicalScope->closeInsnRange(); }
/// assignInstructionRanges - Find ranges of instructions covered by each /// lexical scope. void LexicalScopes:: assignInstructionRanges(SmallVectorImpl<InsnRange> &MIRanges, DenseMap<const MachineInstr *, LexicalScope *> &MI2ScopeMap) { LexicalScope *PrevLexicalScope = NULL; for (SmallVectorImpl<InsnRange>::const_iterator RI = MIRanges.begin(), RE = MIRanges.end(); RI != RE; ++RI) { const InsnRange &R = *RI; LexicalScope *S = MI2ScopeMap.lookup(R.first); assert (S && "Lost LexicalScope for a machine instruction!"); if (PrevLexicalScope && !PrevLexicalScope->dominates(S)) PrevLexicalScope->closeInsnRange(S); S->openInsnRange(R.first); S->extendInsnRange(R.second); PrevLexicalScope = S; } if (PrevLexicalScope) PrevLexicalScope->closeInsnRange(); }
void UserValue::computeIntervals(MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, LiveIntervals &LIS, LexicalScopes &LS) { SmallVector<std::pair<SlotIndex, unsigned>, 16> Defs; // Collect all defs to be extended (Skipping undefs). for (LocMap::const_iterator I = locInts.begin(); I.valid(); ++I) if (I.value() != UndefLocNo) Defs.push_back(std::make_pair(I.start(), I.value())); // Extend all defs, and possibly add new ones along the way. for (unsigned i = 0; i != Defs.size(); ++i) { SlotIndex Idx = Defs[i].first; unsigned LocNo = Defs[i].second; const MachineOperand &Loc = locations[LocNo]; if (!Loc.isReg()) { extendDef(Idx, LocNo, nullptr, nullptr, nullptr, LIS); continue; } // Register locations are constrained to where the register value is live. if (TargetRegisterInfo::isVirtualRegister(Loc.getReg())) { LiveInterval *LI = nullptr; const VNInfo *VNI = nullptr; if (LIS.hasInterval(Loc.getReg())) { LI = &LIS.getInterval(Loc.getReg()); VNI = LI->getVNInfoAt(Idx); } SmallVector<SlotIndex, 16> Kills; extendDef(Idx, LocNo, LI, VNI, &Kills, LIS); if (LI) addDefsFromCopies(LI, LocNo, Kills, Defs, MRI, LIS); continue; } // For physregs, use the live range of the first regunit as a guide. unsigned Unit = *MCRegUnitIterator(Loc.getReg(), &TRI); LiveRange *LR = &LIS.getRegUnit(Unit); const VNInfo *VNI = LR->getVNInfoAt(Idx); // Don't track copies from physregs, it is too expensive. extendDef(Idx, LocNo, LR, VNI, nullptr, LIS); } // Erase all the undefs. for (LocMap::iterator I = locInts.begin(); I.valid();) if (I.value() == UndefLocNo) I.erase(); else ++I; // The computed intervals may extend beyond the range of the debug // location's lexical scope. In this case, splitting of an interval // can result in an interval outside of the scope being created, // causing extra unnecessary DBG_VALUEs to be emitted. To prevent // this, trim the intervals to the lexical scope. LexicalScope *Scope = LS.findLexicalScope(dl); if (!Scope) return; SlotIndex PrevEnd; LocMap::iterator I = locInts.begin(); // Iterate over the lexical scope ranges. Each time round the loop // we check the intervals for overlap with the end of the previous // range and the start of the next. The first range is handled as // a special case where there is no PrevEnd. for (const InsnRange &Range : Scope->getRanges()) { SlotIndex RStart = LIS.getInstructionIndex(*Range.first); SlotIndex REnd = LIS.getInstructionIndex(*Range.second); // At the start of each iteration I has been advanced so that // I.stop() >= PrevEnd. Check for overlap. if (PrevEnd && I.start() < PrevEnd) { SlotIndex IStop = I.stop(); unsigned LocNo = I.value(); // Stop overlaps previous end - trim the end of the interval to // the scope range. I.setStopUnchecked(PrevEnd); ++I; // If the interval also overlaps the start of the "next" (i.e. // current) range create a new interval for the remainder (which // may be further trimmed). if (RStart < IStop) I.insert(RStart, IStop, LocNo); } // Advance I so that I.stop() >= RStart, and check for overlap. I.advanceTo(RStart); if (!I.valid()) return; if (I.start() < RStart) { // Interval start overlaps range - trim to the scope range. I.setStartUnchecked(RStart); // Remember that this interval was trimmed. trimmedDefs.insert(RStart); } // The end of a lexical scope range is the last instruction in the // range. To convert to an interval we need the index of the // instruction after it. REnd = REnd.getNextIndex(); // Advance I to first interval outside current range. I.advanceTo(REnd); if (!I.valid()) return; PrevEnd = REnd; } // Check for overlap with end of final range. if (PrevEnd && I.start() < PrevEnd) I.setStopUnchecked(PrevEnd); }
Object* const_get(STATE, Symbol* name, ConstantMissingReason* reason, Object* filter, bool replace_autoload) { LexicalScope *cur; Object* result; *reason = vNonExistent; CallFrame* frame = state->vm()->get_ruby_frame(); // Ok, this has to be explained or it will be considered black magic. // The scope chain always ends with an entry at the top that contains // a parent of nil, and a module of Object. This entry is put in // regardless of lexical scoping, it's the fallback scope (the default // scope). This is not case when deriving from BasicObject, which is // explained later. // // When looking up a constant, we don't want to consider the fallback // scope (ie, Object) initially because we need to lookup up // the superclass chain first, because falling back on the default. // // The rub comes from the fact that if a user explicitly opens up // Object in their code, we DO consider it. Like: // // class Idiot // A = 2 // end // // class ::Object // A = 1 // class Stupid < Idiot // def foo // p A // end // end // end // // In this code, when A is looked up, Object must be considering during // the scope walk, NOT during the superclass walk. // // So, in this case, foo would print "1", not "2". // // As indicated above, the fallback scope isn't used when the superclass // chain directly rooted from BasicObject. To determine this is the // case, we record whether Object is seen when looking up the superclass // chain. If Object isn't seen, this means we are directly deriving from // BasicObject. cur = frame->lexical_scope(); while(!cur->nil_p()) { // Detect the toplevel scope (the default) and get outta dodge. if(cur->top_level_p(state)) break; result = cur->module()->get_const(state, name, G(sym_private), reason, false, replace_autoload); if(*reason == vFound) { if(result != filter) return result; *reason = vNonExistent; } cur = cur->parent(); } // Now look up the superclass chain. Module *fallback = G(object); cur = frame->lexical_scope(); if(!cur->nil_p()) { bool object_seen = false; Module* mod = cur->module(); while(!mod->nil_p()) { if(mod == G(object)) { object_seen = true; } if(!object_seen && mod == G(basicobject)) { fallback = NULL; } result = mod->get_const(state, name, G(sym_private), reason, false, replace_autoload); if(*reason == vFound) { if(result != filter) return result; *reason = vNonExistent; } mod = mod->superclass(); } } // Lastly, check the fallback scope (=Object) specifically if needed if(fallback) { result = fallback->get_const(state, name, G(sym_private), reason, true, replace_autoload); if(*reason == vFound) { if(result != filter) return result; *reason = vNonExistent; } } return cNil; }