1 34 package org.jruby.runtime; 35 36 import org.jruby.Ruby; 37 import org.jruby.RubyArray; 38 import org.jruby.RubyClass; 39 import org.jruby.RubyModule; 40 import org.jruby.RubyThread; 41 import org.jruby.lexer.yacc.ISourcePosition; 42 import org.jruby.lexer.yacc.SourcePositionFactory; 43 import org.jruby.parser.LocalStaticScope; 44 import org.jruby.parser.StaticScope; 45 import org.jruby.runtime.builtin.IRubyObject; 46 import org.jruby.util.collections.SinglyLinkedList; 47 48 51 public class ThreadContext { 52 private final static int INITIAL_SIZE = 50; 53 54 private final Ruby runtime; 55 56 private boolean isWithinTrace; 58 59 private boolean isWithinDefined; 61 62 private RubyThread thread; 63 64 private RubyModule[] parentStack = new RubyModule[INITIAL_SIZE]; 66 private int parentIndex = -1; 67 68 private Frame[] frameStack = new Frame[INITIAL_SIZE]; 70 private int frameIndex = -1; 71 private SinglyLinkedList[] crefStack = new SinglyLinkedList[INITIAL_SIZE]; 73 private int crefIndex = -1; 74 75 private DynamicScope[] scopeStack = new DynamicScope[INITIAL_SIZE]; 78 private int scopeIndex = -1; 79 80 private String [] catchStack = new String [INITIAL_SIZE]; 81 private int catchIndex = -1; 82 83 private int[] bindingFrameStack = new int[INITIAL_SIZE]; 84 private int bindingFrameIndex = -1; 85 86 private RubyModule wrapper; 87 88 private ISourcePosition sourcePosition = new SourcePositionFactory(null).getDummyPosition(); 89 90 93 public ThreadContext(Ruby runtime) { 94 this.runtime = runtime; 95 96 pushScope(new DynamicScope(new LocalStaticScope(null), null)); 99 } 100 101 Visibility lastVis; 102 CallType lastCallType; 103 104 public Ruby getRuntime() { 105 return runtime; 106 } 107 108 112 public void setLastCallStatus(Visibility vis, CallType callType) { 113 lastVis = vis; 114 lastCallType = callType; 115 } 116 117 public Visibility getLastVisibility() { 118 return lastVis; 119 } 120 121 public CallType getLastCallType() { 122 return lastCallType; 123 } 124 125 public void printScope() { 126 System.out.println("SCOPE STACK:"); 127 for (int i = 0; i <= scopeIndex; i++) { 128 System.out.println(scopeStack[i]); 129 } 130 } 131 132 public DynamicScope getCurrentScope() { 133 return scopeStack[scopeIndex]; 134 } 135 136 private void expandFramesIfNecessary() { 137 if (frameIndex + 1 == frameStack.length) { 138 int newSize = frameStack.length * 2; 139 Frame[] newFrameStack = new Frame[newSize]; 140 141 System.arraycopy(frameStack, 0, newFrameStack, 0, frameStack.length); 142 143 frameStack = newFrameStack; 144 } 145 } 146 147 private void expandParentsIfNecessary() { 148 if (parentIndex + 1 == parentStack.length) { 149 int newSize = parentStack.length * 2; 150 RubyModule[] newParentStack = new RubyModule[newSize]; 151 152 System.arraycopy(parentStack, 0, newParentStack, 0, parentStack.length); 153 154 parentStack = newParentStack; 155 } 156 } 157 158 private void expandCrefsIfNecessary() { 159 if (crefIndex + 1 == crefStack.length) { 160 int newSize = crefStack.length * 2; 161 SinglyLinkedList[] newCrefStack = new SinglyLinkedList[newSize]; 162 163 System.arraycopy(crefStack, 0, newCrefStack, 0, crefStack.length); 164 165 crefStack = newCrefStack; 166 } 167 } 168 169 public void pushScope(DynamicScope scope) { 170 scopeStack[++scopeIndex] = scope; 171 expandScopesIfNecessary(); 172 } 173 174 public void popScope() { 175 scopeStack[scopeIndex--] = null; 176 } 177 178 private void expandScopesIfNecessary() { 179 if (scopeIndex + 1 == scopeStack.length) { 180 int newSize = scopeStack.length * 2; 181 DynamicScope[] newScopeStack = new DynamicScope[newSize]; 182 183 System.arraycopy(scopeStack, 0, newScopeStack, 0, scopeStack.length); 184 185 scopeStack = newScopeStack; 186 } 187 } 188 189 public RubyThread getThread() { 190 return thread; 191 } 192 193 public void setThread(RubyThread thread) { 194 this.thread = thread; 195 } 196 197 public IRubyObject getLastline() { 198 return getCurrentScope().getLastLine(); 199 } 200 201 public void setLastline(IRubyObject value) { 202 getCurrentScope().setLastLine(value); 203 } 204 205 private void expandCatchIfNecessary() { 207 if (catchIndex + 1 == catchStack.length) { 208 int newSize = catchStack.length * 2; 209 String [] newCatchStack = new String [newSize]; 210 211 System.arraycopy(catchStack, 0, newCatchStack, 0, catchStack.length); 212 catchStack = newCatchStack; 213 } 214 } 215 216 public void pushCatch(String catchSymbol) { 217 catchStack[++catchIndex] = catchSymbol; 218 expandCatchIfNecessary(); 219 } 220 221 public void popCatch() { 222 catchIndex--; 223 } 224 225 public String [] getActiveCatches() { 226 if (catchIndex < 0) return new String [0]; 227 228 String [] activeCatches = new String [catchIndex + 1]; 229 System.arraycopy(catchStack, 0, activeCatches, 0, catchIndex + 1); 230 return activeCatches; 231 } 232 233 private void pushFrameCopy() { 235 pushFrame(getCurrentFrame().duplicate()); 236 } 237 238 private void pushCallFrame(RubyModule clazz, String name, 239 IRubyObject self, IRubyObject[] args, Block block) { 240 pushFrame(new Frame(clazz, self, name, args, block, getPosition())); 241 } 242 243 private void pushFrame() { 244 pushFrame(new Frame(getPosition())); 245 } 246 247 private void pushFrame(Frame frame) { 248 frameStack[++frameIndex] = frame; 249 expandFramesIfNecessary(); 250 } 251 252 private void popFrame() { 253 Frame frame = (Frame)frameStack[frameIndex--]; 254 255 setPosition(frame.getPosition()); 256 } 257 258 public Frame getCurrentFrame() { 259 return (Frame)frameStack[frameIndex]; 260 } 261 262 public Frame getPreviousFrame() { 263 int size = frameIndex + 1; 264 return size <= 1 ? null : (Frame) frameStack[size - 2]; 265 } 266 267 public int getFrameCount() { 268 return frameIndex + 1; 269 } 270 271 public String getFrameName() { 272 return getCurrentFrame().getName(); 273 } 274 275 public IRubyObject[] getFrameArgs() { 276 return getCurrentFrame().getArgs(); 277 } 278 279 public void setFrameArgs(IRubyObject[] args) { 280 getCurrentFrame().setArgs(args); 281 } 282 283 public IRubyObject getFrameSelf() { 284 return getCurrentFrame().getSelf(); 285 } 286 287 public void setFrameSelf(IRubyObject self) { 288 getCurrentFrame().setSelf(self); 289 } 290 291 public void setSelfToPrevious() { 292 getCurrentFrame().setSelf(getPreviousFrame().getSelf()); 293 } 294 295 public RubyModule getFrameKlazz() { 296 return getCurrentFrame().getKlazz(); 297 } 298 299 public ISourcePosition getFramePosition() { 300 return getCurrentFrame().getPosition(); 301 } 302 303 public ISourcePosition getPreviousFramePosition() { 304 return getPreviousFrame().getPosition(); 305 } 306 307 private void expandBindingFrameIfNecessary() { 308 if (bindingFrameIndex + 1 == bindingFrameStack.length) { 309 int newSize = bindingFrameStack.length * 2; 310 int[] newbindingFrameStack = new int[newSize]; 311 312 System.arraycopy(bindingFrameStack, 0, newbindingFrameStack, 0, bindingFrameStack.length); 313 bindingFrameStack = newbindingFrameStack; 314 } 315 } 316 317 public void pushBindingFrame(int bindingDepth) { 318 bindingFrameStack[++bindingFrameIndex] = bindingDepth; 319 expandBindingFrameIfNecessary(); 320 } 321 322 public void popBindingFrame() { 323 bindingFrameIndex--; 324 } 325 326 327 public int currentBindingFrame() { 328 if(bindingFrameIndex == -1) { 329 return 0; 330 } else { 331 return bindingFrameStack[bindingFrameIndex]; 332 } 333 } 334 335 public ISourcePosition getPosition() { 336 return sourcePosition; 337 } 338 339 public String getSourceFile() { 340 return sourcePosition.getFile(); 341 } 342 343 public int getSourceLine() { 344 return sourcePosition.getEndLine(); 345 } 346 347 public void setPosition(ISourcePosition position) { 348 sourcePosition = position; 349 } 350 351 public IRubyObject getBackref() { 352 IRubyObject value = getCurrentScope().getBackRef(); 353 354 return value == null ? runtime.getNil() : value; 357 } 358 359 public void setBackref(IRubyObject backref) { 360 getCurrentScope().setBackRef(backref); 361 } 362 363 public Visibility getCurrentVisibility() { 364 return getCurrentFrame().getVisibility(); 365 } 366 367 public Visibility getPreviousVisibility() { 368 return getPreviousFrame().getVisibility(); 369 } 370 371 public void setCurrentVisibility(Visibility visibility) { 372 getCurrentFrame().setVisibility(visibility); 373 } 374 375 public IRubyObject callSuper(IRubyObject[] args, Block block) { 376 Frame frame = getCurrentFrame(); 377 378 if (frame.getKlazz() == null) { 379 String name = frame.getName(); 380 throw runtime.newNameError("superclass method '" + name + "' must be enabled by enableSuper().", name); 381 } 382 383 RubyClass superClass = frame.getKlazz().getSuperClass(); 384 385 assert superClass != null : "Superclass should always be something for " + frame.getKlazz().getBaseName(); 386 387 return frame.getSelf().callMethod(this, superClass, frame.getName(), args, CallType.SUPER, block); 388 } 389 390 396 public IRubyObject yield(IRubyObject value, Block block) { 397 return block.yield(this, value, null, null, false); 398 } 399 400 405 public void raiseErrorIfNoBlock(Block block) { 406 if (!block.isGiven()) throw runtime.newLocalJumpError("yield called out of block"); 407 } 408 409 public void pollThreadEvents() { 410 getThread().pollThreadEvents(); 411 } 412 413 public SinglyLinkedList peekCRef() { 414 return (SinglyLinkedList)crefStack[crefIndex]; 415 } 416 417 public void setCRef(SinglyLinkedList newCRef) { 418 crefStack[++crefIndex] = newCRef; 419 expandCrefsIfNecessary(); 420 } 421 422 public void unsetCRef() { 423 crefStack[crefIndex--] = null; 424 } 425 426 public SinglyLinkedList pushCRef(RubyModule newModule) { 427 if (crefIndex == -1) { 428 crefStack[++crefIndex] = new SinglyLinkedList(newModule, null); 429 } else { 430 crefStack[crefIndex] = new SinglyLinkedList(newModule, (SinglyLinkedList)crefStack[crefIndex]); 431 } 432 433 return (SinglyLinkedList)peekCRef(); 434 } 435 436 public RubyModule popCRef() { 437 assert !(crefIndex == -1) : "Tried to pop from empty CRef stack"; 438 439 RubyModule module = (RubyModule)peekCRef().getValue(); 440 441 SinglyLinkedList next = ((SinglyLinkedList)crefStack[crefIndex--]).getNext(); 442 443 if (next != null) { 444 crefStack[++crefIndex] = next; 445 } else { 446 crefStack[crefIndex+1] = null; 447 } 448 449 return module; 450 } 451 452 public void pushRubyClass(RubyModule currentModule) { 453 assert currentModule != null : "Can't push null RubyClass"; 454 455 parentStack[++parentIndex] = currentModule; 456 expandParentsIfNecessary(); 457 } 458 459 public RubyModule popRubyClass() { 460 RubyModule ret = (RubyModule)parentStack[parentIndex]; 461 parentStack[parentIndex--] = null; 462 return ret; 463 } 464 465 public RubyModule getRubyClass() { 466 assert !(parentIndex == -1) : "Trying to get RubyClass from empty stack"; 467 468 RubyModule parentModule = (RubyModule)parentStack[parentIndex]; 469 470 return parentModule.getNonIncludedClass(); 471 } 472 473 public RubyModule getBindingRubyClass() { 474 RubyModule parentModule = null; 475 if(parentIndex == 0) { 476 parentModule = (RubyModule)parentStack[parentIndex]; 477 } else { 478 parentModule = (RubyModule)parentStack[parentIndex-1]; 479 480 } 481 return parentModule.getNonIncludedClass(); 482 } 483 484 public boolean isTopLevel() { 485 return parentIndex == 0; 486 } 487 488 public RubyModule getWrapper() { 489 return wrapper; 490 } 491 492 public void setWrapper(RubyModule wrapper) { 493 this.wrapper = wrapper; 494 } 495 496 public boolean getConstantDefined(String name) { 497 IRubyObject result = null; 498 499 for (SinglyLinkedList cbase = peekCRef(); cbase != null; cbase = cbase.getNext()) { 501 result = ((RubyModule) cbase.getValue()).getConstantAt(name); 502 if (result != null || runtime.getLoadService().autoload(name) != null) { 503 return true; 504 } 505 } 506 507 return false; 508 } 509 510 public IRubyObject getConstant(String name) { 511 SinglyLinkedList cbase = peekCRef(); 513 RubyClass object = runtime.getObject(); 514 IRubyObject result = null; 515 516 do { 518 RubyModule klass = (RubyModule) cbase.getValue(); 519 520 result = klass.getConstantAt(name); 523 if (result == null) { 524 if (runtime.getLoadService().autoload(name) != null) { 525 continue; 526 } 527 } else { 528 return result; 529 } 530 cbase = cbase.getNext(); 531 } while (cbase != null && cbase.getValue() != object); 532 533 return ((RubyModule) peekCRef().getValue()).getConstant(name); 534 } 535 536 public IRubyObject getConstant(String name, RubyModule module) { 537 SinglyLinkedList cbase = module.getCRef(); 539 IRubyObject result = null; 540 541 do { 543 RubyModule klass = (RubyModule) cbase.getValue(); 544 545 result = klass.getConstantAt(name); 548 if (result == null) { 549 if (runtime.getLoadService().autoload(name) != null) { 550 continue; 551 } 552 } else { 553 return result; 554 } 555 cbase = cbase.getNext(); 556 } while (cbase != null); 557 558 return ((RubyModule) peekCRef().getValue()).getConstant(name); 560 } 561 562 private void addBackTraceElement(RubyArray backtrace, Frame frame, Frame previousFrame) { 563 StringBuffer sb = new StringBuffer (100); 564 ISourcePosition position = frame.getPosition(); 565 566 if(previousFrame != null && frame.getName() != null && previousFrame.getName() != null && 567 frame.getName().equals(previousFrame.getName()) && 568 frame.getPosition().getFile().equals(previousFrame.getPosition().getFile()) && 569 frame.getPosition().getEndLine() == previousFrame.getPosition().getEndLine()) { 570 return; 571 } 572 573 sb.append(position.getFile()).append(':').append(position.getEndLine()); 574 575 if (previousFrame != null && previousFrame.getName() != null) { 576 sb.append(":in `").append(previousFrame.getName()).append('\''); 577 } else if (previousFrame == null && frame.getName() != null) { 578 sb.append(":in `").append(frame.getName()).append('\''); 579 } 580 581 backtrace.append(backtrace.getRuntime().newString(sb.toString())); 582 } 583 584 591 public IRubyObject createBacktrace(int level, boolean nativeException) { 592 RubyArray backtrace = runtime.newArray(); 593 int base = currentBindingFrame(); 594 int traceSize = frameIndex - level; 595 596 if (traceSize <= 0) { 597 return backtrace; 598 } 599 600 if (nativeException) { 601 addBackTraceElement(backtrace, frameStack[frameIndex], null); 603 } 604 605 for (int i = traceSize; i > base; i--) { 606 addBackTraceElement(backtrace, (Frame) frameStack[i], (Frame) frameStack[i-1]); 607 } 608 609 return backtrace; 610 } 611 612 public void preAdoptThread() { 613 pushFrame(); 614 pushRubyClass(runtime.getObject()); 615 pushCRef(runtime.getObject()); 616 getCurrentFrame().setSelf(runtime.getTopSelf()); 617 } 618 619 public void preClassEval(StaticScope staticScope, RubyModule type) { 620 pushCRef(type); 621 pushRubyClass(type); 622 pushFrameCopy(); 623 getCurrentFrame().setVisibility(Visibility.PUBLIC); 624 pushScope(new DynamicScope(staticScope, getCurrentScope())); 625 } 626 627 public void postClassEval() { 628 popCRef(); 629 popScope(); 630 popRubyClass(); 631 popFrame(); 632 } 633 634 public void preBsfApply(String [] names) { 635 LocalStaticScope staticScope = new LocalStaticScope(null); 637 staticScope.setVariables(names); 638 pushFrame(); 639 } 640 641 public void postBsfApply() { 642 popFrame(); 643 } 644 645 public void preMethodCall(RubyModule implementationClass, RubyModule clazz, 646 IRubyObject self, String name, IRubyObject[] args, Block block, boolean noSuper) { 647 pushRubyClass((RubyModule)implementationClass.getCRef().getValue()); 648 pushCallFrame(noSuper ? null : clazz, name, self, args, block); 649 } 650 651 public void postMethodCall() { 652 popFrame(); 653 popRubyClass(); 654 } 655 656 public void preDefMethodInternalCall(RubyModule clazz, String name, 657 IRubyObject self, IRubyObject[] args, Block block, boolean noSuper, 658 SinglyLinkedList cref, StaticScope staticScope) { 659 RubyModule implementationClass = (RubyModule)cref.getValue(); 660 setCRef(cref); 661 pushCallFrame(noSuper ? null : clazz, name, self, args, block); 662 pushScope(new DynamicScope(staticScope, getCurrentScope())); 663 pushRubyClass(implementationClass); 664 } 665 666 public void postDefMethodInternalCall() { 667 popRubyClass(); 668 popScope(); 669 popFrame(); 670 unsetCRef(); 671 } 672 673 public void preCompiledMethod(RubyModule implementationClass, SinglyLinkedList cref) { 674 pushRubyClass(implementationClass); 675 setCRef(cref); 676 } 677 678 public void postCompiledMethod() { 679 popRubyClass(); 680 unsetCRef(); 681 } 682 683 public void preReflectedMethodInternalCall(RubyModule implementationClass, RubyModule klazz, IRubyObject self, String name, IRubyObject[] args, boolean noSuper, Block block) { 686 pushRubyClass((RubyModule)implementationClass.getCRef().getValue()); 687 pushCallFrame(noSuper ? null : klazz, name, self, args, block); 688 getCurrentFrame().setVisibility(getPreviousFrame().getVisibility()); 689 } 690 691 public void postReflectedMethodInternalCall() { 692 popFrame(); 693 popRubyClass(); 694 } 695 696 public void preInitCoreClasses() { 697 pushFrame(); 698 setCurrentVisibility(Visibility.PRIVATE); 699 } 700 701 public void preInitBuiltinClasses(RubyClass objectClass, IRubyObject topSelf) { 702 pushRubyClass(objectClass); 703 setCRef(objectClass.getCRef()); 704 705 Frame frame = getCurrentFrame(); 706 frame.setSelf(topSelf); 707 } 708 709 public void preNodeEval(RubyModule newWrapper, RubyModule rubyClass, IRubyObject self) { 710 setWrapper(newWrapper); 711 pushRubyClass(rubyClass); 712 pushCallFrame(null, null, self, IRubyObject.NULL_ARRAY, Block.NULL_BLOCK); 713 714 setCRef(rubyClass.getCRef()); 715 } 716 717 public void postNodeEval(RubyModule newWrapper) { 718 popFrame(); 719 popRubyClass(); 720 setWrapper(newWrapper); 721 unsetCRef(); 722 } 723 724 public void preExecuteUnder(RubyModule executeUnderClass, Block block) { 726 Frame frame = getCurrentFrame(); 727 728 pushRubyClass(executeUnderClass); 729 pushCRef(executeUnderClass); 730 pushCallFrame(frame.getKlazz(), frame.getName(), frame.getSelf(), frame.getArgs(), block); 731 getCurrentFrame().setVisibility(getPreviousFrame().getVisibility()); 732 } 733 734 public void postExecuteUnder() { 735 popFrame(); 736 popRubyClass(); 737 popCRef(); 738 } 739 740 public void preMproc() { 741 pushFrame(); 742 } 743 744 public void postMproc() { 745 popFrame(); 746 } 747 748 public void preRunThread(Frame currentFrame) { 749 pushFrame(currentFrame); 750 } 751 752 public void preTrace() { 753 pushFrame(); 754 } 755 756 public void postTrace() { 757 popFrame(); 758 } 759 760 public void preForBlock(Block block, RubyModule klass) { 761 pushFrame(block.getFrame()); 762 setCRef(block.getCRef()); 763 getCurrentFrame().setVisibility(block.getVisibility()); 764 pushScope(block.getDynamicScope()); 765 pushRubyClass((klass != null) ? klass : block.getKlass()); 766 } 767 768 public void preYieldSpecificBlock(Block block, RubyModule klass) { 769 pushFrame(block.getFrame()); 771 setCRef(block.getCRef()); 772 getCurrentFrame().setVisibility(block.getVisibility()); 773 pushScope(block.getDynamicScope().cloneScope()); 774 pushRubyClass((klass != null) ? klass : block.getKlass()); 775 } 776 777 public void preEvalWithBinding(Block block) { 778 pushBindingFrame(frameIndex); 779 pushFrame(block.getFrame()); 780 setCRef(block.getCRef()); 781 getCurrentFrame().setVisibility(block.getVisibility()); 782 pushRubyClass(block.getKlass()); 783 } 784 785 public void postEvalWithBinding() { 786 popFrame(); 787 unsetCRef(); 788 popRubyClass(); 789 popBindingFrame(); 790 } 791 792 public void postYield() { 793 popScope(); 794 popFrame(); 795 unsetCRef(); 796 popRubyClass(); 797 } 798 799 public void preRootNode(DynamicScope scope) { 800 pushScope(scope); 801 } 802 803 public void postRootNode() { 804 popScope(); 805 } 806 807 813 public boolean isWithinTrace() { 814 return isWithinTrace; 815 } 816 817 823 public void setWithinTrace(boolean isWithinTrace) { 824 this.isWithinTrace = isWithinTrace; 825 } 826 827 832 public boolean isWithinDefined() { 833 return isWithinDefined; 834 } 835 836 841 public void setWithinDefined(boolean isWithinDefined) { 842 this.isWithinDefined = isWithinDefined; 843 } 844 } 845 | Popular Tags |