changeset 13514:0fbee3eb71f0

Ruby: import project.
author Chris Seaton <chris.seaton@oracle.com>
date Mon, 06 Jan 2014 17:12:09 +0000
parents 64a23ce736a0
children fa5180b3c18e
files .hgignore LICENSE.EPL LICENSE.LGPL graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/CoreSource.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/CoreSourceSection.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/DefinedNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/InlinableMethodImplementation.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/ReadNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/RubyNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/RubyRootNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/RubyTypes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/WriteNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/BooleanDispatchNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/BoxedDispatchNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/BoxingDispatchNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/CachedBoxedDispatchNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/CachedUnboxedDispatchNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/CallNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/DispatchHeadNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/DispatchNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/GeneralBoxedDispatchNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/GeneralSuperCallNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/InlineHeuristic.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/InlinedBoxedDispatchNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/InlinedUnboxedDispatchNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/ProcOrNullNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/UnboxedDispatchNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/UninitializedBoxingDispatchNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/UninitializedDispatchNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/cast/BooleanCastNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/cast/LambdaNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/cast/ProcCastNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/cast/SplatCastNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/cast/StringToRegexpNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/cast/StringToSymbolNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/constants/CachedReadConstantNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/constants/ReadConstantNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/constants/UninitializedReadConstantNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/constants/WriteConstantNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/AndNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/BreakNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/ElidableResultNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/EnsureNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/FlipFlopNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/IfNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/NextNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/NotNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/OrNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/RedoNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/RescueAnyNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/RescueClassesNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/RescueNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/RescueSplatNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/RetryNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/ReturnNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/SequenceNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/TryNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/WhileNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayConcatNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayCoreMethodNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayIndexNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayPushNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayRestNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/BasicObjectNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/BignumNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ClassNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ComparableNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ContinuationNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/CoreClass.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/CoreMethod.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/CoreMethodNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/CoreMethodNodeManager.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/DirNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ExceptionNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FalseClassNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FiberNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FileNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FixnumNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FloatNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/HashNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/InterpolatedStringNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/KernelNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/MainNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/MatchDataNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/MathNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ModuleNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/NilClassNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ObjectNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ObjectSpaceNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ProcNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ProcessNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/RangeNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/RegexpNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/SignalNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/StringNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/StructNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/SymbolNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/SystemNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ThreadNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/TimeNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/TrueClassNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/YieldingCoreMethodNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/DebugNodes.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/RubyProxyNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/BignumLiteralNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/BooleanLiteralNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/FixnumLiteralNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/FloatLiteralNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/HashLiteralNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/NilNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/ObjectLiteralNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/RangeLiteralNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/StringLiteralNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/array/ArrayLiteralNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/array/FixnumArrayLiteralNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/array/ObjectArrayLiteralNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/array/UninitialisedArrayLiteralNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/AddMethodNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/AliasNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/BlockDefinitionNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/CatchNextNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/CatchReturnAsErrorNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/CatchReturnNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/MethodDefinitionNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/ShellResultNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/BlockDestructureSwitchNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/CheckArityNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadAllArgumentsNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadBlockArgumentNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadDestructureArgumentNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadOptionalArgumentNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadPostArgumentNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadPreArgumentNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadRestArgumentNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/FlipFlopStateNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/FrameSlotNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/InitFlipFlopSlotNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/LevelFlipFlopStateNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/LocalFlipFlopStateNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/ReadLevelVariableNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/ReadLocalVariableNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/WriteLevelVariableNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/WriteLocalVariableNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/ClassNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/DefineOrGetClassNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/DefineOrGetModuleNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/OpenModuleNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/ReadClassVariableNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/SelfNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/SingletonClassNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/WriteClassVariableNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/ReadFixnumInstanceVariableNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/ReadFloatInstanceVariableNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/ReadInstanceVariableNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/ReadMissingInstanceVariableNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/ReadObjectInstanceVariableNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/ReadSpecializedInstanceVariableNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/UninitializedReadInstanceVariableNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/UninitializedWriteInstanceVariableNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/WriteFixnumInstanceVariableNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/WriteFloatInstanceVariableNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/WriteInstanceVariableNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/WriteObjectInstanceVariableNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/WriteSpecializedInstanceVariableNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/yield/GeneralYieldDispatchNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/yield/InlinedYieldDispatchNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/yield/UninitializedYieldDispatchNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/yield/YieldDispatchNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/yield/YieldNode.java graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/DeadNode.java graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/JRubyParser.java graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/MethodTranslator.java graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/ModuleTranslator.java graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/RubyFrameTypeConversion.java graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/Translator.java graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/TranslatorEnvironment.java graal/com.oracle.truffle.ruby.runtime/.checkstyle_checks.xml graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/InputReader.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/NilPlaceholder.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyArguments.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyContext.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyParser.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyParserResult.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/ShellResult.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/UndefinedPlaceholder.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/configuration/Configuration.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/configuration/ConfigurationBuilder.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/configuration/RubyVersion.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/BreakException.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/BreakShellException.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/ContinuationReturnException.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/ExceptionTranslator.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/NextException.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/QuitException.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/RaiseException.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/RedoException.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/RetryException.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/ReturnException.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/ThrowException.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/CoreLibrary.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/GeneralConversions.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyBignum.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyBinding.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyClass.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyContinuation.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyException.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyFalseClass.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyFiber.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyFile.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyFixnum.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyFloat.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyHash.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyMatchData.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyModule.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyNilClass.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyObject.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyProc.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyRegexp.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyString.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubySymbol.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyThread.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyTime.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyTrueClass.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/StringFormatter.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/ArrayStore.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/ArrayUtilities.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/BaseArrayStore.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/EmptyArrayStore.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/FixnumArrayStore.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/FixnumImmutablePairArrayStore.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/GeneraliseArrayStoreException.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/ObjectArrayStore.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/ObjectImmutablePairArrayStore.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/RubyArray.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/range/FixnumRange.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/range/ObjectRange.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/range/RubyRange.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/MethodLocal.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyBreakAfterProbe.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyBreakBeforeProbe.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyDebugManager.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyProbe.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyProcAfterProbe.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyProcBeforeProbe.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyTraceProbe.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/lookup/LookupFork.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/lookup/LookupNode.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/lookup/LookupTerminal.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/methods/Arity.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/methods/CallTargetMethodImplementation.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/methods/MethodImplementation.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/methods/RubyMethod.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/methods/UniqueMethodIdentifier.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/methods/Visibility.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/FixnumStorageLocation.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/FloatStorageLocation.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/GeneralizeStorageLocationException.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/ObjectLayout.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/ObjectStorageLocation.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/PrimitiveStorageLocation.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/RubyBasicObject.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/StorageLocation.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/Unboxable.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/subsystems/AtExitManager.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/subsystems/FeatureManager.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/subsystems/FiberManager.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/subsystems/ObjectSpaceManager.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/subsystems/ThreadManager.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/subsystems/TraceManager.java graal/com.oracle.truffle.ruby.shell/src/com/oracle/truffle/ruby/shell/CommandLineOptions.java graal/com.oracle.truffle.ruby.shell/src/com/oracle/truffle/ruby/shell/CommandLineParser.java graal/com.oracle.truffle.ruby.shell/src/com/oracle/truffle/ruby/shell/Shell.java graal/com.oracle.truffle.ruby.test/specs/README graal/com.oracle.truffle.ruby.test/specs/rubytruffle graal/com.oracle.truffle.ruby.test/specs/rubytruffle.mspec graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_a_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_d_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_e_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_n_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_p_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_r_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_s_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_upper_e_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_upper_f_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_upper_i_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_upper_u_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_upper_w_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_v_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_w_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_x_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/command_line/error_message_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/BEGIN_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/alias_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/array_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/block_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/break_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/case_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/class_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/class_variable_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/constants_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/def_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/defined_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/encoding_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/ensure_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/execution_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/file_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/for_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/hash_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/line_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/literal_lambda_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/magic_comment_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/match_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/metaclass_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/module_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/next_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/precedence_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/predefined/data_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/predefined_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/private_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/proc_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/redo_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/anchors_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/back-references_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/character_classes_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/encoding_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/escapes_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/grouping_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/interpolation_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/modifiers_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/repetition_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/rescue_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/retry_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/return_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/send_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/singleton_class_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/splat_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/string_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/super_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/symbol_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/throw_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/undef_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/until_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/variables_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/while_tags.txt graal/com.oracle.truffle.ruby.test/specs/tags/language/yield_tags.txt graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/RubyTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/ArrayTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/BignumTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/BoolTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/ContinuationTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/FiberTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/FixnumTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/FloatTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/HashTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/IntegerTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/KernelTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/MathTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/ModuleTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/ObjectSpaceTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/ObjectTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/ProcTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/RangeTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/RegexpTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/StringTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/SymbolTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/ThreadTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/debug/DebugTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/AndTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/BlockTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/CaseTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/ClassLocalTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/ClassTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/ConstantTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/ForTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/GlobalVariableTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/IfTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/InterpolatedStringTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/LocalTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/MethodTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/ModuleTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/MultipleAssignmentTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/OrTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/PolymorphismTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/RaiseRescueTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/RedefinitionTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/ShortcutTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/SpecialVariableTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/UntilTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/WhileTests.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/runtime/ObjectLayoutTests.java mx/mx_graal.py mx/projects
diffstat 394 files changed, 34510 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Mon Jan 06 14:21:39 2014 +0100
+++ b/.hgignore	Mon Jan 06 17:12:09 2014 +0000
@@ -85,3 +85,5 @@
 agent/build/*
 agent/make/filelist
 agent/make/sa17.tar.gz
+graal/com.oracle.truffle.ruby.test/specs/mspec
+graal/com.oracle.truffle.ruby.test/specs/rubyspec
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LICENSE.EPL	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,242 @@
+Some parts of this software are marked as being licensed to you under the terms
+of the Eclipse Public License version 1.0, as follows.
+
+  THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
+  PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION
+  OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+  1. DEFINITIONS
+
+  "Contribution" means:
+
+      a) in the case of the initial Contributor, the initial code and
+         documentation distributed under this Agreement, and
+
+      b) in the case of each subsequent Contributor:
+
+          i) changes to the Program, and
+
+          ii) additions to the Program;
+              where such changes and/or additions to the Program
+              originate from and are distributed by that particular
+              Contributor. A Contribution 'originates' from a
+              Contributor if it was added to the Program by such
+              Contributor itself or anyone acting on such
+              Contributor's behalf. Contributions do not include
+              additions to the Program which: (i) are separate modules
+              of software distributed in conjunction with the Program
+              under their own license agreement, and (ii) are not
+              derivative works of the Program.
+
+  "Contributor" means any person or entity that distributes the Program.
+
+  "Licensed Patents" mean patent claims licensable by a Contributor
+  which are necessarily infringed by the use or sale of its
+  Contribution alone or when combined with the Program.
+
+  "Program" means the Contributions distributed in accordance with
+  this Agreement.
+
+  "Recipient" means anyone who receives the Program under this
+  Agreement, including all Contributors.
+
+  2. GRANT OF RIGHTS
+
+      a) Subject to the terms of this Agreement, each Contributor
+         hereby grants Recipient a non-exclusive, worldwide,
+         royalty-free copyright license to reproduce, prepare
+         derivative works of, publicly display, publicly perform,
+         distribute and sublicense the Contribution of such
+         Contributor, if any, and such derivative works, in source
+         code and object code form.
+
+      b) Subject to the terms of this Agreement, each Contributor
+         hereby grants Recipient a non-exclusive, worldwide,
+         royalty-free patent license under Licensed Patents to make,
+         use, sell, offer to sell, import and otherwise transfer the
+         Contribution of such Contributor, if any, in source code and
+         object code form. This patent license shall apply to the
+         combination of the Contribution and the Program if, at the
+         time the Contribution is added by the Contributor, such
+         addition of the Contribution causes such combination to be
+         covered by the Licensed Patents. The patent license shall not
+         apply to any other combinations which include the
+         Contribution. No hardware per se is licensed hereunder.
+
+      c) Recipient understands that although each Contributor grants
+         the licenses to its Contributions set forth herein, no
+         assurances are provided by any Contributor that the Program
+         does not infringe the patent or other intellectual property
+         rights of any other entity. Each Contributor disclaims any
+         liability to Recipient for claims brought by any other entity
+         based on infringement of intellectual property rights or
+         otherwise. As a condition to exercising the rights and
+         licenses granted hereunder, each Recipient hereby assumes
+         sole responsibility to secure any other intellectual property
+         rights needed, if any. For example, if a third party patent
+         license is required to allow Recipient to distribute the
+         Program, it is Recipient's responsibility to acquire that
+         license before distributing the Program.
+
+      d) Each Contributor represents that to its knowledge it has
+         sufficient copyright rights in its Contribution, if any, to
+         grant the copyright license set forth in this Agreement.
+
+  3. REQUIREMENTS
+
+  A Contributor  may choose to  distribute the Program in  object code
+  form under its own license agreement, provided that:
+
+      a) it complies with the terms and conditions of this Agreement; and
+
+      b) its license agreement:
+
+          i) effectively disclaims on behalf of all Contributors all
+             warranties and conditions, express and implied, including
+             warranties or conditions of title and non-infringement,
+             and implied warranties or conditions of merchantability
+             and fitness for a particular purpose;
+
+          ii) effectively excludes on behalf of all Contributors all
+              liability for damages, including direct, indirect,
+              special, incidental and consequential damages, such as
+              lost profits;
+
+          iii) states that any provisions which differ from this
+               Agreement are offered by that Contributor alone and not
+               by any other party; and
+
+          iv) states that source code for the Program is available
+              from such Contributor, and informs licensees how to
+              obtain it in a reasonable manner on or through a medium
+              customarily used for software exchange.
+
+  When the Program is made available in source code form:
+
+      a) it must be made available under this Agreement; and
+
+      b) a copy of this Agreement must be included with each copy of
+         the Program.
+
+  Contributors may not remove or alter any copyright notices contained
+  within the Program.
+
+  Each Contributor must identify itself as the originator of its
+  Contribution, if any, in a manner that reasonably allows subsequent
+  Recipients to identify the originator of the Contribution.
+
+  4. COMMERCIAL DISTRIBUTION
+
+  Commercial distributors of software may accept certain
+  responsibilities with respect to end users, business partners and
+  the like. While this license is intended to facilitate the
+  commercial use of the Program, the Contributor who includes the
+  Program in a commercial product offering should do so in a manner
+  which does not create potential liability for other Contributors.
+  Therefore, if a Contributor includes the Program in a commercial
+  product offering, such Contributor ("Commercial Contributor") hereby
+  agrees to defend and indemnify every other Contributor ("Indemnified
+  Contributor") against any losses, damages and costs (collectively
+  "Losses") arising from claims, lawsuits and other legal actions
+  brought by a third party against the Indemnified Contributor to the
+  extent caused by the acts or omissions of such Commercial
+  Contributor in connection with its distribution of the Program in a
+  commercial product offering. The obligations in this section do not
+  apply to any claims or Losses relating to any actual or alleged
+  intellectual property infringement. In order to qualify, an
+  Indemnified Contributor must: a) promptly notify the Commercial
+  Contributor in writing of such claim, and b) allow the Commercial
+  Contributor to control, and cooperate with the Commercial
+  Contributor in, the defense and any related settlement negotiations.
+  The Indemnified Contributor may participate in any such claim at its
+  own expense.
+
+  For example, a Contributor might include the Program in a commercial
+  product offering, Product X. That Contributor is then a Commercial
+  Contributor. If that Commercial Contributor then makes performance
+  claims, or offers warranties related to Product X, those performance
+  claims and warranties are such Commercial Contributor's
+  responsibility alone. Under this section, the Commercial Contributor
+  would have to defend claims against the other Contributors related
+  to those performance claims and warranties, and if a court requires
+  any other Contributor to pay any damages as a result, the Commercial
+  Contributor must pay those damages.
+
+  5. NO WARRANTY
+
+  EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
+  PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
+  ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION,
+  ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient
+  is solely responsible for determining the appropriateness of using
+  and distributing the Program and assumes all risks associated with
+  its exercise of rights under this Agreement , including but not
+  limited to the risks and costs of program errors, compliance with
+  applicable laws, damage to or loss of data, programs or equipment,
+  and unavailability or interruption of operations.
+
+  6. DISCLAIMER OF LIABILITY
+
+  EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT
+  NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT,
+  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON
+  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+  THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS
+  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+  DAMAGES.
+
+  7. GENERAL
+
+  If any provision of this Agreement is invalid or unenforceable under
+  applicable law, it shall not affect the validity or enforceability
+  of the remainder of the terms of this Agreement, and without further
+  action by the parties hereto, such provision shall be reformed to
+  the minimum extent necessary to make such provision valid and
+  enforceable.
+
+  If Recipient institutes patent litigation against any entity
+  (including a cross-claim or counterclaim in a lawsuit) alleging that
+  the Program itself (excluding combinations of the Program with other
+  software or hardware) infringes such Recipient's patent(s), then
+  such Recipient's rights granted under Section 2(b) shall terminate
+  as of the date such litigation is filed.
+
+  All Recipient's rights under this Agreement shall terminate if it
+  fails to comply with any of the material terms or conditions of this
+  Agreement and does not cure such failure in a reasonable period of
+  time after becoming aware of such noncompliance. If all Recipient's
+  rights under this Agreement terminate, Recipient agrees to cease use
+  and distribution of the Program as soon as reasonably practicable.
+  However, Recipient's obligations under this Agreement and any
+  licenses granted by Recipient relating to the Program shall continue
+  and survive.
+
+  Everyone is permitted to copy and distribute copies of this
+  Agreement, but in order to avoid inconsistency the Agreement is
+  copyrighted and may only be modified in the following manner. The
+  Agreement Steward reserves the right to publish new versions
+  (including revisions) of this Agreement from time to time. No one
+  other than the Agreement Steward has the right to modify this
+  Agreement. The Eclipse Foundation is the initial Agreement Steward.
+  The Eclipse Foundation may assign the responsibility to serve as the
+  Agreement Steward to a suitable separate entity. Each new version of
+  the Agreement will be given a distinguishing version number. The
+  Program (including Contributions) may always be distributed subject
+  to the version of the Agreement under which it was received. In
+  addition, after a new version of the Agreement is published,
+  Contributor may elect to distribute the Program (including its
+  Contributions) under the new version. Except as expressly stated in
+  Sections 2(a) and 2(b) above, Recipient receives no rights or
+  licenses to the intellectual property of any Contributor under this
+  Agreement, whether expressly, by implication, estoppel or otherwise.
+  All rights in the Program not expressly granted under this Agreement
+  are reserved.
+
+  This Agreement is governed by the laws of the State of New York and
+  the intellectual property laws of the United States of America. No
+  party to this Agreement will bring a legal action under this
+  Agreement more than one year after the cause of action arose. Each
+  party waives its rights to a jury trial in any resulting litigation.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LICENSE.LGPL	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,505 @@
+Some parts of this software are marked as being licensed to you under the terms
+of the GNU Lesser General Public License version 2.1, as follows.
+
+        GNU LESSER GENERAL PUBLIC LICENSE
+             Version 2.1, February 1999
+
+   Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+   Everyone is permitted to copy and distribute verbatim copies
+   of this license document, but changing it is not allowed.
+
+  [This is the first released version of the Lesser GPL.  It also counts
+   as the successor of the GNU Library Public License, version 2, hence
+   the version number 2.1.]
+
+            Preamble
+
+    The licenses for most software are designed to take away your
+  freedom to share and change it.  By contrast, the GNU General Public
+  Licenses are intended to guarantee your freedom to share and change
+  free software--to make sure the software is free for all its users.
+
+    This license, the Lesser General Public License, applies to some
+  specially designated software packages--typically libraries--of the
+  Free Software Foundation and other authors who decide to use it.  You
+  can use it too, but we suggest you first think carefully about whether
+  this license or the ordinary General Public License is the better
+  strategy to use in any particular case, based on the explanations below.
+
+    When we speak of free software, we are referring to freedom of use,
+  not price.  Our General Public Licenses are designed to make sure that
+  you have the freedom to distribute copies of free software (and charge
+  for this service if you wish); that you receive source code or can get
+  it if you want it; that you can change the software and use pieces of
+  it in new free programs; and that you are informed that you can do
+  these things.
+
+    To protect your rights, we need to make restrictions that forbid
+  distributors to deny you these rights or to ask you to surrender these
+  rights.  These restrictions translate to certain responsibilities for
+  you if you distribute copies of the library or if you modify it.
+
+    For example, if you distribute copies of the library, whether gratis
+  or for a fee, you must give the recipients all the rights that we gave
+  you.  You must make sure that they, too, receive or can get the source
+  code.  If you link other code with the library, you must provide
+  complete object files to the recipients, so that they can relink them
+  with the library after making changes to the library and recompiling
+  it.  And you must show them these terms so they know their rights.
+
+    We protect your rights with a two-step method: (1) we copyright the
+  library, and (2) we offer you this license, which gives you legal
+  permission to copy, distribute and/or modify the library.
+
+    To protect each distributor, we want to make it very clear that
+  there is no warranty for the free library.  Also, if the library is
+  modified by someone else and passed on, the recipients should know
+  that what they have is not the original version, so that the original
+  author's reputation will not be affected by problems that might be
+  introduced by others.
+
+    Finally, software patents pose a constant threat to the existence of
+  any free program.  We wish to make sure that a company cannot
+  effectively restrict the users of a free program by obtaining a
+  restrictive license from a patent holder.  Therefore, we insist that
+  any patent license obtained for a version of the library must be
+  consistent with the full freedom of use specified in this license.
+
+    Most GNU software, including some libraries, is covered by the
+  ordinary GNU General Public License.  This license, the GNU Lesser
+  General Public License, applies to certain designated libraries, and
+  is quite different from the ordinary General Public License.  We use
+  this license for certain libraries in order to permit linking those
+  libraries into non-free programs.
+
+    When a program is linked with a library, whether statically or using
+  a shared library, the combination of the two is legally speaking a
+  combined work, a derivative of the original library.  The ordinary
+  General Public License therefore permits such linking only if the
+  entire combination fits its criteria of freedom.  The Lesser General
+  Public License permits more lax criteria for linking other code with
+  the library.
+
+    We call this license the "Lesser" General Public License because it
+  does Less to protect the user's freedom than the ordinary General
+  Public License.  It also provides other free software developers Less
+  of an advantage over competing non-free programs.  These disadvantages
+  are the reason we use the ordinary General Public License for many
+  libraries.  However, the Lesser license provides advantages in certain
+  special circumstances.
+
+    For example, on rare occasions, there may be a special need to
+  encourage the widest possible use of a certain library, so that it becomes
+  a de-facto standard.  To achieve this, non-free programs must be
+  allowed to use the library.  A more frequent case is that a free
+  library does the same job as widely used non-free libraries.  In this
+  case, there is little to gain by limiting the free library to free
+  software only, so we use the Lesser General Public License.
+
+    In other cases, permission to use a particular library in non-free
+  programs enables a greater number of people to use a large body of
+  free software.  For example, permission to use the GNU C Library in
+  non-free programs enables many more people to use the whole GNU
+  operating system, as well as its variant, the GNU/Linux operating
+  system.
+
+    Although the Lesser General Public License is Less protective of the
+  users' freedom, it does ensure that the user of a program that is
+  linked with the Library has the freedom and the wherewithal to run
+  that program using a modified version of the Library.
+
+    The precise terms and conditions for copying, distribution and
+  modification follow.  Pay close attention to the difference between a
+  "work based on the library" and a "work that uses the library".  The
+  former contains code derived from the library, whereas the latter must
+  be combined with the library in order to run.
+
+        GNU LESSER GENERAL PUBLIC LICENSE
+     TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+    0. This License Agreement applies to any software library or other
+  program which contains a notice placed by the copyright holder or
+  other authorized party saying it may be distributed under the terms of
+  this Lesser General Public License (also called "this License").
+  Each licensee is addressed as "you".
+
+    A "library" means a collection of software functions and/or data
+  prepared so as to be conveniently linked with application programs
+  (which use some of those functions and data) to form executables.
+
+    The "Library", below, refers to any such software library or work
+  which has been distributed under these terms.  A "work based on the
+  Library" means either the Library or any derivative work under
+  copyright law: that is to say, a work containing the Library or a
+  portion of it, either verbatim or with modifications and/or translated
+  straightforwardly into another language.  (Hereinafter, translation is
+  included without limitation in the term "modification".)
+
+    "Source code" for a work means the preferred form of the work for
+  making modifications to it.  For a library, complete source code means
+  all the source code for all modules it contains, plus any associated
+  interface definition files, plus the scripts used to control compilation
+  and installation of the library.
+
+    Activities other than copying, distribution and modification are not
+  covered by this License; they are outside its scope.  The act of
+  running a program using the Library is not restricted, and output from
+  such a program is covered only if its contents constitute a work based
+  on the Library (independent of the use of the Library in a tool for
+  writing it).  Whether that is true depends on what the Library does
+  and what the program that uses the Library does.
+  
+    1. You may copy and distribute verbatim copies of the Library's
+  complete source code as you receive it, in any medium, provided that
+  you conspicuously and appropriately publish on each copy an
+  appropriate copyright notice and disclaimer of warranty; keep intact
+  all the notices that refer to this License and to the absence of any
+  warranty; and distribute a copy of this License along with the
+  Library.
+
+    You may charge a fee for the physical act of transferring a copy,
+  and you may at your option offer warranty protection in exchange for a
+  fee.
+
+    2. You may modify your copy or copies of the Library or any portion
+  of it, thus forming a work based on the Library, and copy and
+  distribute such modifications or work under the terms of Section 1
+  above, provided that you also meet all of these conditions:
+
+      a) The modified work must itself be a software library.
+
+      b) You must cause the files modified to carry prominent notices
+      stating that you changed the files and the date of any change.
+
+      c) You must cause the whole of the work to be licensed at no
+      charge to all third parties under the terms of this License.
+
+      d) If a facility in the modified Library refers to a function or a
+      table of data to be supplied by an application program that uses
+      the facility, other than as an argument passed when the facility
+      is invoked, then you must make a good faith effort to ensure that,
+      in the event an application does not supply such function or
+      table, the facility still operates, and performs whatever part of
+      its purpose remains meaningful.
+
+      (For example, a function in a library to compute square roots has
+      a purpose that is entirely well-defined independent of the
+      application.  Therefore, Subsection 2d requires that any
+      application-supplied function or table used by this function must
+      be optional: if the application does not supply it, the square
+      root function must still compute square roots.)
+
+  These requirements apply to the modified work as a whole.  If
+  identifiable sections of that work are not derived from the Library,
+  and can be reasonably considered independent and separate works in
+  themselves, then this License, and its terms, do not apply to those
+  sections when you distribute them as separate works.  But when you
+  distribute the same sections as part of a whole which is a work based
+  on the Library, the distribution of the whole must be on the terms of
+  this License, whose permissions for other licensees extend to the
+  entire whole, and thus to each and every part regardless of who wrote
+  it.
+
+  Thus, it is not the intent of this section to claim rights or contest
+  your rights to work written entirely by you; rather, the intent is to
+  exercise the right to control the distribution of derivative or
+  collective works based on the Library.
+
+  In addition, mere aggregation of another work not based on the Library
+  with the Library (or with a work based on the Library) on a volume of
+  a storage or distribution medium does not bring the other work under
+  the scope of this License.
+
+    3. You may opt to apply the terms of the ordinary GNU General Public
+  License instead of this License to a given copy of the Library.  To do
+  this, you must alter all the notices that refer to this License, so
+  that they refer to the ordinary GNU General Public License, version 2,
+  instead of to this License.  (If a newer version than version 2 of the
+  ordinary GNU General Public License has appeared, then you can specify
+  that version instead if you wish.)  Do not make any other change in
+  these notices.
+
+    Once this change is made in a given copy, it is irreversible for
+  that copy, so the ordinary GNU General Public License applies to all
+  subsequent copies and derivative works made from that copy.
+
+    This option is useful when you wish to copy part of the code of
+  the Library into a program that is not a library.
+
+    4. You may copy and distribute the Library (or a portion or
+  derivative of it, under Section 2) in object code or executable form
+  under the terms of Sections 1 and 2 above provided that you accompany
+  it with the complete corresponding machine-readable source code, which
+  must be distributed under the terms of Sections 1 and 2 above on a
+  medium customarily used for software interchange.
+
+    If distribution of object code is made by offering access to copy
+  from a designated place, then offering equivalent access to copy the
+  source code from the same place satisfies the requirement to
+  distribute the source code, even though third parties are not
+  compelled to copy the source along with the object code.
+
+    5. A program that contains no derivative of any portion of the
+  Library, but is designed to work with the Library by being compiled or
+  linked with it, is called a "work that uses the Library".  Such a
+  work, in isolation, is not a derivative work of the Library, and
+  therefore falls outside the scope of this License.
+
+    However, linking a "work that uses the Library" with the Library
+  creates an executable that is a derivative of the Library (because it
+  contains portions of the Library), rather than a "work that uses the
+  library".  The executable is therefore covered by this License.
+  Section 6 states terms for distribution of such executables.
+
+    When a "work that uses the Library" uses material from a header file
+  that is part of the Library, the object code for the work may be a
+  derivative work of the Library even though the source code is not.
+  Whether this is true is especially significant if the work can be
+  linked without the Library, or if the work is itself a library.  The
+  threshold for this to be true is not precisely defined by law.
+
+    If such an object file uses only numerical parameters, data
+  structure layouts and accessors, and small macros and small inline
+  functions (ten lines or less in length), then the use of the object
+  file is unrestricted, regardless of whether it is legally a derivative
+  work.  (Executables containing this object code plus portions of the
+  Library will still fall under Section 6.)
+
+    Otherwise, if the work is a derivative of the Library, you may
+  distribute the object code for the work under the terms of Section 6.
+  Any executables containing that work also fall under Section 6,
+  whether or not they are linked directly with the Library itself.
+
+    6. As an exception to the Sections above, you may also combine or
+  link a "work that uses the Library" with the Library to produce a
+  work containing portions of the Library, and distribute that work
+  under terms of your choice, provided that the terms permit
+  modification of the work for the customer's own use and reverse
+  engineering for debugging such modifications.
+
+    You must give prominent notice with each copy of the work that the
+  Library is used in it and that the Library and its use are covered by
+  this License.  You must supply a copy of this License.  If the work
+  during execution displays copyright notices, you must include the
+  copyright notice for the Library among them, as well as a reference
+  directing the user to the copy of this License.  Also, you must do one
+  of these things:
+
+      a) Accompany the work with the complete corresponding
+      machine-readable source code for the Library including whatever
+      changes were used in the work (which must be distributed under
+      Sections 1 and 2 above); and, if the work is an executable linked
+      with the Library, with the complete machine-readable "work that
+      uses the Library", as object code and/or source code, so that the
+      user can modify the Library and then relink to produce a modified
+      executable containing the modified Library.  (It is understood
+      that the user who changes the contents of definitions files in the
+      Library will not necessarily be able to recompile the application
+      to use the modified definitions.)
+
+      b) Use a suitable shared library mechanism for linking with the
+      Library.  A suitable mechanism is one that (1) uses at run time a
+      copy of the library already present on the user's computer system,
+      rather than copying library functions into the executable, and (2)
+      will operate properly with a modified version of the library, if
+      the user installs one, as long as the modified version is
+      interface-compatible with the version that the work was made with.
+
+      c) Accompany the work with a written offer, valid for at
+      least three years, to give the same user the materials
+      specified in Subsection 6a, above, for a charge no more
+      than the cost of performing this distribution.
+
+      d) If distribution of the work is made by offering access to copy
+      from a designated place, offer equivalent access to copy the above
+      specified materials from the same place.
+
+      e) Verify that the user has already received a copy of these
+      materials or that you have already sent this user a copy.
+
+    For an executable, the required form of the "work that uses the
+  Library" must include any data and utility programs needed for
+  reproducing the executable from it.  However, as a special exception,
+  the materials to be distributed need not include anything that is
+  normally distributed (in either source or binary form) with the major
+  components (compiler, kernel, and so on) of the operating system on
+  which the executable runs, unless that component itself accompanies
+  the executable.
+
+    It may happen that this requirement contradicts the license
+  restrictions of other proprietary libraries that do not normally
+  accompany the operating system.  Such a contradiction means you cannot
+  use both them and the Library together in an executable that you
+  distribute.
+
+    7. You may place library facilities that are a work based on the
+  Library side-by-side in a single library together with other library
+  facilities not covered by this License, and distribute such a combined
+  library, provided that the separate distribution of the work based on
+  the Library and of the other library facilities is otherwise
+  permitted, and provided that you do these two things:
+
+      a) Accompany the combined library with a copy of the same work
+      based on the Library, uncombined with any other library
+      facilities.  This must be distributed under the terms of the
+      Sections above.
+
+      b) Give prominent notice with the combined library of the fact
+      that part of it is a work based on the Library, and explaining
+      where to find the accompanying uncombined form of the same work.
+
+    8. You may not copy, modify, sublicense, link with, or distribute
+  the Library except as expressly provided under this License.  Any
+  attempt otherwise to copy, modify, sublicense, link with, or
+  distribute the Library is void, and will automatically terminate your
+  rights under this License.  However, parties who have received copies,
+  or rights, from you under this License will not have their licenses
+  terminated so long as such parties remain in full compliance.
+
+    9. You are not required to accept this License, since you have not
+  signed it.  However, nothing else grants you permission to modify or
+  distribute the Library or its derivative works.  These actions are
+  prohibited by law if you do not accept this License.  Therefore, by
+  modifying or distributing the Library (or any work based on the
+  Library), you indicate your acceptance of this License to do so, and
+  all its terms and conditions for copying, distributing or modifying
+  the Library or works based on it.
+
+    10. Each time you redistribute the Library (or any work based on the
+  Library), the recipient automatically receives a license from the
+  original licensor to copy, distribute, link with or modify the Library
+  subject to these terms and conditions.  You may not impose any further
+  restrictions on the recipients' exercise of the rights granted herein.
+  You are not responsible for enforcing compliance by third parties with
+  this License.
+
+    11. If, as a consequence of a court judgment or allegation of patent
+  infringement or for any other reason (not limited to patent issues),
+  conditions are imposed on you (whether by court order, agreement or
+  otherwise) that contradict the conditions of this License, they do not
+  excuse you from the conditions of this License.  If you cannot
+  distribute so as to satisfy simultaneously your obligations under this
+  License and any other pertinent obligations, then as a consequence you
+  may not distribute the Library at all.  For example, if a patent
+  license would not permit royalty-free redistribution of the Library by
+  all those who receive copies directly or indirectly through you, then
+  the only way you could satisfy both it and this License would be to
+  refrain entirely from distribution of the Library.
+
+  If any portion of this section is held invalid or unenforceable under any
+  particular circumstance, the balance of the section is intended to apply,
+  and the section as a whole is intended to apply in other circumstances.
+
+  It is not the purpose of this section to induce you to infringe any
+  patents or other property right claims or to contest validity of any
+  such claims; this section has the sole purpose of protecting the
+  integrity of the free software distribution system which is
+  implemented by public license practices.  Many people have made
+  generous contributions to the wide range of software distributed
+  through that system in reliance on consistent application of that
+  system; it is up to the author/donor to decide if he or she is willing
+  to distribute software through any other system and a licensee cannot
+  impose that choice.
+
+  This section is intended to make thoroughly clear what is believed to
+  be a consequence of the rest of this License.
+
+    12. If the distribution and/or use of the Library is restricted in
+  certain countries either by patents or by copyrighted interfaces, the
+  original copyright holder who places the Library under this License may add
+  an explicit geographical distribution limitation excluding those countries,
+  so that distribution is permitted only in or among countries not thus
+  excluded.  In such case, this License incorporates the limitation as if
+  written in the body of this License.
+
+    13. The Free Software Foundation may publish revised and/or new
+  versions of the Lesser General Public License from time to time.
+  Such new versions will be similar in spirit to the present version,
+  but may differ in detail to address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the Library
+  specifies a version number of this License which applies to it and
+  "any later version", you have the option of following the terms and
+  conditions either of that version or of any later version published by
+  the Free Software Foundation.  If the Library does not specify a
+  license version number, you may choose any version ever published by
+  the Free Software Foundation.
+
+    14. If you wish to incorporate parts of the Library into other free
+  programs whose distribution conditions are incompatible with these,
+  write to the author to ask for permission.  For software which is
+  copyrighted by the Free Software Foundation, write to the Free
+  Software Foundation; we sometimes make exceptions for this.  Our
+  decision will be guided by the two goals of preserving the free status
+  of all derivatives of our free software and of promoting the sharing
+  and reuse of software generally.
+
+            NO WARRANTY
+
+    15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+  WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+  OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+  PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+  LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+  THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+    16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+  WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+  AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+  FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+  CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+  LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+  RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+  FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+  SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+  DAMAGES.
+
+           END OF TERMS AND CONDITIONS
+
+             How to Apply These Terms to Your New Libraries
+
+    If you develop a new library, and you want it to be of the greatest
+  possible use to the public, we recommend making it free software that
+  everyone can redistribute and change.  You can do so by permitting
+  redistribution under these terms (or, alternatively, under the terms of the
+  ordinary General Public License).
+
+    To apply these terms, attach the following notices to the library.  It is
+  safest to attach them to the start of each source file to most effectively
+  convey the exclusion of warranty; and each file should have at least the
+  "copyright" line and a pointer to where the full notice is found.
+
+      <one line to give the library's name and a brief idea of what it does.>
+      Copyright (C) <year>  <name of author>
+
+      This library is free software; you can redistribute it and/or
+      modify it under the terms of the GNU Lesser General Public
+      License as published by the Free Software Foundation; either
+      version 2.1 of the License, or (at your option) any later version.
+
+      This library is distributed in the hope that it will be useful,
+      but WITHOUT ANY WARRANTY; without even the implied warranty of
+      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+      Lesser General Public License for more details.
+
+      You should have received a copy of the GNU Lesser General Public
+      License along with this library; if not, write to the Free Software
+      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+  Also add information on how to contact you by electronic and paper mail.
+
+  You should also get your employer (if you work as a programmer) or your
+  school, if any, to sign a "copyright disclaimer" for the library, if
+  necessary.  Here is a sample; alter the names:
+
+    Yoyodyne, Inc., hereby disclaims all copyright interest in the
+    library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+    <signature of Ty Coon>, 1 April 1990
+    Ty Coon, President of Vice
+
+  That's all there is to it!
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/CoreSource.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes;
+
+import java.io.*;
+
+import com.oracle.truffle.api.*;
+
+/**
+ * Singleton source used for core method nodes.
+ */
+public final class CoreSource implements Source {
+
+    private final String name;
+
+    public CoreSource(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getCode() {
+        return name;
+    }
+
+    @Override
+    public String toString() {
+        return name;
+    }
+
+    public String getPath() {
+        return null;
+    }
+
+    public Reader getReader() {
+        return null;
+    }
+
+    public InputStream getInputStream() {
+        return null;
+    }
+
+    public String getCode(int lineNumber) {
+        return null;
+    }
+
+    public int getLineCount() {
+        return 0;
+    }
+
+    public int getLineNumber(int offset) {
+        return 0;
+    }
+
+    public int getLineStartOffset(int lineNumber) {
+        return 0;
+    }
+
+    public int getLineLength(int lineNumber) {
+        return 0;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/CoreSourceSection.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes;
+
+import com.oracle.truffle.api.*;
+
+/**
+ * Singleton source section used for core method nodes.
+ */
+public final class CoreSourceSection implements SourceSection {
+
+    private final String name;
+
+    public CoreSourceSection(String name) {
+        this.name = name;
+    }
+
+    public Source getSource() {
+        return new CoreSource(name);
+    }
+
+    public int getStartLine() {
+        return 0;
+    }
+
+    public int getStartColumn() {
+        return 0;
+    }
+
+    public int getCharIndex() {
+        return 0;
+    }
+
+    @Override
+    public int getCharLength() {
+        return 0;
+    }
+
+    public int getCharEndIndex() {
+        return 0;
+    }
+
+    public String getIdentifier() {
+        return null;
+    }
+
+    public String getCode() {
+        return name;
+    }
+
+    @Override
+    public String toString() {
+        return name;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/DefinedNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * Switches execution to the parallel {@link RubyNode#isDefined} semantic path. Represents the
+ * {@code defined?} keyword in Ruby.
+ */
+@NodeInfo(shortName = "defined")
+public class DefinedNode extends RubyNode {
+
+    @Child protected RubyNode child;
+
+    public DefinedNode(RubyContext context, SourceSection sourceSection, RubyNode child) {
+        super(context, sourceSection);
+        this.child = adoptChild(child);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        return child.isDefined(frame);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/InlinableMethodImplementation.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.call.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+
+/**
+ * A method implementation that also carries the pristine root node and frame descriptor, from which
+ * we can inline.
+ * 
+ * @see InlinedUnboxedDispatchNode
+ * @see InlinedBoxedDispatchNode
+ * @see InlineHeuristic
+ */
+public class InlinableMethodImplementation extends CallTargetMethodImplementation {
+
+    private final FrameDescriptor frameDescriptor;
+    private final RubyRootNode pristineRootNode;
+
+    public final boolean alwaysInline;
+    public final boolean shouldAppendCallNode;
+
+    public InlinableMethodImplementation(CallTarget callTarget, MaterializedFrame declarationFrame, FrameDescriptor frameDescriptor, RubyRootNode pristineRootNode, boolean alwaysInline,
+                    boolean shouldAppendCallNode) {
+        super(callTarget, declarationFrame);
+
+        assert frameDescriptor != null;
+        assert pristineRootNode != null;
+
+        this.frameDescriptor = frameDescriptor;
+        this.pristineRootNode = pristineRootNode;
+        this.alwaysInline = alwaysInline;
+        this.shouldAppendCallNode = shouldAppendCallNode;
+    }
+
+    public FrameDescriptor getFrameDescriptor() {
+        return frameDescriptor;
+    }
+
+    public RubyRootNode getPristineRootNode() {
+        return pristineRootNode;
+    }
+
+    public RubyRootNode getCloneOfPristineRootNode() {
+        return NodeUtil.cloneNode(pristineRootNode);
+    }
+
+    public boolean alwaysInline() {
+        return alwaysInline;
+    }
+
+    public boolean getShouldAppendCallNode() {
+        return shouldAppendCallNode;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/ReadNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes;
+
+/**
+ * Interface for all nodes which read something, providing a method to transform them to write the
+ * same thing.
+ */
+public interface ReadNode {
+
+    /**
+     * Return a new node that performs the equivalent write operation to this node's read, using the
+     * supplied node for the right-hand-side.
+     */
+    RubyNode makeWriteNode(RubyNode rhs);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/RubyNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes;
+
+import java.math.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.call.*;
+import com.oracle.truffle.ruby.nodes.debug.*;
+import com.oracle.truffle.ruby.nodes.yield.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+import com.oracle.truffle.ruby.runtime.core.range.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Base class for most nodes in Ruby.
+ * 
+ * @see DispatchNode
+ * @see YieldDispatchNode
+ */
+@TypeSystemReference(RubyTypes.class)
+public abstract class RubyNode extends Node {
+
+    private final RubyContext context;
+
+    public RubyNode(RubyContext context, SourceSection sourceSection) {
+        super(sourceSection);
+
+        assert context != null;
+        assert sourceSection != null;
+
+        this.context = context;
+    }
+
+    public RubyNode(RubyNode prev) {
+        this(prev.context, prev.getSourceSection());
+    }
+
+    public abstract Object execute(VirtualFrame frame);
+
+    /**
+     * Ruby's parallel semantic path.
+     * 
+     * @see DefinedNode
+     */
+    public Object isDefined(@SuppressWarnings("unused") VirtualFrame frame) {
+        throw new UnsupportedOperationException("no definition for " + getClass().getName());
+    }
+
+    public RubyArray executeArray(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectRubyArray(execute(frame));
+    }
+
+    public BigInteger executeBignum(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectBigInteger(execute(frame));
+    }
+
+    public boolean executeBoolean(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectBoolean(execute(frame));
+    }
+
+    public RubyBignum executeBoxedBignum(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectRubyBignum(execute(frame));
+    }
+
+    public RubyFixnum executeBoxedFixnum(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectRubyFixnum(execute(frame));
+    }
+
+    public RubyFloat executeBoxedFloat(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectRubyFloat(execute(frame));
+    }
+
+    public int executeFixnum(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectInteger(execute(frame));
+    }
+
+    public FixnumRange executeFixnumRange(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectFixnumRange(execute(frame));
+    }
+
+    public double executeFloat(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectDouble(execute(frame));
+    }
+
+    public NilPlaceholder executeNilPlaceholder(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectNilPlaceholder(execute(frame));
+    }
+
+    public Node executeNode(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectNode(execute(frame));
+    }
+
+    public Object[] executeObjectArray(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectObjectArray(execute(frame));
+    }
+
+    public ObjectRange executeObjectRange(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectObjectRange(execute(frame));
+    }
+
+    public RubyBasicObject executeRubyBasicObject(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectRubyBasicObject(execute(frame));
+    }
+
+    public RubyBinding executeRubyBinding(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectRubyBinding(execute(frame));
+    }
+
+    public RubyClass executeRubyClass(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectRubyClass(execute(frame));
+    }
+
+    public RubyContinuation executeRubyContinuation(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectRubyContinuation(execute(frame));
+    }
+
+    public RubyException executeRubyException(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectRubyException(execute(frame));
+    }
+
+    public RubyFiber executeRubyFiber(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectRubyFiber(execute(frame));
+    }
+
+    public RubyFile executeRubyFile(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectRubyFile(execute(frame));
+    }
+
+    public RubyHash executeRubyHash(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectRubyHash(execute(frame));
+    }
+
+    public RubyMatchData executeRubyMatchData(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectRubyMatchData(execute(frame));
+    }
+
+    public RubyMethod executeRubyMethod(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectRubyMethod(execute(frame));
+    }
+
+    public RubyModule executeRubyModule(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectRubyModule(execute(frame));
+    }
+
+    public RubyNilClass executeRubyNilClass(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectRubyNilClass(execute(frame));
+    }
+
+    public RubyObject executeRubyObject(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectRubyObject(execute(frame));
+    }
+
+    public RubyProc executeRubyProc(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectRubyProc(execute(frame));
+    }
+
+    public RubyRange executeRubyRange(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectRubyRange(execute(frame));
+    }
+
+    public RubyRegexp executeRubyRegexp(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectRubyRegexp(execute(frame));
+    }
+
+    public RubySymbol executeRubySymbol(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectRubySymbol(execute(frame));
+    }
+
+    public RubyThread executeRubyThread(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectRubyThread(execute(frame));
+    }
+
+    public RubyTime executeRubyTime(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectRubyTime(execute(frame));
+    }
+
+    public RubyString executeString(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectRubyString(execute(frame));
+    }
+
+    public UndefinedPlaceholder executeUndefinedPlaceholder(VirtualFrame frame) throws UnexpectedResultException {
+        return RubyTypesGen.RUBYTYPES.expectUndefinedPlaceholder(execute(frame));
+    }
+
+    public void executeVoid(VirtualFrame frame) {
+        execute(frame);
+    }
+
+    /**
+     * If you aren't sure whether you have a normal {@link RubyNode} or a {@link RubyProxyNode},
+     * this method will return the real node, whether that is this node, or whether this node is a
+     * proxy and you actually need the child.
+     */
+    public RubyNode getNonProxyNode() {
+        return this;
+    }
+
+    public RubyContext getContext() {
+        return context;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/RubyRootNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * The root node in an AST for a method. Unlike {@link RubyNode}, this has a single entry point,
+ * {@link #execute}, which Truffle knows about and can create a {@link CallTarget} from.
+ */
+public class RubyRootNode extends RootNode {
+
+    protected final String indicativeName;
+    @Child protected RubyNode body;
+
+    public RubyRootNode(SourceSection sourceSection, String indicativeName, RubyNode body) {
+        super(sourceSection);
+
+        assert indicativeName != null;
+        assert body != null;
+
+        this.body = adoptChild(body);
+        this.indicativeName = indicativeName;
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        return body.execute(frame);
+    }
+
+    @Override
+    public String toString() {
+        final SourceSection sourceSection = getSourceSection();
+        final String source = sourceSection == null ? "<unknown>" : sourceSection.toString();
+        return "Method " + indicativeName + ":" + source + "@" + Integer.toHexString(hashCode());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/RubyTypes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes;
+
+import java.math.*;
+
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+import com.oracle.truffle.ruby.runtime.core.range.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * The list of types and type conversions that the AST interpreter knows about and can specialise
+ * using. Used by the DSL.
+ */
+@TypeSystem({UndefinedPlaceholder.class, //
+                NilPlaceholder.class, //
+                boolean.class, //
+                int.class, //
+                double.class, //
+                BigInteger.class, //
+                FixnumRange.class, //
+                ObjectRange.class, //
+                RubyArray.class, //
+                RubyBignum.class, //
+                RubyBinding.class, //
+                RubyClass.class, //
+                RubyContinuation.class, //
+                RubyException.class, //
+                RubyFiber.class, //
+                RubyFile.class, //
+                RubyFixnum.class, //
+                RubyFloat.class, //
+                RubyHash.class, //
+                RubyMatchData.class, //
+                RubyMethod.class, //
+                RubyModule.class, //
+                RubyNilClass.class, //
+                RubyProc.class, //
+                RubyRange.class, //
+                RubyRegexp.class, //
+                RubyString.class, //
+                RubySymbol.class, //
+                RubyThread.class, //
+                RubyTime.class, //
+                RubyObject.class, //
+                RubyBasicObject.class, //
+                Node.class, //
+                Object[].class})
+public class RubyTypes {
+
+    /*
+     * The implicit casts allow the DSL to convert from an object of one type to another to satisfy
+     * specializations.
+     */
+
+    @ImplicitCast
+    public NilPlaceholder unboxNil(@SuppressWarnings("unused") RubyNilClass value) {
+        return NilPlaceholder.INSTANCE;
+    }
+
+    @ImplicitCast
+    public int unboxFixnum(RubyFixnum value) {
+        return value.getValue();
+    }
+
+    @ImplicitCast
+    public BigInteger unboxBignum(RubyBignum value) {
+        return value.getValue();
+    }
+
+    @ImplicitCast
+    public double unboxFloat(RubyFloat value) {
+        return value.getValue();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/WriteNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes;
+
+/**
+ * Interface for all nodes which write something, providing a method to transform them to read the
+ * same thing.
+ */
+public interface WriteNode {
+
+    /**
+     * Return a new node that performs the equivalent read operation to this node's write.
+     */
+    RubyNode makeReadNode();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/BooleanDispatchNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.call;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+
+/**
+ * An unboxed node in the dispatch chain that dispatches if the node is a boolean. In normal unboxed
+ * dispatch we look at the Java class of the receiver. However, in Ruby true and false are two
+ * separate classes, so in this situation we have to dispatch on the value, as well as the Java
+ * class when we are dealing with booleans.
+ * <p>
+ * TODO(CS): it would be nice if we could {@link RubyNode#executeBoolean} the receiver, but by the
+ * time we get to this dispatch node the receiver is already executed.
+ */
+public class BooleanDispatchNode extends UnboxedDispatchNode {
+
+    private final Assumption falseUnmodifiedAssumption;
+    private final RubyMethod falseMethod;
+
+    private final Assumption trueUnmodifiedAssumption;
+    private final RubyMethod trueMethod;
+
+    @Child protected UnboxedDispatchNode next;
+
+    public BooleanDispatchNode(RubyContext context, SourceSection sourceSection, Assumption falseUnmodifiedAssumption, RubyMethod falseMethod, Assumption trueUnmodifiedAssumption,
+                    RubyMethod trueMethod, UnboxedDispatchNode next) {
+        super(context, sourceSection);
+
+        assert falseUnmodifiedAssumption != null;
+        assert falseMethod != null;
+        assert trueUnmodifiedAssumption != null;
+        assert trueMethod != null;
+
+        this.falseUnmodifiedAssumption = falseUnmodifiedAssumption;
+        this.falseMethod = falseMethod;
+
+        this.trueUnmodifiedAssumption = trueUnmodifiedAssumption;
+        this.trueMethod = trueMethod;
+
+        this.next = adoptChild(next);
+    }
+
+    @Override
+    public Object dispatch(VirtualFrame frame, Object receiverObject, RubyProc blockObject, Object[] argumentsObjects) {
+        // Check it's a boolean
+
+        if (!(receiverObject instanceof Boolean)) {
+            return next.dispatch(frame, receiverObject, blockObject, argumentsObjects);
+        }
+
+        // Check the value
+
+        Assumption unmodifiedAssumption;
+        RubyMethod method;
+
+        if ((boolean) receiverObject) {
+            unmodifiedAssumption = trueUnmodifiedAssumption;
+            method = trueMethod;
+        } else {
+            unmodifiedAssumption = falseUnmodifiedAssumption;
+            method = falseMethod;
+        }
+
+        // Check the class has not been modified
+
+        try {
+            unmodifiedAssumption.check();
+        } catch (InvalidAssumptionException e) {
+            return respecialize("class modified", frame, receiverObject, blockObject, argumentsObjects);
+        }
+
+        // Call the method
+
+        return method.call(frame.pack(), receiverObject, blockObject, argumentsObjects);
+    }
+
+    @Override
+    public void setNext(UnboxedDispatchNode next) {
+        this.next = adoptChild(next);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/BoxedDispatchNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.call;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * A node in the dispatch chain that expects the receiver to be an object boxed into a full
+ * {@link RubyBasicObject}.
+ */
+public abstract class BoxedDispatchNode extends DispatchNode {
+
+    public BoxedDispatchNode(RubyContext context, SourceSection sourceSection) {
+        super(context, sourceSection);
+    }
+
+    public abstract Object dispatch(VirtualFrame frame, RubyBasicObject receiverObject, RubyProc blockObject, Object[] argumentsObjects);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/BoxingDispatchNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.call;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.utilities.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * A node in the dispatch chain that boxes the receiver into a full Ruby {@link RubyBasicObject}.
+ * This node is initially created as an {@link UninitializedBoxingDispatchNode} and only becomes
+ * this node when we know that we do need to box on the fast path. Within this node we specialized
+ * for the case that the receiver is always already boxed.
+ */
+public class BoxingDispatchNode extends UnboxedDispatchNode {
+
+    @Child protected BoxedDispatchNode next;
+
+    private final BranchProfile boxBranch = new BranchProfile();
+
+    public BoxingDispatchNode(RubyContext context, SourceSection sourceSection, BoxedDispatchNode next) {
+        super(context, sourceSection);
+
+        this.next = adoptChild(next);
+    }
+
+    @Override
+    public Object dispatch(VirtualFrame frame, Object receiverObject, RubyProc blockObject, Object[] argumentsObjects) {
+        RubyBasicObject boxedReceiverObject;
+
+        if (receiverObject instanceof RubyBasicObject) {
+            boxedReceiverObject = (RubyBasicObject) receiverObject;
+        } else {
+            boxBranch.enter();
+            boxedReceiverObject = getContext().getCoreLibrary().box(receiverObject);
+        }
+
+        return next.dispatch(frame, boxedReceiverObject, blockObject, argumentsObjects);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/CachedBoxedDispatchNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.call;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.lookup.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * A node in the dispatch chain that comes after the boxing point and caches a method on a full
+ * boxed Ruby BasicObject, matching it by looking at the lookup node and assuming it has not been
+ * modified.
+ */
+public class CachedBoxedDispatchNode extends BoxedDispatchNode {
+
+    private final LookupNode expectedLookupNode;
+    private final Assumption unmodifiedAssumption;
+    private final RubyMethod method;
+
+    @Child protected BoxedDispatchNode next;
+
+    public CachedBoxedDispatchNode(RubyContext context, SourceSection sourceSection, LookupNode expectedLookupNode, RubyMethod method, BoxedDispatchNode next) {
+        super(context, sourceSection);
+
+        assert expectedLookupNode != null;
+        assert method != null;
+
+        this.expectedLookupNode = expectedLookupNode;
+        unmodifiedAssumption = expectedLookupNode.getUnmodifiedAssumption();
+        this.method = method;
+        this.next = adoptChild(next);
+    }
+
+    @Override
+    public Object dispatch(VirtualFrame frame, RubyBasicObject receiverObject, RubyProc blockObject, Object[] argumentsObjects) {
+        // Check the lookup node is what we expect
+
+        if (receiverObject.getLookupNode() != expectedLookupNode) {
+            return next.dispatch(frame, receiverObject, blockObject, argumentsObjects);
+        }
+
+        // Check the class has not been modified
+
+        try {
+            unmodifiedAssumption.check();
+        } catch (InvalidAssumptionException e) {
+            return respecialize("class modified", frame, receiverObject, blockObject, argumentsObjects);
+        }
+
+        // Call the method
+
+        return method.call(frame.pack(), receiverObject, blockObject, argumentsObjects);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/CachedUnboxedDispatchNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.call;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+
+/**
+ * A node in the dispatch chain that comes before the boxing point and caches a method on a Java
+ * object, matching it by looking at the class and assuming it has not been modified.
+ */
+public class CachedUnboxedDispatchNode extends UnboxedDispatchNode {
+
+    private final Class expectedClass;
+    private final Assumption unmodifiedAssumption;
+    private final RubyMethod method;
+
+    @Child protected UnboxedDispatchNode next;
+
+    public CachedUnboxedDispatchNode(RubyContext context, SourceSection sourceSection, Class expectedClass, Assumption unmodifiedAssumption, RubyMethod method, UnboxedDispatchNode next) {
+        super(context, sourceSection);
+
+        assert expectedClass != null;
+        assert unmodifiedAssumption != null;
+        assert method != null;
+
+        this.expectedClass = expectedClass;
+        this.unmodifiedAssumption = unmodifiedAssumption;
+        this.method = method;
+        this.next = adoptChild(next);
+    }
+
+    @Override
+    public Object dispatch(VirtualFrame frame, Object receiverObject, RubyProc blockObject, Object[] argumentsObjects) {
+        // Check the class is what we expect
+
+        if (receiverObject.getClass() != expectedClass) {
+            return next.dispatch(frame, receiverObject, blockObject, argumentsObjects);
+        }
+
+        // Check the class has not been modified
+
+        try {
+            unmodifiedAssumption.check();
+        } catch (InvalidAssumptionException e) {
+            return respecialize("class modified", frame, receiverObject, blockObject, argumentsObjects);
+        }
+
+        // Call the method
+
+        return method.call(frame.pack(), receiverObject, blockObject, argumentsObjects);
+    }
+
+    @Override
+    public void setNext(UnboxedDispatchNode next) {
+        this.next = adoptChild(next);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/CallNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.call;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * A call node that has a chain of dispatch nodes.
+ * <p>
+ * The dispatch chain starts as {@link CallNode} -&gt; {@link DispatchHeadNode} -&gt;
+ * {@link UninitializedBoxingDispatchNode} -&gt; {@link UninitializedDispatchNode}.
+ * <p>
+ * When the {@link UninitializedDispatchNode} is reached a new node is inserted into the chain. If
+ * the node dispatches based on some unboxed value (unboxed as in it's not a Ruby object, just a
+ * Java object) such as {@link Integer}, then that node is inserted before the
+ * {@link UninitializedBoxingDispatchNode}, otherwise if it dispatches based on some Ruby
+ * BasicObject, it is inserted afterwards.
+ * <p>
+ * The {@link UninitializedBoxingDispatchNode} becomes a {@link BoxingDispatchNode} when we find
+ * that the boxing has to be done on the fast path - when there is some boxed dispatch node.
+ * <p>
+ * So the general format is {@link CallNode} -&gt; {@link DispatchHeadNode} -&gt; zero or more
+ * unboxed dispatches -&gt; {@link UninitializedBoxingDispatchNode} | {@link BoxingDispatchNode}
+ * -&gt; zero or more boxed dispatches -&gt; {@link UninitializedDispatchNode}.
+ * <p>
+ * There are several special cases of unboxed and boxed dispatch nodes based on the types and
+ * methods involved.
+ * <p>
+ * If we have too many dispatch nodes we replace the whole chain with {@link DispatchHeadNode} -&gt;
+ * {@link BoxingDispatchNode} -&gt; {@link GeneralBoxedDispatchNode}.
+ * <p>
+ * This system allows us to dispatch based purely on Java class, before we have to turn the object
+ * into a full {@link RubyBasicObject} and consider the full Ruby lookup process, and something such
+ * as a math call which may work on Fixnum or Float to work as just a couple of applications of
+ * {@code instanceof} and assumption checks.
+ */
+public class CallNode extends RubyNode {
+
+    @Child protected RubyNode receiver;
+    @Child protected ProcOrNullNode block;
+    @Children protected final RubyNode[] arguments;
+
+    private final String name;
+    private final boolean isSplatted;
+
+    @Child protected DispatchHeadNode dispatchHead;
+
+    public CallNode(RubyContext context, SourceSection section, String name, RubyNode receiver, RubyNode block, boolean isSplatted, RubyNode[] arguments) {
+        super(context, section);
+
+        assert receiver != null;
+        assert arguments != null;
+        assert name != null;
+
+        this.receiver = adoptChild(receiver);
+
+        if (block == null) {
+            this.block = null;
+        } else {
+            this.block = adoptChild(ProcOrNullNodeFactory.create(context, section, block));
+        }
+
+        this.arguments = adoptChildren(arguments);
+        this.name = name;
+        this.isSplatted = isSplatted;
+
+        dispatchHead = adoptChild(adoptChild(new DispatchHeadNode(context, section, name, isSplatted)));
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        final Object receiverObject = receiver.execute(frame);
+        final Object[] argumentsObjects = executeArguments(frame);
+        final RubyProc blockObject = executeBlock(frame);
+
+        return dispatchHead.dispatch(frame, receiverObject, blockObject, argumentsObjects);
+    }
+
+    private RubyProc executeBlock(VirtualFrame frame) {
+        if (block != null) {
+            return block.executeRubyProc(frame);
+        } else {
+            return null;
+        }
+    }
+
+    @ExplodeLoop
+    private Object[] executeArguments(VirtualFrame frame) {
+        final Object[] argumentsObjects = new Object[arguments.length];
+
+        for (int i = 0; i < arguments.length; i++) {
+            argumentsObjects[i] = arguments[i].execute(frame);
+            assert RubyContext.shouldObjectBeVisible(argumentsObjects[i]) : argumentsObjects[i].getClass();
+        }
+
+        if (isSplatted) {
+            assert argumentsObjects[0] instanceof RubyArray;
+            return ((RubyArray) argumentsObjects[0]).toObjectArray();
+        } else {
+            return argumentsObjects;
+        }
+    }
+
+    @Override
+    public Object isDefined(VirtualFrame frame) {
+        final RubyContext context = getContext();
+
+        Object receiverObject;
+
+        try {
+            /*
+             * TODO(CS): Getting a node via an accessor like this doesn't work with Truffle at the
+             * moment and will cause frame escape errors, so we don't use it in compilation mode.
+             */
+
+            CompilerAsserts.neverPartOfCompilation();
+
+            receiverObject = receiver.execute(frame);
+        } catch (Exception e) {
+            return NilPlaceholder.INSTANCE;
+        }
+
+        final RubyBasicObject receiverBasicObject = context.getCoreLibrary().box(receiverObject);
+
+        final RubyMethod method = receiverBasicObject.getLookupNode().lookupMethod(name);
+
+        final RubyBasicObject self = context.getCoreLibrary().box(frame.getArguments(RubyArguments.class).getSelf());
+
+        if (method == null || method.isUndefined()) {
+            return NilPlaceholder.INSTANCE;
+        }
+
+        if (!method.isVisibleTo(self)) {
+            return NilPlaceholder.INSTANCE;
+        }
+
+        return context.makeString("method");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/DispatchHeadNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.call;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * The head of a chain of dispatch nodes. Can be used with {@link CallNode} or on its own.
+ */
+public class DispatchHeadNode extends DispatchNode {
+
+    private final RubyContext context;
+    private final String name;
+    private final boolean isSplatted;
+
+    @Child protected UnboxedDispatchNode dispatch;
+
+    public DispatchHeadNode(RubyContext context, SourceSection sourceSection, String name, boolean isSplatted) {
+        super(context, sourceSection);
+
+        assert context != null;
+        assert name != null;
+
+        this.context = context;
+        this.name = name;
+        this.isSplatted = isSplatted;
+
+        final UninitializedDispatchNode uninitializedDispatch = new UninitializedDispatchNode(context, sourceSection, name);
+        dispatch = adoptChild(new UninitializedBoxingDispatchNode(context, sourceSection, uninitializedDispatch));
+    }
+
+    public Object dispatch(VirtualFrame frame, Object receiverObject, RubyProc blockObject, Object... argumentsObjects) {
+        return dispatch.dispatch(frame, receiverObject, blockObject, argumentsObjects);
+    }
+
+    /**
+     * Replace the entire dispatch chain with a fresh chain. Used when the situation has changed in
+     * such a significant way that it's best to start again rather than add new specializations to
+     * the chain. Used for example when methods appear to have been monkey-patched.
+     */
+    public Object respecialize(VirtualFrame frame, String reason, Object receiverObject, RubyProc blockObject, Object... argumentObjects) {
+        CompilerAsserts.neverPartOfCompilation();
+
+        replace(new DispatchHeadNode(context, getSourceSection(), name, isSplatted), reason);
+
+        final RubyBasicObject receiverBasicObject = context.getCoreLibrary().box(receiverObject);
+
+        final RubyMethod method = lookup(frame, receiverBasicObject, name);
+        return method.call(frame.pack(), receiverBasicObject, blockObject, argumentObjects);
+    }
+
+    public UnboxedDispatchNode getDispatch() {
+        return dispatch;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/DispatchNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.call;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Any node in the dispatch chain.
+ */
+public class DispatchNode extends Node {
+
+    private final RubyContext context;
+
+    public DispatchNode(RubyContext context, SourceSection sourceSection) {
+        super(sourceSection);
+
+        assert context != null;
+        assert sourceSection != null;
+
+        this.context = context;
+    }
+
+    /**
+     * Get the depth of this node in the dispatch chain. The first node below
+     * {@link DispatchHeadNode} is at depth 1.
+     */
+    public int getDepth() {
+        int depth = 1;
+        Node parent = this.getParent();
+
+        while (!(parent instanceof DispatchHeadNode)) {
+            parent = parent.getParent();
+            depth++;
+        }
+
+        return depth;
+    }
+
+    public Object respecialize(String reason, VirtualFrame frame, Object receiverObject, RubyProc blockObject, Object... argumentsObjects) {
+        CompilerAsserts.neverPartOfCompilation();
+
+        final int depth = getDepth();
+        final DispatchHeadNode head = (DispatchHeadNode) NodeUtil.getNthParent(this, depth);
+
+        return head.respecialize(frame, reason, receiverObject, blockObject, argumentsObjects);
+    }
+
+    /**
+     * The central point for method lookup.
+     */
+    protected RubyMethod lookup(VirtualFrame frame, RubyBasicObject receiverBasicObject, String name) {
+        final RubyMethod method = receiverBasicObject.getLookupNode().lookupMethod(name);
+
+        final RubyBasicObject self = context.getCoreLibrary().box(frame.getArguments(RubyArguments.class).getSelf());
+
+        if (method == null || method.isUndefined()) {
+            CompilerDirectives.transferToInterpreter();
+            throw new RaiseException(context.getCoreLibrary().nameErrorNoMethod(name, receiverBasicObject.toString()));
+        }
+
+        if (!method.isVisibleTo(self)) {
+            CompilerDirectives.transferToInterpreter();
+            throw new RaiseException(context.getCoreLibrary().noMethodError(name, receiverBasicObject.toString()));
+        }
+
+        return method;
+    }
+
+    public RubyContext getContext() {
+        return context;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/GeneralBoxedDispatchNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.call;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * A node in the dispatch chain that does no caching and looks up methods from scratch each time it
+ * is called.
+ */
+public class GeneralBoxedDispatchNode extends BoxedDispatchNode {
+
+    private final String name;
+
+    public GeneralBoxedDispatchNode(RubyContext context, SourceSection sourceSection, String name) {
+        super(context, sourceSection);
+
+        assert name != null;
+
+        this.name = name;
+    }
+
+    @Override
+    public Object dispatch(VirtualFrame frame, RubyBasicObject receiverObject, RubyProc blockObject, Object[] argumentsObjects) {
+        /*
+         * TODO(CS): we should probably have some kind of cache here - even if it's just a hash map.
+         * MRI and JRuby do and might avoid some pathological cases.
+         */
+
+        final RubyMethod method = lookup(frame, receiverObject, name);
+        return method.call(frame.pack(), receiverObject, blockObject, argumentsObjects);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/GeneralSuperCallNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.call;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Represents a super call - that is a call with self as the receiver, but the superclass of self
+ * used for lookup. Currently implemented without any caching, and needs to be replaced with the
+ * same caching mechanism as for normal calls without complicating the existing calls too much.
+ */
+@NodeInfo(shortName = "general-super-call")
+public class GeneralSuperCallNode extends RubyNode {
+
+    private final String name;
+    private final boolean isSplatted;
+    @Child protected RubyNode block;
+    @Children protected final RubyNode[] arguments;
+
+    public GeneralSuperCallNode(RubyContext context, SourceSection sourceSection, String name, RubyNode block, RubyNode[] arguments, boolean isSplatted) {
+        super(context, sourceSection);
+
+        assert name != null;
+        assert arguments != null;
+        assert !isSplatted || arguments.length == 1;
+
+        this.name = name;
+        this.block = adoptChild(block);
+        this.arguments = adoptChildren(arguments);
+        this.isSplatted = isSplatted;
+    }
+
+    @ExplodeLoop
+    @Override
+    public final Object execute(VirtualFrame frame) {
+        // This method is only a simple implementation - it needs proper caching
+
+        CompilerAsserts.neverPartOfCompilation();
+
+        final RubyBasicObject self = (RubyBasicObject) frame.getArguments(RubyArguments.class).getSelf();
+
+        // Execute the arguments
+
+        final Object[] argumentsObjects = new Object[arguments.length];
+
+        CompilerAsserts.compilationConstant(arguments.length);
+        for (int i = 0; i < arguments.length; i++) {
+            argumentsObjects[i] = arguments[i].execute(frame);
+        }
+
+        // Execute the block
+
+        RubyProc blockObject;
+
+        if (block != null) {
+            final Object blockTempObject = block.execute(frame);
+
+            if (blockTempObject instanceof NilPlaceholder) {
+                blockObject = null;
+            } else {
+                blockObject = (RubyProc) blockTempObject;
+            }
+        } else {
+            blockObject = null;
+        }
+
+        // Lookup method
+
+        final RubyClass selfClass = self.getRubyClass();
+        final RubyMethod method = selfClass.getSuperclass().lookupMethod(name);
+
+        if (method == null || method.isUndefined()) {
+            CompilerDirectives.transferToInterpreter();
+            throw new RaiseException(getContext().getCoreLibrary().nameErrorNoMethod(name, self.toString()));
+        }
+
+        if (!method.isVisibleTo(self)) {
+            CompilerDirectives.transferToInterpreter();
+            throw new RaiseException(getContext().getCoreLibrary().noMethodError("(unknown)"));
+        }
+
+        // Call the method
+
+        if (isSplatted) {
+            final RubyArray argumentsArray = (RubyArray) argumentsObjects[0];
+            return method.call(frame.pack(), self, blockObject, argumentsArray.asList().toArray());
+        } else {
+            return method.call(frame.pack(), self, blockObject, argumentsObjects);
+        }
+    }
+
+    @Override
+    public Object isDefined(VirtualFrame frame) {
+        final RubyContext context = getContext();
+
+        try {
+            final RubyBasicObject self = context.getCoreLibrary().box(frame.getArguments(RubyArguments.class).getSelf());
+            final RubyBasicObject receiverRubyObject = context.getCoreLibrary().box(self);
+
+            final RubyMethod method = receiverRubyObject.getRubyClass().getSuperclass().lookupMethod(name);
+
+            if (method == null || method.isUndefined() || !method.isVisibleTo(self)) {
+                return NilPlaceholder.INSTANCE;
+            } else {
+                return context.makeString("super");
+            }
+        } catch (Exception e) {
+            return NilPlaceholder.INSTANCE;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/InlineHeuristic.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.call;
+
+import com.oracle.truffle.ruby.nodes.*;
+
+public class InlineHeuristic {
+
+    public static boolean shouldInline(InlinableMethodImplementation method) {
+        if (method.alwaysInline()) {
+            return true;
+        }
+
+        return false;
+    }
+
+    public static boolean shouldInlineYield(@SuppressWarnings("unused") InlinableMethodImplementation method) {
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/InlinedBoxedDispatchNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.call;
+
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.lookup.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * A node in the dispatch chain that comes after the boxing point and caches a method on a full
+ * boxed {@link RubyBasicObject}, matching it by looking at the lookup node and assuming it has not
+ * been modified.
+ */
+public class InlinedBoxedDispatchNode extends BoxedDispatchNode {
+
+    private final LookupNode expectedLookupNode;
+    private final Assumption unmodifiedAssumption;
+
+    private final InlinableMethodImplementation method;
+    private final RubyRootNode rootNode;
+
+    @Child protected BoxedDispatchNode next;
+
+    public InlinedBoxedDispatchNode(RubyContext context, SourceSection sourceSection, LookupNode expectedLookupNode, InlinableMethodImplementation method, BoxedDispatchNode next) {
+        super(context, sourceSection);
+
+        assert expectedLookupNode != null;
+        assert method != null;
+
+        this.expectedLookupNode = expectedLookupNode;
+        unmodifiedAssumption = expectedLookupNode.getUnmodifiedAssumption();
+        this.method = method;
+        this.rootNode = method.getCloneOfPristineRootNode();
+        this.next = adoptChild(next);
+    }
+
+    @Override
+    public Object dispatch(VirtualFrame frame, RubyBasicObject receiverObject, RubyProc blockObject, Object[] argumentsObjects) {
+        // Check the lookup node is what we expect
+
+        if (receiverObject.getLookupNode() != expectedLookupNode) {
+            return next.dispatch(frame, receiverObject, blockObject, argumentsObjects);
+        }
+
+        // Check the class has not been modified
+
+        try {
+            unmodifiedAssumption.check();
+        } catch (InvalidAssumptionException e) {
+            return respecialize("class modified", frame, receiverObject, blockObject, argumentsObjects);
+        }
+
+        // Call the method
+
+        Object[] modifiedArgumentsObjects;
+
+        CompilerAsserts.compilationConstant(method.getShouldAppendCallNode());
+
+        if (method.getShouldAppendCallNode()) {
+            modifiedArgumentsObjects = Arrays.copyOf(argumentsObjects, argumentsObjects.length + 1);
+            modifiedArgumentsObjects[modifiedArgumentsObjects.length - 1] = this;
+        } else {
+            modifiedArgumentsObjects = argumentsObjects;
+        }
+
+        final RubyArguments arguments = new RubyArguments(method.getDeclarationFrame(), receiverObject, blockObject, modifiedArgumentsObjects);
+        final VirtualFrame inlinedFrame = Truffle.getRuntime().createVirtualFrame(frame.pack(), arguments, method.getFrameDescriptor());
+        return rootNode.execute(inlinedFrame);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/InlinedUnboxedDispatchNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.call;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+public class InlinedUnboxedDispatchNode extends UnboxedDispatchNode {
+
+    private final Class expectedClass;
+    private final Assumption unmodifiedAssumption;
+
+    private final InlinableMethodImplementation method;
+    private final RubyRootNode rootNode;
+
+    @Child protected UnboxedDispatchNode next;
+
+    public InlinedUnboxedDispatchNode(RubyContext context, SourceSection sourceSection, Class expectedClass, Assumption unmodifiedAssumption, InlinableMethodImplementation method,
+                    UnboxedDispatchNode next) {
+        super(context, sourceSection);
+
+        assert expectedClass != null;
+        assert method != null;
+
+        this.expectedClass = expectedClass;
+        this.unmodifiedAssumption = unmodifiedAssumption;
+        this.method = method;
+        this.rootNode = method.getCloneOfPristineRootNode();
+        this.next = adoptChild(next);
+    }
+
+    @Override
+    public Object dispatch(VirtualFrame frame, Object receiverObject, RubyProc blockObject, Object[] argumentsObjects) {
+        // Check the class is what we expect
+
+        if (receiverObject.getClass() != expectedClass) {
+            return next.dispatch(frame, receiverObject, blockObject, argumentsObjects);
+        }
+
+        // Check the class has not been modified
+
+        try {
+            unmodifiedAssumption.check();
+        } catch (InvalidAssumptionException e) {
+            return respecialize("class modified", frame, receiverObject, blockObject, argumentsObjects);
+        }
+
+        // Call the method
+
+        final RubyArguments arguments = new RubyArguments(method.getDeclarationFrame(), receiverObject, blockObject, argumentsObjects);
+        final VirtualFrame inlinedFrame = Truffle.getRuntime().createVirtualFrame(frame.pack(), arguments, method.getFrameDescriptor());
+        return rootNode.execute(inlinedFrame);
+    }
+
+    @Override
+    public void setNext(UnboxedDispatchNode next) {
+        this.next = adoptChild(next);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/ProcOrNullNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.call;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+/**
+ * Wraps some node that will produce either a {@link RubyProc} or a {@link NilPlaceholder} and
+ * returns {@code null} in case of the latter. Used in parts of the dispatch chain.
+ */
+@NodeInfo(shortName = "proc-or-null")
+@NodeChild(value = "child", type = RubyNode.class)
+public abstract class ProcOrNullNode extends RubyNode {
+
+    public ProcOrNullNode(RubyContext context, SourceSection sourceSection) {
+        super(context, sourceSection);
+    }
+
+    public ProcOrNullNode(ProcOrNullNode prev) {
+        super(prev);
+    }
+
+    @Specialization
+    public Object doNil(@SuppressWarnings("unused") NilPlaceholder nil) {
+        return null;
+    }
+
+    @Specialization
+    public Object doProc(RubyProc proc) {
+        return proc;
+    }
+
+    @Override
+    public RubyProc executeRubyProc(VirtualFrame frame) {
+        final Object proc = execute(frame);
+
+        // The standard asRubyProc test doesn't allow for null
+        assert proc == null || RubyTypesGen.RUBYTYPES.isRubyProc(proc);
+
+        return (RubyProc) proc;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/UnboxedDispatchNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.call;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * A node in the dispatch chain that expects the receiver to be a simple Java object such as a boxed
+ * primitive, rather than a full {@link RubyBasicObject}. This allows calls to be made with a
+ * receiver such as {@link Integer} without having to turn it into a {@link RubyFixnum}. Followed at
+ * some point by an {@link UninitializedBoxingDispatchNode} or {@link BoxingDispatchNode} before we
+ * try to dispatch on a Ruby BasicObject or the {@link UninitializedDispatchNode}.
+ */
+public abstract class UnboxedDispatchNode extends DispatchNode {
+
+    public UnboxedDispatchNode(RubyContext context, SourceSection sourceSection) {
+        super(context, sourceSection);
+    }
+
+    public abstract Object dispatch(VirtualFrame frame, Object receiverObject, RubyProc blockObject, Object[] argumentsObjects);
+
+    public void setNext(@SuppressWarnings("unused") UnboxedDispatchNode next) {
+        throw new UnsupportedOperationException();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/UninitializedBoxingDispatchNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.call;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+/**
+ * A node in the dispatch chain that transfers to interpreter and then boxes the receiver.
+ */
+public class UninitializedBoxingDispatchNode extends UnboxedDispatchNode {
+
+    @Child protected BoxedDispatchNode next;
+
+    public UninitializedBoxingDispatchNode(RubyContext context, SourceSection sourceSection, BoxedDispatchNode next) {
+        super(context, sourceSection);
+
+        this.next = adoptChild(next);
+    }
+
+    @Override
+    public Object dispatch(VirtualFrame frame, Object receiverObject, RubyProc blockObject, Object[] argumentsObjects) {
+        CompilerDirectives.transferToInterpreter();
+
+        /*
+         * If the next dispatch node is something other than the uninitialized dispatch node then we
+         * need to replace this node because it's now on the fast path. If the receiver was already
+         * boxed.
+         * 
+         * Note that with this scheme it will take a couple of calls for the chain to become fully
+         * specialized.
+         */
+
+        if (next instanceof UninitializedDispatchNode) {
+            this.replace(new BoxingDispatchNode(getContext(), getSourceSection(), next));
+        }
+
+        return next.dispatch(frame, getContext().getCoreLibrary().box(receiverObject), blockObject, argumentsObjects);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/call/UninitializedDispatchNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.call;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * The uninitialized dispatch node. Only reached when the method is not expected by any node in the
+ * dispatch chain, and only creates new nodes or modifies the existing chain.
+ */
+public class UninitializedDispatchNode extends BoxedDispatchNode {
+
+    /*
+     * Node at depth 5 is 4 actual dispatches, the boxing dispatch and the final uninitalized
+     * dispatch.
+     */
+
+    private static final int MAX_DEPTH = 5;
+
+    private final String name;
+
+    public UninitializedDispatchNode(RubyContext context, SourceSection sourceSection, String name) {
+        super(context, sourceSection);
+
+        assert name != null;
+
+        this.name = name;
+    }
+
+    @Override
+    public Object dispatch(VirtualFrame frame, RubyBasicObject receiverObject, RubyProc blockObject, Object[] argumentsObjects) {
+        CompilerDirectives.transferToInterpreter();
+
+        final RubyContext context = getContext();
+
+        final RubyMethod method = lookup(frame, receiverObject, name);
+
+        final int depth = getDepth();
+
+        final DispatchHeadNode dispatchHead = (DispatchHeadNode) NodeUtil.getNthParent(this, depth);
+
+        if (depth == MAX_DEPTH) {
+            /*
+             * Replace the chain with DispatchHeadNode -> ExpectBoxedDispatchNode ->
+             * GeneralDispatchNode.
+             */
+
+            context.implementationMessage("resorting to a general call node at %s", getSourceSection());
+            NodeUtil.printTree(System.err, dispatchHead);
+
+            final GeneralBoxedDispatchNode newGeneralDispatch = new GeneralBoxedDispatchNode(getContext(), getSourceSection(), name);
+            final BoxingDispatchNode newBoxing = new BoxingDispatchNode(getContext(), getSourceSection(), newGeneralDispatch);
+
+            dispatchHead.getDispatch().replace(newBoxing);
+            return newBoxing.dispatch(frame, receiverObject, blockObject, argumentsObjects);
+        } else if (receiverObject instanceof Unboxable) {
+            /*
+             * Unboxed dispatch nodes are prepended to the chain of dispatch nodes, so they're
+             * before the point where receivers will definitely be boxed.
+             */
+
+            final Object receiverUnboxed = ((Unboxable) receiverObject).unbox();
+
+            final UnboxedDispatchNode firstDispatch = dispatchHead.getDispatch();
+
+            if (receiverObject instanceof RubyTrueClass || receiverObject instanceof RubyFalseClass) {
+                final Assumption falseUnmodifiedAssumption = context.getCoreLibrary().getFalseClass().getUnmodifiedAssumption();
+                final RubyMethod falseMethod = lookup(frame, context.getCoreLibrary().box(false), name);
+                final Assumption trueUnmodifiedAssumption = context.getCoreLibrary().getTrueClass().getUnmodifiedAssumption();
+                final RubyMethod trueMethod = lookup(frame, context.getCoreLibrary().box(true), name);
+
+                final BooleanDispatchNode newDispatch = new BooleanDispatchNode(getContext(), getSourceSection(), falseUnmodifiedAssumption, falseMethod, trueUnmodifiedAssumption, trueMethod, null);
+                firstDispatch.replace(newDispatch, "prepending new unboxed dispatch node to chain");
+                newDispatch.setNext(firstDispatch);
+                return newDispatch.dispatch(frame, receiverUnboxed, blockObject, argumentsObjects);
+            } else {
+                UnboxedDispatchNode newDispatch;
+
+                if (method.getImplementation() instanceof InlinableMethodImplementation && InlineHeuristic.shouldInline((InlinableMethodImplementation) method.getImplementation())) {
+                    newDispatch = new InlinedUnboxedDispatchNode(getContext(), getSourceSection(), receiverUnboxed.getClass(), receiverObject.getRubyClass().getUnmodifiedAssumption(),
+                                    (InlinableMethodImplementation) method.getImplementation(), null);
+                } else {
+                    newDispatch = new CachedUnboxedDispatchNode(getContext(), getSourceSection(), receiverUnboxed.getClass(), receiverObject.getRubyClass().getUnmodifiedAssumption(), method, null);
+                }
+
+                firstDispatch.replace(newDispatch, "prepending new unboxed dispatch node to chain");
+                newDispatch.setNext(firstDispatch);
+
+                return newDispatch.dispatch(frame, receiverUnboxed, blockObject, argumentsObjects);
+            }
+        } else {
+            /*
+             * Boxed dispatch nodes are appended to the chain of dispatch nodes, so they're after
+             * the point where receivers are guaranteed to be boxed.
+             */
+
+            final UninitializedDispatchNode newUninitializedDispatch = new UninitializedDispatchNode(getContext(), getSourceSection(), name);
+
+            BoxedDispatchNode newDispatch;
+
+            if (method.getImplementation() instanceof InlinableMethodImplementation && InlineHeuristic.shouldInline((InlinableMethodImplementation) method.getImplementation())) {
+                newDispatch = new InlinedBoxedDispatchNode(getContext(), getSourceSection(), receiverObject.getLookupNode(), (InlinableMethodImplementation) method.getImplementation(),
+                                newUninitializedDispatch);
+            } else {
+                newDispatch = new CachedBoxedDispatchNode(getContext(), getSourceSection(), receiverObject.getLookupNode(), method, newUninitializedDispatch);
+            }
+
+            replace(newDispatch, "appending new boxed dispatch node to chain");
+
+            return newDispatch.dispatch(frame, receiverObject, blockObject, argumentsObjects);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/cast/BooleanCastNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.cast;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+/**
+ * Casts a value into a boolean. Works at the language level, so doesn't call any Ruby methods to
+ * cast non-core or monkey-patched objects.
+ */
+@NodeInfo(shortName = "cast-boolean")
+@NodeChild(value = "child", type = RubyNode.class)
+public abstract class BooleanCastNode extends RubyNode {
+
+    public BooleanCastNode(RubyContext context, SourceSection sourceSection) {
+        super(context, sourceSection);
+    }
+
+    public BooleanCastNode(BooleanCastNode copy) {
+        super(copy.getContext(), copy.getSourceSection());
+    }
+
+    @Specialization
+    public boolean doBoolean(boolean value) {
+        return value;
+    }
+
+    @Specialization
+    public boolean doNil(@SuppressWarnings("unused") NilPlaceholder nil) {
+        return false;
+    }
+
+    @Generic
+    public boolean doGeneric(Object object) {
+        if (object instanceof Boolean) {
+            return (boolean) object;
+        } else if (object instanceof NilPlaceholder || object instanceof RubyNilClass) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    @Override
+    public abstract boolean executeBoolean(VirtualFrame frame);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/cast/LambdaNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.cast;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+
+@NodeInfo(shortName = "lambda")
+public class LambdaNode extends RubyNode {
+
+    @Child private RubyNode definition;
+
+    public LambdaNode(RubyContext context, SourceSection sourceSection, RubyNode definition) {
+        super(context, sourceSection);
+        this.definition = adoptChild(definition);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        return new RubyProc(getContext().getCoreLibrary().getProcClass(), RubyProc.Type.LAMBDA, frame.getArguments(RubyArguments.class).getSelf(), null, (RubyMethod) definition.execute(frame));
+    }
+
+    @Override
+    public void executeVoid(VirtualFrame frame) {
+        definition.executeVoid(frame);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/cast/ProcCastNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.cast;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.nodes.call.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Casts an object to a Ruby Proc object.
+ */
+@NodeInfo(shortName = "cast-proc")
+@NodeChild("child")
+public abstract class ProcCastNode extends RubyNode {
+
+    @Child protected DispatchHeadNode toProc;
+
+    public ProcCastNode(RubyContext context, SourceSection sourceSection) {
+        super(context, sourceSection);
+        toProc = adoptChild(new DispatchHeadNode(context, getSourceSection(), "to_proc", false));
+    }
+
+    public ProcCastNode(ProcCastNode prev) {
+        super(prev);
+        toProc = adoptChild(prev.toProc);
+    }
+
+    @Specialization
+    public NilPlaceholder doNil(NilPlaceholder nil) {
+        return nil;
+    }
+
+    @Specialization
+    public RubyProc doRubyProc(RubyProc proc) {
+        return proc;
+    }
+
+    @Specialization
+    public RubyProc doObject(VirtualFrame frame, RubyBasicObject object) {
+        return (RubyProc) toProc.dispatch(frame, object, null);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/cast/SplatCastNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.cast;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+/**
+ * Splat as used to cast a value to an array if it isn't already, as in {@code *value}.
+ */
+@NodeInfo(shortName = "cast-splat")
+@NodeChild("child")
+public abstract class SplatCastNode extends RubyNode {
+
+    public SplatCastNode(RubyContext context, SourceSection sourceSection) {
+        super(context, sourceSection);
+    }
+
+    public SplatCastNode(SplatCastNode prev) {
+        super(prev);
+    }
+
+    protected abstract RubyNode getChild();
+
+    @Specialization
+    public RubyArray doArray(RubyArray array) {
+        return array;
+    }
+
+    @Specialization
+    public RubyArray doObject(Object object) {
+        if (object instanceof RubyArray) {
+            return (RubyArray) object;
+        } else {
+            return RubyArray.specializedFromObject(getContext().getCoreLibrary().getArrayClass(), object);
+        }
+    }
+
+    @Override
+    public void executeVoid(VirtualFrame frame) {
+        getChild().executeVoid(frame);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/cast/StringToRegexpNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.cast;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+/**
+ * Creates a regex from a string.
+ */
+@NodeInfo(shortName = "cast-string-to-regexp")
+@NodeChild("string")
+public abstract class StringToRegexpNode extends RubyNode {
+
+    public StringToRegexpNode(RubyContext context, SourceSection sourceSection) {
+        super(context, sourceSection);
+    }
+
+    public StringToRegexpNode(StringToRegexpNode prev) {
+        super(prev);
+    }
+
+    @Specialization
+    public RubyRegexp doString(RubyString string) {
+        return new RubyRegexp(getContext().getCoreLibrary().getRegexpClass(), string.toString());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/cast/StringToSymbolNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.cast;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+/**
+ * Creates a symbol from a string.
+ */
+@NodeInfo(shortName = "cast-string-to-symbol")
+@NodeChild("string")
+public abstract class StringToSymbolNode extends RubyNode {
+
+    public StringToSymbolNode(RubyContext context, SourceSection sourceSection) {
+        super(context, sourceSection);
+    }
+
+    public StringToSymbolNode(StringToSymbolNode prev) {
+        super(prev);
+    }
+
+    @Specialization
+    public RubySymbol doString(RubyString string) {
+        return new RubySymbol(getContext().getCoreLibrary().getSymbolClass(), string.toString());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/constants/CachedReadConstantNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.constants;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.utilities.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Represents a constant read from some object and cached, with the assumption that the object it
+ * was read from is unmodified. If that assumption does not hold the read is uninitialized. If the
+ * class of the receiver changes we also uninitialize.
+ */
+@NodeInfo(shortName = "cached-read-constant")
+public class CachedReadConstantNode extends ReadConstantNode {
+
+    private final RubyClass expectedClass;
+    private final Assumption unmodifiedAssumption;
+
+    private final Object value;
+
+    private final boolean hasBoolean;
+    private final boolean booleanValue;
+
+    private final boolean hasInt;
+    private final int intValue;
+
+    private final boolean hasDouble;
+    private final double doubleValue;
+
+    private final BranchProfile boxBranchProfile = new BranchProfile();
+
+    public CachedReadConstantNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver, RubyClass expectedClass, Object value) {
+        super(context, sourceSection, name, receiver);
+
+        this.expectedClass = expectedClass;
+        unmodifiedAssumption = expectedClass.getUnmodifiedAssumption();
+
+        this.value = value;
+
+        /*
+         * We could do this lazily as needed, but I'm sure the compiler will appreciate the fact
+         * that these fields are all final.
+         */
+
+        if (value instanceof Boolean) {
+            hasBoolean = true;
+            booleanValue = (boolean) value;
+
+            hasInt = false;
+            intValue = -1;
+
+            hasDouble = false;
+            doubleValue = -1;
+        } else if (value instanceof Integer) {
+            hasBoolean = false;
+            booleanValue = false;
+
+            hasInt = true;
+            intValue = (int) value;
+
+            hasDouble = true;
+            doubleValue = (int) value;
+        } else if (value instanceof Double) {
+            hasBoolean = false;
+            booleanValue = false;
+
+            hasInt = false;
+            intValue = -1;
+
+            hasDouble = true;
+            doubleValue = (double) value;
+        } else {
+            hasBoolean = false;
+            booleanValue = false;
+
+            hasInt = false;
+            intValue = -1;
+
+            hasDouble = false;
+            doubleValue = -1;
+        }
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        try {
+            guard(frame);
+        } catch (UnexpectedResultException e) {
+            return e.getResult();
+        }
+
+        return value;
+    }
+
+    @Override
+    public boolean executeBoolean(VirtualFrame frame) throws UnexpectedResultException {
+        guard(frame);
+
+        if (hasBoolean) {
+            return booleanValue;
+        } else {
+            throw new UnexpectedResultException(value);
+        }
+    }
+
+    @Override
+    public int executeFixnum(VirtualFrame frame) throws UnexpectedResultException {
+        guard(frame);
+
+        if (hasInt) {
+            return intValue;
+        } else {
+            throw new UnexpectedResultException(value);
+        }
+    }
+
+    @Override
+    public double executeFloat(VirtualFrame frame) throws UnexpectedResultException {
+        guard(frame);
+
+        if (hasDouble) {
+            return doubleValue;
+        } else {
+            throw new UnexpectedResultException(value);
+        }
+    }
+
+    @Override
+    public void executeVoid(VirtualFrame frame) {
+    }
+
+    public void guard(VirtualFrame frame) throws UnexpectedResultException {
+        final RubyContext context = getContext();
+
+        final Object receiverObject = receiver.execute(frame);
+
+        RubyBasicObject receiverRubyObject;
+
+        // TODO(CS): put the boxing into a separate node that can specialize for each type it sees
+
+        if (receiverObject instanceof RubyBasicObject) {
+            receiverRubyObject = (RubyBasicObject) receiverObject;
+        } else {
+            boxBranchProfile.enter();
+            receiverRubyObject = context.getCoreLibrary().box(receiverObject);
+        }
+
+        if (receiverRubyObject.getRubyClass() != expectedClass) {
+            CompilerDirectives.transferToInterpreter();
+            throw new UnexpectedResultException(uninitialize(receiverRubyObject));
+        }
+
+        try {
+            unmodifiedAssumption.check();
+        } catch (InvalidAssumptionException e) {
+            throw new UnexpectedResultException(uninitialize(receiverRubyObject));
+        }
+    }
+
+    private Object uninitialize(RubyBasicObject receiverObject) {
+        return replace(new UninitializedReadConstantNode(getContext(), getSourceSection(), name, receiver)).execute(receiverObject);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/constants/ReadConstantNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.constants;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+
+public abstract class ReadConstantNode extends RubyNode {
+
+    protected final String name;
+    @Child protected RubyNode receiver;
+
+    public ReadConstantNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver) {
+        super(context, sourceSection);
+        this.name = name;
+        this.receiver = adoptChild(receiver);
+    }
+
+    @Override
+    public Object isDefined(VirtualFrame frame) {
+        final RubyContext context = getContext();
+
+        if (name.equals("Encoding")) {
+            /*
+             * Work-around so I don't have to load the iconv library - runners/formatters/junit.rb.
+             */
+            return context.makeString("constant");
+        }
+
+        Object value;
+
+        try {
+            value = context.getCoreLibrary().box(receiver.execute(frame)).getLookupNode().lookupConstant(name);
+        } catch (RaiseException e) {
+            /*
+             * If we are looking up a constant in a constant that is itself undefined, we return Nil
+             * rather than raising the error. Eg.. defined?(Defined::Undefined1::Undefined2)
+             */
+
+            if (e.getRubyException().getRubyClass() == context.getCoreLibrary().getNameErrorClass()) {
+                return NilPlaceholder.INSTANCE;
+            }
+
+            throw e;
+        }
+
+        if (value == null) {
+            return NilPlaceholder.INSTANCE;
+        } else {
+            return context.makeString("constant");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/constants/UninitializedReadConstantNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.constants;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Represents an uninitialized constant read from some object. After the first read it will be
+ * specialized to some other node. This is the starting point for all constant reads.
+ */
+@NodeInfo(shortName = "uninitialized-read-constant")
+public class UninitializedReadConstantNode extends ReadConstantNode {
+
+    public UninitializedReadConstantNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver) {
+        super(context, sourceSection, name, receiver);
+    }
+
+    /**
+     * This execute method allows us to pass in the already executed receiver object, so that during
+     * uninitialization it is not executed once by the specialized node and again by this node.
+     */
+    public Object execute(RubyBasicObject receiverObject) {
+        CompilerAsserts.neverPartOfCompilation();
+
+        final RubyContext context = receiverObject.getRubyClass().getContext();
+
+        Object value;
+
+        value = receiverObject.getLookupNode().lookupConstant(name);
+
+        if (value == null && receiverObject instanceof RubyModule) {
+            /*
+             * FIXME(CS): I'm obviously doing something wrong with constant lookup in nested modules
+             * here, but explicitly looking in the Module itself, not its lookup node, seems to fix
+             * it for now.
+             */
+
+            value = ((RubyModule) receiverObject).lookupConstant(name);
+        }
+
+        if (value == null) {
+            throw new RaiseException(context.getCoreLibrary().nameErrorUninitializedConstant(name));
+        }
+
+        replace(new CachedReadConstantNode(context, getSourceSection(), name, receiver, receiverObject.getRubyClass(), value));
+
+        assert RubyContext.shouldObjectBeVisible(value);
+
+        return value;
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        CompilerDirectives.transferToInterpreter();
+
+        final RubyContext context = getContext();
+
+        final Object receiverObject = receiver.execute(frame);
+        final RubyBasicObject receiverRubyObject = context.getCoreLibrary().box(receiverObject);
+
+        return execute(receiverRubyObject);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/constants/WriteConstantNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.constants;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+/**
+ * Represents writing a constant into some module.
+ */
+@NodeInfo(shortName = "write-constant")
+public class WriteConstantNode extends RubyNode {
+
+    private final String name;
+    @Child protected RubyNode module;
+    @Child protected RubyNode rhs;
+
+    public WriteConstantNode(RubyContext context, SourceSection sourceSection, String name, RubyNode module, RubyNode rhs) {
+        super(context, sourceSection);
+        this.name = name;
+        this.module = adoptChild(module);
+        this.rhs = adoptChild(rhs);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        // TODO(cs): can module ever not evaluate to a RubyModule?
+
+        final RubyModule moduleObject = (RubyModule) module.execute(frame);
+
+        final Object rhsValue = rhs.execute(frame);
+
+        assert rhsValue != null;
+        assert !(rhsValue instanceof String);
+
+        moduleObject.setModuleConstant(name, rhsValue);
+
+        return rhsValue;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/AndNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.control;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+/**
+ * Represents a Ruby {@code and} or {@code &&} expression.
+ */
+@NodeInfo(shortName = "and")
+@NodeChildren({@NodeChild("left"), @NodeChild("right")})
+public abstract class AndNode extends RubyNode {
+
+    public AndNode(RubyContext context, SourceSection sourceSection) {
+        super(context, sourceSection);
+    }
+
+    public AndNode(AndNode copy) {
+        super(copy.getContext(), copy.getSourceSection());
+    }
+
+    @ShortCircuit("right")
+    public boolean needsRightNode(Object a) {
+        return GeneralConversions.toBoolean(a);
+    }
+
+    @ShortCircuit("right")
+    public boolean needsRightNode(boolean a) {
+        return a;
+    }
+
+    @Specialization
+    public boolean doBoolean(boolean a, boolean hasB, boolean b) {
+        return hasB ? b : a;
+    }
+
+    @Specialization
+    public Object doObject(boolean a, boolean hasB, Object b) {
+        return hasB ? b : a;
+    }
+
+    @Generic
+    public Object doGeneric(Object a, boolean hasB, Object b) {
+        return hasB ? b : a;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/BreakNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.control;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+
+@NodeInfo(shortName = "break")
+public class BreakNode extends RubyNode {
+
+    @Child private RubyNode child;
+
+    public BreakNode(RubyContext context, SourceSection sourceSection, RubyNode child) {
+        super(context, sourceSection);
+        this.child = adoptChild(child);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        throw new BreakException(child.execute(frame));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/ElidableResultNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.control;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * This node has a pair of children - one required and one elidable result. The required node is
+ * always executed, but its result is discarded. Therefore it should perform some useful side
+ * effects. The elidable node is executed, and its result value returned, if an execute method with
+ * a non-void type is used. It is not executed at all if a void typed execute method is used.
+ * Therefore it should not perform any observable side effects.
+ */
+@NodeInfo(shortName = "elidable-result")
+public class ElidableResultNode extends RubyNode {
+
+    @Child protected RubyNode required;
+    @Child protected RubyNode elidableResult;
+
+    public ElidableResultNode(RubyContext context, SourceSection sourceSection, RubyNode required, RubyNode elidableResult) {
+        super(context, sourceSection);
+        this.required = adoptChild(required);
+        this.elidableResult = adoptChild(elidableResult);
+    }
+
+    @Override
+    public int executeFixnum(VirtualFrame frame) throws UnexpectedResultException {
+        required.executeVoid(frame);
+        return elidableResult.executeFixnum(frame);
+    }
+
+    @Override
+    public double executeFloat(VirtualFrame frame) throws UnexpectedResultException {
+        required.executeVoid(frame);
+        return elidableResult.executeFloat(frame);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        required.executeVoid(frame);
+        return elidableResult.execute(frame);
+    }
+
+    @Override
+    public void executeVoid(VirtualFrame frame) {
+        required.execute(frame);
+    }
+
+    @Override
+    public Object isDefined(VirtualFrame frame) {
+        return elidableResult.isDefined(frame);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/EnsureNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.control;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * Represents an ensure clause in exception handling. Represented separately to the try part.
+ */
+@NodeInfo(shortName = "ensure")
+public class EnsureNode extends RubyNode {
+
+    @Child protected RubyNode tryPart;
+    @Child protected RubyNode ensurePart;
+
+    public EnsureNode(RubyContext context, SourceSection sourceSection, RubyNode tryPart, RubyNode ensurePart) {
+        super(context, sourceSection);
+        this.tryPart = adoptChild(tryPart);
+        this.ensurePart = adoptChild(ensurePart);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        try {
+            return tryPart.execute(frame);
+        } finally {
+            ensurePart.executeVoid(frame);
+        }
+    }
+
+    @Override
+    public void executeVoid(VirtualFrame frame) {
+        try {
+            tryPart.executeVoid(frame);
+        } finally {
+            ensurePart.executeVoid(frame);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/FlipFlopNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.control;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.nodes.cast.*;
+import com.oracle.truffle.ruby.nodes.methods.locals.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+@NodeInfo(shortName = "flip-flop")
+public class FlipFlopNode extends RubyNode {
+
+    @Child protected BooleanCastNode begin;
+    @Child protected BooleanCastNode end;
+    @Child protected FlipFlopStateNode stateNode;
+
+    private final boolean exclusive;
+
+    public FlipFlopNode(RubyContext context, SourceSection sourceSection, BooleanCastNode begin, BooleanCastNode end, FlipFlopStateNode stateNode, boolean exclusive) {
+        super(context, sourceSection);
+        this.begin = adoptChild(begin);
+        this.end = adoptChild(end);
+        this.stateNode = adoptChild(stateNode);
+        this.exclusive = exclusive;
+    }
+
+    @Override
+    public boolean executeBoolean(VirtualFrame frame) {
+        if (exclusive) {
+            if (stateNode.getState(frame)) {
+                if (end.executeBoolean(frame)) {
+                    stateNode.setState(frame, false);
+                }
+
+                return true;
+            } else {
+                final boolean newState = begin.executeBoolean(frame);
+                stateNode.setState(frame, newState);
+                return newState;
+            }
+        } else {
+            if (stateNode.getState(frame)) {
+                if (end.executeBoolean(frame)) {
+                    stateNode.setState(frame, false);
+                }
+
+                return true;
+            } else {
+                if (begin.executeBoolean(frame)) {
+                    stateNode.setState(frame, !end.executeBoolean(frame));
+                    return true;
+                }
+
+                return false;
+            }
+        }
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        return executeBoolean(frame);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/IfNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.control;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.utilities.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.nodes.cast.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * Represents a Ruby {@code if} expression. Note that in this representation we always have an
+ * {@code else} part.
+ */
+@NodeInfo(shortName = "if")
+public class IfNode extends RubyNode {
+
+    @Child protected BooleanCastNode condition;
+    @Child protected RubyNode thenBody;
+    @Child protected RubyNode elseBody;
+
+    private final BranchProfile thenProfile = new BranchProfile();
+    private final BranchProfile elseProfile = new BranchProfile();
+
+    public IfNode(RubyContext context, SourceSection sourceSection, BooleanCastNode condition, RubyNode thenBody, RubyNode elseBody) {
+        super(context, sourceSection);
+        this.condition = adoptChild(condition);
+        this.thenBody = adoptChild(thenBody);
+        this.elseBody = adoptChild(elseBody);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        if (condition.executeBoolean(frame)) {
+            thenProfile.enter();
+            return thenBody.execute(frame);
+        } else {
+            elseProfile.enter();
+            return elseBody.execute(frame);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/NextNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.control;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+
+@NodeInfo(shortName = "next")
+public class NextNode extends RubyNode {
+
+    public NextNode(RubyContext context, SourceSection sourceSection) {
+        super(context, sourceSection);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        throw new NextException();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/NotNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.control;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.nodes.cast.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * Represents a Ruby {@code not} or {@code !} expression.
+ */
+@NodeInfo(shortName = "not")
+public class NotNode extends RubyNode {
+
+    @Child protected BooleanCastNode child;
+
+    public NotNode(RubyContext context, SourceSection sourceSection, BooleanCastNode child) {
+        super(context, sourceSection);
+        this.child = adoptChild(child);
+    }
+
+    @Override
+    public boolean executeBoolean(VirtualFrame frame) {
+        return !child.executeBoolean(frame);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        return executeBoolean(frame);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/OrNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.control;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+/**
+ * Represents a Ruby {@code or} or {@code ||} expression.
+ */
+@NodeInfo(shortName = "or")
+@NodeChildren({@NodeChild("left"), @NodeChild("right")})
+public abstract class OrNode extends RubyNode {
+
+    public OrNode(RubyContext context, SourceSection sourceSection) {
+        super(context, sourceSection);
+    }
+
+    public OrNode(OrNode copy) {
+        super(copy.getContext(), copy.getSourceSection());
+    }
+
+    @ShortCircuit("right")
+    public boolean needsRightNode(Object a) {
+        return !GeneralConversions.toBoolean(a);
+    }
+
+    @ShortCircuit("right")
+    public boolean needsRightNode(boolean a) {
+        return !a;
+    }
+
+    @Specialization
+    public Object doBoolean(boolean a, boolean hasB, Object b) {
+        return hasB ? b : a;
+    }
+
+    @Generic
+    public Object doGeneric(Object a, boolean hasB, Object b) {
+        return hasB ? b : a;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/RedoNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.control;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+
+@NodeInfo(shortName = "redo")
+public class RedoNode extends RubyNode {
+
+    public RedoNode(RubyContext context, SourceSection sourceSection) {
+        super(context, sourceSection);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        throw new RedoException();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/RescueAnyNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.control;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Rescues any exception.
+ */
+@NodeInfo(shortName = "rescue-any")
+public class RescueAnyNode extends RescueNode {
+
+    public RescueAnyNode(RubyContext context, SourceSection sourceSection, RubyNode body) {
+        super(context, sourceSection, body);
+    }
+
+    @Override
+    public boolean canHandle(VirtualFrame frame, RubyBasicObject exception) {
+        return true;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/RescueClassesNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.control;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Rescues any of a set of classes.
+ */
+@NodeInfo(shortName = "rescue-classes")
+public class RescueClassesNode extends RescueNode {
+
+    @Children final RubyNode[] handlingClassNodes;
+
+    public RescueClassesNode(RubyContext context, SourceSection sourceSection, RubyNode[] handlingClassNodes, RubyNode body) {
+        super(context, sourceSection, body);
+        this.handlingClassNodes = adoptChildren(handlingClassNodes);
+    }
+
+    @ExplodeLoop
+    @Override
+    public boolean canHandle(VirtualFrame frame, RubyBasicObject exception) {
+        final RubyClass exceptionRubyClass = exception.getRubyClass();
+
+        for (RubyNode handlingClassNode : handlingClassNodes) {
+            // TODO(CS): what if we don't get a class?
+
+            final RubyClass handlingClass = (RubyClass) handlingClassNode.execute(frame);
+
+            if (exceptionRubyClass.assignableTo(handlingClass)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/RescueNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.control;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Base node for all nodes which may be able to rescue an exception. They have a test method
+ * {@link #canHandle} and a body to execute if that test passes.
+ */
+public abstract class RescueNode extends RubyNode {
+
+    @Child protected RubyNode body;
+
+    public RescueNode(RubyContext context, SourceSection sourceSection, RubyNode body) {
+        super(context, sourceSection);
+        this.body = adoptChild(body);
+    }
+
+    public abstract boolean canHandle(VirtualFrame frame, RubyBasicObject exception);
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        return body.execute(frame);
+    }
+
+    @Override
+    public void executeVoid(VirtualFrame frame) {
+        body.executeVoid(frame);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/RescueSplatNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.control;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Rescue any of several classes, that we get from an expression that evaluates to an array of
+ * classes.
+ * 
+ */
+@NodeInfo(shortName = "rescue-splat")
+public class RescueSplatNode extends RescueNode {
+
+    @Child RubyNode handlingClassesArray;
+
+    public RescueSplatNode(RubyContext context, SourceSection sourceSection, RubyNode handlingClassesArray, RubyNode body) {
+        super(context, sourceSection, body);
+        this.handlingClassesArray = adoptChild(handlingClassesArray);
+    }
+
+    @ExplodeLoop
+    @Override
+    public boolean canHandle(VirtualFrame frame, RubyBasicObject exception) {
+        final RubyArray handlingClasses = (RubyArray) handlingClassesArray.execute(frame);
+
+        final RubyClass exceptionRubyClass = exception.getRubyClass();
+
+        for (Object handlingClass : handlingClasses.asList()) {
+            if (exceptionRubyClass.assignableTo((RubyClass) handlingClass)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/RetryNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.control;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+
+@NodeInfo(shortName = "retry")
+public class RetryNode extends RubyNode {
+
+    public RetryNode(RubyContext context, SourceSection sourceSection) {
+        super(context, sourceSection);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        throw new RetryException();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/ReturnNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.control;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+
+/**
+ * Represents an explicit return. The return ID indicates where we should be returning to - this can
+ * be non-trivial if you have blocks.
+ */
+@NodeInfo(shortName = "return")
+public class ReturnNode extends RubyNode {
+
+    private final long returnID;
+    @Child protected RubyNode value;
+
+    public ReturnNode(RubyContext context, SourceSection sourceSection, long returnID, RubyNode value) {
+        super(context, sourceSection);
+        this.returnID = returnID;
+        this.value = adoptChild(value);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        throw new ReturnException(returnID, value.execute(frame));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/SequenceNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.control;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * A sequence of statements to be executed in serial.
+ */
+@NodeInfo(shortName = "sequence")
+public final class SequenceNode extends RubyNode {
+
+    @Children protected final RubyNode[] body;
+
+    public SequenceNode(RubyContext context, SourceSection sourceSection, RubyNode... body) {
+        super(context, sourceSection);
+        this.body = adoptChildren(body);
+    }
+
+    @ExplodeLoop
+    @Override
+    public Object execute(VirtualFrame frame) {
+        for (int n = 0; n < body.length - 1; n++) {
+            body[n].executeVoid(frame);
+        }
+
+        return body[body.length - 1].execute(frame);
+    }
+
+    @ExplodeLoop
+    @Override
+    public void executeVoid(VirtualFrame frame) {
+        for (int n = 0; n < body.length; n++) {
+            body[n].executeVoid(frame);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/TryNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.control;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.utilities.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Represents a block of code run with exception handlers. There's no {@code try} keyword in Ruby -
+ * it's implicit - but it's similar to a try statement in any other language.
+ */
+@NodeInfo(shortName = "try")
+public class TryNode extends RubyNode {
+
+    @Child protected RubyNode tryPart;
+    @Children final RescueNode[] rescueParts;
+    @Child protected RubyNode elsePart;
+
+    private final BranchProfile controlFlowProfile = new BranchProfile();
+
+    public TryNode(RubyContext context, SourceSection sourceSection, RubyNode tryPart, RescueNode[] rescueParts, RubyNode elsePart) {
+        super(context, sourceSection);
+        this.tryPart = adoptChild(tryPart);
+        this.rescueParts = adoptChildren(rescueParts);
+        this.elsePart = adoptChild(elsePart);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        while (true) {
+            try {
+                final Object result = tryPart.execute(frame);
+                elsePart.executeVoid(frame);
+                return result;
+            } catch (ControlFlowException exception) {
+                controlFlowProfile.enter();
+
+                throw exception;
+            } catch (RuntimeException exception) {
+                CompilerDirectives.transferToInterpreter();
+
+                try {
+                    return handleException(frame, exception);
+                } catch (RetryException e) {
+                    continue;
+                }
+            }
+        }
+    }
+
+    private Object handleException(VirtualFrame frame, RuntimeException exception) {
+        CompilerAsserts.neverPartOfCompilation();
+
+        final RubyContext context = getContext();
+
+        final RubyBasicObject rubyException = ExceptionTranslator.translateException(context, exception);
+
+        context.getCoreLibrary().getGlobalVariablesObject().setInstanceVariable("$!", rubyException);
+
+        for (RescueNode rescue : rescueParts) {
+            if (rescue.canHandle(frame, rubyException)) {
+                return rescue.execute(frame);
+            }
+        }
+
+        throw exception;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/control/WhileNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.control;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.utilities.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.nodes.cast.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+
+/**
+ * Represents a Ruby {@code while} statement.
+ */
+@NodeInfo(shortName = "while")
+public class WhileNode extends RubyNode {
+
+    @Child protected BooleanCastNode condition;
+    @Child protected RubyNode body;
+
+    private final BranchProfile breakProfile = new BranchProfile();
+    private final BranchProfile nextProfile = new BranchProfile();
+    private final BranchProfile redoProfile = new BranchProfile();
+
+    public WhileNode(RubyContext context, SourceSection sourceSection, BooleanCastNode condition, RubyNode body) {
+        super(context, sourceSection);
+        this.condition = adoptChild(condition);
+        this.body = adoptChild(body);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        outer: while (condition.executeBoolean(frame)) {
+            while (true) {
+                try {
+                    body.execute(frame);
+                    continue outer;
+                } catch (BreakException e) {
+                    breakProfile.enter();
+                    return e.getResult();
+                } catch (NextException e) {
+                    nextProfile.enter();
+                    continue outer;
+                } catch (RedoException e) {
+                    redoProfile.enter();
+                }
+            }
+        }
+
+        return NilPlaceholder.INSTANCE;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayConcatNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+/**
+ * Concatenate arrays.
+ */
+@NodeInfo(shortName = "array-concat")
+public final class ArrayConcatNode extends RubyNode {
+
+    @Children protected final RubyNode[] children;
+
+    public ArrayConcatNode(RubyContext context, SourceSection sourceSection, RubyNode[] children) {
+        super(context, sourceSection);
+        assert children.length > 1;
+        this.children = adoptChildren(children);
+    }
+
+    @ExplodeLoop
+    @Override
+    public Object execute(VirtualFrame frame) {
+        final RubyArray array = new RubyArray(getContext().getCoreLibrary().getArrayClass());
+
+        for (int n = 0; n < children.length; n++) {
+            final Object childObject = children[n].execute(frame);
+
+            if (childObject instanceof RubyArray) {
+                // setRangeArray has special cases for setting a zero-length range at the end
+                final int end = array.size();
+                array.setRangeArrayExclusive(end, end, (RubyArray) childObject);
+            } else {
+                array.push(childObject);
+            }
+        }
+
+        return array;
+    }
+
+    @ExplodeLoop
+    @Override
+    public void executeVoid(VirtualFrame frame) {
+        for (int n = 0; n < children.length; n++) {
+            children[n].executeVoid(frame);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayCoreMethodNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+public abstract class ArrayCoreMethodNode extends CoreMethodNode {
+
+    public ArrayCoreMethodNode(RubyContext context, SourceSection sourceSection) {
+        super(context, sourceSection);
+    }
+
+    public ArrayCoreMethodNode(ArrayCoreMethodNode prev) {
+        super(prev);
+    }
+
+    protected boolean isEmptyStore(RubyArray receiver) {
+        return receiver.getArrayStore() instanceof EmptyArrayStore;
+    }
+
+    protected boolean isFixnumStore(RubyArray receiver) {
+        return receiver.getArrayStore() instanceof FixnumArrayStore;
+    }
+
+    protected boolean isFixnumImmutablePairStore(RubyArray receiver) {
+        return receiver.getArrayStore() instanceof FixnumImmutablePairArrayStore;
+    }
+
+    protected boolean isObjectStore(RubyArray receiver) {
+        return receiver.getArrayStore() instanceof ObjectArrayStore;
+    }
+
+    protected boolean isObjectImmutablePairStore(RubyArray receiver) {
+        return receiver.getArrayStore() instanceof ObjectImmutablePairArrayStore;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayIndexNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+/**
+ * Index an array, without using any method lookup. This isn't a call - it's an operation on a core
+ * class.
+ */
+@NodeInfo(shortName = "array-index")
+@NodeChildren({@NodeChild(value = "array", type = RubyNode.class)})
+public abstract class ArrayIndexNode extends RubyNode {
+
+    final int index;
+
+    public ArrayIndexNode(RubyContext context, SourceSection sourceSection, int index) {
+        super(context, sourceSection);
+        this.index = index;
+    }
+
+    public ArrayIndexNode(ArrayIndexNode prev) {
+        super(prev);
+        index = prev.index;
+    }
+
+    @Specialization(guards = "isEmptyStore", order = 1)
+    public NilPlaceholder indexEmpty(@SuppressWarnings("unused") RubyArray array) {
+        return NilPlaceholder.INSTANCE;
+    }
+
+    @Specialization(guards = "isFixnumStore", rewriteOn = UnexpectedResultException.class, order = 2)
+    public int indexFixnum(RubyArray array) throws UnexpectedResultException {
+        final FixnumArrayStore store = (FixnumArrayStore) array.getArrayStore();
+        return store.getFixnum(ArrayUtilities.normaliseIndex(store.size(), index));
+    }
+
+    @Specialization(guards = "isFixnumStore", order = 3)
+    public Object indexMaybeFixnum(RubyArray array) {
+        final FixnumArrayStore store = (FixnumArrayStore) array.getArrayStore();
+
+        try {
+            return store.getFixnum(ArrayUtilities.normaliseIndex(store.size(), index));
+        } catch (UnexpectedResultException e) {
+            return e.getResult();
+        }
+    }
+
+    @Specialization(guards = "isFixnumImmutablePairStore", rewriteOn = UnexpectedResultException.class, order = 4)
+    public int indexFixnumImmutablePair(RubyArray array) throws UnexpectedResultException {
+        final FixnumImmutablePairArrayStore store = (FixnumImmutablePairArrayStore) array.getArrayStore();
+        return store.getFixnum(ArrayUtilities.normaliseIndex(store.size(), index));
+    }
+
+    @Specialization(guards = "isFixnumImmutablePairStore", order = 5)
+    public Object indexMaybeFixnumImmutablePair(RubyArray array) {
+        final FixnumImmutablePairArrayStore store = (FixnumImmutablePairArrayStore) array.getArrayStore();
+
+        try {
+            return store.getFixnum(ArrayUtilities.normaliseIndex(store.size(), index));
+        } catch (UnexpectedResultException e) {
+            return e.getResult();
+        }
+    }
+
+    @Specialization(guards = "isObjectStore", order = 6)
+    public Object indexObject(RubyArray array) {
+        final ObjectArrayStore store = (ObjectArrayStore) array.getArrayStore();
+        return store.get(ArrayUtilities.normaliseIndex(store.size(), index));
+    }
+
+    @Specialization(guards = "isObjectImmutablePairStore", order = 7)
+    public Object indexObjectImmutablePair(RubyArray array) {
+        final ObjectImmutablePairArrayStore store = (ObjectImmutablePairArrayStore) array.getArrayStore();
+        return store.get(ArrayUtilities.normaliseIndex(store.size(), index));
+    }
+
+    protected boolean isEmptyStore(RubyArray receiver) {
+        return receiver.getArrayStore() instanceof EmptyArrayStore;
+    }
+
+    protected boolean isFixnumStore(RubyArray receiver) {
+        return receiver.getArrayStore() instanceof FixnumArrayStore;
+    }
+
+    protected boolean isFixnumImmutablePairStore(RubyArray receiver) {
+        return receiver.getArrayStore() instanceof FixnumImmutablePairArrayStore;
+    }
+
+    protected boolean isObjectStore(RubyArray receiver) {
+        return receiver.getArrayStore() instanceof ObjectArrayStore;
+    }
+
+    protected boolean isObjectImmutablePairStore(RubyArray receiver) {
+        return receiver.getArrayStore() instanceof ObjectImmutablePairArrayStore;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,1066 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import java.util.*;
+
+import com.oracle.truffle.api.CompilerDirectives.SlowPath;
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+import com.oracle.truffle.ruby.runtime.core.range.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+@CoreClass(name = "Array")
+public abstract class ArrayNodes {
+
+    @CoreMethod(names = "+", minArgs = 1, maxArgs = 1)
+    public abstract static class AddNode extends CoreMethodNode {
+
+        public AddNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public AddNode(AddNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray equal(RubyArray a, RubyArray b) {
+            final RubyArray result = new RubyArray(getContext().getCoreLibrary().getArrayClass());
+            result.setRangeArrayExclusive(0, 0, a);
+            result.setRangeArrayExclusive(a.size(), a.size(), b);
+            return result;
+        }
+
+    }
+
+    @CoreMethod(names = "-", minArgs = 1, maxArgs = 1)
+    public abstract static class SubNode extends CoreMethodNode {
+
+        public SubNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public SubNode(SubNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray equal(RubyArray a, RubyArray b) {
+            return a.relativeComplement(b);
+        }
+
+    }
+
+    @CoreMethod(names = "*", minArgs = 1, maxArgs = 1)
+    public abstract static class MulNode extends CoreMethodNode {
+
+        public MulNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public MulNode(MulNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray mul(RubyArray array, int count) {
+            // TODO(CS): use the same storage type
+
+            final RubyArray result = new RubyArray(array.getRubyClass().getContext().getCoreLibrary().getArrayClass());
+
+            for (int n = 0; n < count; n++) {
+                for (int i = 0; i < array.size(); i++) {
+                    result.push(array.get(i));
+                }
+            }
+
+            return result;
+        }
+
+    }
+
+    @CoreMethod(names = "==", minArgs = 1, maxArgs = 1)
+    public abstract static class EqualNode extends CoreMethodNode {
+
+        public EqualNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public EqualNode(EqualNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean equal(RubyArray a, RubyArray b) {
+            // TODO(CS)
+            return a.equals(b);
+        }
+
+    }
+
+    @CoreMethod(names = "[]", minArgs = 1, maxArgs = 2)
+    public abstract static class IndexNode extends ArrayCoreMethodNode {
+
+        public IndexNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public IndexNode(IndexNode prev) {
+            super(prev);
+        }
+
+        @Specialization(guards = "isEmptyStore", order = 1)
+        public NilPlaceholder indexEmpty(@SuppressWarnings("unused") RubyArray array, @SuppressWarnings("unused") int index, @SuppressWarnings("unused") UndefinedPlaceholder unused) {
+            return NilPlaceholder.INSTANCE;
+        }
+
+        @Specialization(guards = "isFixnumStore", rewriteOn = UnexpectedResultException.class, order = 2)
+        public int indexFixnum(RubyArray array, int index, @SuppressWarnings("unused") UndefinedPlaceholder unused) throws UnexpectedResultException {
+            final FixnumArrayStore store = (FixnumArrayStore) array.getArrayStore();
+            return store.getFixnum(ArrayUtilities.normaliseIndex(store.size(), index));
+        }
+
+        @Specialization(guards = "isFixnumStore", order = 3)
+        public Object indexMaybeFixnum(RubyArray array, int index, @SuppressWarnings("unused") UndefinedPlaceholder unused) {
+            final FixnumArrayStore store = (FixnumArrayStore) array.getArrayStore();
+
+            try {
+                return store.getFixnum(ArrayUtilities.normaliseIndex(store.size(), index));
+            } catch (UnexpectedResultException e) {
+                return e.getResult();
+            }
+        }
+
+        @Specialization(guards = "isFixnumImmutablePairStore", rewriteOn = UnexpectedResultException.class, order = 4)
+        public int indexFixnumImmutablePair(RubyArray array, int index, @SuppressWarnings("unused") UndefinedPlaceholder unused) throws UnexpectedResultException {
+            final FixnumImmutablePairArrayStore store = (FixnumImmutablePairArrayStore) array.getArrayStore();
+            return store.getFixnum(ArrayUtilities.normaliseIndex(store.size(), index));
+        }
+
+        @Specialization(guards = "isFixnumImmutablePairStore", order = 5)
+        public Object indexMaybeFixnumImmutablePair(RubyArray array, int index, @SuppressWarnings("unused") UndefinedPlaceholder unused) {
+            final FixnumImmutablePairArrayStore store = (FixnumImmutablePairArrayStore) array.getArrayStore();
+
+            try {
+                return store.getFixnum(ArrayUtilities.normaliseIndex(store.size(), index));
+            } catch (UnexpectedResultException e) {
+                return e.getResult();
+            }
+        }
+
+        @Specialization(guards = "isObjectStore", order = 6)
+        public Object indexObject(RubyArray array, int index, @SuppressWarnings("unused") UndefinedPlaceholder unused) {
+            final ObjectArrayStore store = (ObjectArrayStore) array.getArrayStore();
+            return store.get(ArrayUtilities.normaliseIndex(store.size(), index));
+        }
+
+        @Specialization(guards = "isObjectImmutablePairStore", order = 7)
+        public Object indexObjectImmutablePair(RubyArray array, int index, @SuppressWarnings("unused") UndefinedPlaceholder unused) {
+            final ObjectImmutablePairArrayStore store = (ObjectImmutablePairArrayStore) array.getArrayStore();
+            return store.get(ArrayUtilities.normaliseIndex(store.size(), index));
+        }
+
+        @Specialization(order = 8)
+        public Object indexRange(RubyArray array, int begin, int rangeLength) {
+            final int length = array.size();
+            final int normalisedBegin = ArrayUtilities.normaliseIndex(length, begin);
+            return array.getRangeExclusive(normalisedBegin, normalisedBegin + rangeLength);
+        }
+
+        @Specialization(order = 9)
+        public Object indexRange(RubyArray array, FixnumRange range, @SuppressWarnings("unused") UndefinedPlaceholder unused) {
+            if (range.doesExcludeEnd()) {
+                return array.getRangeExclusive(range.getBegin(), range.getExclusiveEnd());
+            } else {
+                return array.getRangeInclusive(range.getBegin(), range.getInclusiveEnd());
+            }
+        }
+
+    }
+
+    @CoreMethod(names = "[]=", minArgs = 2, maxArgs = 3)
+    public abstract static class IndexSetNode extends ArrayCoreMethodNode {
+
+        public IndexSetNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public IndexSetNode(IndexSetNode prev) {
+            super(prev);
+        }
+
+        @Specialization(guards = "isEmptyStore", order = 1)
+        public Object indexSetEmpty(RubyArray array, int index, Object value, @SuppressWarnings("unused") UndefinedPlaceholder unused) {
+            array.set(index, value);
+            return value;
+        }
+
+        @Specialization(guards = "isFixnumStore", rewriteOn = GeneraliseArrayStoreException.class, order = 2)
+        public int indexSetFixnum(RubyArray array, int index, int value, @SuppressWarnings("unused") UndefinedPlaceholder unused) throws GeneraliseArrayStoreException {
+            final FixnumArrayStore store = (FixnumArrayStore) array.getArrayStore();
+            final int normalisedIndex = ArrayUtilities.normaliseIndex(store.size(), index);
+            store.setFixnum(normalisedIndex, value);
+            return value;
+        }
+
+        @Specialization(guards = "isFixnumStore", order = 3)
+        public int indexSetFixnumMayGeneralise(RubyArray array, int index, int value, @SuppressWarnings("unused") UndefinedPlaceholder unused) {
+            final FixnumArrayStore store = (FixnumArrayStore) array.getArrayStore();
+            final int normalisedIndex = ArrayUtilities.normaliseIndex(store.size(), index);
+
+            try {
+                store.setFixnum(normalisedIndex, value);
+            } catch (GeneraliseArrayStoreException e) {
+                array.set(normalisedIndex, value);
+            }
+
+            return value;
+        }
+
+        @Specialization(guards = "isObjectStore", order = 4)
+        public Object indexSetObject(RubyArray array, int index, Object value, @SuppressWarnings("unused") UndefinedPlaceholder unused) {
+            final ObjectArrayStore store = (ObjectArrayStore) array.getArrayStore();
+            final int normalisedIndex = ArrayUtilities.normaliseIndex(store.size(), index);
+
+            try {
+                store.set(normalisedIndex, value);
+            } catch (GeneraliseArrayStoreException e) {
+                array.set(normalisedIndex, value);
+            }
+
+            return value;
+        }
+
+        @Specialization(order = 5)
+        public RubyArray indexSetRange(RubyArray array, FixnumRange range, RubyArray value, @SuppressWarnings("unused") UndefinedPlaceholder unused) {
+            if (range.doesExcludeEnd()) {
+                array.setRangeArrayExclusive(range.getBegin(), range.getExclusiveEnd(), value);
+            } else {
+                array.setRangeArrayInclusive(range.getBegin(), range.getInclusiveEnd(), value);
+            }
+
+            return value;
+        }
+
+        @Specialization(order = 6)
+        public Object indexSetRange(RubyArray array, FixnumRange range, Object value, @SuppressWarnings("unused") UndefinedPlaceholder unused) {
+            if (range.doesExcludeEnd()) {
+                array.setRangeSingleExclusive(range.getBegin(), range.getExclusiveEnd(), value);
+            } else {
+                array.setRangeSingleInclusive(range.getBegin(), range.getInclusiveEnd(), value);
+            }
+
+            return value;
+        }
+
+        @Specialization(order = 7)
+        public RubyArray indexSetRange(RubyArray array, int begin, int rangeLength, RubyArray value) {
+            array.setRangeArrayExclusive(begin, begin + rangeLength, value);
+            return value;
+        }
+
+        @Specialization(order = 8)
+        public Object indexSetRange(RubyArray array, int begin, int rangeLength, Object value) {
+            if (value instanceof UndefinedPlaceholder) {
+                if (array.getArrayStore() instanceof EmptyArrayStore) {
+                    return indexSetEmpty(array, begin, rangeLength, UndefinedPlaceholder.INSTANCE);
+                } else if (array.getArrayStore() instanceof FixnumArrayStore) {
+                    return indexSetFixnumMayGeneralise(array, begin, rangeLength, UndefinedPlaceholder.INSTANCE);
+                } else {
+                    return indexSetObject(array, begin, rangeLength, UndefinedPlaceholder.INSTANCE);
+                }
+            }
+
+            array.setRangeSingleExclusive(begin, begin + rangeLength, value);
+            return value;
+        }
+
+    }
+
+    @CoreMethod(names = "all?", needsBlock = true, maxArgs = 0)
+    public abstract static class AllNode extends YieldingCoreMethodNode {
+
+        public AllNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public AllNode(AllNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean all(VirtualFrame frame, RubyArray array, RubyProc block) {
+            for (Object value : array.asList()) {
+                if (!yieldBoolean(frame, block, value)) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+    }
+
+    @CoreMethod(names = "any?", needsBlock = true, maxArgs = 0)
+    public abstract static class AnyNode extends YieldingCoreMethodNode {
+
+        public AnyNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public AnyNode(AnyNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean any(VirtualFrame frame, RubyArray array, RubyProc block) {
+            for (Object value : array.asList()) {
+                if (yieldBoolean(frame, block, value)) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+    }
+
+    @CoreMethod(names = "compact", maxArgs = 0)
+    public abstract static class CompactNode extends ArrayCoreMethodNode {
+
+        public CompactNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public CompactNode(CompactNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray compat(RubyArray array) {
+            final RubyArray result = new RubyArray(array.getRubyClass().getContext().getCoreLibrary().getArrayClass());
+
+            for (Object value : array.asList()) {
+                if (!(value instanceof NilPlaceholder || value instanceof RubyNilClass)) {
+                    result.push(value);
+                }
+            }
+
+            return result;
+        }
+
+    }
+
+    @CoreMethod(names = "concat", minArgs = 1, maxArgs = 1)
+    public abstract static class ConcatNode extends CoreMethodNode {
+
+        public ConcatNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ConcatNode(ConcatNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray concat(RubyArray array, RubyArray other) {
+            array.setRangeArrayExclusive(array.size(), array.size(), other);
+            return array;
+        }
+
+    }
+
+    @CoreMethod(names = "delete", minArgs = 1, maxArgs = 1)
+    public abstract static class DeleteNode extends CoreMethodNode {
+
+        public DeleteNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public DeleteNode(DeleteNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object delete(RubyArray array, Object value) {
+            boolean deleted = false;
+            int n = 0;
+
+            while (n < array.size()) {
+                if (array.get(n) == value) {
+                    array.deleteAt(n);
+                    deleted = true;
+                } else {
+                    n++;
+                }
+            }
+
+            if (deleted) {
+                return value;
+            } else {
+                return NilPlaceholder.INSTANCE;
+            }
+        }
+
+    }
+
+    @CoreMethod(names = "delete_at", minArgs = 1, maxArgs = 1)
+    public abstract static class DeleteAtNode extends CoreMethodNode {
+
+        public DeleteAtNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public DeleteAtNode(DeleteAtNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object deleteAt(RubyArray array, int index) {
+            return array.deleteAt(index);
+        }
+
+    }
+
+    @CoreMethod(names = "dup", maxArgs = 0)
+    public abstract static class DupNode extends ArrayCoreMethodNode {
+
+        public DupNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public DupNode(DupNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object dup(RubyArray array) {
+            return array.dup();
+        }
+
+    }
+
+    @CoreMethod(names = "each", needsBlock = true, maxArgs = 0)
+    public abstract static class EachNode extends YieldingCoreMethodNode {
+
+        public EachNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public EachNode(EachNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder each(VirtualFrame frame, RubyArray array, RubyProc block) {
+            for (int n = 0; n < array.size(); n++) {
+                try {
+                    yield(frame, block, array.get(n));
+                } catch (BreakException e) {
+                    break;
+                }
+            }
+
+            return NilPlaceholder.INSTANCE;
+        }
+
+    }
+
+    @CoreMethod(names = "each_with_index", needsBlock = true, maxArgs = 0)
+    public abstract static class EachWithIndexNode extends YieldingCoreMethodNode {
+
+        public EachWithIndexNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public EachWithIndexNode(EachWithIndexNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder eachWithIndex(VirtualFrame frame, RubyArray array, RubyProc block) {
+            for (int n = 0; n < array.size(); n++) {
+                try {
+                    yield(frame, block, array.get(n), n);
+                } catch (BreakException e) {
+                    break;
+                }
+            }
+
+            return NilPlaceholder.INSTANCE;
+        }
+
+    }
+
+    @CoreMethod(names = "empty?", maxArgs = 0)
+    public abstract static class EmptyNode extends ArrayCoreMethodNode {
+
+        public EmptyNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public EmptyNode(EmptyNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean isEmpty(RubyArray array) {
+            return array.isEmpty();
+        }
+
+    }
+
+    @CoreMethod(names = "find", needsBlock = true, maxArgs = 0)
+    public abstract static class FindNode extends YieldingCoreMethodNode {
+
+        public FindNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public FindNode(FindNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object find(VirtualFrame frame, RubyArray array, RubyProc block) {
+            for (int n = 0; n < array.size(); n++) {
+                try {
+                    final Object value = array.get(n);
+
+                    if (yieldBoolean(frame, block, value)) {
+                        return value;
+                    }
+                } catch (BreakException e) {
+                    break;
+                }
+            }
+
+            return NilPlaceholder.INSTANCE;
+        }
+    }
+
+    @CoreMethod(names = "first", maxArgs = 0)
+    public abstract static class FirstNode extends ArrayCoreMethodNode {
+
+        public FirstNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public FirstNode(FirstNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object first(RubyArray array) {
+            if (array.size() == 0) {
+                return NilPlaceholder.INSTANCE;
+            } else {
+                return array.get(0);
+            }
+        }
+
+    }
+
+    @CoreMethod(names = "flatten", maxArgs = 0)
+    public abstract static class FlattenNode extends ArrayCoreMethodNode {
+
+        public FlattenNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public FlattenNode(FlattenNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray flatten(RubyArray array) {
+            final RubyArray result = new RubyArray(array.getRubyClass().getContext().getCoreLibrary().getArrayClass());
+            array.flattenTo(result);
+            return result;
+        }
+
+    }
+
+    @CoreMethod(names = "include?", minArgs = 1, maxArgs = 1)
+    public abstract static class IncludeNode extends ArrayCoreMethodNode {
+
+        public IncludeNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public IncludeNode(IncludeNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean include(RubyArray array, Object value) {
+            return array.contains(value);
+        }
+
+    }
+
+    @CoreMethod(names = {"inject", "reduce"}, needsBlock = true, minArgs = 0, maxArgs = 1)
+    public abstract static class InjectNode extends YieldingCoreMethodNode {
+
+        public InjectNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public InjectNode(InjectNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object inject(VirtualFrame frame, RubyArray array, @SuppressWarnings("unused") UndefinedPlaceholder initial, RubyProc block) {
+            Object accumulator = array.get(0);
+
+            for (int n = 1; n < array.size(); n++) {
+                accumulator = yield(frame, block, accumulator, array.get(n));
+            }
+
+            return accumulator;
+        }
+
+        @Specialization
+        public Object inject(VirtualFrame frame, RubyArray array, Object initial, RubyProc block) {
+            if (initial instanceof UndefinedPlaceholder) {
+                return inject(frame, array, UndefinedPlaceholder.INSTANCE, block);
+            }
+
+            Object accumulator = initial;
+
+            for (int n = 0; n < array.size(); n++) {
+                accumulator = yield(frame, block, accumulator, array.get(n));
+            }
+
+            return accumulator;
+        }
+
+    }
+
+    @CoreMethod(names = "insert", minArgs = 2, maxArgs = 2)
+    public abstract static class InsertNode extends ArrayCoreMethodNode {
+
+        public InsertNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public InsertNode(InsertNode prev) {
+            super(prev);
+        }
+
+        @Specialization(guards = "isFixnumStore", rewriteOn = GeneraliseArrayStoreException.class)
+        public int insert(RubyArray array, int index, int value) throws GeneraliseArrayStoreException {
+            final FixnumArrayStore store = (FixnumArrayStore) array.getArrayStore();
+            store.insertFixnum(ArrayUtilities.normaliseIndex(store.size(), index), value);
+            return value;
+        }
+
+        @Specialization
+        public Object insert(RubyArray array, int index, Object value) {
+            array.insert(ArrayUtilities.normaliseIndex(array.size(), index), value);
+            return value;
+        }
+
+    }
+
+    @CoreMethod(names = {"inspect", "to_s"}, maxArgs = 0)
+    public abstract static class InspectNode extends CoreMethodNode {
+
+        public InspectNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public InspectNode(InspectNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString inspect(RubyArray array) {
+            final RubyContext context = getContext();
+            return getContext().makeString(inspect(context, array));
+        }
+
+        @SlowPath
+        private static String inspect(RubyContext context, RubyArray array) {
+            final StringBuilder builder = new StringBuilder();
+
+            builder.append("[");
+
+            for (int n = 0; n < array.size(); n++) {
+                if (n > 0) {
+                    builder.append(", ");
+                }
+
+                // TODO(CS): slow path send
+                builder.append(context.getCoreLibrary().box(array.get(n)).send("inspect", null));
+            }
+
+            builder.append("]");
+
+            return builder.toString();
+        }
+
+    }
+
+    @CoreMethod(names = "join", minArgs = 1, maxArgs = 1)
+    public abstract static class JoinNode extends ArrayCoreMethodNode {
+
+        public JoinNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public JoinNode(JoinNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString join(RubyArray array, RubyString separator) {
+            return array.getRubyClass().getContext().makeString(array.join(separator.toString()));
+        }
+
+    }
+
+    @CoreMethod(names = "last", maxArgs = 0)
+    public abstract static class LastNode extends ArrayCoreMethodNode {
+
+        public LastNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public LastNode(LastNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object last(RubyArray array) {
+            final int size = array.size();
+            if (size == 0) {
+                return NilPlaceholder.INSTANCE;
+            } else {
+                return array.get(size - 1);
+            }
+        }
+
+    }
+
+    @CoreMethod(names = {"map", "collect"}, needsBlock = true, maxArgs = 0)
+    public abstract static class MapNode extends YieldingCoreMethodNode {
+
+        public MapNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public MapNode(MapNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray map(VirtualFrame frame, RubyArray array, RubyProc block) {
+            final RubyArray result = new RubyArray(array.getRubyClass().getContext().getCoreLibrary().getArrayClass());
+
+            for (int n = 0; n < array.size(); n++) {
+                result.push(yield(frame, block, array.get(n)));
+            }
+
+            return result;
+        }
+    }
+
+    @CoreMethod(names = {"map!", "collect!"}, needsBlock = true, maxArgs = 0)
+    public abstract static class MapInPlaceNode extends YieldingCoreMethodNode {
+
+        public MapInPlaceNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public MapInPlaceNode(MapInPlaceNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray mapInPlace(VirtualFrame frame, RubyArray array, RubyProc block) {
+            for (int n = 0; n < array.size(); n++) {
+                array.set(n, yield(frame, block, array.get(n)));
+            }
+
+            return array;
+        }
+    }
+
+    @CoreMethod(names = "pop", maxArgs = 0)
+    public abstract static class PopNode extends ArrayCoreMethodNode {
+
+        public PopNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public PopNode(PopNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object pop(RubyArray array) {
+            final int size = array.size();
+
+            if (size == 0) {
+                return NilPlaceholder.INSTANCE;
+            } else {
+                return array.deleteAt(size - 1);
+            }
+        }
+
+    }
+
+    @CoreMethod(names = "product", isSplatted = true)
+    public abstract static class ProductNode extends ArrayCoreMethodNode {
+
+        public ProductNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ProductNode(ProductNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object product(RubyArray array, Object... args) {
+            final RubyArray[] arrays = new RubyArray[1 + args.length];
+            arrays[0] = array;
+            System.arraycopy(args, 0, arrays, 1, args.length);
+            return RubyArray.product(array.getRubyClass().getContext().getCoreLibrary().getArrayClass(), arrays, arrays.length);
+        }
+
+    }
+
+    @CoreMethod(names = {"push", "<<"}, isSplatted = true)
+    public abstract static class PushNode extends CoreMethodNode {
+
+        public PushNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public PushNode(PushNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray push(RubyArray array, Object... args) {
+            for (int n = 0; n < args.length; n++) {
+                array.push(args[n]);
+            }
+
+            return array;
+        }
+
+    }
+
+    @CoreMethod(names = "reject!", needsBlock = true, maxArgs = 0)
+    public abstract static class RejectInPlaceNode extends YieldingCoreMethodNode {
+
+        public RejectInPlaceNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public RejectInPlaceNode(RejectInPlaceNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object rejectInPlace(VirtualFrame frame, RubyArray array, RubyProc block) {
+            boolean modified = false;
+            int n = 0;
+
+            while (n < array.size()) {
+                if (yieldBoolean(frame, block, array.get(n))) {
+                    array.deleteAt(n);
+                    modified = true;
+                } else {
+                    n++;
+                }
+            }
+
+            if (modified) {
+                return array;
+            } else {
+                return NilPlaceholder.INSTANCE;
+            }
+        }
+
+    }
+
+    @CoreMethod(names = "select", needsBlock = true, maxArgs = 0)
+    public abstract static class SelectNode extends YieldingCoreMethodNode {
+
+        public SelectNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public SelectNode(SelectNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object select(VirtualFrame frame, RubyArray array, RubyProc block) {
+            final RubyArray result = new RubyArray(getContext().getCoreLibrary().getArrayClass());
+
+            for (int n = 0; n < array.size(); n++) {
+                final Object value = array.get(n);
+
+                if (yieldBoolean(frame, block, value)) {
+                    result.push(value);
+                }
+            }
+
+            return result;
+        }
+
+    }
+
+    @CoreMethod(names = "shift", maxArgs = 0)
+    public abstract static class ShiftNode extends CoreMethodNode {
+
+        public ShiftNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ShiftNode(ShiftNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object shift(RubyArray array) {
+            final int size = array.size();
+
+            if (size == 0) {
+                return NilPlaceholder.INSTANCE;
+            } else {
+                return array.deleteAt(0);
+            }
+        }
+
+    }
+
+    @CoreMethod(names = {"size", "length"}, maxArgs = 0)
+    public abstract static class SizeNode extends ArrayCoreMethodNode {
+
+        public SizeNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public SizeNode(SizeNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public int size(RubyArray array) {
+            return array.size();
+        }
+
+    }
+
+    @CoreMethod(names = "sort", maxArgs = 0)
+    public abstract static class SortNode extends CoreMethodNode {
+
+        public SortNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public SortNode(SortNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray sort(RubyArray array) {
+            final RubyContext context = array.getRubyClass().getContext();
+
+            final Object[] objects = array.asList().toArray();
+
+            Arrays.sort(objects, new Comparator<Object>() {
+
+                @Override
+                public int compare(Object a, Object b) {
+                    final RubyBasicObject aBoxed = context.getCoreLibrary().box(a);
+                    return (int) aBoxed.getLookupNode().lookupMethod("<=>").call(null, aBoxed, null, b);
+                }
+
+            });
+
+            return RubyArray.specializedFromObjects(context.getCoreLibrary().getArrayClass(), objects);
+        }
+
+    }
+
+    @CoreMethod(names = "unshift", isSplatted = true)
+    public abstract static class UnshiftNode extends CoreMethodNode {
+
+        public UnshiftNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public UnshiftNode(UnshiftNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object unshift(RubyArray array, Object... args) {
+            for (int n = 0; n < args.length; n++) {
+                array.unshift(args[n]);
+            }
+
+            return array;
+        }
+
+    }
+
+    @CoreMethod(names = "zip", isSplatted = true)
+    public abstract static class ZipNode extends CoreMethodNode {
+
+        public ZipNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ZipNode(ZipNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray zip(RubyArray array, Object... args) {
+            final RubyContext context = getContext();
+            final RubyClass arrayClass = context.getCoreLibrary().getArrayClass();
+
+            final RubyArray result = new RubyArray(arrayClass);
+
+            for (int n = 0; n < array.size(); n++) {
+                final RubyArray tuple = new RubyArray(arrayClass);
+
+                tuple.push(array.get(n));
+
+                for (Object arg : args) {
+                    final RubyArray argArray = (RubyArray) arg;
+                    tuple.push(argArray.get(n));
+                }
+
+                result.push(tuple);
+            }
+
+            return result;
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayPushNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+public class ArrayPushNode extends RubyNode {
+
+    @Child protected RubyNode array;
+    @Child protected RubyNode pushed;
+
+    public ArrayPushNode(RubyContext context, SourceSection sourceSection, RubyNode array, RubyNode pushed) {
+        super(context, sourceSection);
+        this.array = adoptChild(array);
+        this.pushed = adoptChild(pushed);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        RubyArray a = (RubyArray) array.execute(frame);
+        a = (RubyArray) a.dup();
+        a.push(pushed.execute(frame));
+        return a;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ArrayRestNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+/**
+ * Take the rest of values in an array after an index, without using any method lookup. This isn't a
+ * call - it's an operation on a core class.
+ */
+@NodeInfo(shortName = "array-rest")
+public final class ArrayRestNode extends RubyNode {
+
+    final int begin;
+    @Child protected RubyNode array;
+
+    public ArrayRestNode(RubyContext context, SourceSection sourceSection, int begin, RubyNode array) {
+        super(context, sourceSection);
+        this.begin = begin;
+        this.array = adoptChild(array);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        final RubyArray arrayObject = (RubyArray) array.execute(frame);
+        return arrayObject.getRangeExclusive(begin, arrayObject.size());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/BasicObjectNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import java.math.*;
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+@CoreClass(name = "BasicObject")
+public abstract class BasicObjectNodes {
+
+    @CoreMethod(names = "!", needsSelf = false, maxArgs = 0)
+    public abstract static class NotNode extends CoreMethodNode {
+
+        public NotNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public NotNode(NotNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean not() {
+            return false;
+        }
+
+    }
+
+    @CoreMethod(names = "==", minArgs = 1, maxArgs = 1)
+    public abstract static class EqualNode extends CoreMethodNode {
+
+        public EqualNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public EqualNode(EqualNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean equal(Object a, Object b) {
+            // TODO(CS) ideally all classes would do this in their own nodes
+            return a.equals(b);
+        }
+
+    }
+
+    @CoreMethod(names = "!=", minArgs = 1, maxArgs = 1)
+    public abstract static class NotEqualNode extends CoreMethodNode {
+
+        public NotEqualNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public NotEqualNode(NotEqualNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean notEqual(Object a, Object b) {
+            // TODO(CS) ideally all classes would do this in their own nodes
+            return !a.equals(b);
+        }
+
+    }
+
+    @CoreMethod(names = "equal?", minArgs = 1, maxArgs = 1)
+    public abstract static class ReferenceEqualNode extends CoreMethodNode {
+
+        public ReferenceEqualNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ReferenceEqualNode(ReferenceEqualNode prev) {
+            super(prev);
+        }
+
+        @Specialization(order = 1)
+        public boolean equal(@SuppressWarnings("unused") NilPlaceholder a, @SuppressWarnings("unused") NilPlaceholder b) {
+            return true;
+        }
+
+        @Specialization(order = 2)
+        public boolean equal(int a, int b) {
+            return a == b;
+        }
+
+        @Specialization(order = 3)
+        public boolean equal(double a, double b) {
+            return a == b;
+        }
+
+        @Specialization(order = 4)
+        public boolean equal(BigInteger a, BigInteger b) {
+            return a.compareTo(b) == 0;
+        }
+
+        @Specialization(order = 5)
+        public boolean equal(RubyBasicObject a, RubyBasicObject b) {
+            return a == b;
+        }
+    }
+
+    @CoreMethod(names = "initialize", needsSelf = false, maxArgs = 0)
+    public abstract static class InitializeNode extends CoreMethodNode {
+
+        public InitializeNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public InitializeNode(InitializeNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder initiailze() {
+            return NilPlaceholder.INSTANCE;
+        }
+
+    }
+
+    @CoreMethod(names = {"send", "__send__"}, needsSelf = true, needsBlock = true, minArgs = 1, isSplatted = true)
+    public abstract static class SendNode extends CoreMethodNode {
+
+        public SendNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public SendNode(SendNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object send(RubyBasicObject self, Object[] args, @SuppressWarnings("unused") UndefinedPlaceholder block) {
+            final String name = args[0].toString();
+            final Object[] sendArgs = Arrays.copyOfRange(args, 1, args.length);
+            return self.send(name, null, sendArgs);
+        }
+
+        @Specialization
+        public Object send(RubyBasicObject self, Object[] args, RubyProc block) {
+            final String name = args[0].toString();
+            final Object[] sendArgs = Arrays.copyOfRange(args, 1, args.length);
+            return self.send(name, block, sendArgs);
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/BignumNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,642 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import java.math.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+@CoreClass(name = "Bignum")
+public abstract class BignumNodes {
+
+    @CoreMethod(names = "+@", maxArgs = 0)
+    public abstract static class PosNode extends CoreMethodNode {
+
+        public PosNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public PosNode(PosNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public BigInteger pos(BigInteger value) {
+            return value;
+        }
+
+    }
+
+    @CoreMethod(names = "-@", maxArgs = 0)
+    public abstract static class NegNode extends CoreMethodNode {
+
+        public NegNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public NegNode(NegNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public BigInteger neg(BigInteger value) {
+            return value.negate();
+        }
+
+    }
+
+    @CoreMethod(names = "+", minArgs = 1, maxArgs = 1)
+    public abstract static class AddNode extends CoreMethodNode {
+
+        public AddNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public AddNode(AddNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object add(BigInteger a, int b) {
+            return a.add(BigInteger.valueOf(b));
+        }
+
+        @Specialization
+        public double add(BigInteger a, double b) {
+            return a.doubleValue() + b;
+        }
+
+        @Specialization
+        public Object add(BigInteger a, BigInteger b) {
+            return GeneralConversions.fixnumOrBignum(a.add(b));
+        }
+
+    }
+
+    @CoreMethod(names = "-", minArgs = 1, maxArgs = 1)
+    public abstract static class SubNode extends CoreMethodNode {
+
+        public SubNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public SubNode(SubNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object sub(BigInteger a, int b) {
+            return a.subtract(BigInteger.valueOf(b));
+        }
+
+        @Specialization
+        public double sub(BigInteger a, double b) {
+            return a.doubleValue() - b;
+        }
+
+        @Specialization
+        public Object sub(BigInteger a, BigInteger b) {
+            return GeneralConversions.fixnumOrBignum(a.subtract(b));
+        }
+
+    }
+
+    @CoreMethod(names = "*", minArgs = 1, maxArgs = 1)
+    public abstract static class MulNode extends CoreMethodNode {
+
+        public MulNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public MulNode(MulNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object mul(BigInteger a, int b) {
+            return a.multiply(BigInteger.valueOf(b));
+        }
+
+        @Specialization
+        public double mul(BigInteger a, double b) {
+            return a.doubleValue() * b;
+        }
+
+        @Specialization
+        public Object mul(BigInteger a, BigInteger b) {
+            return GeneralConversions.fixnumOrBignum(a.multiply(b));
+        }
+
+    }
+
+    @CoreMethod(names = "**", minArgs = 1, maxArgs = 1)
+    public abstract static class PowNode extends CoreMethodNode {
+
+        public PowNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public PowNode(PowNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public BigInteger pow(BigInteger a, int b) {
+            return a.pow(b);
+        }
+
+        @Specialization
+        public double pow(BigInteger a, double b) {
+            return Math.pow(a.doubleValue(), b);
+        }
+
+        @Specialization
+        public BigInteger pow(BigInteger a, BigInteger b) {
+            BigInteger result = BigInteger.ONE;
+
+            for (BigInteger n = BigInteger.ZERO; b.compareTo(b) < 0; n = n.add(BigInteger.ONE)) {
+                result = result.multiply(a);
+            }
+
+            return result;
+        }
+
+    }
+
+    @CoreMethod(names = "/", minArgs = 1, maxArgs = 1)
+    public abstract static class DivNode extends CoreMethodNode {
+
+        public DivNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public DivNode(DivNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object div(BigInteger a, int b) {
+            return a.divide(BigInteger.valueOf(b));
+        }
+
+        @Specialization
+        public double div(BigInteger a, double b) {
+            return a.doubleValue() / b;
+        }
+
+        @Specialization
+        public Object div(BigInteger a, BigInteger b) {
+            return GeneralConversions.fixnumOrBignum(a.divide(b));
+        }
+
+    }
+
+    @CoreMethod(names = "%", minArgs = 1, maxArgs = 1)
+    public abstract static class ModNode extends CoreMethodNode {
+
+        public ModNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ModNode(ModNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object mod(BigInteger a, int b) {
+            return GeneralConversions.fixnumOrBignum(a.mod(BigInteger.valueOf(b)));
+        }
+
+        @Specialization
+        public Object mod(@SuppressWarnings("unused") BigInteger a, @SuppressWarnings("unused") double b) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Specialization
+        public Object mod(BigInteger a, BigInteger b) {
+            return GeneralConversions.fixnumOrBignum(a.mod(b));
+        }
+
+    }
+
+    @CoreMethod(names = "divmod", minArgs = 1, maxArgs = 1)
+    public abstract static class DivModNode extends CoreMethodNode {
+
+        public DivModNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public DivModNode(DivModNode prev) {
+            super(prev);
+        }
+
+        @SuppressWarnings("unused")
+        @Specialization
+        public RubyArray divMod(VirtualFrame frame, BigInteger a, int b) {
+            return RubyBignum.divMod(getContext(), a, BigInteger.valueOf(b));
+        }
+
+        @Specialization
+        public RubyArray divMod(@SuppressWarnings("unused") BigInteger a, @SuppressWarnings("unused") double b) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Specialization
+        public RubyArray divMod(BigInteger a, BigInteger b) {
+            return RubyBignum.divMod(getContext(), a, b);
+        }
+
+    }
+
+    @CoreMethod(names = "<", minArgs = 1, maxArgs = 1)
+    public abstract static class LessNode extends CoreMethodNode {
+
+        public LessNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public LessNode(LessNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean less(BigInteger a, int b) {
+            return a.compareTo(BigInteger.valueOf(b)) < 0;
+        }
+
+        @Specialization
+        public boolean less(BigInteger a, double b) {
+            return a.compareTo(BigInteger.valueOf((long) b)) < 0;
+        }
+
+        @Specialization
+        public boolean less(BigInteger a, BigInteger b) {
+            return a.compareTo(b) < 0;
+        }
+    }
+
+    @CoreMethod(names = "<=", minArgs = 1, maxArgs = 1)
+    public abstract static class LessEqualNode extends CoreMethodNode {
+
+        public LessEqualNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public LessEqualNode(LessEqualNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean lessEqual(BigInteger a, int b) {
+            return a.compareTo(BigInteger.valueOf(b)) <= 0;
+        }
+
+        @Specialization
+        public boolean lessEqual(BigInteger a, double b) {
+            return a.compareTo(BigInteger.valueOf((long) b)) <= 0;
+        }
+
+        @Specialization
+        public boolean lessEqual(BigInteger a, BigInteger b) {
+            return a.compareTo(b) <= 0;
+        }
+    }
+
+    @CoreMethod(names = "==", minArgs = 1, maxArgs = 1)
+    public abstract static class EqualNode extends CoreMethodNode {
+
+        public EqualNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public EqualNode(EqualNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean equal(BigInteger a, int b) {
+            return a.compareTo(BigInteger.valueOf(b)) == 0;
+        }
+
+        @Specialization
+        public boolean equal(BigInteger a, double b) {
+            return a.compareTo(BigInteger.valueOf((long) b)) == 0;
+        }
+
+        @Specialization
+        public boolean equal(BigInteger a, BigInteger b) {
+            return a.compareTo(b) == 0;
+        }
+    }
+
+    @CoreMethod(names = "<=>", minArgs = 1, maxArgs = 1)
+    public abstract static class CompareNode extends CoreMethodNode {
+
+        public CompareNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public CompareNode(CompareNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public int compare(BigInteger a, int b) {
+            return a.compareTo(BigInteger.valueOf(b));
+        }
+
+        @Specialization
+        public int compare(BigInteger a, double b) {
+            return a.compareTo(BigInteger.valueOf((long) b));
+        }
+
+        @Specialization
+        public int compare(BigInteger a, BigInteger b) {
+            return a.compareTo(b);
+        }
+    }
+
+    @CoreMethod(names = "!=", minArgs = 1, maxArgs = 1)
+    public abstract static class NotEqualNode extends CoreMethodNode {
+
+        public NotEqualNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public NotEqualNode(NotEqualNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean notEqual(BigInteger a, int b) {
+            return a.compareTo(BigInteger.valueOf(b)) != 0;
+        }
+
+        @Specialization
+        public boolean notEqual(BigInteger a, double b) {
+            return a.compareTo(BigInteger.valueOf((long) b)) != 0;
+        }
+
+        @Specialization
+        public boolean notEqual(BigInteger a, BigInteger b) {
+            return a.compareTo(b) != 0;
+        }
+    }
+
+    @CoreMethod(names = ">=", minArgs = 1, maxArgs = 1)
+    public abstract static class GreaterEqualNode extends CoreMethodNode {
+
+        public GreaterEqualNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public GreaterEqualNode(GreaterEqualNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean greaterEqual(BigInteger a, int b) {
+            return a.compareTo(BigInteger.valueOf(b)) >= 0;
+        }
+
+        @Specialization
+        public boolean greaterEqual(BigInteger a, double b) {
+            return a.compareTo(BigInteger.valueOf((long) b)) >= 0;
+        }
+
+        @Specialization
+        public boolean greaterEqual(BigInteger a, BigInteger b) {
+            return a.compareTo(b) >= 0;
+        }
+    }
+
+    @CoreMethod(names = ">", minArgs = 1, maxArgs = 1)
+    public abstract static class GreaterNode extends CoreMethodNode {
+
+        public GreaterNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public GreaterNode(GreaterNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean equal(BigInteger a, int b) {
+            return a.compareTo(BigInteger.valueOf(b)) > 0;
+        }
+
+        @Specialization
+        public boolean equal(BigInteger a, double b) {
+            return a.compareTo(BigInteger.valueOf((long) b)) > 0;
+        }
+
+        @Specialization
+        public boolean equal(BigInteger a, BigInteger b) {
+            return a.compareTo(b) > 0;
+        }
+    }
+
+    @CoreMethod(names = "&", minArgs = 1, maxArgs = 1)
+    public abstract static class BitAndNode extends CoreMethodNode {
+
+        public BitAndNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public BitAndNode(BitAndNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object bitAnd(BigInteger a, int b) {
+            return GeneralConversions.fixnumOrBignum(a.and(BigInteger.valueOf(b)));
+        }
+
+        @Specialization
+        public Object bitAnd(BigInteger a, BigInteger b) {
+            return GeneralConversions.fixnumOrBignum(a.and(b));
+        }
+    }
+
+    @CoreMethod(names = "|", minArgs = 1, maxArgs = 1)
+    public abstract static class BitOrNode extends CoreMethodNode {
+
+        public BitOrNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public BitOrNode(BitOrNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object bitOr(BigInteger a, int b) {
+            return GeneralConversions.fixnumOrBignum(a.or(BigInteger.valueOf(b)));
+        }
+
+        @Specialization
+        public Object bitOr(BigInteger a, BigInteger b) {
+            return GeneralConversions.fixnumOrBignum(a.or(b));
+        }
+    }
+
+    @CoreMethod(names = "^", minArgs = 1, maxArgs = 1)
+    public abstract static class BitXOrNode extends CoreMethodNode {
+
+        public BitXOrNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public BitXOrNode(BitXOrNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object bitXOr(BigInteger a, int b) {
+            return GeneralConversions.fixnumOrBignum(a.xor(BigInteger.valueOf(b)));
+        }
+
+        @Specialization
+        public Object bitXOr(BigInteger a, BigInteger b) {
+            return GeneralConversions.fixnumOrBignum(a.xor(b));
+        }
+    }
+
+    @CoreMethod(names = "<<", minArgs = 1, maxArgs = 1)
+    public abstract static class LeftShiftNode extends CoreMethodNode {
+
+        public LeftShiftNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public LeftShiftNode(LeftShiftNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object leftShift(BigInteger a, int b) {
+            if (b >= 0) {
+                return GeneralConversions.fixnumOrBignum(a.shiftLeft(b));
+            } else {
+                return GeneralConversions.fixnumOrBignum(a.shiftRight(-b));
+            }
+        }
+
+    }
+
+    @CoreMethod(names = ">>", minArgs = 1, maxArgs = 1)
+    public abstract static class RightShiftNode extends CoreMethodNode {
+
+        public RightShiftNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public RightShiftNode(RightShiftNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object leftShift(BigInteger a, int b) {
+            if (b >= 0) {
+                return GeneralConversions.fixnumOrBignum(a.shiftRight(b));
+            } else {
+                return GeneralConversions.fixnumOrBignum(a.shiftLeft(-b));
+            }
+        }
+
+    }
+
+    @CoreMethod(names = "inspect", maxArgs = 0)
+    public abstract static class InpsectNode extends CoreMethodNode {
+
+        public InpsectNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public InpsectNode(InpsectNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString inspect(BigInteger n) {
+            return getContext().makeString(n.toString());
+        }
+
+    }
+
+    @CoreMethod(names = "nonzero?", maxArgs = 0)
+    public abstract static class NonZeroNode extends CoreMethodNode {
+
+        public NonZeroNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public NonZeroNode(NonZeroNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object nonZero(BigInteger value) {
+            if (value.compareTo(BigInteger.ZERO) == 0) {
+                return false;
+            } else {
+                return value;
+            }
+        }
+
+    }
+
+    @CoreMethod(names = "times", needsBlock = true, maxArgs = 0)
+    public abstract static class TimesNode extends YieldingCoreMethodNode {
+
+        public TimesNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public TimesNode(TimesNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public BigInteger times(VirtualFrame frame, BigInteger n, RubyProc block) {
+            for (BigInteger i = BigInteger.ZERO; i.compareTo(n) < 0; i = i.add(BigInteger.ONE)) {
+                yield(frame, block, i);
+            }
+
+            return n;
+        }
+
+    }
+
+    @CoreMethod(names = "to_s", maxArgs = 0)
+    public abstract static class ToSNode extends CoreMethodNode {
+
+        public ToSNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ToSNode(ToSNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString toS(BigInteger value) {
+            return getContext().makeString(value.toString());
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ClassNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.nodes.call.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+@CoreClass(name = "Class")
+public abstract class ClassNodes {
+
+    @CoreMethod(names = "===", minArgs = 1, maxArgs = 1)
+    public abstract static class ContainsInstanceNode extends CoreMethodNode {
+
+        public ContainsInstanceNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ContainsInstanceNode(ContainsInstanceNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean containsInstance(RubyClass rubyClass, RubyBasicObject instance) {
+            return instance.getRubyClass().assignableTo(rubyClass);
+        }
+    }
+
+    @CoreMethod(names = "new", needsBlock = true, isSplatted = true)
+    public abstract static class NewNode extends CoreMethodNode {
+
+        @Child protected DispatchHeadNode initialize;
+
+        public NewNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+            initialize = adoptChild(new DispatchHeadNode(context, getSourceSection(), "initialize", false));
+        }
+
+        public NewNode(NewNode prev) {
+            super(prev);
+            initialize = adoptChild(prev.initialize);
+        }
+
+        @Specialization
+        public RubyBasicObject newInstance(VirtualFrame frame, RubyClass rubyClass, Object[] args, @SuppressWarnings("unused") UndefinedPlaceholder block) {
+            return doNewInstance(frame, rubyClass, args, null);
+        }
+
+        @Specialization
+        public RubyBasicObject newInstance(VirtualFrame frame, RubyClass rubyClass, Object[] args, RubyProc block) {
+            return doNewInstance(frame, rubyClass, args, block);
+        }
+
+        private RubyBasicObject doNewInstance(VirtualFrame frame, RubyClass rubyClass, Object[] args, RubyProc block) {
+            final RubyBasicObject instance = rubyClass.newInstance();
+            initialize.dispatch(frame, instance, block, args);
+            return instance;
+        }
+
+    }
+
+    @CoreMethod(names = "to_s", maxArgs = 0)
+    public abstract static class ToSNode extends CoreMethodNode {
+
+        public ToSNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ToSNode(ToSNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString toS(RubyClass rubyClass) {
+            return getContext().makeString(rubyClass.getName());
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ComparableNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.nodes.call.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+@CoreClass(name = "Comparable")
+public abstract class ComparableNodes {
+
+    public abstract static class ComparableCoreMethodNode extends CoreMethodNode {
+
+        @Child protected DispatchHeadNode compareNode;
+
+        public ComparableCoreMethodNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+            compareNode = adoptChild(new DispatchHeadNode(context, getSourceSection(), "<=>", false));
+        }
+
+        public ComparableCoreMethodNode(ComparableCoreMethodNode prev) {
+            super(prev);
+            compareNode = adoptChild(prev.compareNode);
+        }
+
+        public int compare(VirtualFrame frame, RubyBasicObject receiverObject, Object comparedTo) {
+            return (int) compareNode.dispatch(frame, receiverObject, null, comparedTo);
+        }
+
+    }
+
+    @CoreMethod(names = "<", isModuleMethod = true, minArgs = 1, maxArgs = 1)
+    public abstract static class LessNode extends ComparableCoreMethodNode {
+
+        public LessNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public LessNode(LessNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean less(VirtualFrame frame, RubyBasicObject self, Object comparedTo) {
+            return compare(frame, self, comparedTo) < 0;
+        }
+
+    }
+
+    @CoreMethod(names = "<=", isModuleMethod = true, minArgs = 1, maxArgs = 1)
+    public abstract static class LessEqualNode extends ComparableCoreMethodNode {
+
+        public LessEqualNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public LessEqualNode(LessEqualNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean lessEqual(VirtualFrame frame, RubyBasicObject self, Object comparedTo) {
+            return compare(frame, self, comparedTo) <= 0;
+        }
+
+    }
+
+    @CoreMethod(names = "==", isModuleMethod = true, minArgs = 1, maxArgs = 1)
+    public abstract static class EqualNode extends ComparableCoreMethodNode {
+
+        public EqualNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public EqualNode(EqualNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean equal(VirtualFrame frame, RubyBasicObject self, Object comparedTo) {
+            if (self == comparedTo) {
+                return true;
+            }
+
+            try {
+                return compare(frame, self, comparedTo) == 0;
+            } catch (Exception e) {
+                // Comparable#== catches and ignores all exceptions in <=>, returning false
+                return false;
+            }
+        }
+    }
+
+    @CoreMethod(names = ">=", isModuleMethod = true, minArgs = 1, maxArgs = 1)
+    public abstract static class GreaterEqualNode extends ComparableCoreMethodNode {
+
+        public GreaterEqualNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public GreaterEqualNode(GreaterEqualNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean greaterEqual(VirtualFrame frame, RubyBasicObject self, Object comparedTo) {
+            return compare(frame, self, comparedTo) >= 0;
+        }
+
+    }
+
+    @CoreMethod(names = ">", isModuleMethod = true, minArgs = 1, maxArgs = 1)
+    public abstract static class GreaterNode extends ComparableCoreMethodNode {
+
+        public GreaterNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public GreaterNode(GreaterNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean greater(VirtualFrame frame, RubyBasicObject self, Object comparedTo) {
+            return compare(frame, self, comparedTo) > 0;
+        }
+
+    }
+
+    @CoreMethod(names = "between?", isModuleMethod = true, minArgs = 2, maxArgs = 2)
+    public abstract static class BetweenNode extends ComparableCoreMethodNode {
+
+        public BetweenNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public BetweenNode(BetweenNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean between(VirtualFrame frame, RubyBasicObject self, Object min, Object max) {
+            return !(compare(frame, self, min) < 0 || compare(frame, self, max) > 0);
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ContinuationNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+@CoreClass(name = "Continuation")
+public abstract class ContinuationNodes {
+
+    @CoreMethod(names = "call", isSplatted = true)
+    public abstract static class CallNode extends CoreMethodNode {
+
+        public CallNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public CallNode(CallNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object call(RubyContinuation continuation, Object[] args) {
+            continuation.call(args);
+            return null;
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/CoreClass.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import java.lang.annotation.*;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface CoreClass {
+
+    String name();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/CoreMethod.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import java.lang.annotation.*;
+
+import com.oracle.truffle.ruby.runtime.configuration.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface CoreMethod {
+
+    String[] names();
+
+    boolean isModuleMethod() default false;
+
+    boolean needsSelf() default true;
+
+    boolean isSplatted() default false;
+
+    boolean needsBlock() default false;
+
+    boolean appendCallNode() default false;
+
+    RubyVersion[] versions() default {RubyVersion.RUBY_18, RubyVersion.RUBY_19, RubyVersion.RUBY_20, RubyVersion.RUBY_21};
+
+    int minArgs() default Arity.NO_MINIMUM;
+
+    int maxArgs() default Arity.NO_MAXIMUM;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/CoreMethodNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+@NodeChild(value = "arguments", type = RubyNode[].class)
+public abstract class CoreMethodNode extends RubyNode {
+
+    public CoreMethodNode(RubyContext context, SourceSection sourceSection) {
+        super(context, sourceSection);
+    }
+
+    public CoreMethodNode(CoreMethodNode prev) {
+        super(prev);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/CoreMethodNodeManager.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.nodes.control.*;
+import com.oracle.truffle.ruby.nodes.debug.*;
+import com.oracle.truffle.ruby.nodes.methods.arguments.*;
+import com.oracle.truffle.ruby.nodes.objects.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+
+public abstract class CoreMethodNodeManager {
+
+    /**
+     * Register all the nodes that represent core methods as methods with their respective classes,
+     * given the Object class object, which should already be initialized with all the core classes.
+     */
+    public static void addMethods(RubyClass rubyObjectClass) {
+        for (MethodDetails methodDetails : getMethods()) {
+            if (Arrays.asList(methodDetails.getMethodAnnotation().versions()).contains(rubyObjectClass.getContext().getConfiguration().getRubyVersion())) {
+                addMethod(rubyObjectClass, methodDetails);
+            }
+        }
+    }
+
+    /**
+     * Collect up all the core method nodes. Abstracted to allow the SVM to implement at compile
+     * type.
+     */
+    public static List<MethodDetails> getMethods() {
+        final List<MethodDetails> methods = new ArrayList<>();
+        getMethods(methods, ArrayNodesFactory.getFactories());
+        getMethods(methods, BasicObjectNodesFactory.getFactories());
+        getMethods(methods, BignumNodesFactory.getFactories());
+        getMethods(methods, ClassNodesFactory.getFactories());
+        getMethods(methods, ContinuationNodesFactory.getFactories());
+        getMethods(methods, ComparableNodesFactory.getFactories());
+        getMethods(methods, DebugNodesFactory.getFactories());
+        getMethods(methods, DirNodesFactory.getFactories());
+        getMethods(methods, ExceptionNodesFactory.getFactories());
+        getMethods(methods, FalseClassNodesFactory.getFactories());
+        getMethods(methods, FiberNodesFactory.getFactories());
+        getMethods(methods, FileNodesFactory.getFactories());
+        getMethods(methods, FixnumNodesFactory.getFactories());
+        getMethods(methods, FloatNodesFactory.getFactories());
+        getMethods(methods, HashNodesFactory.getFactories());
+        getMethods(methods, KernelNodesFactory.getFactories());
+        getMethods(methods, MainNodesFactory.getFactories());
+        getMethods(methods, MatchDataNodesFactory.getFactories());
+        getMethods(methods, MathNodesFactory.getFactories());
+        getMethods(methods, ModuleNodesFactory.getFactories());
+        getMethods(methods, NilClassNodesFactory.getFactories());
+        getMethods(methods, ObjectNodesFactory.getFactories());
+        getMethods(methods, ObjectSpaceNodesFactory.getFactories());
+        getMethods(methods, ProcessNodesFactory.getFactories());
+        getMethods(methods, ProcNodesFactory.getFactories());
+        getMethods(methods, RangeNodesFactory.getFactories());
+        getMethods(methods, RegexpNodesFactory.getFactories());
+        getMethods(methods, SignalNodesFactory.getFactories());
+        getMethods(methods, StringNodesFactory.getFactories());
+        getMethods(methods, StructNodesFactory.getFactories());
+        getMethods(methods, SymbolNodesFactory.getFactories());
+        getMethods(methods, ThreadNodesFactory.getFactories());
+        getMethods(methods, TimeNodesFactory.getFactories());
+        getMethods(methods, TrueClassNodesFactory.getFactories());
+        return methods;
+    }
+
+    /**
+     * Collect up the core methods created by a factory.
+     */
+    private static void getMethods(List<MethodDetails> methods, List<? extends NodeFactory<? extends CoreMethodNode>> nodeFactories) {
+        for (NodeFactory<? extends RubyNode> nodeFactory : nodeFactories) {
+            final GeneratedBy generatedBy = nodeFactory.getClass().getAnnotation(GeneratedBy.class);
+            final Class<?> nodeClass = generatedBy.value();
+            final CoreClass classAnnotation = nodeClass.getEnclosingClass().getAnnotation(CoreClass.class);
+            final CoreMethod methodAnnotation = nodeClass.getAnnotation(CoreMethod.class);
+            methods.add(new MethodDetails(classAnnotation, methodAnnotation, nodeFactory));
+        }
+    }
+
+    /**
+     * Take a core method node factory, the annotations for the class and method, and add it as a
+     * method on the correct class.
+     */
+    private static void addMethod(RubyClass rubyObjectClass, MethodDetails methodDetails) {
+        assert rubyObjectClass != null;
+        assert methodDetails != null;
+
+        final RubyContext context = rubyObjectClass.getContext();
+
+        RubyModule module;
+
+        if (methodDetails.getClassAnnotation().name().equals("main")) {
+            module = context.getCoreLibrary().getMainObject().getSingletonClass();
+        } else {
+            module = (RubyModule) rubyObjectClass.lookupConstant(methodDetails.getClassAnnotation().name());
+        }
+
+        assert module != null : methodDetails.getClassAnnotation().name();
+
+        final List<String> names = Arrays.asList(methodDetails.getMethodAnnotation().names());
+        assert names.size() >= 1;
+
+        final String canonicalName = names.get(0);
+        final List<String> aliases = names.subList(1, names.size());
+
+        final UniqueMethodIdentifier uniqueIdentifier = new UniqueMethodIdentifier();
+        final Visibility visibility = Visibility.PUBLIC;
+
+        final RubyRootNode pristineRootNode = makeGenericMethod(context, methodDetails);
+        final CallTarget callTarget = Truffle.getRuntime().createCallTarget(NodeUtil.cloneNode(pristineRootNode));
+
+        final String intrinsicName = methodDetails.getClassAnnotation().name() + "#" + canonicalName;
+
+        final InlinableMethodImplementation methodImplementation = new InlinableMethodImplementation(callTarget, null, new FrameDescriptor(), pristineRootNode, true,
+                        methodDetails.getMethodAnnotation().appendCallNode());
+        final RubyMethod method = new RubyMethod(pristineRootNode.getSourceSection(), module, uniqueIdentifier, intrinsicName, canonicalName, visibility, false, methodImplementation);
+
+        module.addMethod(method);
+
+        if (methodDetails.getMethodAnnotation().isModuleMethod()) {
+            module.getSingletonClass().addMethod(method);
+        }
+
+        for (String alias : aliases) {
+            final RubyMethod withAlias = method.withNewName(alias);
+
+            module.addMethod(withAlias);
+
+            if (methodDetails.getMethodAnnotation().isModuleMethod()) {
+                module.getSingletonClass().addMethod(withAlias);
+            }
+        }
+    }
+
+    private static RubyRootNode makeGenericMethod(RubyContext context, MethodDetails methodDetails) {
+        final SourceSection sourceSection = new CoreSourceSection(methodDetails.getClassAnnotation().name() + "#" + methodDetails.getMethodAnnotation().names()[0]);
+
+        final Arity arity = new Arity(methodDetails.getMethodAnnotation().minArgs(), methodDetails.getMethodAnnotation().maxArgs());
+
+        final List<RubyNode> argumentsNodes = new ArrayList<>();
+
+        if (methodDetails.getMethodAnnotation().needsSelf()) {
+            argumentsNodes.add(new SelfNode(context, sourceSection));
+        }
+
+        if (methodDetails.getMethodAnnotation().isSplatted()) {
+            argumentsNodes.add(new ReadAllArgumentsNode(context, sourceSection));
+        } else {
+            assert arity.getMaximum() != Arity.NO_MAXIMUM;
+
+            for (int n = 0; n < arity.getMaximum(); n++) {
+                argumentsNodes.add(new ReadPreArgumentNode(context, sourceSection, n, true));
+            }
+        }
+
+        if (methodDetails.getMethodAnnotation().needsBlock()) {
+            argumentsNodes.add(new ReadBlockArgumentNode(context, sourceSection, true));
+        }
+
+        final RubyNode methodNode = methodDetails.getNodeFactory().createNode(context, sourceSection, argumentsNodes.toArray(new RubyNode[argumentsNodes.size()]));
+        final CheckArityNode checkArity = new CheckArityNode(context, sourceSection, arity);
+        final SequenceNode block = new SequenceNode(context, sourceSection, checkArity, methodNode);
+
+        return new RubyRootNode(sourceSection, methodDetails.getClassAnnotation().name() + "#" + methodDetails.getMethodAnnotation().names()[0] + "(core)", block);
+    }
+
+    public static class MethodDetails {
+
+        private final CoreClass classAnnotation;
+        private final CoreMethod methodAnnotation;
+        private final NodeFactory<? extends RubyNode> nodeFactory;
+
+        public MethodDetails(CoreClass classAnnotation, CoreMethod methodAnnotation, NodeFactory<? extends RubyNode> nodeFactory) {
+            assert classAnnotation != null;
+            assert methodAnnotation != null;
+            assert nodeFactory != null;
+            this.classAnnotation = classAnnotation;
+            this.methodAnnotation = methodAnnotation;
+            this.nodeFactory = nodeFactory;
+        }
+
+        public CoreClass getClassAnnotation() {
+            return classAnnotation;
+        }
+
+        public CoreMethod getMethodAnnotation() {
+            return methodAnnotation;
+        }
+
+        public NodeFactory<? extends RubyNode> getNodeFactory() {
+            return nodeFactory;
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/DirNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import java.io.*;
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+
+import com.oracle.truffle.api.CompilerDirectives.SlowPath;
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+@CoreClass(name = "Dir")
+public abstract class DirNodes {
+
+    @CoreMethod(names = "[]", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1)
+    public abstract static class GlobNode extends CoreMethodNode {
+
+        public GlobNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public GlobNode(GlobNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray glob(RubyString glob) {
+            return glob(getContext(), glob.toString());
+        }
+
+        @SlowPath
+        private static RubyArray glob(final RubyContext context, String glob) {
+            /*
+             * Globbing is quite complicated. We've implemented a subset of the functionality that
+             * satisfies MSpec, but it will likely break for anyone else.
+             */
+
+            context.implementationMessage("globbing %s", glob);
+
+            String absoluteGlob;
+
+            if (!glob.startsWith("/")) {
+                absoluteGlob = new File(".", glob).getAbsolutePath().toString();
+            } else {
+                absoluteGlob = glob;
+            }
+
+            // Get the first star
+
+            final int firstStar = absoluteGlob.indexOf('*');
+            assert firstStar >= 0;
+
+            // Walk back from that to the first / before that star
+
+            int prefixLength = firstStar;
+
+            while (prefixLength > 0 && absoluteGlob.charAt(prefixLength) == File.separatorChar) {
+                prefixLength--;
+            }
+
+            final String prefix = absoluteGlob.substring(0, prefixLength - 1);
+
+            final PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:" + absoluteGlob.substring(prefixLength));
+
+            final RubyArray array = new RubyArray(context.getCoreLibrary().getArrayClass());
+
+            try {
+                Files.walkFileTree(FileSystems.getDefault().getPath(prefix), new SimpleFileVisitor<Path>() {
+
+                    @Override
+                    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                        if (matcher.matches(file)) {
+                            array.push(context.makeString(file.toString()));
+                        }
+
+                        return FileVisitResult.CONTINUE;
+                    }
+
+                });
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+
+            return array;
+        }
+
+    }
+
+    @CoreMethod(names = "chdir", isModuleMethod = true, needsSelf = false, needsBlock = true, minArgs = 1, maxArgs = 1)
+    public abstract static class ChdirNode extends YieldingCoreMethodNode {
+
+        public ChdirNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ChdirNode(ChdirNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object chdir(VirtualFrame frame, RubyString path, RubyProc block) {
+            final RubyContext context = getContext();
+
+            final String previous = context.getCurrentDirectory();
+            context.setCurrentDirectory(path.toString());
+
+            if (block != null) {
+                try {
+                    return yield(frame, block, path);
+                } finally {
+                    context.setCurrentDirectory(previous);
+                }
+            } else {
+                return 0;
+            }
+        }
+
+    }
+
+    @CoreMethod(names = {"exist?", "exists?"}, isModuleMethod = true, needsSelf = false, maxArgs = 1)
+    public abstract static class ExistsNode extends CoreMethodNode {
+
+        public ExistsNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ExistsNode(ExistsNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean exists(RubyString path) {
+            return new File(path.toString()).isDirectory();
+        }
+
+    }
+
+    @CoreMethod(names = "pwd", isModuleMethod = true, needsSelf = false, maxArgs = 0)
+    public abstract static class PwdNode extends CoreMethodNode {
+
+        public PwdNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public PwdNode(PwdNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString pwd() {
+            return getContext().makeString(getContext().getCurrentDirectory());
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ExceptionNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+@CoreClass(name = "Exception")
+public abstract class ExceptionNodes {
+
+    @CoreMethod(names = "initialize", minArgs = 0, maxArgs = 1)
+    public abstract static class InitializeNode extends CoreMethodNode {
+
+        public InitializeNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public InitializeNode(InitializeNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder initialize(RubyException exception, @SuppressWarnings("unused") UndefinedPlaceholder message) {
+            exception.initialize(getContext().makeString(" "));
+            return NilPlaceholder.INSTANCE;
+        }
+
+        @Specialization
+        public NilPlaceholder initialize(RubyException exception, RubyString message) {
+            exception.initialize(message);
+            return NilPlaceholder.INSTANCE;
+        }
+
+    }
+
+    @CoreMethod(names = "backtrace", needsSelf = false, maxArgs = 0)
+    public abstract static class BacktraceNode extends CoreMethodNode {
+
+        public BacktraceNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public BacktraceNode(BacktraceNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray backtrace() {
+            return new RubyArray(getContext().getCoreLibrary().getArrayClass());
+        }
+
+    }
+
+    @CoreMethod(names = "message", maxArgs = 0)
+    public abstract static class MessageNode extends CoreMethodNode {
+
+        public MessageNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public MessageNode(MessageNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString message(RubyException exception) {
+            return exception.getMessage();
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FalseClassNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+@CoreClass(name = "FalseClass")
+public abstract class FalseClassNodes {
+
+    @CoreMethod(names = "!", needsSelf = false, maxArgs = 0)
+    public abstract static class NotNode extends CoreMethodNode {
+
+        public NotNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public NotNode(NotNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean not() {
+            return true;
+        }
+
+    }
+
+    @CoreMethod(names = {"==", "===", "=~"}, needsSelf = false, minArgs = 1, maxArgs = 1)
+    public abstract static class EqualNode extends CoreMethodNode {
+
+        public EqualNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public EqualNode(EqualNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean equal(boolean other) {
+            return !other;
+        }
+
+        @Specialization
+        public boolean equal(Object other) {
+            return other instanceof Boolean && !((boolean) other);
+        }
+
+    }
+
+    @CoreMethod(names = "^", needsSelf = false, minArgs = 1, maxArgs = 1)
+    public abstract static class XorNode extends CoreMethodNode {
+
+        public XorNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public XorNode(XorNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean xor(boolean other) {
+            return false ^ other;
+        }
+
+    }
+
+    @CoreMethod(names = "to_s", needsSelf = false, maxArgs = 0)
+    public abstract static class ToSNode extends CoreMethodNode {
+
+        public ToSNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ToSNode(ToSNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString toS() {
+            return getContext().makeString("false");
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FiberNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+@CoreClass(name = "Fiber")
+public abstract class FiberNodes {
+
+    @CoreMethod(names = "resume", isSplatted = true)
+    public abstract static class ResumeNode extends CoreMethodNode {
+
+        public ResumeNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ResumeNode(ResumeNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object resume(RubyFiber fiberBeingResumed, Object[] args) {
+            final RubyFiber sendingFiber = getContext().getFiberManager().getCurrentFiber();
+
+            fiberBeingResumed.resume(sendingFiber, args);
+
+            return sendingFiber.waitForResume();
+        }
+
+    }
+
+    @CoreMethod(names = "initialize", needsBlock = true, maxArgs = 0)
+    public abstract static class InitializeNode extends CoreMethodNode {
+
+        public InitializeNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public InitializeNode(InitializeNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder initialize(RubyFiber fiber, RubyProc block) {
+            fiber.initialize(block);
+            return NilPlaceholder.INSTANCE;
+        }
+
+    }
+
+    @CoreMethod(names = "yield", isModuleMethod = true, needsSelf = false, isSplatted = true)
+    public abstract static class YieldNode extends CoreMethodNode {
+
+        public YieldNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public YieldNode(YieldNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object yield(Object[] args) {
+            final RubyFiber yieldingFiber = getContext().getFiberManager().getCurrentFiber();
+            final RubyFiber fiberYieldedTo = yieldingFiber.lastResumedByFiber;
+
+            fiberYieldedTo.resume(yieldingFiber, args);
+
+            return yieldingFiber.waitForResume();
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FileNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import java.io.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+@CoreClass(name = "File")
+public abstract class FileNodes {
+
+    @CoreMethod(names = "absolute_path", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1)
+    public abstract static class AbsolutePathNode extends CoreMethodNode {
+
+        public AbsolutePathNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public AbsolutePathNode(AbsolutePathNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString absolutePath(RubyString path) {
+            return getContext().makeString(new File(path.toString()).getAbsolutePath());
+        }
+
+    }
+
+    @CoreMethod(names = "close", maxArgs = 0)
+    public abstract static class CloseNode extends CoreMethodNode {
+
+        public CloseNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public CloseNode(CloseNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder close(RubyFile file) {
+            file.close();
+            return NilPlaceholder.INSTANCE;
+        }
+
+    }
+
+    @CoreMethod(names = "directory?", isModuleMethod = true, needsSelf = false, maxArgs = 1)
+    public abstract static class DirectoryNode extends CoreMethodNode {
+
+        public DirectoryNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public DirectoryNode(DirectoryNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean directory(RubyString path) {
+            return new File(path.toString()).isDirectory();
+        }
+
+    }
+
+    @CoreMethod(names = "dirname", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1)
+    public abstract static class DirnameNode extends CoreMethodNode {
+
+        public DirnameNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public DirnameNode(DirnameNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString dirname(RubyString path) {
+            final String parent = new File(path.toString()).getParent();
+
+            if (parent == null) {
+                return getContext().makeString(".");
+            } else {
+                return getContext().makeString(parent);
+            }
+        }
+
+    }
+
+    @CoreMethod(names = "each_line", needsBlock = true, maxArgs = 0)
+    public abstract static class EachLineNode extends YieldingCoreMethodNode {
+
+        public EachLineNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public EachLineNode(EachLineNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder eachLine(VirtualFrame frame, RubyFile file, RubyProc block) {
+            final RubyContext context = getContext();
+
+            // TODO(cs): this buffered reader may consume too much
+
+            final BufferedReader lineReader = new BufferedReader(file.getReader());
+
+            while (true) {
+                String line;
+
+                try {
+                    line = lineReader.readLine();
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+
+                if (line == null) {
+                    break;
+                }
+
+                yield(frame, block, context.makeString(line));
+            }
+
+            return NilPlaceholder.INSTANCE;
+        }
+
+    }
+
+    @CoreMethod(names = {"exist?", "exists?"}, isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1)
+    public abstract static class ExistsNode extends CoreMethodNode {
+
+        public ExistsNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ExistsNode(ExistsNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean exists(RubyString path) {
+            return new File(path.toString()).isFile();
+        }
+
+    }
+
+    @CoreMethod(names = "executable?", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1)
+    public abstract static class ExecutableNode extends CoreMethodNode {
+
+        public ExecutableNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ExecutableNode(ExecutableNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean executable(RubyString path) {
+            return new File(path.toString()).canExecute();
+        }
+
+    }
+
+    @CoreMethod(names = "expand_path", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 2)
+    public abstract static class ExpandPathNode extends CoreMethodNode {
+
+        public ExpandPathNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ExpandPathNode(ExpandPathNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString expandPath(RubyString path, @SuppressWarnings("unused") UndefinedPlaceholder dir) {
+            return getContext().makeString(RubyFile.expandPath(path.toString()));
+        }
+
+        @Specialization
+        public RubyString expandPath(RubyString path, RubyString dir) {
+            return getContext().makeString(RubyFile.expandPath(path.toString(), dir.toString()));
+        }
+
+    }
+
+    @CoreMethod(names = "file?", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1)
+    public abstract static class FileNode extends CoreMethodNode {
+
+        public FileNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public FileNode(FileNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean file(RubyString path) {
+            return new File(path.toString()).isFile();
+        }
+
+    }
+
+    @CoreMethod(names = "join", isModuleMethod = true, needsSelf = false, isSplatted = true)
+    public abstract static class JoinNode extends CoreMethodNode {
+
+        public JoinNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public JoinNode(JoinNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString join(Object[] parts) {
+            return getContext().makeString(RubyArray.join(parts, File.separator));
+        }
+    }
+
+    @CoreMethod(names = "open", isModuleMethod = true, needsSelf = false, needsBlock = true, minArgs = 2, maxArgs = 2)
+    public abstract static class OpenNode extends YieldingCoreMethodNode {
+
+        public OpenNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public OpenNode(OpenNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object open(VirtualFrame frame, RubyString fileName, RubyString mode, RubyProc block) {
+            final RubyFile file = RubyFile.open(getContext(), fileName.toString(), mode.toString());
+
+            if (block != null) {
+                try {
+                    yield(frame, block, file);
+                } finally {
+                    file.close();
+                }
+            }
+
+            return file;
+        }
+
+    }
+
+    @CoreMethod(names = "write", maxArgs = 0)
+    public abstract static class WriteNode extends CoreMethodNode {
+
+        public WriteNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public WriteNode(WriteNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder write(RubyFile file, RubyString string) {
+            try {
+                final Writer writer = file.getWriter();
+                writer.write(string.toString());
+                writer.flush();
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+
+            return NilPlaceholder.INSTANCE;
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FixnumNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,853 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import java.math.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+@CoreClass(name = "Fixnum")
+public abstract class FixnumNodes {
+
+    @CoreMethod(names = "+@", maxArgs = 0)
+    public abstract static class PosNode extends CoreMethodNode {
+
+        public PosNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public PosNode(PosNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public int pos(int value) {
+            return value;
+        }
+
+    }
+
+    @CoreMethod(names = "-@", maxArgs = 0)
+    public abstract static class NegNode extends CoreMethodNode {
+
+        public NegNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public NegNode(NegNode prev) {
+            super(prev);
+        }
+
+        @Specialization(rewriteOn = ArithmeticException.class)
+        public int neg(int value) {
+            return ExactMath.subtractExact(0, value);
+        }
+
+        @Specialization
+        public BigInteger negWithOverflow(int value) {
+            return BigInteger.valueOf(value).negate();
+        }
+
+    }
+
+    @CoreMethod(names = "+", minArgs = 1, maxArgs = 1)
+    public abstract static class AddNode extends CoreMethodNode {
+
+        public AddNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public AddNode(AddNode prev) {
+            super(prev);
+        }
+
+        @Specialization(rewriteOn = ArithmeticException.class)
+        public int add(int a, int b) {
+            return ExactMath.addExact(a, b);
+        }
+
+        @Specialization
+        public Object addWithOverflow(int a, int b) {
+            return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).add(BigInteger.valueOf(b)));
+        }
+
+        @Specialization
+        public double add(int a, double b) {
+            return a + b;
+        }
+
+        @Specialization
+        public Object add(int a, BigInteger b) {
+            return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).add(b));
+        }
+
+    }
+
+    @CoreMethod(names = "-", minArgs = 1, maxArgs = 1)
+    public abstract static class SubNode extends CoreMethodNode {
+
+        public SubNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public SubNode(SubNode prev) {
+            super(prev);
+        }
+
+        @Specialization(rewriteOn = ArithmeticException.class)
+        public int sub(int a, int b) {
+            return ExactMath.subtractExact(a, b);
+        }
+
+        @Specialization
+        public Object subWithOverflow(int a, int b) {
+            return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).subtract(BigInteger.valueOf(b)));
+        }
+
+        @Specialization
+        public double sub(int a, double b) {
+            return a - b;
+        }
+
+        @Specialization
+        public Object sub(int a, BigInteger b) {
+            return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).subtract(b));
+        }
+
+    }
+
+    @CoreMethod(names = "*", minArgs = 1, maxArgs = 1)
+    public abstract static class MulNode extends CoreMethodNode {
+
+        public MulNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public MulNode(MulNode prev) {
+            super(prev);
+        }
+
+        @Specialization(rewriteOn = ArithmeticException.class)
+        public int mul(int a, int b) {
+            return ExactMath.multiplyExact(a, b);
+        }
+
+        @Specialization
+        public Object mulWithOverflow(int a, int b) {
+            return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).multiply(BigInteger.valueOf(b)));
+        }
+
+        @Specialization
+        public double mul(int a, double b) {
+            return a * b;
+        }
+
+        @Specialization
+        public Object mul(int a, BigInteger b) {
+            return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).multiply(b));
+        }
+
+    }
+
+    @CoreMethod(names = "**", minArgs = 1, maxArgs = 1)
+    public abstract static class PowNode extends CoreMethodNode {
+
+        public PowNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public PowNode(PowNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object pow(int a, int b) {
+            return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).pow(b));
+        }
+
+        @Specialization
+        public double pow(int a, double b) {
+            return Math.pow(a, b);
+        }
+
+        @Specialization
+        public Object pow(int a, BigInteger b) {
+            final BigInteger bigA = BigInteger.valueOf(a);
+
+            BigInteger result = BigInteger.ONE;
+
+            for (BigInteger n = BigInteger.ZERO; b.compareTo(b) < 0; n = n.add(BigInteger.ONE)) {
+                result = result.multiply(bigA);
+            }
+
+            return result;
+        }
+
+    }
+
+    @CoreMethod(names = "/", minArgs = 1, maxArgs = 1)
+    public abstract static class DivNode extends CoreMethodNode {
+
+        public DivNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public DivNode(DivNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public int div(int a, int b) {
+            return a / b;
+        }
+
+        @Specialization
+        public double div(int a, double b) {
+            return a / b;
+        }
+
+        @Specialization
+        public int div(@SuppressWarnings("unused") int a, @SuppressWarnings("unused") BigInteger b) {
+            return 0;
+        }
+    }
+
+    @CoreMethod(names = "%", minArgs = 1, maxArgs = 1)
+    public abstract static class ModNode extends CoreMethodNode {
+
+        public ModNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ModNode(ModNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public int mod(int a, int b) {
+            return a % b;
+        }
+
+        @Specialization
+        public double mod(@SuppressWarnings("unused") int a, @SuppressWarnings("unused") double b) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Specialization
+        public BigInteger mod(@SuppressWarnings("unused") int a, BigInteger b) {
+            return b;
+        }
+    }
+
+    @CoreMethod(names = "divmod", minArgs = 1, maxArgs = 1)
+    public abstract static class DivModNode extends CoreMethodNode {
+
+        public DivModNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public DivModNode(DivModNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray divMod(int a, int b) {
+            int q;
+
+            if (b < 0) {
+                if (a < 0) {
+                    q = -a / -b;
+                } else {
+                    q = -(a / -b);
+                }
+            } else {
+                if (a < 0) {
+                    q = -(-a / b);
+                } else {
+                    q = a / b;
+                }
+            }
+
+            int r = a - q * b;
+
+            if ((r < 0 && b > 0) || (r > 0 && b < 0)) {
+                r += b;
+                q -= 1;
+            }
+
+            final FixnumImmutablePairArrayStore store = new FixnumImmutablePairArrayStore(q, r);
+            return new RubyArray(getContext().getCoreLibrary().getArrayClass(), store);
+        }
+
+        @Specialization
+        public RubyArray divMod(@SuppressWarnings("unused") int a, @SuppressWarnings("unused") double b) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Specialization
+        public RubyArray divMod(int a, BigInteger b) {
+            return RubyBignum.divMod(getContext(), BigInteger.valueOf(a), b);
+        }
+    }
+
+    @CoreMethod(names = "<", minArgs = 1, maxArgs = 1)
+    public abstract static class LessNode extends CoreMethodNode {
+
+        public LessNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public LessNode(LessNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean less(int a, int b) {
+            return a < b;
+        }
+
+        @Specialization
+        public boolean less(int a, double b) {
+            return a < b;
+        }
+
+        @Specialization
+        public boolean less(int a, BigInteger b) {
+            return BigInteger.valueOf(a).compareTo(b) < 0;
+        }
+    }
+
+    @CoreMethod(names = "<=", minArgs = 1, maxArgs = 1)
+    public abstract static class LessEqualNode extends CoreMethodNode {
+
+        public LessEqualNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public LessEqualNode(LessEqualNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean lessEqual(int a, int b) {
+            return a <= b;
+        }
+
+        @Specialization
+        public boolean lessEqual(int a, double b) {
+            return a <= b;
+        }
+
+        @Specialization
+        public boolean lessEqual(int a, BigInteger b) {
+            return BigInteger.valueOf(a).compareTo(b) <= 0;
+        }
+    }
+
+    @CoreMethod(names = {"==", "==="}, minArgs = 1, maxArgs = 1)
+    public abstract static class EqualNode extends CoreMethodNode {
+
+        public EqualNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public EqualNode(EqualNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean equal(int a, int b) {
+            return a == b;
+        }
+
+        @Specialization
+        public boolean equal(int a, double b) {
+            return a == b;
+        }
+
+        @Specialization
+        public boolean equal(int a, BigInteger b) {
+            return BigInteger.valueOf(a).compareTo(b) == 0;
+        }
+    }
+
+    @CoreMethod(names = "<=>", minArgs = 1, maxArgs = 1)
+    public abstract static class CompareNode extends CoreMethodNode {
+
+        public CompareNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public CompareNode(CompareNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public int compare(int a, int b) {
+            return Integer.compare(a, b);
+        }
+
+        @Specialization
+        public int compare(int a, double b) {
+            return Double.compare(a, b);
+        }
+
+        @Specialization
+        public int compare(int a, BigInteger b) {
+            return BigInteger.valueOf(a).compareTo(b);
+        }
+    }
+
+    @CoreMethod(names = "!=", minArgs = 1, maxArgs = 1)
+    public abstract static class NotEqualNode extends CoreMethodNode {
+
+        public NotEqualNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public NotEqualNode(NotEqualNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean notEqual(int a, int b) {
+            return a != b;
+        }
+
+        @Specialization
+        public boolean notEqual(int a, double b) {
+            return a != b;
+        }
+
+        @Specialization
+        public boolean notEqual(int a, BigInteger b) {
+            return BigInteger.valueOf(a).compareTo(b) != 0;
+        }
+    }
+
+    @CoreMethod(names = ">=", minArgs = 1, maxArgs = 1)
+    public abstract static class GreaterEqualNode extends CoreMethodNode {
+
+        public GreaterEqualNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public GreaterEqualNode(GreaterEqualNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean greaterEqual(int a, int b) {
+            return a >= b;
+        }
+
+        @Specialization
+        public boolean greaterEqual(int a, double b) {
+            return a >= b;
+        }
+
+        @Specialization
+        public boolean greaterEqual(int a, BigInteger b) {
+            return BigInteger.valueOf(a).compareTo(b) >= 0;
+        }
+    }
+
+    @CoreMethod(names = ">", minArgs = 1, maxArgs = 1)
+    public abstract static class GreaterNode extends CoreMethodNode {
+
+        public GreaterNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public GreaterNode(GreaterNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean equal(int a, int b) {
+            return a > b;
+        }
+
+        @Specialization
+        public boolean equal(int a, double b) {
+            return a > b;
+        }
+
+        @Specialization
+        public boolean equal(int a, BigInteger b) {
+            return BigInteger.valueOf(a).compareTo(b) > 0;
+        }
+    }
+
+    @CoreMethod(names = "~", maxArgs = 0)
+    public abstract static class ComplementNode extends CoreMethodNode {
+
+        public ComplementNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ComplementNode(ComplementNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public int complement(int n) {
+            return ~n;
+        }
+
+    }
+
+    @CoreMethod(names = "&", minArgs = 1, maxArgs = 1)
+    public abstract static class BitAndNode extends CoreMethodNode {
+
+        public BitAndNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public BitAndNode(BitAndNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public int bitAnd(int a, int b) {
+            return a & b;
+        }
+
+        @Specialization
+        public Object bitAnd(int a, BigInteger b) {
+            return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).and(b));
+        }
+    }
+
+    @CoreMethod(names = "|", minArgs = 1, maxArgs = 1)
+    public abstract static class BitOrNode extends CoreMethodNode {
+
+        public BitOrNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public BitOrNode(BitOrNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public int bitOr(int a, int b) {
+            return a | b;
+        }
+
+        @Specialization
+        public Object bitOr(int a, BigInteger b) {
+            return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).or(b));
+        }
+    }
+
+    @CoreMethod(names = "^", minArgs = 1, maxArgs = 1)
+    public abstract static class BitXOrNode extends CoreMethodNode {
+
+        public BitXOrNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public BitXOrNode(BitXOrNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public int bitXOr(int a, int b) {
+            return a ^ b;
+        }
+
+        @Specialization
+        public Object bitXOr(int a, BigInteger b) {
+            return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).xor(b));
+        }
+    }
+
+    @CoreMethod(names = "<<", minArgs = 1, maxArgs = 1)
+    public abstract static class LeftShiftNode extends CoreMethodNode {
+
+        public LeftShiftNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public LeftShiftNode(LeftShiftNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object leftShift(int a, int b) {
+            if (b > 0) {
+                if (RubyFixnum.SIZE - Integer.numberOfLeadingZeros(a) + b > RubyFixnum.SIZE - 1) {
+                    return GeneralConversions.fixnumOrBignum(BigInteger.valueOf(a).shiftLeft(b));
+                } else {
+                    return a << b;
+                }
+            } else {
+                if (-b >= Integer.SIZE) {
+                    return 0;
+                } else {
+                    return a >> -b;
+                }
+            }
+        }
+
+    }
+
+    @CoreMethod(names = ">>", minArgs = 1, maxArgs = 1)
+    public abstract static class RightShiftNode extends CoreMethodNode {
+
+        public RightShiftNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public RightShiftNode(RightShiftNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public int rightShift(int a, int b) {
+            if (b > 0) {
+                return a >> b;
+            } else {
+                if (-b >= RubyFixnum.SIZE) {
+                    return 0;
+                } else {
+                    return a >> -b;
+                }
+            }
+        }
+
+    }
+
+    @CoreMethod(names = "[]", minArgs = 1, maxArgs = 1)
+    public abstract static class GetIndexNode extends CoreMethodNode {
+
+        public GetIndexNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public GetIndexNode(GetIndexNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public int getIndex(int self, int index) {
+            if ((self & (1 << index)) == 0) {
+                return 0;
+            } else {
+                return 1;
+            }
+        }
+
+    }
+
+    @CoreMethod(names = "chr", maxArgs = 0)
+    public abstract static class ChrNode extends CoreMethodNode {
+
+        public ChrNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ChrNode(ChrNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString chr(int n) {
+            // TODO(CS): not sure about encoding here
+            return getContext().makeString((char) n);
+        }
+
+    }
+
+    @CoreMethod(names = "inspect", maxArgs = 0)
+    public abstract static class InpsectNode extends CoreMethodNode {
+
+        public InpsectNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public InpsectNode(InpsectNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString inspect(int n) {
+            return getContext().makeString(Integer.toString(n));
+        }
+
+    }
+
+    @CoreMethod(names = "nonzero?", maxArgs = 0)
+    public abstract static class NonZeroNode extends CoreMethodNode {
+
+        public NonZeroNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public NonZeroNode(NonZeroNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object nonZero(int value) {
+            if (value == 0) {
+                return false;
+            } else {
+                return value;
+            }
+        }
+
+    }
+
+    @CoreMethod(names = "size", needsSelf = false, maxArgs = 0)
+    public abstract static class SizeNode extends CoreMethodNode {
+
+        public SizeNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public SizeNode(SizeNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public int size() {
+            return Integer.SIZE / Byte.SIZE;
+        }
+
+    }
+
+    @CoreMethod(names = "step", needsBlock = true, minArgs = 2, maxArgs = 2)
+    public abstract static class StepNode extends YieldingCoreMethodNode {
+
+        public StepNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public StepNode(StepNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder step(VirtualFrame frame, int from, int to, int step, RubyProc block) {
+            for (int i = from; i <= to; i += step) {
+                yield(frame, block, i);
+            }
+
+            return NilPlaceholder.INSTANCE;
+        }
+
+    }
+
+    @CoreMethod(names = "times", needsBlock = true, maxArgs = 0)
+    public abstract static class TimesNode extends YieldingCoreMethodNode {
+
+        public TimesNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public TimesNode(TimesNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public int times(VirtualFrame frame, int n, RubyProc block) {
+            for (int i = 0; i < n; i++) {
+                yield(frame, block, i);
+            }
+
+            return n;
+        }
+
+    }
+
+    @CoreMethod(names = {"to_i", "to_int"}, maxArgs = 0)
+    public abstract static class ToINode extends CoreMethodNode {
+
+        public ToINode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ToINode(ToINode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public int toI(int n) {
+            return n;
+        }
+
+    }
+
+    @CoreMethod(names = "to_f", maxArgs = 0)
+    public abstract static class ToFNode extends CoreMethodNode {
+
+        public ToFNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ToFNode(ToFNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public double toF(int n) {
+            return n;
+        }
+
+    }
+
+    @CoreMethod(names = "to_s", maxArgs = 0)
+    public abstract static class ToSNode extends CoreMethodNode {
+
+        public ToSNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ToSNode(ToSNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString toS(int n) {
+            return getContext().makeString(Integer.toString(n));
+        }
+
+    }
+
+    @CoreMethod(names = "upto", needsBlock = true, minArgs = 1, maxArgs = 1)
+    public abstract static class UpToNode extends YieldingCoreMethodNode {
+
+        public UpToNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public UpToNode(UpToNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder upto(VirtualFrame frame, int from, int to, RubyProc block) {
+            for (int i = from; i <= to; i++) {
+                yield(frame, block, i);
+            }
+
+            return NilPlaceholder.INSTANCE;
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/FloatNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import java.math.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+@CoreClass(name = "Float")
+public abstract class FloatNodes {
+
+    @CoreMethod(names = "+@", maxArgs = 0)
+    public abstract static class PosNode extends CoreMethodNode {
+
+        public PosNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public PosNode(PosNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public double pos(double value) {
+            return value;
+        }
+
+    }
+
+    @CoreMethod(names = "-@", maxArgs = 0)
+    public abstract static class NegNode extends CoreMethodNode {
+
+        public NegNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public NegNode(NegNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public double neg(double value) {
+            return -value;
+        }
+
+    }
+
+    @CoreMethod(names = "+", minArgs = 1, maxArgs = 1)
+    public abstract static class AddNode extends CoreMethodNode {
+
+        public AddNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public AddNode(AddNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public double add(double a, int b) {
+            return a + b;
+        }
+
+        @Specialization
+        public double add(double a, double b) {
+            return a + b;
+        }
+
+        @Specialization
+        public double add(double a, BigInteger b) {
+            return a + b.doubleValue();
+        }
+
+    }
+
+    @CoreMethod(names = "-", minArgs = 1, maxArgs = 1)
+    public abstract static class SubNode extends CoreMethodNode {
+
+        public SubNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public SubNode(SubNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public double sub(double a, int b) {
+            return a - b;
+        }
+
+        @Specialization
+        public double sub(double a, double b) {
+            return a - b;
+        }
+
+        @Specialization
+        public double sub(double a, BigInteger b) {
+            return a - b.doubleValue();
+        }
+
+    }
+
+    @CoreMethod(names = "*", minArgs = 1, maxArgs = 1)
+    public abstract static class MulNode extends CoreMethodNode {
+
+        public MulNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public MulNode(MulNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public double mul(double a, int b) {
+            return a * b;
+        }
+
+        @Specialization
+        public double mul(double a, double b) {
+            return a * b;
+        }
+
+        @Specialization
+        public double mul(double a, BigInteger b) {
+            return a * b.doubleValue();
+        }
+
+    }
+
+    @CoreMethod(names = "**", minArgs = 1, maxArgs = 1)
+    public abstract static class PowNode extends CoreMethodNode {
+
+        public PowNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public PowNode(PowNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public double mul(double a, int b) {
+            return Math.pow(a, b);
+        }
+
+        @Specialization
+        public double mul(double a, double b) {
+            return Math.pow(a, b);
+        }
+
+        @Specialization
+        public double mul(double a, BigInteger b) {
+            return Math.pow(a, b.doubleValue());
+        }
+
+    }
+
+    @CoreMethod(names = "/", minArgs = 1, maxArgs = 1)
+    public abstract static class DivNode extends CoreMethodNode {
+
+        public DivNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public DivNode(DivNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public double div(double a, int b) {
+            return a / b;
+        }
+
+        @Specialization
+        public double div(double a, double b) {
+            return a / b;
+        }
+
+        @Specialization
+        public double div(double a, BigInteger b) {
+            return a / b.doubleValue();
+        }
+
+    }
+
+    @CoreMethod(names = "%", minArgs = 1, maxArgs = 1)
+    public abstract static class ModNode extends CoreMethodNode {
+
+        public ModNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ModNode(ModNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public double mod(@SuppressWarnings("unused") double a, @SuppressWarnings("unused") int b) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Specialization
+        public double mod(@SuppressWarnings("unused") double a, @SuppressWarnings("unused") double b) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Specialization
+        public double mod(@SuppressWarnings("unused") double a, @SuppressWarnings("unused") BigInteger b) {
+            throw new UnsupportedOperationException();
+        }
+
+    }
+
+    @CoreMethod(names = "divmod", minArgs = 1, maxArgs = 1)
+    public abstract static class DivModNode extends CoreMethodNode {
+
+        public DivModNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public DivModNode(DivModNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray divMod(@SuppressWarnings("unused") double a, @SuppressWarnings("unused") int b) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Specialization
+        public RubyArray divMod(@SuppressWarnings("unused") double a, @SuppressWarnings("unused") double b) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Specialization
+        public RubyArray divMod(@SuppressWarnings("unused") double a, @SuppressWarnings("unused") BigInteger b) {
+            throw new UnsupportedOperationException();
+        }
+
+    }
+
+    @CoreMethod(names = "<", minArgs = 1, maxArgs = 1)
+    public abstract static class LessNode extends CoreMethodNode {
+
+        public LessNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public LessNode(LessNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean less(double a, int b) {
+            return a < b;
+        }
+
+        @Specialization
+        public boolean less(double a, double b) {
+            return a < b;
+        }
+
+        @Specialization
+        public boolean less(double a, BigInteger b) {
+            return BigInteger.valueOf((long) a).compareTo(b) < 0;
+        }
+    }
+
+    @CoreMethod(names = "<=", minArgs = 1, maxArgs = 1)
+    public abstract static class LessEqualNode extends CoreMethodNode {
+
+        public LessEqualNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public LessEqualNode(LessEqualNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean lessEqual(double a, int b) {
+            return a <= b;
+        }
+
+        @Specialization
+        public boolean lessEqual(double a, double b) {
+            return a <= b;
+        }
+
+        @Specialization
+        public boolean lessEqual(double a, BigInteger b) {
+            return BigInteger.valueOf((long) a).compareTo(b) <= 0;
+        }
+    }
+
+    @CoreMethod(names = "==", minArgs = 1, maxArgs = 1)
+    public abstract static class EqualNode extends CoreMethodNode {
+
+        public EqualNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public EqualNode(EqualNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean equal(double a, int b) {
+            return a == b;
+        }
+
+        @Specialization
+        public boolean equal(double a, double b) {
+            return a == b;
+        }
+
+        @Specialization
+        public boolean equal(double a, BigInteger b) {
+            return BigInteger.valueOf((long) a).compareTo(b) == 0;
+        }
+    }
+
+    @CoreMethod(names = "!=", minArgs = 1, maxArgs = 1)
+    public abstract static class NotEqualNode extends CoreMethodNode {
+
+        public NotEqualNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public NotEqualNode(NotEqualNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean notEqual(double a, int b) {
+            return a != b;
+        }
+
+        @Specialization
+        public boolean notEqual(double a, double b) {
+            return a != b;
+        }
+
+        @Specialization
+        public boolean notEqual(double a, BigInteger b) {
+            return BigInteger.valueOf((long) a).compareTo(b) != 0;
+        }
+    }
+
+    @CoreMethod(names = ">=", minArgs = 1, maxArgs = 1)
+    public abstract static class GreaterEqualNode extends CoreMethodNode {
+
+        public GreaterEqualNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public GreaterEqualNode(GreaterEqualNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean greaterEqual(double a, int b) {
+            return a >= b;
+        }
+
+        @Specialization
+        public boolean greaterEqual(double a, double b) {
+            return a >= b;
+        }
+
+        @Specialization
+        public boolean greaterEqual(double a, BigInteger b) {
+            return BigInteger.valueOf((long) a).compareTo(b) >= 0;
+        }
+    }
+
+    @CoreMethod(names = ">", minArgs = 1, maxArgs = 1)
+    public abstract static class GreaterNode extends CoreMethodNode {
+
+        public GreaterNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public GreaterNode(GreaterNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean equal(double a, int b) {
+            return a > b;
+        }
+
+        @Specialization
+        public boolean equal(double a, double b) {
+            return a > b;
+        }
+
+        @Specialization
+        public boolean equal(double a, BigInteger b) {
+            return BigInteger.valueOf((long) a).compareTo(b) > 0;
+        }
+    }
+
+    @CoreMethod(names = "abs", maxArgs = 0)
+    public abstract static class AbsNode extends CoreMethodNode {
+
+        public AbsNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public AbsNode(AbsNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public double abs(double n) {
+            return Math.abs(n);
+        }
+
+    }
+
+    @CoreMethod(names = "inspect", maxArgs = 0)
+    public abstract static class InpsectNode extends CoreMethodNode {
+
+        public InpsectNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public InpsectNode(InpsectNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString inspect(double n) {
+            return getContext().makeString(Double.toString(n));
+        }
+
+    }
+
+    @CoreMethod(names = "nonzero?", maxArgs = 0)
+    public abstract static class NonZeroNode extends CoreMethodNode {
+
+        public NonZeroNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public NonZeroNode(NonZeroNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object nonZero(double value) {
+            if (value == 0) {
+                return false;
+            } else {
+                return value;
+            }
+        }
+
+    }
+
+    @CoreMethod(names = "to_s", maxArgs = 0)
+    public abstract static class ToSNode extends CoreMethodNode {
+
+        public ToSNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ToSNode(ToSNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString toS(double value) {
+            return getContext().makeString(Double.toString(value));
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/HashNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+@CoreClass(name = "Hash")
+public abstract class HashNodes {
+
+    @CoreMethod(names = "[]", isModuleMethod = true, needsSelf = false, isSplatted = true)
+    public abstract static class ConstructNode extends CoreMethodNode {
+
+        public ConstructNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ConstructNode(ConstructNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyHash construct(Object[] args) {
+            final RubyHash hash = new RubyHash(getContext().getCoreLibrary().getHashClass());
+
+            if (args.length == 1) {
+                final RubyArray array = (RubyArray) args[0];
+
+                for (int n = 0; n < array.size(); n++) {
+                    final RubyArray keyValue = (RubyArray) array.get(n);
+                    hash.put(keyValue.get(0), keyValue.get(1));
+                }
+            } else {
+                assert args.length % 2 == 0;
+
+                for (int n = 0; n < args.length; n += 2) {
+                    hash.put(args[n], args[n + 1]);
+                }
+            }
+
+            return hash;
+        }
+
+    }
+
+    @CoreMethod(names = "[]", minArgs = 1, maxArgs = 1)
+    public abstract static class GetIndexNode extends CoreMethodNode {
+
+        public GetIndexNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public GetIndexNode(GetIndexNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object construct(VirtualFrame frame, RubyHash hash, Object index) {
+            final Object value = hash.get(index);
+
+            if (value == null) {
+                if (hash.defaultBlock == null) {
+                    return NilPlaceholder.INSTANCE;
+                } else {
+                    return hash.defaultBlock.call(frame.pack(), hash, index);
+                }
+            } else {
+                return value;
+            }
+        }
+
+    }
+
+    @CoreMethod(names = "[]=", minArgs = 2, maxArgs = 2)
+    public abstract static class SetIndexNode extends CoreMethodNode {
+
+        public SetIndexNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public SetIndexNode(SetIndexNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object construct(RubyHash hash, Object index, Object value) {
+            hash.put(index, value);
+            return value;
+        }
+
+    }
+
+    @CoreMethod(names = "delete", minArgs = 1, maxArgs = 1)
+    public abstract static class DeleteNode extends CoreMethodNode {
+
+        public DeleteNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public DeleteNode(DeleteNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object delete(RubyHash hash, Object index) {
+            hash.checkFrozen();
+
+            final Object value = hash.getMap().remove(index);
+
+            if (value == null) {
+                return NilPlaceholder.INSTANCE;
+            } else {
+                return value;
+            }
+        }
+
+    }
+
+    @CoreMethod(names = "each", needsBlock = true, maxArgs = 0)
+    public abstract static class EachNode extends YieldingCoreMethodNode {
+
+        public EachNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public EachNode(EachNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder each(VirtualFrame frame, RubyHash hash, RubyProc block) {
+            for (Map.Entry<Object, Object> entry : hash.storage.entrySet()) {
+                yield(frame, block, entry.getKey(), entry.getValue());
+            }
+
+            return NilPlaceholder.INSTANCE;
+        }
+
+    }
+
+    @CoreMethod(names = "empty?", maxArgs = 0)
+    public abstract static class EmptyNode extends CoreMethodNode {
+
+        public EmptyNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public EmptyNode(EmptyNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean empty(RubyHash hash) {
+            return hash.storage.isEmpty();
+        }
+
+    }
+
+    @CoreMethod(names = "initialize", needsBlock = true, maxArgs = 0)
+    public abstract static class InitializeNode extends CoreMethodNode {
+
+        public InitializeNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public InitializeNode(InitializeNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder initialize(RubyHash hash, @SuppressWarnings("unused") UndefinedPlaceholder block) {
+            hash.initialize(null);
+            return NilPlaceholder.INSTANCE;
+        }
+
+        @Specialization
+        public NilPlaceholder initialize(RubyHash hash, RubyProc block) {
+            hash.initialize(block);
+            return NilPlaceholder.INSTANCE;
+        }
+
+    }
+
+    @CoreMethod(names = {"map", "collect"}, needsBlock = true, maxArgs = 0)
+    public abstract static class MapNode extends YieldingCoreMethodNode {
+
+        public MapNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public MapNode(MapNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray map(VirtualFrame frame, RubyHash hash, RubyProc block) {
+            final RubyArray result = new RubyArray(getContext().getCoreLibrary().getArrayClass());
+
+            for (Map.Entry<Object, Object> entry : hash.storage.entrySet()) {
+                result.push(yield(frame, block, entry.getKey(), entry.getValue()));
+            }
+
+            return result;
+        }
+
+    }
+
+    @CoreMethod(names = "key?", minArgs = 1, maxArgs = 1)
+    public abstract static class KeyNode extends CoreMethodNode {
+
+        public KeyNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public KeyNode(KeyNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean key(RubyHash hash, Object key) {
+            return hash.storage.containsKey(key);
+        }
+
+    }
+
+    @CoreMethod(names = "keys", maxArgs = 0)
+    public abstract static class KeysNode extends CoreMethodNode {
+
+        public KeysNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public KeysNode(KeysNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray keys(RubyHash hash) {
+            final RubyArray array = new RubyArray(getContext().getCoreLibrary().getArrayClass());
+
+            for (Object key : hash.storage.keySet()) {
+                array.push(key);
+            }
+
+            return array;
+        }
+
+    }
+
+    @CoreMethod(names = "size", maxArgs = 0)
+    public abstract static class SizeNode extends CoreMethodNode {
+
+        public SizeNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public SizeNode(SizeNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public int size(RubyHash hash) {
+            return hash.storage.size();
+        }
+
+    }
+
+    @CoreMethod(names = "values", maxArgs = 0)
+    public abstract static class ValuesNode extends CoreMethodNode {
+
+        public ValuesNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ValuesNode(ValuesNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray values(RubyHash hash) {
+            final RubyArray array = new RubyArray(getContext().getCoreLibrary().getArrayClass());
+
+            for (Object value : hash.storage.values()) {
+                array.push(value);
+            }
+
+            return array;
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/InterpolatedStringNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * A list of expressions to build up into a string.
+ */
+@NodeInfo(shortName = "interpolated-string")
+public final class InterpolatedStringNode extends RubyNode {
+
+    @CompilationFinal private int expectedLength = 64;
+
+    @Children protected final RubyNode[] children;
+
+    public InterpolatedStringNode(RubyContext context, SourceSection sourceSection, RubyNode[] children) {
+        super(context, sourceSection);
+        this.children = adoptChildren(children);
+    }
+
+    @ExplodeLoop
+    @Override
+    public Object execute(VirtualFrame frame) {
+        final StringBuilder builder = new StringBuilder(expectedLength);
+
+        for (int n = 0; n < children.length; n++) {
+            builder.append(children[n].execute(frame).toString());
+        }
+
+        if (builder.length() > expectedLength) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            expectedLength = builder.length() * 2;
+        }
+
+        return getContext().makeString(builder.toString());
+    }
+
+    @ExplodeLoop
+    @Override
+    public void executeVoid(VirtualFrame frame) {
+        for (int n = 0; n < children.length; n++) {
+            children[n].executeVoid(frame);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/KernelNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,823 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import java.io.*;
+import java.math.*;
+import java.util.*;
+
+import com.oracle.truffle.api.CompilerDirectives.SlowPath;
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.nodes.call.*;
+import com.oracle.truffle.ruby.nodes.cast.*;
+import com.oracle.truffle.ruby.nodes.control.*;
+import com.oracle.truffle.ruby.nodes.literal.*;
+import com.oracle.truffle.ruby.nodes.yield.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.configuration.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+import com.oracle.truffle.ruby.runtime.subsystems.*;
+
+@CoreClass(name = "Kernel")
+public abstract class KernelNodes {
+
+    @CoreMethod(names = "Array", isModuleMethod = true, needsSelf = false, isSplatted = true)
+    public abstract static class ArrayNode extends CoreMethodNode {
+
+        public ArrayNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ArrayNode(ArrayNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray array(Object[] args) {
+            if (args.length == 1 && args[0] instanceof RubyArray) {
+                return (RubyArray) args[0];
+            } else {
+                return RubyArray.specializedFromObjects(getContext().getCoreLibrary().getArrayClass(), args);
+            }
+        }
+
+    }
+
+    @CoreMethod(names = "at_exit", isModuleMethod = true, needsSelf = false, needsBlock = true, maxArgs = 0)
+    public abstract static class AtExitNode extends CoreMethodNode {
+
+        public AtExitNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public AtExitNode(AtExitNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object atExit(RubyProc block) {
+            getContext().getAtExitManager().add(block);
+            return NilPlaceholder.INSTANCE;
+        }
+    }
+
+    @CoreMethod(names = "binding", isModuleMethod = true, needsSelf = true, maxArgs = 0)
+    public abstract static class BindingNode extends CoreMethodNode {
+
+        public BindingNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public BindingNode(BindingNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object binding(VirtualFrame frame, Object self) {
+            return new RubyBinding(getContext().getCoreLibrary().getBindingClass(), self, frame.getCaller().unpack().materialize());
+        }
+    }
+
+    @CoreMethod(names = "block_given?", isModuleMethod = true, needsSelf = false, maxArgs = 0)
+    public abstract static class BlockGivenNode extends CoreMethodNode {
+
+        public BlockGivenNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public BlockGivenNode(BlockGivenNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean blockGiven(VirtualFrame frame) {
+            return frame.getCaller().unpack().getArguments(RubyArguments.class).getBlock() != null;
+        }
+    }
+
+    // TODO(CS): should hide this in a feature
+
+    @CoreMethod(names = "callcc", isModuleMethod = true, needsSelf = false, needsBlock = true, maxArgs = 0)
+    public abstract static class CallccNode extends CoreMethodNode {
+
+        public CallccNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public CallccNode(CallccNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object callcc(RubyProc block) {
+            final RubyContext context = getContext();
+
+            if (block == null) {
+                // TODO(CS): should really have acceptsBlock and needsBlock to do this automatically
+                throw new RaiseException(context.getCoreLibrary().localJumpError("no block given"));
+            }
+
+            final RubyContinuation continuation = new RubyContinuation(context.getCoreLibrary().getContinuationClass());
+            return continuation.enter(block);
+        }
+    }
+
+    @CoreMethod(names = "catch", isModuleMethod = true, needsSelf = false, needsBlock = true, minArgs = 1, maxArgs = 1)
+    public abstract static class CatchNode extends YieldingCoreMethodNode {
+
+        public CatchNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public CatchNode(CatchNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object doCatch(VirtualFrame frame, Object tag, RubyProc block) {
+            try {
+                return yield(frame, block);
+            } catch (ThrowException e) {
+                if (e.getTag().equals(tag)) {
+                    // TODO(cs): unset rather than set to Nil?
+                    getContext().getCoreLibrary().getGlobalVariablesObject().setInstanceVariable("$!", NilPlaceholder.INSTANCE);
+                    return e.getValue();
+                } else {
+                    throw e;
+                }
+            }
+        }
+    }
+
+    @CoreMethod(names = "eval", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 2)
+    public abstract static class EvalNode extends CoreMethodNode {
+
+        public EvalNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public EvalNode(EvalNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object eval(RubyString source, @SuppressWarnings("unused") UndefinedPlaceholder binding) {
+            return getContext().eval(source.toString());
+        }
+
+        @Specialization
+        public Object eval(RubyString source, RubyBinding binding) {
+            return getContext().eval(source.toString(), binding);
+        }
+
+    }
+
+    @CoreMethod(names = "exec", isModuleMethod = true, needsSelf = false, minArgs = 1, isSplatted = true)
+    public abstract static class ExecNode extends CoreMethodNode {
+
+        public ExecNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ExecNode(ExecNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object require(Object[] args) {
+            final String[] commandLine = new String[args.length];
+
+            for (int n = 0; n < args.length; n++) {
+                commandLine[n] = args[n].toString();
+            }
+
+            exec(getContext(), commandLine);
+
+            return null;
+        }
+
+        @SlowPath
+        private static void exec(RubyContext context, String[] commandLine) {
+            context.implementationMessage("starting child process to simulate exec: ");
+
+            for (int n = 0; n < commandLine.length; n++) {
+                if (n > 0) {
+                    System.err.print(" ");
+                }
+
+                System.err.print(commandLine[n]);
+            }
+
+            final ProcessBuilder builder = new ProcessBuilder(commandLine);
+            builder.inheritIO();
+
+            final RubyHash env = (RubyHash) context.getCoreLibrary().getObjectClass().lookupConstant("ENV");
+
+            for (Map.Entry<Object, Object> entry : env.getMap().entrySet()) {
+                builder.environment().put(entry.getKey().toString(), entry.getValue().toString());
+            }
+
+            Process process;
+
+            try {
+                process = builder.start();
+            } catch (IOException e) {
+                // TODO(cs): proper Ruby exception
+                throw new RuntimeException(e);
+            }
+
+            int exitCode;
+
+            while (true) {
+                try {
+                    exitCode = process.waitFor();
+                    break;
+                } catch (InterruptedException e) {
+                    continue;
+                }
+            }
+
+            context.implementationMessage("child process simulating exec finished");
+
+            System.exit(exitCode);
+        }
+
+    }
+
+    @CoreMethod(names = "exit", isModuleMethod = true, needsSelf = false, minArgs = 0, maxArgs = 1)
+    public abstract static class ExitNode extends CoreMethodNode {
+
+        public ExitNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ExitNode(ExitNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object exit(@SuppressWarnings("unused") UndefinedPlaceholder exitCode) {
+            getContext().shutdown();
+            System.exit(0);
+            return null;
+        }
+
+        @Specialization
+        public Object exit(int exitCode) {
+            getContext().shutdown();
+            System.exit(exitCode);
+            return null;
+        }
+
+    }
+
+    @CoreMethod(names = "gets", isModuleMethod = true, needsSelf = false, maxArgs = 0)
+    public abstract static class GetsNode extends CoreMethodNode {
+
+        public GetsNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public GetsNode(GetsNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString gets(VirtualFrame frame) {
+            final RubyContext context = getContext();
+
+            final ThreadManager threadManager = context.getThreadManager();
+
+            RubyString line;
+
+            try {
+                final RubyThread runningThread = threadManager.leaveGlobalLock();
+
+                try {
+                    line = context.makeString(context.getConfiguration().getInputReader().readLine(""));
+                } finally {
+                    threadManager.enterGlobalLock(runningThread);
+                }
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+
+            // Set the local variable $_ in the caller
+
+            final Frame unpacked = frame.getCaller().unpack();
+            final FrameSlot slot = unpacked.getFrameDescriptor().findFrameSlot("$_");
+
+            if (slot != null) {
+                unpacked.setObject(slot, line);
+            }
+
+            return line;
+        }
+    }
+
+    @CoreMethod(names = "Integer", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1)
+    public abstract static class IntegerNode extends CoreMethodNode {
+
+        @Child protected DispatchHeadNode toInt;
+
+        public IntegerNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+            toInt = adoptChild(new DispatchHeadNode(context, getSourceSection(), "to_int", false));
+        }
+
+        public IntegerNode(IntegerNode prev) {
+            super(prev);
+            toInt = adoptChild(prev.toInt);
+        }
+
+        @Specialization
+        public int integer(int value) {
+            return value;
+        }
+
+        @Specialization
+        public BigInteger integer(BigInteger value) {
+            return value;
+        }
+
+        @Specialization
+        public int integer(double value) {
+            return (int) value;
+        }
+
+        @Specialization
+        public Object integer(RubyString value) {
+            return value.toInteger();
+        }
+
+        @Specialization
+        public Object integer(VirtualFrame frame, Object value) {
+            return toInt.dispatch(frame, value, null);
+        }
+
+    }
+
+    @CoreMethod(names = "lambda", isModuleMethod = true, needsBlock = true, maxArgs = 0)
+    public abstract static class LambdaNode extends CoreMethodNode {
+
+        public LambdaNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public LambdaNode(LambdaNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyProc proc(Object self, RubyProc block) {
+            return new RubyProc(getContext().getCoreLibrary().getProcClass(), RubyProc.Type.LAMBDA, self, block, block.getMethod());
+
+        }
+    }
+
+    @CoreMethod(names = "load", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1)
+    public abstract static class LoadNode extends CoreMethodNode {
+
+        public LoadNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public LoadNode(LoadNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean load(RubyString file) {
+            getContext().loadFile(file.toString());
+            return true;
+        }
+    }
+
+    @CoreMethod(names = "loop", isModuleMethod = true, needsSelf = false, maxArgs = 0)
+    public abstract static class LoopNode extends CoreMethodNode {
+
+        @Child protected WhileNode whileNode;
+
+        public LoopNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+            whileNode = adoptChild(new WhileNode(context, sourceSection, BooleanCastNodeFactory.create(context, sourceSection, new BooleanLiteralNode(context, sourceSection, true)), new YieldNode(
+                            context, getSourceSection(), new RubyNode[]{})));
+        }
+
+        public LoopNode(LoopNode prev) {
+            super(prev);
+            whileNode = adoptChild(prev.whileNode);
+        }
+
+        @Specialization
+        public Object loop(VirtualFrame frame) {
+            return whileNode.execute(frame);
+        }
+    }
+
+    @CoreMethod(names = "print", isModuleMethod = true, needsSelf = false, isSplatted = true)
+    public abstract static class PrintNode extends CoreMethodNode {
+
+        public PrintNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public PrintNode(PrintNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder print(Object[] args) {
+            final RubyContext context = getContext();
+            final ThreadManager threadManager = context.getThreadManager();
+
+            final RubyThread runningThread = threadManager.leaveGlobalLock();
+
+            try {
+                for (Object arg : args) {
+                    /*
+                     * TODO(cs): If it's a RubyString and made up of bytes, just write the bytes out
+                     * - using toString will mess up the encoding. We need to stop using toString
+                     * everywhere, and write our own bytes, possibly using JRuby's library for this.
+                     */
+
+                    if (arg instanceof RubyString && !((RubyString) arg).isFromJavaString()) {
+                        try {
+                            context.getConfiguration().getStandardOut().write(((RubyString) arg).getBytes());
+                        } catch (IOException e) {
+                            throw new RuntimeException(e);
+                        }
+                    } else {
+                        context.getConfiguration().getStandardOut().print(arg);
+                    }
+                }
+            } finally {
+                threadManager.enterGlobalLock(runningThread);
+            }
+
+            return NilPlaceholder.INSTANCE;
+        }
+    }
+
+    @CoreMethod(names = "printf", isModuleMethod = true, needsSelf = false, isSplatted = true)
+    public abstract static class PrintfNode extends CoreMethodNode {
+
+        public PrintfNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public PrintfNode(PrintfNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder printf(Object[] args) {
+            final RubyContext context = getContext();
+            final ThreadManager threadManager = context.getThreadManager();
+
+            if (args.length > 0) {
+                final String format = ((RubyString) args[0]).toString();
+                final List<Object> values = Arrays.asList(args).subList(1, args.length);
+
+                final RubyThread runningThread = threadManager.leaveGlobalLock();
+
+                try {
+                    StringFormatter.format(context.getConfiguration().getStandardOut(), format, values);
+                } finally {
+                    threadManager.enterGlobalLock(runningThread);
+                }
+            }
+
+            return NilPlaceholder.INSTANCE;
+        }
+    }
+
+    /*
+     * Kernel#pretty_inspect is normally part of stdlib, in pp.rb, but we aren't able to execute
+     * that file yet. Instead we implement a very simple version here, which is the solution
+     * suggested by RubySpec.
+     */
+
+    @CoreMethod(names = "pretty_inspect", maxArgs = 0)
+    public abstract static class PrettyInspectNode extends CoreMethodNode {
+
+        @Child protected DispatchHeadNode toS;
+
+        public PrettyInspectNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+            toS = adoptChild(new DispatchHeadNode(context, getSourceSection(), "to_s", false));
+        }
+
+        public PrettyInspectNode(PrettyInspectNode prev) {
+            super(prev);
+            toS = adoptChild(prev.toS);
+        }
+
+        @Specialization
+        public Object prettyInspect(VirtualFrame frame, Object self) {
+            return toS.dispatch(frame, self, null);
+
+        }
+    }
+
+    @CoreMethod(names = "proc", isModuleMethod = true, needsBlock = true, maxArgs = 0, versions = RubyVersion.RUBY_18)
+    public abstract static class Proc18Node extends CoreMethodNode {
+
+        public Proc18Node(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public Proc18Node(Proc18Node prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyProc proc(Object self, RubyProc block) {
+            return new RubyProc(getContext().getCoreLibrary().getProcClass(), RubyProc.Type.LAMBDA, self, block, block.getMethod());
+
+        }
+    }
+
+    @CoreMethod(names = "proc", isModuleMethod = true, needsBlock = true, maxArgs = 0, versions = {RubyVersion.RUBY_19, RubyVersion.RUBY_20, RubyVersion.RUBY_21})
+    public abstract static class ProcNode extends CoreMethodNode {
+
+        public ProcNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ProcNode(ProcNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyProc proc(Object self, RubyProc block) {
+            return new RubyProc(getContext().getCoreLibrary().getProcClass(), RubyProc.Type.PROC, self, block, block.getMethod());
+
+        }
+    }
+
+    @CoreMethod(names = "puts", isModuleMethod = true, needsSelf = false, isSplatted = true)
+    public abstract static class PutsNode extends CoreMethodNode {
+
+        public PutsNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public PutsNode(PutsNode prev) {
+            super(prev);
+        }
+
+        @ExplodeLoop
+        @Specialization
+        public NilPlaceholder puts(Object[] args) {
+            final RubyContext context = getContext();
+            final ThreadManager threadManager = context.getThreadManager();
+            final PrintStream standardOut = context.getConfiguration().getStandardOut();
+
+            final RubyThread runningThread = threadManager.leaveGlobalLock();
+
+            try {
+                if (args.length == 0) {
+                    standardOut.println();
+                } else {
+                    for (int n = 0; n < args.length; n++) {
+                        puts(context, standardOut, args[n]);
+                    }
+                }
+            } finally {
+                threadManager.enterGlobalLock(runningThread);
+            }
+
+            return NilPlaceholder.INSTANCE;
+        }
+
+        @SlowPath
+        private void puts(RubyContext context, PrintStream standardOut, Object value) {
+            if (value instanceof RubyArray) {
+                final RubyArray array = (RubyArray) value;
+
+                for (int n = 0; n < array.size(); n++) {
+                    puts(context, standardOut, array.get(n));
+                }
+            } else {
+                // TODO(CS): slow path send
+                standardOut.println(context.getCoreLibrary().box(value).send("to_s", null));
+            }
+        }
+
+    }
+
+    @CoreMethod(names = "raise", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 2)
+    public abstract static class RaiseNode extends CoreMethodNode {
+
+        @Child protected DispatchHeadNode initialize;
+
+        public RaiseNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+            initialize = adoptChild(new DispatchHeadNode(context, getSourceSection(), "initialize", false));
+        }
+
+        public RaiseNode(RaiseNode prev) {
+            super(prev);
+            initialize = adoptChild(prev.initialize);
+        }
+
+        @Specialization(order = 1)
+        public Object raise(VirtualFrame frame, RubyString message, @SuppressWarnings("unused") UndefinedPlaceholder undefined) {
+            return raise(frame, getContext().getCoreLibrary().getRuntimeErrorClass(), message);
+        }
+
+        @Specialization(order = 2)
+        public Object raise(VirtualFrame frame, RubyClass exceptionClass, @SuppressWarnings("unused") UndefinedPlaceholder undefined) {
+            return raise(frame, exceptionClass, getContext().makeString(""));
+        }
+
+        @Specialization(order = 3)
+        public Object raise(VirtualFrame frame, RubyClass exceptionClass, RubyString message) {
+            final RubyContext context = getContext();
+
+            if (context.getConfiguration().getPrintRubyExceptions()) {
+                context.implementationMessage("Ruby raise: %s", message);
+                new Exception().printStackTrace();
+            }
+
+            final RubyBasicObject exception = exceptionClass.newInstance();
+            initialize.dispatch(frame, exception, null, message);
+            throw new RaiseException(exception);
+        }
+
+    }
+
+    @CoreMethod(names = "require", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1)
+    public abstract static class RequireNode extends CoreMethodNode {
+
+        public RequireNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public RequireNode(RequireNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean require(RubyString feature) {
+            try {
+                getContext().getFeatureManager().require(feature.toString());
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+
+            return true;
+        }
+    }
+
+    @CoreMethod(names = "set_trace_func", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1)
+    public abstract static class SetTraceFuncNode extends CoreMethodNode {
+
+        public SetTraceFuncNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public SetTraceFuncNode(SetTraceFuncNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder setTraceFunc(NilPlaceholder proc) {
+            getContext().getTraceManager().setTraceProc(null);
+            return proc;
+        }
+
+        @Specialization
+        public RubyProc setTraceFunc(RubyProc proc) {
+            getContext().getTraceManager().setTraceProc(proc);
+            return proc;
+        }
+
+    }
+
+    @CoreMethod(names = "String", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1)
+    public abstract static class StringNode extends CoreMethodNode {
+
+        @Child protected DispatchHeadNode toS;
+
+        public StringNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+            toS = adoptChild(new DispatchHeadNode(context, getSourceSection(), "to_s", false));
+        }
+
+        public StringNode(StringNode prev) {
+            super(prev);
+            toS = adoptChild(prev.toS);
+        }
+
+        @Specialization
+        public RubyString string(int value) {
+            return getContext().makeString(Integer.toString(value));
+        }
+
+        @Specialization
+        public RubyString string(BigInteger value) {
+            return getContext().makeString(value.toString());
+        }
+
+        @Specialization
+        public RubyString string(double value) {
+            return getContext().makeString(Double.toString(value));
+        }
+
+        @Specialization
+        public RubyString string(RubyString value) {
+            return value;
+        }
+
+        @Specialization
+        public Object string(VirtualFrame frame, Object value) {
+            return toS.dispatch(frame, value, null);
+        }
+
+    }
+
+    @CoreMethod(names = "sleep", isModuleMethod = true, needsSelf = false, maxArgs = 1)
+    public abstract static class SleepNode extends CoreMethodNode {
+
+        public SleepNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public SleepNode(SleepNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public double sleep(double duration) {
+            final RubyContext context = getContext();
+
+            final RubyThread runningThread = context.getThreadManager().leaveGlobalLock();
+
+            try {
+                final long start = System.nanoTime();
+
+                try {
+                    Thread.sleep((long) (duration * 1000));
+                } catch (InterruptedException e) {
+                    // Ignore interruption
+                }
+
+                final long end = System.nanoTime();
+
+                return (end - start) / 1e9;
+            } finally {
+                context.getThreadManager().enterGlobalLock(runningThread);
+            }
+        }
+
+        @Specialization
+        public double sleep(int duration) {
+            return sleep((double) duration);
+        }
+
+    }
+
+    @CoreMethod(names = "throw", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 2)
+    public abstract static class ThrowNode extends CoreMethodNode {
+
+        public ThrowNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ThrowNode(ThrowNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object doThrow(Object tag, UndefinedPlaceholder value) {
+            return doThrow(tag, (Object) value);
+        }
+
+        @Specialization
+        public Object doThrow(Object tag, Object value) {
+            if (value instanceof UndefinedPlaceholder) {
+                throw new ThrowException(tag, NilPlaceholder.INSTANCE);
+            } else {
+                throw new ThrowException(tag, value);
+            }
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/MainNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+@CoreClass(name = "main")
+public abstract class MainNodes {
+
+    @CoreMethod(names = "include", isSplatted = true, minArgs = 1)
+    public abstract static class IncludeNode extends CoreMethodNode {
+
+        public IncludeNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public IncludeNode(IncludeNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder include(RubyObject main, Object[] args) {
+            // TODO(cs): copied from Module - but where does this method really come from?
+
+            // Note that we traverse the arguments backwards
+
+            for (int n = args.length - 1; n >= 0; n--) {
+                if (args[n] instanceof RubyModule) {
+                    final RubyModule included = (RubyModule) args[n];
+
+                    // Note that we do appear to do full method lookup here
+                    included.getLookupNode().lookupMethod("append_features").call(null, included, null, main.getSingletonClass());
+
+                    // TODO(cs): call included hook
+                }
+            }
+
+            return NilPlaceholder.INSTANCE;
+        }
+    }
+
+    @CoreMethod(names = "to_s", needsSelf = false, maxArgs = 0)
+    public abstract static class ToSNode extends CoreMethodNode {
+
+        public ToSNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ToSNode(ToSNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString toS() {
+            return getContext().makeString("main");
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/MatchDataNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+@CoreClass(name = "MatchData")
+public abstract class MatchDataNodes {
+
+    @CoreMethod(names = "[]", minArgs = 1, maxArgs = 1)
+    public abstract static class GetIndexNode extends CoreMethodNode {
+
+        public GetIndexNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public GetIndexNode(GetIndexNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object getIndex(RubyMatchData matchData, int index) {
+            return matchData.getValues()[index];
+        }
+
+    }
+
+    @CoreMethod(names = "to_a", maxArgs = 0)
+    public abstract static class ToANode extends CoreMethodNode {
+
+        public ToANode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ToANode(ToANode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray toA(RubyMatchData matchData) {
+            return RubyArray.specializedFromObjects(getContext().getCoreLibrary().getArrayClass(), matchData.getValues());
+        }
+
+    }
+
+    @CoreMethod(names = "values_at", isSplatted = true)
+    public abstract static class ValuesAtNode extends CoreMethodNode {
+
+        public ValuesAtNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ValuesAtNode(ValuesAtNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray valuesAt(RubyMatchData matchData, Object[] args) {
+            final int[] indicies = new int[args.length];
+
+            for (int n = 0; n < args.length; n++) {
+                indicies[n] = (int) args[n];
+            }
+
+            return RubyArray.specializedFromObjects(getContext().getCoreLibrary().getArrayClass(), matchData.valuesAt(indicies));
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/MathNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import java.math.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+@CoreClass(name = "Math")
+public abstract class MathNodes {
+
+    @CoreMethod(names = "sqrt", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1)
+    public abstract static class SqrtNode extends CoreMethodNode {
+
+        public SqrtNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public SqrtNode(SqrtNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public double sqrt(int a) {
+            return Math.sqrt(a);
+        }
+
+        @Specialization
+        public double sqrt(BigInteger a) {
+            return Math.sqrt(a.doubleValue());
+        }
+
+        @Specialization
+        public double sqrt(double a) {
+            return Math.sqrt(a);
+        }
+
+    }
+
+    @CoreMethod(names = "exp", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1)
+    public abstract static class ExpNode extends CoreMethodNode {
+
+        public ExpNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ExpNode(ExpNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public double exp(int a) {
+            return Math.exp(a);
+        }
+
+        @Specialization
+        public double exp(BigInteger a) {
+            return Math.exp(a.doubleValue());
+        }
+
+        @Specialization
+        public double exp(double a) {
+            return Math.exp(a);
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ModuleNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,652 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.nodes.control.*;
+import com.oracle.truffle.ruby.nodes.methods.arguments.*;
+import com.oracle.truffle.ruby.nodes.objects.*;
+import com.oracle.truffle.ruby.nodes.objects.instancevariables.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.RubyParser.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+
+@CoreClass(name = "Module")
+public abstract class ModuleNodes {
+
+    @CoreMethod(names = "alias_method", minArgs = 2, maxArgs = 2)
+    public abstract static class AliasMethodNode extends CoreMethodNode {
+
+        public AliasMethodNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public AliasMethodNode(AliasMethodNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyModule aliasMethod(RubyModule module, RubySymbol newName, RubySymbol oldName) {
+            module.alias(newName.toString(), oldName.toString());
+            return module;
+        }
+    }
+
+    @CoreMethod(names = "append_features", minArgs = 1, maxArgs = 1)
+    public abstract static class AppendFeaturesNode extends CoreMethodNode {
+
+        public AppendFeaturesNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public AppendFeaturesNode(AppendFeaturesNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder appendFeatures(RubyModule module, RubyModule other) {
+            module.appendFeatures(other);
+            return NilPlaceholder.INSTANCE;
+        }
+    }
+
+    @CoreMethod(names = "attr_reader", isSplatted = true, appendCallNode = true)
+    public abstract static class AttrReaderNode extends CoreMethodNode {
+
+        public AttrReaderNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public AttrReaderNode(AttrReaderNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder attrReader(RubyModule module, Object[] args) {
+            final Node callSite = (Node) args[args.length - 1];
+            final SourceSection sourceSection = callSite.getSourceSection();
+
+            for (int n = 0; n < args.length - 1; n++) {
+                attrReader(getContext(), sourceSection, module, args[n].toString());
+            }
+
+            return NilPlaceholder.INSTANCE;
+        }
+
+        public static void attrReader(RubyContext context, SourceSection sourceSection, RubyModule module, String name) {
+            CompilerDirectives.transferToInterpreter();
+
+            final CheckArityNode checkArity = new CheckArityNode(context, sourceSection, Arity.NO_ARGS);
+
+            final SelfNode self = new SelfNode(context, sourceSection);
+            final UninitializedReadInstanceVariableNode readInstanceVariable = new UninitializedReadInstanceVariableNode(context, sourceSection, name, self);
+
+            final SequenceNode block = new SequenceNode(context, sourceSection, checkArity, readInstanceVariable);
+
+            final RubyRootNode pristineRoot = new RubyRootNode(sourceSection, name + "(attr_reader)", block);
+            final CallTarget callTarget = Truffle.getRuntime().createCallTarget(NodeUtil.cloneNode(pristineRoot));
+            final InlinableMethodImplementation methodImplementation = new InlinableMethodImplementation(callTarget, null, new FrameDescriptor(), pristineRoot, true, false);
+            final RubyMethod method = new RubyMethod(sourceSection, module, new UniqueMethodIdentifier(), null, name, Visibility.PUBLIC, false, methodImplementation);
+
+            module.addMethod(method);
+        }
+    }
+
+    @CoreMethod(names = "attr_writer", isSplatted = true, appendCallNode = true)
+    public abstract static class AttrWriterNode extends CoreMethodNode {
+
+        public AttrWriterNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public AttrWriterNode(AttrWriterNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder attrWriter(RubyModule module, Object[] args) {
+            final Node callSite = (Node) args[args.length - 1];
+            final SourceSection sourceSection = callSite.getSourceSection();
+
+            for (int n = 0; n < args.length - 1; n++) {
+                attrWriter(getContext(), sourceSection, module, args[n].toString());
+            }
+
+            return NilPlaceholder.INSTANCE;
+        }
+
+        public static void attrWriter(RubyContext context, SourceSection sourceSection, RubyModule module, String name) {
+            CompilerDirectives.transferToInterpreter();
+
+            final CheckArityNode checkArity = new CheckArityNode(context, sourceSection, Arity.ONE_ARG);
+
+            final SelfNode self = new SelfNode(context, sourceSection);
+            final ReadPreArgumentNode readArgument = new ReadPreArgumentNode(context, sourceSection, 0, false);
+            final UninitializedWriteInstanceVariableNode writeInstanceVariable = new UninitializedWriteInstanceVariableNode(context, sourceSection, name, self, readArgument);
+
+            final SequenceNode block = new SequenceNode(context, sourceSection, checkArity, writeInstanceVariable);
+
+            final RubyRootNode pristineRoot = new RubyRootNode(sourceSection, name + "(attr_writer)", block);
+            final CallTarget callTarget = Truffle.getRuntime().createCallTarget(NodeUtil.cloneNode(pristineRoot));
+            final InlinableMethodImplementation methodImplementation = new InlinableMethodImplementation(callTarget, null, new FrameDescriptor(), pristineRoot, true, false);
+            final RubyMethod method = new RubyMethod(sourceSection, module, new UniqueMethodIdentifier(), null, name + "=", Visibility.PUBLIC, false, methodImplementation);
+
+            module.addMethod(method);
+        }
+    }
+
+    @CoreMethod(names = {"attr_accessor", "attr"}, isSplatted = true, appendCallNode = true)
+    public abstract static class AttrAccessorNode extends CoreMethodNode {
+
+        public AttrAccessorNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public AttrAccessorNode(AttrAccessorNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder attrAccessor(RubyModule module, Object[] args) {
+            final Node callSite = (Node) args[args.length - 1];
+            final SourceSection sourceSection = callSite.getSourceSection();
+
+            for (int n = 0; n < args.length - 1; n++) {
+                attrAccessor(getContext(), sourceSection, module, args[n].toString());
+            }
+
+            return NilPlaceholder.INSTANCE;
+        }
+
+        public static void attrAccessor(RubyContext context, SourceSection sourceSection, RubyModule module, String name) {
+            CompilerDirectives.transferToInterpreter();
+            AttrReaderNode.attrReader(context, sourceSection, module, name);
+            AttrWriterNode.attrWriter(context, sourceSection, module, name);
+        }
+
+    }
+
+    @CoreMethod(names = "class_eval", minArgs = 1, maxArgs = 3)
+    public abstract static class ClassEvalNode extends CoreMethodNode {
+
+        public ClassEvalNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ClassEvalNode(ClassEvalNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object classEval(VirtualFrame frame, RubyModule module, RubyString code, @SuppressWarnings("unused") UndefinedPlaceholder file, @SuppressWarnings("unused") UndefinedPlaceholder line) {
+            final Source source = getContext().getSourceManager().get("(eval)", code.toString());
+            return getContext().execute(getContext(), source, ParserContext.MODULE, module, frame.materialize());
+        }
+
+        @Specialization
+        public Object classEval(VirtualFrame frame, RubyModule module, RubyString code, RubyString file, @SuppressWarnings("unused") UndefinedPlaceholder line) {
+            final Source source = getContext().getSourceManager().get(file.toString(), code.toString());
+            return getContext().execute(getContext(), source, ParserContext.MODULE, module, frame.materialize());
+        }
+
+        @Specialization
+        public Object classEval(VirtualFrame frame, RubyModule module, RubyString code, RubyString file, @SuppressWarnings("unused") int line) {
+            final Source source = getContext().getSourceManager().get(file.toString(), code.toString());
+            return getContext().execute(getContext(), source, ParserContext.MODULE, module, frame.materialize());
+        }
+
+    }
+
+    @CoreMethod(names = "class_variable_defined?", maxArgs = 0)
+    public abstract static class ClassVariableDefinedNode extends CoreMethodNode {
+
+        public ClassVariableDefinedNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ClassVariableDefinedNode(ClassVariableDefinedNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean isClassVariableDefined(RubyModule module, RubyString name) {
+            return module.lookupClassVariable(name.toString()) != null;
+        }
+
+        @Specialization
+        public boolean isClassVariableDefined(RubyModule module, RubySymbol name) {
+            return module.lookupClassVariable(name.toString()) != null;
+        }
+
+    }
+
+    @CoreMethod(names = "constants", maxArgs = 0)
+    public abstract static class ConstantsNode extends CoreMethodNode {
+
+        public ConstantsNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ConstantsNode(ConstantsNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray constants(@SuppressWarnings("unused") RubyModule module) {
+            getContext().implementationMessage("Module#constants returns an empty array");
+            return new RubyArray(getContext().getCoreLibrary().getArrayClass());
+        }
+    }
+
+    @CoreMethod(names = "const_defined?", minArgs = 1, maxArgs = 2)
+    public abstract static class ConstDefinedNode extends CoreMethodNode {
+
+        public ConstDefinedNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ConstDefinedNode(ConstDefinedNode prev) {
+            super(prev);
+        }
+
+        @Specialization(order = 1)
+        public boolean isConstDefined(RubyModule module, RubyString name, @SuppressWarnings("unused") UndefinedPlaceholder inherit) {
+            return module.lookupConstant(name.toString()) != null;
+        }
+
+        @Specialization(order = 2)
+        public boolean isConstDefined(RubyModule module, RubyString name, boolean inherit) {
+            if (inherit) {
+                return module.lookupConstant(name.toString()) != null;
+            } else {
+                return module.getConstants().containsKey(name.toString());
+            }
+        }
+
+        @Specialization(order = 3)
+        public boolean isConstDefined(RubyModule module, RubySymbol name, @SuppressWarnings("unused") UndefinedPlaceholder inherit) {
+            return module.lookupConstant(name.toString()) != null;
+        }
+
+        public boolean isConstDefined(RubyModule module, RubySymbol name, boolean inherit) {
+            if (inherit) {
+                return module.lookupConstant(name.toString()) != null;
+            } else {
+                return module.getConstants().containsKey(name.toString());
+            }
+        }
+
+    }
+
+    @CoreMethod(names = "define_method", needsBlock = true, minArgs = 1, maxArgs = 2)
+    public abstract static class DefineMethodNode extends CoreMethodNode {
+
+        public DefineMethodNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public DefineMethodNode(DefineMethodNode prev) {
+            super(prev);
+        }
+
+        @Specialization(order = 1)
+        public RubyMethod defineMethod(RubyModule module, RubyString name, @SuppressWarnings("unused") UndefinedPlaceholder proc, RubyProc block) {
+            final RubyMethod method = block.getMethod();
+            module.addMethod(method.withNewName(name.toString()));
+            return method;
+        }
+
+        @Specialization(order = 2)
+        public RubyMethod defineMethod(RubyModule module, RubyString name, RubyProc proc, @SuppressWarnings("unused") UndefinedPlaceholder block) {
+            final RubyMethod method = proc.getMethod();
+            module.addMethod(method.withNewName(name.toString()));
+            return method;
+        }
+
+        @Specialization(order = 3)
+        public RubyMethod defineMethod(RubyModule module, RubySymbol name, @SuppressWarnings("unused") UndefinedPlaceholder proc, RubyProc block) {
+            final RubyMethod method = block.getMethod();
+            module.addMethod(method.withNewName(name.toString()));
+            return method;
+        }
+
+        @Specialization(order = 4)
+        public RubyMethod defineMethod(RubyModule module, RubySymbol name, RubyProc proc, @SuppressWarnings("unused") UndefinedPlaceholder block) {
+            final RubyMethod method = proc.getMethod();
+            module.addMethod(method.withNewName(name.toString()));
+            return method;
+        }
+
+    }
+
+    @CoreMethod(names = "include", isSplatted = true, minArgs = 1)
+    public abstract static class IncludeNode extends CoreMethodNode {
+
+        public IncludeNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public IncludeNode(IncludeNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder include(RubyModule module, Object[] args) {
+            // Note that we traverse the arguments backwards
+
+            for (int n = args.length - 1; n >= 0; n--) {
+                if (args[n] instanceof RubyModule) {
+                    final RubyModule included = (RubyModule) args[n];
+
+                    // Note that we do appear to do full method lookup here
+                    included.getLookupNode().lookupMethod("append_features").call(null, included, null, module);
+
+                    // TODO(cs): call included hook
+                }
+            }
+
+            return NilPlaceholder.INSTANCE;
+        }
+    }
+
+    @CoreMethod(names = "method_defined?", minArgs = 1, maxArgs = 2)
+    public abstract static class MethodDefinedNode extends CoreMethodNode {
+
+        public MethodDefinedNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public MethodDefinedNode(MethodDefinedNode prev) {
+            super(prev);
+        }
+
+        @Specialization(order = 1)
+        public boolean isMethodDefined(RubyModule module, RubyString name, @SuppressWarnings("unused") UndefinedPlaceholder inherit) {
+            return module.lookupMethod(name.toString()) != null;
+        }
+
+        @Specialization(order = 2)
+        public boolean isMethodDefined(RubyModule module, RubyString name, boolean inherit) {
+            if (inherit) {
+                return module.lookupMethod(name.toString()) != null;
+            } else {
+                return module.getMethods().containsKey(name.toString());
+            }
+        }
+
+        @Specialization(order = 3)
+        public boolean isMethodDefined(RubyModule module, RubySymbol name, @SuppressWarnings("unused") UndefinedPlaceholder inherit) {
+            return module.lookupMethod(name.toString()) != null;
+        }
+
+        public boolean isMethodDefined(RubyModule module, RubySymbol name, boolean inherit) {
+            if (inherit) {
+                return module.lookupMethod(name.toString()) != null;
+            } else {
+                return module.getMethods().containsKey(name.toString());
+            }
+        }
+    }
+
+    @CoreMethod(names = "module_eval", minArgs = 1, maxArgs = 3)
+    public abstract static class ModuleEvalNode extends CoreMethodNode {
+
+        public ModuleEvalNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ModuleEvalNode(ModuleEvalNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyModule moduleEval(RubyModule module, RubyString code, @SuppressWarnings("unused") Object file, @SuppressWarnings("unused") Object line) {
+            module.moduleEval(code.toString());
+            return module;
+        }
+    }
+
+    @CoreMethod(names = "module_function", isSplatted = true)
+    public abstract static class ModuleFunctionNode extends CoreMethodNode {
+
+        public ModuleFunctionNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ModuleFunctionNode(ModuleFunctionNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder moduleFunction(VirtualFrame frame, RubyModule module, Object... args) {
+            if (args.length == 0) {
+                final Frame unpacked = frame.getCaller().unpack();
+
+                final FrameSlot slot = unpacked.getFrameDescriptor().findFrameSlot(RubyModule.MODULE_FUNCTION_FLAG_FRAME_SLOT_ID);
+
+                /*
+                 * setObject, even though it's a boolean, so we can getObject and either get the
+                 * default Nil or the boolean value without triggering deoptimization.
+                 */
+
+                unpacked.setObject(slot, true);
+            } else {
+                for (Object argument : args) {
+                    final String methodName = argument.toString();
+                    module.getSingletonClass().addMethod(module.lookupMethod(methodName));
+                }
+            }
+
+            return NilPlaceholder.INSTANCE;
+        }
+    }
+
+    @CoreMethod(names = "public", isSplatted = true)
+    public abstract static class PublicNode extends CoreMethodNode {
+
+        public PublicNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public PublicNode(PublicNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyModule doPublic(VirtualFrame frame, RubyModule module, Object... args) {
+            module.visibilityMethod(frame.getCaller(), args, Visibility.PUBLIC);
+            return module;
+        }
+    }
+
+    @CoreMethod(names = "private", isSplatted = true)
+    public abstract static class PrivateNode extends CoreMethodNode {
+
+        public PrivateNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public PrivateNode(PrivateNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyModule doPrivate(VirtualFrame frame, RubyModule module, Object... args) {
+            module.visibilityMethod(frame.getCaller(), args, Visibility.PRIVATE);
+            return module;
+        }
+    }
+
+    @CoreMethod(names = "private_class_method", isSplatted = true)
+    public abstract static class PrivateClassMethodNode extends CoreMethodNode {
+
+        public PrivateClassMethodNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public PrivateClassMethodNode(PrivateClassMethodNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyModule privateClassMethod(RubyModule module, Object... args) {
+            final RubyClass moduleSingleton = module.getSingletonClass();
+
+            for (Object arg : args) {
+                final RubyMethod method = moduleSingleton.lookupMethod(arg.toString());
+
+                if (method == null) {
+                    throw new RuntimeException("Couldn't find method " + arg.toString());
+                }
+
+                moduleSingleton.addMethod(method.withNewVisibility(Visibility.PRIVATE));
+            }
+
+            return module;
+        }
+    }
+
+    @CoreMethod(names = "private_constant", isSplatted = true)
+    public abstract static class PrivateConstantNode extends CoreMethodNode {
+
+        public PrivateConstantNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public PrivateConstantNode(PrivateConstantNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyModule privateConstnat(RubyModule module, @SuppressWarnings("unused") Object... args) {
+            getContext().implementationMessage("private_constant does nothing at the moment");
+            return module;
+        }
+    }
+
+    @CoreMethod(names = "protected", isSplatted = true)
+    public abstract static class ProtectedNode extends CoreMethodNode {
+
+        public ProtectedNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ProtectedNode(ProtectedNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyModule doProtected(RubyModule module, @SuppressWarnings("unused") Object... args) {
+            getContext().implementationMessage("protected does nothing at the moment");
+            return module;
+        }
+    }
+
+    @CoreMethod(names = "remove_class_variable", minArgs = 1, maxArgs = 1)
+    public abstract static class RemoveClassVariableNode extends CoreMethodNode {
+
+        public RemoveClassVariableNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public RemoveClassVariableNode(RemoveClassVariableNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyModule removeClassVariable(RubyModule module, RubyString name) {
+            module.removeClassVariable(name.toString());
+            return module;
+        }
+
+        @Specialization
+        public RubyModule removeClassVariable(RubyModule module, RubySymbol name) {
+            module.removeClassVariable(name.toString());
+            return module;
+        }
+
+    }
+
+    @CoreMethod(names = "remove_method", minArgs = 1, maxArgs = 1)
+    public abstract static class RemoveMethodNode extends CoreMethodNode {
+
+        public RemoveMethodNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public RemoveMethodNode(RemoveMethodNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyModule removeMethod(RubyModule module, RubyString name) {
+            module.removeMethod(name.toString());
+            return module;
+        }
+
+        @Specialization
+        public RubyModule removeMethod(RubyModule module, RubySymbol name) {
+            module.removeMethod(name.toString());
+            return module;
+        }
+
+    }
+
+    @CoreMethod(names = "to_s", maxArgs = 0)
+    public abstract static class ToSNode extends CoreMethodNode {
+
+        public ToSNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ToSNode(ToSNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString toS(RubyModule module) {
+            return getContext().makeString(module.getName());
+        }
+    }
+
+    @CoreMethod(names = "undef_method", minArgs = 1, maxArgs = 1)
+    public abstract static class UndefMethodNode extends CoreMethodNode {
+
+        public UndefMethodNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public UndefMethodNode(UndefMethodNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyModule undefMethod(RubyModule module, RubyString name) {
+            final RubyMethod method = module.lookupMethod(name.toString());
+            module.undefMethod(method);
+            return module;
+        }
+
+        @Specialization
+        public RubyModule undefMethod(RubyModule module, RubySymbol name) {
+            final RubyMethod method = module.lookupMethod(name.toString());
+            module.undefMethod(method);
+            return module;
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/NilClassNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+@CoreClass(name = "NilClass")
+public abstract class NilClassNodes {
+
+    @CoreMethod(names = "!", needsSelf = false, maxArgs = 0)
+    public abstract static class NotNode extends CoreMethodNode {
+
+        public NotNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public NotNode(NotNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean not() {
+            return true;
+        }
+    }
+
+    @CoreMethod(names = "==", needsSelf = false, minArgs = 1, maxArgs = 1)
+    public abstract static class EqualNode extends CoreMethodNode {
+
+        public EqualNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public EqualNode(EqualNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean equal(Object b) {
+            return b instanceof NilPlaceholder || b instanceof RubyNilClass;
+        }
+
+    }
+
+    @CoreMethod(names = "!=", needsSelf = false, minArgs = 1, maxArgs = 1)
+    public abstract static class NotEqualNode extends CoreMethodNode {
+
+        public NotEqualNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public NotEqualNode(NotEqualNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean equal(Object b) {
+            return !(b instanceof NilPlaceholder || b instanceof RubyNilClass);
+        }
+
+    }
+
+    @CoreMethod(names = "inspect", needsSelf = false, maxArgs = 0)
+    public abstract static class InpsectNode extends CoreMethodNode {
+
+        public InpsectNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public InpsectNode(InpsectNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString inspect() {
+            return getContext().makeString("nil");
+        }
+    }
+
+    @CoreMethod(names = "nil?", needsSelf = false, maxArgs = 0)
+    public abstract static class NilNode extends CoreMethodNode {
+
+        public NilNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public NilNode(NilNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean nil() {
+            return true;
+        }
+    }
+
+    @CoreMethod(names = "to_i", needsSelf = false, maxArgs = 0)
+    public abstract static class ToINode extends CoreMethodNode {
+
+        public ToINode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ToINode(ToINode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public int toI() {
+            return 0;
+        }
+    }
+
+    @CoreMethod(names = "to_s", needsSelf = false, maxArgs = 0)
+    public abstract static class ToSNode extends CoreMethodNode {
+
+        public ToSNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ToSNode(ToSNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString toS() {
+            return getContext().makeString("");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ObjectNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,514 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import java.math.*;
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+@CoreClass(name = "Object")
+public abstract class ObjectNodes {
+
+    @CoreMethod(names = "class", maxArgs = 0)
+    public abstract static class ClassNode extends CoreMethodNode {
+
+        public ClassNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ClassNode(ClassNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyClass getClass(boolean value) {
+            if (value) {
+                return getContext().getCoreLibrary().getTrueClass();
+            } else {
+                return getContext().getCoreLibrary().getFalseClass();
+            }
+        }
+
+        @Specialization
+        public RubyClass getClass(@SuppressWarnings("unused") int value) {
+            return getContext().getCoreLibrary().getFixnumClass();
+        }
+
+        @Specialization
+        public RubyClass getClass(@SuppressWarnings("unused") BigInteger value) {
+            return getContext().getCoreLibrary().getBignumClass();
+        }
+
+        @Specialization
+        public RubyClass getClass(@SuppressWarnings("unused") double value) {
+            return getContext().getCoreLibrary().getFloatClass();
+        }
+
+        @Specialization
+        public RubyClass getClass(RubyBasicObject self) {
+            return self.getRubyClass();
+        }
+
+    }
+
+    @CoreMethod(names = "dup", maxArgs = 0)
+    public abstract static class DupNode extends CoreMethodNode {
+
+        public DupNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public DupNode(DupNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object dup(RubyObject self) {
+            return self.dup();
+        }
+
+    }
+
+    @CoreMethod(names = "extend", isSplatted = true, minArgs = 1)
+    public abstract static class ExtendNode extends CoreMethodNode {
+
+        public ExtendNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ExtendNode(ExtendNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyBasicObject extend(RubyBasicObject self, Object[] args) {
+            for (int n = 0; n < args.length; n++) {
+                self.extend((RubyModule) args[n]);
+            }
+
+            return self;
+        }
+
+    }
+
+    @CoreMethod(names = "freeze", maxArgs = 0)
+    public abstract static class FreezeNode extends CoreMethodNode {
+
+        public FreezeNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public FreezeNode(FreezeNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyObject freeze(RubyObject self) {
+            self.frozen = true;
+            return self;
+        }
+
+    }
+
+    @CoreMethod(names = "frozen?", maxArgs = 0)
+    public abstract static class FrozenNode extends CoreMethodNode {
+
+        public FrozenNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public FrozenNode(FrozenNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean isFrozen(RubyObject self) {
+            return self.frozen;
+        }
+
+    }
+
+    @CoreMethod(names = "inspect", maxArgs = 0)
+    public abstract static class InspectNode extends CoreMethodNode {
+
+        public InspectNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public InspectNode(InspectNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString inspect(boolean value) {
+            return getContext().makeString(Boolean.toString(value));
+        }
+
+        @Specialization
+        public RubyString inspect(int value) {
+            return getContext().makeString(Integer.toString(value));
+        }
+
+        @Specialization
+        public RubyString inspect(BigInteger value) {
+            return getContext().makeString(value.toString());
+        }
+
+        @Specialization
+        public RubyString inspect(double value) {
+            return getContext().makeString(Double.toString(value));
+        }
+
+        @Specialization
+        public RubyString inspect(RubyObject self) {
+            return getContext().makeString(self.inspect());
+        }
+
+    }
+
+    @CoreMethod(names = "instance_eval", needsBlock = true, maxArgs = 0)
+    public abstract static class InstanceEvalNode extends CoreMethodNode {
+
+        public InstanceEvalNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public InstanceEvalNode(InstanceEvalNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object instanceEval(VirtualFrame frame, RubyObject self, RubyProc block) {
+            return block.callWithModifiedSelf(frame.pack(), self);
+        }
+
+    }
+
+    @CoreMethod(names = "instance_variable_defined?", minArgs = 1, maxArgs = 1)
+    public abstract static class InstanceVariableDefinedNode extends CoreMethodNode {
+
+        public InstanceVariableDefinedNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public InstanceVariableDefinedNode(InstanceVariableDefinedNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean isInstanceVariableDefined(RubyBasicObject object, RubyString name) {
+            return object.isInstanceVariableDefined(RubyObject.checkInstanceVariableName(getContext(), name.toString()));
+        }
+
+        @Specialization
+        public boolean isInstanceVariableDefined(RubyBasicObject object, RubySymbol name) {
+            return object.isInstanceVariableDefined(RubyObject.checkInstanceVariableName(getContext(), name.toString()));
+        }
+
+    }
+
+    @CoreMethod(names = "instance_variable_get", minArgs = 1, maxArgs = 1)
+    public abstract static class InstanceVariableGetNode extends CoreMethodNode {
+
+        public InstanceVariableGetNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public InstanceVariableGetNode(InstanceVariableGetNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object isInstanceVariableGet(RubyBasicObject object, RubyString name) {
+            return object.getInstanceVariable(RubyObject.checkInstanceVariableName(getContext(), name.toString()));
+        }
+
+        @Specialization
+        public Object isInstanceVariableGet(RubyBasicObject object, RubySymbol name) {
+            return object.getInstanceVariable(RubyObject.checkInstanceVariableName(getContext(), name.toString()));
+        }
+
+    }
+
+    @CoreMethod(names = "instance_variable_set", minArgs = 2, maxArgs = 2)
+    public abstract static class InstanceVariableSetNode extends CoreMethodNode {
+
+        public InstanceVariableSetNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public InstanceVariableSetNode(InstanceVariableSetNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object isInstanceVariableSet(RubyBasicObject object, RubyString name, Object value) {
+            object.setInstanceVariable(RubyObject.checkInstanceVariableName(getContext(), name.toString()), value);
+            return value;
+        }
+
+        @Specialization
+        public Object isInstanceVariableSet(RubyBasicObject object, RubySymbol name, Object value) {
+            object.setInstanceVariable(RubyObject.checkInstanceVariableName(getContext(), name.toString()), value);
+            return value;
+        }
+
+    }
+
+    @CoreMethod(names = "instance_variables", maxArgs = 0)
+    public abstract static class InstanceVariablesNode extends CoreMethodNode {
+
+        public InstanceVariablesNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public InstanceVariablesNode(InstanceVariablesNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray instanceVariables(RubyObject self) {
+            final String[] instanceVariableNames = self.getInstanceVariableNames();
+
+            Arrays.sort(instanceVariableNames);
+
+            final RubyArray array = new RubyArray(getContext().getCoreLibrary().getArrayClass());
+
+            for (String name : instanceVariableNames) {
+                array.push(new RubyString(getContext().getCoreLibrary().getStringClass(), name));
+            }
+
+            return array;
+        }
+
+    }
+
+    @CoreMethod(names = {"is_a?", "instance_of?", "kind_of?"}, minArgs = 1, maxArgs = 1)
+    public abstract static class IsANode extends CoreMethodNode {
+
+        public IsANode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public IsANode(IsANode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean isA(@SuppressWarnings("unused") RubyObject self, @SuppressWarnings("unused") NilPlaceholder nil) {
+            return false;
+        }
+
+        @Specialization
+        public boolean isA(RubyObject self, RubyClass rubyClass) {
+            return self.getRubyClass().assignableTo(rubyClass);
+        }
+
+    }
+
+    @CoreMethod(names = "methods", minArgs = 0, maxArgs = 1)
+    public abstract static class MethodsNode extends CoreMethodNode {
+
+        public MethodsNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public MethodsNode(MethodsNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray methods(RubyObject self, boolean includeInherited) {
+            if (!includeInherited) {
+                self.getRubyClass().getContext().implementationMessage("Object#methods always returns inherited methods at the moment");
+            }
+
+            return methods(self, UndefinedPlaceholder.INSTANCE);
+        }
+
+        @Specialization
+        public RubyArray methods(RubyObject self, @SuppressWarnings("unused") UndefinedPlaceholder includeInherited) {
+            final RubyArray array = new RubyArray(self.getRubyClass().getContext().getCoreLibrary().getArrayClass());
+
+            final Map<String, RubyMethod> methods = new HashMap<>();
+
+            self.getLookupNode().getMethods(methods);
+
+            for (RubyMethod method : methods.values()) {
+                if (method.getVisibility() == Visibility.PUBLIC || method.getVisibility() == Visibility.PROTECTED) {
+                    array.push(new RubySymbol(self.getRubyClass().getContext().getCoreLibrary().getSymbolClass(), method.getName()));
+                }
+            }
+
+            return array;
+        }
+
+    }
+
+    @CoreMethod(names = "nil?", needsSelf = false, maxArgs = 0)
+    public abstract static class NilNode extends CoreMethodNode {
+
+        public NilNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public NilNode(NilNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean nil() {
+            return false;
+        }
+    }
+
+    @CoreMethod(names = "object_id", needsSelf = true, maxArgs = 0)
+    public abstract static class ObjectIDNode extends CoreMethodNode {
+
+        public ObjectIDNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ObjectIDNode(ObjectIDNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object objectID(RubyBasicObject object) {
+            return GeneralConversions.fixnumOrBignum(object.getObjectID());
+        }
+
+    }
+
+    @CoreMethod(names = "respond_to?", minArgs = 1, maxArgs = 2)
+    public abstract static class RespondToNode extends CoreMethodNode {
+
+        public RespondToNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public RespondToNode(RespondToNode prev) {
+            super(prev);
+        }
+
+        @Specialization(order = 1)
+        public boolean doesRespondTo(Object object, RubyString name, @SuppressWarnings("unused") UndefinedPlaceholder checkVisibility) {
+            return doesRespondTo(getContext().getCoreLibrary().box(object), name.toString(), false);
+        }
+
+        @Specialization(order = 2)
+        public boolean doesRespondTo(Object object, RubyString name, boolean dontCheckVisibility) {
+            return doesRespondTo(getContext().getCoreLibrary().box(object), name.toString(), dontCheckVisibility);
+        }
+
+        @Specialization(order = 3)
+        public boolean doesRespondTo(Object object, RubySymbol name, @SuppressWarnings("unused") UndefinedPlaceholder checkVisibility) {
+            return doesRespondTo(getContext().getCoreLibrary().box(object), name.toString(), false);
+        }
+
+        @Specialization(order = 4)
+        public boolean doesRespondTo(Object object, RubySymbol name, boolean dontCheckVisibility) {
+            return doesRespondTo(getContext().getCoreLibrary().box(object), name.toString(), dontCheckVisibility);
+        }
+
+        private static boolean doesRespondTo(RubyBasicObject object, String name, boolean dontCheckVisibility) {
+            final RubyMethod method = object.getLookupNode().lookupMethod(name);
+
+            if (method == null || method.isUndefined()) {
+                return false;
+            }
+
+            if (dontCheckVisibility) {
+                return true;
+            } else {
+                return method.getVisibility() == Visibility.PUBLIC;
+            }
+        }
+
+    }
+
+    @CoreMethod(names = "singleton_class", maxArgs = 0)
+    public abstract static class SingletonClassNode extends CoreMethodNode {
+
+        public SingletonClassNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public SingletonClassNode(SingletonClassNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyClass singletonClass(RubyBasicObject self) {
+            return self.getSingletonClass();
+        }
+
+    }
+
+    @CoreMethod(names = "singleton_methods", minArgs = 0, maxArgs = 1)
+    public abstract static class SingletonMethodsNode extends CoreMethodNode {
+
+        public SingletonMethodsNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public SingletonMethodsNode(SingletonMethodsNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray singletonMethods(RubyObject self, boolean includeInherited) {
+            if (!includeInherited) {
+                self.getRubyClass().getContext().implementationMessage("Object#singleton_methods always returns inherited methods at the moment");
+            }
+
+            return singletonMethods(self, UndefinedPlaceholder.INSTANCE);
+        }
+
+        @Specialization
+        public RubyArray singletonMethods(RubyObject self, @SuppressWarnings("unused") UndefinedPlaceholder includeInherited) {
+            final RubyArray array = new RubyArray(self.getRubyClass().getContext().getCoreLibrary().getArrayClass());
+
+            for (RubyMethod method : self.getSingletonClass().getDeclaredMethods()) {
+                array.push(new RubySymbol(self.getRubyClass().getContext().getCoreLibrary().getSymbolClass(), method.getName()));
+            }
+
+            return array;
+        }
+
+    }
+
+    @CoreMethod(names = "to_s", maxArgs = 0)
+    public abstract static class ToSNode extends CoreMethodNode {
+
+        public ToSNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ToSNode(ToSNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString toS(RubyObject self) {
+            return getContext().makeString(self.toString());
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ObjectSpaceNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import java.math.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+@CoreClass(name = "ObjectSpace")
+public abstract class ObjectSpaceNodes {
+
+    @CoreMethod(names = "_id2ref", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1)
+    public abstract static class ID2RefNode extends CoreMethodNode {
+
+        public ID2RefNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ID2RefNode(ID2RefNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object id2Ref(int id) {
+            final Object object = getContext().getObjectSpaceManager().lookupId(id);
+
+            if (object == null) {
+                return NilPlaceholder.INSTANCE;
+            } else {
+                return object;
+            }
+        }
+
+        @Specialization
+        public Object id2Ref(BigInteger id) {
+            final Object object = getContext().getObjectSpaceManager().lookupId(id.longValue());
+
+            if (object == null) {
+                return NilPlaceholder.INSTANCE;
+            } else {
+                return object;
+            }
+        }
+
+    }
+
+    @CoreMethod(names = "each_object", isModuleMethod = true, needsSelf = false, needsBlock = true, minArgs = 0, maxArgs = 1)
+    public abstract static class EachObjectNode extends YieldingCoreMethodNode {
+
+        public EachObjectNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public EachObjectNode(EachObjectNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder eachObject(VirtualFrame frame, @SuppressWarnings("unused") UndefinedPlaceholder ofClass, RubyProc block) {
+            for (RubyBasicObject object : getContext().getObjectSpaceManager().getObjects()) {
+                yield(frame, block, object);
+            }
+            return NilPlaceholder.INSTANCE;
+        }
+
+        @Specialization
+        public NilPlaceholder eachObject(VirtualFrame frame, RubyClass ofClass, RubyProc block) {
+            for (RubyBasicObject object : getContext().getObjectSpaceManager().getObjects()) {
+                if (object.getRubyClass().assignableTo(ofClass)) {
+                    yield(frame, block, object);
+                }
+            }
+            return NilPlaceholder.INSTANCE;
+        }
+
+    }
+
+    @CoreMethod(names = "define_finalizer", isModuleMethod = true, needsSelf = false, minArgs = 2, maxArgs = 2)
+    public abstract static class DefineFinalizerNode extends CoreMethodNode {
+
+        public DefineFinalizerNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public DefineFinalizerNode(DefineFinalizerNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyProc defineFinalizer(Object object, RubyProc finalizer) {
+            getContext().getObjectSpaceManager().defineFinalizer((RubyBasicObject) object, finalizer);
+            return finalizer;
+        }
+    }
+
+    @CoreMethod(names = {"garbage_collect", "start"}, isModuleMethod = true, needsSelf = false, maxArgs = 0)
+    public abstract static class GarbageCollectNode extends CoreMethodNode {
+
+        public GarbageCollectNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public GarbageCollectNode(GarbageCollectNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder garbageCollect() {
+            final RubyThread runningThread = getContext().getThreadManager().leaveGlobalLock();
+
+            try {
+                System.gc();
+            } finally {
+                getContext().getThreadManager().enterGlobalLock(runningThread);
+            }
+
+            return NilPlaceholder.INSTANCE;
+        }
+    }
+
+    @CoreMethod(names = "undefine_finalizer", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1)
+    public abstract static class UndefineFinalizerNode extends CoreMethodNode {
+
+        public UndefineFinalizerNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public UndefineFinalizerNode(UndefineFinalizerNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object undefineFinalizer(Object object) {
+            getContext().getObjectSpaceManager().undefineFinalizer((RubyBasicObject) object);
+            return object;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ProcNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+@CoreClass(name = "Proc")
+public abstract class ProcNodes {
+
+    @CoreMethod(names = {"call", "[]"}, isSplatted = true)
+    public abstract static class CallNode extends CoreMethodNode {
+
+        public CallNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public CallNode(CallNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object call(VirtualFrame frame, RubyProc proc, Object[] args) {
+            return proc.call(frame.getCaller(), args);
+        }
+
+    }
+
+    @CoreMethod(names = "initialize", needsBlock = true, maxArgs = 0)
+    public abstract static class InitializeNode extends CoreMethodNode {
+
+        public InitializeNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public InitializeNode(InitializeNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder initialize(VirtualFrame frame, RubyProc proc, RubyProc block) {
+            final RubyArguments callerArguments = frame.getCaller().unpack().getArguments(RubyArguments.class);
+            proc.initialize(RubyProc.Type.PROC, callerArguments.getSelf(), callerArguments.getBlock(), block.getMethod());
+            return NilPlaceholder.INSTANCE;
+        }
+
+    }
+
+    @CoreMethod(names = "lambda?", maxArgs = 0)
+    public abstract static class LambdaNode extends CoreMethodNode {
+
+        public LambdaNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public LambdaNode(LambdaNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean lambda(RubyProc proc) {
+            return proc.getType() == RubyProc.Type.LAMBDA;
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ProcessNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+@CoreClass(name = "Process")
+public abstract class ProcessNodes {
+
+    @CoreMethod(names = "pid", isModuleMethod = true, needsSelf = false, maxArgs = 0)
+    public abstract static class PidNode extends CoreMethodNode {
+
+        public PidNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public PidNode(PidNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public int pid() {
+            return getContext().getPOSIX().getpid();
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/RangeNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.nodes.call.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+import com.oracle.truffle.ruby.runtime.core.range.*;
+
+@CoreClass(name = "Range")
+public abstract class RangeNodes {
+
+    @CoreMethod(names = {"collect", "map"}, needsBlock = true, maxArgs = 0)
+    public abstract static class CollectNode extends YieldingCoreMethodNode {
+
+        public CollectNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public CollectNode(CollectNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray collect(VirtualFrame frame, FixnumRange range, RubyProc block) {
+            final RubyContext context = getContext();
+
+            final RubyArray array = new RubyArray(context.getCoreLibrary().getArrayClass());
+
+            for (int n = range.getBegin(); n < range.getExclusiveEnd(); n++) {
+                array.push(yield(frame, block, n));
+            }
+
+            return array;
+        }
+
+    }
+
+    @CoreMethod(names = "each", needsBlock = true, maxArgs = 0)
+    public abstract static class EachNode extends YieldingCoreMethodNode {
+
+        public EachNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public EachNode(EachNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public FixnumRange each(VirtualFrame frame, FixnumRange range, RubyProc block) {
+            for (int n = range.getBegin(); n < range.getExclusiveEnd(); n++) {
+                yield(frame, block, n);
+            }
+
+            return range;
+        }
+
+    }
+
+    @CoreMethod(names = "exclude_end?", maxArgs = 0)
+    public abstract static class ExcludeEndNode extends CoreMethodNode {
+
+        public ExcludeEndNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ExcludeEndNode(ExcludeEndNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean excludeEnd(RubyRange range) {
+            return range.doesExcludeEnd();
+        }
+
+    }
+
+    @CoreMethod(names = "first", maxArgs = 0)
+    public abstract static class FirstNode extends CoreMethodNode {
+
+        public FirstNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public FirstNode(FirstNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public int each(FixnumRange range) {
+            return range.getBegin();
+        }
+
+        @Specialization
+        public Object each(ObjectRange range) {
+            return range.getBegin();
+        }
+
+    }
+
+    @CoreMethod(names = "include?", maxArgs = 1)
+    public abstract static class IncludeNode extends CoreMethodNode {
+
+        @Child protected DispatchHeadNode callLess;
+        @Child protected DispatchHeadNode callGreater;
+        @Child protected DispatchHeadNode callGreaterEqual;
+
+        public IncludeNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+            callLess = adoptChild(new DispatchHeadNode(context, getSourceSection(), "<", false));
+            callGreater = adoptChild(new DispatchHeadNode(context, getSourceSection(), ">", false));
+            callGreaterEqual = adoptChild(new DispatchHeadNode(context, getSourceSection(), ">=", false));
+        }
+
+        public IncludeNode(IncludeNode prev) {
+            super(prev);
+            callLess = adoptChild(prev.callLess);
+            callGreater = adoptChild(prev.callGreater);
+            callGreaterEqual = adoptChild(prev.callGreaterEqual);
+        }
+
+        @Specialization
+        public boolean include(FixnumRange range, int value) {
+            return value >= range.getBegin() && value < range.getExclusiveEnd();
+        }
+
+        @Specialization
+        public boolean include(VirtualFrame frame, ObjectRange range, Object value) {
+            if ((boolean) callLess.dispatch(frame, value, null, range.getBegin())) {
+                return false;
+            }
+
+            if (range.doesExcludeEnd()) {
+                if ((boolean) callGreaterEqual.dispatch(frame, value, null, range.getEnd())) {
+                    return false;
+                }
+            } else {
+                if ((boolean) callGreater.dispatch(frame, value, null, range.getEnd())) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+    }
+
+    @CoreMethod(names = "last", maxArgs = 0)
+    public abstract static class LastNode extends CoreMethodNode {
+
+        public LastNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public LastNode(LastNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public int last(FixnumRange range) {
+            return range.getEnd();
+        }
+
+        @Specialization
+        public Object last(ObjectRange range) {
+            return range.getEnd();
+        }
+
+    }
+
+    @CoreMethod(names = "step", needsBlock = true, minArgs = 1, maxArgs = 1)
+    public abstract static class StepNode extends YieldingCoreMethodNode {
+
+        public StepNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public StepNode(StepNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public FixnumRange step(VirtualFrame frame, FixnumRange range, int step, RubyProc block) {
+            for (int n = range.getBegin(); n < range.getExclusiveEnd(); n += step) {
+                yield(frame, block, n);
+            }
+
+            return range;
+        }
+
+    }
+
+    @CoreMethod(names = "to_a", maxArgs = 0)
+    public abstract static class ToANode extends CoreMethodNode {
+
+        public ToANode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ToANode(ToANode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray toA(RubyRange range) {
+            return range.toArray();
+        }
+
+    }
+
+    @CoreMethod(names = "to_s", maxArgs = 0)
+    public abstract static class ToSNode extends CoreMethodNode {
+
+        public ToSNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ToSNode(ToSNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString toS(RubyRange range) {
+            return getContext().makeString(range.toString());
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/RegexpNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import java.util.regex.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+@CoreClass(name = "Regexp")
+public abstract class RegexpNodes {
+
+    @CoreMethod(names = {"=~", "==="}, minArgs = 1, maxArgs = 1)
+    public abstract static class MatchOperatorNode extends CoreMethodNode {
+
+        public MatchOperatorNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public MatchOperatorNode(MatchOperatorNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object match(VirtualFrame frame, RubyRegexp regexp, RubyString string) {
+            return regexp.matchOperator(frame.getCaller().unpack(), string.toString());
+        }
+
+    }
+
+    @CoreMethod(names = "!~", minArgs = 1, maxArgs = 1)
+    public abstract static class NotMatchOperatorNode extends CoreMethodNode {
+
+        public NotMatchOperatorNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public NotMatchOperatorNode(NotMatchOperatorNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object match(VirtualFrame frame, RubyRegexp regexp, RubyString string) {
+            return regexp.matchOperator(frame.getCaller().unpack(), string.toString()) == NilPlaceholder.INSTANCE;
+        }
+
+    }
+
+    @CoreMethod(names = "escape", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1)
+    public abstract static class EscapeNode extends CoreMethodNode {
+
+        public EscapeNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public EscapeNode(EscapeNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString sqrt(RubyString pattern) {
+            return getContext().makeString(Pattern.quote(pattern.toString()));
+        }
+
+    }
+
+    @CoreMethod(names = "initialize", minArgs = 1, maxArgs = 1)
+    public abstract static class InitializeNode extends CoreMethodNode {
+
+        public InitializeNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public InitializeNode(InitializeNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder initialize(RubyRegexp regexp, RubyString string) {
+            regexp.initialize(string.toString());
+            return NilPlaceholder.INSTANCE;
+        }
+
+    }
+
+    @CoreMethod(names = "match", minArgs = 1, maxArgs = 1)
+    public abstract static class MatchNode extends CoreMethodNode {
+
+        public MatchNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public MatchNode(MatchNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object match(RubyRegexp regexp, RubyString string) {
+            return regexp.match(string.toString());
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/SignalNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+@CoreClass(name = "Signal")
+public abstract class SignalNodes {
+
+    @CoreMethod(names = "trap", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1)
+    public abstract static class SignalNode extends CoreMethodNode {
+
+        public SignalNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public SignalNode(SignalNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder trap(@SuppressWarnings("unused") Object signal) {
+            getContext().implementationMessage("Signal#trap doesn't do anything");
+            return NilPlaceholder.INSTANCE;
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/StringNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,559 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import java.util.*;
+import java.util.regex.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+@CoreClass(name = "String")
+public abstract class StringNodes {
+
+    @CoreMethod(names = "+", minArgs = 1, maxArgs = 1)
+    public abstract static class AddNode extends CoreMethodNode {
+
+        public AddNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public AddNode(AddNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString add(RubyString a, RubyString b) {
+            return new RubyString(a.getRubyClass().getContext().getCoreLibrary().getStringClass(), a.toString() + b.toString());
+        }
+    }
+
+    @CoreMethod(names = {"==", "==="}, minArgs = 1, maxArgs = 1)
+    public abstract static class EqualNode extends CoreMethodNode {
+
+        public EqualNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public EqualNode(EqualNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean equal(@SuppressWarnings("unused") RubyString a, @SuppressWarnings("unused") NilPlaceholder b) {
+            return false;
+        }
+
+        @Specialization
+        public boolean equal(RubyString a, RubyString b) {
+            return a.toString().equals(b.toString());
+        }
+    }
+
+    @CoreMethod(names = "!=", minArgs = 1, maxArgs = 1)
+    public abstract static class NotEqualNode extends CoreMethodNode {
+
+        public NotEqualNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public NotEqualNode(NotEqualNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean equal(@SuppressWarnings("unused") RubyString a, @SuppressWarnings("unused") NilPlaceholder b) {
+            return true;
+        }
+
+        @Specialization
+        public boolean notEqual(RubyString a, RubyString b) {
+            return !a.toString().equals(b.toString());
+        }
+
+    }
+
+    @CoreMethod(names = "<=>", minArgs = 1, maxArgs = 1)
+    public abstract static class CompareNode extends CoreMethodNode {
+
+        public CompareNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public CompareNode(CompareNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public int compare(RubyString a, RubyString b) {
+            return a.toString().compareTo(b.toString());
+        }
+    }
+
+    @CoreMethod(names = "<<", minArgs = 1, maxArgs = 1)
+    public abstract static class ConcatNode extends CoreMethodNode {
+
+        public ConcatNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ConcatNode(ConcatNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString concat(RubyString string, RubyString other) {
+            string.replace(string.toString() + other.toString());
+            return string;
+        }
+    }
+
+    @CoreMethod(names = "%", minArgs = 1, maxArgs = 1, isSplatted = true)
+    public abstract static class FormatNode extends CoreMethodNode {
+
+        public FormatNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public FormatNode(FormatNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString format(RubyString format, Object[] args) {
+            final RubyContext context = getContext();
+
+            if (args.length == 1 && args[0] instanceof RubyArray) {
+                return context.makeString(StringFormatter.format(format.toString(), ((RubyArray) args[0]).asList()));
+            } else {
+                return context.makeString(StringFormatter.format(format.toString(), Arrays.asList(args)));
+            }
+        }
+    }
+
+    @CoreMethod(names = "[]", minArgs = 1, maxArgs = 2, isSplatted = true)
+    public abstract static class GetIndexNode extends CoreMethodNode {
+
+        public GetIndexNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public GetIndexNode(GetIndexNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object getIndex(RubyString string, Object[] args) {
+            return RubyString.getIndex(getContext(), string.toString(), args);
+        }
+    }
+
+    @CoreMethod(names = "=~", minArgs = 1, maxArgs = 1)
+    public abstract static class MatchOperatorNode extends CoreMethodNode {
+
+        public MatchOperatorNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public MatchOperatorNode(MatchOperatorNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object match(VirtualFrame frame, RubyString string, RubyRegexp regexp) {
+            return regexp.matchOperator(frame, string.toString());
+        }
+    }
+
+    @CoreMethod(names = "chomp", maxArgs = 0)
+    public abstract static class ChompNode extends CoreMethodNode {
+
+        public ChompNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ChompNode(ChompNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString chomp(RubyString string) {
+            return string.getRubyClass().getContext().makeString(string.toString().trim());
+        }
+    }
+
+    @CoreMethod(names = "chomp!", maxArgs = 0)
+    public abstract static class ChompBangNode extends CoreMethodNode {
+
+        public ChompBangNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ChompBangNode(ChompBangNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString chompBang(RubyString string) {
+            string.replace(string.toString().trim());
+            return string;
+        }
+    }
+
+    @CoreMethod(names = "downcase", maxArgs = 0)
+    public abstract static class DowncaseNode extends CoreMethodNode {
+
+        public DowncaseNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public DowncaseNode(DowncaseNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString downcase(RubyString string) {
+            return string.getRubyClass().getContext().makeString(string.toString().toLowerCase());
+        }
+    }
+
+    @CoreMethod(names = "downcase!", maxArgs = 0)
+    public abstract static class DowncaseBangNode extends CoreMethodNode {
+
+        public DowncaseBangNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public DowncaseBangNode(DowncaseBangNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString downcase(RubyString string) {
+            string.replace(string.toString().toLowerCase());
+            return string;
+        }
+    }
+
+    @CoreMethod(names = "empty?", maxArgs = 0)
+    public abstract static class EmptyNode extends CoreMethodNode {
+
+        public EmptyNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public EmptyNode(EmptyNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean empty(RubyString string) {
+            return string.toString().isEmpty();
+        }
+    }
+
+    @CoreMethod(names = "end_with?", minArgs = 1, maxArgs = 1)
+    public abstract static class EndWithNode extends CoreMethodNode {
+
+        public EndWithNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public EndWithNode(EndWithNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean endWith(RubyString string, RubyString b) {
+            return string.toString().endsWith(b.toString());
+        }
+    }
+
+    @CoreMethod(names = "gsub", minArgs = 2, maxArgs = 2)
+    public abstract static class GsubNode extends CoreMethodNode {
+
+        public GsubNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public GsubNode(GsubNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString gsub(RubyString string, RubyString regexpString, RubyString replacement) {
+            final RubyRegexp regexp = new RubyRegexp(getContext().getCoreLibrary().getRegexpClass(), regexpString.toString());
+            return gsub(string, regexp, replacement);
+        }
+
+        @Specialization
+        public RubyString gsub(RubyString string, RubyRegexp regexp, RubyString replacement) {
+            return getContext().makeString(regexp.getPattern().matcher(string.toString()).replaceAll(replacement.toString()));
+        }
+    }
+
+    @CoreMethod(names = "inspect", maxArgs = 0)
+    public abstract static class InpsectNode extends CoreMethodNode {
+
+        public InpsectNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public InpsectNode(InpsectNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString inspect(RubyString string) {
+            return getContext().makeString("\"" + string.toString().replace("\\", "\\\\").replace("\"", "\\\"") + "\"");
+        }
+    }
+
+    @CoreMethod(names = "ljust", minArgs = 1, maxArgs = 2)
+    public abstract static class LjustNode extends CoreMethodNode {
+
+        public LjustNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public LjustNode(LjustNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString ljust(RubyString string, int length, @SuppressWarnings("unused") UndefinedPlaceholder padding) {
+            return getContext().makeString(RubyString.ljust(string.toString(), length, " "));
+        }
+
+        @Specialization
+        public RubyString ljust(RubyString string, int length, RubyString padding) {
+            return getContext().makeString(RubyString.ljust(string.toString(), length, padding.toString()));
+        }
+
+    }
+
+    @CoreMethod(names = "size", maxArgs = 0)
+    public abstract static class SizeNode extends CoreMethodNode {
+
+        public SizeNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public SizeNode(SizeNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public int size(RubyString string) {
+            return string.toString().length();
+        }
+    }
+
+    @CoreMethod(names = "match", minArgs = 1, maxArgs = 1)
+    public abstract static class MatchNode extends CoreMethodNode {
+
+        public MatchNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public MatchNode(MatchNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object match(RubyString string, RubyString regexpString) {
+            final RubyRegexp regexp = new RubyRegexp(getContext().getCoreLibrary().getRegexpClass(), regexpString.toString());
+            return regexp.match(string.toString());
+        }
+
+        @Specialization
+        public Object match(RubyString string, RubyRegexp regexp) {
+            return regexp.match(string.toString());
+        }
+    }
+
+    @CoreMethod(names = "rjust", minArgs = 1, maxArgs = 2)
+    public abstract static class RjustNode extends CoreMethodNode {
+
+        public RjustNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public RjustNode(RjustNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString rjust(RubyString string, int length, @SuppressWarnings("unused") UndefinedPlaceholder padding) {
+            return getContext().makeString(RubyString.rjust(string.toString(), length, " "));
+        }
+
+        @Specialization
+        public RubyString rjust(RubyString string, int length, RubyString padding) {
+            return getContext().makeString(RubyString.rjust(string.toString(), length, padding.toString()));
+        }
+
+    }
+
+    @CoreMethod(names = "scan", minArgs = 1, maxArgs = 1)
+    public abstract static class ScanNode extends CoreMethodNode {
+
+        public ScanNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ScanNode(ScanNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray scan(RubyString string, RubyString regexp) {
+            return RubyString.scan(getContext(), string.toString(), Pattern.compile(regexp.toString()));
+        }
+
+        @Specialization
+        public RubyArray scan(RubyString string, RubyRegexp regexp) {
+            return RubyString.scan(getContext(), string.toString(), regexp.getPattern());
+        }
+
+    }
+
+    @CoreMethod(names = "split", minArgs = 1, maxArgs = 1)
+    public abstract static class SplitNode extends CoreMethodNode {
+
+        public SplitNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public SplitNode(SplitNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyArray split(RubyString string, RubyString sep) {
+            final RubyContext context = getContext();
+
+            final String[] components = string.toString().split(Pattern.quote(sep.toString()));
+
+            final Object[] objects = new Object[components.length];
+
+            for (int n = 0; n < objects.length; n++) {
+                objects[n] = context.makeString(components[n]);
+            }
+
+            return RubyArray.specializedFromObjects(context.getCoreLibrary().getArrayClass(), objects);
+        }
+
+        @Specialization
+        public RubyArray split(RubyString string, RubyRegexp sep) {
+            final RubyContext context = getContext();
+
+            final String[] components = string.toString().split(sep.getPattern().pattern());
+
+            final Object[] objects = new Object[components.length];
+
+            for (int n = 0; n < objects.length; n++) {
+                objects[n] = context.makeString(components[n]);
+            }
+
+            return RubyArray.specializedFromObjects(context.getCoreLibrary().getArrayClass(), objects);
+        }
+    }
+
+    @CoreMethod(names = "start_with?", minArgs = 1, maxArgs = 1)
+    public abstract static class StartWithNode extends CoreMethodNode {
+
+        public StartWithNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public StartWithNode(StartWithNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean endWith(RubyString string, RubyString b) {
+            return string.toString().startsWith(b.toString());
+        }
+    }
+
+    @CoreMethod(names = "to_f", maxArgs = 0)
+    public abstract static class ToFNode extends CoreMethodNode {
+
+        public ToFNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ToFNode(ToFNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public double toF(RubyString string) {
+            return Double.parseDouble(string.toString());
+        }
+    }
+
+    @CoreMethod(names = "to_i", maxArgs = 0)
+    public abstract static class ToINode extends CoreMethodNode {
+
+        public ToINode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ToINode(ToINode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object toI(RubyString string) {
+            return string.toInteger();
+        }
+    }
+
+    @CoreMethod(names = "to_s", maxArgs = 0)
+    public abstract static class ToSNode extends CoreMethodNode {
+
+        public ToSNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ToSNode(ToSNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString toF(RubyString string) {
+            return string;
+        }
+    }
+
+    @CoreMethod(names = {"to_sym", "intern"}, maxArgs = 0)
+    public abstract static class ToSymNode extends CoreMethodNode {
+
+        public ToSymNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ToSymNode(ToSymNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubySymbol toSym(RubyString string) {
+            return new RubySymbol(getContext().getCoreLibrary().getSymbolClass(), string.toString());
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/StructNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+@CoreClass(name = "Struct")
+public abstract class StructNodes {
+
+    @CoreMethod(names = "initialize", needsBlock = true, appendCallNode = true, isSplatted = true)
+    public abstract static class InitalizeNode extends CoreMethodNode {
+
+        public InitalizeNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public InitalizeNode(InitalizeNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder initialize(VirtualFrame frame, RubyClass struct, Object[] args, Object block, Node callSite) {
+            CompilerDirectives.transferToInterpreter();
+
+            final RubySymbol[] symbols = new RubySymbol[args.length];
+
+            for (int n = 0; n < args.length; n++) {
+                symbols[n] = (RubySymbol) args[n];
+            }
+
+            for (RubySymbol symbol : symbols) {
+                ModuleNodes.AttrAccessorNode.attrAccessor(getContext(), callSite.getSourceSection(), struct, symbol.toString());
+            }
+
+            if (!RubyNilClass.isNil(block)) {
+                ((RubyProc) block).callWithModifiedSelf(frame.pack(), struct);
+            }
+
+            return NilPlaceholder.INSTANCE;
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/SymbolNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+@CoreClass(name = "Symbol")
+public abstract class SymbolNodes {
+
+    @CoreMethod(names = {"==", "==="}, minArgs = 1, maxArgs = 1)
+    public abstract static class EqualNode extends CoreMethodNode {
+
+        public EqualNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public EqualNode(EqualNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean equal(@SuppressWarnings("unused") RubyString a, @SuppressWarnings("unused") NilPlaceholder b) {
+            return false;
+        }
+
+        @Specialization
+        public boolean equal(RubySymbol a, RubySymbol b) {
+            return a.toString().equals(b.toString());
+        }
+
+        @Specialization
+        public boolean equal(RubySymbol a, RubyString b) {
+            return a.toString().equals(b.toString());
+        }
+
+        @Specialization
+        public boolean equal(RubySymbol a, int b) {
+            return a.toString().equals(Integer.toString(b));
+        }
+
+    }
+
+    @CoreMethod(names = "empty?", maxArgs = 0)
+    public abstract static class EmptyNode extends CoreMethodNode {
+
+        public EmptyNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public EmptyNode(EmptyNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean empty(RubySymbol symbol) {
+            return symbol.toString().isEmpty();
+        }
+
+    }
+
+    @CoreMethod(names = "to_proc", maxArgs = 0)
+    public abstract static class ToProcNode extends CoreMethodNode {
+
+        public ToProcNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ToProcNode(ToProcNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyProc toProc(RubySymbol symbol) {
+            // TODO(CS): this should be doing all kinds of caching
+            return symbol.toProc();
+        }
+    }
+
+    @CoreMethod(names = "to_sym", maxArgs = 0)
+    public abstract static class ToSymNode extends CoreMethodNode {
+
+        public ToSymNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ToSymNode(ToSymNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubySymbol toSym(RubySymbol symbol) {
+            return symbol;
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/SystemNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import java.io.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * Represents an expression that is evaluated by running it as a system command via forking and
+ * execing, and then taking stdout as a string.
+ */
+@NodeInfo(shortName = "system")
+public class SystemNode extends RubyNode {
+
+    @Child protected RubyNode child;
+
+    public SystemNode(RubyContext context, SourceSection sourceSection, RubyNode child) {
+        super(context, sourceSection);
+        this.child = adoptChild(child);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        final RubyContext context = getContext();
+
+        final String command = child.execute(frame).toString();
+
+        Process process;
+
+        try {
+            // We need to run via bash to get the variable and other expansion we expect
+            process = Runtime.getRuntime().exec(new String[]{"bash", "-c", command});
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+
+        final InputStream stdout = process.getInputStream();
+        final BufferedReader reader = new BufferedReader(new InputStreamReader(stdout));
+
+        final StringBuilder resultBuilder = new StringBuilder();
+
+        String line;
+
+        // TODO(cs): this isn't great for binary output
+
+        try {
+            while ((line = reader.readLine()) != null) {
+                resultBuilder.append(line);
+                resultBuilder.append("\n");
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+
+        return context.makeString(resultBuilder.toString());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ThreadNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+@CoreClass(name = "Thread")
+public abstract class ThreadNodes {
+
+    @CoreMethod(names = "initialize", needsBlock = true, maxArgs = 0)
+    public abstract static class InitializeNode extends CoreMethodNode {
+
+        public InitializeNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public InitializeNode(InitializeNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder initialize(RubyThread thread, RubyProc block) {
+            thread.initialize(block);
+            return NilPlaceholder.INSTANCE;
+        }
+
+    }
+
+    @CoreMethod(names = "join", maxArgs = 0)
+    public abstract static class JoinNode extends CoreMethodNode {
+
+        public JoinNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public JoinNode(JoinNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyThread join(RubyThread self) {
+            self.join();
+            return self;
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/TimeNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+@CoreClass(name = "Time")
+public abstract class TimeNodes {
+
+    @CoreMethod(names = "-", minArgs = 1, maxArgs = 1)
+    public abstract static class SubNode extends CoreMethodNode {
+
+        public SubNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public SubNode(SubNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public double sub(RubyTime a, RubyTime b) {
+            return a.subtract(b);
+        }
+
+    }
+
+    @CoreMethod(names = "now", isModuleMethod = true, needsSelf = false, maxArgs = 0)
+    public abstract static class NowNode extends CoreMethodNode {
+
+        public NowNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public NowNode(NowNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyTime now() {
+            return RubyTime.fromDate(getContext().getCoreLibrary().getTimeClass(), System.currentTimeMillis());
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/TrueClassNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+@CoreClass(name = "TrueClass")
+public abstract class TrueClassNodes {
+
+    @CoreMethod(names = "!", needsSelf = false, maxArgs = 0)
+    public abstract static class NotNode extends CoreMethodNode {
+
+        public NotNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public NotNode(NotNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean not() {
+            return false;
+        }
+
+    }
+
+    @CoreMethod(names = {"==", "===", "=~"}, needsSelf = false, minArgs = 1, maxArgs = 1)
+    public abstract static class EqualNode extends CoreMethodNode {
+
+        public EqualNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public EqualNode(EqualNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean equal(boolean other) {
+            return other;
+        }
+
+        @Specialization
+        public boolean equal(Object other) {
+            return other instanceof Boolean && ((boolean) other);
+        }
+
+    }
+
+    @CoreMethod(names = "^", needsSelf = false, minArgs = 1, maxArgs = 1)
+    public abstract static class XorNode extends CoreMethodNode {
+
+        public XorNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public XorNode(XorNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean xor(boolean other) {
+            return true ^ other;
+        }
+
+    }
+
+    @CoreMethod(names = "to_s", needsSelf = false, maxArgs = 0)
+    public abstract static class ToSNode extends CoreMethodNode {
+
+        public ToSNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ToSNode(ToSNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public RubyString toS() {
+            return getContext().makeString("true");
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/YieldingCoreMethodNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.nodes.yield.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+public abstract class YieldingCoreMethodNode extends CoreMethodNode {
+
+    @Child protected YieldDispatchNode dispatchNode;
+
+    public YieldingCoreMethodNode(RubyContext context, SourceSection sourceSection) {
+        super(context, sourceSection);
+        dispatchNode = adoptChild(new UninitializedYieldDispatchNode(context, getSourceSection()));
+    }
+
+    public YieldingCoreMethodNode(YieldingCoreMethodNode prev) {
+        super(prev);
+        dispatchNode = adoptChild(prev.dispatchNode);
+    }
+
+    public Object yield(VirtualFrame frame, RubyProc block, Object... arguments) {
+        return dispatchNode.dispatch(frame, block, arguments);
+    }
+
+    public boolean yieldBoolean(VirtualFrame frame, RubyProc block, Object... arguments) {
+        return GeneralConversions.toBoolean(dispatchNode.dispatch(frame, block, arguments));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/DebugNodes.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.debug;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.source.*;
+import com.oracle.truffle.ruby.nodes.call.*;
+import com.oracle.truffle.ruby.nodes.core.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+
+@CoreClass(name = "Debug")
+public abstract class DebugNodes {
+
+    @CoreMethod(names = "break", isModuleMethod = true, needsSelf = false, needsBlock = true, appendCallNode = true, minArgs = 0, maxArgs = 3)
+    public abstract static class BreakNode extends CoreMethodNode {
+
+        public BreakNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public BreakNode(BreakNode prev) {
+            super(prev);
+        }
+
+        @Specialization(order = 1)
+        public NilPlaceholder debugBreak(VirtualFrame frame, Node callNode, @SuppressWarnings("unused") UndefinedPlaceholder undefined0, @SuppressWarnings("unused") UndefinedPlaceholder undefined1,
+                        @SuppressWarnings("unused") UndefinedPlaceholder block) {
+            final RubyContext context = getContext();
+            if (context.getConfiguration().getDebug()) {
+                Node realCallNode = callNode;
+                while (realCallNode != null && !(realCallNode instanceof CallNode)) {
+                    realCallNode = realCallNode.getParent();
+                }
+                context.getDebugManager().haltedAt(realCallNode, frame.materialize());
+            }
+            return NilPlaceholder.INSTANCE;
+        }
+
+        @Specialization(order = 2)
+        public NilPlaceholder debugBreak(RubyString fileName, int line, @SuppressWarnings("unused") Node callNode, @SuppressWarnings("unused") UndefinedPlaceholder block) {
+            final RubyContext context = getContext();
+            if (context.getConfiguration().getDebug()) {
+                final Source source = context.getSourceManager().get(fileName.toString());
+                final SourceLineLocation lineLocation = new SourceLineLocation(source, line);
+                context.getDebugManager().setBreakpoint(lineLocation);
+            }
+            return NilPlaceholder.INSTANCE;
+        }
+
+        @Specialization(order = 3)
+        public NilPlaceholder debugBreak(RubyString fileName, int line, @SuppressWarnings("unused") Node callNode, RubyProc block) {
+            final RubyContext context = getContext();
+            if (context.getConfiguration().getDebug()) {
+                final Source source = context.getSourceManager().get(fileName.toString());
+                final SourceLineLocation lineLocation = new SourceLineLocation(source, line);
+                context.getDebugManager().setLineProc(lineLocation, block);
+            }
+            return NilPlaceholder.INSTANCE;
+        }
+
+        @Specialization(order = 4)
+        public NilPlaceholder debugBreak(RubySymbol methodName, RubySymbol localName, @SuppressWarnings("unused") Node callNode, @SuppressWarnings("unused") UndefinedPlaceholder block) {
+            final RubyContext context = getContext();
+            if (context.getConfiguration().getDebug()) {
+                final RubyMethod method = context.getCoreLibrary().getMainObject().getLookupNode().lookupMethod(methodName.toString());
+                context.getDebugManager().setLocalBreak(method.getUniqueIdentifier(), localName.toString());
+            }
+            return NilPlaceholder.INSTANCE;
+        }
+
+        @Specialization(order = 5)
+        public NilPlaceholder debugBreak(RubySymbol methodName, RubySymbol localName, @SuppressWarnings("unused") Node callNode, RubyProc block) {
+            final RubyContext context = getContext();
+            if (context.getConfiguration().getDebug()) {
+                final RubyMethod method = context.getCoreLibrary().getMainObject().getLookupNode().lookupMethod(methodName.toString());
+                context.getDebugManager().setLocalProc(method.getUniqueIdentifier(), localName.toString(), block);
+            }
+            return NilPlaceholder.INSTANCE;
+        }
+
+    }
+
+    @CoreMethod(names = "continue", isModuleMethod = true, needsSelf = false, maxArgs = 0)
+    public abstract static class ContinueNode extends CoreMethodNode {
+
+        public ContinueNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public ContinueNode(ContinueNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public Object debugContinue() {
+            if (getContext().getConfiguration().getDebug()) {
+                throw new BreakShellException();
+            }
+            return NilPlaceholder.INSTANCE;
+        }
+
+    }
+
+    @CoreMethod(names = "enabled?", isModuleMethod = true, needsSelf = false, maxArgs = 0)
+    public abstract static class EnabledNode extends CoreMethodNode {
+
+        public EnabledNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public EnabledNode(ContinueNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public boolean enabled() {
+            return getContext().getConfiguration().getDebug();
+        }
+
+    }
+
+    @CoreMethod(names = "where", isModuleMethod = true, needsSelf = false, appendCallNode = true, minArgs = 1, maxArgs = 1)
+    public abstract static class WhereNode extends CoreMethodNode {
+
+        public WhereNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public WhereNode(WhereNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder where(Node callNode) {
+            final RubyContext context = getContext();
+            if (context.getConfiguration().getDebug()) {
+                context.getConfiguration().getStandardOut().println(callNode.getSourceSection());
+            }
+            return NilPlaceholder.INSTANCE;
+        }
+
+    }
+
+    @CoreMethod(names = "remove", isModuleMethod = true, needsSelf = false, needsBlock = true, minArgs = 2, maxArgs = 2)
+    public abstract static class RemoveNode extends CoreMethodNode {
+
+        public RemoveNode(RubyContext context, SourceSection sourceSection) {
+            super(context, sourceSection);
+        }
+
+        public RemoveNode(RemoveNode prev) {
+            super(prev);
+        }
+
+        @Specialization
+        public NilPlaceholder debugRemove(RubyString fileName, int line) {
+            final RubyContext context = getContext();
+            if (context.getConfiguration().getDebug()) {
+                final Source source = context.getSourceManager().get(fileName.toString());
+                final SourceLineLocation lineLocation = new SourceLineLocation(source, line);
+                context.getDebugManager().removeBreakpoint(lineLocation);
+            }
+            return NilPlaceholder.INSTANCE;
+        }
+
+        @Specialization
+        public NilPlaceholder debugRemove(RubySymbol methodName, RubySymbol localName) {
+            final RubyContext context = getContext();
+            if (context.getConfiguration().getDebug()) {
+                final RubyMethod method = context.getCoreLibrary().getMainObject().getLookupNode().lookupMethod(methodName.toString());
+                context.getDebugManager().removeLocalProbe(method.getUniqueIdentifier(), localName.toString());
+            }
+            return NilPlaceholder.INSTANCE;
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/RubyProxyNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.debug;
+
+import java.math.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.nodes.instrument.*;
+import com.oracle.truffle.api.nodes.instrument.InstrumentationProbeNode.ProbeChain;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+/**
+ * An <strong>instrumentation proxy node</strong> that forwards all Ruby execution calls through to
+ * a child node and returns results back to the parent, but which also sends notifications to an
+ * attached {@linkplain ProbeChain chain} of {@linkplain InstrumentationProbeNode probes}.
+ */
+public class RubyProxyNode extends RubyNode implements InstrumentationProxyNode {
+
+    @Child private RubyNode child;
+
+    private final ProbeChain probeChain;
+
+    public RubyProxyNode(RubyContext context, RubyNode child) {
+        super(context, SourceSection.NULL);
+        this.child = adoptChild(child);
+        assert !(child instanceof RubyProxyNode);
+        this.probeChain = new ProbeChain(child.getSourceSection(), null);
+    }
+
+    @Override
+    public RubyNode getNonProxyNode() {
+        return child;
+    }
+
+    public RubyNode getChild() {
+        return child;
+    }
+
+    public ProbeChain getProbeChain() {
+        return probeChain;
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        probeChain.notifyEnter(child, frame);
+
+        Object result;
+
+        try {
+            result = child.execute(frame);
+            probeChain.notifyLeave(child, frame, result);
+        } catch (Exception e) {
+            probeChain.notifyLeaveExceptional(child, frame, e);
+            throw (e);
+        }
+
+        return result;
+    }
+
+    @Override
+    public RubyArray executeArray(VirtualFrame frame) throws UnexpectedResultException {
+        probeChain.notifyEnter(child, frame);
+
+        RubyArray result;
+
+        try {
+            result = child.executeArray(frame);
+            probeChain.notifyLeave(child, frame, result);
+        } catch (Exception e) {
+            probeChain.notifyLeaveExceptional(child, frame, e);
+            throw (e);
+        }
+
+        return result;
+    }
+
+    @Override
+    public BigInteger executeBignum(VirtualFrame frame) throws UnexpectedResultException {
+        probeChain.notifyEnter(child, frame);
+
+        BigInteger result;
+
+        try {
+            result = child.executeBignum(frame);
+            probeChain.notifyLeave(child, frame, result);
+        } catch (Exception e) {
+            probeChain.notifyLeaveExceptional(child, frame, e);
+            throw (e);
+        }
+
+        return result;
+    }
+
+    @Override
+    public boolean executeBoolean(VirtualFrame frame) throws UnexpectedResultException {
+        probeChain.notifyEnter(child, frame);
+
+        boolean result;
+
+        try {
+            result = child.executeBoolean(frame);
+            probeChain.notifyLeave(child, frame, result);
+        } catch (Exception e) {
+            probeChain.notifyLeaveExceptional(child, frame, e);
+            throw (e);
+        }
+
+        return result;
+    }
+
+    @Override
+    public Object isDefined(VirtualFrame frame) {
+        return child.isDefined(frame);
+    }
+
+    @Override
+    public int executeFixnum(VirtualFrame frame) throws UnexpectedResultException {
+        probeChain.notifyEnter(child, frame);
+
+        int result;
+
+        try {
+            result = child.executeFixnum(frame);
+            probeChain.notifyLeave(child, frame, result);
+        } catch (Exception e) {
+            probeChain.notifyLeaveExceptional(child, frame, e);
+            throw (e);
+        }
+
+        return result;
+    }
+
+    @Override
+    public double executeFloat(VirtualFrame frame) throws UnexpectedResultException {
+        probeChain.notifyEnter(child, frame);
+
+        double result;
+
+        try {
+            result = child.executeFloat(frame);
+            probeChain.notifyLeave(child, frame, result);
+        } catch (Exception e) {
+            probeChain.notifyLeaveExceptional(child, frame, e);
+            throw (e);
+        }
+
+        return result;
+    }
+
+    @Override
+    public RubyString executeString(VirtualFrame frame) throws UnexpectedResultException {
+        probeChain.notifyEnter(child, frame);
+
+        RubyString result;
+
+        try {
+            result = child.executeString(frame);
+            probeChain.notifyLeave(child, frame, result);
+        } catch (Exception e) {
+            probeChain.notifyLeaveExceptional(child, frame, e);
+            throw (e);
+        }
+
+        return result;
+    }
+
+    @Override
+    public void executeVoid(VirtualFrame frame) {
+        probeChain.notifyEnter(child, frame);
+
+        try {
+            child.executeVoid(frame);
+            probeChain.notifyLeave(child, frame);
+        } catch (Exception e) {
+            probeChain.notifyLeaveExceptional(child, frame, e);
+            throw (e);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/BignumLiteralNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.literal;
+
+import java.math.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+@NodeInfo(shortName = "bignum")
+public class BignumLiteralNode extends RubyNode {
+
+    private final BigInteger value;
+
+    public BignumLiteralNode(RubyContext context, SourceSection sourceSection, BigInteger value) {
+        super(context, sourceSection);
+        this.value = value;
+    }
+
+    @Override
+    public BigInteger executeBignum(VirtualFrame frame) {
+        return value;
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        return value;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/BooleanLiteralNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.literal;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+@NodeInfo(shortName = "boolean")
+public class BooleanLiteralNode extends RubyNode {
+
+    private final boolean value;
+
+    public BooleanLiteralNode(RubyContext context, SourceSection sourceSection, boolean value) {
+        super(context, sourceSection);
+        this.value = value;
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        return executeBoolean(frame);
+    }
+
+    @Override
+    public boolean executeBoolean(VirtualFrame frame) {
+        return value;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/FixnumLiteralNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.literal;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+@NodeInfo(shortName = "fixnum")
+public class FixnumLiteralNode extends RubyNode {
+
+    private final int value;
+
+    public FixnumLiteralNode(RubyContext context, SourceSection sourceSection, int value) {
+        super(context, sourceSection);
+        this.value = value;
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        return executeFixnum(frame);
+    }
+
+    @Override
+    public int executeFixnum(VirtualFrame frame) {
+        return value;
+    }
+
+    // TODO(CS): remove this - shouldn't be fiddling with nodes from the outside
+    public int getValue() {
+        return value;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/FloatLiteralNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.literal;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+@NodeInfo(shortName = "float")
+public class FloatLiteralNode extends RubyNode {
+
+    private final double value;
+
+    public FloatLiteralNode(RubyContext context, SourceSection sourceSection, double value) {
+        super(context, sourceSection);
+        this.value = value;
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        return executeFloat(frame);
+    }
+
+    @Override
+    public double executeFloat(VirtualFrame frame) {
+        return value;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/HashLiteralNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.literal;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+@NodeInfo(shortName = "hash")
+public class HashLiteralNode extends RubyNode {
+
+    @Children protected final RubyNode[] keys;
+    @Children protected final RubyNode[] values;
+
+    public HashLiteralNode(SourceSection sourceSection, RubyNode[] keys, RubyNode[] values, RubyContext context) {
+        super(context, sourceSection);
+        assert keys.length == values.length;
+        this.keys = adoptChildren(keys);
+        this.values = adoptChildren(values);
+    }
+
+    @ExplodeLoop
+    @Override
+    public Object execute(VirtualFrame frame) {
+        final RubyHash hash = new RubyHash(getContext().getCoreLibrary().getHashClass());
+
+        for (int n = 0; n < keys.length; n++) {
+            hash.put(keys[n].execute(frame), values[n].execute(frame));
+        }
+
+        return hash;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/NilNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.literal;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * A node that does nothing and evaluates to Nil. A no-op.
+ */
+@NodeInfo(shortName = "nil")
+public final class NilNode extends RubyNode {
+
+    public NilNode(RubyContext context, SourceSection sourceSection) {
+        super(context, sourceSection);
+    }
+
+    @Override
+    public NilPlaceholder executeNilPlaceholder(VirtualFrame frame) {
+        return NilPlaceholder.INSTANCE;
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        return executeNilPlaceholder(frame);
+    }
+
+    @Override
+    public void executeVoid(VirtualFrame frame) {
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/ObjectLiteralNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.literal;
+
+import java.math.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+@NodeInfo(shortName = "object")
+public class ObjectLiteralNode extends RubyNode {
+
+    private final Object object;
+
+    public ObjectLiteralNode(RubyContext context, SourceSection sourceSection, Object object) {
+        super(context, sourceSection);
+
+        assert RubyContext.shouldObjectBeVisible(object);
+        assert !(object instanceof Integer);
+        assert !(object instanceof Double);
+        assert !(object instanceof BigInteger);
+        assert !(object instanceof String);
+        assert !(object instanceof RubyString);
+
+        this.object = object;
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        return object;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/RangeLiteralNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.literal;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.range.*;
+
+@NodeInfo(shortName = "range")
+@NodeChildren({@NodeChild("begin"), @NodeChild("end")})
+public abstract class RangeLiteralNode extends RubyNode {
+
+    private final boolean excludeEnd;
+
+    public RangeLiteralNode(RubyContext context, SourceSection sourceSection, boolean excludeEnd) {
+        super(context, sourceSection);
+        this.excludeEnd = excludeEnd;
+    }
+
+    public RangeLiteralNode(RangeLiteralNode prev) {
+        this(prev.getContext(), prev.getSourceSection(), prev.excludeEnd);
+    }
+
+    @Specialization
+    public FixnumRange doFixnum(int begin, int end) {
+        return new FixnumRange(getContext().getCoreLibrary().getRangeClass(), begin, end, excludeEnd);
+    }
+
+    @Generic
+    public Object doGeneric(Object begin, Object end) {
+        final RubyContext context = getContext();
+
+        if ((begin instanceof Integer) && (end instanceof Integer)) {
+            return doFixnum((int) begin, (int) end);
+        } else {
+            return new ObjectRange(context.getCoreLibrary().getRangeClass(), begin, end, excludeEnd);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/StringLiteralNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.literal;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+@NodeInfo(shortName = "string")
+public class StringLiteralNode extends RubyNode {
+
+    private final String string;
+
+    public StringLiteralNode(RubyContext context, SourceSection sourceSection, String string) {
+        super(context, sourceSection);
+
+        assert string != null;
+
+        this.string = string;
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        return getContext().makeString(string);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/array/ArrayLiteralNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.literal.array;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+public abstract class ArrayLiteralNode extends RubyNode {
+
+    @Children protected final RubyNode[] values;
+
+    public ArrayLiteralNode(RubyContext context, SourceSection sourceSection, RubyNode[] values) {
+        super(context, sourceSection);
+        this.values = adoptChildren(values);
+    }
+
+    protected RubyArray makeGeneric(VirtualFrame frame, Object[] alreadyExecuted) {
+        CompilerAsserts.neverPartOfCompilation();
+
+        replace(new ObjectArrayLiteralNode(getContext(), getSourceSection(), values));
+
+        final Object[] executedValues = new Object[values.length];
+
+        for (int n = 0; n < values.length; n++) {
+            if (n < alreadyExecuted.length) {
+                executedValues[n] = alreadyExecuted[n];
+            } else {
+                executedValues[n] = values[n].execute(frame);
+            }
+        }
+
+        return RubyArray.specializedFromObjects(getContext().getCoreLibrary().getArrayClass(), executedValues);
+    }
+
+    @Override
+    public Object isDefined(VirtualFrame frame) {
+        return getContext().makeString("expression");
+    }
+
+    // TODO(CS): remove this - shouldn't be fiddling with nodes from the outside
+    public RubyNode[] getValues() {
+        return values;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/array/FixnumArrayLiteralNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.literal.array;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+@NodeInfo(shortName = "fixnum-array-literal")
+public class FixnumArrayLiteralNode extends ArrayLiteralNode {
+
+    public FixnumArrayLiteralNode(RubyContext context, SourceSection sourceSection, RubyNode[] values) {
+        super(context, sourceSection, values);
+    }
+
+    @ExplodeLoop
+    @Override
+    public RubyArray executeArray(VirtualFrame frame) {
+        final int[] executedValues = new int[values.length];
+
+        for (int n = 0; n < values.length; n++) {
+            try {
+                executedValues[n] = values[n].executeFixnum(frame);
+            } catch (UnexpectedResultException e) {
+                final Object[] executedObjects = new Object[n];
+
+                for (int i = 0; i < n; i++) {
+                    executedObjects[i] = executedValues[i];
+                }
+
+                return makeGeneric(frame, executedObjects);
+            }
+        }
+
+        return new RubyArray(getContext().getCoreLibrary().getArrayClass(), new FixnumArrayStore(executedValues));
+    }
+
+    @ExplodeLoop
+    @Override
+    public void executeVoid(VirtualFrame frame) {
+        for (int n = 0; n < values.length; n++) {
+            values[n].executeVoid(frame);
+        }
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        return executeArray(frame);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/array/ObjectArrayLiteralNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.literal.array;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+@NodeInfo(shortName = "object-array-literal")
+public class ObjectArrayLiteralNode extends ArrayLiteralNode {
+
+    public ObjectArrayLiteralNode(RubyContext context, SourceSection sourceSection, RubyNode[] values) {
+        super(context, sourceSection, values);
+    }
+
+    @ExplodeLoop
+    @Override
+    public RubyArray executeArray(VirtualFrame frame) {
+        final Object[] executedValues = new Object[values.length];
+
+        for (int n = 0; n < values.length; n++) {
+            executedValues[n] = values[n].execute(frame);
+        }
+
+        return new RubyArray(getContext().getCoreLibrary().getArrayClass(), new ObjectArrayStore(executedValues));
+    }
+
+    @ExplodeLoop
+    @Override
+    public void executeVoid(VirtualFrame frame) {
+        for (int n = 0; n < values.length; n++) {
+            values[n].executeVoid(frame);
+        }
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        return executeArray(frame);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/literal/array/UninitialisedArrayLiteralNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.literal.array;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+@NodeInfo(shortName = "uninit-array-literal")
+public class UninitialisedArrayLiteralNode extends ArrayLiteralNode {
+
+    public UninitialisedArrayLiteralNode(RubyContext context, SourceSection sourceSection, RubyNode[] values) {
+        super(context, sourceSection, values);
+    }
+
+    @ExplodeLoop
+    @Override
+    public Object execute(VirtualFrame frame) {
+        CompilerDirectives.transferToInterpreter();
+
+        final Object[] executedValues = new Object[values.length];
+
+        for (int n = 0; n < values.length; n++) {
+            executedValues[n] = values[n].execute(frame);
+        }
+
+        final RubyArray array = RubyArray.specializedFromObjects(getContext().getCoreLibrary().getArrayClass(), executedValues);
+        final ArrayStore store = array.getArrayStore();
+
+        if (store instanceof FixnumArrayStore) {
+            replace(new FixnumArrayLiteralNode(getContext(), getSourceSection(), values));
+        } else {
+            replace(new ObjectArrayLiteralNode(getContext(), getSourceSection(), values));
+        }
+
+        return array;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/AddMethodNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.methods;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+
+@NodeInfo(shortName = "add-method")
+public class AddMethodNode extends RubyNode {
+
+    @Child protected RubyNode receiver;
+    @Child protected MethodDefinitionNode method;
+
+    public AddMethodNode(RubyContext context, SourceSection section, RubyNode receiver, MethodDefinitionNode method) {
+        super(context, section);
+        this.receiver = adoptChild(receiver);
+        this.method = adoptChild(method);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        final Object receiverObject = receiver.execute(frame);
+
+        final RubyMethod methodObject = (RubyMethod) method.execute(frame);
+
+        final FrameSlot moduleFunctionFlagSlot = frame.getFrameDescriptor().findFrameSlot(RubyModule.MODULE_FUNCTION_FLAG_FRAME_SLOT_ID);
+
+        boolean moduleFunctionFlag;
+
+        if (moduleFunctionFlagSlot == null) {
+            moduleFunctionFlag = false;
+        } else {
+            Object moduleFunctionObject;
+
+            try {
+                moduleFunctionObject = frame.getObject(moduleFunctionFlagSlot);
+            } catch (FrameSlotTypeException e) {
+                throw new RuntimeException(e);
+            }
+
+            if (moduleFunctionObject instanceof Boolean) {
+                moduleFunctionFlag = (boolean) moduleFunctionObject;
+            } else {
+                moduleFunctionFlag = false;
+            }
+        }
+
+        final RubyModule module = (RubyModule) receiverObject;
+
+        final RubyMethod methodWithDeclaringModule = methodObject.withDeclaringModule(module);
+
+        module.addMethod(methodWithDeclaringModule);
+
+        if (moduleFunctionFlag) {
+            module.getSingletonClass().addMethod(methodWithDeclaringModule);
+        }
+
+        return NilPlaceholder.INSTANCE;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/AliasNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.methods;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+@NodeInfo(shortName = "alias")
+public class AliasNode extends RubyNode {
+
+    @Child protected RubyNode module;
+    final String newName;
+    final String oldName;
+
+    public AliasNode(RubyContext context, SourceSection sourceSection, RubyNode module, String newName, String oldName) {
+        super(context, sourceSection);
+        this.module = adoptChild(module);
+        this.newName = newName;
+        this.oldName = oldName;
+    }
+
+    @Override
+    public void executeVoid(VirtualFrame frame) {
+        final RubyModule moduleObject = (RubyModule) module.execute(frame);
+        moduleObject.alias(newName, oldName);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        executeVoid(frame);
+        return NilPlaceholder.INSTANCE;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/BlockDefinitionNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.methods;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+
+/**
+ * Define a block. That is, store the definition of a block and when executed produce the executable
+ * object that results.
+ */
+@NodeInfo(shortName = "block-def")
+public class BlockDefinitionNode extends MethodDefinitionNode {
+
+    public BlockDefinitionNode(RubyContext context, SourceSection sourceSection, String name, UniqueMethodIdentifier uniqueIdentifier, FrameDescriptor frameDescriptor,
+                    boolean requiresDeclarationFrame, RubyRootNode pristineRootNode, CallTarget callTarget) {
+        super(context, sourceSection, name, uniqueIdentifier, frameDescriptor, requiresDeclarationFrame, pristineRootNode, callTarget);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        final RubyContext context = getContext();
+
+        MaterializedFrame declarationFrame;
+
+        if (requiresDeclarationFrame) {
+            declarationFrame = frame.materialize();
+        } else {
+            declarationFrame = null;
+        }
+
+        final RubyArguments arguments = frame.getArguments(RubyArguments.class);
+
+        final InlinableMethodImplementation methodImplementation = new InlinableMethodImplementation(callTarget, declarationFrame, frameDescriptor, pristineRootNode, true, false);
+        final RubyMethod method = new RubyMethod(getSourceSection(), null, uniqueIdentifier, null, name, Visibility.PUBLIC, false, methodImplementation);
+
+        return new RubyProc(context.getCoreLibrary().getProcClass(), RubyProc.Type.PROC, arguments.getSelf(), arguments.getBlock(), method);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/CatchNextNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.methods;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.utilities.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+
+/**
+ * Catch a {@code next} jump at the root of a method.
+ */
+public class CatchNextNode extends RubyNode {
+
+    @Child protected RubyNode body;
+
+    private final BranchProfile nextProfile = new BranchProfile();
+
+    public CatchNextNode(RubyContext context, SourceSection sourceSection, RubyNode body) {
+        super(context, sourceSection);
+        this.body = adoptChild(body);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        try {
+            return body.execute(frame);
+        } catch (NextException e) {
+            nextProfile.enter();
+            return NilPlaceholder.INSTANCE;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/CatchReturnAsErrorNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.methods;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+
+/**
+ * Catch a {@code return} jump at the root of a method, and report it as an error.
+ */
+public class CatchReturnAsErrorNode extends RubyNode {
+
+    @Child protected RubyNode body;
+
+    public CatchReturnAsErrorNode(RubyContext context, SourceSection sourceSection, RubyNode body) {
+        super(context, sourceSection);
+        this.body = adoptChild(body);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        try {
+            return body.execute(frame);
+        } catch (ReturnException e) {
+            CompilerDirectives.transferToInterpreter();
+            throw new RaiseException(getContext().getCoreLibrary().unexpectedReturn());
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/CatchReturnNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.methods;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.utilities.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+
+/**
+ * Catch a {@code return} jump at the root of a method.
+ */
+public class CatchReturnNode extends RubyNode {
+
+    @Child protected RubyNode body;
+    private final long returnID;
+
+    private final BranchProfile returnProfile = new BranchProfile();
+    private final BranchProfile returnToOtherMethodProfile = new BranchProfile();
+
+    public CatchReturnNode(RubyContext context, SourceSection sourceSection, RubyNode body, long returnID) {
+        super(context, sourceSection);
+        this.body = adoptChild(body);
+        this.returnID = returnID;
+    }
+
+    public CatchReturnNode(CatchReturnNode prev) {
+        super(prev);
+        returnID = prev.returnID;
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        try {
+            return body.execute(frame);
+        } catch (ReturnException e) {
+            returnProfile.enter();
+
+            if (e.getReturnID() == returnID) {
+                return e.getValue();
+            } else {
+                returnToOtherMethodProfile.enter();
+                throw e;
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/MethodDefinitionNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.methods;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+
+/**
+ * Define a method. That is, store the definition of a method and when executed produce the
+ * executable object that results.
+ */
+@NodeInfo(shortName = "method-def")
+public class MethodDefinitionNode extends RubyNode {
+
+    protected final String name;
+    protected final UniqueMethodIdentifier uniqueIdentifier;
+
+    protected final FrameDescriptor frameDescriptor;
+    protected final RubyRootNode pristineRootNode;
+
+    protected final CallTarget callTarget;
+
+    protected final boolean requiresDeclarationFrame;
+
+    public MethodDefinitionNode(RubyContext context, SourceSection sourceSection, String name, UniqueMethodIdentifier uniqueIdentifier, FrameDescriptor frameDescriptor,
+                    boolean requiresDeclarationFrame, RubyRootNode pristineRootNode, CallTarget callTarget) {
+        super(context, sourceSection);
+        this.name = name;
+        this.uniqueIdentifier = uniqueIdentifier;
+        this.frameDescriptor = frameDescriptor;
+        this.requiresDeclarationFrame = requiresDeclarationFrame;
+        this.pristineRootNode = pristineRootNode;
+        this.callTarget = callTarget;
+    }
+
+    public RubyMethod executeMethod(VirtualFrame frame) {
+        CompilerDirectives.transferToInterpreter();
+
+        MaterializedFrame declarationFrame;
+
+        if (requiresDeclarationFrame) {
+            declarationFrame = frame.materialize();
+        } else {
+            declarationFrame = null;
+        }
+
+        final FrameSlot visibilitySlot = frame.getFrameDescriptor().findFrameSlot(RubyModule.VISIBILITY_FRAME_SLOT_ID);
+
+        Visibility visibility;
+
+        if (visibilitySlot == null) {
+            visibility = Visibility.PUBLIC;
+        } else {
+            Object visibilityObject;
+
+            try {
+                visibilityObject = frame.getObject(visibilitySlot);
+            } catch (FrameSlotTypeException e) {
+                throw new RuntimeException(e);
+            }
+
+            if (visibilityObject instanceof Visibility) {
+                visibility = (Visibility) visibilityObject;
+            } else {
+                visibility = Visibility.PUBLIC;
+            }
+        }
+
+        final InlinableMethodImplementation methodImplementation = new InlinableMethodImplementation(callTarget, declarationFrame, frameDescriptor, pristineRootNode, false, false);
+        return new RubyMethod(getSourceSection(), null, uniqueIdentifier, null, name, visibility, false, methodImplementation);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        return executeMethod(frame);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/ShellResultNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.methods;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * Produce a {@link ShellResult} object from a return value and the resulting frame.
+ */
+public class ShellResultNode extends RubyNode {
+
+    @Child protected RubyNode body;
+
+    public ShellResultNode(RubyContext context, SourceSection sourceSection, RubyNode body) {
+        super(context, sourceSection);
+        this.body = adoptChild(body);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        return new ShellResult(body.execute(frame), frame.materialize());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/BlockDestructureSwitchNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.methods.arguments;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+/**
+ * Switches between loading arguments as normal and doing a destructure. See
+ * testBlockArgumentsDestructure and MethodTranslator.
+ */
+@NodeInfo(shortName = "block-destructure-switch")
+public class BlockDestructureSwitchNode extends RubyNode {
+
+    @Child protected RubyNode loadIndividualArguments;
+    @Child protected RubyNode destructureArguments;
+    @Child protected RubyNode body;
+
+    public BlockDestructureSwitchNode(RubyContext context, SourceSection sourceSection, RubyNode loadIndividualArguments, RubyNode destructureArguments, RubyNode body) {
+        super(context, sourceSection);
+        this.loadIndividualArguments = adoptChild(loadIndividualArguments);
+        this.destructureArguments = adoptChild(destructureArguments);
+        this.body = adoptChild(body);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        final RubyArguments arguments = frame.getArguments(RubyArguments.class);
+
+        if (arguments.getArguments().length == 1 && arguments.getArguments()[0] instanceof RubyArray) {
+            destructureArguments.executeVoid(frame);
+        } else {
+            loadIndividualArguments.executeVoid(frame);
+        }
+
+        return body.execute(frame);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/CheckArityNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.methods.arguments;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+
+/**
+ * Check arguments meet the arity of the method.
+ */
+@NodeInfo(shortName = "check-arity")
+public class CheckArityNode extends RubyNode {
+
+    private final Arity arity;
+
+    public CheckArityNode(RubyContext context, SourceSection sourceSection, Arity arity) {
+        super(context, sourceSection);
+        this.arity = arity;
+    }
+
+    @Override
+    public void executeVoid(VirtualFrame frame) {
+        final RubyArguments arguments = frame.getArguments(RubyArguments.class);
+        arity.checkArguments(getContext(), arguments.getArguments());
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        executeVoid(frame);
+        return NilPlaceholder.INSTANCE;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadAllArgumentsNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.methods.arguments;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+public class ReadAllArgumentsNode extends RubyNode {
+
+    public ReadAllArgumentsNode(RubyContext context, SourceSection sourceSection) {
+        super(context, sourceSection);
+    }
+
+    @Override
+    public Object[] executeObjectArray(VirtualFrame frame) {
+        return frame.getArguments(RubyArguments.class).getArguments();
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        return executeObjectArray(frame);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadBlockArgumentNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.methods.arguments;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+/**
+ * Read the block as a {@code Proc}.
+ */
+@NodeInfo(shortName = "read-block-argument")
+public class ReadBlockArgumentNode extends RubyNode {
+
+    private final boolean undefinedIfNotPresent;
+
+    public ReadBlockArgumentNode(RubyContext context, SourceSection sourceSection, boolean undefinedIfNotPresent) {
+        super(context, sourceSection);
+        this.undefinedIfNotPresent = undefinedIfNotPresent;
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        final RubyArguments arguments = frame.getArguments(RubyArguments.class);
+        final RubyProc block = arguments.getBlock();
+
+        if (block == null) {
+            if (undefinedIfNotPresent) {
+                return UndefinedPlaceholder.INSTANCE;
+            } else {
+                return NilPlaceholder.INSTANCE;
+            }
+        } else {
+            return block;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadDestructureArgumentNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.methods.arguments;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+/**
+ * Assuming argument 0 is an array, read an element from that array.
+ */
+@NodeInfo(shortName = "read-destructure-argument")
+public class ReadDestructureArgumentNode extends RubyNode {
+
+    private final int index;
+
+    public ReadDestructureArgumentNode(RubyContext context, SourceSection sourceSection, int index) {
+        super(context, sourceSection);
+        this.index = index;
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        final RubyArray array = (RubyArray) frame.getArguments(RubyArguments.class).getArguments()[0];
+        return array.get(index);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadOptionalArgumentNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.methods.arguments;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.utilities.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * Read an optional argument.
+ */
+@NodeInfo(shortName = "read-optional-argument")
+public class ReadOptionalArgumentNode extends RubyNode {
+
+    private final int index;
+    private final int minimum;
+    @Child protected RubyNode defaultValue;
+
+    private final BranchProfile defaultValueProfile = new BranchProfile();
+
+    public ReadOptionalArgumentNode(RubyContext context, SourceSection sourceSection, int index, int minimum, RubyNode defaultValue) {
+        super(context, sourceSection);
+        this.index = index;
+        this.minimum = minimum;
+        this.defaultValue = adoptChild(defaultValue);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        final Object[] arguments = frame.getArguments(RubyArguments.class).getArguments();
+
+        if (arguments.length < minimum) {
+            defaultValueProfile.enter();
+            return defaultValue.execute(frame);
+        } else {
+            assert index < arguments.length;
+            return arguments[index];
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadPostArgumentNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.methods.arguments;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * Read a post-optional argument.
+ */
+@NodeInfo(shortName = "read-post-optional-argument")
+public class ReadPostArgumentNode extends RubyNode {
+
+    private final int indexFromEnd;
+
+    public ReadPostArgumentNode(RubyContext context, SourceSection sourceSection, int indexFromEnd) {
+        super(context, sourceSection);
+        this.indexFromEnd = indexFromEnd;
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        final Object[] arguments = frame.getArguments(RubyArguments.class).getArguments();
+        final int effectiveIndex = arguments.length - 1 - indexFromEnd;
+        assert effectiveIndex < arguments.length;
+        return arguments[effectiveIndex];
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadPreArgumentNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.methods.arguments;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.utilities.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * Read pre-optional argument.
+ */
+@NodeInfo(shortName = "read-pre-optional-argument")
+public class ReadPreArgumentNode extends RubyNode {
+
+    private final int index;
+    private final boolean undefinedIfNotPresent;
+
+    private final BranchProfile notPresentProfile = new BranchProfile();
+
+    public ReadPreArgumentNode(RubyContext context, SourceSection sourceSection, int index, boolean undefinedIfNotPresent) {
+        super(context, sourceSection);
+        this.index = index;
+        this.undefinedIfNotPresent = undefinedIfNotPresent;
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        final Object[] arguments = frame.getArguments(RubyArguments.class).getArguments();
+
+        if (undefinedIfNotPresent) {
+            if (index >= arguments.length) {
+                notPresentProfile.enter();
+                return UndefinedPlaceholder.INSTANCE;
+            }
+        } else {
+            assert index < arguments.length;
+        }
+
+        return arguments[index];
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/arguments/ReadRestArgumentNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.methods.arguments;
+
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+/**
+ * Read the rest of arguments after a certain point into an array.
+ */
+@NodeInfo(shortName = "read-rest-of-arguments")
+public class ReadRestArgumentNode extends RubyNode {
+
+    private final int index;
+
+    public ReadRestArgumentNode(RubyContext context, SourceSection sourceSection, int index) {
+        super(context, sourceSection);
+        this.index = index;
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        final RubyArguments rubyArguments = frame.getArguments(RubyArguments.class);
+
+        final Object[] arguments = rubyArguments.getArguments();
+
+        final RubyClass arrayClass = getContext().getCoreLibrary().getArrayClass();
+
+        if (arguments.length <= index) {
+            return new RubyArray(arrayClass);
+        } else if (index == 0) {
+            return new RubyArray(arrayClass, new ObjectArrayStore(arguments));
+        } else {
+            return new RubyArray(arrayClass, new ObjectArrayStore(Arrays.copyOfRange(arguments, index, arguments.length)));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/FlipFlopStateNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.methods.locals;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+public abstract class FlipFlopStateNode extends Node {
+
+    public FlipFlopStateNode(SourceSection sourceSection) {
+        super(sourceSection);
+    }
+
+    public abstract boolean getState(VirtualFrame frame);
+
+    public abstract void setState(VirtualFrame frame, boolean state);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/FrameSlotNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.methods.locals;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+public abstract class FrameSlotNode extends RubyNode {
+
+    protected final FrameSlot frameSlot;
+
+    protected FrameSlotNode(RubyContext context, SourceSection sourceSection, FrameSlot frameSlot) {
+        super(context, sourceSection);
+        this.frameSlot = frameSlot;
+    }
+
+    public final FrameSlot getFrameSlot() {
+        return frameSlot;
+    }
+
+    @Override
+    public FrameSlotNode copy() {
+        return (FrameSlotNode) super.copy();
+    }
+
+    protected final void setBoolean(Frame frame, boolean value) {
+        frame.setBoolean(frameSlot, value);
+    }
+
+    protected final void setFixnum(Frame frame, int value) {
+        frame.setInt(frameSlot, value);
+    }
+
+    protected final void setFloat(Frame frame, double value) {
+        frame.setDouble(frameSlot, value);
+    }
+
+    protected final void setObject(Frame frame, Object value) {
+        frame.setObject(frameSlot, value);
+    }
+
+    protected final boolean getBoolean(Frame frame) throws FrameSlotTypeException {
+        return frame.getBoolean(frameSlot);
+    }
+
+    protected final int getFixnum(Frame frame) throws FrameSlotTypeException {
+        return frame.getInt(frameSlot);
+    }
+
+    protected final double getFloat(Frame frame) throws FrameSlotTypeException {
+        return frame.getDouble(frameSlot);
+    }
+
+    protected final Object getObject(Frame frame) {
+        try {
+            return frame.getObject(frameSlot);
+        } catch (FrameSlotTypeException e) {
+            throw new IllegalStateException();
+        }
+    }
+
+    protected final boolean isBooleanKind() {
+        return isKind(FrameSlotKind.Boolean);
+    }
+
+    protected final boolean isFixnumKind() {
+        return isKind(FrameSlotKind.Int);
+    }
+
+    protected final boolean isFloatKind() {
+        return isKind(FrameSlotKind.Double);
+    }
+
+    protected final boolean isObjectKind() {
+        if (frameSlot.getKind() != FrameSlotKind.Object) {
+            CompilerDirectives.transferToInterpreter();
+            frameSlot.setKind(FrameSlotKind.Object);
+        }
+        return true;
+    }
+
+    private boolean isKind(FrameSlotKind kind) {
+        return frameSlot.getKind() == kind || initialSetKind(kind);
+    }
+
+    private boolean initialSetKind(FrameSlotKind kind) {
+        if (frameSlot.getKind() == FrameSlotKind.Illegal) {
+            CompilerDirectives.transferToInterpreter();
+            frameSlot.setKind(kind);
+            return true;
+        }
+        return false;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/InitFlipFlopSlotNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.methods.locals;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+public class InitFlipFlopSlotNode extends RubyNode {
+
+    private final FrameSlot frameSlot;
+
+    public InitFlipFlopSlotNode(RubyContext context, SourceSection sourceSection, FrameSlot frameSlot) {
+        super(context, sourceSection);
+        this.frameSlot = frameSlot;
+    }
+
+    @Override
+    public void executeVoid(VirtualFrame frame) {
+        frame.setBoolean(frameSlot, false);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        executeVoid(frame);
+        return null;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/LevelFlipFlopStateNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.methods.locals;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+public class LevelFlipFlopStateNode extends FlipFlopStateNode {
+
+    private final int level;
+    private final FrameSlot frameSlot;
+
+    public LevelFlipFlopStateNode(SourceSection sourceSection, int level, FrameSlot frameSlot) {
+        super(sourceSection);
+        this.level = level;
+        this.frameSlot = frameSlot;
+    }
+
+    @Override
+    public boolean getState(VirtualFrame frame) {
+        final MaterializedFrame levelFrame = RubyArguments.getDeclarationFrame(frame, level);
+
+        try {
+            return levelFrame.getBoolean(frameSlot);
+        } catch (FrameSlotTypeException e) {
+            throw new IllegalStateException();
+        }
+    }
+
+    @Override
+    public void setState(VirtualFrame frame, boolean state) {
+        final MaterializedFrame levelFrame = RubyArguments.getDeclarationFrame(frame, level);
+        levelFrame.setBoolean(frameSlot, state);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/LocalFlipFlopStateNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.methods.locals;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+
+public class LocalFlipFlopStateNode extends FlipFlopStateNode {
+
+    private final FrameSlot frameSlot;
+
+    public LocalFlipFlopStateNode(SourceSection sourceSection, FrameSlot frameSlot) {
+        super(sourceSection);
+        this.frameSlot = frameSlot;
+    }
+
+    @Override
+    public boolean getState(VirtualFrame frame) {
+        try {
+            return frame.getBoolean(frameSlot);
+        } catch (FrameSlotTypeException e) {
+            throw new IllegalStateException();
+        }
+    }
+
+    @Override
+    public void setState(VirtualFrame frame, boolean state) {
+        frame.setBoolean(frameSlot, state);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/ReadLevelVariableNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.methods.locals;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+public abstract class ReadLevelVariableNode extends FrameSlotNode implements ReadNode {
+
+    private final int varLevel;
+
+    public ReadLevelVariableNode(RubyContext context, SourceSection sourceSection, FrameSlot slot, int level) {
+        super(context, sourceSection, slot);
+        this.varLevel = level;
+    }
+
+    public ReadLevelVariableNode(ReadLevelVariableNode prev) {
+        this(prev.getContext(), prev.getSourceSection(), prev.frameSlot, prev.varLevel);
+    }
+
+    @Specialization(rewriteOn = {FrameSlotTypeException.class})
+    public boolean doBoolean(VirtualFrame frame) throws FrameSlotTypeException {
+        MaterializedFrame levelFrame = RubyArguments.getDeclarationFrame(frame, varLevel);
+        return getBoolean(levelFrame);
+    }
+
+    @Specialization(rewriteOn = {FrameSlotTypeException.class})
+    public int doFixnum(VirtualFrame frame) throws FrameSlotTypeException {
+        MaterializedFrame levelFrame = RubyArguments.getDeclarationFrame(frame, varLevel);
+        return getFixnum(levelFrame);
+    }
+
+    @Specialization(rewriteOn = {FrameSlotTypeException.class})
+    public double doFloat(VirtualFrame frame) throws FrameSlotTypeException {
+        MaterializedFrame levelFrame = RubyArguments.getDeclarationFrame(frame, varLevel);
+        return getFloat(levelFrame);
+    }
+
+    @Specialization
+    public Object doObject(VirtualFrame frame) {
+        MaterializedFrame levelFrame = RubyArguments.getDeclarationFrame(frame, varLevel);
+        return getObject(levelFrame);
+    }
+
+    public int getVarLevel() {
+        return varLevel;
+    }
+
+    @Override
+    public RubyNode makeWriteNode(RubyNode rhs) {
+        return WriteLevelVariableNodeFactory.create(getContext(), getSourceSection(), frameSlot, varLevel, rhs);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/ReadLocalVariableNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.methods.locals;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+public abstract class ReadLocalVariableNode extends FrameSlotNode implements ReadNode {
+
+    public ReadLocalVariableNode(RubyContext context, SourceSection sourceSection, FrameSlot slot) {
+        super(context, sourceSection, slot);
+    }
+
+    public ReadLocalVariableNode(ReadLocalVariableNode prev) {
+        this(prev.getContext(), prev.getSourceSection(), prev.frameSlot);
+    }
+
+    @Specialization(rewriteOn = {FrameSlotTypeException.class})
+    public boolean doBoolean(VirtualFrame frame) throws FrameSlotTypeException {
+        return getBoolean(frame);
+    }
+
+    @Specialization(rewriteOn = {FrameSlotTypeException.class})
+    public int doFixnum(VirtualFrame frame) throws FrameSlotTypeException {
+        return getFixnum(frame);
+    }
+
+    @Specialization(rewriteOn = {FrameSlotTypeException.class})
+    public double doFloat(VirtualFrame frame) throws FrameSlotTypeException {
+        return getFloat(frame);
+    }
+
+    @Specialization
+    public Object doObject(VirtualFrame frame) {
+        return getObject(frame);
+    }
+
+    @Override
+    public RubyNode makeWriteNode(RubyNode rhs) {
+        return WriteLocalVariableNodeFactory.create(getContext(), getSourceSection(), frameSlot, rhs);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/WriteLevelVariableNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.methods.locals;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+@NodeChild(value = "rhs", type = RubyNode.class)
+public abstract class WriteLevelVariableNode extends FrameSlotNode implements WriteNode {
+
+    private final int varLevel;
+
+    public WriteLevelVariableNode(RubyContext context, SourceSection sourceSection, FrameSlot frameSlot, int level) {
+        super(context, sourceSection, frameSlot);
+        this.varLevel = level;
+    }
+
+    protected WriteLevelVariableNode(WriteLevelVariableNode prev) {
+        this(prev.getContext(), prev.getSourceSection(), prev.frameSlot, prev.varLevel);
+    }
+
+    @Specialization(guards = "isBooleanKind")
+    public boolean doBoolean(VirtualFrame frame, boolean value) {
+        MaterializedFrame levelFrame = RubyArguments.getDeclarationFrame(frame, varLevel);
+        setBoolean(levelFrame, value);
+        return value;
+    }
+
+    @Specialization(guards = "isFixnumKind")
+    public int doFixnum(VirtualFrame frame, int value) {
+        MaterializedFrame levelFrame = RubyArguments.getDeclarationFrame(frame, varLevel);
+        setFixnum(levelFrame, value);
+        return value;
+    }
+
+    @Specialization(guards = "isFloatKind")
+    public double doFloat(VirtualFrame frame, double value) {
+        MaterializedFrame levelFrame = RubyArguments.getDeclarationFrame(frame, varLevel);
+        setFloat(levelFrame, value);
+        return value;
+    }
+
+    @Specialization(guards = "isObjectKind")
+    public Object doObject(VirtualFrame frame, Object value) {
+        MaterializedFrame levelFrame = RubyArguments.getDeclarationFrame(frame, varLevel);
+        setObject(levelFrame, value);
+        return value;
+    }
+
+    @Override
+    public RubyNode makeReadNode() {
+        return ReadLevelVariableNodeFactory.create(getContext(), getSourceSection(), frameSlot, varLevel);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/methods/locals/WriteLocalVariableNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.methods.locals;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+@NodeChild(value = "rhs", type = RubyNode.class)
+public abstract class WriteLocalVariableNode extends FrameSlotNode implements WriteNode {
+
+    public WriteLocalVariableNode(RubyContext context, SourceSection sourceSection, FrameSlot frameSlot) {
+        super(context, sourceSection, frameSlot);
+    }
+
+    protected WriteLocalVariableNode(WriteLocalVariableNode prev) {
+        this(prev.getContext(), prev.getSourceSection(), prev.frameSlot);
+    }
+
+    @Specialization(guards = "isBooleanKind")
+    public boolean doFixnum(VirtualFrame frame, boolean value) {
+        setBoolean(frame, value);
+        return value;
+    }
+
+    @Specialization(guards = "isFixnumKind")
+    public int doFixnum(VirtualFrame frame, int value) {
+        setFixnum(frame, value);
+        return value;
+    }
+
+    @Specialization(guards = "isFloatKind")
+    public double doFloat(VirtualFrame frame, double value) {
+        setFloat(frame, value);
+        return value;
+    }
+
+    @Specialization(guards = "isObjectKind")
+    public Object doObject(VirtualFrame frame, Object value) {
+        setObject(frame, value);
+        return value;
+    }
+
+    @Override
+    public RubyNode makeReadNode() {
+        return ReadLocalVariableNodeFactory.create(getContext(), getSourceSection(), frameSlot);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/ClassNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.objects;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Reads the class of an object.
+ */
+@NodeInfo(shortName = "class")
+public class ClassNode extends RubyNode {
+
+    @Child protected RubyNode child;
+
+    public ClassNode(RubyContext context, SourceSection sourceSection, RubyNode child) {
+        super(context, sourceSection);
+        this.child = adoptChild(child);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        return ((RubyBasicObject) child.execute(frame)).getRubyClass();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/DefineOrGetClassNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.objects;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+/**
+ * Define a new class, or get the existing one of the same name.
+ */
+public class DefineOrGetClassNode extends RubyNode {
+
+    private final String name;
+    @Child protected RubyNode moduleDefinedIn;
+    @Child protected RubyNode superClass;
+
+    public DefineOrGetClassNode(RubyContext context, SourceSection sourceSection, String name, RubyNode moduleDefinedIn, RubyNode superClass) {
+        super(context, sourceSection);
+        this.name = name;
+        this.moduleDefinedIn = adoptChild(moduleDefinedIn);
+        this.superClass = adoptChild(superClass);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        CompilerAsserts.neverPartOfCompilation();
+
+        final RubyContext context = getContext();
+
+        final RubyModule moduleDefinedInObject = (RubyModule) moduleDefinedIn.execute(frame);
+
+        // Look for a current definition of the class, or create a new one
+
+        final Object constantValue = moduleDefinedInObject.lookupConstant(name);
+
+        RubyClass definingClass;
+
+        if (constantValue == null) {
+            final Object self = frame.getArguments(RubyArguments.class).getSelf();
+
+            RubyModule parentModule;
+
+            if (self instanceof RubyModule) {
+                parentModule = (RubyModule) self;
+            } else {
+                // Because it's top level, and so self is the magic main object
+                parentModule = null;
+            }
+
+            final RubyClass superClassObject = (RubyClass) superClass.execute(frame);
+
+            if (superClassObject instanceof RubyException.RubyExceptionClass) {
+                definingClass = new RubyException.RubyExceptionClass(superClassObject, name);
+            } else {
+                definingClass = new RubyClass(parentModule, superClassObject, name);
+            }
+
+            moduleDefinedInObject.setConstant(name, definingClass);
+            moduleDefinedInObject.getSingletonClass().setConstant(name, definingClass);
+
+            definingClass.getRubyClass().include(moduleDefinedInObject);
+        } else {
+            if (constantValue instanceof RubyClass) {
+                definingClass = (RubyClass) constantValue;
+            } else {
+                throw new RaiseException(context.getCoreLibrary().typeErrorIsNotA(constantValue.toString(), "class"));
+            }
+        }
+
+        return definingClass;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/DefineOrGetModuleNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.objects;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+/**
+ * Define a new module, or get the existing one of the same name.
+ */
+public class DefineOrGetModuleNode extends RubyNode {
+
+    private final String name;
+    @Child protected RubyNode moduleDefinedIn;
+
+    public DefineOrGetModuleNode(RubyContext context, SourceSection sourceSection, String name, RubyNode moduleDefinedIn) {
+        super(context, sourceSection);
+        this.name = name;
+        this.moduleDefinedIn = adoptChild(moduleDefinedIn);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        CompilerAsserts.neverPartOfCompilation();
+
+        final RubyContext context = getContext();
+
+        final RubyModule moduleDefinedInObject = (RubyModule) moduleDefinedIn.execute(frame);
+
+        // Look for a current definition of the module, or create a new one
+
+        final Object constantValue = moduleDefinedInObject.lookupConstant(name);
+
+        RubyModule definingModule;
+
+        if (constantValue == null) {
+            final Object self = frame.getArguments(RubyArguments.class).getSelf();
+
+            RubyModule parentModule;
+
+            if (self instanceof RubyModule) {
+                parentModule = (RubyModule) self;
+            } else {
+                // Because it's top level, and so self is the magic main object
+                parentModule = null;
+            }
+
+            definingModule = new RubyModule(context.getCoreLibrary().getModuleClass(), parentModule, name);
+            moduleDefinedInObject.setConstant(name, definingModule);
+            moduleDefinedInObject.getSingletonClass().setConstant(name, definingModule);
+        } else {
+            if (constantValue instanceof RubyModule) {
+                definingModule = (RubyModule) constantValue;
+            } else {
+                throw new RaiseException(context.getCoreLibrary().typeErrorIsNotA(constantValue.toString(), "module"));
+            }
+        }
+
+        return definingModule;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/OpenModuleNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.objects;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.nodes.methods.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+/**
+ * Open a module and execute a method in it - probably to define new methods.
+ */
+public class OpenModuleNode extends RubyNode {
+
+    @Child protected RubyNode definingModule;
+    @Child protected MethodDefinitionNode definitionMethod;
+
+    public OpenModuleNode(RubyContext context, SourceSection sourceSection, RubyNode definingModule, MethodDefinitionNode definitionMethod) {
+        super(context, sourceSection);
+        this.definingModule = adoptChild(definingModule);
+        this.definitionMethod = adoptChild(definitionMethod);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        CompilerAsserts.neverPartOfCompilation();
+
+        // Call the definition method with the module as self - there's no return value
+
+        final RubyModule module = (RubyModule) definingModule.execute(frame);
+        definitionMethod.executeMethod(frame).call(frame.pack(), module, null);
+
+        return NilPlaceholder.INSTANCE;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/ReadClassVariableNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.objects;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+@NodeInfo(shortName = "read-class-variable")
+public class ReadClassVariableNode extends RubyNode {
+
+    protected final String name;
+    @Child protected RubyNode module;
+
+    public ReadClassVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode module) {
+        super(context, sourceSection);
+        this.name = name;
+        this.module = adoptChild(module);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        final RubyObject object = (RubyObject) module.execute(frame);
+
+        RubyModule moduleObject;
+
+        // TODO(CS): this cannot be right
+
+        if (object instanceof RubyModule) {
+            moduleObject = (RubyModule) object;
+        } else {
+            moduleObject = object.getRubyClass();
+        }
+
+        final Object value = moduleObject.lookupClassVariable(name);
+
+        if (value == null) {
+            // TODO(CS): is this right?
+            return NilPlaceholder.INSTANCE;
+        }
+
+        return value;
+    }
+
+    @Override
+    public Object isDefined(VirtualFrame frame) {
+        final RubyContext context = getContext();
+
+        final RubyObject object = (RubyObject) module.execute(frame);
+
+        RubyModule moduleObject;
+
+        if (object instanceof RubyModule) {
+            moduleObject = (RubyModule) object;
+        } else {
+            moduleObject = object.getRubyClass();
+        }
+
+        final Object value = moduleObject.lookupClassVariable(name);
+
+        if (value == null) {
+            return NilPlaceholder.INSTANCE;
+        } else {
+            return context.makeString("class variable");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/SelfNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.objects;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+@NodeInfo(shortName = "self")
+public class SelfNode extends RubyNode {
+
+    public SelfNode(RubyContext context, SourceSection sourceSection) {
+        super(context, sourceSection);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        final Object self = frame.getArguments(RubyArguments.class).getSelf();
+        assert RubyContext.shouldObjectBeVisible(self);
+        return self;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/SingletonClassNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.objects;
+
+import java.math.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Reads the singleton (meta, eigen) class of an object.
+ */
+@NodeInfo(shortName = "singleton")
+public class SingletonClassNode extends RubyNode {
+
+    @Child protected RubyNode child;
+
+    public SingletonClassNode(RubyContext context, SourceSection sourceSection, RubyNode child) {
+        super(context, sourceSection);
+        this.child = adoptChild(child);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        final Object childResult = child.execute(frame);
+
+        final RubyContext context = getContext();
+
+        if (childResult instanceof NilPlaceholder) {
+            return context.getCoreLibrary().getNilClass();
+        } else if (childResult instanceof BigInteger) {
+            // TODO(CS): this is problematic - do Bignums have singletons or not?
+            return context.getCoreLibrary().box(childResult).getSingletonClass();
+        } else {
+            return ((RubyBasicObject) childResult).getSingletonClass();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/WriteClassVariableNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.objects;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+@NodeInfo(shortName = "write-class-variable")
+public class WriteClassVariableNode extends RubyNode {
+
+    private final String name;
+    @Child protected RubyNode module;
+    @Child protected RubyNode rhs;
+
+    public WriteClassVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode module, RubyNode rhs) {
+        super(context, sourceSection);
+        this.name = name;
+        this.module = adoptChild(module);
+        this.rhs = adoptChild(rhs);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        // TODO(CS): can module ever not evaluate to a RubyModule?
+
+        final RubyModule moduleObject = (RubyModule) module.execute(frame);
+
+        final Object rhsValue = rhs.execute(frame);
+
+        moduleObject.setClassVariable(name, rhsValue);
+
+        return rhsValue;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/ReadFixnumInstanceVariableNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.objects.instancevariables;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+@NodeInfo(shortName = "@Fixnum")
+public class ReadFixnumInstanceVariableNode extends ReadSpecializedInstanceVariableNode {
+
+    private final FixnumStorageLocation storageLocation;
+
+    public ReadFixnumInstanceVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver, ObjectLayout objectLayout, FixnumStorageLocation storageLocation) {
+        super(context, sourceSection, name, receiver, objectLayout);
+        this.storageLocation = storageLocation;
+    }
+
+    @Override
+    public int executeFixnum(VirtualFrame frame) throws UnexpectedResultException {
+        final RubyBasicObject receiverObject = (RubyBasicObject) receiver.execute(frame);
+
+        final ObjectLayout receiverLayout = receiverObject.getObjectLayout();
+
+        final boolean condition = receiverLayout == objectLayout;
+
+        if (condition) {
+            assert receiverLayout != null;
+            return storageLocation.readFixnum(receiverObject, condition);
+        } else {
+            CompilerDirectives.transferToInterpreter();
+            replace(respecialize(receiverObject));
+            throw new UnexpectedResultException(receiverObject.getInstanceVariable(name));
+        }
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        try {
+            return executeFixnum(frame);
+        } catch (UnexpectedResultException e) {
+            return e.getResult();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/ReadFloatInstanceVariableNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.objects.instancevariables;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+@NodeInfo(shortName = "@Float")
+public class ReadFloatInstanceVariableNode extends ReadSpecializedInstanceVariableNode {
+
+    private final FloatStorageLocation storageLocation;
+
+    public ReadFloatInstanceVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver, ObjectLayout objectLayout, FloatStorageLocation storageLocation) {
+        super(context, sourceSection, name, receiver, objectLayout);
+        this.storageLocation = storageLocation;
+    }
+
+    @Override
+    public double executeFloat(VirtualFrame frame) throws UnexpectedResultException {
+        final RubyBasicObject receiverObject = (RubyBasicObject) receiver.execute(frame);
+
+        final ObjectLayout receiverLayout = receiverObject.getObjectLayout();
+
+        final boolean condition = receiverLayout == objectLayout;
+
+        if (condition) {
+            assert receiverLayout != null;
+            return storageLocation.readFloat(receiverObject, condition);
+        } else {
+            CompilerDirectives.transferToInterpreter();
+            replace(respecialize(receiverObject));
+            throw new UnexpectedResultException(receiverObject.getInstanceVariable(name));
+        }
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        try {
+            return executeFloat(frame);
+        } catch (UnexpectedResultException e) {
+            return e.getResult();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/ReadInstanceVariableNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.objects.instancevariables;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+public abstract class ReadInstanceVariableNode extends RubyNode implements ReadNode {
+
+    protected final String name;
+    @Child protected RubyNode receiver;
+
+    public ReadInstanceVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver) {
+        super(context, sourceSection);
+        this.name = name;
+        this.receiver = adoptChild(receiver);
+    }
+
+    public ReadInstanceVariableNode respecialize(RubyBasicObject receiverObject) {
+        final StorageLocation storageLocation = receiverObject.getUpdatedObjectLayout().findStorageLocation(name);
+
+        if (storageLocation == null) {
+            return new ReadMissingInstanceVariableNode(getSourceSection(), name, receiver, receiverObject.getObjectLayout(), getContext());
+        }
+
+        if (storageLocation instanceof FixnumStorageLocation) {
+            return new ReadFixnumInstanceVariableNode(getContext(), getSourceSection(), name, receiver, storageLocation.getObjectLayout(), (FixnumStorageLocation) storageLocation);
+        } else if (storageLocation instanceof FloatStorageLocation) {
+            return new ReadFloatInstanceVariableNode(getContext(), getSourceSection(), name, receiver, storageLocation.getObjectLayout(), (FloatStorageLocation) storageLocation);
+        } else {
+            return new ReadObjectInstanceVariableNode(getContext(), getSourceSection(), name, receiver, storageLocation.getObjectLayout(), (ObjectStorageLocation) storageLocation);
+        }
+    }
+
+    public WriteInstanceVariableNode makeWriteNode(RubyNode rhs) {
+        return new UninitializedWriteInstanceVariableNode(getContext(), getEncapsulatingSourceSection(), name, (RubyNode) receiver.copy(), rhs);
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public RubyNode getReceiver() {
+        return receiver;
+    }
+
+    @Override
+    public Object isDefined(VirtualFrame frame) {
+        final RubyContext context = getContext();
+
+        try {
+            final Object receiverObject = receiver.execute(frame);
+            final RubyBasicObject receiverRubyObject = context.getCoreLibrary().box(receiverObject);
+
+            final ObjectLayout layout = receiverRubyObject.getObjectLayout();
+            final StorageLocation storageLocation = layout.findStorageLocation(name);
+
+            if (storageLocation.isSet(receiverRubyObject)) {
+                return context.makeString("instance-variable");
+            } else {
+                return NilPlaceholder.INSTANCE;
+            }
+        } catch (Exception e) {
+            return NilPlaceholder.INSTANCE;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/ReadMissingInstanceVariableNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.objects.instancevariables;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+@NodeInfo(shortName = "@missing")
+public class ReadMissingInstanceVariableNode extends ReadSpecializedInstanceVariableNode {
+
+    public ReadMissingInstanceVariableNode(SourceSection sourceSection, String name, RubyNode receiver, ObjectLayout objectLayout, RubyContext context) {
+        super(context, sourceSection, name, receiver, objectLayout);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        final RubyBasicObject receiverObject = (RubyBasicObject) receiver.execute(frame);
+
+        if (!receiverObject.getObjectLayout().contains(objectLayout)) {
+            CompilerDirectives.transferToInterpreter();
+            replace(respecialize(receiverObject));
+            return receiverObject.getInstanceVariable(name);
+        }
+
+        return NilPlaceholder.INSTANCE;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/ReadObjectInstanceVariableNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.objects.instancevariables;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+@NodeInfo(shortName = "@Object")
+public class ReadObjectInstanceVariableNode extends ReadSpecializedInstanceVariableNode {
+
+    private final ObjectStorageLocation storageLocation;
+
+    public ReadObjectInstanceVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver, ObjectLayout objectLayout, ObjectStorageLocation storageLocation) {
+        super(context, sourceSection, name, receiver, objectLayout);
+        this.storageLocation = storageLocation;
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        final RubyBasicObject receiverObject = (RubyBasicObject) receiver.execute(frame);
+
+        final ObjectLayout receiverLayout = receiverObject.getObjectLayout();
+
+        final boolean condition = receiverLayout == objectLayout;
+
+        if (condition) {
+            assert receiverLayout != null;
+            return storageLocation.read(receiverObject, condition);
+        } else {
+            CompilerDirectives.transferToInterpreter();
+            replace(respecialize(receiverObject));
+            return receiverObject.getInstanceVariable(name);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/ReadSpecializedInstanceVariableNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.objects.instancevariables;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+public abstract class ReadSpecializedInstanceVariableNode extends ReadInstanceVariableNode {
+
+    protected final ObjectLayout objectLayout;
+
+    public ReadSpecializedInstanceVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver, ObjectLayout objectLayout) {
+        super(context, sourceSection, name, receiver);
+        this.objectLayout = objectLayout;
+    }
+
+    protected void respecialize() {
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/UninitializedReadInstanceVariableNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.objects.instancevariables;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+@NodeInfo(shortName = "@uninit")
+public class UninitializedReadInstanceVariableNode extends ReadInstanceVariableNode {
+
+    public UninitializedReadInstanceVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver) {
+        super(context, sourceSection, name, receiver);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        CompilerDirectives.transferToInterpreter();
+        final RubyBasicObject receiverObject = (RubyBasicObject) receiver.execute(frame);
+        replace(respecialize(receiverObject));
+        return receiverObject.getInstanceVariable(name);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/UninitializedWriteInstanceVariableNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.objects.instancevariables;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+@NodeInfo(shortName = "@uninit=")
+public class UninitializedWriteInstanceVariableNode extends WriteInstanceVariableNode {
+
+    public UninitializedWriteInstanceVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver, RubyNode rhs) {
+        super(context, sourceSection, name, receiver, rhs);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        CompilerDirectives.transferToInterpreter();
+        final RubyBasicObject receiverObject = (RubyBasicObject) receiver.execute(frame);
+        final Object value = rhs.execute(frame);
+        receiverObject.setInstanceVariable(name, value);
+        replace(respecialize(receiverObject));
+        return value;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/WriteFixnumInstanceVariableNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.objects.instancevariables;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+@NodeInfo(shortName = "@Fixnum=")
+public class WriteFixnumInstanceVariableNode extends WriteSpecializedInstanceVariableNode {
+
+    private final FixnumStorageLocation storageLocation;
+
+    public WriteFixnumInstanceVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver, RubyNode rhs, ObjectLayout objectLayout,
+                    FixnumStorageLocation storageLocation) {
+        super(context, sourceSection, name, receiver, rhs, objectLayout);
+        this.storageLocation = storageLocation;
+    }
+
+    @Override
+    public int executeFixnum(VirtualFrame frame) throws UnexpectedResultException {
+        final RubyBasicObject receiverObject = (RubyBasicObject) receiver.execute(frame);
+
+        int value;
+
+        try {
+            value = rhs.executeFixnum(frame);
+        } catch (UnexpectedResultException e) {
+            receiverObject.setInstanceVariable(name, e.getResult());
+            replace(respecialize(receiverObject));
+            throw e;
+        }
+
+        final ObjectLayout receiverLayout = receiverObject.getObjectLayout();
+
+        if (receiverLayout != objectLayout) {
+            CompilerDirectives.transferToInterpreter();
+            receiverObject.setInstanceVariable(name, value);
+            replace(respecialize(receiverObject));
+            return value;
+        }
+
+        assert receiverLayout != null;
+
+        storageLocation.writeFixnum(receiverObject, value);
+        return value;
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        try {
+            return executeFixnum(frame);
+        } catch (UnexpectedResultException e) {
+            return e.getResult();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/WriteFloatInstanceVariableNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.objects.instancevariables;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+@NodeInfo(shortName = "@Float=")
+public class WriteFloatInstanceVariableNode extends WriteSpecializedInstanceVariableNode {
+
+    private final FloatStorageLocation storageLocation;
+
+    public WriteFloatInstanceVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver, RubyNode rhs, ObjectLayout objectLayout,
+                    FloatStorageLocation storageLocation) {
+        super(context, sourceSection, name, receiver, rhs, objectLayout);
+        this.storageLocation = storageLocation;
+    }
+
+    @Override
+    public double executeFloat(VirtualFrame frame) throws UnexpectedResultException {
+        final RubyBasicObject receiverObject = (RubyBasicObject) receiver.execute(frame);
+
+        double value;
+
+        try {
+            value = rhs.executeFloat(frame);
+        } catch (UnexpectedResultException e) {
+            receiverObject.setInstanceVariable(name, e.getResult());
+            replace(respecialize(receiverObject));
+            throw e;
+        }
+
+        final ObjectLayout receiverLayout = receiverObject.getObjectLayout();
+
+        if (receiverLayout != objectLayout) {
+            CompilerDirectives.transferToInterpreter();
+            receiverObject.setInstanceVariable(name, value);
+            replace(respecialize(receiverObject));
+            return value;
+        }
+
+        assert receiverLayout != null;
+
+        storageLocation.writeFloat(receiverObject, value);
+        return value;
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        try {
+            return executeFloat(frame);
+        } catch (UnexpectedResultException e) {
+            return e.getResult();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/WriteInstanceVariableNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.objects.instancevariables;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+public abstract class WriteInstanceVariableNode extends RubyNode implements WriteNode {
+
+    protected final String name;
+    @Child protected RubyNode receiver;
+    @Child protected RubyNode rhs;
+
+    public WriteInstanceVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver, RubyNode rhs) {
+        super(context, sourceSection);
+        this.name = name;
+        this.receiver = adoptChild(receiver);
+        this.rhs = adoptChild(rhs);
+    }
+
+    public WriteInstanceVariableNode respecialize(RubyBasicObject receiverObject) {
+        StorageLocation storageLocation = receiverObject.getObjectLayout().findStorageLocation(name);
+
+        if (storageLocation == null) {
+            throw new RuntimeException("Storage location should be found at this point");
+        }
+
+        if (storageLocation instanceof FixnumStorageLocation) {
+            return new WriteFixnumInstanceVariableNode(getContext(), getSourceSection(), name, receiver, rhs, storageLocation.getObjectLayout(), (FixnumStorageLocation) storageLocation);
+        } else if (storageLocation instanceof FloatStorageLocation) {
+            return new WriteFloatInstanceVariableNode(getContext(), getSourceSection(), name, receiver, rhs, storageLocation.getObjectLayout(), (FloatStorageLocation) storageLocation);
+        } else {
+            return new WriteObjectInstanceVariableNode(getContext(), getSourceSection(), name, receiver, rhs, storageLocation.getObjectLayout(), (ObjectStorageLocation) storageLocation);
+        }
+    }
+
+    @Override
+    public ReadInstanceVariableNode makeReadNode() {
+        return new UninitializedReadInstanceVariableNode(getContext(), getEncapsulatingSourceSection(), name, (RubyNode) receiver.copy());
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public RubyNode getReceiver() {
+        return receiver;
+    }
+
+    public RubyNode getRHS() {
+        return rhs;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/WriteObjectInstanceVariableNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.objects.instancevariables;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+@NodeInfo(shortName = "@Object=")
+public class WriteObjectInstanceVariableNode extends WriteSpecializedInstanceVariableNode {
+
+    private final ObjectStorageLocation storageLocation;
+
+    public WriteObjectInstanceVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver, RubyNode rhs, ObjectLayout objectLayout,
+                    ObjectStorageLocation storageLocation) {
+        super(context, sourceSection, name, receiver, rhs, objectLayout);
+        this.storageLocation = storageLocation;
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        final RubyBasicObject receiverObject = (RubyBasicObject) receiver.execute(frame);
+        final Object value = rhs.execute(frame);
+
+        final ObjectLayout receiverLayout = receiverObject.getObjectLayout();
+
+        if (receiverLayout != objectLayout) {
+            CompilerDirectives.transferToInterpreter();
+            receiverObject.setInstanceVariable(name, value);
+            replace(respecialize(receiverObject));
+            return value;
+        }
+
+        assert receiverLayout != null;
+
+        storageLocation.write(receiverObject, value);
+        return value;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/objects/instancevariables/WriteSpecializedInstanceVariableNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.objects.instancevariables;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+public abstract class WriteSpecializedInstanceVariableNode extends WriteInstanceVariableNode {
+
+    protected final ObjectLayout objectLayout;
+
+    public WriteSpecializedInstanceVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver, RubyNode rhs, ObjectLayout objectLayout) {
+        super(context, sourceSection, name, receiver, rhs);
+        this.objectLayout = objectLayout;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/yield/GeneralYieldDispatchNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.yield;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+/**
+ * A yield dispatch node that just calls {@link RubyProc#call} as normal.
+ */
+public class GeneralYieldDispatchNode extends YieldDispatchNode {
+
+    public GeneralYieldDispatchNode(RubyContext context, SourceSection sourceSection) {
+        super(context, sourceSection);
+    }
+
+    @Override
+    public Object dispatch(VirtualFrame frame, RubyProc block, Object[] argumentsObjects) {
+        return block.call(frame.pack(), argumentsObjects);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/yield/InlinedYieldDispatchNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.yield;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+/**
+ * Dispatch to a known method which has been inlined.
+ */
+public class InlinedYieldDispatchNode extends YieldDispatchNode {
+
+    private final RubyRootNode pristineRootNode;
+
+    private final FrameDescriptor frameDescriptor;
+    private final RubyRootNode rootNode;
+
+    public InlinedYieldDispatchNode(RubyContext context, SourceSection sourceSection, InlinableMethodImplementation method) {
+        super(context, sourceSection);
+        pristineRootNode = method.getPristineRootNode();
+        frameDescriptor = method.getFrameDescriptor();
+        rootNode = method.getCloneOfPristineRootNode();
+    }
+
+    @Override
+    public Object dispatch(VirtualFrame frame, RubyProc block, Object[] argumentsObjects) {
+        /*
+         * We're inlining based on the root node used, checking that root node still matches, and
+         * then taking the materialized frame from the block we actually got. We can't look for
+         * RubyMethod or RubyProc, because they're allocated for each call passing a block.
+         */
+
+        if (!(block.getMethod().getImplementation() instanceof InlinableMethodImplementation) ||
+                        ((InlinableMethodImplementation) block.getMethod().getImplementation()).getPristineRootNode() != pristineRootNode) {
+            CompilerDirectives.transferToInterpreter();
+
+            // TODO(CS): at the moment we just go back to uninit, which may cause loops
+
+            final UninitializedYieldDispatchNode dispatch = new UninitializedYieldDispatchNode(getContext(), getSourceSection());
+            replace(dispatch);
+            return dispatch.dispatch(frame, block, argumentsObjects);
+        }
+
+        final InlinableMethodImplementation implementation = (InlinableMethodImplementation) block.getMethod().getImplementation();
+
+        final RubyArguments arguments = new RubyArguments(implementation.getDeclarationFrame(), block.getSelf(), block.getBlock(), argumentsObjects);
+        final VirtualFrame inlinedFrame = Truffle.getRuntime().createVirtualFrame(frame.pack(), arguments, frameDescriptor);
+        return rootNode.execute(inlinedFrame);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/yield/UninitializedYieldDispatchNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.yield;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.nodes.call.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+
+/**
+ * An uninitialized node in the yield dispatch chain.
+ */
+public class UninitializedYieldDispatchNode extends YieldDispatchNode {
+
+    public UninitializedYieldDispatchNode(RubyContext context, SourceSection sourceSection) {
+        super(context, sourceSection);
+    }
+
+    @Override
+    public Object dispatch(VirtualFrame frame, RubyProc block, Object[] argumentsObjects) {
+        CompilerDirectives.transferToInterpreter();
+
+        final MethodImplementation implementation = block.getMethod().getImplementation();
+
+        if (implementation instanceof InlinableMethodImplementation && InlineHeuristic.shouldInlineYield((InlinableMethodImplementation) implementation)) {
+            final InlinedYieldDispatchNode dispatch = new InlinedYieldDispatchNode(getContext(), getSourceSection(), (InlinableMethodImplementation) implementation);
+            replace(dispatch);
+            return dispatch.dispatch(frame, block, argumentsObjects);
+        } else {
+            final GeneralYieldDispatchNode dispatch = new GeneralYieldDispatchNode(getContext(), getSourceSection());
+            replace(dispatch);
+            return dispatch.dispatch(frame, block, argumentsObjects);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/yield/YieldDispatchNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.yield;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+/**
+ * A node in the yield dispatch chain.
+ */
+public abstract class YieldDispatchNode extends Node {
+
+    private final RubyContext context;
+
+    public YieldDispatchNode(RubyContext context, SourceSection sourceSection) {
+        super(sourceSection);
+
+        assert context != null;
+        assert sourceSection != null;
+
+        this.context = context;
+    }
+
+    public abstract Object dispatch(VirtualFrame frame, RubyProc block, Object[] argumentsObjects);
+
+    public RubyContext getContext() {
+        return context;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/yield/YieldNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.yield;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+/**
+ * Yield to the current block.
+ */
+@NodeInfo(shortName = "yield")
+public class YieldNode extends RubyNode {
+
+    @Children protected final RubyNode[] arguments;
+    @Child protected YieldDispatchNode dispatch;
+
+    public YieldNode(RubyContext context, SourceSection sourceSection, RubyNode[] arguments) {
+        super(context, sourceSection);
+        this.arguments = adoptChildren(arguments);
+        dispatch = adoptChild(new UninitializedYieldDispatchNode(getContext(), getSourceSection()));
+    }
+
+    @ExplodeLoop
+    @Override
+    public final Object execute(VirtualFrame frame) {
+        final Object[] argumentsObjects = new Object[arguments.length];
+
+        for (int i = 0; i < arguments.length; i++) {
+            argumentsObjects[i] = arguments[i].execute(frame);
+        }
+
+        final RubyProc block = frame.getArguments(RubyArguments.class).getBlock();
+
+        if (block == null) {
+            CompilerDirectives.transferToInterpreter();
+            // TODO(CS): convert to the proper Ruby exception
+            throw new RuntimeException("No block to yield to");
+        }
+
+        return dispatch.dispatch(frame, block, argumentsObjects);
+    }
+
+    @Override
+    public Object isDefined(VirtualFrame frame) {
+        final RubyArguments args = frame.getArguments(RubyArguments.class);
+
+        if (args.getBlock() == null) {
+            return NilPlaceholder.INSTANCE;
+        } else {
+            return getContext().makeString("yield");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/DeadNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.parser;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * Dead nodes are removed wherever they are found during translation. They fill in for some missing
+ * nodes when we're processing the AST.
+ */
+public class DeadNode extends RubyNode {
+
+    public DeadNode(RubyContext context, SourceSection sourceSection) {
+        super(context, sourceSection);
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        throw new UnsupportedOperationException("Dead nodes should have been pruned before execution starts");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/JRubyParser.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.parser;
+
+import java.io.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.nodes.control.*;
+import com.oracle.truffle.ruby.nodes.literal.*;
+import com.oracle.truffle.ruby.nodes.methods.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.debug.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+
+public class JRubyParser implements RubyParser {
+
+    private long nextReturnID = 0;
+
+    @Override
+    public RubyParserResult parse(RubyContext context, Source source, ParserContext parserContext, MaterializedFrame parentFrame) {
+        // Set up the JRuby parser
+
+        final org.jrubyparser.Parser parser = new org.jrubyparser.Parser();
+
+        org.jrubyparser.CompatVersion parserVersion = null;
+
+        switch (context.getConfiguration().getRubyVersion()) {
+            case RUBY_18:
+                parserVersion = org.jrubyparser.CompatVersion.RUBY1_8;
+                break;
+            case RUBY_19:
+                parserVersion = org.jrubyparser.CompatVersion.RUBY1_9;
+                break;
+            case RUBY_20:
+                parserVersion = org.jrubyparser.CompatVersion.RUBY2_0;
+                break;
+            case RUBY_21:
+                parserVersion = org.jrubyparser.CompatVersion.RUBY2_0;
+                break;
+        }
+
+        // TODO(cs) should this get a new unique method identifier or not?
+        final TranslatorEnvironment environment = new TranslatorEnvironment(context, environmentForFrame(context, parentFrame), this, allocateReturnID(), true, true, new UniqueMethodIdentifier());
+
+        // All parsing contexts have a visibility slot at their top level
+
+        environment.addMethodDeclarationSlots();
+
+        final org.jrubyparser.LocalStaticScope staticScope = new org.jrubyparser.LocalStaticScope(null);
+
+        if (parentFrame != null) {
+            /*
+             * Note that jruby-parser will be mistaken about how deep the existing variables are,
+             * but that doesn't matter as we look them up ourselves after being told their in some
+             * parent scope.
+             */
+
+            MaterializedFrame frame = parentFrame;
+
+            while (frame != null) {
+                for (FrameSlot slot : frame.getFrameDescriptor().getSlots()) {
+                    if (slot.getIdentifier() instanceof String) {
+                        final String name = (String) slot.getIdentifier();
+                        if (staticScope.exists(name) == -1) {
+                            staticScope.assign(null, name, null);
+                        }
+                    }
+                }
+
+                frame = frame.getArguments(RubyArguments.class).getDeclarationFrame();
+            }
+        }
+
+        final org.jrubyparser.parser.ParserConfiguration parserConfiguration = new org.jrubyparser.parser.ParserConfiguration(0, parserVersion, staticScope);
+
+        // Parse to the JRuby AST
+
+        org.jrubyparser.ast.RootNode node;
+
+        try {
+            node = (org.jrubyparser.ast.RootNode) parser.parse(source.getName(), new StringReader(source.getCode()), parserConfiguration);
+        } catch (UnsupportedOperationException | org.jrubyparser.lexer.SyntaxException e) {
+            String message = e.getMessage();
+
+            if (message == null) {
+                message = "(no message)";
+            }
+
+            throw new RaiseException(new RubyException(context.getCoreLibrary().getSyntaxErrorClass(), message));
+        }
+
+        if (context.getConfiguration().getPrintParseTree()) {
+            System.err.println(node);
+        }
+
+        // Translate to Ruby Truffle nodes
+
+        final Translator translator;
+
+        if (parserContext == RubyParser.ParserContext.MODULE) {
+            translator = new ModuleTranslator(context, null, environment, source);
+        } else {
+            translator = new Translator(context, null, environment, source);
+        }
+
+        RubyNode truffleNode;
+
+        final RubyDebugManager debugManager = context.getDebugManager();
+        try {
+            if (debugManager != null) {
+                debugManager.notifyStartLoading(source);
+            }
+
+            if (node.getBody() == null) {
+                truffleNode = new NilNode(context, null);
+            } else {
+                truffleNode = (RubyNode) node.getBody().accept(translator);
+            }
+
+            // Load flip-flop states
+
+            if (environment.getFlipFlopStates().size() > 0) {
+                truffleNode = new SequenceNode(context, truffleNode.getSourceSection(), translator.initFlipFlopStates(truffleNode.getSourceSection()), truffleNode);
+            }
+
+            // Catch next
+
+            truffleNode = new CatchNextNode(context, truffleNode.getSourceSection(), truffleNode);
+
+            // Catch return
+
+            truffleNode = new CatchReturnAsErrorNode(context, truffleNode.getSourceSection(), truffleNode);
+
+            // Shell result
+
+            if (parserContext == RubyParser.ParserContext.SHELL) {
+                truffleNode = new ShellResultNode(context, truffleNode.getSourceSection(), truffleNode);
+            }
+
+            // Root Node
+
+            String indicativeName;
+
+            switch (parserContext) {
+                case TOP_LEVEL:
+                    indicativeName = "(main)";
+                    break;
+                case SHELL:
+                    indicativeName = "(shell)";
+                    break;
+                case MODULE:
+                    indicativeName = "(module)";
+                    break;
+                default:
+                    throw new UnsupportedOperationException();
+            }
+
+            final RootNode root = new RubyRootNode(truffleNode.getSourceSection(), indicativeName, truffleNode);
+
+            // Return the root and the frame descriptor
+
+            return new RubyParserResult(root, environment.getFrameDescriptor());
+        } finally {
+            if (debugManager != null) {
+                debugManager.notifyFinishedLoading(source);
+            }
+        }
+    }
+
+    public long allocateReturnID() {
+        if (nextReturnID == Long.MAX_VALUE) {
+            throw new RuntimeException("Return IDs exhausted");
+        }
+
+        final long allocated = nextReturnID;
+        nextReturnID++;
+        return allocated;
+    }
+
+    private TranslatorEnvironment environmentForFrame(RubyContext context, MaterializedFrame frame) {
+        if (frame == null) {
+            return null;
+        } else {
+            final MaterializedFrame parent = frame.getArguments(RubyArguments.class).getDeclarationFrame();
+            return new TranslatorEnvironment(context, environmentForFrame(context, parent), frame.getFrameDescriptor(), this, allocateReturnID(), true, true, new UniqueMethodIdentifier());
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/MethodTranslator.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.parser;
+
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.nodes.call.*;
+import com.oracle.truffle.ruby.nodes.control.*;
+import com.oracle.truffle.ruby.nodes.literal.*;
+import com.oracle.truffle.ruby.nodes.methods.*;
+import com.oracle.truffle.ruby.nodes.methods.arguments.*;
+import com.oracle.truffle.ruby.nodes.methods.locals.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+
+class MethodTranslator extends Translator {
+
+    private boolean isBlock;
+
+    public MethodTranslator(RubyContext context, Translator parent, TranslatorEnvironment environment, boolean isBlock, Source source) {
+        super(context, parent, environment, source);
+        this.isBlock = isBlock;
+    }
+
+    public MethodDefinitionNode compileFunctionNode(SourceSection sourceSection, String methodName, org.jrubyparser.ast.ArgsNode argsNode, org.jrubyparser.ast.Node bodyNode) {
+        environment.setMethodName(methodName);
+
+        final Arity arity = findParameters(argsNode);
+
+        RubyNode body;
+
+        if (bodyNode != null) {
+            body = (RubyNode) bodyNode.accept(this);
+        } else {
+            body = new NilNode(context, sourceSection);
+        }
+
+        body = loadArgumentsIntoLocals(arity, body);
+
+        if (environment.getFlipFlopStates().size() > 0) {
+            body = new SequenceNode(context, sourceSection, initFlipFlopStates(sourceSection), body);
+        }
+
+        if (isBlock) {
+            body = new CatchNextNode(context, sourceSection, body);
+        } else {
+            body = new CatchReturnNode(context, sourceSection, body, environment.getReturnID());
+            body = new CatchNextNode(context, sourceSection, body);
+        }
+
+        final RubyRootNode pristineRootNode = new RubyRootNode(sourceSection, methodName, body);
+
+        final CallTarget callTarget = Truffle.getRuntime().createCallTarget(NodeUtil.cloneNode(pristineRootNode), environment.getFrameDescriptor());
+
+        if (isBlock) {
+            return new BlockDefinitionNode(context, sourceSection, methodName, environment.getUniqueMethodIdentifier(), environment.getFrameDescriptor(), environment.needsDeclarationFrame(),
+                            pristineRootNode, callTarget);
+        } else {
+            return new MethodDefinitionNode(context, sourceSection, methodName, environment.getUniqueMethodIdentifier(), environment.getFrameDescriptor(), environment.needsDeclarationFrame(),
+                            pristineRootNode, callTarget);
+        }
+    }
+
+    private RubyNode loadArgumentsIntoLocals(Arity arity, RubyNode body) {
+        final SourceSection sourceSection = body.getEncapsulatingSourceSection();
+
+        final List<RubyNode> loadIndividualArgumentsNodes = new ArrayList<>();
+
+        if (!isBlock) {
+            loadIndividualArgumentsNodes.add(new CheckArityNode(context, sourceSection, arity));
+        }
+
+        final int preCount = environment.getPreParameters().size();
+        final int postCount = environment.getPostParameters().size();
+
+        for (int n = 0; n < environment.getPreParameters().size(); n++) {
+            final FrameSlot param = environment.getPreParameters().get(n);
+
+            // ReadPre reads from the start of the arguments array
+
+            final ReadPreArgumentNode readArgumentNode = new ReadPreArgumentNode(context, sourceSection, n, false);
+
+            final WriteLocalVariableNode writeLocal = WriteLocalVariableNodeFactory.create(context, sourceSection, param, readArgumentNode);
+
+            loadIndividualArgumentsNodes.add(writeLocal);
+        }
+
+        for (int n = 0; n < environment.getOptionalParameters().size(); n++) {
+            final FrameSlot param = environment.getOptionalParameters().get(n);
+            final RubyNode defaultValue = environment.getOptionalParametersDefaultValues().get(param);
+
+            /*
+             * ReadOptional reads from the start of the arguments array, as long as it is long
+             * enough, else uses the default value (which may use locals with arguments just loaded,
+             * either from pre or preceding optionals).
+             */
+
+            final ReadOptionalArgumentNode readArgumentNode = new ReadOptionalArgumentNode(context, body.getEncapsulatingSourceSection(), preCount + n, preCount + postCount + n + 1,
+                            (RubyNode) defaultValue.copy());
+
+            final WriteLocalVariableNode writeLocal = WriteLocalVariableNodeFactory.create(context, sourceSection, param, readArgumentNode);
+
+            loadIndividualArgumentsNodes.add(writeLocal);
+        }
+
+        for (int n = 0; n < environment.getPostParameters().size(); n++) {
+            final FrameSlot param = environment.getPostParameters().get(n);
+
+            // ReadPost reads from the end of the arguments array
+
+            final ReadPostArgumentNode readArgumentNode = new ReadPostArgumentNode(context, sourceSection, postCount - n - 1);
+
+            final WriteLocalVariableNode writeLocal = WriteLocalVariableNodeFactory.create(context, sourceSection, param, readArgumentNode);
+
+            loadIndividualArgumentsNodes.add(writeLocal);
+        }
+
+        if (environment.getRestParameter() != null) {
+            /*
+             * TODO(cs): this assumes there are no optionals and therefore also no posts, which may
+             * not be a valid assumption.
+             */
+
+            if (postCount != 0) {
+                context.implementationMessage("post arguments as well as a rest argument - they will conflict");
+            }
+
+            final ReadRestArgumentNode readArgumentNode = new ReadRestArgumentNode(context, sourceSection, preCount);
+
+            final WriteLocalVariableNode writeLocal = WriteLocalVariableNodeFactory.create(context, sourceSection, environment.getRestParameter(), readArgumentNode);
+
+            loadIndividualArgumentsNodes.add(writeLocal);
+        }
+
+        if (environment.getBlockParameter() != null) {
+            final FrameSlot param = environment.getBlockParameter();
+
+            final ReadBlockArgumentNode readArgumentNode = new ReadBlockArgumentNode(context, sourceSection, false);
+
+            final WriteLocalVariableNode writeLocal = WriteLocalVariableNodeFactory.create(context, sourceSection, param, readArgumentNode);
+
+            loadIndividualArgumentsNodes.add(writeLocal);
+        }
+
+        final RubyNode loadIndividualArguments = new SequenceNode(context, sourceSection, loadIndividualArgumentsNodes.toArray(new RubyNode[loadIndividualArgumentsNodes.size()]));
+
+        final RubyNode noSwitch = new SequenceNode(context, body.getSourceSection(), loadIndividualArguments, body);
+
+        if (!isBlock) {
+            return noSwitch;
+        }
+
+        /*
+         * See the test testBlockArgumentsDestructure for a motivation for this. See
+         * BlockDestructureSwitchNode for how it works.
+         */
+
+        if (preCount + postCount == 1 && environment.getOptionalParameters().size() == 0) {
+            return noSwitch;
+        }
+
+        final List<RubyNode> destructureLoadArgumentsNodes = new ArrayList<>();
+
+        for (int n = 0; n < environment.getPreParameters().size(); n++) {
+            final FrameSlot param = environment.getPreParameters().get(n);
+
+            final ReadDestructureArgumentNode readArgumentNode = new ReadDestructureArgumentNode(context, sourceSection, n);
+
+            final WriteLocalVariableNode writeLocal = WriteLocalVariableNodeFactory.create(context, sourceSection, param, readArgumentNode);
+
+            destructureLoadArgumentsNodes.add(writeLocal);
+        }
+
+        final RubyNode destructureLoadArguments = new SequenceNode(context, body.getSourceSection(), destructureLoadArgumentsNodes.toArray(new RubyNode[destructureLoadArgumentsNodes.size()]));
+
+        return new BlockDestructureSwitchNode(context, body.getEncapsulatingSourceSection(), loadIndividualArguments, destructureLoadArguments, body);
+
+    }
+
+    private Arity findParameters(org.jrubyparser.ast.ArgsNode args) {
+        if (args == null) {
+            return Arity.NO_ARGS;
+        }
+
+        final SourceSection sourceSection = translate(args.getPosition());
+
+        if (args.getPre() != null) {
+            for (org.jrubyparser.ast.Node arg : args.getPre().childNodes()) {
+                if (arg instanceof org.jrubyparser.ast.ArgumentNode) {
+                    final org.jrubyparser.ast.ArgumentNode argNode = (org.jrubyparser.ast.ArgumentNode) arg;
+                    environment.getPreParameters().add(environment.declareVar(argNode.getName()));
+                } else if (arg instanceof org.jrubyparser.ast.MultipleAsgnNode) {
+                    /*
+                     * TODO(cs): I don't know how to handle this yet, so I just do my best to get
+                     * the names out and define them so the rest of the parser succeeds.
+                     */
+
+                    context.implementationMessage("only extracting names from multiple assignment in arguments");
+
+                    final org.jrubyparser.ast.MultipleAsgnNode multAsgn = (org.jrubyparser.ast.MultipleAsgnNode) arg;
+
+                    final List<String> names = new ArrayList<>();
+                    getNamesFromMultipleAssignment(multAsgn, names);
+
+                    for (String name : names) {
+                        environment.getPreParameters().add(environment.declareVar(name));
+                    }
+                }
+            }
+        }
+
+        // The JRuby parser expresses optional arguments as a block of local assignments
+
+        /*
+         * Note that default values for optional params can refer to the actual value of previous
+         * args, so be careful with the order of args here and in loadArgumentsIntoLocals.
+         */
+
+        if (args.getOptional() != null) {
+            for (org.jrubyparser.ast.Node arg : args.getOptional().childNodes()) {
+                final org.jrubyparser.ast.OptArgNode optArgNode = (org.jrubyparser.ast.OptArgNode) arg;
+
+                String name;
+                org.jrubyparser.ast.Node valueNode;
+
+                if (optArgNode.getValue() instanceof org.jrubyparser.ast.LocalAsgnNode) {
+                    final org.jrubyparser.ast.LocalAsgnNode optLocalAsgn = (org.jrubyparser.ast.LocalAsgnNode) optArgNode.getValue();
+                    name = optLocalAsgn.getName();
+                    valueNode = optLocalAsgn.getValue();
+                } else if (optArgNode.getValue() instanceof org.jrubyparser.ast.DAsgnNode) {
+                    final org.jrubyparser.ast.DAsgnNode optLocalAsgn = (org.jrubyparser.ast.DAsgnNode) optArgNode.getValue();
+                    name = optLocalAsgn.getName();
+                    valueNode = optLocalAsgn.getValue();
+                } else {
+                    throw new UnsupportedOperationException(optArgNode.getValue().getClass().getName());
+                }
+
+                RubyNode paramDefaultValue;
+
+                if (valueNode == null) {
+                    paramDefaultValue = new NilNode(context, sourceSection);
+                } else {
+                    paramDefaultValue = (RubyNode) valueNode.accept(this);
+                }
+
+                final FrameSlot frameSlot = environment.declareVar(name);
+                environment.getOptionalParameters().add(frameSlot);
+                environment.getOptionalParametersDefaultValues().put(frameSlot, paramDefaultValue);
+            }
+        }
+
+        if (args.getPost() != null) {
+            for (org.jrubyparser.ast.Node arg : args.getPost().childNodes()) {
+                final org.jrubyparser.ast.ArgumentNode argNode = (org.jrubyparser.ast.ArgumentNode) arg;
+                environment.getPostParameters().add(environment.declareVar(argNode.getName()));
+            }
+        }
+
+        if (args.getRest() != null) {
+            final org.jrubyparser.ast.RestArgNode rest = (org.jrubyparser.ast.RestArgNode) args.getRest();
+            environment.setRestParameter(environment.declareVar(rest.getName()));
+        }
+
+        if (args.getBlock() != null) {
+            final org.jrubyparser.ast.BlockArgNode blockArgNode = args.getBlock();
+            final FrameSlot frameSlot = environment.declareVar(blockArgNode.getName());
+            environment.setBlockParameter(frameSlot);
+        }
+
+        final int minimum = environment.getPreParameters().size() + environment.getPostParameters().size();
+
+        int maximum = minimum + environment.getOptionalParameters().size();
+
+        if (args.getRest() != null) {
+            maximum = Arity.NO_MAXIMUM;
+        }
+
+        return new Arity(minimum, maximum);
+    }
+
+    private void getNamesFromMultipleAssignment(org.jrubyparser.ast.MultipleAsgnNode multAsgn, List<String> names) {
+        for (org.jrubyparser.ast.Node a : multAsgn.getPre().childNodes()) {
+            if (a instanceof org.jrubyparser.ast.DAsgnNode) {
+                names.add(((org.jrubyparser.ast.DAsgnNode) a).getName());
+            } else if (a instanceof org.jrubyparser.ast.MultipleAsgnNode) {
+                getNamesFromMultipleAssignment((org.jrubyparser.ast.MultipleAsgnNode) a, names);
+            } else if (a instanceof org.jrubyparser.ast.LocalAsgnNode) {
+                names.add(((org.jrubyparser.ast.LocalAsgnNode) a).getName());
+            } else {
+                throw new RuntimeException(a.getClass().getName());
+            }
+        }
+    }
+
+    @Override
+    public Object visitSuperNode(org.jrubyparser.ast.SuperNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        final ArgumentsAndBlockTranslation argumentsAndBlock = translateArgumentsAndBlock(sourceSection, node.getIter(), node.getArgs(), null);
+
+        final String name = environment.getMethodName();
+
+        return new GeneralSuperCallNode(context, sourceSection, name, argumentsAndBlock.getBlock(), argumentsAndBlock.getArguments(), argumentsAndBlock.isSplatted());
+    }
+
+    @Override
+    public Object visitZSuperNode(org.jrubyparser.ast.ZSuperNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        final ArgumentsAndBlockTranslation argumentsAndBlock = translateArgumentsAndBlock(sourceSection, node.getIter(), null, null);
+
+        final String name = environment.getMethodName();
+
+        return new GeneralSuperCallNode(context, sourceSection, name, argumentsAndBlock.getBlock(), argumentsAndBlock.getArguments(), argumentsAndBlock.isSplatted());
+    }
+
+    @Override
+    protected FlipFlopStateNode createFlipFlopState(SourceSection sourceSection, int depth) {
+        if (isBlock) {
+            environment.setNeedsDeclarationFrame();
+            return parent.createFlipFlopState(sourceSection, depth + 1);
+        } else {
+            return super.createFlipFlopState(sourceSection, depth);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/ModuleTranslator.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.parser;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.nodes.constants.*;
+import com.oracle.truffle.ruby.nodes.control.*;
+import com.oracle.truffle.ruby.nodes.literal.*;
+import com.oracle.truffle.ruby.nodes.methods.*;
+import com.oracle.truffle.ruby.nodes.objects.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+
+/**
+ * Translates module and class nodes.
+ * <p>
+ * In Ruby, a module or class definition is somewhat like a method. It has a local scope and a value
+ * for self, which is the module or class object that is being defined. Therefore for a module or
+ * class definition we translate into a special method. We run that method with self set to be the
+ * newly allocated module or class. We then have to treat at least method and constant definitions
+ * differently.
+ */
+class ModuleTranslator extends Translator {
+
+    public ModuleTranslator(RubyContext context, Translator parent, TranslatorEnvironment environment, Source source) {
+        super(context, parent, environment, source);
+    }
+
+    public MethodDefinitionNode compileClassNode(org.jrubyparser.SourcePosition sourcePosition, String name, org.jrubyparser.ast.Node bodyNode) {
+        final SourceSection sourceSection = translate(sourcePosition);
+
+        environment.addMethodDeclarationSlots();
+
+        final String methodName = "(" + name + "-def" + ")";
+        environment.setMethodName(methodName);
+
+        RubyNode body;
+
+        if (bodyNode != null) {
+            body = (RubyNode) bodyNode.accept(this);
+        } else {
+            body = new NilNode(context, sourceSection);
+        }
+
+        if (environment.getFlipFlopStates().size() > 0) {
+            body = new SequenceNode(context, sourceSection, initFlipFlopStates(sourceSection), body);
+        }
+
+        body = new CatchReturnNode(context, sourceSection, body, environment.getReturnID());
+
+        final RubyRootNode pristineRootNode = new RubyRootNode(sourceSection, methodName, body);
+
+        final CallTarget callTarget = Truffle.getRuntime().createCallTarget(NodeUtil.cloneNode(pristineRootNode), environment.getFrameDescriptor());
+
+        return new MethodDefinitionNode(context, sourceSection, methodName, environment.getUniqueMethodIdentifier(), environment.getFrameDescriptor(), environment.needsDeclarationFrame(),
+                        pristineRootNode, callTarget);
+    }
+
+    @Override
+    public Object visitConstDeclNode(org.jrubyparser.ast.ConstDeclNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        final SelfNode selfNode = new SelfNode(context, sourceSection);
+
+        return new WriteConstantNode(context, sourceSection, node.getName(), selfNode, (RubyNode) node.getValue().accept(this));
+    }
+
+    @Override
+    public Object visitConstNode(org.jrubyparser.ast.ConstNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        final SelfNode selfNode = new SelfNode(context, sourceSection);
+
+        return new UninitializedReadConstantNode(context, sourceSection, node.getName(), selfNode);
+    }
+
+    @Override
+    public Object visitDefnNode(org.jrubyparser.ast.DefnNode node) {
+        /*
+         * The top-level translator puts methods into Object. We put ours into the self, which is
+         * the class being defined.
+         */
+
+        final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(context, environment, environment.getParser(), environment.getParser().allocateReturnID(), true, true,
+                        new UniqueMethodIdentifier());
+        final MethodTranslator methodCompiler = new MethodTranslator(context, this, newEnvironment, false, source);
+        final MethodDefinitionNode functionExprNode = methodCompiler.compileFunctionNode(translate(node.getPosition()), node.getName(), node.getArgs(), node.getBody());
+
+        final SourceSection sourceSection = translate(node.getPosition());
+        return new AddMethodNode(context, sourceSection, new SelfNode(context, sourceSection), functionExprNode);
+    }
+
+    @Override
+    public Object visitClassVarAsgnNode(org.jrubyparser.ast.ClassVarAsgnNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        final RubyNode receiver = new SelfNode(context, sourceSection);
+
+        final RubyNode rhs = (RubyNode) node.getValue().accept(this);
+
+        return new WriteClassVariableNode(context, sourceSection, node.getName(), receiver, rhs);
+    }
+
+    @Override
+    public Object visitClassVarNode(org.jrubyparser.ast.ClassVarNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+        return new ReadClassVariableNode(context, sourceSection, node.getName(), new SelfNode(context, sourceSection));
+    }
+
+    @Override
+    public Object visitAliasNode(org.jrubyparser.ast.AliasNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        final org.jrubyparser.ast.LiteralNode oldName = (org.jrubyparser.ast.LiteralNode) node.getOldName();
+        final org.jrubyparser.ast.LiteralNode newName = (org.jrubyparser.ast.LiteralNode) node.getNewName();
+
+        return new AliasNode(context, sourceSection, new SelfNode(context, sourceSection), newName.getName(), oldName.getName());
+    }
+
+    @Override
+    protected RubyNode getModuleToDefineModulesIn(SourceSection sourceSection) {
+        return new SelfNode(context, sourceSection);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/RubyFrameTypeConversion.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.parser;
+
+import com.oracle.truffle.api.impl.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+public final class RubyFrameTypeConversion extends DefaultFrameTypeConversion {
+
+    private static final RubyFrameTypeConversion INSTANCE = new RubyFrameTypeConversion();
+
+    private RubyFrameTypeConversion() {
+    }
+
+    @Override
+    public Object getDefaultValue() {
+        return NilPlaceholder.INSTANCE;
+    }
+
+    public static RubyFrameTypeConversion getInstance() {
+        return INSTANCE;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/Translator.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,2093 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.parser;
+
+import java.math.*;
+import java.util.*;
+import java.util.regex.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.impl.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.nodes.call.*;
+import com.oracle.truffle.ruby.nodes.cast.*;
+import com.oracle.truffle.ruby.nodes.constants.*;
+import com.oracle.truffle.ruby.nodes.control.*;
+import com.oracle.truffle.ruby.nodes.core.*;
+import com.oracle.truffle.ruby.nodes.debug.*;
+import com.oracle.truffle.ruby.nodes.literal.*;
+import com.oracle.truffle.ruby.nodes.literal.array.*;
+import com.oracle.truffle.ruby.nodes.methods.*;
+import com.oracle.truffle.ruby.nodes.methods.locals.*;
+import com.oracle.truffle.ruby.nodes.objects.*;
+import com.oracle.truffle.ruby.nodes.objects.instancevariables.*;
+import com.oracle.truffle.ruby.nodes.yield.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.core.range.*;
+import com.oracle.truffle.ruby.runtime.debug.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+
+/**
+ * A JRuby parser node visitor which translates JRuby AST nodes into our Ruby nodes, implementing a
+ * Ruby parser. Therefore there is some namespace contention here! We make all references to JRuby
+ * explicit. This is the only place though - it doesn't leak out elsewhere.
+ */
+public class Translator implements org.jrubyparser.NodeVisitor {
+
+    protected final Translator parent;
+
+    protected final RubyContext context;
+    protected final TranslatorEnvironment environment;
+    protected final Source source;
+
+    private boolean translatingForStatement = false;
+
+    private static final Map<Class, String> nodeDefinedNames = new HashMap<>();
+
+    static {
+        nodeDefinedNames.put(org.jrubyparser.ast.SelfNode.class, "self");
+        nodeDefinedNames.put(org.jrubyparser.ast.NilNode.class, "nil");
+        nodeDefinedNames.put(org.jrubyparser.ast.TrueNode.class, "true");
+        nodeDefinedNames.put(org.jrubyparser.ast.FalseNode.class, "false");
+        nodeDefinedNames.put(org.jrubyparser.ast.LocalAsgnNode.class, "assignment");
+        nodeDefinedNames.put(org.jrubyparser.ast.DAsgnNode.class, "assignment");
+        nodeDefinedNames.put(org.jrubyparser.ast.GlobalAsgnNode.class, "assignment");
+        nodeDefinedNames.put(org.jrubyparser.ast.InstAsgnNode.class, "assignment");
+        nodeDefinedNames.put(org.jrubyparser.ast.ClassVarAsgnNode.class, "assignment");
+        nodeDefinedNames.put(org.jrubyparser.ast.OpAsgnAndNode.class, "assignment");
+        nodeDefinedNames.put(org.jrubyparser.ast.OpAsgnOrNode.class, "assignment");
+        nodeDefinedNames.put(org.jrubyparser.ast.OpAsgnNode.class, "assignment");
+        nodeDefinedNames.put(org.jrubyparser.ast.OpElementAsgnNode.class, "assignment");
+        nodeDefinedNames.put(org.jrubyparser.ast.MultipleAsgnNode.class, "assignment");
+        nodeDefinedNames.put(org.jrubyparser.ast.GlobalVarNode.class, "global-variable");
+        nodeDefinedNames.put(org.jrubyparser.ast.StrNode.class, "expression");
+        nodeDefinedNames.put(org.jrubyparser.ast.DStrNode.class, "expression");
+        nodeDefinedNames.put(org.jrubyparser.ast.FixnumNode.class, "expression");
+        nodeDefinedNames.put(org.jrubyparser.ast.BignumNode.class, "expression");
+        nodeDefinedNames.put(org.jrubyparser.ast.FloatNode.class, "expression");
+        nodeDefinedNames.put(org.jrubyparser.ast.RegexpNode.class, "expression");
+        nodeDefinedNames.put(org.jrubyparser.ast.DRegexpNode.class, "expression");
+        nodeDefinedNames.put(org.jrubyparser.ast.ArrayNode.class, "expression");
+        nodeDefinedNames.put(org.jrubyparser.ast.HashNode.class, "expression");
+        nodeDefinedNames.put(org.jrubyparser.ast.SymbolNode.class, "expression");
+        nodeDefinedNames.put(org.jrubyparser.ast.DotNode.class, "expression");
+        nodeDefinedNames.put(org.jrubyparser.ast.NotNode.class, "expression");
+        nodeDefinedNames.put(org.jrubyparser.ast.AndNode.class, "expression");
+        nodeDefinedNames.put(org.jrubyparser.ast.OrNode.class, "expression");
+        nodeDefinedNames.put(org.jrubyparser.ast.LocalVarNode.class, "local-variable");
+        nodeDefinedNames.put(org.jrubyparser.ast.DVarNode.class, "local-variable");
+    }
+
+    /**
+     * Global variables which in common usage have frame local semantics.
+     */
+    public static final Set<String> FRAME_LOCAL_GLOBAL_VARIABLES = new HashSet<>(Arrays.asList("$_"));
+
+    public Translator(RubyContext context, Translator parent, TranslatorEnvironment environment, Source source) {
+        this.context = context;
+        this.parent = parent;
+        this.environment = environment;
+        this.source = source;
+    }
+
+    @Override
+    public Object visitAliasNode(org.jrubyparser.ast.AliasNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        final org.jrubyparser.ast.LiteralNode oldName = (org.jrubyparser.ast.LiteralNode) node.getOldName();
+        final org.jrubyparser.ast.LiteralNode newName = (org.jrubyparser.ast.LiteralNode) node.getNewName();
+
+        final ClassNode classNode = new ClassNode(context, sourceSection, new SelfNode(context, sourceSection));
+
+        return new AliasNode(context, sourceSection, classNode, newName.getName(), oldName.getName());
+    }
+
+    @Override
+    public Object visitAndNode(org.jrubyparser.ast.AndNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        RubyNode x;
+
+        if (node.getFirst() == null) {
+            x = new NilNode(context, sourceSection);
+        } else {
+            x = (RubyNode) node.getFirst().accept(this);
+        }
+
+        RubyNode y;
+
+        if (node.getSecond() == null) {
+            y = new NilNode(context, sourceSection);
+        } else {
+            y = (RubyNode) node.getSecond().accept(this);
+        }
+
+        return AndNodeFactory.create(context, sourceSection, x, y);
+    }
+
+    @Override
+    public Object visitArgsCatNode(org.jrubyparser.ast.ArgsCatNode node) {
+        final List<org.jrubyparser.ast.Node> nodes = new ArrayList<>();
+        collectArgsCatNodes(nodes, node);
+
+        final List<RubyNode> translatedNodes = new ArrayList<>();
+
+        for (org.jrubyparser.ast.Node catNode : nodes) {
+            translatedNodes.add((RubyNode) catNode.accept(this));
+        }
+
+        return new ArrayConcatNode(context, translate(node.getPosition()), translatedNodes.toArray(new RubyNode[translatedNodes.size()]));
+    }
+
+    // ArgsCatNodes can be nested - this collects them into a flat list of children
+    private void collectArgsCatNodes(List<org.jrubyparser.ast.Node> nodes, org.jrubyparser.ast.ArgsCatNode node) {
+        if (node.getFirst() instanceof org.jrubyparser.ast.ArgsCatNode) {
+            collectArgsCatNodes(nodes, (org.jrubyparser.ast.ArgsCatNode) node.getFirst());
+        } else {
+            nodes.add(node.getFirst());
+        }
+
+        if (node.getSecond() instanceof org.jrubyparser.ast.ArgsCatNode) {
+            collectArgsCatNodes(nodes, (org.jrubyparser.ast.ArgsCatNode) node.getSecond());
+        } else {
+            nodes.add(node.getSecond());
+        }
+    }
+
+    @Override
+    public Object visitArgsNode(org.jrubyparser.ast.ArgsNode node) {
+        return unimplemented(node);
+    }
+
+    @Override
+    public Object visitArgsPushNode(org.jrubyparser.ast.ArgsPushNode node) {
+        return new ArrayPushNode(context, translate(node.getPosition()), (RubyNode) node.getFirstNode().accept(this), (RubyNode) node.getSecondNode().accept(this));
+    }
+
+    @Override
+    public Object visitArrayNode(org.jrubyparser.ast.ArrayNode node) {
+        final List<org.jrubyparser.ast.Node> values = node.childNodes();
+
+        final RubyNode[] translatedValues = new RubyNode[values.size()];
+
+        for (int n = 0; n < values.size(); n++) {
+            translatedValues[n] = (RubyNode) values.get(n).accept(this);
+        }
+
+        return new UninitialisedArrayLiteralNode(context, translate(node.getPosition()), translatedValues);
+    }
+
+    @Override
+    public Object visitAttrAssignNode(org.jrubyparser.ast.AttrAssignNode node) {
+        return visitAttrAssignNodeExtraArgument(node, null);
+    }
+
+    /**
+     * See translateDummyAssignment to understand what this is for.
+     */
+    public RubyNode visitAttrAssignNodeExtraArgument(org.jrubyparser.ast.AttrAssignNode node, RubyNode extraArgument) {
+        final org.jrubyparser.ast.CallNode callNode = new org.jrubyparser.ast.CallNode(node.getPosition(), node.getReceiver(), node.getName(), node.getArgs());
+        return visitCallNodeExtraArgument(callNode, extraArgument);
+    }
+
+    @Override
+    public Object visitBackRefNode(org.jrubyparser.ast.BackRefNode node) {
+        return unimplemented(node);
+    }
+
+    @Override
+    public Object visitBeginNode(org.jrubyparser.ast.BeginNode node) {
+        return node.getBody().accept(this);
+    }
+
+    @Override
+    public Object visitBignumNode(org.jrubyparser.ast.BignumNode node) {
+        return new BignumLiteralNode(context, translate(node.getPosition()), node.getValue());
+    }
+
+    @Override
+    public Object visitBlockArg18Node(org.jrubyparser.ast.BlockArg18Node node) {
+        return unimplemented(node);
+    }
+
+    @Override
+    public Object visitBlockArgNode(org.jrubyparser.ast.BlockArgNode node) {
+        return unimplemented(node);
+    }
+
+    @Override
+    public Object visitBlockNode(org.jrubyparser.ast.BlockNode node) {
+        final List<org.jrubyparser.ast.Node> children = node.childNodes();
+
+        final List<RubyNode> translatedChildren = new ArrayList<>();
+
+        for (int n = 0; n < children.size(); n++) {
+            final RubyNode translatedChild = (RubyNode) children.get(n).accept(this);
+
+            if (!(translatedChild instanceof DeadNode)) {
+                translatedChildren.add(translatedChild);
+            }
+        }
+
+        if (translatedChildren.size() == 1) {
+            return translatedChildren.get(0);
+        } else {
+            return new SequenceNode(context, translate(node.getPosition()), translatedChildren.toArray(new RubyNode[translatedChildren.size()]));
+        }
+    }
+
+    @Override
+    public Object visitBlockPassNode(org.jrubyparser.ast.BlockPassNode node) {
+        return unimplemented(node);
+    }
+
+    @Override
+    public Object visitBreakNode(org.jrubyparser.ast.BreakNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        RubyNode resultNode;
+
+        if (node.getValueNode() == null) {
+            resultNode = new NilNode(context, sourceSection);
+        } else {
+            resultNode = (RubyNode) node.getValueNode().accept(this);
+        }
+
+        return new BreakNode(context, sourceSection, resultNode);
+    }
+
+    @Override
+    public Object visitCallNode(org.jrubyparser.ast.CallNode node) {
+        return visitCallNodeExtraArgument(node, null);
+    }
+
+    /**
+     * See translateDummyAssignment to understand what this is for.
+     */
+    public RubyNode visitCallNodeExtraArgument(org.jrubyparser.ast.CallNode node, RubyNode extraArgument) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        final RubyNode receiverTranslated = (RubyNode) node.getReceiver().accept(this);
+
+        org.jrubyparser.ast.Node args = node.getArgs();
+        org.jrubyparser.ast.Node block = node.getIter();
+
+        if (block == null && args instanceof org.jrubyparser.ast.IterNode) {
+            final org.jrubyparser.ast.Node temp = args;
+            args = block;
+            block = temp;
+        }
+
+        final ArgumentsAndBlockTranslation argumentsAndBlock = translateArgumentsAndBlock(sourceSection, block, args, extraArgument);
+
+        return new CallNode(context, sourceSection, node.getName(), receiverTranslated, argumentsAndBlock.getBlock(), argumentsAndBlock.isSplatted(), argumentsAndBlock.getArguments());
+    }
+
+    protected class ArgumentsAndBlockTranslation {
+
+        private final RubyNode block;
+        private final RubyNode[] arguments;
+        private final boolean isSplatted;
+
+        public ArgumentsAndBlockTranslation(RubyNode block, RubyNode[] arguments, boolean isSplatted) {
+            super();
+            this.block = block;
+            this.arguments = arguments;
+            this.isSplatted = isSplatted;
+        }
+
+        public RubyNode getBlock() {
+            return block;
+        }
+
+        public RubyNode[] getArguments() {
+            return arguments;
+        }
+
+        public boolean isSplatted() {
+            return isSplatted;
+        }
+
+    }
+
+    protected ArgumentsAndBlockTranslation translateArgumentsAndBlock(SourceSection sourceSection, org.jrubyparser.ast.Node iterNode, org.jrubyparser.ast.Node argsNode, RubyNode extraArgument) {
+        assert !(argsNode instanceof org.jrubyparser.ast.IterNode);
+
+        final List<org.jrubyparser.ast.Node> arguments = new ArrayList<>();
+        org.jrubyparser.ast.Node blockPassNode = null;
+
+        boolean isSplatted = false;
+
+        if (argsNode instanceof org.jrubyparser.ast.ListNode) {
+            arguments.addAll(((org.jrubyparser.ast.ListNode) argsNode).childNodes());
+        } else if (argsNode instanceof org.jrubyparser.ast.BlockPassNode) {
+            final org.jrubyparser.ast.BlockPassNode blockPass = (org.jrubyparser.ast.BlockPassNode) argsNode;
+
+            final org.jrubyparser.ast.Node blockPassArgs = blockPass.getArgs();
+
+            if (blockPassArgs instanceof org.jrubyparser.ast.ListNode) {
+                arguments.addAll(((org.jrubyparser.ast.ListNode) blockPassArgs).childNodes());
+            } else if (blockPassArgs instanceof org.jrubyparser.ast.ArgsCatNode) {
+                arguments.add(blockPassArgs);
+            } else if (blockPassArgs != null) {
+                throw new UnsupportedOperationException("Don't know how to block pass " + blockPassArgs);
+            }
+
+            blockPassNode = blockPass.getBody();
+        } else if (argsNode instanceof org.jrubyparser.ast.SplatNode) {
+            isSplatted = true;
+            arguments.add(argsNode);
+        } else if (argsNode instanceof org.jrubyparser.ast.ArgsCatNode) {
+            isSplatted = true;
+            arguments.add(argsNode);
+        } else if (argsNode != null) {
+            isSplatted = true;
+            arguments.add(argsNode);
+        }
+
+        RubyNode blockTranslated;
+
+        if (blockPassNode != null && iterNode != null) {
+            throw new UnsupportedOperationException("Don't know how to pass both an block and a block-pass argument");
+        } else if (iterNode != null) {
+            blockTranslated = (BlockDefinitionNode) iterNode.accept(this);
+        } else if (blockPassNode != null) {
+            blockTranslated = ProcCastNodeFactory.create(context, sourceSection, (RubyNode) blockPassNode.accept(this));
+        } else {
+            blockTranslated = null;
+        }
+
+        final List<RubyNode> argumentsTranslated = new ArrayList<>();
+
+        for (org.jrubyparser.ast.Node argument : arguments) {
+            argumentsTranslated.add((RubyNode) argument.accept(this));
+        }
+
+        if (extraArgument != null) {
+            argumentsTranslated.add(extraArgument);
+        }
+
+        final RubyNode[] argumentsTranslatedArray = argumentsTranslated.toArray(new RubyNode[argumentsTranslated.size()]);
+
+        return new ArgumentsAndBlockTranslation(blockTranslated, argumentsTranslatedArray, isSplatted);
+    }
+
+    @Override
+    public Object visitCaseNode(org.jrubyparser.ast.CaseNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        RubyNode elseNode;
+
+        if (node.getElse() != null) {
+            elseNode = (RubyNode) node.getElse().accept(this);
+        } else {
+            elseNode = new NilNode(context, sourceSection);
+        }
+
+        /*
+         * There are two sorts of case - one compares a list of expressions against a value, the
+         * other just checks a list of expressions for truth.
+         */
+
+        if (node.getCase() != null) {
+            // Evaluate the case expression and store it in a local
+
+            final String tempName = environment.allocateLocalTemp();
+
+            final RubyNode readTemp = environment.findLocalVarNode(tempName, sourceSection);
+
+            final RubyNode assignTemp = ((ReadNode) readTemp).makeWriteNode((RubyNode) node.getCase().accept(this));
+
+            /*
+             * Build an if expression from the whens and else. Work backwards because the first if
+             * contains all the others in its else clause.
+             */
+
+            for (int n = node.getCases().size() - 1; n >= 0; n--) {
+                final org.jrubyparser.ast.WhenNode when = (org.jrubyparser.ast.WhenNode) node.getCases().get(n);
+
+                // Make a condition from the one or more expressions combined in an or expression
+
+                final List<org.jrubyparser.ast.Node> expressions;
+
+                if (when.getExpression() instanceof org.jrubyparser.ast.ListNode) {
+                    expressions = ((org.jrubyparser.ast.ListNode) when.getExpression()).childNodes();
+                } else {
+                    expressions = Arrays.asList(when.getExpression());
+                }
+
+                final List<RubyNode> comparisons = new ArrayList<>();
+
+                for (org.jrubyparser.ast.Node expressionNode : expressions) {
+                    final RubyNode rubyExpression = (RubyNode) expressionNode.accept(this);
+
+                    final CallNode comparison = new CallNode(context, sourceSection, "===", rubyExpression, null, false, new RubyNode[]{environment.findLocalVarNode(tempName, sourceSection)});
+
+                    comparisons.add(comparison);
+                }
+
+                RubyNode conditionNode = comparisons.get(comparisons.size() - 1);
+
+                // As with the if nodes, we work backwards to make it left associative
+
+                for (int i = comparisons.size() - 2; i >= 0; i--) {
+                    conditionNode = OrNodeFactory.create(context, sourceSection, comparisons.get(i), conditionNode);
+                }
+
+                // Create the if node
+
+                final BooleanCastNode conditionCastNode = BooleanCastNodeFactory.create(context, sourceSection, conditionNode);
+
+                RubyNode thenNode;
+
+                if (when.getBody() == null) {
+                    thenNode = new NilNode(context, sourceSection);
+                } else {
+                    thenNode = (RubyNode) when.getBody().accept(this);
+                }
+
+                final IfNode ifNode = new IfNode(context, sourceSection, conditionCastNode, thenNode, elseNode);
+
+                // This if becomes the else for the next if
+
+                elseNode = ifNode;
+            }
+
+            final RubyNode ifNode = elseNode;
+
+            // A top-level block assigns the temp then runs the if
+
+            return new SequenceNode(context, sourceSection, assignTemp, ifNode);
+        } else {
+            for (int n = node.getCases().size() - 1; n >= 0; n--) {
+                final org.jrubyparser.ast.WhenNode when = (org.jrubyparser.ast.WhenNode) node.getCases().get(n);
+
+                // Make a condition from the one or more expressions combined in an or expression
+
+                final List<org.jrubyparser.ast.Node> expressions;
+
+                if (when.getExpression() instanceof org.jrubyparser.ast.ListNode) {
+                    expressions = ((org.jrubyparser.ast.ListNode) when.getExpression()).childNodes();
+                } else {
+                    expressions = Arrays.asList(when.getExpression());
+                }
+
+                final List<RubyNode> tests = new ArrayList<>();
+
+                for (org.jrubyparser.ast.Node expressionNode : expressions) {
+                    final RubyNode rubyExpression = (RubyNode) expressionNode.accept(this);
+                    tests.add(rubyExpression);
+                }
+
+                RubyNode conditionNode = tests.get(tests.size() - 1);
+
+                // As with the if nodes, we work backwards to make it left associative
+
+                for (int i = tests.size() - 2; i >= 0; i--) {
+                    conditionNode = OrNodeFactory.create(context, sourceSection, tests.get(i), conditionNode);
+                }
+
+                // Create the if node
+
+                final BooleanCastNode conditionCastNode = BooleanCastNodeFactory.create(context, sourceSection, conditionNode);
+
+                final RubyNode thenNode = (RubyNode) when.getBody().accept(this);
+
+                final IfNode ifNode = new IfNode(context, sourceSection, conditionCastNode, thenNode, elseNode);
+
+                // This if becomes the else for the next if
+
+                elseNode = ifNode;
+            }
+
+            return elseNode;
+        }
+    }
+
+    @Override
+    public Object visitClassNode(org.jrubyparser.ast.ClassNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        final String name = node.getCPath().getName();
+
+        final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(context, environment, environment.getParser(), environment.getParser().allocateReturnID(), true, true,
+                        new UniqueMethodIdentifier());
+        final ModuleTranslator classTranslator = new ModuleTranslator(context, this, newEnvironment, source);
+
+        final MethodDefinitionNode definitionMethod = classTranslator.compileClassNode(node.getPosition(), node.getCPath().getName(), node.getBody());
+
+        /*
+         * See my note in visitDefnNode about where the class gets defined - the same applies here.
+         */
+
+        RubyNode superClass;
+
+        if (node.getSuper() != null) {
+            superClass = (RubyNode) node.getSuper().accept(this);
+        } else {
+            superClass = new ObjectLiteralNode(context, sourceSection, context.getCoreLibrary().getObjectClass());
+        }
+
+        final DefineOrGetClassNode defineOrGetClass = new DefineOrGetClassNode(context, sourceSection, name, getModuleToDefineModulesIn(sourceSection), superClass);
+
+        return new OpenModuleNode(context, sourceSection, defineOrGetClass, definitionMethod);
+    }
+
+    protected RubyNode getModuleToDefineModulesIn(SourceSection sourceSection) {
+        return new ClassNode(context, sourceSection, new SelfNode(context, sourceSection));
+    }
+
+    @Override
+    public Object visitClassVarAsgnNode(org.jrubyparser.ast.ClassVarAsgnNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        final RubyNode receiver = new ClassNode(context, sourceSection, new SelfNode(context, sourceSection));
+
+        final RubyNode rhs = (RubyNode) node.getValue().accept(this);
+
+        return new WriteClassVariableNode(context, sourceSection, node.getName(), receiver, rhs);
+    }
+
+    @Override
+    public Object visitClassVarDeclNode(org.jrubyparser.ast.ClassVarDeclNode node) {
+        return unimplemented(node);
+    }
+
+    @Override
+    public Object visitClassVarNode(org.jrubyparser.ast.ClassVarNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+        return new ReadClassVariableNode(context, sourceSection, node.getName(), new SelfNode(context, sourceSection));
+    }
+
+    @Override
+    public Object visitColon2Node(org.jrubyparser.ast.Colon2Node node) {
+        final RubyNode lhs = (RubyNode) node.getLeftNode().accept(this);
+
+        return new UninitializedReadConstantNode(context, translate(node.getPosition()), node.getName(), lhs);
+    }
+
+    @Override
+    public Object visitColon3Node(org.jrubyparser.ast.Colon3Node node) {
+        // Colon3 means the root namespace, as in ::Foo
+
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        final ObjectLiteralNode root = new ObjectLiteralNode(context, sourceSection, context.getCoreLibrary().getMainObject());
+
+        return new UninitializedReadConstantNode(context, sourceSection, node.getName(), root);
+    }
+
+    @Override
+    public Object visitConstDeclNode(org.jrubyparser.ast.ConstDeclNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        final ClassNode classNode = new ClassNode(context, sourceSection, new SelfNode(context, sourceSection));
+
+        return new WriteConstantNode(context, sourceSection, node.getName(), classNode, (RubyNode) node.getValue().accept(this));
+    }
+
+    @Override
+    public Object visitConstNode(org.jrubyparser.ast.ConstNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        return new UninitializedReadConstantNode(context, sourceSection, node.getName(), new SelfNode(context, sourceSection));
+    }
+
+    @Override
+    public Object visitDAsgnNode(org.jrubyparser.ast.DAsgnNode node) {
+        return new org.jrubyparser.ast.LocalAsgnNode(node.getPosition(), node.getName(), node.getDepth(), node.getValue()).accept(this);
+    }
+
+    @Override
+    public Object visitDRegxNode(org.jrubyparser.ast.DRegexpNode node) {
+        SourceSection sourceSection = translate(node.getPosition());
+
+        final RubyNode stringNode = translateInterpolatedString(sourceSection, node.childNodes());
+
+        return StringToRegexpNodeFactory.create(context, sourceSection, stringNode);
+    }
+
+    @Override
+    public Object visitDStrNode(org.jrubyparser.ast.DStrNode node) {
+        return translateInterpolatedString(translate(node.getPosition()), node.childNodes());
+    }
+
+    @Override
+    public Object visitDSymbolNode(org.jrubyparser.ast.DSymbolNode node) {
+        SourceSection sourceSection = translate(node.getPosition());
+
+        final RubyNode stringNode = translateInterpolatedString(sourceSection, node.childNodes());
+
+        return StringToSymbolNodeFactory.create(context, sourceSection, stringNode);
+    }
+
+    private RubyNode translateInterpolatedString(SourceSection sourceSection, List<org.jrubyparser.ast.Node> childNodes) {
+        final List<RubyNode> children = new ArrayList<>();
+
+        for (org.jrubyparser.ast.Node child : childNodes) {
+            children.add((RubyNode) child.accept(this));
+        }
+
+        return new InterpolatedStringNode(context, sourceSection, children.toArray(new RubyNode[children.size()]));
+    }
+
+    @Override
+    public Object visitDVarNode(org.jrubyparser.ast.DVarNode node) {
+        RubyNode readNode = environment.findLocalVarNode(node.getName(), translate(node.getPosition()));
+
+        if (readNode == null) {
+            context.implementationMessage("can't find variable %s at %s, using noop", node.getName(), node.getPosition());
+            readNode = new NilNode(context, translate(node.getPosition()));
+        }
+
+        return readNode;
+    }
+
+    @Override
+    public Object visitDXStrNode(org.jrubyparser.ast.DXStrNode node) {
+        SourceSection sourceSection = translate(node.getPosition());
+
+        final RubyNode string = translateInterpolatedString(sourceSection, node.childNodes());
+
+        return new SystemNode(context, sourceSection, string);
+    }
+
+    @Override
+    public Object visitDefinedNode(org.jrubyparser.ast.DefinedNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        org.jrubyparser.ast.Node expressionNode = node.getExpression();
+
+        while (expressionNode instanceof org.jrubyparser.ast.NewlineNode) {
+            expressionNode = ((org.jrubyparser.ast.NewlineNode) expressionNode).getNextNode();
+        }
+
+        final String name = nodeDefinedNames.get(expressionNode.getClass());
+
+        if (name != null) {
+            final StringLiteralNode literal = new StringLiteralNode(context, sourceSection, name);
+            return literal;
+        }
+
+        return new DefinedNode(context, sourceSection, (RubyNode) node.getExpression().accept(this));
+    }
+
+    @Override
+    public Object visitDefnNode(org.jrubyparser.ast.DefnNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+        final ClassNode classNode = new ClassNode(context, sourceSection, new SelfNode(context, sourceSection));
+        return translateMethodDefinition(sourceSection, classNode, node.getName(), node.getArgs(), node.getBody());
+    }
+
+    @Override
+    public Object visitDefsNode(org.jrubyparser.ast.DefsNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        final RubyNode objectNode = (RubyNode) node.getReceiver().accept(this);
+
+        final SingletonClassNode singletonClassNode = new SingletonClassNode(context, sourceSection, objectNode);
+
+        return translateMethodDefinition(sourceSection, singletonClassNode, node.getName(), node.getArgs(), node.getBody());
+    }
+
+    private RubyNode translateMethodDefinition(SourceSection sourceSection, RubyNode classNode, String methodName, org.jrubyparser.ast.ArgsNode argsNode, org.jrubyparser.ast.Node bodyNode) {
+        final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(context, environment, environment.getParser(), environment.getParser().allocateReturnID(), true, true,
+                        new UniqueMethodIdentifier());
+
+        // ownScopeForAssignments is the same for the defined method as the current one.
+
+        final MethodTranslator methodCompiler = new MethodTranslator(context, this, newEnvironment, false, source);
+
+        final MethodDefinitionNode functionExprNode = methodCompiler.compileFunctionNode(sourceSection, methodName, argsNode, bodyNode);
+
+        /*
+         * In the top-level, methods are defined in the class of the main object. This is
+         * counter-intuitive - I would have expected them to be defined in the singleton class.
+         * Apparently this is a design decision to make top-level methods sort of global.
+         * 
+         * http://stackoverflow.com/questions/1761148/where-are-methods-defined-at-the-ruby-top-level
+         */
+
+        return new AddMethodNode(context, sourceSection, classNode, functionExprNode);
+    }
+
+    @Override
+    public Object visitDotNode(org.jrubyparser.ast.DotNode node) {
+        final RubyNode begin = (RubyNode) node.getBegin().accept(this);
+        final RubyNode end = (RubyNode) node.getEnd().accept(this);
+        SourceSection sourceSection = translate(node.getPosition());
+
+        if (begin instanceof FixnumLiteralNode && end instanceof FixnumLiteralNode) {
+            final int beginValue = ((FixnumLiteralNode) begin).getValue();
+            final int endValue = ((FixnumLiteralNode) end).getValue();
+
+            return new ObjectLiteralNode(context, sourceSection, new FixnumRange(context.getCoreLibrary().getRangeClass(), beginValue, endValue, node.isExclusive()));
+        }
+        // See RangeNode for why there is a node specifically for creating this one type
+        return RangeLiteralNodeFactory.create(context, sourceSection, node.isExclusive(), begin, end);
+    }
+
+    @Override
+    public Object visitEncodingNode(org.jrubyparser.ast.EncodingNode node) {
+        return unimplemented(node);
+    }
+
+    @Override
+    public Object visitEnsureNode(org.jrubyparser.ast.EnsureNode node) {
+        final RubyNode tryPart = (RubyNode) node.getBody().accept(this);
+        final RubyNode ensurePart = (RubyNode) node.getEnsure().accept(this);
+        return new EnsureNode(context, translate(node.getPosition()), tryPart, ensurePart);
+    }
+
+    @Override
+    public Object visitEvStrNode(org.jrubyparser.ast.EvStrNode node) {
+        return node.getBody().accept(this);
+    }
+
+    @Override
+    public Object visitFCallNode(org.jrubyparser.ast.FCallNode node) {
+        final org.jrubyparser.ast.Node receiver = new org.jrubyparser.ast.SelfNode(node.getPosition());
+        final org.jrubyparser.ast.Node callNode = new org.jrubyparser.ast.CallNode(node.getPosition(), receiver, node.getName(), node.getArgs(), node.getIter());
+
+        return callNode.accept(this);
+    }
+
+    @Override
+    public Object visitFalseNode(org.jrubyparser.ast.FalseNode node) {
+        return new BooleanLiteralNode(context, translate(node.getPosition()), false);
+    }
+
+    @Override
+    public Object visitFixnumNode(org.jrubyparser.ast.FixnumNode node) {
+        final long value = node.getValue();
+
+        if (value >= RubyFixnum.MIN_VALUE && value <= RubyFixnum.MAX_VALUE) {
+            return new FixnumLiteralNode(context, translate(node.getPosition()), (int) value);
+        }
+        return new BignumLiteralNode(context, translate(node.getPosition()), BigInteger.valueOf(value));
+    }
+
+    @Override
+    public Object visitFlipNode(org.jrubyparser.ast.FlipNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        final RubyNode begin = (RubyNode) node.getBegin().accept(this);
+        final RubyNode end = (RubyNode) node.getEnd().accept(this);
+
+        final BooleanCastNode beginCast = BooleanCastNodeFactory.create(context, sourceSection, begin);
+        final BooleanCastNode endCast = BooleanCastNodeFactory.create(context, sourceSection, end);
+        final FlipFlopStateNode stateNode = createFlipFlopState(sourceSection, 0);
+
+        return new FlipFlopNode(context, sourceSection, beginCast, endCast, stateNode, node.isExclusive());
+    }
+
+    protected FlipFlopStateNode createFlipFlopState(SourceSection sourceSection, int depth) {
+        final FrameSlot frameSlot = environment.declareVar(environment.allocateLocalTemp());
+        environment.getFlipFlopStates().add(frameSlot);
+
+        if (depth == 0) {
+            return new LocalFlipFlopStateNode(sourceSection, frameSlot);
+        } else {
+            return new LevelFlipFlopStateNode(sourceSection, depth, frameSlot);
+        }
+    }
+
+    @Override
+    public Object visitFloatNode(org.jrubyparser.ast.FloatNode node) {
+        return new FloatLiteralNode(context, translate(node.getPosition()), node.getValue());
+    }
+
+    @Override
+    public Object visitForNode(org.jrubyparser.ast.ForNode node) {
+        /**
+         * A Ruby for-loop, such as:
+         * 
+         * <pre>
+         * for x in y
+         *     z = x
+         *     puts z
+         * end
+         * </pre>
+         * 
+         * naively desugars to:
+         * 
+         * <pre>
+         * y.each do |x|
+         *     z = x
+         *     puts z
+         * end
+         * </pre>
+         * 
+         * The main difference is that z is always going to be local to the scope outside the block,
+         * so it's a bit more like:
+         * 
+         * <pre>
+         * z = nil unless z is already defined
+         * y.each do |x|
+         *    z = x
+         *    puts x
+         * end
+         * </pre>
+         * 
+         * Which forces z to be defined in the correct scope. The parser already correctly calls z a
+         * local, but then that causes us a problem as if we're going to translate to a block we
+         * need a formal parameter - not a local variable. My solution to this is to add a
+         * temporary:
+         * 
+         * <pre>
+         * z = nil unless z is already defined
+         * y.each do |temp|
+         *    x = temp
+         *    z = x
+         *    puts x
+         * end
+         * </pre>
+         * 
+         * We also need that temp because the expression assigned in the for could be index
+         * assignment, multiple assignment, or whatever:
+         * 
+         * <pre>
+         * for x[0] in y
+         *     z = x[0]
+         *     puts z
+         * end
+         * </pre>
+         * 
+         * http://blog.grayproductions.net/articles/the_evils_of_the_for_loop
+         * http://stackoverflow.com/questions/3294509/for-vs-each-in-ruby
+         * 
+         * The other complication is that normal locals should be defined in the enclosing scope,
+         * unlike a normal block. We do that by setting a flag on this translator object when we
+         * visit the new iter, translatingForStatement, which we recognise when visiting an iter
+         * node.
+         * 
+         * Finally, note that JRuby's terminology is strange here. Normally 'iter' is a different
+         * term for a block. Here, JRuby calls the object being iterated over the 'iter'.
+         */
+
+        final String temp = environment.allocateLocalTemp();
+
+        final org.jrubyparser.ast.Node receiver = node.getIter();
+
+        /*
+         * The x in for x in ... is like the nodes in multiple assignment - it has a dummy RHS which
+         * we need to replace with our temp. Just like in multiple assignment this is really awkward
+         * with the JRuby AST.
+         */
+
+        final org.jrubyparser.ast.LocalVarNode readTemp = new org.jrubyparser.ast.LocalVarNode(node.getPosition(), 0, temp);
+        final org.jrubyparser.ast.Node forVar = node.getVar();
+        final org.jrubyparser.ast.Node assignTemp = setRHS(forVar, readTemp);
+
+        final org.jrubyparser.ast.BlockNode bodyWithTempAssign = new org.jrubyparser.ast.BlockNode(node.getPosition());
+        bodyWithTempAssign.add(assignTemp);
+        bodyWithTempAssign.add(node.getBody());
+
+        final org.jrubyparser.ast.ArgumentNode blockVar = new org.jrubyparser.ast.ArgumentNode(node.getPosition(), temp);
+        final org.jrubyparser.ast.ListNode blockArgsPre = new org.jrubyparser.ast.ListNode(node.getPosition(), blockVar);
+        final org.jrubyparser.ast.ArgsNode blockArgs = new org.jrubyparser.ast.ArgsNode(node.getPosition(), blockArgsPre, null, null, null, null, null, null);
+        final org.jrubyparser.ast.IterNode block = new org.jrubyparser.ast.IterNode(node.getPosition(), blockArgs, node.getScope(), bodyWithTempAssign);
+
+        final org.jrubyparser.ast.CallNode callNode = new org.jrubyparser.ast.CallNode(node.getPosition(), receiver, "each", null, block);
+
+        translatingForStatement = true;
+        final RubyNode translated = (RubyNode) callNode.accept(this);
+        translatingForStatement = false;
+
+        return translated;
+    }
+
+    private static org.jrubyparser.ast.Node setRHS(org.jrubyparser.ast.Node node, org.jrubyparser.ast.Node rhs) {
+        if (node instanceof org.jrubyparser.ast.LocalAsgnNode) {
+            final org.jrubyparser.ast.LocalAsgnNode localAsgnNode = (org.jrubyparser.ast.LocalAsgnNode) node;
+            return new org.jrubyparser.ast.LocalAsgnNode(node.getPosition(), localAsgnNode.getName(), 0, rhs);
+        } else if (node instanceof org.jrubyparser.ast.DAsgnNode) {
+            final org.jrubyparser.ast.DAsgnNode dAsgnNode = (org.jrubyparser.ast.DAsgnNode) node;
+            return new org.jrubyparser.ast.DAsgnNode(node.getPosition(), dAsgnNode.getName(), 0, rhs);
+        } else if (node instanceof org.jrubyparser.ast.MultipleAsgnNode) {
+            final org.jrubyparser.ast.MultipleAsgnNode multAsgnNode = (org.jrubyparser.ast.MultipleAsgnNode) node;
+            return new org.jrubyparser.ast.MultipleAsgnNode(node.getPosition(), multAsgnNode.getPre(), multAsgnNode.getRest(), multAsgnNode.getPost());
+        } else if (node instanceof org.jrubyparser.ast.InstAsgnNode) {
+            final org.jrubyparser.ast.InstAsgnNode instAsgnNode = (org.jrubyparser.ast.InstAsgnNode) node;
+            return new org.jrubyparser.ast.InstAsgnNode(node.getPosition(), instAsgnNode.getName(), rhs);
+        } else if (node instanceof org.jrubyparser.ast.ClassVarAsgnNode) {
+            final org.jrubyparser.ast.ClassVarAsgnNode instAsgnNode = (org.jrubyparser.ast.ClassVarAsgnNode) node;
+            return new org.jrubyparser.ast.ClassVarAsgnNode(node.getPosition(), instAsgnNode.getName(), rhs);
+        } else if (node instanceof org.jrubyparser.ast.ConstDeclNode) {
+            final org.jrubyparser.ast.ConstDeclNode constDeclNode = (org.jrubyparser.ast.ConstDeclNode) node;
+            return new org.jrubyparser.ast.ConstDeclNode(node.getPosition(), constDeclNode.getName(), (org.jrubyparser.ast.INameNode) constDeclNode.getConstNode(), rhs);
+        } else {
+            throw new UnsupportedOperationException("Don't know how to set the RHS of a " + node.getClass().getName());
+        }
+    }
+
+    @Override
+    public Object visitGlobalAsgnNode(org.jrubyparser.ast.GlobalAsgnNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        final String name = "$" + node.getName();
+        final RubyNode rhs = (RubyNode) node.getValue().accept(this);
+
+        if (FRAME_LOCAL_GLOBAL_VARIABLES.contains(name)) {
+            context.implementationMessage("Assigning to frame local global variables not implemented at %s", node.getPosition());
+
+            return rhs;
+        } else {
+            final ObjectLiteralNode globalVariablesObjectNode = new ObjectLiteralNode(context, sourceSection, context.getCoreLibrary().getGlobalVariablesObject());
+
+            return new UninitializedWriteInstanceVariableNode(context, sourceSection, name, globalVariablesObjectNode, rhs);
+        }
+    }
+
+    @Override
+    public Object visitGlobalVarNode(org.jrubyparser.ast.GlobalVarNode node) {
+        final String name = "$" + node.getName();
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        if (FRAME_LOCAL_GLOBAL_VARIABLES.contains(name)) {
+            // Assignment is implicit for many of these, so we need to declare when we use
+
+            environment.declareVar(name);
+
+            final RubyNode readNode = environment.findLocalVarNode(name, sourceSection);
+
+            return readNode;
+        } else {
+            final ObjectLiteralNode globalVariablesObjectNode = new ObjectLiteralNode(context, sourceSection, context.getCoreLibrary().getGlobalVariablesObject());
+
+            return new UninitializedReadInstanceVariableNode(context, sourceSection, name, globalVariablesObjectNode);
+        }
+    }
+
+    @Override
+    public Object visitHashNode(org.jrubyparser.ast.HashNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        final List<RubyNode> keys = new ArrayList<>();
+        final List<RubyNode> values = new ArrayList<>();
+
+        final org.jrubyparser.ast.ListNode entries = node.getListNode();
+
+        assert entries.size() % 2 == 0;
+
+        for (int n = 0; n < entries.size(); n += 2) {
+            if (entries.get(n) == null) {
+                final NilNode nilNode = new NilNode(context, sourceSection);
+                keys.add(nilNode);
+            } else {
+                keys.add((RubyNode) entries.get(n).accept(this));
+            }
+
+            if (entries.get(n + 1) == null) {
+                final NilNode nilNode = new NilNode(context, sourceSection);
+                values.add(nilNode);
+            } else {
+                values.add((RubyNode) entries.get(n + 1).accept(this));
+            }
+        }
+
+        return new HashLiteralNode(translate(node.getPosition()), keys.toArray(new RubyNode[keys.size()]), values.toArray(new RubyNode[values.size()]), context);
+    }
+
+    @Override
+    public Object visitIfNode(org.jrubyparser.ast.IfNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        org.jrubyparser.ast.Node thenBody = node.getThenBody();
+
+        if (thenBody == null) {
+            thenBody = new org.jrubyparser.ast.NilNode(node.getPosition());
+        }
+
+        org.jrubyparser.ast.Node elseBody = node.getElseBody();
+
+        if (elseBody == null) {
+            elseBody = new org.jrubyparser.ast.NilNode(node.getPosition());
+        }
+
+        RubyNode condition;
+
+        if (node.getCondition() == null) {
+            condition = new NilNode(context, sourceSection);
+        } else {
+            condition = (RubyNode) node.getCondition().accept(this);
+        }
+
+        final BooleanCastNode conditionCast = BooleanCastNodeFactory.create(context, sourceSection, condition);
+
+        final RubyNode thenBodyTranslated = (RubyNode) thenBody.accept(this);
+        final RubyNode elseBodyTranslated = (RubyNode) elseBody.accept(this);
+
+        return new IfNode(context, sourceSection, conditionCast, thenBodyTranslated, elseBodyTranslated);
+    }
+
+    @Override
+    public Object visitInstAsgnNode(org.jrubyparser.ast.InstAsgnNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+        final String nameWithoutSigil = node.getName();
+
+        final RubyNode receiver = new SelfNode(context, sourceSection);
+
+        RubyNode rhs;
+
+        if (node.getValue() == null) {
+            rhs = new DeadNode(context, sourceSection);
+        } else {
+            rhs = (RubyNode) node.getValue().accept(this);
+        }
+
+        return new UninitializedWriteInstanceVariableNode(context, sourceSection, nameWithoutSigil, receiver, rhs);
+    }
+
+    @Override
+    public Object visitInstVarNode(org.jrubyparser.ast.InstVarNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+        final String nameWithoutSigil = node.getName();
+
+        final RubyNode receiver = new SelfNode(context, sourceSection);
+
+        return new UninitializedReadInstanceVariableNode(context, sourceSection, nameWithoutSigil, receiver);
+    }
+
+    @Override
+    public Object visitIterNode(org.jrubyparser.ast.IterNode node) {
+        /*
+         * In a block we do NOT allocate a new return ID - returns will return from the method, not
+         * the block (in the general case, see Proc and the difference between Proc and Lambda for
+         * specifics).
+         */
+
+        final boolean hasOwnScope = !translatingForStatement;
+
+        // Unset this flag for any for any blocks within the for statement's body
+
+        translatingForStatement = false;
+
+        final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(context, environment, environment.getParser(), environment.getReturnID(), hasOwnScope, false,
+                        new UniqueMethodIdentifier());
+        final MethodTranslator methodCompiler = new MethodTranslator(context, this, newEnvironment, true, source);
+
+        org.jrubyparser.ast.ArgsNode argsNode;
+
+        if (node.getVar() instanceof org.jrubyparser.ast.ArgsNode) {
+            argsNode = (org.jrubyparser.ast.ArgsNode) node.getVar();
+        } else if (node.getVar() instanceof org.jrubyparser.ast.DAsgnNode) {
+            final org.jrubyparser.ast.ArgumentNode arg = new org.jrubyparser.ast.ArgumentNode(node.getPosition(), ((org.jrubyparser.ast.DAsgnNode) node.getVar()).getName());
+            final org.jrubyparser.ast.ListNode preArgs = new org.jrubyparser.ast.ArrayNode(node.getPosition(), arg);
+            argsNode = new org.jrubyparser.ast.ArgsNode(node.getPosition(), preArgs, null, null, null, null, null, null);
+        } else if (node.getVar() == null) {
+            argsNode = null;
+        } else {
+            throw new UnsupportedOperationException();
+        }
+
+        return methodCompiler.compileFunctionNode(translate(node.getPosition()), "(block)", argsNode, node.getBody());
+    }
+
+    @Override
+    public Object visitLiteralNode(org.jrubyparser.ast.LiteralNode node) {
+        return unimplemented(node);
+    }
+
+    @Override
+    public Object visitLocalAsgnNode(org.jrubyparser.ast.LocalAsgnNode node) {
+
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        if (environment.getNeverAssignInParentScope()) {
+            environment.declareVar(node.getName());
+        }
+
+        RubyNode lhs = environment.findLocalVarNode(node.getName(), sourceSection);
+
+        if (lhs == null) {
+            if (environment.hasOwnScopeForAssignments()) {
+                environment.declareVar(node.getName());
+            }
+
+            TranslatorEnvironment environmentToDeclareIn = environment;
+
+            while (!environmentToDeclareIn.hasOwnScopeForAssignments()) {
+                environmentToDeclareIn = environmentToDeclareIn.getParent();
+            }
+
+            environmentToDeclareIn.declareVar(node.getName());
+            lhs = environment.findLocalVarNode(node.getName(), sourceSection);
+
+            if (lhs == null) {
+                throw new RuntimeException("shoudln't be here");
+            }
+        }
+
+        RubyNode rhs;
+
+        if (node.getValue() == null) {
+            rhs = new DeadNode(context, sourceSection);
+        } else {
+            rhs = (RubyNode) node.getValue().accept(this);
+        }
+
+        RubyNode translated = ((ReadNode) lhs).makeWriteNode(rhs);
+
+        if (context.getConfiguration().getDebug()) {
+            final UniqueMethodIdentifier methodIdentifier = environment.findMethodForLocalVar(node.getName());
+
+            RubyProxyNode proxy;
+            if (translated instanceof RubyProxyNode) {
+                proxy = (RubyProxyNode) translated;
+            } else {
+                proxy = new RubyProxyNode(context, translated);
+            }
+            context.getDebugManager().registerLocalDebugProxy(methodIdentifier, node.getName(), proxy.getProbeChain());
+
+            translated = proxy;
+        }
+
+        return translated;
+    }
+
+    @Override
+    public Object visitLocalVarNode(org.jrubyparser.ast.LocalVarNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        final String name = node.getName();
+
+        RubyNode readNode = environment.findLocalVarNode(name, sourceSection);
+
+        if (readNode == null) {
+            context.implementationMessage("Local variable found by parser but not by translator - " + name + " at " + node.getPosition());
+            readNode = environment.findLocalVarNode(environment.allocateLocalTemp(), sourceSection);
+        }
+
+        return readNode;
+    }
+
+    @Override
+    public Object visitMatch2Node(org.jrubyparser.ast.Match2Node node) {
+        final org.jrubyparser.ast.Node argsNode = buildArrayNode(node.getPosition(), node.getValue());
+        final org.jrubyparser.ast.Node callNode = new org.jrubyparser.ast.CallNode(node.getPosition(), node.getReceiver(), "=~", argsNode, null);
+        return callNode.accept(this);
+    }
+
+    @Override
+    public Object visitMatch3Node(org.jrubyparser.ast.Match3Node node) {
+        final org.jrubyparser.ast.Node argsNode = buildArrayNode(node.getPosition(), node.getValue());
+        final org.jrubyparser.ast.Node callNode = new org.jrubyparser.ast.CallNode(node.getPosition(), node.getReceiver(), "=~", argsNode, null);
+        return callNode.accept(this);
+    }
+
+    @Override
+    public Object visitMatchNode(org.jrubyparser.ast.MatchNode node) {
+        return unimplemented(node);
+    }
+
+    @Override
+    public Object visitModuleNode(org.jrubyparser.ast.ModuleNode node) {
+        // See visitClassNode
+
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        final String name = node.getCPath().getName();
+
+        final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(context, environment, environment.getParser(), environment.getParser().allocateReturnID(), true, true,
+                        new UniqueMethodIdentifier());
+        final ModuleTranslator classTranslator = new ModuleTranslator(context, this, newEnvironment, source);
+
+        final MethodDefinitionNode definitionMethod = classTranslator.compileClassNode(node.getPosition(), node.getCPath().getName(), node.getBody());
+
+        final DefineOrGetModuleNode defineModuleNode = new DefineOrGetModuleNode(context, sourceSection, name, getModuleToDefineModulesIn(sourceSection));
+
+        return new OpenModuleNode(context, sourceSection, defineModuleNode, definitionMethod);
+    }
+
+    @Override
+    public Object visitMultipleAsgnNode(org.jrubyparser.ast.MultipleAsgnNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        final org.jrubyparser.ast.ArrayNode preArray = (org.jrubyparser.ast.ArrayNode) node.getPre();
+        final org.jrubyparser.ast.Node rhs = node.getValue();
+
+        RubyNode rhsTranslated;
+
+        if (rhs == null) {
+            context.implementationMessage("warning: no RHS for multiple assignment - using noop");
+            rhsTranslated = new NilNode(context, sourceSection);
+        } else {
+            rhsTranslated = (RubyNode) rhs.accept(this);
+        }
+
+        /*
+         * One very common case is to do
+         * 
+         * a, b = c, d
+         */
+
+        if (preArray != null && node.getPost() == null && node.getRest() == null && rhsTranslated instanceof UninitialisedArrayLiteralNode &&
+                        ((UninitialisedArrayLiteralNode) rhsTranslated).getValues().length == preArray.size()) {
+            /*
+             * We can deal with this common case be rewriting as
+             * 
+             * temp1 = c; temp2 = d; a = temp1; b = temp2
+             * 
+             * We can't just do
+             * 
+             * a = c; b = d
+             * 
+             * As we don't know if d depends on the original value of a.
+             * 
+             * We also need to return an array [c, d], but we make that result elidable so it isn't
+             * executed if it isn't actually demanded.
+             */
+
+            final RubyNode[] rhsValues = ((UninitialisedArrayLiteralNode) rhsTranslated).getValues();
+            final int assignedValuesCount = preArray.size();
+
+            final RubyNode[] sequence = new RubyNode[assignedValuesCount * 2];
+
+            final RubyNode[] tempValues = new RubyNode[assignedValuesCount];
+
+            for (int n = 0; n < assignedValuesCount; n++) {
+                final String tempName = environment.allocateLocalTemp();
+                final RubyNode readTemp = environment.findLocalVarNode(tempName, sourceSection);
+                final RubyNode assignTemp = ((ReadNode) readTemp).makeWriteNode(rhsValues[n]);
+                final RubyNode assignFinalValue = translateDummyAssignment(preArray.get(n), readTemp);
+
+                sequence[n] = assignTemp;
+                sequence[assignedValuesCount + n] = assignFinalValue;
+
+                tempValues[n] = readTemp;
+            }
+
+            final RubyNode blockNode = new SequenceNode(context, sourceSection, sequence);
+
+            final UninitialisedArrayLiteralNode arrayNode = new UninitialisedArrayLiteralNode(context, sourceSection, tempValues);
+
+            final ElidableResultNode elidableResult = new ElidableResultNode(context, sourceSection, blockNode, arrayNode);
+
+            return elidableResult;
+        } else if (preArray != null) {
+            /*
+             * The other simple case is
+             * 
+             * a, b, c = x
+             * 
+             * If x is an array, then it's
+             * 
+             * a[0] = x[0] etc
+             * 
+             * If x isn't an array then it's
+             * 
+             * a, b, c = [x, nil, nil]
+             * 
+             * Which I believe is the same effect as
+             * 
+             * a, b, c, = *x
+             * 
+             * So we insert the splat cast node, even though it isn't there.
+             */
+
+            /*
+             * Create a temp for the array.
+             */
+
+            final String tempName = environment.allocateLocalTemp();
+
+            /*
+             * Create a sequence of instructions, with the first being the literal array assigned to
+             * the temp.
+             */
+
+            final List<RubyNode> sequence = new ArrayList<>();
+
+            final RubyNode splatCastNode = SplatCastNodeFactory.create(context, sourceSection, rhsTranslated);
+
+            final RubyNode writeTemp = ((ReadNode) environment.findLocalVarNode(tempName, sourceSection)).makeWriteNode(splatCastNode);
+
+            sequence.add(writeTemp);
+
+            /*
+             * Then index the temp array for each assignment on the LHS.
+             */
+
+            for (int n = 0; n < preArray.size(); n++) {
+                final ArrayIndexNode assignedValue = ArrayIndexNodeFactory.create(context, sourceSection, n, environment.findLocalVarNode(tempName, sourceSection));
+
+                sequence.add(translateDummyAssignment(preArray.get(n), assignedValue));
+            }
+
+            if (node.getRest() != null) {
+                final ArrayRestNode assignedValue = new ArrayRestNode(context, sourceSection, preArray.size(), environment.findLocalVarNode(tempName, sourceSection));
+
+                sequence.add(translateDummyAssignment(node.getRest(), assignedValue));
+            }
+
+            return new SequenceNode(context, sourceSection, sequence.toArray(new RubyNode[sequence.size()]));
+        } else if (node.getPre() == null && node.getPost() == null && node.getRest() instanceof org.jrubyparser.ast.StarNode) {
+            return rhsTranslated;
+        } else if (node.getPre() == null && node.getPost() == null && node.getRest() != null && rhs != null && !(rhs instanceof org.jrubyparser.ast.ArrayNode)) {
+            /*
+             * *a = b
+             * 
+             * >= 1.8, this seems to be the same as:
+             * 
+             * a = *b
+             */
+
+            final RubyNode restTranslated = ((RubyNode) node.getRest().accept(this)).getNonProxyNode();
+
+            /*
+             * Sometimes rest is a corrupt write with no RHS, like in other multiple assignments,
+             * and sometimes it is already a read.
+             */
+
+            ReadNode restRead;
+
+            if (restTranslated instanceof ReadNode) {
+                restRead = (ReadNode) restTranslated;
+            } else if (restTranslated instanceof WriteNode) {
+                restRead = (ReadNode) ((WriteNode) restTranslated).makeReadNode();
+            } else {
+                throw new RuntimeException("Unknown form of multiple assignment " + node + " at " + node.getPosition());
+            }
+
+            final SplatCastNode rhsSplatCast = SplatCastNodeFactory.create(context, sourceSection, rhsTranslated);
+
+            return restRead.makeWriteNode(rhsSplatCast);
+        } else if (node.getPre() == null && node.getPost() == null && node.getRest() != null && rhs != null && rhs instanceof org.jrubyparser.ast.ArrayNode) {
+            /*
+             * *a = [b, c]
+             * 
+             * This seems to be the same as:
+             * 
+             * a = [b, c]
+             */
+
+            final RubyNode restTranslated = ((RubyNode) node.getRest().accept(this)).getNonProxyNode();
+
+            /*
+             * Sometimes rest is a corrupt write with no RHS, like in other multiple assignments,
+             * and sometimes it is already a read.
+             */
+
+            ReadNode restRead;
+
+            if (restTranslated instanceof ReadNode) {
+                restRead = (ReadNode) restTranslated;
+            } else if (restTranslated instanceof WriteNode) {
+                restRead = (ReadNode) ((WriteNode) restTranslated).makeReadNode();
+            } else {
+                throw new RuntimeException("Unknown form of multiple assignment " + node + " at " + node.getPosition());
+            }
+
+            return restRead.makeWriteNode(rhsTranslated);
+        } else {
+            throw new RuntimeException("Unknown form of multiple assignment " + node + " at " + node.getPosition());
+        }
+    }
+
+    private RubyNode translateDummyAssignment(org.jrubyparser.ast.Node dummyAssignment, RubyNode rhs) {
+        final SourceSection sourceSection = translate(dummyAssignment.getPosition());
+
+        /*
+         * This is tricky. To represent the RHS of a multiple assignment they use corrupt assignment
+         * values, in some cases with no value to be assigned, and in other cases with a dummy
+         * value. We can't visit them normally, as they're corrupt. We can't just modify them to
+         * have our RHS, as that's a node in our AST, not theirs. We can't use a dummy value in
+         * their AST because I can't add new visitors to this interface.
+         */
+
+        RubyNode translated;
+
+        if (dummyAssignment instanceof org.jrubyparser.ast.LocalAsgnNode) {
+            /*
+             * They have a dummy NilImplicitNode as the RHS. Translate, convert to read, convert to
+             * write which allows us to set the RHS.
+             */
+
+            final WriteNode dummyTranslated = (WriteNode) ((RubyNode) dummyAssignment.accept(this)).getNonProxyNode();
+            translated = ((ReadNode) dummyTranslated.makeReadNode()).makeWriteNode(rhs);
+        } else if (dummyAssignment instanceof org.jrubyparser.ast.InstAsgnNode) {
+            /*
+             * Same as before, just a different type of assignment.
+             */
+
+            final WriteInstanceVariableNode dummyTranslated = (WriteInstanceVariableNode) dummyAssignment.accept(this);
+            translated = dummyTranslated.makeReadNode().makeWriteNode(rhs);
+        } else if (dummyAssignment instanceof org.jrubyparser.ast.AttrAssignNode) {
+            /*
+             * They've given us an AttrAssignNode with the final argument, the assigned value,
+             * missing. If we translate that we'll get foo.[]=(index), so missing the value. To
+             * solve we have a special version of the visitCallNode that allows us to pass another
+             * already translated argument, visitCallNodeExtraArgument. However, we initially have
+             * an AttrAssignNode, so we also need a special version of that.
+             */
+
+            final org.jrubyparser.ast.AttrAssignNode dummyAttrAssignment = (org.jrubyparser.ast.AttrAssignNode) dummyAssignment;
+            translated = visitAttrAssignNodeExtraArgument(dummyAttrAssignment, rhs);
+        } else if (dummyAssignment instanceof org.jrubyparser.ast.DAsgnNode) {
+            final RubyNode dummyTranslated = (RubyNode) dummyAssignment.accept(this);
+
+            if (dummyTranslated.getNonProxyNode() instanceof WriteLevelVariableNode) {
+                translated = ((ReadNode) ((WriteLevelVariableNode) dummyTranslated.getNonProxyNode()).makeReadNode()).makeWriteNode(rhs);
+            } else {
+                translated = ((ReadNode) ((WriteLocalVariableNode) dummyTranslated.getNonProxyNode()).makeReadNode()).makeWriteNode(rhs);
+            }
+        } else {
+            translated = ((ReadNode) environment.findLocalVarNode(environment.allocateLocalTemp(), sourceSection)).makeWriteNode(rhs);
+        }
+
+        return translated;
+    }
+
+    @Override
+    public Object visitNewlineNode(org.jrubyparser.ast.NewlineNode node) {
+        RubyNode translated = (RubyNode) node.getNextNode().accept(this);
+
+        if (context.getConfiguration().getDebug()) {
+
+            RubyProxyNode proxy;
+            SourceSection sourceSection;
+            if (translated instanceof RubyProxyNode) {
+                proxy = (RubyProxyNode) translated;
+                sourceSection = proxy.getChild().getSourceSection();
+            } else {
+                proxy = new RubyProxyNode(context, translated);
+                sourceSection = translated.getSourceSection();
+            }
+            context.getDebugManager().registerProbeChain(sourceSection, proxy.getProbeChain());
+            translated = proxy;
+        }
+
+        if (context.getConfiguration().getTrace()) {
+            RubyProxyNode proxy;
+            if (translated instanceof RubyProxyNode) {
+                proxy = (RubyProxyNode) translated;
+            } else {
+                proxy = new RubyProxyNode(context, translated);
+            }
+            proxy.getProbeChain().appendProbe(new RubyTraceProbe(context));
+
+            translated = proxy;
+        }
+
+        return translated;
+    }
+
+    @Override
+    public Object visitNextNode(org.jrubyparser.ast.NextNode node) {
+        return new NextNode(context, translate(node.getPosition()));
+    }
+
+    @Override
+    public Object visitNilNode(org.jrubyparser.ast.NilNode node) {
+        return new NilNode(context, translate(node.getPosition()));
+    }
+
+    @Override
+    public Object visitNotNode(org.jrubyparser.ast.NotNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        final BooleanCastNode booleanCastNode = BooleanCastNodeFactory.create(context, sourceSection, (RubyNode) node.getCondition().accept(this));
+
+        return new NotNode(context, sourceSection, booleanCastNode);
+    }
+
+    @Override
+    public Object visitNthRefNode(org.jrubyparser.ast.NthRefNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        final String name = "$" + node.getMatchNumber();
+
+        RubyNode readLocal = environment.findLocalVarNode(name, sourceSection);
+
+        if (readLocal == null) {
+            environment.declareVar(name);
+            readLocal = environment.findLocalVarNode(name, sourceSection);
+        }
+
+        return readLocal;
+    }
+
+    @Override
+    public Object visitOpAsgnAndNode(org.jrubyparser.ast.OpAsgnAndNode node) {
+        final org.jrubyparser.ast.Node lhs = node.getFirst();
+        final org.jrubyparser.ast.Node rhs = node.getSecond();
+
+        return AndNodeFactory.create(context, translate(node.getPosition()), (RubyNode) lhs.accept(this), (RubyNode) rhs.accept(this));
+    }
+
+    @Override
+    public Object visitOpAsgnNode(org.jrubyparser.ast.OpAsgnNode node) {
+        /*
+         * We're going to de-sugar a.foo += c into a.foo = a.foo + c. Note that we can't evaluate a
+         * more than once, so we put it into a temporary, and we're doing something more like:
+         * 
+         * temp = a; temp.foo = temp.foo + c
+         */
+
+        final String temp = environment.allocateLocalTemp();
+        final org.jrubyparser.ast.Node writeReceiverToTemp = new org.jrubyparser.ast.LocalAsgnNode(node.getPosition(), temp, 0, node.getReceiver());
+        final org.jrubyparser.ast.Node readReceiverFromTemp = new org.jrubyparser.ast.LocalVarNode(node.getPosition(), 0, temp);
+
+        final org.jrubyparser.ast.Node readMethod = new org.jrubyparser.ast.CallNode(node.getPosition(), readReceiverFromTemp, node.getVariableName(), null);
+        final org.jrubyparser.ast.Node operation = new org.jrubyparser.ast.CallNode(node.getPosition(), readMethod, node.getOperatorName(), buildArrayNode(node.getPosition(), node.getValue()));
+        final org.jrubyparser.ast.Node writeMethod = new org.jrubyparser.ast.CallNode(node.getPosition(), readReceiverFromTemp, node.getVariableName() + "=", buildArrayNode(node.getPosition(),
+                        operation));
+
+        final org.jrubyparser.ast.BlockNode block = new org.jrubyparser.ast.BlockNode(node.getPosition());
+        block.add(writeReceiverToTemp);
+        block.add(writeMethod);
+
+        return block.accept(this);
+    }
+
+    @Override
+    public Object visitOpAsgnOrNode(org.jrubyparser.ast.OpAsgnOrNode node) {
+        /*
+         * De-sugar x ||= y into x || x = y. No repeated evaluations there so it's easy. It's also
+         * basically how jruby-parser represents it already. We'll do it directly, rather than via
+         * another JRuby AST node.
+         */
+
+        final org.jrubyparser.ast.Node lhs = node.getFirst();
+        final org.jrubyparser.ast.Node rhs = node.getSecond();
+
+        return OrNodeFactory.create(context, translate(node.getPosition()), (RubyNode) lhs.accept(this), (RubyNode) rhs.accept(this));
+    }
+
+    @Override
+    public Object visitOpElementAsgnNode(org.jrubyparser.ast.OpElementAsgnNode node) {
+        /*
+         * We're going to de-sugar a[b] += c into a[b] = a[b] + c. See discussion in
+         * visitOpAsgnNode.
+         */
+
+        org.jrubyparser.ast.Node index;
+
+        if (node.getArgs() == null) {
+            index = null;
+        } else {
+            index = node.getArgs().childNodes().get(0);
+        }
+
+        final org.jrubyparser.ast.Node operand = node.getValue();
+
+        final String temp = environment.allocateLocalTemp();
+        final org.jrubyparser.ast.Node writeArrayToTemp = new org.jrubyparser.ast.LocalAsgnNode(node.getPosition(), temp, 0, node.getReceiver());
+        final org.jrubyparser.ast.Node readArrayFromTemp = new org.jrubyparser.ast.LocalVarNode(node.getPosition(), 0, temp);
+
+        final org.jrubyparser.ast.Node arrayRead = new org.jrubyparser.ast.CallNode(node.getPosition(), readArrayFromTemp, "[]", buildArrayNode(node.getPosition(), index));
+
+        final String op = node.getOperatorName();
+
+        org.jrubyparser.ast.Node operation = null;
+
+        if (op.equals("||")) {
+            operation = new org.jrubyparser.ast.OrNode(node.getPosition(), arrayRead, operand);
+        } else if (op.equals("&&")) {
+            operation = new org.jrubyparser.ast.AndNode(node.getPosition(), arrayRead, operand);
+        } else {
+            operation = new org.jrubyparser.ast.CallNode(node.getPosition(), arrayRead, node.getOperatorName(), buildArrayNode(node.getPosition(), operand));
+        }
+
+        final org.jrubyparser.ast.Node arrayWrite = new org.jrubyparser.ast.CallNode(node.getPosition(), readArrayFromTemp, "[]=", buildArrayNode(node.getPosition(), index, operation));
+
+        final org.jrubyparser.ast.BlockNode block = new org.jrubyparser.ast.BlockNode(node.getPosition());
+        block.add(writeArrayToTemp);
+        block.add(arrayWrite);
+
+        return block.accept(this);
+    }
+
+    private static org.jrubyparser.ast.ArrayNode buildArrayNode(org.jrubyparser.SourcePosition sourcePosition, org.jrubyparser.ast.Node first, org.jrubyparser.ast.Node... rest) {
+        if (first == null) {
+            return new org.jrubyparser.ast.ArrayNode(sourcePosition);
+        }
+
+        final org.jrubyparser.ast.ArrayNode array = new org.jrubyparser.ast.ArrayNode(sourcePosition, first);
+
+        for (org.jrubyparser.ast.Node node : rest) {
+            array.add(node);
+        }
+
+        return array;
+    }
+
+    @Override
+    public Object visitOrNode(org.jrubyparser.ast.OrNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        RubyNode x;
+
+        if (node.getFirst() == null) {
+            x = new NilNode(context, sourceSection);
+        } else {
+            x = (RubyNode) node.getFirst().accept(this);
+        }
+
+        RubyNode y;
+
+        if (node.getSecond() == null) {
+            y = new NilNode(context, sourceSection);
+        } else {
+            y = (RubyNode) node.getSecond().accept(this);
+        }
+
+        return OrNodeFactory.create(context, sourceSection, x, y);
+    }
+
+    @Override
+    public Object visitPostExeNode(org.jrubyparser.ast.PostExeNode node) {
+        return unimplemented(node);
+    }
+
+    @Override
+    public Object visitPreExeNode(org.jrubyparser.ast.PreExeNode node) {
+        return unimplemented(node);
+    }
+
+    @Override
+    public Object visitRedoNode(org.jrubyparser.ast.RedoNode node) {
+        return new RedoNode(context, translate(node.getPosition()));
+    }
+
+    @Override
+    public Object visitRegexpNode(org.jrubyparser.ast.RegexpNode node) {
+        RubyRegexp regexp;
+
+        try {
+            final String patternText = node.getValue();
+
+            int flags = Pattern.MULTILINE | Pattern.UNIX_LINES;
+
+            final org.jrubyparser.RegexpOptions options = node.getOptions();
+
+            if (options.isIgnorecase()) {
+                flags |= Pattern.CASE_INSENSITIVE;
+            }
+
+            if (options.isMultiline()) {
+                // TODO(cs): isn't this the default?
+                flags |= Pattern.MULTILINE;
+            }
+
+            final Pattern pattern = Pattern.compile(patternText, flags);
+
+            regexp = new RubyRegexp(context.getCoreLibrary().getRegexpClass(), pattern);
+        } catch (PatternSyntaxException e) {
+            context.implementationMessage("failed to parse Ruby regexp " + node.getValue() + " as Java regexp - replacing with .");
+            regexp = new RubyRegexp(context.getCoreLibrary().getRegexpClass(), ".");
+        }
+
+        final ObjectLiteralNode literalNode = new ObjectLiteralNode(context, translate(node.getPosition()), regexp);
+        return literalNode;
+    }
+
+    @Override
+    public Object visitRescueBodyNode(org.jrubyparser.ast.RescueBodyNode node) {
+        return unimplemented(node);
+    }
+
+    @Override
+    public Object visitRescueNode(org.jrubyparser.ast.RescueNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        RubyNode tryPart;
+
+        if (node.getBody() != null) {
+            tryPart = (RubyNode) node.getBody().accept(this);
+        } else {
+            tryPart = new NilNode(context, sourceSection);
+        }
+
+        final List<RescueNode> rescueNodes = new ArrayList<>();
+
+        org.jrubyparser.ast.RescueBodyNode rescueBody = node.getRescue();
+
+        while (rescueBody != null) {
+            if (rescueBody.getExceptions() != null) {
+                if (rescueBody.getExceptions() instanceof org.jrubyparser.ast.ArrayNode) {
+                    final List<org.jrubyparser.ast.Node> exceptionNodes = ((org.jrubyparser.ast.ArrayNode) rescueBody.getExceptions()).childNodes();
+
+                    final RubyNode[] handlingClasses = new RubyNode[exceptionNodes.size()];
+
+                    for (int n = 0; n < handlingClasses.length; n++) {
+                        handlingClasses[n] = (RubyNode) exceptionNodes.get(n).accept(this);
+                    }
+
+                    RubyNode translatedBody;
+
+                    if (rescueBody.getBody() == null) {
+                        translatedBody = new NilNode(context, sourceSection);
+                    } else {
+                        translatedBody = (RubyNode) rescueBody.getBody().accept(this);
+                    }
+
+                    final RescueClassesNode rescueNode = new RescueClassesNode(context, sourceSection, handlingClasses, translatedBody);
+                    rescueNodes.add(rescueNode);
+                } else if (rescueBody.getExceptions() instanceof org.jrubyparser.ast.SplatNode) {
+                    final org.jrubyparser.ast.SplatNode splat = (org.jrubyparser.ast.SplatNode) rescueBody.getExceptions();
+
+                    RubyNode splatTranslated;
+
+                    if (splat.getValue() == null) {
+                        splatTranslated = new NilNode(context, sourceSection);
+                    } else {
+                        splatTranslated = (RubyNode) splat.getValue().accept(this);
+                    }
+
+                    RubyNode bodyTranslated;
+
+                    if (rescueBody.getBody() == null) {
+                        bodyTranslated = new NilNode(context, sourceSection);
+                    } else {
+                        bodyTranslated = (RubyNode) rescueBody.getBody().accept(this);
+                    }
+
+                    final RescueSplatNode rescueNode = new RescueSplatNode(context, sourceSection, splatTranslated, bodyTranslated);
+                    rescueNodes.add(rescueNode);
+                } else {
+                    unimplemented(node);
+                }
+            } else {
+                RubyNode bodyNode;
+
+                if (rescueBody.getBody() == null) {
+                    bodyNode = new NilNode(context, sourceSection);
+                } else {
+                    bodyNode = (RubyNode) rescueBody.getBody().accept(this);
+                }
+
+                final RescueAnyNode rescueNode = new RescueAnyNode(context, sourceSection, bodyNode);
+                rescueNodes.add(rescueNode);
+            }
+
+            rescueBody = rescueBody.getOptRescue();
+        }
+
+        RubyNode elsePart;
+
+        if (node.getElse() != null) {
+            elsePart = (RubyNode) node.getElse().accept(this);
+        } else {
+            elsePart = new NilNode(context, sourceSection);
+        }
+
+        return new TryNode(context, sourceSection, tryPart, rescueNodes.toArray(new RescueNode[rescueNodes.size()]), elsePart);
+    }
+
+    @Override
+    public Object visitRestArgNode(org.jrubyparser.ast.RestArgNode node) {
+        return unimplemented(node);
+    }
+
+    @Override
+    public Object visitRetryNode(org.jrubyparser.ast.RetryNode node) {
+        return new RetryNode(context, translate(node.getPosition()));
+    }
+
+    @Override
+    public Object visitReturnNode(org.jrubyparser.ast.ReturnNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        RubyNode translatedChild;
+
+        if (node.getValue() == null) {
+            translatedChild = new NilNode(context, sourceSection);
+        } else {
+            translatedChild = (RubyNode) node.getValue().accept(this);
+        }
+
+        return new ReturnNode(context, sourceSection, environment.getReturnID(), translatedChild);
+    }
+
+    @Override
+    public Object visitRootNode(org.jrubyparser.ast.RootNode node) {
+        return unimplemented(node);
+    }
+
+    @Override
+    public Object visitSClassNode(org.jrubyparser.ast.SClassNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(context, environment, environment.getParser(), environment.getParser().allocateReturnID(), true, true,
+                        new UniqueMethodIdentifier());
+        final ModuleTranslator classTranslator = new ModuleTranslator(context, this, newEnvironment, source);
+
+        final MethodDefinitionNode definitionMethod = classTranslator.compileClassNode(node.getPosition(), "singleton", node.getBody());
+
+        final RubyNode receiverNode = (RubyNode) node.getReceiver().accept(this);
+
+        final SingletonClassNode singletonClassNode = new SingletonClassNode(context, sourceSection, receiverNode);
+
+        return new OpenModuleNode(context, sourceSection, singletonClassNode, definitionMethod);
+    }
+
+    @Override
+    public Object visitSValueNode(org.jrubyparser.ast.SValueNode node) {
+        return node.getValue().accept(this);
+    }
+
+    @Override
+    public Object visitSelfNode(org.jrubyparser.ast.SelfNode node) {
+        return new SelfNode(context, translate(node.getPosition()));
+    }
+
+    @Override
+    public Object visitSplatNode(org.jrubyparser.ast.SplatNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        RubyNode value;
+
+        if (node.getValue() == null) {
+            value = new NilNode(context, sourceSection);
+        } else {
+            value = (RubyNode) node.getValue().accept(this);
+        }
+
+        return SplatCastNodeFactory.create(context, sourceSection, value);
+    }
+
+    @Override
+    public Object visitStrNode(org.jrubyparser.ast.StrNode node) {
+        return new StringLiteralNode(context, translate(node.getPosition()), node.getValue());
+    }
+
+    @Override
+    public Object visitSuperNode(org.jrubyparser.ast.SuperNode node) {
+        return unimplemented(node);
+    }
+
+    @Override
+    public Object visitSymbolNode(org.jrubyparser.ast.SymbolNode node) {
+        return new ObjectLiteralNode(context, translate(node.getPosition()), new RubySymbol(context.getCoreLibrary().getSymbolClass(), node.getName()));
+    }
+
+    @Override
+    public Object visitToAryNode(org.jrubyparser.ast.ToAryNode node) {
+        return unimplemented(node);
+    }
+
+    @Override
+    public Object visitTrueNode(org.jrubyparser.ast.TrueNode node) {
+        return new BooleanLiteralNode(context, translate(node.getPosition()), true);
+    }
+
+    @Override
+    public Object visitUndefNode(org.jrubyparser.ast.UndefNode node) {
+        return unimplemented(node);
+    }
+
+    @Override
+    public Object visitUntilNode(org.jrubyparser.ast.UntilNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        RubyNode condition;
+
+        if (node.getCondition() == null) {
+            condition = new NilNode(context, sourceSection);
+        } else {
+            condition = (RubyNode) node.getCondition().accept(this);
+        }
+
+        final BooleanCastNode conditionCast = BooleanCastNodeFactory.create(context, sourceSection, condition);
+        final NotNode conditionCastNot = new NotNode(context, sourceSection, conditionCast);
+        final BooleanCastNode conditionCastNotCast = BooleanCastNodeFactory.create(context, sourceSection, conditionCastNot);
+
+        final RubyNode body = (RubyNode) node.getBody().accept(this);
+
+        return new WhileNode(context, sourceSection, conditionCastNotCast, body);
+    }
+
+    @Override
+    public Object visitVAliasNode(org.jrubyparser.ast.VAliasNode node) {
+        return unimplemented(node);
+    }
+
+    @Override
+    public Object visitVCallNode(org.jrubyparser.ast.VCallNode node) {
+        final org.jrubyparser.ast.Node receiver = new org.jrubyparser.ast.SelfNode(node.getPosition());
+        final org.jrubyparser.ast.Node args = null;
+        final org.jrubyparser.ast.Node callNode = new org.jrubyparser.ast.CallNode(node.getPosition(), receiver, node.getName(), args);
+
+        return callNode.accept(this);
+    }
+
+    @Override
+    public Object visitWhenNode(org.jrubyparser.ast.WhenNode node) {
+        return unimplemented(node);
+    }
+
+    @Override
+    public Object visitWhileNode(org.jrubyparser.ast.WhileNode node) {
+        final SourceSection sourceSection = translate(node.getPosition());
+
+        RubyNode condition;
+
+        if (node.getCondition() == null) {
+            condition = new NilNode(context, sourceSection);
+        } else {
+            condition = (RubyNode) node.getCondition().accept(this);
+        }
+
+        final BooleanCastNode conditionCast = BooleanCastNodeFactory.create(context, sourceSection, condition);
+
+        final RubyNode body = (RubyNode) node.getBody().accept(this);
+
+        return new WhileNode(context, sourceSection, conditionCast, body);
+    }
+
+    @Override
+    public Object visitXStrNode(org.jrubyparser.ast.XStrNode node) {
+        SourceSection sourceSection = translate(node.getPosition());
+
+        final StringLiteralNode literal = new StringLiteralNode(context, sourceSection, node.getValue());
+
+        return new SystemNode(context, sourceSection, literal);
+    }
+
+    @Override
+    public Object visitYieldNode(org.jrubyparser.ast.YieldNode node) {
+        final List<org.jrubyparser.ast.Node> arguments = new ArrayList<>();
+
+        final org.jrubyparser.ast.Node argsNode = node.getArgs();
+
+        if (argsNode != null) {
+            if (argsNode instanceof org.jrubyparser.ast.ListNode) {
+                arguments.addAll(((org.jrubyparser.ast.ListNode) node.getArgs()).childNodes());
+            } else {
+                arguments.add(node.getArgs());
+            }
+        }
+
+        final List<RubyNode> argumentsTranslated = new ArrayList<>();
+
+        for (org.jrubyparser.ast.Node argument : arguments) {
+            argumentsTranslated.add((RubyNode) argument.accept(this));
+        }
+
+        final RubyNode[] argumentsTranslatedArray = argumentsTranslated.toArray(new RubyNode[argumentsTranslated.size()]);
+
+        return new YieldNode(context, translate(node.getPosition()), argumentsTranslatedArray);
+    }
+
+    @Override
+    public Object visitZArrayNode(org.jrubyparser.ast.ZArrayNode node) {
+        final RubyNode[] values = new RubyNode[0];
+
+        return new UninitialisedArrayLiteralNode(context, translate(node.getPosition()), values);
+    }
+
+    @Override
+    public Object visitZSuperNode(org.jrubyparser.ast.ZSuperNode node) {
+        return unimplemented(node);
+    }
+
+    public Object visitArgumentNode(org.jrubyparser.ast.ArgumentNode node) {
+        return unimplemented(node);
+    }
+
+    public Object visitCommentNode(org.jrubyparser.ast.CommentNode node) {
+        return unimplemented(node);
+    }
+
+    public Object visitKeywordArgNode(org.jrubyparser.ast.KeywordArgNode node) {
+        return unimplemented(node);
+    }
+
+    public Object visitKeywordRestArgNode(org.jrubyparser.ast.KeywordRestArgNode node) {
+        return unimplemented(node);
+    }
+
+    public Object visitListNode(org.jrubyparser.ast.ListNode node) {
+        return unimplemented(node);
+    }
+
+    public Object visitMethodNameNode(org.jrubyparser.ast.MethodNameNode node) {
+        return unimplemented(node);
+    }
+
+    public Object visitOptArgNode(org.jrubyparser.ast.OptArgNode node) {
+        return unimplemented(node);
+    }
+
+    public Object visitSyntaxNode(org.jrubyparser.ast.SyntaxNode node) {
+        return unimplemented(node);
+    }
+
+    public Object visitImplicitNilNode(org.jrubyparser.ast.ImplicitNilNode node) {
+        return new NilNode(context, translate(node.getPosition()));
+    }
+
+    public Object visitLambdaNode(org.jrubyparser.ast.LambdaNode node) {
+        // TODO(cs): code copied and modified from visitIterNode - extract common
+
+        final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(context, environment, environment.getParser(), environment.getReturnID(), false, false, new UniqueMethodIdentifier());
+        final MethodTranslator methodCompiler = new MethodTranslator(context, this, newEnvironment, false, source);
+
+        org.jrubyparser.ast.ArgsNode argsNode;
+
+        if (node.getVar() instanceof org.jrubyparser.ast.ArgsNode) {
+            argsNode = (org.jrubyparser.ast.ArgsNode) node.getVar();
+        } else if (node.getVar() instanceof org.jrubyparser.ast.DAsgnNode) {
+            final org.jrubyparser.ast.ArgumentNode arg = new org.jrubyparser.ast.ArgumentNode(node.getPosition(), ((org.jrubyparser.ast.DAsgnNode) node.getVar()).getName());
+            final org.jrubyparser.ast.ListNode preArgs = new org.jrubyparser.ast.ArrayNode(node.getPosition(), arg);
+            argsNode = new org.jrubyparser.ast.ArgsNode(node.getPosition(), preArgs, null, null, null, null, null, null);
+        } else if (node.getVar() == null) {
+            argsNode = null;
+        } else {
+            throw new UnsupportedOperationException();
+        }
+
+        final MethodDefinitionNode definitionNode = methodCompiler.compileFunctionNode(translate(node.getPosition()), "(lambda)", argsNode, node.getBody());
+
+        return new LambdaNode(context, translate(node.getPosition()), definitionNode);
+    }
+
+    public Object visitUnaryCallNode(org.jrubyparser.ast.UnaryCallNode node) {
+        final org.jrubyparser.ast.Node callNode = new org.jrubyparser.ast.CallNode(node.getPosition(), node.getReceiver(), node.getName(), null, null);
+        return callNode.accept(this);
+    }
+
+    protected Object unimplemented(org.jrubyparser.ast.Node node) {
+        context.implementationMessage("warning: %s at %s does nothing", node, node.getPosition());
+        return new NilNode(context, translate(node.getPosition()));
+    }
+
+    protected SourceSection translate(final org.jrubyparser.SourcePosition sourcePosition) {
+        try {
+            // TODO(cs): get an identifier
+            final String identifier = "(identifier)";
+
+            // TODO(cs): work out the start column
+            final int startColumn = -1;
+
+            final int charLength = sourcePosition.getEndOffset() - sourcePosition.getStartOffset();
+
+            return new DefaultSourceSection(source, identifier, sourcePosition.getStartLine() + 1, startColumn, sourcePosition.getStartOffset(), charLength);
+        } catch (UnsupportedOperationException e) {
+            // In some circumstances JRuby can't tell you what the position is
+            return translate(new org.jrubyparser.SourcePosition("(unknown)", 0, 0));
+        }
+    }
+
+    protected SequenceNode initFlipFlopStates(SourceSection sourceSection) {
+        final RubyNode[] initNodes = new RubyNode[environment.getFlipFlopStates().size()];
+
+        for (int n = 0; n < initNodes.length; n++) {
+            initNodes[n] = new InitFlipFlopSlotNode(context, sourceSection, environment.getFlipFlopStates().get(n));
+        }
+
+        return new SequenceNode(context, sourceSection, initNodes);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/TranslatorEnvironment.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.parser;
+
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.nodes.methods.locals.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+
+public class TranslatorEnvironment {
+
+    private final RubyContext context;
+
+    private final FrameDescriptor frameDescriptor;
+
+    private final List<FrameSlot> preParameters = new ArrayList<>();
+
+    private final List<FrameSlot> optionalParameters = new ArrayList<>();
+    private final Map<FrameSlot, RubyNode> optionalParametersDefaultValues = new HashMap<>();
+
+    private final List<FrameSlot> postParameters = new ArrayList<>();
+
+    private final List<FrameSlot> flipFlopStates = new ArrayList<>();
+
+    private FrameSlot restParameter = null;
+
+    private FrameSlot blockParameter = null;
+
+    private JRubyParser parser;
+    private final long returnID;
+
+    private final boolean ownScopeForAssignments;
+    private final boolean neverAssignInParentScope;
+
+    protected final TranslatorEnvironment parent;
+    private String methodName = "";
+    private boolean needsDeclarationFrame = false;
+    private UniqueMethodIdentifier methodIdentifier;
+
+    private int tempIndex;
+
+    public TranslatorEnvironment(RubyContext context, TranslatorEnvironment parent, FrameDescriptor frameDescriptor, JRubyParser parser, long returnID, boolean ownScopeForAssignments,
+                    boolean neverAssignInParentScope, UniqueMethodIdentifier methodIdentifier) {
+        this.context = context;
+        this.parent = parent;
+        this.frameDescriptor = frameDescriptor;
+        this.parser = parser;
+        this.returnID = returnID;
+        this.ownScopeForAssignments = ownScopeForAssignments;
+        this.neverAssignInParentScope = neverAssignInParentScope;
+        this.methodIdentifier = methodIdentifier;
+    }
+
+    public TranslatorEnvironment(RubyContext context, TranslatorEnvironment parent, JRubyParser parser, long returnID, boolean ownScopeForAssignments, boolean neverAssignInParentScope,
+                    UniqueMethodIdentifier methodIdentifier) {
+        this(context, parent, new FrameDescriptor(RubyFrameTypeConversion.getInstance()), parser, returnID, ownScopeForAssignments, neverAssignInParentScope, methodIdentifier);
+    }
+
+    public int getLocalVarCount() {
+        return getFrameDescriptor().getSize();
+    }
+
+    public TranslatorEnvironment getParent() {
+        return parent;
+    }
+
+    public List<FrameSlot> getPreParameters() {
+        return preParameters;
+    }
+
+    public List<FrameSlot> getOptionalParameters() {
+        return optionalParameters;
+    }
+
+    public Map<FrameSlot, RubyNode> getOptionalParametersDefaultValues() {
+        return optionalParametersDefaultValues;
+    }
+
+    public List<FrameSlot> getPostParameters() {
+        return postParameters;
+    }
+
+    public TranslatorEnvironment getParent(int level) {
+        assert level >= 0;
+        if (level == 0) {
+            return this;
+        } else {
+            return parent.getParent(level - 1);
+        }
+    }
+
+    public FrameSlot declareVar(String name) {
+        return getFrameDescriptor().findOrAddFrameSlot(name);
+    }
+
+    public UniqueMethodIdentifier findMethodForLocalVar(String name) {
+        TranslatorEnvironment current = this;
+        do {
+            FrameSlot slot = current.getFrameDescriptor().findFrameSlot(name);
+            if (slot != null) {
+                return current.methodIdentifier;
+            }
+
+            current = current.parent;
+        } while (current != null);
+
+        return null;
+    }
+
+    public RubyNode findLocalVarNode(String name, SourceSection sourceSection) {
+        TranslatorEnvironment current = this;
+        int level = -1;
+        try {
+            do {
+                level++;
+                FrameSlot slot = current.getFrameDescriptor().findFrameSlot(name);
+                if (slot != null) {
+                    if (level == 0) {
+                        return ReadLocalVariableNodeFactory.create(context, sourceSection, slot);
+                    } else {
+                        return ReadLevelVariableNodeFactory.create(context, sourceSection, slot, level);
+                    }
+                }
+
+                current = current.parent;
+            } while (current != null);
+        } finally {
+            if (current != null) {
+                current = this;
+                while (level-- > 0) {
+                    current.needsDeclarationFrame = true;
+                    current = current.parent;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    public void setRestParameter(FrameSlot restParameter) {
+        this.restParameter = restParameter;
+    }
+
+    public FrameSlot getRestParameter() {
+        return restParameter;
+    }
+
+    public void setBlockParameter(FrameSlot blockParameter) {
+        this.blockParameter = blockParameter;
+    }
+
+    public FrameSlot getBlockParameter() {
+        return blockParameter;
+    }
+
+    public void declareFunction(String name) {
+        declareVar(name);
+    }
+
+    public String getMethodName() {
+        return methodName;
+    }
+
+    public void setMethodName(String methodName) {
+        this.methodName = methodName;
+    }
+
+    public void setNeedsDeclarationFrame() {
+        needsDeclarationFrame = true;
+    }
+
+    public boolean needsDeclarationFrame() {
+        return needsDeclarationFrame;
+    }
+
+    public FrameDescriptor getFrameDescriptor() {
+        return frameDescriptor;
+    }
+
+    public String allocateLocalTemp() {
+        final String name = "rubytruffle_temp" + tempIndex;
+        tempIndex++;
+        declareVar(name);
+        return name;
+    }
+
+    public long getReturnID() {
+        return returnID;
+    }
+
+    public JRubyParser getParser() {
+        return parser;
+    }
+
+    public boolean hasOwnScopeForAssignments() {
+        return ownScopeForAssignments;
+    }
+
+    public boolean getNeverAssignInParentScope() {
+        return neverAssignInParentScope;
+    }
+
+    public void addMethodDeclarationSlots() {
+        frameDescriptor.addFrameSlot(RubyModule.VISIBILITY_FRAME_SLOT_ID);
+        frameDescriptor.addFrameSlot(RubyModule.MODULE_FUNCTION_FLAG_FRAME_SLOT_ID);
+    }
+
+    public UniqueMethodIdentifier getUniqueMethodIdentifier() {
+        return methodIdentifier;
+    }
+
+    public List<FrameSlot> getFlipFlopStates() {
+        return flipFlopStates;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/.checkstyle_checks.xml	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
+
+<!--
+    This configuration file was written by the eclipse-cs plugin configuration editor
+-->
+<!--
+    Checkstyle-Configuration: Maxine Checks
+    Description: none
+-->
+<module name="Checker">
+  <property name="severity" value="warning"/>
+  <module name="TreeWalker">
+    <property name="tabWidth" value="4"/>
+    <module name="FileContentsHolder"/>
+    <module name="JavadocStyle">
+      <property name="checkHtml" value="false"/>
+    </module>
+    <module name="LocalFinalVariableName"/>
+    <module name="LocalVariableName"/>
+    <module name="MemberName">
+      <property name="format" value="^(([a-z][a-zA-Z0-9]*$)|(_[A-Z][a-zA-Z0-9]*_[a-z][a-zA-Z0-9]*$))"/>
+    </module>
+    <module name="MethodName">
+      <property name="format" value="^[a-z][a-z_A-Z0-9]*$"/>
+    </module>
+    <module name="PackageName"/>
+    <module name="ParameterName"/>
+    <module name="TypeName">
+      <property name="format" value="^[A-Z][_a-zA-Z0-9]*$"/>
+    </module>
+    <module name="RedundantImport"/>
+    <module name="LineLength">
+      <property name="max" value="250"/>
+    </module>
+    <module name="MethodParamPad"/>
+    <module name="NoWhitespaceAfter">
+      <property name="tokens" value="ARRAY_INIT,BNOT,DEC,DOT,INC,LNOT,UNARY_MINUS,UNARY_PLUS"/>
+    </module>
+    <module name="NoWhitespaceBefore">
+      <property name="tokens" value="SEMI,DOT,POST_DEC,POST_INC"/>
+    </module>
+    <module name="ParenPad"/>
+    <module name="TypecastParenPad">
+      <property name="tokens" value="RPAREN,TYPECAST"/>
+    </module>
+    <module name="WhitespaceAfter"/>
+    <module name="WhitespaceAround">
+      <property name="tokens" value="ASSIGN,BAND,BAND_ASSIGN,BOR,BOR_ASSIGN,BSR,BSR_ASSIGN,BXOR,BXOR_ASSIGN,COLON,DIV,DIV_ASSIGN,EQUAL,GE,GT,LAND,LE,LITERAL_ASSERT,LITERAL_CATCH,LITERAL_DO,LITERAL_ELSE,LITERAL_FINALLY,LITERAL_FOR,LITERAL_IF,LITERAL_RETURN,LITERAL_SYNCHRONIZED,LITERAL_TRY,LITERAL_WHILE,LOR,LT,MINUS,MINUS_ASSIGN,MOD,MOD_ASSIGN,NOT_EQUAL,PLUS,PLUS_ASSIGN,QUESTION,SL,SLIST,SL_ASSIGN,SR,SR_ASSIGN,STAR,STAR_ASSIGN,LITERAL_ASSERT,TYPE_EXTENSION_AND"/>
+    </module>
+    <module name="RedundantModifier"/>
+    <module name="AvoidNestedBlocks">
+      <property name="allowInSwitchCase" value="true"/>
+    </module>
+    <module name="EmptyBlock">
+      <property name="option" value="text"/>
+      <property name="tokens" value="LITERAL_DO,LITERAL_ELSE,LITERAL_FINALLY,LITERAL_IF,LITERAL_TRY,LITERAL_WHILE,STATIC_INIT"/>
+    </module>
+    <module name="LeftCurly"/>
+    <module name="NeedBraces"/>
+    <module name="RightCurly"/>
+    <module name="EmptyStatement"/>
+    <module name="HiddenField">
+      <property name="severity" value="ignore"/>
+      <property name="ignoreConstructorParameter" value="true"/>
+      <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+    </module>
+    <module name="FinalClass"/>
+    <module name="HideUtilityClassConstructor">
+      <property name="severity" value="ignore"/>
+      <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+    </module>
+    <module name="ArrayTypeStyle"/>
+    <module name="UpperEll"/>
+    <module name="FallThrough"/>
+    <module name="FinalLocalVariable">
+      <property name="severity" value="ignore"/>
+      <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+    </module>
+    <module name="MultipleVariableDeclarations"/>
+    <module name="StringLiteralEquality">
+      <property name="severity" value="error"/>
+    </module>
+    <module name="SuperFinalize"/>
+    <module name="UnnecessaryParentheses">
+      <property name="severity" value="ignore"/>
+      <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+    </module>
+    <module name="Indentation">
+      <property name="severity" value="ignore"/>
+      <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+    </module>
+    <module name="StaticVariableName">
+      <property name="format" value="^[A-Za-z][a-zA-Z0-9]*$"/>
+    </module>
+    <module name="EmptyForInitializerPad"/>
+    <module name="EmptyForIteratorPad"/>
+    <module name="ModifierOrder"/>
+    <module name="DefaultComesLast"/>
+    <module name="InnerAssignment">
+      <property name="severity" value="ignore"/>
+      <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+    </module>
+    <module name="JUnitTestCase"/>
+    <module name="ModifiedControlVariable"/>
+    <module name="MutableException">
+      <property name="severity" value="ignore"/>
+      <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+    </module>
+    <module name="ParameterAssignment">
+      <property name="severity" value="ignore"/>
+      <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+    </module>
+    <module name="RegexpSinglelineJava">
+      <metadata name="net.sf.eclipsecs.core.comment" value="Illegal trailing whitespace(s) at the end of the line."/>
+      <property name="format" value="\s$"/>
+      <property name="message" value="Illegal trailing whitespace(s) at the end of the line."/>
+      <property name="ignoreComments" value="true"/>
+      <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Checks for trailing spaces at the end of a line"/>
+    </module>
+    <module name="RegexpSinglelineJava">
+      <metadata name="net.sf.eclipsecs.core.comment" value="illegal space before a comma"/>
+      <property name="format" value=" ,"/>
+      <property name="message" value="illegal space before a comma"/>
+      <property name="ignoreComments" value="true"/>
+      <metadata name="com.atlassw.tools.eclipse.checkstyle.customMessage" value="Illegal whitespace before a comma."/>
+      <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Checks for whitespace before a comma."/>
+    </module>
+  </module>
+  <!--<module name="RegexpHeader">
+    <property name="header" value="/\*\n \* Copyright \(c\) 2013 Oracle and/or its affiliates. All rights reserved. This\n \* code is released under a tri EPL/GPL/LGPL license. You can use it,\n \* redistribute it and/or modify it under the terms of the:\n \*\n \* Eclipse Public License version 1.0\n \* GNU General Public License version 2\n \* GNU Lesser General Public License version 2.1\n \*/\n"/>
+    <property name="fileExtensions" value="java"/>
+  </module>-->
+  <module name="FileTabCharacter">
+    <property name="severity" value="error"/>
+  </module>
+  <module name="NewlineAtEndOfFile">
+    <property name="lineSeparator" value="lf"/>
+  </module>
+  <module name="Translation"/>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="Checkstyle: stop constant name check"/>
+    <property name="onCommentFormat" value="Checkstyle: resume constant name check"/>
+    <property name="checkFormat" value="ConstantNameCheck"/>
+    <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Allow non-conforming constant names"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="Checkstyle: stop method name check"/>
+    <property name="onCommentFormat" value="Checkstyle: resume method name check"/>
+    <property name="checkFormat" value="MethodName"/>
+    <property name="checkC" value="false"/>
+    <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable method name checks"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="CheckStyle: stop parameter assignment check"/>
+    <property name="onCommentFormat" value="CheckStyle: resume parameter assignment check"/>
+    <property name="checkFormat" value="ParameterAssignment"/>
+    <property name="checkC" value="false"/>
+    <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable Parameter Assignment"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="Checkstyle: stop final variable check"/>
+    <property name="onCommentFormat" value="Checkstyle: resume final variable check"/>
+    <property name="checkFormat" value="FinalLocalVariable"/>
+    <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable final variable checks"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="Checkstyle: stop"/>
+    <property name="onCommentFormat" value="Checkstyle: resume"/>
+    <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable all checks"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="// START GENERATED RAW ASSEMBLER METHODS"/>
+    <property name="onCommentFormat" value="// END GENERATED RAW ASSEMBLER METHODS"/>
+    <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable all checks for generated raw assembler methods"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="// START GENERATED LABEL ASSEMBLER METHODS"/>
+    <property name="onCommentFormat" value="// END GENERATED LABEL ASSEMBLER METHODS"/>
+    <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable all checks for generated label assembler methods"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="CheckStyle: stop inner assignment check"/>
+    <property name="onCommentFormat" value="CheckStyle: resume inner assignment check"/>
+    <property name="checkFormat" value="InnerAssignment"/>
+    <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable inner assignment checks"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="Checkstyle: stop field name check"/>
+    <property name="onCommentFormat" value="Checkstyle: resume field name check"/>
+    <property name="checkFormat" value="MemberName"/>
+    <property name="checkC" value="false"/>
+    <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable field name checks"/>
+  </module>
+  <module name="RegexpMultiline">
+    <metadata name="net.sf.eclipsecs.core.comment" value="illegal Windows line ending"/>
+    <property name="format" value="\r\n"/>
+    <property name="message" value="illegal Windows line ending"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="CheckStyle: stop header check"/>
+    <property name="onCommentFormat" value="CheckStyle: resume header check"/>
+    <property name="checkFormat" value=".*Header"/>
+    <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable header checks"/>
+  </module>
+</module>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/InputReader.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime;
+
+import java.io.*;
+
+/**
+ * Interface allowing Ruby {@code Kernel#gets} to be configured to use the standard Java readLine,
+ * some library like JLine, or to be mocked for testing.
+ */
+public interface InputReader {
+
+    /**
+     * Show a prompt and read one line of input.
+     */
+    String readLine(String prompt) throws IOException;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/NilPlaceholder.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime;
+
+/**
+ * Represents the Ruby {@code Nil} object, but without being a full Ruby object. This allows us to
+ * have a simple values that is {@code nil}, but more readily available than the particular instance
+ * for a context.
+ */
+public final class NilPlaceholder {
+
+    public static final NilPlaceholder INSTANCE = new NilPlaceholder();
+
+    private NilPlaceholder() {
+    }
+
+    @Override
+    public String toString() {
+        return "";
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyArguments.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+/**
+ * Arguments and other context passed to a Ruby method. Includes the central Ruby context object,
+ * optionally the scope at the point of declaration (forming a closure), the value of self, a passed
+ * block, and the formal arguments.
+ */
+public final class RubyArguments extends Arguments {
+
+    private final MaterializedFrame declarationFrame;
+    private final Object self;
+    private final RubyProc block;
+    private final Object[] arguments;
+
+    public RubyArguments(MaterializedFrame declarationFrame, Object self, RubyProc block, Object... arguments) {
+        assert self != null;
+        assert arguments != null;
+
+        this.declarationFrame = declarationFrame;
+        this.self = self;
+        this.block = block;
+        this.arguments = arguments;
+    }
+
+    public MaterializedFrame getDeclarationFrame() {
+        return declarationFrame;
+    }
+
+    /**
+     * Get the declaration frame a certain number of levels up from the current frame, where the
+     * current frame is 0.
+     */
+    public static MaterializedFrame getDeclarationFrame(VirtualFrame frame, int level) {
+        assert level > 0;
+
+        MaterializedFrame parentFrame = frame.getArguments(RubyArguments.class).getDeclarationFrame();
+        return getDeclarationFrame(parentFrame, level - 1);
+    }
+
+    /**
+     * Get the declaration frame a certain number of levels up from the current frame, where the
+     * current frame is 0.
+     */
+    @ExplodeLoop
+    private static MaterializedFrame getDeclarationFrame(MaterializedFrame frame, int level) {
+        assert frame != null;
+        assert level >= 0;
+
+        MaterializedFrame parentFrame = frame;
+
+        for (int n = 0; n < level; n++) {
+            parentFrame = parentFrame.getArguments(RubyArguments.class).getDeclarationFrame();
+        }
+
+        return parentFrame;
+    }
+
+    public Object getSelf() {
+        return self;
+    }
+
+    public RubyProc getBlock() {
+        return block;
+    }
+
+    public Object[] getArguments() {
+        return arguments;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyContext.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime;
+
+import java.math.*;
+import java.util.concurrent.atomic.*;
+
+import jnr.posix.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.source.*;
+import com.oracle.truffle.ruby.runtime.configuration.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.debug.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+import com.oracle.truffle.ruby.runtime.subsystems.*;
+
+/**
+ * The global state of a running Ruby system.
+ */
+public class RubyContext implements ExecutionContext {
+
+    private final Configuration configuration;
+    private final RubyParser parser;
+    private final CoreLibrary coreLibrary;
+    private final FeatureManager featureManager;
+    private final ObjectSpaceManager objectSpaceManager;
+    private final TraceManager traceManager;
+    private final ThreadManager threadManager;
+    private final FiberManager fiberManager;
+    private final AtExitManager atExitManager;
+    private final RubyDebugManager debugManager;
+    private final SourceManager sourceManager;
+
+    private AtomicLong nextObjectID = new AtomicLong(0);
+
+    private String currentDirectory = System.getProperty("user.dir");
+
+    private POSIX posix = POSIXFactory.getPOSIX();
+
+    public RubyContext(RubyParser parser) {
+        this(new Configuration(new ConfigurationBuilder()), parser);
+    }
+
+    public RubyContext(Configuration configuration, RubyParser parser) {
+        assert configuration != null;
+
+        this.configuration = configuration;
+        this.parser = parser;
+
+        objectSpaceManager = new ObjectSpaceManager(this);
+        traceManager = new TraceManager(this);
+
+        // See note in CoreLibrary#initialize to see why we need to break this into two statements
+        coreLibrary = new CoreLibrary(this);
+        coreLibrary.initialize();
+
+        featureManager = new FeatureManager(this);
+        atExitManager = new AtExitManager();
+        sourceManager = new SourceManager();
+
+        debugManager = configuration.getDebug() ? new RubyDebugManager(this) : null;
+
+        // Must initialize threads before fibers
+
+        threadManager = new ThreadManager(this);
+
+        if (configuration.getRubyVersion().is19OrLater()) {
+            fiberManager = new FiberManager(this);
+        } else {
+            fiberManager = null;
+        }
+    }
+
+    public String getLanguageShortName() {
+        return configuration.getRubyVersion().getShortName();
+    }
+
+    public RubyDebugManager getDebugManager() {
+        return debugManager;
+    }
+
+    public void implementationMessage(String format, Object... arguments) {
+        System.err.println("rubytruffle: " + String.format(format, arguments));
+    }
+
+    public void load(Source source) {
+        execute(this, source, RubyParser.ParserContext.TOP_LEVEL, coreLibrary.getMainObject(), null);
+    }
+
+    public void loadFile(String fileName) {
+        final Source source = sourceManager.get(fileName);
+        final String code = source.getCode();
+        if (code == null) {
+            throw new RuntimeException("Can't read file " + fileName);
+        }
+        execute(this, source, RubyParser.ParserContext.TOP_LEVEL, coreLibrary.getMainObject(), null);
+    }
+
+    /**
+     * Receives runtime notification that execution has halted.
+     */
+    public void haltedAt(Node node, MaterializedFrame frame) {
+        runShell(node, frame);
+    }
+
+    public Object eval(String code) {
+        final Source source = sourceManager.get("(eval)", code);
+        return execute(this, source, RubyParser.ParserContext.TOP_LEVEL, coreLibrary.getMainObject(), null);
+    }
+
+    public Object eval(String code, RubyModule module) {
+        final Source source = sourceManager.get("(eval)", code);
+        return execute(this, source, RubyParser.ParserContext.MODULE, module, null);
+    }
+
+    public Object eval(String code, RubyBinding binding) {
+        final Source source = sourceManager.get("(eval)", code);
+        return execute(this, source, RubyParser.ParserContext.TOP_LEVEL, binding.getSelf(), binding.getFrame());
+    }
+
+    public void runShell(Node node, MaterializedFrame frame) {
+        MaterializedFrame existingLocals = frame;
+
+        String prompt = "Ruby> ";
+        if (node != null) {
+            final SourceSection src = node.getSourceSection();
+            if (src != null) {
+                prompt = (src.getSource().getName() + ":" + src.getStartLine() + "> ");
+            }
+        }
+
+        while (true) {
+            try {
+                final String line = configuration.getInputReader().readLine(prompt);
+
+                final ShellResult result = evalShell(line, existingLocals);
+
+                configuration.getStandardOut().println("=> " + result.getResult());
+
+                existingLocals = result.getFrame();
+            } catch (BreakShellException e) {
+                return;
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public ShellResult evalShell(String code, MaterializedFrame existingLocals) {
+        final Source source = sourceManager.get("(shell)", code);
+        return (ShellResult) execute(this, source, RubyParser.ParserContext.SHELL, coreLibrary.getMainObject(), existingLocals);
+    }
+
+    public Object execute(RubyContext context, Source source, RubyParser.ParserContext parserContext, Object self, MaterializedFrame parentFrame) {
+        if (configuration.getPrintExecutedFiles()) {
+            implementationMessage("executing: %s", source.getName());
+        }
+
+        try {
+            final RubyParserResult parseResult = parser.parse(context, source, parserContext, parentFrame);
+            final RubyArguments arguments = new RubyArguments(parentFrame, self, null);
+            final CallTarget callTarget = Truffle.getRuntime().createCallTarget(parseResult.getRootNode(), parseResult.getFrameDescriptor());
+
+            return callTarget.call(null, arguments);
+        } catch (RaiseException e) {
+            throw e;
+        } catch (ThrowException e) {
+            if (context.getConfiguration().getRubyVersion().is18OrEarlier()) {
+                throw new RaiseException(context.getCoreLibrary().nameErrorUncaughtThrow(e.getTag()));
+            } else {
+                throw new RaiseException(context.getCoreLibrary().argumentErrorUncaughtThrow(e.getTag()));
+            }
+        } catch (BreakShellException | QuitException e) {
+            throw e;
+        } catch (Throwable e) {
+            throw new RaiseException(ExceptionTranslator.translateException(this, e));
+        }
+    }
+
+    public long getNextObjectID() {
+        // TODO(CS): We can theoretically run out of long values
+
+        final long id = nextObjectID.getAndIncrement();
+
+        if (id < 0) {
+            nextObjectID.set(Long.MIN_VALUE);
+            throw new RuntimeException("Object IDs exhausted");
+        }
+
+        return id;
+    }
+
+    public void shutdown() {
+        atExitManager.run();
+
+        threadManager.leaveGlobalLock();
+
+        objectSpaceManager.shutdown();
+
+        if (fiberManager != null) {
+            fiberManager.shutdown();
+        }
+    }
+
+    public RubyString makeString(String string) {
+        return new RubyString(coreLibrary.getStringClass(), string);
+    }
+
+    public RubyString makeString(char string) {
+        return makeString(Character.toString(string));
+    }
+
+    public Configuration getConfiguration() {
+        return configuration;
+    }
+
+    public CoreLibrary getCoreLibrary() {
+        return coreLibrary;
+    }
+
+    public FeatureManager getFeatureManager() {
+        return featureManager;
+    }
+
+    public ObjectSpaceManager getObjectSpaceManager() {
+        return objectSpaceManager;
+    }
+
+    public TraceManager getTraceManager() {
+        return traceManager;
+    }
+
+    public FiberManager getFiberManager() {
+        return fiberManager;
+    }
+
+    public ThreadManager getThreadManager() {
+        return threadManager;
+    }
+
+    public RubyParser getParser() {
+        return parser;
+    }
+
+    /**
+     * Utility method to check if an object should be visible in a Ruby program. Used in assertions
+     * at method boundaries to check that only values we want to be visible to the programmer become
+     * so.
+     */
+    public static boolean shouldObjectBeVisible(Object object) {
+        // TODO(cs): RubyMethod should never be visible
+
+        return object instanceof UndefinedPlaceholder || //
+                        object instanceof Boolean || //
+                        object instanceof Integer || //
+                        object instanceof BigInteger || //
+                        object instanceof Double || //
+                        object instanceof RubyBasicObject || //
+                        object instanceof RubyMethod || //
+                        object instanceof NilPlaceholder || //
+                        object instanceof RubyMethod;
+    }
+
+    public static boolean shouldObjectsBeVisible(Object... objects) {
+        for (Object object : objects) {
+            if (!shouldObjectBeVisible(object)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    public void setCurrentDirectory(String currentDirectory) {
+        this.currentDirectory = currentDirectory;
+    }
+
+    public String getCurrentDirectory() {
+        return currentDirectory;
+    }
+
+    public POSIX getPOSIX() {
+        return posix;
+    }
+
+    public AtExitManager getAtExitManager() {
+        return atExitManager;
+    }
+
+    public SourceManager getSourceManager() {
+        return sourceManager;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyParser.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+
+/**
+ * Interface to a Ruby parser.
+ */
+public interface RubyParser {
+
+    public static enum ParserContext {
+        TOP_LEVEL, SHELL, MODULE
+    }
+
+    RubyParserResult parse(RubyContext context, Source source, ParserContext parserContext, MaterializedFrame parentFrame);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyParserResult.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime;
+
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * The result of parsing Ruby code is a root node and a frame descriptor for the method in that
+ * root. The root node will always be a {@code RubyRootNode}, but this package is below the nodes
+ * package so currently cannot refer to it.
+ */
+public class RubyParserResult {
+
+    private RootNode rootNode;
+    private FrameDescriptor frameDescriptor;
+
+    public RubyParserResult(RootNode rootNode, FrameDescriptor frameDescriptor) {
+        assert rootNode != null;
+        assert frameDescriptor != null;
+
+        this.rootNode = rootNode;
+        this.frameDescriptor = frameDescriptor;
+    }
+
+    public RootNode getRootNode() {
+        return rootNode;
+    }
+
+    public FrameDescriptor getFrameDescriptor() {
+        return frameDescriptor;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/ShellResult.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime;
+
+import com.oracle.truffle.api.frame.*;
+
+/**
+ * The result of executing a line in a shell is a result value and the final frame containing any
+ * local variables set.
+ */
+public class ShellResult {
+
+    private final Object result;
+    private final MaterializedFrame frame;
+
+    public ShellResult(Object result, MaterializedFrame frame) {
+        assert RubyContext.shouldObjectBeVisible(result);
+        assert frame != null;
+
+        this.result = result;
+        this.frame = frame;
+    }
+
+    public Object getResult() {
+        return result;
+    }
+
+    public MaterializedFrame getFrame() {
+        return frame;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/UndefinedPlaceholder.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime;
+
+/**
+ * The {@link UndefinedPlaceholder} is a value that represents an undefined value in Ruby. This is
+ * used to differentiate between nil and the true absence of a value, such as an argument that has
+ * not been passed.
+ */
+public final class UndefinedPlaceholder {
+
+    public static final UndefinedPlaceholder INSTANCE = new UndefinedPlaceholder();
+
+    private UndefinedPlaceholder() {
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/configuration/Configuration.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.configuration;
+
+import java.io.*;
+
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * Configurable, immutable global parameters for Ruby.
+ */
+public class Configuration {
+
+    private final String standardLibrary;
+
+    private final RubyVersion rubyVersion;
+
+    private final boolean verbose;
+    private final int warningLevel;
+    private final int taintCheckLevel;
+
+    private final String defaultExternalEncoding;
+    private final String defaultInternalEncoding;
+
+    private final boolean debug;
+    private final boolean trace;
+    private final boolean fullObjectSpace;
+
+    private final boolean printParseTree;
+    private final boolean printExecutedFiles;
+    private final boolean printSpiltInstanceVariables;
+    private final boolean printUninitializedCalls;
+    private final boolean printJavaExceptions;
+    private final boolean printRubyExceptions;
+
+    private final PrintStream standardOut;
+    private final InputReader inputReader;
+
+    public Configuration(ConfigurationBuilder builder) {
+        assert builder != null;
+
+        standardLibrary = builder.getStandardLibrary();
+
+        rubyVersion = builder.getRubyVersion();
+
+        verbose = builder.getVerbose();
+        warningLevel = builder.getWarningLevel();
+        taintCheckLevel = builder.getTaintCheckLevel();
+
+        defaultExternalEncoding = builder.getDefaultExternalEncoding();
+        defaultInternalEncoding = builder.getDefaultInternalEncoding();
+
+        debug = builder.getDebug();
+        trace = builder.getTrace();
+        fullObjectSpace = builder.getFullObjectSpace();
+
+        printParseTree = builder.getPrintParseTree();
+        printExecutedFiles = builder.getPrintExecutedFiles();
+        printSpiltInstanceVariables = builder.getPrintSpiltInstanceVariables();
+        printUninitializedCalls = builder.getPrintUninitializedCalls();
+        printJavaExceptions = builder.getPrintJavaExceptions();
+        printRubyExceptions = builder.getPrintRubyExceptions();
+
+        standardOut = builder.getStandardOut();
+        inputReader = builder.getInputReader();
+    }
+
+    public String getStandardLibrary() {
+        return standardLibrary;
+    }
+
+    public RubyVersion getRubyVersion() {
+        return rubyVersion;
+    }
+
+    public boolean getDebug() {
+        return debug;
+    }
+
+    public boolean getVerbose() {
+        return verbose;
+    }
+
+    public int getWarningLevel() {
+        return warningLevel;
+    }
+
+    public int getTaintCheckLevel() {
+        return taintCheckLevel;
+    }
+
+    public String getDefaultExternalEncoding() {
+        return defaultExternalEncoding;
+    }
+
+    public String getDefaultInternalEncoding() {
+        return defaultInternalEncoding;
+    }
+
+    public boolean getTrace() {
+        return trace;
+    }
+
+    public boolean getFullObjectSpace() {
+        return fullObjectSpace;
+    }
+
+    public boolean getPrintParseTree() {
+        return printParseTree;
+    }
+
+    public boolean getPrintExecutedFiles() {
+        return printExecutedFiles;
+    }
+
+    public boolean getPrintSpiltInstanceVariables() {
+        return printSpiltInstanceVariables;
+    }
+
+    public boolean getPrintUninitializedCalls() {
+        return printUninitializedCalls;
+    }
+
+    public boolean getPrintJavaExceptions() {
+        return printJavaExceptions;
+    }
+
+    public boolean getPrintRubyExceptions() {
+        return printRubyExceptions;
+    }
+
+    public PrintStream getStandardOut() {
+        return standardOut;
+    }
+
+    public InputReader getInputReader() {
+        return inputReader;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/configuration/ConfigurationBuilder.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.configuration;
+
+import java.io.*;
+
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * The mutable counterpart to {@link Configuration}.
+ */
+public class ConfigurationBuilder {
+
+    /**
+     * The path of the JRuby packaging of the Ruby standard library within our source tree.
+     */
+    public static final String JRUBY_STDLIB_JAR = "lib/jruby-stdlib-1.7.4.jar";
+
+    private String standardLibrary = JRUBY_STDLIB_JAR;
+
+    private RubyVersion rubyVersion = RubyVersion.RUBY_19;
+
+    private boolean debug = true;
+    private boolean verbose = false;
+    private int warningLevel = 0;
+    private int taintCheckLevel = 0;
+
+    private String defaultExternalEncoding = null;
+    private String defaultInternalEncoding = null;
+
+    private boolean trace = true;
+    private boolean fullObjectSpace = false;
+
+    private boolean printParseTree = false;
+    private boolean printExecutedFiles = false;
+    private boolean printSpiltInstanceVariables = false;
+    private boolean printUninitializedCalls = false;
+    private boolean printJavaExceptions = false;
+    private boolean printRubyExceptions = false;
+
+    private PrintStream standardOut = System.out;
+
+    private InputReader inputReader = new InputReader() {
+
+        private final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
+
+        @Override
+        public String readLine(String prompt) throws IOException {
+            System.err.print(prompt);
+            return reader.readLine();
+        }
+
+    };
+
+    public ConfigurationBuilder() {
+    }
+
+    public ConfigurationBuilder(Configuration configuration) {
+        assert configuration != null;
+
+        standardLibrary = configuration.getStandardLibrary();
+
+        rubyVersion = configuration.getRubyVersion();
+
+        debug = configuration.getDebug();
+        verbose = configuration.getVerbose();
+        warningLevel = configuration.getWarningLevel();
+        taintCheckLevel = configuration.getTaintCheckLevel();
+
+        defaultExternalEncoding = configuration.getDefaultExternalEncoding();
+        defaultInternalEncoding = configuration.getDefaultInternalEncoding();
+
+        trace = configuration.getTrace();
+        fullObjectSpace = configuration.getFullObjectSpace();
+
+        printParseTree = configuration.getPrintParseTree();
+        printExecutedFiles = configuration.getPrintExecutedFiles();
+        printSpiltInstanceVariables = configuration.getPrintSpiltInstanceVariables();
+        printUninitializedCalls = configuration.getPrintUninitializedCalls();
+        printJavaExceptions = configuration.getPrintJavaExceptions();
+        printRubyExceptions = configuration.getPrintRubyExceptions();
+
+        standardOut = configuration.getStandardOut();
+    }
+
+    public String getStandardLibrary() {
+        return standardLibrary;
+    }
+
+    public void setStandardLibrary(String standardLibrary) {
+        assert standardLibrary != null;
+        this.standardLibrary = standardLibrary;
+    }
+
+    public RubyVersion getRubyVersion() {
+        return rubyVersion;
+    }
+
+    public void setRubyVersion(RubyVersion rubyVersion) {
+        assert rubyVersion != null;
+        this.rubyVersion = rubyVersion;
+    }
+
+    public boolean getDebug() {
+        return debug;
+    }
+
+    public void setDebug(boolean debug) {
+        this.debug = debug;
+    }
+
+    public boolean getVerbose() {
+        return verbose;
+    }
+
+    public void setVerbose(boolean verbose) {
+        this.verbose = verbose;
+    }
+
+    public int getWarningLevel() {
+        return warningLevel;
+    }
+
+    public void setWarningLevel(int warningLevel) {
+        this.warningLevel = warningLevel;
+    }
+
+    public int getTaintCheckLevel() {
+        return taintCheckLevel;
+    }
+
+    public void setTaintCheckLevel(int taintCheckLevel) {
+        this.taintCheckLevel = taintCheckLevel;
+    }
+
+    public String getDefaultExternalEncoding() {
+        return defaultExternalEncoding;
+    }
+
+    public void setDefaultExternalEncoding(String defaultExternalEncoding) {
+        assert defaultExternalEncoding != null;
+        this.defaultExternalEncoding = defaultExternalEncoding;
+    }
+
+    public String getDefaultInternalEncoding() {
+        return defaultInternalEncoding;
+    }
+
+    public void setDefaultInternalEncoding(String defaultInternalEncoding) {
+        assert defaultInternalEncoding != null;
+        this.defaultInternalEncoding = defaultInternalEncoding;
+    }
+
+    public boolean getTrace() {
+        return trace;
+    }
+
+    public void setTrace(boolean trace) {
+        this.trace = trace;
+    }
+
+    public boolean getFullObjectSpace() {
+        return fullObjectSpace;
+    }
+
+    public void setFullObjectSpace(boolean fullObjectSpace) {
+        this.fullObjectSpace = fullObjectSpace;
+    }
+
+    public boolean getPrintParseTree() {
+        return printParseTree;
+    }
+
+    public void setPrintParseTree(boolean printParseTree) {
+        this.printParseTree = printParseTree;
+    }
+
+    public boolean getPrintExecutedFiles() {
+        return printExecutedFiles;
+    }
+
+    public void setPrintExecutedFiles(boolean printExecutedFiles) {
+        this.printExecutedFiles = printExecutedFiles;
+    }
+
+    public boolean getPrintSpiltInstanceVariables() {
+        return printSpiltInstanceVariables;
+    }
+
+    public void setPrintSpiltInstanceVariables(boolean printSpiltInstanceVariables) {
+        this.printSpiltInstanceVariables = printSpiltInstanceVariables;
+    }
+
+    public boolean getPrintUninitializedCalls() {
+        return printUninitializedCalls;
+    }
+
+    public void setPrintUninitializedCalls(boolean printUninitializedCalls) {
+        this.printUninitializedCalls = printUninitializedCalls;
+    }
+
+    public boolean getPrintJavaExceptions() {
+        return printJavaExceptions;
+    }
+
+    public void setPrintJavaExceptions(boolean printJavaExceptions) {
+        this.printJavaExceptions = printJavaExceptions;
+    }
+
+    public boolean getPrintRubyExceptions() {
+        return printRubyExceptions;
+    }
+
+    public void setPrintRubyExceptions(boolean printRubyExceptions) {
+        this.printRubyExceptions = printRubyExceptions;
+    }
+
+    public PrintStream getStandardOut() {
+        return standardOut;
+    }
+
+    public void setStandardOut(PrintStream standardOut) {
+        assert standardOut != null;
+        this.standardOut = standardOut;
+    }
+
+    public InputReader getInputReader() {
+        return inputReader;
+    }
+
+    public void setInputReader(InputReader lineReader) {
+        assert lineReader != null;
+        this.inputReader = lineReader;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/configuration/RubyVersion.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.configuration;
+
+/**
+ * A Ruby version that we want to be compatible with.
+ */
+public enum RubyVersion {
+    RUBY_18("1.8.7", 374), RUBY_19("1.9.3", 448), RUBY_20("2.0.0", 247), RUBY_21("2.1.0", 0);
+
+    private final String version;
+    private final int patch;
+
+    private RubyVersion(String version, int patch) {
+        this.version = version;
+        this.patch = patch;
+    }
+
+    public boolean is18OrEarlier() {
+        return this.compareTo(RUBY_18) <= 0;
+    }
+
+    public boolean is19OrLater() {
+        return this.compareTo(RUBY_19) >= 0;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public int getPatch() {
+        return patch;
+    }
+
+    public String getShortName() {
+        return "Ruby" + getVersion();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/BreakException.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.control;
+
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * Controls a break from a control structure or method.
+ */
+public final class BreakException extends ControlFlowException {
+
+    private final Object result;
+
+    public BreakException(Object result) {
+        assert RubyContext.shouldObjectBeVisible(result);
+
+        this.result = result;
+    }
+
+    public Object getResult() {
+        return result;
+    }
+
+    private static final long serialVersionUID = -8650123232850256133L;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/BreakShellException.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.control;
+
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Controls breaking out of a shell.
+ */
+public final class BreakShellException extends ControlFlowException {
+
+    private static final long serialVersionUID = 6448983812696841922L;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/ContinuationReturnException.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.control;
+
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+/**
+ * Controls return from a continuation.
+ */
+public final class ContinuationReturnException extends ControlFlowException {
+
+    private final RubyContinuation continuation;
+    private final Object value;
+
+    public ContinuationReturnException(RubyContinuation continuation, Object value) {
+        assert continuation != null;
+        assert RubyContext.shouldObjectBeVisible(value);
+
+        this.continuation = continuation;
+        this.value = value;
+    }
+
+    /**
+     * Get the continuation that caused this.
+     */
+    public RubyContinuation getContinuation() {
+        return continuation;
+    }
+
+    /**
+     * Get the value that has been returned.
+     */
+    public Object getValue() {
+        return value;
+    }
+
+    private static final long serialVersionUID = 6215834704293311504L;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/ExceptionTranslator.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.control;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+public final class ExceptionTranslator {
+
+    /**
+     * Translate a Java exception into a Ruby exception.
+     */
+    public static RubyBasicObject translateException(RubyContext context, Throwable exception) {
+        assert context != null;
+        assert exception != null;
+
+        CompilerAsserts.neverPartOfCompilation();
+
+        // RaiseException already includes the Ruby exception
+
+        if (exception instanceof RaiseException) {
+            return ((RaiseException) exception).getRubyException();
+        }
+
+        // Translate divide by zero into ZeroDivisionError
+
+        if (exception instanceof ArithmeticException && (exception.getMessage().endsWith("divide by zero") || exception.getMessage().endsWith("/ by zero"))) {
+            return new RubyException(context.getCoreLibrary().getZeroDivisionErrorClass(), "divided by 0");
+        }
+
+        /*
+         * If we can't translate the exception into a Ruby exception, then the error is ours and we
+         * report it as as RubyTruffleError. If a programmer sees this then it's a bug in our
+         * implementation.
+         */
+
+        if (context.getConfiguration().getPrintJavaExceptions()) {
+            exception.printStackTrace();
+        }
+
+        String message;
+
+        if (exception.getMessage() == null) {
+            message = exception.getClass().getSimpleName();
+        } else {
+            message = exception.getMessage();
+        }
+
+        return new RubyException(context.getCoreLibrary().getRubyTruffleErrorClass(), message);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/NextException.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.control;
+
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Controls moving to the next iteration in a control structure or method.
+ */
+public final class NextException extends ControlFlowException {
+
+    private static final long serialVersionUID = -302759969186731457L;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/QuitException.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.control;
+
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Controls breaking out of all executions and ending Ruby execution.
+ */
+public final class QuitException extends ControlFlowException {
+
+    private static final long serialVersionUID = -3568511099628564190L;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/RaiseException.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.control;
+
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Ruby exceptions are just Ruby objects, so they cannot also be exceptions unless we made all Ruby
+ * objects exceptions. A simpler approach is to wrap Ruby exceptions in Java exceptions when we want
+ * to throw them. The error messages match MRI. Note that throwing is different to raising in Ruby,
+ * which is the reason we have both {@link ThrowException} and {@link RaiseException}.
+ */
+public class RaiseException extends RuntimeException {
+
+    private final RubyBasicObject rubyException;
+
+    public RaiseException(RubyBasicObject rubyException) {
+        this.rubyException = rubyException;
+    }
+
+    @Override
+    public String toString() {
+        return rubyException.toString();
+    }
+
+    @Override
+    public String getMessage() {
+        return rubyException.toString();
+    }
+
+    public RubyBasicObject getRubyException() {
+        return rubyException;
+    }
+
+    private static final long serialVersionUID = 7501185855599094740L;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/RedoException.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.control;
+
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Controls re-doing an iteration in a control structure or method.
+ */
+public final class RedoException extends ControlFlowException {
+
+    private static final long serialVersionUID = -4717868827111714052L;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/RetryException.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.control;
+
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Controls re-trying an iteration in a control structure or method.
+ */
+public final class RetryException extends ControlFlowException {
+
+    private static final long serialVersionUID = -1675586631300635765L;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/ReturnException.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.control;
+
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * Controls an explicit return from a method.
+ */
+public final class ReturnException extends ControlFlowException {
+
+    private final long returnID;
+    private final Object value;
+
+    public ReturnException(long returnID, Object value) {
+        assert RubyContext.shouldObjectBeVisible(value);
+
+        this.returnID = returnID;
+        this.value = value;
+    }
+
+    /**
+     * Return the return ID of this return that identifies where it intends to return to.
+     */
+    public long getReturnID() {
+        return returnID;
+    }
+
+    /**
+     * Get the value that has been returned.
+     */
+    public Object getValue() {
+        return value;
+    }
+
+    private static final long serialVersionUID = -9177536212065610691L;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/ThrowException.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.control;
+
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * Controls throwing a value. Note that throwing is different to raising in Ruby, which is the
+ * reason we have both {@link ThrowException} and {@link RaiseException}.
+ */
+public class ThrowException extends ControlFlowException {
+
+    private final Object tag;
+    private final Object value;
+
+    public ThrowException(Object tag, Object value) {
+        assert tag != null;
+        assert RubyContext.shouldObjectBeVisible(value);
+
+        this.tag = tag;
+        this.value = value;
+    }
+
+    public Object getTag() {
+        return tag;
+    }
+
+    public Object getValue() {
+        return value;
+    }
+
+    private static final long serialVersionUID = 8693305627979840677L;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/CoreLibrary.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,649 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core;
+
+import java.io.*;
+import java.math.*;
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+public class CoreLibrary {
+
+    private final RubyContext context;
+
+    private RubyClass argumentErrorClass;
+    private RubyClass arrayClass;
+    private RubyClass basicObjectClass;
+    private RubyClass bignumClass;
+    private RubyClass bindingClass;
+    private RubyClass classClass;
+    private RubyClass continuationClass;
+    private RubyClass dirClass;
+    private RubyClass exceptionClass;
+    private RubyClass falseClass;
+    private RubyClass fiberClass;
+    private RubyClass fileClass;
+    private RubyClass fixnumClass;
+    private RubyClass floatClass;
+    private RubyClass hashClass;
+    private RubyClass integerClass;
+    private RubyClass ioClass;
+    private RubyClass loadErrorClass;
+    private RubyClass localJumpErrorClass;
+    private RubyClass matchDataClass;
+    private RubyClass moduleClass;
+    private RubyClass nameErrorClass;
+    private RubyClass nilClass;
+    private RubyClass noMethodErrorClass;
+    private RubyClass numericClass;
+    private RubyClass objectClass;
+    private RubyClass procClass;
+    private RubyClass processClass;
+    private RubyClass rangeClass;
+    private RubyClass rangeErrorClass;
+    private RubyClass regexpClass;
+    private RubyClass rubyTruffleErrorClass;
+    private RubyClass runtimeErrorClass;
+    private RubyClass standardErrorClass;
+    private RubyClass stringClass;
+    private RubyClass structClass;
+    private RubyClass symbolClass;
+    private RubyClass syntaxErrorClass;
+    private RubyClass systemCallErrorClass;
+    private RubyClass systemExitClass;
+    private RubyClass threadClass;
+    private RubyClass timeClass;
+    private RubyClass trueClass;
+    private RubyClass typeErrorClass;
+    private RubyClass zeroDivisionErrorClass;
+
+    private RubyModule comparableModule;
+    private RubyModule configModule;
+    private RubyModule errnoModule;
+    private RubyModule kernelModule;
+    private RubyModule mathModule;
+    private RubyModule objectSpaceModule;
+    private RubyModule signalModule;
+
+    private RubyModule debugModule;
+    private RubyArray argv;
+    private RubyBasicObject globalVariablesObject;
+    private RubyBasicObject mainObject;
+    private RubyFalseClass falseObject;
+    private RubyNilClass nilObject;
+    private RubyTrueClass trueObject;
+
+    public CoreLibrary(RubyContext context) {
+        this.context = context;
+    }
+
+    public void initialize() {
+        // Create the cyclic classes and modules
+
+        classClass = new RubyClass.RubyClassClass(context);
+        basicObjectClass = new RubyClass(context, classClass, null, null, "BasicObject");
+        objectClass = new RubyClass(null, basicObjectClass, "Object");
+        moduleClass = new RubyModule.RubyModuleClass(context);
+
+        // Close the cycles
+
+        moduleClass.unsafeSetRubyClass(classClass);
+        classClass.unsafeSetSuperclass(moduleClass);
+        moduleClass.unsafeSetSuperclass(objectClass);
+        classClass.unsafeSetRubyClass(classClass);
+
+        // Create all other classes and modules
+
+        numericClass = new RubyClass(null, objectClass, "Numeric");
+        integerClass = new RubyClass(null, numericClass, "Integer");
+
+        exceptionClass = new RubyException.RubyExceptionClass(objectClass, "Exception");
+        standardErrorClass = new RubyException.RubyExceptionClass(exceptionClass, "StandardError");
+
+        ioClass = new RubyClass(null, objectClass, "IO");
+
+        argumentErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "ArgumentError");
+        arrayClass = new RubyArray.RubyArrayClass(objectClass);
+        bignumClass = new RubyClass(null, integerClass, "Bignum");
+        bindingClass = new RubyClass(null, objectClass, "Binding");
+        continuationClass = new RubyClass(null, objectClass, "Continuation");
+        comparableModule = new RubyModule(moduleClass, null, "Comparable");
+        configModule = new RubyModule(moduleClass, null, "Config");
+        debugModule = new RubyModule(moduleClass, null, "Debug");
+        dirClass = new RubyClass(null, objectClass, "Dir");
+        errnoModule = new RubyModule(moduleClass, null, "Errno");
+        falseClass = new RubyClass(null, objectClass, "FalseClass");
+        fiberClass = new RubyFiber.RubyFiberClass(objectClass);
+        fileClass = new RubyClass(null, ioClass, "File");
+        fixnumClass = new RubyClass(null, integerClass, "Fixnum");
+        floatClass = new RubyClass(null, objectClass, "Float");
+        hashClass = new RubyHash.RubyHashClass(objectClass);
+        kernelModule = new RubyModule(moduleClass, null, "Kernel");
+        loadErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "LoadError");
+        localJumpErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "LocalJumpError");
+        matchDataClass = new RubyClass(null, objectClass, "MatchData");
+        mathModule = new RubyModule(moduleClass, null, "Math");
+        nameErrorClass = new RubyClass(null, standardErrorClass, "NameError");
+        nilClass = new RubyClass(null, objectClass, "NilClass");
+        noMethodErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "NoMethodError");
+        objectSpaceModule = new RubyModule(moduleClass, null, "ObjectSpace");
+        procClass = new RubyProc.RubyProcClass(objectClass);
+        processClass = new RubyClass(null, objectClass, "Process");
+        rangeClass = new RubyClass(null, objectClass, "Range");
+        rangeErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "RangeError");
+        regexpClass = new RubyRegexp.RubyRegexpClass(objectClass);
+        rubyTruffleErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "RubyTruffleError");
+        runtimeErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "RuntimeError");
+        stringClass = new RubyString.RubyStringClass(objectClass);
+        structClass = new RubyClass(null, ioClass, "Struct");
+        signalModule = new RubyModule(moduleClass, null, "Signal");
+        symbolClass = new RubyClass(null, objectClass, "Symbol");
+        syntaxErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "SyntaxError");
+        systemCallErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "SystemCallError");
+        systemExitClass = new RubyException.RubyExceptionClass(exceptionClass, "SystemExit");
+        threadClass = new RubyThread.RubyThreadClass(objectClass);
+        timeClass = new RubyTime.RubyTimeClass(objectClass);
+        trueClass = new RubyClass(null, objectClass, "TrueClass");
+        typeErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "TypeError");
+        zeroDivisionErrorClass = new RubyException.RubyExceptionClass(standardErrorClass, "ZeroDivisionError");
+
+        // Includes
+
+        objectClass.include(kernelModule);
+
+        // Set constants
+
+        objectClass.setConstant("RUBY_VERSION", new RubyString(stringClass, context.getConfiguration().getRubyVersion().getVersion()));
+        objectClass.setConstant("RUBY_PATCHLEVEL", context.getConfiguration().getRubyVersion().getPatch());
+        objectClass.setConstant("RUBY_ENGINE", new RubyString(stringClass, "rubytruffle"));
+        objectClass.setConstant("RUBY_PLATFORM", new RubyString(stringClass, "jvm"));
+
+        argv = new RubyArray(arrayClass, new ObjectArrayStore());
+        objectClass.setConstant("ARGV", argv);
+        objectClass.setConstant("ENV", getEnv());
+
+        final RubyHash configHash = new RubyHash(hashClass);
+        configHash.put(new RubyString(stringClass, "ruby_install_name"), new RubyString(stringClass, "rubytruffle"));
+        configHash.put(new RubyString(stringClass, "RUBY_INSTALL_NAME"), new RubyString(stringClass, "rubytruffle"));
+        configHash.put(new RubyString(stringClass, "host_os"), new RubyString(stringClass, "unknown"));
+        configHash.put(new RubyString(stringClass, "exeext"), new RubyString(stringClass, ""));
+        configHash.put(new RubyString(stringClass, "EXEEXT"), new RubyString(stringClass, "rubytruffle"));
+        configModule.setConstant("CONFIG", configHash);
+        objectClass.setConstant("RbConfig", configModule);
+
+        mathModule.setConstant("PI", Math.PI);
+
+        fileClass.setConstant("SEPARATOR", new RubyString(stringClass, File.separator));
+        fileClass.setConstant("Separator", new RubyString(stringClass, File.separator));
+        fileClass.setConstant("ALT_SEPARATOR", NilPlaceholder.INSTANCE);
+        fileClass.setConstant("PATH_SEPARATOR", new RubyString(stringClass, File.pathSeparator));
+        fileClass.setConstant("FNM_SYSCASE", 0);
+
+        errnoModule.setConstant("ENOENT", new RubyClass(null, systemCallErrorClass, "ENOENT"));
+        errnoModule.setConstant("EPERM", new RubyClass(null, systemCallErrorClass, "EPERM"));
+        errnoModule.setConstant("ENOTEMPTY", new RubyClass(null, systemCallErrorClass, "ENOTEMPTY"));
+        errnoModule.setConstant("EEXIST", new RubyClass(null, systemCallErrorClass, "EEXIST"));
+        errnoModule.setConstant("EXDEV", new RubyClass(null, systemCallErrorClass, "EXDEV"));
+        errnoModule.setConstant("EACCES", new RubyClass(null, systemCallErrorClass, "EACCES"));
+
+        // Add all classes and modules as constants in Object
+
+        final RubyModule[] modules = {argumentErrorClass, //
+                        arrayClass, //
+                        basicObjectClass, //
+                        bignumClass, //
+                        bindingClass, //
+                        classClass, //
+                        continuationClass, //
+                        comparableModule, //
+                        configModule, //
+                        debugModule, //
+                        dirClass, //
+                        errnoModule, //
+                        exceptionClass, //
+                        falseClass, //
+                        fiberClass, //
+                        fileClass, //
+                        fixnumClass, //
+                        floatClass, //
+                        hashClass, //
+                        integerClass, //
+                        ioClass, //
+                        kernelModule, //
+                        loadErrorClass, //
+                        localJumpErrorClass, //
+                        matchDataClass, //
+                        mathModule, //
+                        moduleClass, //
+                        nameErrorClass, //
+                        nilClass, //
+                        noMethodErrorClass, //
+                        numericClass, //
+                        objectClass, //
+                        objectSpaceModule, //
+                        procClass, //
+                        processClass, //
+                        rangeClass, //
+                        rangeErrorClass, //
+                        regexpClass, //
+                        rubyTruffleErrorClass, //
+                        runtimeErrorClass, //
+                        signalModule, //
+                        standardErrorClass, //
+                        stringClass, //
+                        structClass, //
+                        symbolClass, //
+                        syntaxErrorClass, //
+                        systemCallErrorClass, //
+                        systemExitClass, //
+                        threadClass, //
+                        timeClass, //
+                        trueClass, //
+                        typeErrorClass, //
+                        zeroDivisionErrorClass};
+
+        for (RubyModule module : modules) {
+            objectClass.setConstant(module.getName(), module);
+        }
+
+        // Create some key objects
+
+        mainObject = new RubyObject(objectClass);
+        nilObject = new RubyNilClass(nilClass);
+        trueObject = new RubyTrueClass(trueClass);
+        falseObject = new RubyFalseClass(falseClass);
+
+        // Create the globals object
+
+        globalVariablesObject = new RubyBasicObject(objectClass);
+        globalVariablesObject.switchToPrivateLayout();
+        globalVariablesObject.setInstanceVariable("$:", new RubyArray(arrayClass, new ObjectArrayStore()));
+    }
+
+    public void initializeAfterMethodsAdded() {
+        bignumClass.getSingletonClass().undefMethod("new");
+        falseClass.getSingletonClass().undefMethod("new");
+        fixnumClass.getSingletonClass().undefMethod("new");
+        floatClass.getSingletonClass().undefMethod("new");
+        integerClass.getSingletonClass().undefMethod("new");
+        nilClass.getSingletonClass().undefMethod("new");
+        numericClass.getSingletonClass().undefMethod("new");
+        trueClass.getSingletonClass().undefMethod("new");
+    }
+
+    public RubyBasicObject box(Object object) {
+        assert RubyContext.shouldObjectBeVisible(object);
+
+        // TODO(cs): pool common object instances like small Fixnums?
+
+        if (object instanceof RubyBasicObject) {
+            return (RubyBasicObject) object;
+        }
+
+        if (object instanceof Boolean) {
+            if ((boolean) object) {
+                return trueObject;
+            } else {
+                return falseObject;
+            }
+        }
+
+        if (object instanceof Integer) {
+            return new RubyFixnum(fixnumClass, (int) object);
+        }
+
+        if (object instanceof BigInteger) {
+            return new RubyBignum(bignumClass, (BigInteger) object);
+        }
+
+        if (object instanceof Double) {
+            return new RubyFloat(floatClass, (double) object);
+        }
+
+        if (object instanceof NilPlaceholder) {
+            return nilObject;
+        }
+
+        CompilerDirectives.transferToInterpreter();
+
+        throw new UnsupportedOperationException("Don't know how to box " + object.getClass().getName());
+    }
+
+    public RubyException runtimeError(String message) {
+        return new RubyException(runtimeErrorClass, message);
+    }
+
+    public RubyException frozenError(String className) {
+        return runtimeError(String.format("can't modify frozen %s", className));
+    }
+
+    public RubyException argumentError(String message) {
+        return new RubyException(argumentErrorClass, message);
+    }
+
+    public RubyException argumentError(int passed, int required) {
+        return argumentError(String.format("wrong number of arguments (%d for %d)", passed, required));
+    }
+
+    public RubyException argumentErrorUncaughtThrow(Object tag) {
+        return argumentError(String.format("uncaught throw `%s'", tag));
+    }
+
+    public RubyException localJumpError(String message) {
+        return new RubyException(localJumpErrorClass, message);
+    }
+
+    public RubyException unexpectedReturn() {
+        return localJumpError("unexpected return");
+    }
+
+    public RubyException typeError(String message) {
+        return new RubyException(typeErrorClass, message);
+    }
+
+    public RubyException typeError(String from, String to) {
+        return typeError(String.format("can't convert %s to %s", from, to));
+    }
+
+    public RubyException typeErrorIsNotA(String value, String expectedType) {
+        return typeError(String.format("%s is not a %s", value, expectedType));
+    }
+
+    public RubyException typeErrorNeedsToBe(String name, String expectedType) {
+        return typeError(String.format("%s needs to be %s", name, expectedType));
+    }
+
+    public RubyException rangeError(String message) {
+        return new RubyException(rangeErrorClass, message);
+    }
+
+    public RubyException nameError(String message) {
+        return new RubyException(nameErrorClass, message);
+    }
+
+    public RubyException nameErrorUninitializedConstant(String name) {
+        return nameError(String.format("uninitialized constant %s", name));
+    }
+
+    public RubyException nameErrorNoMethod(String name, String object) {
+        return nameError(String.format("undefined local variable or method `%s' for %s", name, object));
+    }
+
+    public RubyException nameErrorInstanceNameNotAllowable(String name) {
+        return nameError(String.format("`%s' is not allowable as an instance variable name", name));
+    }
+
+    public RubyException nameErrorUncaughtThrow(Object tag) {
+        return nameError(String.format("uncaught throw `%s'", tag));
+    }
+
+    public RubyException noMethodError(String message) {
+        return new RubyException(context.getCoreLibrary().getNoMethodErrorClass(), message);
+    }
+
+    public RubyException noMethodError(String name, String object) {
+        return noMethodError(String.format("undefined method `%s' for %s", name, object));
+    }
+
+    public RubyException loadError(String message) {
+        return new RubyException(context.getCoreLibrary().getLoadErrorClass(), message);
+    }
+
+    public RubyException loadErrorCannotLoad(String name) {
+        return loadError(String.format("cannot load such file -- %s", name));
+    }
+
+    public RubyException zeroDivisionError() {
+        return new RubyException(context.getCoreLibrary().getZeroDivisionErrorClass(), "divided by 0");
+    }
+
+    public RubyContext getContext() {
+        return context;
+    }
+
+    public RubyClass getArgumentErrorClass() {
+        return argumentErrorClass;
+    }
+
+    public RubyClass getArrayClass() {
+        return arrayClass;
+    }
+
+    public RubyClass getBasicObjectClass() {
+        return basicObjectClass;
+    }
+
+    public RubyClass getBignumClass() {
+        return bignumClass;
+    }
+
+    public RubyClass getBindingClass() {
+        return bindingClass;
+    }
+
+    public RubyClass getClassClass() {
+        return classClass;
+    }
+
+    public RubyModule getComparableClass() {
+        return comparableModule;
+    }
+
+    public RubyClass getContinuationClass() {
+        return continuationClass;
+    }
+
+    public RubyClass getDirClass() {
+        return dirClass;
+    }
+
+    public RubyClass getExceptionClass() {
+        return exceptionClass;
+    }
+
+    public RubyClass getFalseClass() {
+        return falseClass;
+    }
+
+    public RubyClass getFiberClass() {
+        return fiberClass;
+    }
+
+    public RubyClass getFileClass() {
+        return fileClass;
+    }
+
+    public RubyClass getFixnumClass() {
+        return fixnumClass;
+    }
+
+    public RubyClass getFloatClass() {
+        return floatClass;
+    }
+
+    public RubyClass getHashClass() {
+        return hashClass;
+    }
+
+    public RubyClass getIntegerClass() {
+        return integerClass;
+    }
+
+    public RubyClass getIoClass() {
+        return ioClass;
+    }
+
+    public RubyClass getLoadErrorClass() {
+        return loadErrorClass;
+    }
+
+    public RubyClass getLocalJumpErrorClass() {
+        return localJumpErrorClass;
+    }
+
+    public RubyClass getMatchDataClass() {
+        return matchDataClass;
+    }
+
+    public RubyClass getModuleClass() {
+        return moduleClass;
+    }
+
+    public RubyClass getNameErrorClass() {
+        return nameErrorClass;
+    }
+
+    public RubyClass getNilClass() {
+        return nilClass;
+    }
+
+    public RubyClass getNoMethodErrorClass() {
+        return noMethodErrorClass;
+    }
+
+    public RubyClass getNumericClass() {
+        return numericClass;
+    }
+
+    public RubyClass getObjectClass() {
+        return objectClass;
+    }
+
+    public RubyClass getProcClass() {
+        return procClass;
+    }
+
+    public RubyClass getProcessClass() {
+        return processClass;
+    }
+
+    public RubyClass getRangeClass() {
+        return rangeClass;
+    }
+
+    public RubyClass getRangeErrorClass() {
+        return rangeErrorClass;
+    }
+
+    public RubyClass getRegexpClass() {
+        return regexpClass;
+    }
+
+    public RubyClass getRubyTruffleErrorClass() {
+        return rubyTruffleErrorClass;
+    }
+
+    public RubyClass getRuntimeErrorClass() {
+        return runtimeErrorClass;
+    }
+
+    public RubyModule getSignalModule() {
+        return signalModule;
+    }
+
+    public RubyClass getStandardErrorClass() {
+        return standardErrorClass;
+    }
+
+    public RubyClass getStringClass() {
+        return stringClass;
+    }
+
+    public RubyClass getStructClass() {
+        return structClass;
+    }
+
+    public RubyClass getSymbolClass() {
+        return symbolClass;
+    }
+
+    public RubyClass getSyntaxErrorClass() {
+        return syntaxErrorClass;
+    }
+
+    public RubyClass getSystemCallErrorClass() {
+        return systemCallErrorClass;
+    }
+
+    public RubyClass getThreadClass() {
+        return threadClass;
+    }
+
+    public RubyClass getTimeClass() {
+        return timeClass;
+    }
+
+    public RubyClass getTrueClass() {
+        return trueClass;
+    }
+
+    public RubyClass getTypeErrorClass() {
+        return typeErrorClass;
+    }
+
+    public RubyClass getZeroDivisionErrorClass() {
+        return zeroDivisionErrorClass;
+    }
+
+    public RubyModule getKernelModule() {
+        return kernelModule;
+    }
+
+    public RubyModule getMathModule() {
+        return mathModule;
+    }
+
+    public RubyModule getObjectSpaceModule() {
+        return objectSpaceModule;
+    }
+
+    public RubyModule getDebugModule() {
+        return debugModule;
+    }
+
+    public RubyArray getArgv() {
+        return argv;
+    }
+
+    public RubyBasicObject getGlobalVariablesObject() {
+        return globalVariablesObject;
+    }
+
+    public RubyBasicObject getMainObject() {
+        return mainObject;
+    }
+
+    public RubyFalseClass getFalseObject() {
+        return falseObject;
+    }
+
+    public RubyNilClass getNilObject() {
+        return nilObject;
+    }
+
+    public RubyTrueClass getTrueObject() {
+        return trueObject;
+    }
+
+    public RubyHash getEnv() {
+        final RubyHash hash = new RubyHash(context.getCoreLibrary().getHashClass());
+
+        for (Map.Entry<String, String> variable : System.getenv().entrySet()) {
+            hash.put(context.makeString(variable.getKey()), context.makeString(variable.getValue()));
+        }
+
+        return hash;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/GeneralConversions.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core;
+
+import java.math.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+public class GeneralConversions {
+
+    /**
+     * Convert a value to a boolean, without doing any lookup.
+     */
+    public static boolean toBoolean(Object value) {
+        assert value != null;
+
+        if (value instanceof NilPlaceholder) {
+            return false;
+        }
+
+        if (value instanceof Boolean) {
+            return (boolean) value;
+        }
+
+        if (value instanceof RubyTrueClass) {
+            return true;
+        }
+
+        if (value instanceof RubyFalseClass) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Convert a value to a {@code Fixnum}, without doing any lookup.
+     */
+    public static int toFixnum(Object value) {
+        assert value != null;
+
+        if (value instanceof NilPlaceholder || value instanceof RubyNilClass) {
+            return 0;
+        }
+
+        if (value instanceof Integer) {
+            return (int) value;
+        }
+
+        if (value instanceof RubyFixnum) {
+            return ((RubyFixnum) value).getValue();
+        }
+
+        if (value instanceof BigInteger) {
+            throw new UnsupportedOperationException();
+        }
+
+        if (value instanceof RubyBignum) {
+            throw new UnsupportedOperationException();
+        }
+
+        if (value instanceof Double) {
+            return (int) (double) value;
+        }
+
+        if (value instanceof RubyFloat) {
+            return (int) ((RubyFloat) value).getValue();
+        }
+
+        CompilerDirectives.transferToInterpreter();
+
+        throw new UnsupportedOperationException(value.getClass().toString());
+    }
+
+    /**
+     * Convert a value to a {@code Float}, without doing any lookup.
+     */
+    public static double toFloat(Object value) {
+        assert value != null;
+
+        if (value instanceof NilPlaceholder || value instanceof RubyNilClass) {
+            return 0;
+        }
+
+        if (value instanceof Integer) {
+            return (int) value;
+        }
+
+        if (value instanceof RubyFixnum) {
+            return ((RubyFixnum) value).getValue();
+        }
+
+        if (value instanceof BigInteger) {
+            return ((BigInteger) value).doubleValue();
+        }
+
+        if (value instanceof RubyBignum) {
+            return ((RubyBignum) value).getValue().doubleValue();
+        }
+
+        if (value instanceof Double) {
+            return (double) value;
+        }
+
+        if (value instanceof RubyFloat) {
+            return ((RubyFloat) value).getValue();
+        }
+
+        CompilerDirectives.transferToInterpreter();
+
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Given a {@link BigInteger} value, produce either a {@code Fixnum} or {@code Bignum} .
+     */
+    public static Object fixnumOrBignum(BigInteger value) {
+        assert value != null;
+
+        if (value.compareTo(RubyFixnum.MIN_VALUE_BIG) >= 0 && value.compareTo(RubyFixnum.MAX_VALUE_BIG) <= 0) {
+            return value.intValue();
+        } else {
+            return value;
+        }
+    }
+
+    /**
+     * Given a {@code long} value, produce either a {@code Fixnum} or {@code Bignum} .
+     */
+    public static Object fixnumOrBignum(long value) {
+        if (value >= RubyFixnum.MIN_VALUE && value <= RubyFixnum.MAX_VALUE) {
+            return (int) value;
+        } else {
+            return BigInteger.valueOf(value);
+        }
+    }
+
+    /**
+     * Given a reference, produce either {@code nil} or the object. .
+     */
+    public static Object instanceOrNil(Object object) {
+        if (object == null) {
+            return NilPlaceholder.INSTANCE;
+        } else {
+            return object;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyBignum.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core;
+
+import java.math.*;
+
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Represents the Ruby {@code Bignum} class.
+ */
+public class RubyBignum extends RubyObject implements Unboxable {
+
+    private final BigInteger value;
+
+    public RubyBignum(RubyClass bignumClass, BigInteger value) {
+        super(bignumClass);
+
+        assert value != null;
+
+        this.value = value;
+    }
+
+    public BigInteger getValue() {
+        return value;
+    }
+
+    public Object unbox() {
+        return value;
+    }
+
+    public static RubyArray divMod(RubyContext context, BigInteger a, BigInteger b) {
+        final BigInteger[] quotientRemainder = a.divideAndRemainder(b);
+
+        final Object quotient = GeneralConversions.fixnumOrBignum(quotientRemainder[0]);
+        final Object remainder = GeneralConversions.fixnumOrBignum(quotientRemainder[1]);
+
+        final ObjectImmutablePairArrayStore store = new ObjectImmutablePairArrayStore(quotient, remainder);
+        return new RubyArray(context.getCoreLibrary().getArrayClass(), store);
+    }
+
+    @Override
+    public int hashCode() {
+        return value.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof RubyBignum)) {
+            return false;
+        }
+        RubyBignum other = (RubyBignum) obj;
+        if (value == null) {
+            if (other.value != null) {
+                return false;
+            }
+        } else if (!value.equals(other.value)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return value.toString();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyBinding.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core;
+
+import com.oracle.truffle.api.frame.*;
+
+/**
+ * Represents the Ruby {@code Binding} class.
+ */
+public class RubyBinding extends RubyObject {
+
+    private final Object self;
+    private final MaterializedFrame frame;
+
+    public RubyBinding(RubyClass bindingClass, Object self, MaterializedFrame frame) {
+        super(bindingClass);
+
+        assert self != null;
+        assert frame != null;
+
+        this.self = self;
+        this.frame = frame;
+    }
+
+    public Object getSelf() {
+        return self;
+    }
+
+    public MaterializedFrame getFrame() {
+        return frame;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyClass.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core;
+
+import java.util.*;
+
+import com.oracle.truffle.api.CompilerDirectives.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.lookup.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Represents the Ruby {@code Class} class. Note that most of the functionality you might associate
+ * with {@code Class} is actually in {@code Module}, implemented by {@link RubyModule}.
+ */
+public class RubyClass extends RubyModule {
+
+    /**
+     * The class from which we create the object that is {@code Class}. A subclass of
+     * {@link RubyClass} so that we can override {@link #newInstance} and allocate a
+     * {@link RubyClass} rather than a normal {@link RubyBasicObject}.
+     */
+    public static class RubyClassClass extends RubyClass {
+
+        public RubyClassClass(RubyContext context) {
+            super(context, null, null, null, "Class");
+        }
+
+        @Override
+        public RubyBasicObject newInstance() {
+            return new RubyClass(null, getContext().getCoreLibrary().getObjectClass(), "(unnamed class)");
+        }
+
+    }
+
+    @CompilationFinal private RubyClass superclass;
+
+    // We maintain a list of subclasses so we can notify them when they need to update their layout.
+    private final Set<RubyClass> subClasses = Collections.newSetFromMap(new WeakHashMap<RubyClass, Boolean>());
+
+    /*
+     * The layout to use for instances of this class - do not confuse with objectLayout, which is
+     * the layout for this object - the class.
+     */
+    private ObjectLayout objectLayoutForInstances = null;
+
+    public RubyClass(RubyModule parentModule, RubyClass rubySuperclass, String name) {
+        this(parentModule, rubySuperclass, name, false);
+    }
+
+    public RubyClass(RubyModule parentModule, RubyClass rubySuperclass, String name, boolean isSingleton) {
+        this(rubySuperclass.getContext(), rubySuperclass.getContext().getCoreLibrary().getClassClass(), parentModule, rubySuperclass, name);
+
+        if (!isSingleton) {
+            getSingletonClass();
+        }
+    }
+
+    /**
+     * This constructor supports initialization and solves boot-order problems and should not
+     * normally be used from outside this class.
+     */
+    public RubyClass(RubyContext context, RubyClass classClass, RubyModule parentModule, RubyClass superclass, String name) {
+        super(context, classClass, parentModule, name);
+
+        if (superclass == null) {
+            objectLayoutForInstances = ObjectLayout.EMPTY;
+        } else {
+            unsafeSetSuperclass(superclass);
+        }
+    }
+
+    public RubyClass getSuperclass() {
+        assert superclass != null;
+        return superclass;
+    }
+
+    @Override
+    public RubyClass getSingletonClass() {
+        if (rubySingletonClass == null) {
+            RubyClass singletonSuperclass;
+
+            if (superclass == null) {
+                singletonSuperclass = getRubyClass();
+            } else {
+                singletonSuperclass = superclass.getSingletonClass();
+            }
+
+            rubySingletonClass = new RubyClass(getParentModule(), singletonSuperclass, String.format("#<Class:%s>", getName()), true);
+
+            lookupNode = new LookupFork(rubySingletonClass, lookupNode);
+        }
+
+        return rubySingletonClass;
+    }
+
+    /**
+     * This method supports initialization and solves boot-order problems and should not normally be
+     * used.
+     */
+    public void unsafeSetSuperclass(RubyClass newSuperclass) {
+        assert superclass == null;
+
+        superclass = newSuperclass;
+        superclass.addDependent(this);
+        superclass.subClasses.add(this);
+
+        include(superclass);
+
+        objectLayoutForInstances = new ObjectLayout(getName(), getContext(), superclass.objectLayoutForInstances);
+    }
+
+    public RubyBasicObject newInstance() {
+        return new RubyObject(this);
+    }
+
+    /**
+     * Is an instance of this class assignable to some location expecting some other class?
+     */
+    public boolean assignableTo(RubyClass otherClass) {
+        if (this == otherClass) {
+            return true;
+        }
+
+        if (superclass == null) {
+            return false;
+        }
+
+        return superclass.assignableTo(otherClass);
+    }
+
+    /**
+     * Returns the object layout that objects of this class should use. Do not confuse with
+     * {@link #getObjectLayout}, which for {@link RubyClass} will return the layout of the class
+     * object itself.
+     */
+    public ObjectLayout getObjectLayoutForInstances() {
+        return objectLayoutForInstances;
+    }
+
+    /**
+     * Change the layout to be used for instances of this object.
+     */
+    public void setObjectLayoutForInstances(ObjectLayout newObjectLayoutForInstances) {
+        objectLayoutForInstances = newObjectLayoutForInstances;
+
+        for (RubyClass subClass : subClasses) {
+            subClass.renewObjectLayoutForInstances();
+        }
+    }
+
+    private void renewObjectLayoutForInstances() {
+        objectLayoutForInstances = objectLayoutForInstances.renew(getContext(), superclass.objectLayoutForInstances);
+
+        for (RubyClass subClass : subClasses) {
+            subClass.renewObjectLayoutForInstances();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyContinuation.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core;
+
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+/**
+ * Represents the Ruby {@code Continuation} class. We only support continuations that just move up
+ * the stack and are one-shot.
+ */
+public class RubyContinuation extends RubyObject {
+
+    /*
+     * A continuation is dead if we have already resumed it once. We will not be able to resume it
+     * again due to the current implementation being an exception thrown to go back up the stack.
+     */
+    private boolean dead = false;
+
+    public RubyContinuation(RubyClass rubyClass) {
+        super(rubyClass);
+    }
+
+    /**
+     * To enter a continuation means to remember the execution state at this point, reify that into
+     * an object, and then call the passed block. For our implementation, the continuation will be
+     * dead when this method resumes.
+     */
+    public Object enter(RubyProc block) {
+        try {
+            return block.call(null, this);
+        } catch (ContinuationReturnException e) {
+            // Thrown in call
+
+            // Check the exception is for this continuation
+
+            if (e.getContinuation() == this) {
+                return e.getValue();
+            } else {
+                throw e;
+            }
+        } finally {
+            dead = true;
+        }
+    }
+
+    /**
+     * To call a continuation means to go back to the execution state when it was created. For our
+     * implementation we can only do this once, and only if that means jumping back up the stack.
+     */
+    public void call(Object... args) {
+        if (dead) {
+            throw new UnsupportedOperationException("Only continuations that just move up the stack and are one-shot are supported");
+        }
+
+        Object returnValue;
+
+        if (args.length == 0) {
+            returnValue = NilPlaceholder.INSTANCE;
+        } else if (args.length == 1) {
+            returnValue = args[0];
+        } else {
+            returnValue = RubyArray.specializedFromObjects(getRubyClass().getContext().getCoreLibrary().getArrayClass(), args);
+        }
+
+        // Caught in enter
+
+        throw new ContinuationReturnException(this, returnValue);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyException.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core;
+
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Represents the Ruby {@code Exception} class.
+ */
+public class RubyException extends RubyObject {
+
+    /**
+     * The class from which we create the object that is {@code Exception}. A subclass of
+     * {@link RubyClass} so that we can override {@link #newInstance} and allocate a
+     * {@link RubyException} rather than a normal {@link RubyBasicObject}.
+     */
+    public static class RubyExceptionClass extends RubyClass {
+
+        public RubyExceptionClass(RubyClass superClass, String name) {
+            super(null, superClass, name);
+        }
+
+        @Override
+        public RubyBasicObject newInstance() {
+            return new RubyException(this);
+        }
+
+    }
+
+    private RubyString message;
+
+    public RubyException(RubyClass rubyClass) {
+        super(rubyClass);
+        message = rubyClass.getContext().makeString("(object uninitialized)");
+    }
+
+    public RubyException(RubyClass rubyClass, String message) {
+        this(rubyClass, rubyClass.getContext().makeString(message));
+    }
+
+    public RubyException(RubyClass rubyClass, RubyString message) {
+        this(rubyClass);
+        initialize(message);
+    }
+
+    public void initialize(RubyString setMessage) {
+        assert setMessage != null;
+        message = setMessage;
+    }
+
+    public RubyString getMessage() {
+        return message;
+    }
+
+    @Override
+    public String toString() {
+        return message.toString();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyFalseClass.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core;
+
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Represents the Ruby {@code FalseClass} class.
+ */
+public class RubyFalseClass extends RubyObject implements Unboxable {
+
+    public RubyFalseClass(RubyClass objectClass) {
+        super(objectClass);
+    }
+
+    public Object unbox() {
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return "false";
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        return other instanceof RubyFalseClass || (other instanceof Boolean && !((boolean) other));
+    }
+
+    @Override
+    public int hashCode() {
+        return Boolean.FALSE.hashCode();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyFiber.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core;
+
+import java.util.concurrent.*;
+
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+import com.oracle.truffle.ruby.runtime.subsystems.*;
+
+/**
+ * Represents the Ruby {@code Fiber} class. The current implementation uses Java threads and message
+ * passing. Note that the relationship between Java threads, Ruby threads and Ruby fibers is
+ * complex. A Java thread might be running a fiber that on difference resumptions is representing
+ * different Ruby threads. Take note of the lock contracts on {@link #waitForResume} and
+ * {@link #resume}.
+ */
+public class RubyFiber extends RubyObject {
+
+    public static class RubyFiberClass extends RubyClass {
+
+        public RubyFiberClass(RubyClass objectClass) {
+            super(null, objectClass, "Fiber");
+        }
+
+        @Override
+        public RubyBasicObject newInstance() {
+            return new RubyFiber(this, getContext().getFiberManager(), getContext().getThreadManager());
+        }
+
+    }
+
+    private interface FiberMessage {
+    }
+
+    private class FiberResumeMessage implements FiberMessage {
+
+        private final RubyThread thread;
+        private final RubyFiber sendingFiber;
+        private final Object arg;
+
+        public FiberResumeMessage(RubyThread thread, RubyFiber sendingFiber, Object arg) {
+            this.thread = thread;
+            this.sendingFiber = sendingFiber;
+            this.arg = arg;
+        }
+
+        public RubyThread getThread() {
+            return thread;
+        }
+
+        public RubyFiber getSendingFiber() {
+            return sendingFiber;
+        }
+
+        public Object getArg() {
+            return arg;
+        }
+
+    }
+
+    private class FiberExitMessage implements FiberMessage {
+    }
+
+    public class FiberExitException extends ControlFlowException {
+
+        private static final long serialVersionUID = 1522270454305076317L;
+
+    }
+
+    private final FiberManager fiberManager;
+    private final ThreadManager threadManager;
+
+    private BlockingQueue<FiberMessage> messageQueue = new ArrayBlockingQueue<>(1);
+    public RubyFiber lastResumedByFiber = null;
+
+    public RubyFiber(RubyClass rubyClass, FiberManager fiberManager, ThreadManager threadManager) {
+        super(rubyClass);
+        this.fiberManager = fiberManager;
+        this.threadManager = threadManager;
+    }
+
+    public void initialize(RubyProc block) {
+        final RubyFiber finalFiber = this;
+        final RubyProc finalBlock = block;
+
+        new Thread(new Runnable() {
+
+            @Override
+            public void run() {
+                fiberManager.registerFiber(finalFiber);
+
+                try {
+                    try {
+                        final Object arg = finalFiber.waitForResume();
+                        final Object result = finalBlock.call(null, arg);
+                        finalFiber.lastResumedByFiber.resume(finalFiber, result);
+                    } catch (FiberExitException e) {
+                        // Naturally exit the thread on catching this
+                    }
+                } finally {
+                    fiberManager.unregisterFiber(finalFiber);
+                }
+            }
+
+        }).start();
+    }
+
+    /**
+     * Send the Java thread that represents this fiber to sleep until it recieves a resume or exit
+     * message. On entry, assumes that the GIL is not held. On exit, holding the GIL.
+     */
+    public Object waitForResume() {
+        FiberMessage message = null;
+
+        do {
+            try {
+                // TODO(cs) what is a suitable timeout?
+                message = messageQueue.poll(1, TimeUnit.SECONDS);
+            } catch (InterruptedException e) {
+                // Poll again
+            }
+        } while (message == null);
+
+        if (message instanceof FiberExitMessage) {
+            throw new FiberExitException();
+        }
+
+        final FiberResumeMessage resumeMessage = (FiberResumeMessage) message;
+
+        threadManager.enterGlobalLock(resumeMessage.getThread());
+
+        fiberManager.setCurrentFiber(this);
+
+        lastResumedByFiber = resumeMessage.getSendingFiber();
+        return resumeMessage.getArg();
+    }
+
+    /**
+     * Send a message to a fiber by posting into a message queue. Doesn't explicitly notify the Java
+     * thread (although the queue implementation may) and doesn't wait for the message to be
+     * received. On entry, assumes the the GIL is held. On exit, not holding the GIL.
+     */
+    public void resume(RubyFiber sendingFiber, Object... args) {
+        Object arg;
+
+        if (args.length == 0) {
+            arg = NilPlaceholder.INSTANCE;
+        } else if (args.length == 1) {
+            arg = args[0];
+        } else {
+            arg = RubyArray.specializedFromObjects(getRubyClass().getContext().getCoreLibrary().getArrayClass(), args);
+        }
+
+        final RubyThread runningThread = threadManager.leaveGlobalLock();
+
+        messageQueue.add(new FiberResumeMessage(runningThread, sendingFiber, arg));
+    }
+
+    public void shutdown() {
+        messageQueue.add(new FiberExitMessage());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyFile.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core;
+
+import java.io.*;
+
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * Represents the Ruby {@code File} class.
+ */
+public class RubyFile extends RubyObject {
+
+    private final Reader reader;
+    private final Writer writer;
+
+    public RubyFile(RubyClass rubyClass, Reader reader, Writer writer) {
+        super(rubyClass);
+        this.reader = reader;
+        this.writer = writer;
+    }
+
+    public void close() {
+        if (reader != null) {
+            try {
+                reader.close();
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        if (writer != null) {
+            try {
+                writer.close();
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    public static String expandPath(String fileName) {
+        // TODO(cs): see the other expandPath
+
+        try {
+            return new File(fileName).getCanonicalPath();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static String expandPath(String fileName, String dir) {
+        /*
+         * TODO(cs): this isn't quite correct - I think we want to collapse .., but we don't want to
+         * resolve symlinks etc. This might be where we want to start borrowing JRuby's
+         * implementation, but it looks quite tied to their data structures.
+         */
+
+        try {
+            return new File(dir, fileName).getCanonicalPath();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static RubyFile open(RubyContext context, String fileName, String mode) {
+        Reader reader;
+        Writer writer;
+
+        if (mode.equals("rb")) {
+            try {
+                reader = new InputStreamReader(new FileInputStream(fileName));
+            } catch (FileNotFoundException e) {
+                throw new RuntimeException(e);
+            }
+
+            writer = null;
+        } else if (mode.equals("w")) {
+            reader = null;
+
+            try {
+                writer = new OutputStreamWriter(new FileOutputStream(fileName));
+            } catch (FileNotFoundException e) {
+                throw new RuntimeException(e);
+            }
+        } else {
+            throw new UnsupportedOperationException();
+        }
+
+        final RubyFile file = new RubyFile(context.getCoreLibrary().getFileClass(), reader, writer);
+
+        return file;
+    }
+
+    public Reader getReader() {
+        return reader;
+    }
+
+    public Writer getWriter() {
+        return writer;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyFixnum.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core;
+
+import java.math.*;
+
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Represents the Ruby {@code Fixnum} class.
+ */
+public class RubyFixnum extends RubyObject implements Unboxable {
+
+    public static final int MIN_VALUE = Integer.MIN_VALUE;
+    public static final int MAX_VALUE = Integer.MAX_VALUE;
+
+    public static final BigInteger MIN_VALUE_BIG = BigInteger.valueOf(MIN_VALUE);
+    public static final BigInteger MAX_VALUE_BIG = BigInteger.valueOf(MAX_VALUE);
+
+    public static final int SIZE = Integer.SIZE;
+
+    private final int value;
+
+    public RubyFixnum(RubyClass fixnumClass, int value) {
+        super(fixnumClass);
+        this.value = value;
+    }
+
+    public int getValue() {
+        return value;
+    }
+
+    @Override
+    public String toString() {
+        return Integer.toString(value);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (other instanceof Integer) {
+            return value == (int) other;
+        } else if (other instanceof RubyFixnum) {
+            return value == ((RubyFixnum) other).value;
+        } else if (other instanceof BigInteger) {
+            return ((BigInteger) other).equals(value);
+        } else if (other instanceof RubyBignum) {
+            return ((RubyBignum) other).getValue().equals(value);
+        } else if (other instanceof Double) {
+            return value == (double) other;
+        } else if (other instanceof RubyFloat) {
+            return value == ((RubyFloat) other).getValue();
+        } else {
+            return super.equals(other);
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        throw new UnsupportedOperationException();
+    }
+
+    public Object unbox() {
+        return value;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyFloat.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core;
+
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Represents the Ruby {@code Float} class.
+ */
+public class RubyFloat extends RubyObject implements Unboxable {
+
+    private final double value;
+
+    public RubyFloat(RubyClass floatClass, double value) {
+        super(floatClass);
+        this.value = value;
+    }
+
+    public double getValue() {
+        return value;
+    }
+
+    @Override
+    public String toString() {
+        return Double.toString(value);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (other instanceof Integer) {
+            return value == (int) other;
+        } else if (other instanceof RubyFixnum) {
+            return value == ((RubyFixnum) other).getValue();
+        } else if (other instanceof Double) {
+            return value == (double) other;
+        } else if (other instanceof RubyFloat) {
+            return value == ((RubyFloat) other).value;
+        } else {
+            return super.equals(other);
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        throw new UnsupportedOperationException();
+    }
+
+    public Object unbox() {
+        return value;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyHash.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core;
+
+import java.util.*;
+
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Represents the Ruby {@code Hash} class.
+ */
+public class RubyHash extends RubyObject {
+
+    /**
+     * The class from which we create the object that is {@code Hash}. A subclass of
+     * {@link RubyClass} so that we can override {@link #newInstance} and allocate a
+     * {@link RubyHash} rather than a normal {@link RubyBasicObject}.
+     */
+    public static class RubyHashClass extends RubyClass {
+
+        public RubyHashClass(RubyClass objectClass) {
+            super(null, objectClass, "Hash");
+        }
+
+        @Override
+        public RubyBasicObject newInstance() {
+            return new RubyHash(this);
+        }
+
+    }
+
+    public final Map<Object, Object> storage = new LinkedHashMap<>();
+    @CompilationFinal public RubyProc defaultBlock = null;
+
+    public RubyHash(RubyClass rubyClass, RubyProc defaultBlock) {
+        super(rubyClass);
+        initialize(defaultBlock);
+    }
+
+    public RubyHash(RubyClass rubyClass) {
+        super(rubyClass);
+    }
+
+    public void initialize(RubyProc setDefaultBlock) {
+        defaultBlock = setDefaultBlock;
+    }
+
+    @Override
+    public Object dup() {
+        final RubyHash newHash = new RubyHash(rubyClass);
+        newHash.setInstanceVariables(getInstanceVariables());
+        newHash.storage.putAll(storage);
+        return newHash;
+    }
+
+    public void put(Object key, Object value) {
+        checkFrozen();
+
+        storage.put(key, value);
+    }
+
+    public Object get(Object key) {
+        return storage.get(key);
+    }
+
+    public Map<Object, Object> getMap() {
+        return storage;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append("{");
+
+        for (Map.Entry<Object, Object> entry : storage.entrySet()) {
+            if (builder.length() > 1) {
+                builder.append(", ");
+            }
+
+            builder.append(entry.getKey().toString());
+            builder.append("=>");
+            builder.append(entry.getValue().toString());
+        }
+
+        builder.append("}");
+        return builder.toString();
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((storage == null) ? 0 : storage.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof RubyHash)) {
+            return false;
+        }
+        RubyHash other = (RubyHash) obj;
+        if (storage == null) {
+            if (other.storage != null) {
+                return false;
+            }
+        } else if (!storage.equals(other.storage)) {
+            return false;
+        }
+        return true;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyMatchData.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core;
+
+/**
+ * Represents the Ruby {@code MatchData} class.
+ */
+public class RubyMatchData extends RubyObject {
+
+    private final Object[] values;
+
+    public RubyMatchData(RubyClass rubyClass, Object[] values) {
+        super(rubyClass);
+        this.values = values;
+    }
+
+    public Object[] valuesAt(int... indices) {
+        final Object[] result = new Object[indices.length];
+
+        for (int n = 0; n < indices.length; n++) {
+            result[n] = values[indices[n]];
+        }
+
+        return result;
+    }
+
+    public Object[] getValues() {
+        return values;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyModule.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core;
+
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.utilities.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.lookup.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Represents the Ruby {@code Module} class.
+ */
+public class RubyModule extends RubyObject implements LookupNode {
+
+    /**
+     * The class from which we create the object that is {@code Module}. A subclass of
+     * {@link RubyClass} so that we can override {@link #newInstance} and allocate a
+     * {@link RubyModule} rather than a normal {@link RubyBasicObject}.
+     */
+    public static class RubyModuleClass extends RubyClass {
+
+        public RubyModuleClass(RubyContext context) {
+            super(context, null, null, null, "Module");
+        }
+
+        @Override
+        public RubyBasicObject newInstance() {
+            return new RubyModule(this, null, "(unnamed module)");
+        }
+
+    }
+
+    /**
+     * The slot within a module definition method frame where we store the implicit state that is
+     * the current visibility for new methods.
+     */
+    public static final Object VISIBILITY_FRAME_SLOT_ID = new Object();
+
+    /**
+     * The slot within a module definition method frame where we store the implicit state that is
+     * the flag for whether or not new methods will be module methods (functions is the term).
+     */
+    public static final Object MODULE_FUNCTION_FLAG_FRAME_SLOT_ID = new Object();
+
+    // The context is stored here - objects can obtain it via their class (which is a module)
+    private final RubyContext context;
+
+    /*
+     * The module in which this module was defined. By analogy, if superclass is the dynamic scope,
+     * the parent module is the lexical scope.
+     */
+    private final RubyModule parentModule;
+
+    /*
+     * The first thing to lookup names in. Not always the class, as we also have singleton classes,
+     * included modules etc.
+     */
+    private LookupNode lookupParent = LookupTerminal.INSTANCE;
+
+    private final String name;
+    private final Map<String, RubyMethod> methods = new HashMap<>();
+    private final Map<String, Object> constants = new HashMap<>();
+    private final Map<String, Object> classVariables = new HashMap<>();
+
+    private final CyclicAssumption unmodifiedAssumption;
+
+    /**
+     * Keep track of other modules that depend on the configuration of this module in some way. The
+     * include subclasses and modules that include this module.
+     */
+    private final Set<RubyModule> dependents = Collections.newSetFromMap(new WeakHashMap<RubyModule, Boolean>());
+
+    public RubyModule(RubyClass rubyClass, RubyModule parentModule, String name) {
+        this(rubyClass.getContext(), rubyClass, parentModule, name);
+    }
+
+    public RubyModule(RubyContext context, RubyClass rubyClass, RubyModule parentModule, String name) {
+        super(rubyClass);
+
+        this.context = context;
+        this.parentModule = parentModule;
+        this.name = name;
+
+        unmodifiedAssumption = new CyclicAssumption(name + " is unmodified");
+
+        /*
+         * Modules always go into the object space manager. Manually allocate an objectID, because
+         * the lazy mechanism uses the Ruby class of the object, which may not be set yet during
+         * bootstrap.
+         */
+
+        objectID = context.getNextObjectID();
+        context.getObjectSpaceManager().add(this);
+    }
+
+    public RubyModule getParentModule() {
+        return parentModule;
+    }
+
+    public void include(RubyModule module) {
+        checkFrozen();
+
+        lookupParent = new LookupFork(module, lookupParent);
+        newVersion();
+        module.addDependent(this);
+    }
+
+    /**
+     * Set the value of a constant, possibly redefining it.
+     */
+    public void setConstant(String constantName, Object value) {
+        assert RubyContext.shouldObjectBeVisible(value);
+
+        checkFrozen();
+
+        getConstants().put(constantName, value);
+        newVersion();
+        // TODO(CS): warn when redefining a constant
+    }
+
+    public void setClassVariable(String variableName, Object value) {
+        assert RubyContext.shouldObjectBeVisible(value);
+
+        checkFrozen();
+
+        if (!setClassVariableIfAlreadySet(variableName, value)) {
+            classVariables.put(variableName, value);
+        }
+    }
+
+    public boolean setClassVariableIfAlreadySet(String variableName, Object value) {
+        assert RubyContext.shouldObjectBeVisible(value);
+
+        checkFrozen();
+
+        if (lookupParent.setClassVariableIfAlreadySet(variableName, value)) {
+            return true;
+        }
+
+        if (classVariables.containsKey(variableName)) {
+            classVariables.put(variableName, value);
+            return true;
+        }
+
+        return false;
+    }
+
+    public void removeClassVariable(String variableName) {
+        checkFrozen();
+
+        classVariables.remove(variableName);
+    }
+
+    public void setModuleConstant(String constantName, Object value) {
+        checkFrozen();
+
+        setConstant(constantName, value);
+        getSingletonClass().setConstant(constantName, value);
+    }
+
+    public void addMethod(RubyMethod method) {
+        checkFrozen();
+        getMethods().put(method.getName(), method);
+        newVersion();
+    }
+
+    /**
+     * Remove a method from this module.
+     */
+    public void removeMethod(String methodName) {
+        checkFrozen();
+
+        getMethods().remove(methodName);
+        newVersion();
+    }
+
+    public void undefMethod(String methodName) {
+        undefMethod(lookupMethod(methodName));
+    }
+
+    public void undefMethod(RubyMethod method) {
+        addMethod(method.undefined());
+    }
+
+    /**
+     * Alias a method.
+     */
+    public void alias(String newName, String oldName) {
+        final RubyMethod method = lookupMethod(oldName);
+
+        if (method == null) {
+            CompilerDirectives.transferToInterpreter();
+            throw new RuntimeException("Couldn't alias as coudln't find " + oldName);
+        }
+
+        addMethod(method.withNewName(newName));
+    }
+
+    @Override
+    public Object lookupConstant(String constantName) {
+        Object value;
+
+        // Look in this module
+
+        value = getConstants().get(constantName);
+
+        if (value != null) {
+            return value;
+        }
+
+        // Look in the parent module
+
+        if (parentModule != null) {
+            value = parentModule.lookupConstant(constantName);
+
+            if (value != null) {
+                return value;
+            }
+        }
+
+        // Look in the lookup parent
+
+        return lookupParent.lookupConstant(constantName);
+    }
+
+    @Override
+    public Object lookupClassVariable(String variableName) {
+        // Look in this module
+
+        final Object value = classVariables.get(variableName);
+
+        if (value != null) {
+            return value;
+        }
+
+        // Look in the parent
+
+        return lookupParent.lookupClassVariable(variableName);
+    }
+
+    public Set<String> getClassVariables() {
+        final Set<String> classVariablesSet = new HashSet<>();
+
+        classVariablesSet.addAll(classVariables.keySet());
+        classVariablesSet.addAll(lookupParent.getClassVariables());
+
+        return classVariablesSet;
+    }
+
+    @Override
+    public RubyMethod lookupMethod(String methodName) {
+        // Look in this module
+
+        final RubyMethod method = getMethods().get(methodName);
+
+        if (method != null) {
+            return method;
+        }
+
+        // Look in the parent
+
+        return lookupParent.lookupMethod(methodName);
+    }
+
+    public void appendFeatures(RubyModule other) {
+        // TODO(CS): check only run once
+
+        for (Map.Entry<String, Object> constantEntry : getConstants().entrySet()) {
+            final String constantName = constantEntry.getKey();
+            final Object constantValue = constantEntry.getValue();
+            other.setModuleConstant(constantName, constantValue);
+        }
+
+        for (Map.Entry<String, RubyMethod> methodEntry : getMethods().entrySet()) {
+            final String methodName = methodEntry.getKey();
+            final RubyMethod method = methodEntry.getValue();
+            other.addMethod(method.withNewName(methodName));
+        }
+    }
+
+    public RubyContext getContext() {
+        return context;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public int hashCode() {
+        return name.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return name;
+    }
+
+    public void newVersion() {
+        unmodifiedAssumption.invalidate();
+
+        // Make dependents new versions
+
+        for (RubyModule dependent : dependents) {
+            dependent.newVersion();
+        }
+    }
+
+    public void addDependent(RubyModule dependent) {
+        dependents.add(dependent);
+    }
+
+    public Assumption getUnmodifiedAssumption() {
+        return unmodifiedAssumption.getAssumption();
+    }
+
+    public void getMethods(Map<String, RubyMethod> foundMethods) {
+        lookupParent.getMethods(foundMethods);
+
+        for (RubyMethod method : methods.values()) {
+            foundMethods.put(method.getName(), method);
+        }
+    }
+
+    public static void setCurrentVisibility(Frame frame, Visibility visibility) {
+        final FrameSlot slot = frame.getFrameDescriptor().findFrameSlot(VISIBILITY_FRAME_SLOT_ID);
+
+        frame.setObject(slot, visibility);
+    }
+
+    public void visibilityMethod(PackedFrame frame, Object[] arguments, Visibility visibility) {
+        if (arguments.length == 0) {
+            setCurrentVisibility(frame.unpack(), visibility);
+        } else {
+            for (Object arg : arguments) {
+                final RubyMethod method = lookupMethod(arg.toString());
+
+                if (method == null) {
+                    throw new RuntimeException("Couldn't find method " + arg.toString());
+                }
+
+                /*
+                 * If the method was already defined in this class, that's fine {@link addMethod}
+                 * will overwrite it, otherwise we do actually want to add a copy of the method with
+                 * a different visibility to this module.
+                 */
+
+                addMethod(method.withNewVisibility(visibility));
+            }
+        }
+    }
+
+    public List<RubyMethod> getDeclaredMethods() {
+        return new ArrayList<>(getMethods().values());
+    }
+
+    public void moduleEval(String source) {
+        getRubyClass().getContext().eval(source, this);
+    }
+
+    public Map<String, Object> getConstants() {
+        return constants;
+    }
+
+    public Map<String, RubyMethod> getMethods() {
+        return methods;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyNilClass.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core;
+
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * Represents the Ruby {@code NilClass} class.
+ */
+public class RubyNilClass extends RubyObject {
+
+    public RubyNilClass(RubyClass rubyClass) {
+        super(rubyClass);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        return other instanceof RubyNilClass || other instanceof NilPlaceholder;
+    }
+
+    @Override
+    public int hashCode() {
+        return 0;
+    }
+
+    public static boolean isNil(Object block) {
+        return block instanceof NilPlaceholder || block instanceof RubyNilClass;
+    }
+
+    @Override
+    public String toString() {
+        return "";
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyObject.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Represents the Ruby {@code Object} class.
+ */
+public class RubyObject extends RubyBasicObject {
+
+    public boolean frozen = false;
+
+    public RubyObject(RubyClass rubyClass) {
+        super(rubyClass);
+    }
+
+    public void checkFrozen() {
+        if (frozen) {
+            CompilerDirectives.transferToInterpreter();
+            throw new RaiseException(getRubyClass().getContext().getCoreLibrary().frozenError(getRubyClass().getName().toLowerCase()));
+        }
+    }
+
+    public Object dup() {
+        final RubyObject newObject = new RubyObject(rubyClass);
+        newObject.setInstanceVariables(getInstanceVariables());
+        return newObject;
+    }
+
+    public static String checkInstanceVariableName(RubyContext context, String name) {
+        if (!name.startsWith("@")) {
+            throw new RaiseException(context.getCoreLibrary().nameErrorInstanceNameNotAllowable(name));
+        }
+
+        return name.substring(1);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyProc.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Represents the Ruby {@code Proc} class.
+ */
+public class RubyProc extends RubyObject {
+
+    /**
+     * The class from which we create the object that is {@code Proc}. A subclass of
+     * {@link RubyClass} so that we can override {@link #newInstance} and allocate a
+     * {@link RubyProc} rather than a normal {@link RubyBasicObject}.
+     */
+    public static class RubyProcClass extends RubyClass {
+
+        public RubyProcClass(RubyClass objectClass) {
+            super(null, objectClass, "Proc");
+        }
+
+        @Override
+        public RubyBasicObject newInstance() {
+            return new RubyProc(this);
+        }
+
+    }
+
+    public static enum Type {
+        PROC, LAMBDA
+    }
+
+    @CompilationFinal private Type type;
+    @CompilationFinal private Object self;
+    @CompilationFinal private RubyProc block;
+    @CompilationFinal private RubyMethod method;
+
+    public RubyProc(RubyClass procClass) {
+        super(procClass);
+    }
+
+    public RubyProc(RubyClass procClass, Type type, Object self, RubyProc block, RubyMethod method) {
+        super(procClass);
+        initialize(type, self, block, method);
+    }
+
+    public void initialize(Type setType, Object setSelf, RubyProc setBlock, RubyMethod setMethod) {
+        assert setSelf != null;
+        assert RubyContext.shouldObjectBeVisible(setSelf);
+        type = setType;
+        self = setSelf;
+        block = setBlock;
+        method = setMethod;
+    }
+
+    public Object getSelf() {
+        return self;
+    }
+
+    @CompilerDirectives.SlowPath
+    public Object call(PackedFrame caller, Object... args) {
+        return callWithModifiedSelf(caller, self, args);
+    }
+
+    public Object callWithModifiedSelf(PackedFrame caller, Object modifiedSelf, Object... args) {
+        assert modifiedSelf != null;
+
+        try {
+            return method.call(caller, modifiedSelf, block, args);
+        } catch (ReturnException e) {
+            switch (type) {
+                case PROC:
+                    throw e;
+                case LAMBDA:
+                    return e.getValue();
+                default:
+                    throw new IllegalStateException();
+            }
+        }
+    }
+
+    public RubyMethod getMethod() {
+        return method;
+    }
+
+    public Type getType() {
+        return type;
+    }
+
+    public RubyProc getBlock() {
+        return block;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyRegexp.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core;
+
+import java.util.regex.*;
+
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Represents the Ruby {@code Regexp} class.
+ */
+public class RubyRegexp extends RubyObject {
+
+    /**
+     * The class from which we create the object that is {@code Regexp}. A subclass of
+     * {@link RubyClass} so that we can override {@link #newInstance} and allocate a
+     * {@link RubyRegexp} rather than a normal {@link RubyBasicObject}.
+     */
+    public static class RubyRegexpClass extends RubyClass {
+
+        public RubyRegexpClass(RubyClass objectClass) {
+            super(null, objectClass, "Regexp");
+        }
+
+        @Override
+        public RubyBasicObject newInstance() {
+            return new RubyRegexp(getContext().getCoreLibrary().getRegexpClass());
+        }
+
+    }
+
+    @CompilationFinal private Pattern pattern;
+
+    public RubyRegexp(RubyClass regexpClass) {
+        super(regexpClass);
+    }
+
+    public RubyRegexp(RubyClass regexpClass, String pattern) {
+        this(regexpClass);
+        initialize(compile(pattern));
+    }
+
+    public RubyRegexp(RubyClass regexpClass, Pattern pattern) {
+        this(regexpClass);
+        initialize(pattern);
+    }
+
+    public void initialize(String setPattern) {
+        pattern = compile(setPattern);
+    }
+
+    public void initialize(Pattern setPattern) {
+        pattern = setPattern;
+    }
+
+    public Object matchOperator(Frame frame, String string) {
+        final RubyContext context = getRubyClass().getContext();
+
+        final Matcher matcher = pattern.matcher(string);
+
+        if (matcher.find()) {
+            for (int n = 1; n < matcher.groupCount() + 1; n++) {
+                final FrameSlot slot = frame.getFrameDescriptor().findFrameSlot("$" + n);
+
+                if (slot != null) {
+                    frame.setObject(slot, context.makeString(matcher.group(n)));
+                }
+            }
+
+            return matcher.start();
+        } else {
+            return NilPlaceholder.INSTANCE;
+        }
+    }
+
+    public Pattern getPattern() {
+        return pattern;
+    }
+
+    public Object match(String string) {
+        final RubyContext context = getRubyClass().getContext();
+
+        final Matcher matcher = pattern.matcher(string);
+
+        if (!matcher.find()) {
+            return NilPlaceholder.INSTANCE;
+        }
+
+        final Object[] values = new Object[matcher.groupCount() + 1];
+
+        for (int n = 0; n < matcher.groupCount() + 1; n++) {
+            final String group = matcher.group(n);
+
+            if (group == null) {
+                values[n] = NilPlaceholder.INSTANCE;
+            } else {
+                values[n] = context.makeString(group);
+            }
+        }
+
+        return new RubyMatchData(context.getCoreLibrary().getMatchDataClass(), values);
+    }
+
+    @Override
+    public int hashCode() {
+        return pattern.pattern().hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof RubyRegexp)) {
+            return false;
+        }
+        RubyRegexp other = (RubyRegexp) obj;
+        if (pattern == null) {
+            if (other.pattern != null) {
+                return false;
+            }
+        } else if (!pattern.pattern().equals(other.pattern.pattern())) {
+            return false;
+        }
+        return true;
+    }
+
+    public static Pattern compile(String pattern) {
+        return Pattern.compile(pattern, Pattern.MULTILINE | Pattern.UNIX_LINES);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyString.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core;
+
+import java.math.*;
+import java.nio.*;
+import java.nio.charset.*;
+import java.util.*;
+import java.util.regex.*;
+
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+import com.oracle.truffle.ruby.runtime.core.range.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Represents the Ruby {@code String} class.
+ */
+public class RubyString extends RubyObject {
+
+    /**
+     * The class from which we create the object that is {@code String}. A subclass of
+     * {@link RubyClass} so that we can override {@link #newInstance} and allocate a
+     * {@link RubyString} rather than a normal {@link RubyBasicObject}.
+     */
+    public static class RubyStringClass extends RubyClass {
+
+        public RubyStringClass(RubyClass objectClass) {
+            super(null, objectClass, "String");
+        }
+
+        @Override
+        public RubyBasicObject newInstance() {
+            return new RubyString(getContext().getCoreLibrary().getStringClass(), "");
+        }
+
+    }
+
+    private boolean fromJavaString;
+
+    private Charset encoding;
+    private byte[] bytes;
+
+    private String cachedStringValue;
+
+    /**
+     * Construct a string from a Java {@link String}, lazily converting to bytes as needed.
+     */
+    public RubyString(RubyClass stringClass, String value) {
+        super(stringClass);
+        fromJavaString = true;
+        encoding = null;
+        bytes = null;
+        cachedStringValue = value;
+    }
+
+    /**
+     * Construct a string from bytes representing characters in an encoding, lazily converting to a
+     * Java {@link String} as needed.
+     */
+    public RubyString(RubyClass stringClass, Charset encoding, byte[] bytes) {
+        super(stringClass);
+        fromJavaString = false;
+        this.encoding = encoding;
+        this.bytes = bytes;
+        cachedStringValue = null;
+    }
+
+    public RubyString(RubyString copyOf) {
+        super(copyOf.getRubyClass().getContext().getCoreLibrary().getStringClass());
+        fromJavaString = copyOf.fromJavaString;
+        encoding = copyOf.encoding;
+
+        if (copyOf.bytes != null) {
+            bytes = Arrays.copyOf(copyOf.bytes, copyOf.bytes.length);
+        } else {
+            bytes = null;
+        }
+
+        cachedStringValue = copyOf.cachedStringValue;
+    }
+
+    public boolean isFromJavaString() {
+        return fromJavaString;
+    }
+
+    public byte[] getBytes() {
+        return bytes;
+    }
+
+    public void replace(String value) {
+        fromJavaString = true;
+        encoding = null;
+        bytes = null;
+        cachedStringValue = value;
+    }
+
+    @Override
+    public String toString() {
+        if (cachedStringValue == null) {
+            cachedStringValue = encoding.decode(ByteBuffer.wrap(bytes)).toString();
+        }
+
+        return cachedStringValue;
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (other == null) {
+            return false;
+        }
+
+        // If the other value is a Java string, use our Java string representation to compare
+
+        if (other instanceof String) {
+            return toString().equals(other);
+        }
+
+        if (other instanceof RubyString) {
+            final RubyString otherString = (RubyString) other;
+
+            // If we both came from Java strings, use them to compare
+
+            if (fromJavaString && otherString.fromJavaString) {
+                return toString().equals(other.toString());
+            }
+
+            // If we both have the same encoding, compare bytes
+
+            if (encoding == otherString.encoding) {
+                return Arrays.equals(bytes, otherString.bytes);
+            }
+
+            // If we don't have the same encoding, we need some more advanced logic
+
+            throw new UnsupportedOperationException("Can't compare strings in different encodings yet");
+        }
+
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return toString().hashCode();
+    }
+
+    public static Object getIndex(RubyContext context, String string, Object[] args) {
+        if (args.length == 1) {
+            final Object index = args[0];
+
+            if (index instanceof Integer) {
+                final int stringLength = string.length();
+                final int normalisedIndex = ArrayUtilities.normaliseIndex(stringLength, (int) index);
+
+                return context.makeString(string.charAt(normalisedIndex));
+            } else if (index instanceof FixnumRange) {
+                final FixnumRange range = (FixnumRange) index;
+
+                final int stringLength = string.length();
+
+                if (range.doesExcludeEnd()) {
+                    final int begin = ArrayUtilities.normaliseIndex(stringLength, range.getBegin());
+                    final int exclusiveEnd = ArrayUtilities.normaliseExclusiveIndex(stringLength, range.getExclusiveEnd());
+                    return context.makeString(string.substring(begin, exclusiveEnd));
+                } else {
+                    final int begin = ArrayUtilities.normaliseIndex(stringLength, range.getBegin());
+                    final int inclusiveEnd = ArrayUtilities.normaliseIndex(stringLength, range.getInclusiveEnd());
+                    return context.makeString(string.substring(begin, inclusiveEnd + 1));
+                }
+            } else {
+                throw new UnsupportedOperationException("Don't know how to index a string with " + index.getClass());
+            }
+        } else {
+            final int rangeStart = (int) args[0];
+            int rangeLength = (int) args[1];
+
+            if (rangeLength > string.length() - rangeStart) {
+                rangeLength = string.length() - rangeStart;
+            }
+
+            if (rangeStart > string.length()) {
+                return NilPlaceholder.INSTANCE;
+            }
+
+            return context.makeString(string.substring(rangeStart, rangeStart + rangeLength));
+        }
+    }
+
+    @Override
+    public Object dup() {
+        return new RubyString(this);
+    }
+
+    public void concat(RubyString other) {
+        if (fromJavaString && other.fromJavaString) {
+            cachedStringValue += other.cachedStringValue;
+            encoding = null;
+            bytes = null;
+        } else {
+            throw new UnsupportedOperationException("Don't know how to append strings with encodings");
+        }
+    }
+
+    public static String ljust(String string, int length, String padding) {
+        final StringBuilder builder = new StringBuilder();
+
+        builder.append(string);
+
+        int n = 0;
+
+        while (builder.length() < length) {
+            builder.append(padding.charAt(n));
+
+            n++;
+
+            if (n == padding.length()) {
+                n = 0;
+            }
+        }
+
+        return builder.toString();
+    }
+
+    public static String rjust(String string, int length, String padding) {
+        final StringBuilder builder = new StringBuilder();
+
+        int n = 0;
+
+        while (builder.length() + string.length() < length) {
+            builder.append(padding.charAt(n));
+
+            n++;
+
+            if (n == padding.length()) {
+                n = 0;
+            }
+        }
+
+        builder.append(string);
+
+        return builder.toString();
+    }
+
+    public static RubyArray scan(RubyContext context, String string, Pattern pattern) {
+        final Matcher matcher = pattern.matcher(string);
+
+        final RubyArray results = new RubyArray(context.getCoreLibrary().getArrayClass());
+
+        while (matcher.find()) {
+            if (matcher.groupCount() == 0) {
+                results.push(context.makeString(matcher.group(0)));
+            } else {
+                final RubyArray subResults = new RubyArray(context.getCoreLibrary().getArrayClass());
+
+                for (int n = 1; n < matcher.groupCount() + 1; n++) {
+                    subResults.push(context.makeString(matcher.group(n)));
+                }
+
+                results.push(subResults);
+            }
+        }
+
+        return results;
+    }
+
+    public Object toInteger() {
+        if (toString().length() == 0) {
+            return 0;
+        }
+
+        try {
+            final int value = Integer.parseInt(toString());
+
+            if (value >= RubyFixnum.MIN_VALUE && value <= RubyFixnum.MAX_VALUE) {
+                return value;
+            } else {
+                return BigInteger.valueOf(value);
+            }
+        } catch (NumberFormatException e) {
+            return new BigInteger(toString());
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubySymbol.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core;
+
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Represents the Ruby {@code Symbol} class.
+ */
+public class RubySymbol extends RubyObject {
+
+    private final String symbol;
+
+    public RubySymbol(RubyClass symbolClass, String symbol) {
+        super(symbolClass);
+        this.symbol = symbol.intern();
+    }
+
+    public RubyProc toProc() {
+        final RubyContext context = getRubyClass().getContext();
+
+        final CallTarget callTarget = new CallTarget() {
+
+            @Override
+            public Object call(PackedFrame frame, Arguments args) {
+                final RubyArguments rubyArgs = (RubyArguments) args;
+                final Object receiver = rubyArgs.getArguments()[0];
+                final Object[] sendArgs = Arrays.copyOfRange(rubyArgs.getArguments(), 1, rubyArgs.getArguments().length);
+                final RubyBasicObject receiverObject = context.getCoreLibrary().box(receiver);
+                return receiverObject.send(symbol, rubyArgs.getBlock(), sendArgs);
+            }
+
+        };
+
+        final CallTargetMethodImplementation methodImplementation = new CallTargetMethodImplementation(callTarget, null);
+        final RubyMethod method = new RubyMethod(null, null, new UniqueMethodIdentifier(), symbol, null, Visibility.PUBLIC, false, methodImplementation);
+
+        return new RubyProc(context.getCoreLibrary().getProcClass(), RubyProc.Type.PROC, NilPlaceholder.INSTANCE, null, method);
+    }
+
+    @Override
+    public String toString() {
+        return symbol;
+    }
+
+    @Override
+    public String inspect() {
+        return ":" + symbol;
+    }
+
+    @Override
+    public int hashCode() {
+        return symbol.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (other == this) {
+            return true;
+        } else if (other instanceof RubySymbol) {
+            return symbol == ((RubySymbol) other).symbol;
+        } else if (other instanceof RubyString) {
+            return other.equals(symbol);
+        } else {
+            return super.equals(other);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyThread.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core;
+
+import java.util.*;
+import java.util.concurrent.*;
+
+import com.oracle.truffle.ruby.runtime.objects.*;
+import com.oracle.truffle.ruby.runtime.subsystems.*;
+
+/**
+ * Represents the Ruby {@code Thread} class. Implemented using Java threads, but note that there is
+ * not a one-to-one mapping between Ruby threads and Java threads - specifically in combination with
+ * fibers as they are currently implemented as their own Java threads.
+ */
+public class RubyThread extends RubyObject {
+
+    /**
+     * The class from which we create the object that is {@code Thread}. A subclass of
+     * {@link RubyClass} so that we can override {@link #newInstance} and allocate a
+     * {@link RubyThread} rather than a normal {@link RubyBasicObject}.
+     */
+    public static class RubyThreadClass extends RubyClass {
+
+        public RubyThreadClass(RubyClass objectClass) {
+            super(null, objectClass, "Thread");
+        }
+
+        @Override
+        public RubyBasicObject newInstance() {
+            return new RubyThread(this, getContext().getThreadManager());
+        }
+
+    }
+
+    private final ThreadManager manager;
+
+    private final CountDownLatch finished = new CountDownLatch(1);
+
+    private final int hashCode = new Random().nextInt();
+
+    public RubyThread(RubyClass rubyClass, ThreadManager manager) {
+        super(rubyClass);
+        this.manager = manager;
+    }
+
+    public void initialize(RubyProc block) {
+        final RubyProc finalBlock = block;
+
+        initialize(new Runnable() {
+
+            @Override
+            public void run() {
+                finalBlock.call(null);
+            }
+
+        });
+    }
+
+    public void initialize(Runnable runnable) {
+        final RubyThread finalThread = this;
+        final Runnable finalRunnable = runnable;
+
+        new Thread(new Runnable() {
+
+            @Override
+            public void run() {
+                finalThread.manager.registerThread(finalThread);
+                finalThread.manager.enterGlobalLock(finalThread);
+
+                try {
+                    finalRunnable.run();
+                } finally {
+                    finalThread.manager.leaveGlobalLock();
+                    finalThread.manager.unregisterThread(finalThread);
+                    finalThread.finished.countDown();
+                }
+            }
+
+        }).start();
+    }
+
+    @Override
+    public int hashCode() {
+        return hashCode;
+    }
+
+    public void shutdown() {
+    }
+
+    public void join() {
+        final RubyThread runningThread = getRubyClass().getContext().getThreadManager().leaveGlobalLock();
+
+        try {
+            while (true) {
+                try {
+                    finished.await();
+                    break;
+                } catch (InterruptedException e) {
+                    // Await again
+                }
+            }
+        } finally {
+            runningThread.manager.enterGlobalLock(runningThread);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyTime.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core;
+
+import java.text.*;
+import java.util.*;
+
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Represents the Ruby {@code Time} class. This is a very rough implementation and is only really
+ * enough to run benchmark harnesses.
+ */
+public class RubyTime extends RubyObject {
+
+    /**
+     * The class from which we create the object that is {@code Time}. A subclass of
+     * {@link RubyClass} so that we can override {@link #newInstance} and allocate a
+     * {@link RubyTime} rather than a normal {@link RubyBasicObject}.
+     */
+    public static class RubyTimeClass extends RubyClass {
+
+        public RubyTimeClass(RubyClass objectClass) {
+            super(null, objectClass, "Time");
+        }
+
+        @Override
+        public RubyBasicObject newInstance() {
+            return new RubyTime(this, milisecondsToNanoseconds(System.currentTimeMillis()));
+        }
+
+    }
+
+    private final long nanoseconds;
+
+    public RubyTime(RubyClass timeClass, long nanoseconds) {
+        super(timeClass);
+        this.nanoseconds = nanoseconds;
+    }
+
+    /**
+     * Subtract one time from another, producing duration in seconds.
+     */
+    public double subtract(RubyTime other) {
+        return nanosecondsToSecond(nanoseconds - other.nanoseconds);
+    }
+
+    @Override
+    public String toString() {
+        /*
+         * I think this is ISO 8601 with a custom time part. Note that Ruby's time formatting syntax
+         * is different to Java's.
+         */
+
+        return new SimpleDateFormat("Y-MM-d H:m:ss Z").format(toDate());
+    }
+
+    private Date toDate() {
+        return new Date(nanosecondsToMiliseconds(nanoseconds));
+    }
+
+    public static RubyTime fromDate(RubyClass timeClass, long timeMiliseconds) {
+        return new RubyTime(timeClass, milisecondsToNanoseconds(timeMiliseconds));
+    }
+
+    private static long milisecondsToNanoseconds(long miliseconds) {
+        return miliseconds * 1000000;
+    }
+
+    private static long nanosecondsToMiliseconds(long nanoseconds) {
+        return nanoseconds / 1000000;
+    }
+
+    private static double nanosecondsToSecond(long nanoseconds) {
+        return nanoseconds / 1e9;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/RubyTrueClass.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core;
+
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Represents the Ruby {@code TrueClass} class.
+ */
+public class RubyTrueClass extends RubyObject implements Unboxable {
+
+    public RubyTrueClass(RubyClass objectClass) {
+        super(objectClass);
+    }
+
+    public Object unbox() {
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "true";
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        return other instanceof RubyTrueClass || (other instanceof Boolean && (boolean) other);
+    }
+
+    @Override
+    public int hashCode() {
+        return Boolean.TRUE.hashCode();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/StringFormatter.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+public class StringFormatter {
+
+    public static String format(String format, List<Object> values) {
+        final ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
+        final PrintStream printStream = new PrintStream(byteArray);
+
+        format(printStream, format, values);
+
+        return byteArray.toString();
+    }
+
+    public static void format(PrintStream stream, String format, List<Object> values) {
+        /*
+         * See http://www.ruby-doc.org/core-1.9.3/Kernel.html#method-i-sprintf.
+         * 
+         * At the moment we just do the basics that we need. We will need a proper lexer later on.
+         * Or better than that we could compile to Truffle nodes if the format string is constant! I
+         * don't think we can easily translate to Java's format syntax, otherwise JRuby would do
+         * that and they don't.
+         */
+
+        // I'm not using a for loop, because Checkstyle won't let me modify the control variable
+
+        int n = 0;
+        int v = 0;
+
+        while (n < format.length()) {
+            final char c = format.charAt(n);
+            n++;
+
+            if (c == '%') {
+                // %[flags][width][.precision]type
+
+                final String flagChars = "0";
+
+                boolean zeroPad = false;
+
+                while (n < format.length() && flagChars.indexOf(format.charAt(n)) != -1) {
+                    switch (format.charAt(n)) {
+                        case '0':
+                            zeroPad = true;
+                            break;
+                    }
+
+                    n++;
+                }
+
+                int width;
+
+                if (n < format.length() && Character.isDigit(format.charAt(n))) {
+                    final int widthStart = n;
+
+                    while (Character.isDigit(format.charAt(n))) {
+                        n++;
+                    }
+
+                    width = Integer.parseInt(format.substring(widthStart, n));
+                } else {
+                    width = 0;
+                }
+
+                int precision;
+
+                if (format.charAt(n) == '.') {
+                    n++;
+
+                    final int precisionStart = n;
+
+                    while (Character.isDigit(format.charAt(n))) {
+                        n++;
+                    }
+
+                    precision = Integer.parseInt(format.substring(precisionStart, n));
+                } else {
+                    precision = 5;
+                }
+
+                final char type = format.charAt(n);
+                n++;
+
+                final StringBuilder formatBuilder = new StringBuilder();
+
+                formatBuilder.append("%");
+
+                if (width > 0) {
+                    if (zeroPad) {
+                        formatBuilder.append("0");
+                    }
+
+                    formatBuilder.append(width);
+                }
+
+                switch (type) {
+                    case 'd': {
+                        formatBuilder.append("d");
+                        final int value = GeneralConversions.toFixnum(values.get(v));
+                        stream.printf(formatBuilder.toString(), value);
+                        break;
+                    }
+
+                    case 'f': {
+                        formatBuilder.append(".");
+                        formatBuilder.append(precision);
+                        formatBuilder.append("f");
+                        final double value = GeneralConversions.toFloat(values.get(v));
+                        stream.printf(formatBuilder.toString(), value);
+                        break;
+                    }
+
+                    default:
+                        throw new RuntimeException("Kernel#sprintf error");
+                }
+
+                v++;
+            } else {
+                stream.print(c);
+            }
+        }
+    }
+
+    public static void formatPuts(PrintStream stream, List<Object> args) {
+        if (args.size() > 0) {
+            formatPutsInner(stream, args);
+        } else {
+            stream.println();
+        }
+    }
+
+    public static void formatPutsInner(PrintStream stream, List<Object> args) {
+        if (args.size() > 0) {
+            for (Object arg : args) {
+                if (arg instanceof RubyArray) {
+                    final RubyArray array = (RubyArray) arg;
+                    formatPutsInner(stream, array.asList());
+                } else {
+                    stream.println(arg);
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/ArrayStore.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core.array;
+
+/**
+ * Interface to various ways to store values in arrays.
+ */
+public interface ArrayStore {
+
+    /**
+     * Get the size of the store.
+     */
+    int size();
+
+    /**
+     * Get a value from the array using a normalized index.
+     */
+    Object get(int normalisedIndex);
+
+    /**
+     * Get a range of values from an array store.
+     */
+    ArrayStore getRange(int normalisedBegin, int truncatedNormalisedExclusiveEnd);
+
+    /**
+     * Set a value at an index, or throw {@link GeneraliseArrayStoreException} if that's not
+     * possible.
+     */
+    void set(int normalisedIndex, Object value) throws GeneraliseArrayStoreException;
+
+    /**
+     * Set a range to be a single value, or throw {@link GeneraliseArrayStoreException} if that's
+     * not possible.
+     */
+    void setRangeSingle(int normalisedBegin, int truncatedNormalisedExclusiveEnd, Object value) throws GeneraliseArrayStoreException;
+
+    /**
+     * Set a range to be a copied from another array, or throw {@link GeneraliseArrayStoreException}
+     * if that's not possible.
+     */
+    void setRangeArray(int normalisedBegin, int normalisedExclusiveEnd, ArrayStore other) throws GeneraliseArrayStoreException;
+
+    /**
+     * Insert a value at an index, or throw {@link GeneraliseArrayStoreException} if that's not
+     * possible.
+     */
+    void insert(int normalisedIndex, Object value) throws GeneraliseArrayStoreException;
+
+    /**
+     * Push a value onto the end, or throw {@link GeneraliseArrayStoreException} if that's not
+     * possible.
+     */
+    void push(Object value) throws GeneraliseArrayStoreException;
+
+    /**
+     * Delete a value at an index, returning the value.
+     */
+    Object deleteAt(int normalisedIndex);
+
+    /**
+     * Does a store contain a value?
+     */
+    boolean contains(Object value);
+
+    /**
+     * Duplicate the store.
+     */
+    ArrayStore dup();
+
+    /**
+     * Duplicate the store, in a format which can store an object.
+     */
+    ArrayStore generalizeFor(Object type);
+
+    /**
+     * Get the type of value stored.
+     */
+    Object getIndicativeValue();
+
+    /**
+     * Get the contents of the store as a new array.
+     */
+    Object[] toObjectArray();
+
+    /**
+     * Does one store equal another.
+     */
+    boolean equals(ArrayStore other);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/ArrayUtilities.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core.array;
+
+/**
+ * Simple array utilities, not tied to any particular implementation.
+ */
+public abstract class ArrayUtilities {
+
+    /**
+     * Apply Ruby's wrap-around index semantics.
+     */
+    public static int normaliseIndex(int length, int index) {
+        if (index < 0) {
+            return length + index;
+        } else {
+            return index;
+        }
+    }
+
+    /**
+     * Apply Ruby's wrap-around index semantics.
+     */
+    public static int normaliseExclusiveIndex(int length, int exclusiveIndex) {
+        if (exclusiveIndex < 0) {
+            return length + exclusiveIndex + 1;
+        } else {
+            return exclusiveIndex;
+        }
+    }
+
+    /**
+     * If an exclusive index is beyond the end of the array, truncate it to be length of the array.
+     */
+    public static int truncateNormalisedExclusiveIndex(int length, int normalisedExclusiveEnd) {
+        return Math.min(length, normalisedExclusiveEnd);
+    }
+
+    /**
+     * What capacity should we allocate for a given requested length?
+     */
+    public static int capacityFor(int length) {
+        return Math.max(16, length * 2);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/BaseArrayStore.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core.array;
+
+/**
+ * Contains implementations of as much of the array stores that we could easily share. Much of the
+ * rest depends on static types in method signatures, so is lexically almost the same, but isn't the
+ * same in type, and as the whole point is to avoid boxing, we can't use Java's generics.
+ */
+public abstract class BaseArrayStore implements ArrayStore {
+
+    protected int capacity;
+    protected int size;
+
+    @Override
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Set a range in the array to be another range. You must ensure that the otherValues array is
+     * of the same type as your values array.
+     */
+    protected void setRangeArrayMatchingTypes(int normalisedBegin, int normalisedExclusiveEnd, Object otherValues, int otherSize) {
+        // Is the range the whole array?
+
+        if (normalisedBegin == 0 && normalisedExclusiveEnd == size) {
+            // Do we already have enough space?
+
+            if (otherSize <= capacity) {
+                // Copy to our existing array.
+                final Object values = getValuesArrayObject();
+                System.arraycopy(otherValues, 0, values, 0, otherSize);
+            } else {
+                // Create a new copy of their array.
+                setCapacityWithNewArray(otherSize);
+                final Object values = getValuesArrayObject();
+                System.arraycopy(otherValues, 0, values, 0, otherSize);
+            }
+
+            size = otherSize;
+        } else {
+            final int rangeLength = normalisedExclusiveEnd - normalisedBegin;
+
+            // Create extra space - might be negative if the new range is shorter, or zero.
+
+            final int extraSpaceNeeded = otherSize - rangeLength;
+
+            if (extraSpaceNeeded > 0) {
+                createSpace(normalisedBegin, extraSpaceNeeded);
+            } else if (extraSpaceNeeded < 0) {
+                deleteSpace(normalisedBegin, -extraSpaceNeeded);
+            }
+
+            // Copy across the new values.
+            final Object values = getValuesArrayObject();
+            System.arraycopy(otherValues, 0, values, normalisedBegin, otherSize);
+        }
+    }
+
+    protected void createSpace(int normalisedBegin, int count) {
+        /*
+         * Is this space at the end or in the middle?
+         */
+
+        if (normalisedBegin == size) {
+            createSpaceAtEnd(count);
+        } else {
+            /*
+             * Create space in the middle - is the array already big enough?
+             */
+
+            final int elementsToMove = size - normalisedBegin;
+
+            if (size + count > capacity) {
+                /*
+                 * The array isn't big enough. We don't want to use Arrays.copyOf because that will
+                 * do wasted copying of the elements we are about to move. However - is
+                 * Arrays.copyOf clever enough to see that only one instance of Array is using the
+                 * block and use realloc, potentially avoiding a malloc and winning?
+                 */
+
+                final Object values = getValuesArrayObject();
+                setCapacityWithNewArray(ArrayUtilities.capacityFor(size + count));
+                final Object newValues = getValuesArrayObject();
+                System.arraycopy(values, 0, newValues, 0, normalisedBegin);
+                System.arraycopy(values, normalisedBegin, newValues, normalisedBegin + count, elementsToMove);
+            } else {
+                /*
+                 * The array is already big enough - we can copy elements already in the array to
+                 * make space.
+                 */
+
+                final Object values = getValuesArrayObject();
+                System.arraycopy(values, normalisedBegin, values, normalisedBegin + count, elementsToMove);
+            }
+
+            size += count;
+        }
+    }
+
+    protected void createSpaceAtEnd(int count) {
+        /*
+         * Create space at the end - we can do this by creating a copy of the array if needed.
+         */
+
+        if (size + count > capacity) {
+            setCapacityByCopying(ArrayUtilities.capacityFor(size + count));
+        }
+
+        size += count;
+    }
+
+    protected void deleteSpace(int normalisedBegin, int count) {
+        final Object values = getValuesArrayObject();
+        final int elementsToMove = size - normalisedBegin - count;
+
+        if (elementsToMove > 0) {
+            System.arraycopy(values, normalisedBegin + count, values, normalisedBegin, elementsToMove);
+        }
+
+        size -= count;
+    }
+
+    protected abstract void setCapacityByCopying(int newCapacity);
+
+    protected abstract void setCapacityWithNewArray(int newCapacity);
+
+    protected abstract Object getValuesArrayObject();
+
+    @Override
+    public boolean equals(ArrayStore other) {
+        for (int n = 0; n < size; n++) {
+            if (!other.get(n).equals(get(n))) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/EmptyArrayStore.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core.array;
+
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * An array store that can only be empty.
+ */
+public final class EmptyArrayStore implements ArrayStore {
+
+    public static final EmptyArrayStore INSTANCE = new EmptyArrayStore();
+
+    private EmptyArrayStore() {
+    }
+
+    @Override
+    public int size() {
+        return 0;
+    }
+
+    @Override
+    public Object get(int normalisedIndex) {
+        return NilPlaceholder.INSTANCE;
+    }
+
+    @Override
+    public ArrayStore getRange(int normalisedBegin, int truncatedNormalisedExclusiveEnd) {
+        return null; // Represents Nil
+    }
+
+    @Override
+    public void set(int normalisedIndex, Object value) throws GeneraliseArrayStoreException {
+        throw new GeneraliseArrayStoreException();
+    }
+
+    @Override
+    public void setRangeSingle(int normalisedBegin, int truncatedNormalisedExclusiveEnd, Object value) throws GeneraliseArrayStoreException {
+        throw new GeneraliseArrayStoreException();
+    }
+
+    @Override
+    public void setRangeArray(int normalisedBegin, int normalisedExclusiveEnd, ArrayStore other) throws GeneraliseArrayStoreException {
+        throw new GeneraliseArrayStoreException();
+    }
+
+    @Override
+    public void insert(int normalisedIndex, Object value) throws GeneraliseArrayStoreException {
+        throw new GeneraliseArrayStoreException();
+    }
+
+    @Override
+    public void push(Object value) throws GeneraliseArrayStoreException {
+        throw new GeneraliseArrayStoreException();
+    }
+
+    @Override
+    public Object deleteAt(int normalisedIndex) {
+        throw new UnsupportedOperationException("Cannot delete from an empty array");
+    }
+
+    @Override
+    public ArrayStore dup() {
+        return this;
+    }
+
+    @Override
+    public boolean contains(Object value) {
+        return false;
+    }
+
+    @Override
+    public ArrayStore generalizeFor(Object type) {
+        if (type instanceof Integer) {
+            return new FixnumArrayStore();
+        } else {
+            return new ObjectArrayStore();
+        }
+    }
+
+    @Override
+    public Object getIndicativeValue() {
+        return null;
+    }
+
+    @Override
+    public Object[] toObjectArray() {
+        return new Object[]{};
+    }
+
+    @Override
+    public boolean equals(ArrayStore other) {
+        if (other == null) {
+            return false;
+        } else if (other == this) {
+            return true;
+        } else {
+            return other.size() == 0;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/FixnumArrayStore.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core.array;
+
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * A store for an array of Fixnums.
+ */
+public final class FixnumArrayStore extends BaseArrayStore {
+
+    private int[] values;
+
+    public FixnumArrayStore() {
+        this(new int[]{});
+    }
+
+    public FixnumArrayStore(int[] values) {
+        this.values = values;
+        size = values.length;
+        capacity = values.length;
+    }
+
+    @Override
+    public Object get(int normalisedIndex) {
+        try {
+            return getFixnum(normalisedIndex);
+        } catch (UnexpectedResultException e) {
+            return e.getResult();
+        }
+    }
+
+    public int getFixnum(int normalisedIndex) throws UnexpectedResultException {
+        if (normalisedIndex >= size) {
+            throw new UnexpectedResultException(NilPlaceholder.INSTANCE);
+        }
+
+        return values[normalisedIndex];
+    }
+
+    @Override
+    public ArrayStore getRange(int normalisedBegin, int truncatedNormalisedExclusiveEnd) {
+        if (normalisedBegin >= size) {
+            return null; // Represents Nil
+        }
+
+        return new FixnumArrayStore(Arrays.copyOfRange(values, normalisedBegin, truncatedNormalisedExclusiveEnd));
+    }
+
+    @Override
+    public void set(int normalisedIndex, Object value) throws GeneraliseArrayStoreException {
+        if (value instanceof Integer) {
+            setFixnum(normalisedIndex, (int) value);
+        } else {
+            throw new GeneraliseArrayStoreException();
+        }
+    }
+
+    public void setFixnum(int normalisedIndex, int value) throws GeneraliseArrayStoreException {
+        if (normalisedIndex > size) {
+            throw new GeneraliseArrayStoreException();
+        }
+
+        if (normalisedIndex == size) {
+            push(value);
+        } else {
+            values[normalisedIndex] = value;
+        }
+    }
+
+    @Override
+    public void setRangeSingle(int normalisedBegin, int truncatedNormalisedExclusiveEnd, Object value) throws GeneraliseArrayStoreException {
+        if (value instanceof Integer) {
+            setRangeSingleFixnum(normalisedBegin, truncatedNormalisedExclusiveEnd, (int) value);
+        } else {
+            throw new GeneraliseArrayStoreException();
+        }
+    }
+
+    public void setRangeSingleFixnum(int normalisedBegin, int truncatedNormalisedExclusiveEnd, int value) {
+        // Is the range the whole array?
+
+        if (normalisedBegin == 0 && truncatedNormalisedExclusiveEnd == size) {
+            // Reset length and set the value.
+            size = 1;
+            values[0] = value;
+        } else {
+            // Delete the range, except for the first value.
+            deleteSpace(normalisedBegin + 1, truncatedNormalisedExclusiveEnd - normalisedBegin - 1);
+
+            // Set the value we left in.
+            values[normalisedBegin] = value;
+        }
+    }
+
+    @Override
+    public void setRangeArray(int normalisedBegin, int normalisedExclusiveEnd, ArrayStore other) throws GeneraliseArrayStoreException {
+        if (other instanceof FixnumArrayStore) {
+            setRangeArrayFixnum(normalisedBegin, normalisedExclusiveEnd, (FixnumArrayStore) other);
+        } else {
+            throw new GeneraliseArrayStoreException();
+        }
+    }
+
+    public void setRangeArrayFixnum(int normalisedBegin, int normalisedExclusiveEnd, FixnumArrayStore other) {
+        setRangeArrayMatchingTypes(normalisedBegin, normalisedExclusiveEnd, other.values, other.size);
+    }
+
+    @Override
+    public void insert(int normalisedIndex, Object value) throws GeneraliseArrayStoreException {
+        if (value instanceof Integer) {
+            insertFixnum(normalisedIndex, (int) value);
+        } else {
+            throw new GeneraliseArrayStoreException();
+        }
+    }
+
+    public void insertFixnum(int normalisedIndex, int value) throws GeneraliseArrayStoreException {
+        if (normalisedIndex > size) {
+            throw new GeneraliseArrayStoreException();
+        }
+
+        createSpace(normalisedIndex, 1);
+        values[normalisedIndex] = value;
+    }
+
+    @Override
+    public void push(Object value) throws GeneraliseArrayStoreException {
+        if (value instanceof Integer) {
+            pushFixnum((int) value);
+        } else {
+            throw new GeneraliseArrayStoreException();
+        }
+    }
+
+    public void pushFixnum(int value) {
+        createSpaceAtEnd(1);
+        values[size - 1] = value;
+    }
+
+    @Override
+    public Object deleteAt(int normalisedIndex) {
+        try {
+            return deleteAtFixnum(normalisedIndex);
+        } catch (UnexpectedResultException e) {
+            return e.getResult();
+        }
+    }
+
+    public int deleteAtFixnum(int normalisedIndex) throws UnexpectedResultException {
+        if (normalisedIndex >= size) {
+            CompilerDirectives.transferToInterpreter();
+            throw new UnexpectedResultException(NilPlaceholder.INSTANCE);
+        }
+
+        final int value = values[normalisedIndex];
+
+        deleteSpace(normalisedIndex, 1);
+
+        return value;
+    }
+
+    @Override
+    public ArrayStore dup() {
+        return new FixnumArrayStore(Arrays.copyOf(values, size));
+    }
+
+    @Override
+    public boolean contains(Object value) {
+        if (!(value instanceof Integer)) {
+            return false;
+        }
+
+        final int intValue = (int) value;
+
+        for (int n = 0; n < size; n++) {
+            if (values[n] == intValue) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    public ArrayStore generalizeFor(Object type) {
+        return new ObjectArrayStore(toObjectArray());
+    }
+
+    @Override
+    public Object getIndicativeValue() {
+        return 0;
+    }
+
+    @Override
+    protected void setCapacityByCopying(int newCapacity) {
+        values = Arrays.copyOf(values, newCapacity);
+        capacity = values.length;
+    }
+
+    @Override
+    protected void setCapacityWithNewArray(int newCapacity) {
+        values = new int[newCapacity];
+        capacity = values.length;
+    }
+
+    @Override
+    protected Object getValuesArrayObject() {
+        return values;
+    }
+
+    @Override
+    public Object[] toObjectArray() {
+        final Object[] objectValues = new Object[size];
+
+        // System.arraycopy will not box.
+
+        for (int n = 0; n < size; n++) {
+            objectValues[n] = values[n];
+        }
+
+        return objectValues;
+    }
+
+    @Override
+    public boolean equals(ArrayStore other) {
+        if (other instanceof FixnumArrayStore) {
+            return equals((FixnumArrayStore) other);
+        } else {
+            return super.equals(other);
+        }
+    }
+
+    public boolean equals(FixnumArrayStore other) {
+        if (other == null) {
+            return false;
+        } else if (other == this) {
+            return true;
+        } else if (other.size != size) {
+            return false;
+        } else if (other.capacity == capacity) {
+            return Arrays.equals(other.values, values);
+        } else {
+            for (int n = 0; n < size; n++) {
+                if (other.values[n] != values[n]) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/FixnumImmutablePairArrayStore.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core.array;
+
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * A store for a pair of Fixnums.
+ */
+public final class FixnumImmutablePairArrayStore extends BaseArrayStore {
+
+    private final int first;
+    private final int second;
+
+    public FixnumImmutablePairArrayStore(int first, int second) {
+        size = 2;
+        capacity = 2;
+        this.first = first;
+        this.second = second;
+    }
+
+    @Override
+    public int size() {
+        return 2;
+    }
+
+    @Override
+    public Object get(int normalisedIndex) {
+        switch (normalisedIndex) {
+            case 0:
+                return first;
+            case 1:
+                return second;
+            default:
+                return NilPlaceholder.INSTANCE;
+        }
+    }
+
+    public int getFixnum(int normalisedIndex) throws UnexpectedResultException {
+        switch (normalisedIndex) {
+            case 0:
+                return first;
+            case 1:
+                return second;
+            default:
+                CompilerDirectives.transferToInterpreter();
+                throw new UnexpectedResultException(NilPlaceholder.INSTANCE);
+        }
+    }
+
+    @Override
+    public ArrayStore getRange(int normalisedBegin, int truncatedNormalisedExclusiveEnd) {
+        if (normalisedBegin >= size) {
+            return null; // Represents Nil
+        }
+
+        return new FixnumArrayStore(Arrays.copyOfRange(new int[]{first, second}, normalisedBegin, truncatedNormalisedExclusiveEnd));
+    }
+
+    @Override
+    public void set(int normalisedIndex, Object value) throws GeneraliseArrayStoreException {
+        CompilerDirectives.transferToInterpreter();
+        throw new GeneraliseArrayStoreException();
+    }
+
+    @Override
+    public void setRangeSingle(int normalisedBegin, int truncatedNormalisedExclusiveEnd, Object value) throws GeneraliseArrayStoreException {
+        CompilerDirectives.transferToInterpreter();
+        throw new GeneraliseArrayStoreException();
+    }
+
+    @Override
+    public void setRangeArray(int normalisedBegin, int normalisedExclusiveEnd, ArrayStore other) throws GeneraliseArrayStoreException {
+        CompilerDirectives.transferToInterpreter();
+        throw new GeneraliseArrayStoreException();
+    }
+
+    @Override
+    public void insert(int normalisedIndex, Object value) throws GeneraliseArrayStoreException {
+        CompilerDirectives.transferToInterpreter();
+        throw new GeneraliseArrayStoreException();
+    }
+
+    @Override
+    public void push(Object value) throws GeneraliseArrayStoreException {
+        CompilerDirectives.transferToInterpreter();
+        throw new GeneraliseArrayStoreException();
+    }
+
+    @Override
+    public Object deleteAt(int normalisedIndex) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ArrayStore dup() {
+        return this;
+    }
+
+    @Override
+    public boolean contains(Object value) {
+        if (value instanceof Integer) {
+            final int intValue = (int) value;
+            return first == intValue || second == intValue;
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public ArrayStore generalizeFor(Object type) {
+        return new ObjectArrayStore(toObjectArray());
+    }
+
+    @Override
+    public Object getIndicativeValue() {
+        return 0;
+    }
+
+    @Override
+    protected void setCapacityByCopying(int newCapacity) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    protected void setCapacityWithNewArray(int newCapacity) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    protected Object getValuesArrayObject() {
+        return new int[]{first, second};
+    }
+
+    @Override
+    public Object[] toObjectArray() {
+        return new Object[]{first, second};
+    }
+
+    @Override
+    public boolean equals(ArrayStore other) {
+        if (other instanceof FixnumImmutablePairArrayStore) {
+            return equals((FixnumImmutablePairArrayStore) other);
+        } else {
+            return super.equals(other);
+        }
+    }
+
+    public boolean equals(FixnumImmutablePairArrayStore other) {
+        if (other == null) {
+            return false;
+        } else if (other == this) {
+            return true;
+        } else {
+            return other.first == first && other.second == second;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/GeneraliseArrayStoreException.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core.array;
+
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * An exception that signals that an ArrayStore cannot store a given object because of its type, and
+ * that the store must be generalized to accommodate it.
+ */
+public class GeneraliseArrayStoreException extends SlowPathException {
+
+    private static final long serialVersionUID = -7648655548414168177L;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/ObjectArrayStore.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core.array;
+
+import java.util.*;
+
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * A store for an array of any objects.
+ */
+public final class ObjectArrayStore extends BaseArrayStore {
+
+    private Object[] values;
+
+    public ObjectArrayStore() {
+        this(new Object[]{});
+    }
+
+    public ObjectArrayStore(Object[] values) {
+        this.values = values;
+        size = values.length;
+        capacity = values.length;
+    }
+
+    @Override
+    public Object get(int normalisedIndex) {
+        if (normalisedIndex >= size) {
+            return NilPlaceholder.INSTANCE;
+        }
+
+        return values[normalisedIndex];
+    }
+
+    @Override
+    public ArrayStore getRange(int normalisedBegin, int normalisedExclusiveEnd) {
+        if (normalisedBegin >= size) {
+            return null; // Represents Nil
+        }
+
+        return new ObjectArrayStore(Arrays.copyOfRange(values, normalisedBegin, normalisedExclusiveEnd));
+    }
+
+    @Override
+    public void set(int normalisedIndex, Object value) throws GeneraliseArrayStoreException {
+        if (normalisedIndex > size) {
+            final int originalLength = size;
+            createSpace(size, normalisedIndex - size + 1);
+            Arrays.fill(values, originalLength, normalisedIndex, NilPlaceholder.INSTANCE);
+            values[normalisedIndex] = value;
+        } else if (normalisedIndex == size) {
+            push(value);
+        } else {
+            values[normalisedIndex] = value;
+        }
+    }
+
+    @Override
+    public void setRangeSingle(int normalisedBegin, int normalisedExclusiveEnd, Object value) throws GeneraliseArrayStoreException {
+        // Is the range the whole array?
+
+        if (normalisedBegin == 0 && normalisedExclusiveEnd == size) {
+            // Reset length and set the value.
+            size = 1;
+            values[0] = value;
+        } else {
+            // Delete the range, except for the first value.
+            deleteSpace(normalisedBegin + 1, normalisedExclusiveEnd - normalisedBegin - 1);
+
+            // Set the value we left in.
+            System.err.println(normalisedBegin + " in " + size + " with " + values.length);
+            values[normalisedBegin] = value;
+        }
+    }
+
+    @Override
+    public void setRangeArray(int normalisedBegin, int normalisedExclusiveEnd, ArrayStore other) throws GeneraliseArrayStoreException {
+        setRangeArray(normalisedBegin, normalisedExclusiveEnd, (ObjectArrayStore) other.generalizeFor(null));
+    }
+
+    public void setRangeArray(int normalisedBegin, int normalisedExclusiveEnd, ObjectArrayStore other) {
+        setRangeArrayMatchingTypes(normalisedBegin, normalisedExclusiveEnd, other.values, other.size);
+    }
+
+    @Override
+    public void insert(int normalisedIndex, Object value) throws GeneraliseArrayStoreException {
+        if (normalisedIndex > size) {
+            final int originalLength = size;
+            createSpaceAtEnd(normalisedIndex - size + 1);
+            Arrays.fill(values, originalLength, normalisedIndex, NilPlaceholder.INSTANCE);
+            values[normalisedIndex] = value;
+        } else {
+            createSpace(normalisedIndex, 1);
+            values[normalisedIndex] = value;
+        }
+    }
+
+    @Override
+    public void push(Object value) throws GeneraliseArrayStoreException {
+        createSpaceAtEnd(1);
+        values[size - 1] = value;
+    }
+
+    @Override
+    public Object deleteAt(int normalisedIndex) {
+        if (normalisedIndex >= size) {
+            return NilPlaceholder.INSTANCE;
+        }
+
+        final Object value = values[normalisedIndex];
+
+        deleteSpace(normalisedIndex, 1);
+
+        return value;
+    }
+
+    @Override
+    public ArrayStore dup() {
+        return new ObjectArrayStore(Arrays.copyOf(values, size));
+    }
+
+    @Override
+    public boolean contains(Object value) {
+        for (int n = 0; n < size; n++) {
+            if (values[n].equals(value)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    public ObjectArrayStore generalizeFor(Object type) {
+        return this;
+    }
+
+    @Override
+    public Object getIndicativeValue() {
+        return null;
+    }
+
+    @Override
+    protected void setCapacityByCopying(int newCapacity) {
+        values = Arrays.copyOf(values, newCapacity);
+        capacity = values.length;
+    }
+
+    @Override
+    protected void setCapacityWithNewArray(int newCapacity) {
+        values = new Object[newCapacity];
+        capacity = values.length;
+    }
+
+    @Override
+    protected Object getValuesArrayObject() {
+        return values;
+    }
+
+    public Object[] getValues() {
+        return values;
+    }
+
+    @Override
+    public Object[] toObjectArray() {
+        if (values.length == size) {
+            return values;
+        } else {
+            return Arrays.copyOf(values, size);
+        }
+    }
+
+    @Override
+    public boolean equals(ArrayStore other) {
+        if (other instanceof ObjectArrayStore) {
+            return equals((ObjectArrayStore) other);
+        } else {
+            return super.equals(other);
+        }
+    }
+
+    public boolean equals(ObjectArrayStore other) {
+        if (other == null) {
+            return false;
+        } else if (other == this) {
+            return true;
+        } else if (other.size != size) {
+            return false;
+        } else if (other.capacity == capacity) {
+            return Arrays.equals(other.values, values);
+        } else {
+            for (int n = 0; n < size; n++) {
+                if (!other.values[n].equals(values[n])) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/ObjectImmutablePairArrayStore.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core.array;
+
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * A store for a pair of objects.
+ */
+public final class ObjectImmutablePairArrayStore extends BaseArrayStore {
+
+    private final Object first;
+    private final Object second;
+
+    public ObjectImmutablePairArrayStore(Object first, Object second) {
+        size = 2;
+        capacity = 2;
+        this.first = first;
+        this.second = second;
+    }
+
+    @Override
+    public int size() {
+        return 2;
+    }
+
+    @Override
+    public Object get(int normalisedIndex) {
+        switch (normalisedIndex) {
+            case 0:
+                return first;
+            case 1:
+                return second;
+            default:
+                return NilPlaceholder.INSTANCE;
+        }
+    }
+
+    @Override
+    public ArrayStore getRange(int normalisedBegin, int truncatedNormalisedExclusiveEnd) {
+        if (normalisedBegin >= size) {
+            return null; // Represents Nil
+        }
+
+        return new ObjectArrayStore(Arrays.copyOfRange(new Object[]{first, second}, normalisedBegin, truncatedNormalisedExclusiveEnd));
+    }
+
+    @Override
+    public void set(int normalisedIndex, Object value) throws GeneraliseArrayStoreException {
+        CompilerDirectives.transferToInterpreter();
+        throw new GeneraliseArrayStoreException();
+    }
+
+    @Override
+    public void setRangeSingle(int normalisedBegin, int truncatedNormalisedExclusiveEnd, Object value) throws GeneraliseArrayStoreException {
+        CompilerDirectives.transferToInterpreter();
+        throw new GeneraliseArrayStoreException();
+    }
+
+    @Override
+    public void setRangeArray(int normalisedBegin, int normalisedExclusiveEnd, ArrayStore other) throws GeneraliseArrayStoreException {
+        CompilerDirectives.transferToInterpreter();
+        throw new GeneraliseArrayStoreException();
+    }
+
+    @Override
+    public void insert(int normalisedIndex, Object value) throws GeneraliseArrayStoreException {
+        CompilerDirectives.transferToInterpreter();
+        throw new GeneraliseArrayStoreException();
+    }
+
+    @Override
+    public void push(Object value) throws GeneraliseArrayStoreException {
+        CompilerDirectives.transferToInterpreter();
+        throw new GeneraliseArrayStoreException();
+    }
+
+    @Override
+    public Object deleteAt(int normalisedIndex) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ArrayStore dup() {
+        return this;
+    }
+
+    @Override
+    public boolean contains(Object value) {
+        return first.equals(value) || second.equals(value);
+    }
+
+    @Override
+    public ArrayStore generalizeFor(Object type) {
+        return new ObjectArrayStore(toObjectArray());
+    }
+
+    @Override
+    public Object getIndicativeValue() {
+        return 0;
+    }
+
+    @Override
+    protected void setCapacityByCopying(int newCapacity) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    protected void setCapacityWithNewArray(int newCapacity) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    protected Object getValuesArrayObject() {
+        return new Object[]{first, second};
+    }
+
+    @Override
+    public Object[] toObjectArray() {
+        return new Object[]{first, second};
+    }
+
+    @Override
+    public boolean equals(ArrayStore other) {
+        if (other instanceof ObjectImmutablePairArrayStore) {
+            return equals((ObjectImmutablePairArrayStore) other);
+        } else {
+            return super.equals(other);
+        }
+    }
+
+    public boolean equals(ObjectImmutablePairArrayStore other) {
+        if (other == null) {
+            return false;
+        } else if (other == this) {
+            return true;
+        } else {
+            return other.first == first && other.second == second;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/RubyArray.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,428 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core.array;
+
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.CompilerDirectives.SlowPath;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Implements the Ruby {@code Array} class.
+ */
+@SuppressWarnings("unused")
+public final class RubyArray extends RubyObject {
+
+    public static class RubyArrayClass extends RubyClass {
+
+        public RubyArrayClass(RubyClass objectClass) {
+            super(null, objectClass, "Array");
+        }
+
+        @Override
+        public RubyBasicObject newInstance() {
+            return new RubyArray(this);
+        }
+
+    }
+
+    @CompilationFinal private ArrayStore store;
+
+    public RubyArray(RubyClass arrayClass) {
+        this(arrayClass, EmptyArrayStore.INSTANCE);
+    }
+
+    public RubyArray(RubyClass arrayClass, ArrayStore store) {
+        super(arrayClass);
+        this.store = store;
+    }
+
+    private static RubyArray selfAsArray(Object self) {
+        if (self instanceof RubyArray) {
+            return (RubyArray) self;
+        } else {
+            throw new IllegalStateException();
+        }
+    }
+
+    @CompilerDirectives.SlowPath
+    public static RubyArray specializedFromObject(RubyClass arrayClass, Object object) {
+        ArrayStore store;
+
+        if (object instanceof Integer || object instanceof RubyFixnum) {
+            store = new FixnumArrayStore(new int[]{GeneralConversions.toFixnum(object)});
+        } else {
+            store = new ObjectArrayStore(new Object[]{object});
+        }
+
+        return new RubyArray(arrayClass, store);
+    }
+
+    /**
+     * Create a Ruby array from a Java array of objects, choosing the best store.
+     */
+    @CompilerDirectives.SlowPath
+    public static RubyArray specializedFromObjects(RubyClass arrayClass, Object... objects) {
+        if (objects.length == 0) {
+            return new RubyArray(arrayClass);
+        }
+
+        boolean canUseFixnum = true;
+
+        for (Object object : objects) {
+            if (!(object instanceof Integer || object instanceof RubyFixnum)) {
+                canUseFixnum = false;
+            }
+        }
+
+        ArrayStore store;
+
+        if (canUseFixnum) {
+            final int[] values = new int[objects.length];
+
+            for (int n = 0; n < objects.length; n++) {
+                values[n] = GeneralConversions.toFixnum(objects[n]);
+            }
+
+            store = new FixnumArrayStore(values);
+        } else {
+            store = new ObjectArrayStore(objects);
+        }
+
+        return new RubyArray(arrayClass, store);
+    }
+
+    public Object get(int index) {
+        return store.get(ArrayUtilities.normaliseIndex(store.size(), index));
+    }
+
+    public Object getRangeInclusive(int begin, int inclusiveEnd) {
+        final int l = store.size();
+        final int normalisedInclusiveEnd = ArrayUtilities.normaliseIndex(l, inclusiveEnd);
+        return getRangeExclusive(begin, normalisedInclusiveEnd + 1);
+    }
+
+    public Object getRangeExclusive(int begin, int exclusiveEnd) {
+        final int l = store.size();
+        final int normalisedBegin = ArrayUtilities.normaliseIndex(l, begin);
+        final int truncatedNormalisedExclusiveEnd = ArrayUtilities.truncateNormalisedExclusiveIndex(l, ArrayUtilities.normaliseExclusiveIndex(l, exclusiveEnd));
+
+        final Object range = store.getRange(normalisedBegin, truncatedNormalisedExclusiveEnd);
+
+        if (range == null) {
+            return new RubyArray(getRubyClass());
+        } else {
+            return new RubyArray(getRubyClass(), (ArrayStore) range);
+        }
+    }
+
+    public void set(int index, Object value) {
+        checkFrozen();
+
+        final int l = store.size();
+        final int normalisedIndex = ArrayUtilities.normaliseIndex(l, index);
+
+        try {
+            store.set(normalisedIndex, value);
+        } catch (GeneraliseArrayStoreException e) {
+            store = store.generalizeFor(value);
+
+            try {
+                store.set(normalisedIndex, value);
+            } catch (GeneraliseArrayStoreException ex) {
+                throwSecondGeneraliseException();
+            }
+        }
+    }
+
+    public void setRangeSingleInclusive(int begin, int inclusiveEnd, Object value) {
+        final int l = store.size();
+        final int normalisedInclusiveEnd = ArrayUtilities.normaliseIndex(l, inclusiveEnd);
+        setRangeSingleExclusive(begin, normalisedInclusiveEnd + 1, value);
+    }
+
+    public void setRangeSingleExclusive(int begin, int exclusiveEnd, Object value) {
+        checkFrozen();
+
+        final int l = store.size();
+        final int normalisedBegin = ArrayUtilities.normaliseIndex(l, begin);
+        final int truncatedNormalisedExclusiveEnd = ArrayUtilities.truncateNormalisedExclusiveIndex(l, ArrayUtilities.normaliseExclusiveIndex(l, exclusiveEnd));
+
+        try {
+            store.setRangeSingle(normalisedBegin, truncatedNormalisedExclusiveEnd, value);
+        } catch (GeneraliseArrayStoreException e) {
+            store = store.generalizeFor(value);
+
+            try {
+                store.setRangeSingle(normalisedBegin, truncatedNormalisedExclusiveEnd, value);
+            } catch (GeneraliseArrayStoreException ex) {
+                throwSecondGeneraliseException();
+            }
+        }
+    }
+
+    public void setRangeArrayInclusive(int begin, int inclusiveEnd, RubyArray other) {
+        final int l = store.size();
+        final int normalisedInclusiveEnd = ArrayUtilities.normaliseIndex(l, inclusiveEnd);
+        setRangeArrayExclusive(begin, normalisedInclusiveEnd + 1, other);
+    }
+
+    public void setRangeArrayExclusive(int begin, int exclusiveEnd, RubyArray other) {
+        checkFrozen();
+
+        final int l = store.size();
+        final int normalisedBegin = ArrayUtilities.normaliseIndex(l, begin);
+        final int normalisedExclusiveEnd = ArrayUtilities.normaliseExclusiveIndex(l, exclusiveEnd);
+
+        try {
+            store.setRangeArray(normalisedBegin, normalisedExclusiveEnd, other.store);
+        } catch (GeneraliseArrayStoreException e) {
+            store = store.generalizeFor(other.store.getIndicativeValue());
+
+            try {
+                store.setRangeArray(normalisedBegin, normalisedExclusiveEnd, other.store);
+            } catch (GeneraliseArrayStoreException ex) {
+                throwSecondGeneraliseException();
+            }
+        }
+    }
+
+    public void insert(int index, Object value) {
+        checkFrozen();
+
+        final int l = store.size();
+        final int normalisedIndex = ArrayUtilities.normaliseIndex(l, index);
+
+        try {
+            store.insert(normalisedIndex, value);
+        } catch (GeneraliseArrayStoreException e) {
+            store = store.generalizeFor(value);
+
+            try {
+                store.insert(normalisedIndex, value);
+            } catch (GeneraliseArrayStoreException ex) {
+                throwSecondGeneraliseException();
+            }
+        }
+    }
+
+    public void push(Object value) {
+        checkFrozen();
+
+        if (store instanceof EmptyArrayStore) {
+            /*
+             * Normally we want to transfer to interpreter to generalize an array store, but the
+             * special case of an empty array is common, will never cause rewrites and has a simple
+             * implementation, so treat it as a special case.
+             */
+            store = ((EmptyArrayStore) store).generalizeFor(value);
+        }
+
+        try {
+            store.push(value);
+        } catch (GeneraliseArrayStoreException e) {
+            store = store.generalizeFor(value);
+
+            try {
+                store.push(value);
+            } catch (GeneraliseArrayStoreException ex) {
+                throw new IllegalStateException("Generalised to support a specific value, but value still rejected by store");
+            }
+        }
+    }
+
+    public void unshift(Object value) {
+        insert(0, value);
+    }
+
+    public Object deleteAt(int index) {
+        checkFrozen();
+
+        final int l = store.size();
+        final int normalisedIndex = ArrayUtilities.normaliseIndex(l, index);
+
+        return store.deleteAt(normalisedIndex);
+    }
+
+    @Override
+    @CompilerDirectives.SlowPath
+    public Object dup() {
+        return new RubyArray(getRubyClass(), store.dup());
+    }
+
+    public ArrayStore getArrayStore() {
+        return store;
+    }
+
+    public List<Object> asList() {
+        final RubyArray array = this;
+
+        return new AbstractList<Object>() {
+
+            @Override
+            public Object get(int n) {
+                return array.get(n);
+            }
+
+            @Override
+            public int size() {
+                return array.size();
+            }
+
+        };
+    }
+
+    public Object[] toObjectArray() {
+        return store.toObjectArray();
+    }
+
+    private static void throwSecondGeneraliseException() {
+        CompilerAsserts.neverPartOfCompilation();
+        throw new RuntimeException("Generalised based on a value, but the new store also rejected that value.");
+    }
+
+    public int size() {
+        return store.size();
+    }
+
+    public boolean contains(Object value) {
+        return store.contains(value);
+    }
+
+    /**
+     * Recursive Cartesian product.
+     * <p>
+     * The Array#product method is supposed to be able to take a block, to which it yields tuples as
+     * they are produced, so it might be worth abstracting this method into sending tuples to some
+     * interface, which either adds them to an array, or yields them to the block.
+     */
+    @SlowPath
+    public static RubyArray product(RubyClass arrayClass, RubyArray[] arrays, int l) {
+        if (arrays.length - l == 1) {
+            final RubyArray firstArray = arrays[0];
+
+            final RubyArray tuples = new RubyArray(arrayClass);
+
+            for (int i = 0; i < firstArray.size(); i++) {
+                final RubyArray tuple = new RubyArray(arrayClass);
+                tuple.push(firstArray.get(i));
+                tuples.push(tuple);
+            }
+
+            return tuples;
+        } else {
+            final RubyArray intermediateTuples = product(arrayClass, arrays, l - 1);
+            final RubyArray lastArray = arrays[l - 1];
+
+            final RubyArray tuples = new RubyArray(arrayClass);
+
+            for (int n = 0; n < intermediateTuples.size(); n++) {
+                for (int i = 0; i < lastArray.size(); i++) {
+                    final RubyArray tuple = (RubyArray) ((RubyArray) intermediateTuples.get(n)).dup();
+                    tuple.push(lastArray.get(i));
+                    tuples.push(tuple);
+                }
+            }
+
+            return tuples;
+        }
+    }
+
+    public boolean equals(RubyArray other) {
+        if (other == null) {
+            return false;
+        } else if (other == this) {
+            return true;
+        } else {
+            return store.equals(other.store);
+        }
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (other instanceof RubyArray) {
+            return equals((RubyArray) other);
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        getRubyClass().getContext().implementationMessage("Array#hash returns nonsense");
+        return 0;
+    }
+
+    public RubyArray relativeComplement(RubyArray other) {
+        // TODO(cs): specialize for different stores
+
+        final RubyArray result = new RubyArray(getRubyClass().getContext().getCoreLibrary().getArrayClass());
+
+        for (Object value : asList()) {
+            if (!other.contains(value)) {
+                result.push(value);
+            }
+        }
+
+        return result;
+    }
+
+    public String join(String separator) {
+        final StringBuilder builder = new StringBuilder();
+
+        for (int n = 0; n < size(); n++) {
+            if (n > 0) {
+                builder.append(separator);
+            }
+
+            builder.append(get(n).toString());
+        }
+
+        return builder.toString();
+    }
+
+    public static String join(Object[] parts, String separator) {
+        final StringBuilder builder = new StringBuilder();
+
+        for (int n = 0; n < parts.length; n++) {
+            if (n > 0) {
+                builder.append(separator);
+            }
+
+            builder.append(parts[n].toString());
+        }
+
+        return builder.toString();
+    }
+
+    public void flattenTo(RubyArray result) {
+        for (int n = 0; n < size(); n++) {
+            final Object value = get(n);
+
+            if (value instanceof RubyArray) {
+                ((RubyArray) value).flattenTo(result);
+            } else {
+                result.push(value);
+            }
+        }
+    }
+
+    public boolean isEmpty() {
+        return store.size() == 0;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/range/FixnumRange.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core.range;
+
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+/**
+ * A range that has {@code Fixnum} begin and end.
+ */
+public class FixnumRange extends RubyRange {
+
+    private final int begin;
+    private final int end;
+    private final boolean excludeEnd;
+
+    public FixnumRange(RubyClass rangeClass, int begin, int end, boolean excludeEnd) {
+        super(rangeClass);
+        this.begin = begin;
+        this.end = end;
+        this.excludeEnd = excludeEnd;
+    }
+
+    @Override
+    public String toString() {
+        if (excludeEnd) {
+            return begin + "..." + end;
+        } else {
+            return begin + ".." + end;
+        }
+    }
+
+    @Override
+    public RubyArray toArray() {
+        final int length = getLength();
+
+        if (length < 0) {
+            return new RubyArray(getRubyClass().getContext().getCoreLibrary().getArrayClass());
+        } else {
+            final int[] values = new int[length];
+
+            for (int n = 0; n < length; n++) {
+                values[n] = begin + n;
+            }
+
+            return new RubyArray(getRubyClass().getContext().getCoreLibrary().getArrayClass(), new FixnumArrayStore(values));
+        }
+    }
+
+    private int getLength() {
+        if (excludeEnd) {
+            return end - begin;
+        } else {
+            return end - begin + 1;
+        }
+    }
+
+    public final int getBegin() {
+        return begin;
+    }
+
+    public final int getEnd() {
+        return end;
+    }
+
+    public final int getInclusiveEnd() {
+        if (excludeEnd) {
+            return end - 1;
+        } else {
+            return end;
+        }
+    }
+
+    public final int getExclusiveEnd() {
+        if (excludeEnd) {
+            return end;
+        } else {
+            return end + 1;
+        }
+    }
+
+    @Override
+    public boolean doesExcludeEnd() {
+        return excludeEnd;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + begin;
+        result = prime * result + end;
+        result = prime * result + (excludeEnd ? 1231 : 1237);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof FixnumRange)) {
+            return false;
+        }
+        FixnumRange other = (FixnumRange) obj;
+        if (begin != other.begin) {
+            return false;
+        }
+        if (end != other.end) {
+            return false;
+        }
+        if (excludeEnd != other.excludeEnd) {
+            return false;
+        }
+        return true;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/range/ObjectRange.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core.range;
+
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+public class ObjectRange extends RubyRange {
+
+    private final Object begin;
+    private final Object end;
+    private final boolean excludeEnd;
+
+    public ObjectRange(RubyClass rangeClass, Object begin, Object end, boolean excludeEnd) {
+        super(rangeClass);
+        this.begin = begin;
+        this.end = end;
+        this.excludeEnd = excludeEnd;
+    }
+
+    @Override
+    public RubyArray toArray() {
+        throw new UnsupportedOperationException();
+    }
+
+    public Object getBegin() {
+        return begin;
+    }
+
+    public Object getEnd() {
+        return end;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((begin == null) ? 0 : begin.hashCode());
+        result = prime * result + ((end == null) ? 0 : end.hashCode());
+        result = prime * result + (excludeEnd ? 1231 : 1237);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof ObjectRange)) {
+            return false;
+        }
+        ObjectRange other = (ObjectRange) obj;
+        if (begin == null) {
+            if (other.begin != null) {
+                return false;
+            }
+        } else if (!begin.equals(other.begin)) {
+            return false;
+        }
+        if (end == null) {
+            if (other.end != null) {
+                return false;
+            }
+        } else if (!end.equals(other.end)) {
+            return false;
+        }
+        if (excludeEnd != other.excludeEnd) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public boolean doesExcludeEnd() {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/range/RubyRange.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core.range;
+
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+public abstract class RubyRange extends RubyObject {
+
+    public RubyRange(RubyClass rangeClass) {
+        super(rangeClass);
+    }
+
+    public abstract RubyArray toArray();
+
+    public abstract boolean doesExcludeEnd();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/MethodLocal.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.debug;
+
+import com.oracle.truffle.ruby.runtime.methods.*;
+
+/**
+ * A method and local variable identifier tuple.
+ */
+public class MethodLocal {
+
+    private final UniqueMethodIdentifier method;
+    private final String local;
+
+    public MethodLocal(UniqueMethodIdentifier method, String local) {
+        super();
+        this.method = method;
+        this.local = local;
+    }
+
+    @Override
+    public String toString() {
+        return "MethodLocal [method=" + method + ", local=" + local + "]";
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((local == null) ? 0 : local.hashCode());
+        result = prime * result + ((method == null) ? 0 : method.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof MethodLocal)) {
+            return false;
+        }
+        MethodLocal other = (MethodLocal) obj;
+        if (local == null) {
+            if (other.local != null) {
+                return false;
+            }
+        } else if (!local.equals(other.local)) {
+            return false;
+        }
+        if (method == null) {
+            if (other.method != null) {
+                return false;
+            }
+        } else if (!method.equals(other.method)) {
+            return false;
+        }
+        return true;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyBreakAfterProbe.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.debug;
+
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * A Ruby probe for invoking a breakpoint shell after a child execution method completes.
+ */
+public final class RubyBreakAfterProbe extends RubyProbe {
+
+    public RubyBreakAfterProbe(RubyContext context) {
+        super(context);
+    }
+
+    @Override
+    public void leave(Node astNode, VirtualFrame frame) {
+        context.getDebugManager().haltedAt(astNode, frame.materialize());
+    }
+
+    @Override
+    public void leave(Node astNode, VirtualFrame frame, boolean result) {
+        context.getDebugManager().haltedAt(astNode, frame.materialize());
+    }
+
+    @Override
+    public void leave(Node astNode, VirtualFrame frame, int result) {
+        context.getDebugManager().haltedAt(astNode, frame.materialize());
+    }
+
+    @Override
+    public void leave(Node astNode, VirtualFrame frame, double result) {
+        context.getDebugManager().haltedAt(astNode, frame.materialize());
+    }
+
+    @Override
+    public void leave(Node astNode, VirtualFrame frame, Object result) {
+        context.getDebugManager().haltedAt(astNode, frame.materialize());
+    }
+
+    @Override
+    public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
+        context.getDebugManager().haltedAt(astNode, frame.materialize());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyBreakBeforeProbe.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.debug;
+
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * A probe for invoking a breakpoint shell before a child execution method.
+ */
+public final class RubyBreakBeforeProbe extends RubyProbe {
+
+    public RubyBreakBeforeProbe(RubyContext context) {
+        super(context);
+    }
+
+    @Override
+    public void enter(Node astNode, VirtualFrame frame) {
+        context.getDebugManager().haltedAt(astNode, frame.materialize());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyDebugManager.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.debug;
+
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.nodes.instrument.*;
+import com.oracle.truffle.api.nodes.instrument.InstrumentationProbeNode.ProbeChain;
+import com.oracle.truffle.api.source.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+
+/**
+ * Manager for Ruby AST execution.
+ */
+public final class RubyDebugManager implements DebugManager {
+
+    // TODO (mlvdv) no REPL support yet for debugging "locals"; only lines
+
+    private static enum BreakpointStatus {
+
+        /**
+         * Created for a source location but not yet attached for some legitimate reason: new and
+         * not yet attached; new and the source file hasn't been loaded yet; old and the source file
+         * is in the process of being reloaded.
+         */
+        PENDING("Pending"),
+
+        /**
+         * Has an active break probe in the AST.
+         */
+        ATTACHED("Active"),
+
+        /**
+         * Should be attached, but the line location cannot be found in the source.
+         */
+        ERROR("Error: line not found"),
+
+        /**
+         * Abandoned, not attached.
+         */
+        RETIRED("Retired");
+
+        private final String name;
+
+        BreakpointStatus(String name) {
+            this.name = name;
+        }
+
+        @Override
+        public String toString() {
+            return name;
+        }
+    }
+
+    /**
+     * Map: Source lines ==> source chains known to be at line locations in an AST.
+     */
+    private final Map<SourceLineLocation, ProbeChain> linesToProbeChains = new HashMap<>();
+
+    private final Set<Source> loadedSources = new HashSet<>();
+
+    private Source beingLoaded = null;
+
+    /**
+     * Map: Source lines ==> attached Breakpoints/procs to be activated before execution at line.
+     */
+    private final Map<SourceLineLocation, RubyLineBreakpoint> linesToBreakpoints = new TreeMap<>();
+
+    /**
+     * Map: Method locals in AST ==> Method local assignments where breakpoints can be attached.
+     */
+    private final Map<MethodLocal, ProbeChain> localsToProbeChains = new HashMap<>();
+
+    /**
+     * Map: Method locals ==> Breakpoints & procs to be activated after assignment to a local.
+     */
+    private final Map<MethodLocal, RubyProbe> localsToAttachedBreakpoints = new HashMap<>();
+
+    private final RubyContext context;
+
+    public RubyDebugManager(RubyContext context) {
+        this.context = context;
+    }
+
+    public void notifyStartLoading(Source source) {
+
+        beingLoaded = source;
+
+        // Forget all the probe chains from previous loading
+        final List<SourceLineLocation> locations = new ArrayList<>();
+        for (SourceLineLocation lineLocation : linesToProbeChains.keySet()) {
+            if (lineLocation.getSource().equals(beingLoaded)) {
+                locations.add(lineLocation);
+            }
+        }
+        for (SourceLineLocation lineLocation : locations) {
+            linesToProbeChains.remove(lineLocation);
+        }
+
+        // Forget whatever we knew, and detach from old AST/ProbeChain if needed
+        for (RubyLineBreakpoint breakpoint : linesToBreakpoints.values()) {
+            if (breakpoint.getSourceLineLocation().getSource().equals(beingLoaded)) {
+                breakpoint.setPending();
+            }
+        }
+    }
+
+    public void notifyFinishedLoading(Source source) {
+        assert source == beingLoaded;
+
+        // Any pending breakpoints are now erroneous, didn't find the line.
+        for (RubyLineBreakpoint breakpoint : linesToBreakpoints.values()) {
+            if (breakpoint.getSourceLineLocation().getSource().equals(beingLoaded)) {
+                if (breakpoint.status == BreakpointStatus.PENDING) {
+                    breakpoint.setError();
+                }
+            }
+        }
+
+        loadedSources.add(source);
+        beingLoaded = null;
+
+    }
+
+    /**
+     * Notifies the manager about creation of a newly created probe chain associated with a proxy
+     * for an AST node at a specific location in the source text.
+     */
+    public void registerProbeChain(SourceSection sourceSection, ProbeChain probeChain) {
+
+        assert sourceSection.getSource().equals(beingLoaded);
+
+        // Remember this probe chain, indexed by line number
+        final SourceLineLocation lineLocation = new SourceLineLocation(sourceSection.getSource(), sourceSection.getStartLine());
+        linesToProbeChains.put(lineLocation, probeChain);
+
+        final RubyLineBreakpoint breakpoint = linesToBreakpoints.get(lineLocation);
+        if (breakpoint != null && breakpoint.location.equals(lineLocation)) {
+            // We only register while we're loading;
+            // While we're loading, there should only be pending breakpoints for this source
+            assert breakpoint.status == BreakpointStatus.PENDING;
+
+            // Found a line/probeChain where a pending breakpoint should be set
+            breakpoint.attach(probeChain);
+        }
+    }
+
+    @Override
+    public RubyLineBreakpoint setBreakpoint(SourceLineLocation lineLocation) {
+
+        RubyLineBreakpoint breakpoint = linesToBreakpoints.get(lineLocation);
+
+        if (breakpoint != null) {
+            switch (breakpoint.status) {
+                case ATTACHED:
+                    throw new RuntimeException("Breakpoint already set at line " + lineLocation);
+
+                case PENDING:
+                case ERROR:
+                    throw new RuntimeException("Breakpoint already pending at line " + lineLocation);
+
+                default:
+                    assert false;
+            }
+        } else {
+            breakpoint = new RubyLineBreakpoint(lineLocation, new RubyBreakBeforeProbe(context));
+            linesToBreakpoints.put(lineLocation, breakpoint);
+
+            final ProbeChain probeChain = linesToProbeChains.get(lineLocation);
+            if (probeChain != null) {
+                breakpoint.attach(probeChain);
+            }
+        }
+
+        return breakpoint;
+    }
+
+    @Override
+    public RubyLineBreakpoint setConditionalBreakpoint(SourceLineLocation lineLocation, String condition) {
+        throw new UnsupportedOperationException("conditional breakpoints not yet supported");
+    }
+
+    @Override
+    public LineBreakpoint[] getBreakpoints() {
+        return linesToBreakpoints.values().toArray(new LineBreakpoint[0]);
+    }
+
+    @Override
+    public void removeBreakpoint(SourceLineLocation lineLocation) {
+        final RubyLineBreakpoint breakpoint = linesToBreakpoints.get(lineLocation);
+        if (breakpoint == null) {
+            throw new RuntimeException("No break/proc located at line " + lineLocation);
+        }
+        linesToBreakpoints.remove(lineLocation);
+        breakpoint.retire();
+    }
+
+    /**
+     * Sets a Ruby proc of no arguments to be run before a specified line is executed.
+     */
+    public void setLineProc(SourceLineLocation lineLocation, RubyProc proc) {
+
+        RubyLineBreakpoint breakpoint = linesToBreakpoints.get(lineLocation);
+
+        if (breakpoint != null) {
+            switch (breakpoint.status) {
+                case ATTACHED:
+                    throw new RuntimeException("Breakpoint already set at line " + lineLocation);
+
+                case PENDING:
+                case ERROR:
+                    throw new RuntimeException("Breakpoint already pending at line " + lineLocation);
+
+                default:
+                    assert false;
+            }
+        } else {
+            breakpoint = new RubyLineBreakpoint(lineLocation, new RubyProcBeforeProbe(context, proc));
+            linesToBreakpoints.put(lineLocation, breakpoint);
+
+            final ProbeChain probeChain = linesToProbeChains.get(lineLocation);
+            if (probeChain != null) {
+                breakpoint.attach(probeChain);
+            }
+        }
+    }
+
+    /**
+     * Registers the chain of probes associated with a method local variable in the AST.
+     */
+    public void registerLocalDebugProxy(UniqueMethodIdentifier methodIdentifier, String localName, ProbeChain probeChain) {
+        final MethodLocal methodLocal = new MethodLocal(methodIdentifier, localName);
+        localsToProbeChains.put(methodLocal, probeChain);
+    }
+
+    /**
+     * Sets a breakpoint after assignment to a method local variable in the AST.
+     */
+    public void setLocalBreak(UniqueMethodIdentifier methodIdentifier, String localName) {
+        final MethodLocal methodLocal = new MethodLocal(methodIdentifier, localName);
+        ProbeChain probeChain = localsToProbeChains.get(methodLocal);
+        if (probeChain == null) {
+            throw new RuntimeException("Can't find method local " + methodLocal);
+        }
+        RubyProbe probe = localsToAttachedBreakpoints.get(methodLocal);
+        if (probe != null) {
+            throw new RuntimeException("Breakpoint already set on method local " + methodLocal);
+        }
+        probe = new RubyBreakAfterProbe(context);
+        localsToAttachedBreakpoints.put(methodLocal, probe);
+        probeChain.appendProbe(probe);
+    }
+
+    /**
+     * Sets a Ruby proc of one argument to be run after a method local assignment, passed the new
+     * value.
+     */
+    public void setLocalProc(UniqueMethodIdentifier methodIdentifier, String localName, RubyProc proc) {
+        final MethodLocal methodLocal = new MethodLocal(methodIdentifier, localName);
+        ProbeChain probeChain = localsToProbeChains.get(methodLocal);
+        if (probeChain == null) {
+            throw new RuntimeException("Can't find method local " + methodLocal);
+        }
+        RubyProbe probe = localsToAttachedBreakpoints.get(methodLocal);
+        if (probe != null) {
+            throw new RuntimeException("Assignment proc already set on method local " + methodLocal);
+        }
+        probe = new RubyProcAfterProbe(context, proc);
+        localsToAttachedBreakpoints.put(methodLocal, probe);
+        probeChain.appendProbe(probe);
+    }
+
+    /**
+     * Removes a break or proc on assignment to a method local variable in the AST.
+     */
+    public void removeLocalProbe(UniqueMethodIdentifier methodIdentifier, String localName) {
+        final MethodLocal methodLocal = new MethodLocal(methodIdentifier, localName);
+        RubyProbe probe = localsToAttachedBreakpoints.get(methodLocal);
+        if (probe == null) {
+            throw new RuntimeException("No breakpoint set on method local " + methodLocal);
+        }
+        localsToProbeChains.get(methodLocal).removeProbe(probe);
+        localsToAttachedBreakpoints.remove(methodLocal);
+    }
+
+    /**
+     * Receives notification of a suspended execution context; execution resumes when this method
+     * returns.
+     * 
+     * @param astNode a guest language AST node that represents the current execution site, assumed
+     *            not to be any kind of {@link InstrumentationNode},
+     * @param frame execution frame at the site where execution suspended
+     */
+    public void haltedAt(Node astNode, MaterializedFrame frame) {
+        context.haltedAt(astNode, frame);
+    }
+
+    private static final class RubyLineBreakpoint implements DebugManager.LineBreakpoint, Comparable {
+
+        private final SourceLineLocation location;
+
+        private RubyProbe probe;  // non-null until RETIRED, but may get replaced.
+        private ProbeChain probeChain = null;  // only non-null when ATTACHED
+        private BreakpointStatus status = BreakpointStatus.PENDING;
+
+        public RubyLineBreakpoint(SourceLineLocation location, RubyProbe probe) {
+            this.location = location;
+            this.probe = probe;
+        }
+
+        public SourceLineLocation getSourceLineLocation() {
+            return location;
+        }
+
+        // ensure sorted by location
+        public int compareTo(Object o) {
+            final RubyLineBreakpoint other = (RubyLineBreakpoint) o;
+            return location.compareTo(other.location);
+        }
+
+        @Override
+        public String getDebugStatus() {
+            return status == null ? "<none>" : status.name;
+        }
+
+        private void attach(ProbeChain chain) {
+            assert status == BreakpointStatus.PENDING;
+
+            probeChain = chain;
+            probeChain.appendProbe(probe);
+
+            status = BreakpointStatus.ATTACHED;
+        }
+
+        private void setPending() {
+            switch (status) {
+                case ATTACHED:
+                    detach();
+                    // TODO (mlvdv) replace the probe
+                    status = BreakpointStatus.PENDING;
+                    break;
+                case ERROR:
+                    status = BreakpointStatus.PENDING;
+                    break;
+                case PENDING:
+                    break;
+                case RETIRED:
+                    assert false;
+                    break;
+                default:
+                    assert false;
+            }
+        }
+
+        public void setError() {
+            assert status == BreakpointStatus.PENDING;
+
+            status = BreakpointStatus.ERROR;
+        }
+
+        private void detach() {
+            assert status == BreakpointStatus.ATTACHED;
+
+            probeChain.removeProbe(probe);
+            probeChain = null;
+
+            status = BreakpointStatus.PENDING;
+        }
+
+        private void retire() {
+
+            if (probeChain != null) {
+                probeChain.removeProbe(probe);
+            }
+            probe = null;
+            probeChain = null;
+
+            status = BreakpointStatus.RETIRED;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyProbe.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.debug;
+
+import com.oracle.truffle.api.nodes.instrument.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * A "probe node" implemented specifically for the Ruby implementation; subclasses need only
+ * override those members of {@link InstrumentationProbeEvents} for which some action is needed.
+ */
+public abstract class RubyProbe extends InstrumentationProbeNode.DefaultProbeNode {
+
+    protected final RubyContext context;
+
+    public RubyProbe(RubyContext context) {
+        this.context = context;
+        assert context != null;
+    }
+
+    public RubyContext getContext() {
+        return context;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyProcAfterProbe.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.debug;
+
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+/**
+ * A probe for instrumenting a Ruby program with a Ruby procedure to run on the return value from
+ * node execution.
+ */
+public final class RubyProcAfterProbe extends RubyProbe {
+
+    private final RubyProc proc;
+
+    public RubyProcAfterProbe(RubyContext context, RubyProc proc) {
+        super(context);
+        this.proc = proc;
+    }
+
+    @Override
+    public void leave(Node astNode, VirtualFrame frame) {
+        proc.call(frame.pack());
+    }
+
+    @Override
+    public void leave(Node astNode, VirtualFrame frame, boolean result) {
+        proc.call(frame.pack(), result);
+    }
+
+    @Override
+    public void leave(Node astNode, VirtualFrame frame, int result) {
+        proc.call(frame.pack(), result);
+    }
+
+    @Override
+    public void leave(Node astNode, VirtualFrame frame, double result) {
+        proc.call(frame.pack(), result);
+    }
+
+    @Override
+    public void leave(Node astNode, VirtualFrame frame, Object result) {
+        proc.call(frame.pack(), result);
+    }
+
+    @Override
+    public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) {
+        proc.call(frame.pack());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyProcBeforeProbe.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.debug;
+
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+/**
+ * A probe for instrumenting a Ruby program with a Ruby procedure to run before a call.
+ */
+public final class RubyProcBeforeProbe extends RubyProbe {
+
+    private final RubyProc proc;
+
+    public RubyProcBeforeProbe(RubyContext context, RubyProc proc) {
+        super(context);
+        this.proc = proc;
+    }
+
+    @Override
+    public void enter(Node astNode, VirtualFrame frame) {
+        proc.call(frame.pack());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyTraceProbe.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.debug;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.subsystems.*;
+
+/**
+ * A "trace" probe that has no runtime cost until activated, at which time it invokes a trace
+ * message.
+ */
+public final class RubyTraceProbe extends RubyProbe {
+
+    private final Assumption notTracingAssumption;
+
+    @CompilerDirectives.CompilationFinal private boolean tracingEverEnabled = false;
+
+    public RubyTraceProbe(RubyContext context) {
+        super(context);
+        this.notTracingAssumption = context.getTraceManager().getNotTracingAssumption();
+    }
+
+    @Override
+    public void enter(Node astNode, VirtualFrame frame) {
+        if (!tracingEverEnabled) {
+            try {
+                notTracingAssumption.check();
+            } catch (InvalidAssumptionException e) {
+                tracingEverEnabled = true;
+            }
+        }
+        final TraceManager traceManager = context.getTraceManager();
+        if (tracingEverEnabled && traceManager.hasTraceProc()) {
+            final SourceSection sourceSection = astNode.getEncapsulatingSourceSection();
+            traceManager.trace("line", sourceSection.getSource().getName(), sourceSection.getStartLine(), 0, null, null);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/lookup/LookupFork.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.lookup;
+
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.utilities.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+
+/**
+ * A fork in the lookup graph. Look at first and then look at second.
+ */
+public class LookupFork implements LookupNode {
+
+    private LookupNode first;
+    private LookupNode second;
+
+    public LookupFork(LookupNode first, LookupNode second) {
+        this.first = first;
+        this.second = second;
+    }
+
+    public boolean setClassVariableIfAlreadySet(String variableName, Object value) {
+        if (first.setClassVariableIfAlreadySet(variableName, value)) {
+            return true;
+        }
+
+        return second.setClassVariableIfAlreadySet(variableName, value);
+    }
+
+    @Override
+    public Object lookupConstant(String constantName) {
+        final Object firstResult = first.lookupConstant(constantName);
+
+        if (firstResult != null) {
+            return firstResult;
+        }
+
+        return second.lookupConstant(constantName);
+    }
+
+    @Override
+    public Object lookupClassVariable(String classVariable) {
+        final Object firstResult = first.lookupClassVariable(classVariable);
+
+        if (firstResult != null) {
+            return firstResult;
+        }
+
+        return second.lookupClassVariable(classVariable);
+    }
+
+    @Override
+    public RubyMethod lookupMethod(String methodName) {
+        final RubyMethod firstResult = first.lookupMethod(methodName);
+
+        if (firstResult != null) {
+            return firstResult;
+        }
+
+        return second.lookupMethod(methodName);
+    }
+
+    @Override
+    public Assumption getUnmodifiedAssumption() {
+        return new UnionAssumption(first.getUnmodifiedAssumption(), second.getUnmodifiedAssumption());
+    }
+
+    public LookupNode getFirst() {
+        return first;
+    }
+
+    public LookupNode getSecond() {
+        return second;
+    }
+
+    public Set<String> getClassVariables() {
+        final Set<String> classVariables = new HashSet<>();
+        classVariables.addAll(first.getClassVariables());
+        classVariables.addAll(second.getClassVariables());
+        return classVariables;
+    }
+
+    public void getMethods(Map<String, RubyMethod> methods) {
+        second.getMethods(methods);
+        first.getMethods(methods);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/lookup/LookupNode.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.lookup;
+
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+
+/**
+ * A node in the lookup graph. We abstract from modules and classes because with includes and
+ * singletons and so on there are more nodes in the graph than there are classes and modules.
+ */
+public interface LookupNode {
+
+    boolean setClassVariableIfAlreadySet(String variableName, Object value);
+
+    Object lookupConstant(String constantName);
+
+    Object lookupClassVariable(String variableName);
+
+    RubyMethod lookupMethod(String methodName);
+
+    Assumption getUnmodifiedAssumption();
+
+    Set<String> getClassVariables();
+
+    void getMethods(Map<String, RubyMethod> methods);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/lookup/LookupTerminal.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.lookup;
+
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.utilities.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+
+/**
+ * A terminal in the lookup graph.
+ */
+public class LookupTerminal implements LookupNode {
+
+    public static final LookupTerminal INSTANCE = new LookupTerminal();
+
+    public boolean setClassVariableIfAlreadySet(String variableName, Object value) {
+        return false;
+    }
+
+    @Override
+    public Object lookupConstant(String constantName) {
+        return null;
+    }
+
+    @Override
+    public Object lookupClassVariable(String constantName) {
+        return null;
+    }
+
+    @Override
+    public RubyMethod lookupMethod(String methodName) {
+        return null;
+    }
+
+    @Override
+    public Assumption getUnmodifiedAssumption() {
+        return AlwaysValidAssumption.INSTANCE;
+    }
+
+    public Set<String> getClassVariables() {
+        return Collections.emptySet();
+    }
+
+    public void getMethods(Map<String, RubyMethod> methods) {
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/methods/Arity.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.methods;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+
+/**
+ * Represents the arity, or parameter contract, of a method.
+ */
+public class Arity {
+
+    private final int minimum;
+    public static final int NO_MINIMUM = 0;
+
+    private final int maximum;
+    public static final int NO_MAXIMUM = Integer.MAX_VALUE;
+
+    public static final Arity NO_ARGS = new Arity(0, 0);
+    public static final Arity ONE_ARG = new Arity(1, 1);
+
+    public Arity(int minimum, int maximum) {
+        this.minimum = minimum;
+        this.maximum = maximum;
+    }
+
+    public void checkArguments(RubyContext context, Object[] arguments) {
+        if (arguments.length < minimum || arguments.length > maximum) {
+            CompilerDirectives.transferToInterpreter();
+            throw new RaiseException(context.getCoreLibrary().argumentError(arguments.length, minimum));
+        }
+    }
+
+    public int getMinimum() {
+        return minimum;
+    }
+
+    public int getMaximum() {
+        return maximum;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("Arity(%d, %d)", minimum, maximum);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/methods/CallTargetMethodImplementation.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.methods;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+public class CallTargetMethodImplementation implements MethodImplementation {
+
+    private final CallTarget callTarget;
+    private final MaterializedFrame declarationFrame;
+
+    public CallTargetMethodImplementation(CallTarget callTarget, MaterializedFrame declarationFrame) {
+        assert callTarget != null;
+
+        this.callTarget = callTarget;
+        this.declarationFrame = declarationFrame;
+    }
+
+    public Object call(PackedFrame caller, Object self, RubyProc block, Object... args) {
+        assert RubyContext.shouldObjectBeVisible(self);
+        assert RubyContext.shouldObjectsBeVisible(args);
+
+        RubyArguments arguments = new RubyArguments(declarationFrame, self, block, args);
+
+        final Object result = callTarget.call(caller, arguments);
+
+        assert RubyContext.shouldObjectBeVisible(result);
+
+        return result;
+    }
+
+    public MaterializedFrame getDeclarationFrame() {
+        return declarationFrame;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/methods/MethodImplementation.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.methods;
+
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+public interface MethodImplementation {
+
+    Object call(PackedFrame caller, Object self, RubyProc block, Object... args);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/methods/RubyMethod.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.methods;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Any kind of Ruby method - so normal methods in classes and modules, but also blocks, procs,
+ * lambdas and native methods written in Java.
+ */
+public class RubyMethod {
+
+    private final SourceSection sourceSection;
+    private final RubyModule declaringModule;
+    private final UniqueMethodIdentifier uniqueIdentifier;
+    private final String intrinsicName;
+    private final String name;
+    private final Visibility visibility;
+    private final boolean undefined;
+
+    private final MethodImplementation implementation;
+
+    public RubyMethod(SourceSection sourceSection, RubyModule declaringModule, UniqueMethodIdentifier uniqueIdentifier, String intrinsicName, String name, Visibility visibility, boolean undefined,
+                    MethodImplementation implementation) {
+        this.sourceSection = sourceSection;
+        this.declaringModule = declaringModule;
+        this.uniqueIdentifier = uniqueIdentifier;
+        this.intrinsicName = intrinsicName;
+        this.name = name;
+        this.visibility = visibility;
+        this.undefined = undefined;
+        this.implementation = implementation;
+    }
+
+    public Object call(PackedFrame caller, Object self, RubyProc block, Object... args) {
+        assert RubyContext.shouldObjectBeVisible(self);
+        assert RubyContext.shouldObjectsBeVisible(args);
+
+        final Object result = implementation.call(caller, self, block, args);
+
+        assert RubyContext.shouldObjectBeVisible(result);
+
+        return result;
+    }
+
+    public SourceSection getSourceSection() {
+        return sourceSection;
+    }
+
+    public UniqueMethodIdentifier getUniqueIdentifier() {
+        return uniqueIdentifier;
+    }
+
+    public String getIntrinsicName() {
+        return intrinsicName;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Visibility getVisibility() {
+        return visibility;
+    }
+
+    public boolean isUndefined() {
+        return undefined;
+    }
+
+    public MethodImplementation getImplementation() {
+        return implementation;
+    }
+
+    public RubyMethod withNewName(String newName) {
+        if (newName.equals(name)) {
+            return this;
+        }
+
+        return new RubyMethod(sourceSection, declaringModule, uniqueIdentifier, intrinsicName, newName, visibility, undefined, implementation);
+    }
+
+    public RubyMethod withNewVisibility(Visibility newVisibility) {
+        if (newVisibility == visibility) {
+            return this;
+        }
+
+        return new RubyMethod(sourceSection, declaringModule, uniqueIdentifier, intrinsicName, name, newVisibility, undefined, implementation);
+    }
+
+    public RubyMethod withDeclaringModule(RubyModule newDeclaringModule) {
+        if (newDeclaringModule == declaringModule) {
+            return this;
+        }
+
+        return new RubyMethod(sourceSection, newDeclaringModule, uniqueIdentifier, intrinsicName, name, visibility, undefined, implementation);
+    }
+
+    public RubyMethod undefined() {
+        if (undefined) {
+            return this;
+        }
+
+        return new RubyMethod(sourceSection, declaringModule, uniqueIdentifier, intrinsicName, name, visibility, true, implementation);
+    }
+
+    public boolean isVisibleTo(RubyBasicObject caller) {
+        if (caller instanceof RubyModule) {
+            if (isVisibleTo((RubyModule) caller)) {
+                return true;
+            }
+        }
+
+        if (isVisibleTo(caller.getRubyClass())) {
+            return true;
+        }
+
+        if (isVisibleTo(caller.getSingletonClass())) {
+            return true;
+        }
+
+        return false;
+    }
+
+    private boolean isVisibleTo(RubyModule module) {
+        switch (visibility) {
+            case PUBLIC:
+                return true;
+
+            case PROTECTED:
+                return true;
+
+            case PRIVATE:
+                if (module == declaringModule) {
+                    return true;
+                }
+
+                if (module.getSingletonClass() == declaringModule) {
+                    return true;
+                }
+
+                if (module.getParentModule() != null && isVisibleTo(module.getParentModule())) {
+                    return true;
+                }
+
+                return false;
+
+            default:
+                return false;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return implementation.toString();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/methods/UniqueMethodIdentifier.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.methods;
+
+/**
+ * An object that uniquely identifies a method as it appears in the source code, and that follows
+ * the method as a normal method, when it becomes a proc, when it changes access or is aliased etc.
+ */
+public class UniqueMethodIdentifier {
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/methods/Visibility.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.methods;
+
+/**
+ * Represents the visibility of a method.
+ */
+public enum Visibility {
+    PUBLIC, PROTECTED, PRIVATE
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/FixnumStorageLocation.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.objects;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * A storage location for Fixnums.
+ */
+public class FixnumStorageLocation extends PrimitiveStorageLocation {
+
+    public FixnumStorageLocation(ObjectLayout objectLayout, long offset, int mask) {
+        super(objectLayout, offset, mask);
+    }
+
+    @Override
+    public Object read(RubyBasicObject object, boolean condition) {
+        try {
+            return readFixnum(object, condition);
+        } catch (UnexpectedResultException e) {
+            return e.getResult();
+        }
+    }
+
+    public int readFixnum(RubyBasicObject object, boolean condition) throws UnexpectedResultException {
+        if (isSet(object)) {
+            return CompilerDirectives.unsafeGetInt(object, offset, condition, this);
+        } else {
+            throw new UnexpectedResultException(NilPlaceholder.INSTANCE);
+        }
+    }
+
+    @Override
+    public void write(RubyBasicObject object, Object value) throws GeneralizeStorageLocationException {
+        if (value instanceof Integer) {
+            writeFixnum(object, (int) value);
+        } else if (value instanceof NilPlaceholder) {
+            markAsUnset(object);
+        } else {
+            throw new GeneralizeStorageLocationException();
+        }
+    }
+
+    public void writeFixnum(RubyBasicObject object, int value) {
+        CompilerDirectives.unsafePutInt(object, offset, value, null);
+        markAsSet(object);
+    }
+
+    @Override
+    public Class getStoredClass() {
+        return Integer.class;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/FloatStorageLocation.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.objects;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * A storage location for Floats.
+ */
+public class FloatStorageLocation extends PrimitiveStorageLocation {
+
+    public FloatStorageLocation(ObjectLayout objectLayout, long offset, int mask) {
+        super(objectLayout, offset, mask);
+    }
+
+    @Override
+    public Object read(RubyBasicObject object, boolean condition) {
+        try {
+            return readFloat(object, condition);
+        } catch (UnexpectedResultException e) {
+            return e.getResult();
+        }
+    }
+
+    public double readFloat(RubyBasicObject object, boolean condition) throws UnexpectedResultException {
+        if (isSet(object)) {
+            return CompilerDirectives.unsafeGetDouble(object, offset, condition, this);
+        } else {
+            throw new UnexpectedResultException(NilPlaceholder.INSTANCE);
+        }
+    }
+
+    @Override
+    public void write(RubyBasicObject object, Object value) throws GeneralizeStorageLocationException {
+        if (value instanceof Double) {
+            writeFloat(object, (double) value);
+        } else if (value instanceof NilPlaceholder) {
+            markAsUnset(object);
+        } else {
+            throw new GeneralizeStorageLocationException();
+        }
+    }
+
+    public void writeFloat(RubyBasicObject object, Double value) {
+        CompilerDirectives.unsafePutDouble(object, offset, value, null);
+        markAsSet(object);
+    }
+
+    @Override
+    public Class getStoredClass() {
+        return Double.class;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/GeneralizeStorageLocationException.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.objects;
+
+/**
+ * Indicates that a storage location cannot store the type of value that you asked it to.
+ */
+public class GeneralizeStorageLocationException extends Exception {
+
+    private static final long serialVersionUID = -5136358171098229961L;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/ObjectLayout.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.objects;
+
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.Map.Entry;
+
+import sun.misc.*;
+
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.nodes.NodeUtil.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * Maps names of instance variables to storage locations, which are either the offset of a primitive
+ * field in {@code RubyBasicObject}, or an index into an object array in {@code RubyBasicObject}.
+ * Object layouts are chained, with each having zero or one parents.
+ * <p>
+ * Object layouts are immutable, with the methods for adding new instance variables of generalizing
+ * the type of existing instance variables returning new object layouts.
+ */
+public class ObjectLayout {
+
+    public static final ObjectLayout EMPTY = new ObjectLayout("(empty)");
+
+    private final String originHint;
+
+    private final ObjectLayout parent;
+
+    private final Map<String, StorageLocation> storageLocations = new HashMap<>();
+
+    private final int primitiveStorageLocationsUsed;
+    private final int objectStorageLocationsUsed;
+
+    public static final long FIRST_OFFSET = getFirstOffset();
+
+    private ObjectLayout(String originHint) {
+        this.originHint = originHint;
+        this.parent = null;
+        primitiveStorageLocationsUsed = 0;
+        objectStorageLocationsUsed = 0;
+    }
+
+    public ObjectLayout(String originHint, RubyContext context, ObjectLayout parent) {
+        this(originHint, context, parent, new HashMap<String, Class>());
+    }
+
+    public ObjectLayout(String originHint, RubyContext context, ObjectLayout parent, Map<String, Class> storageTypes) {
+        this.originHint = originHint;
+        this.parent = parent;
+
+        // Start our offsets from where the parent ends
+
+        int primitiveStorageLocationIndex;
+        int objectStorageLocationIndex;
+
+        if (parent == null) {
+            primitiveStorageLocationIndex = 0;
+            objectStorageLocationIndex = 0;
+        } else {
+            primitiveStorageLocationIndex = parent.primitiveStorageLocationsUsed;
+            objectStorageLocationIndex = parent.objectStorageLocationsUsed;
+        }
+
+        // Go through the variables we've been asked to store
+
+        for (Entry<String, Class> entry : storageTypes.entrySet()) {
+            // TODO(cs): what if parent has it, but we need a more general type?
+
+            final String name = entry.getKey();
+            final Class type = entry.getValue();
+
+            if (parent == null || parent.findStorageLocation(name) == null) {
+                boolean canStoreInPrimitive = false;
+                int primitivesNeeded = 0;
+
+                if (type == Integer.class) {
+                    canStoreInPrimitive = true;
+                    primitivesNeeded = 1;
+                } else if (type == Double.class) {
+                    canStoreInPrimitive = true;
+                    primitivesNeeded = 2;
+                }
+
+                if (canStoreInPrimitive && primitiveStorageLocationIndex + primitivesNeeded <= RubyBasicObject.PRIMITIVE_STORAGE_LOCATIONS_COUNT) {
+                    final long offset = FIRST_OFFSET + Unsafe.ARRAY_INT_INDEX_SCALE * primitiveStorageLocationIndex;
+                    final int mask = 1 << primitiveStorageLocationIndex;
+
+                    StorageLocation newStorageLocation = null;
+
+                    if (type == Integer.class) {
+                        newStorageLocation = new FixnumStorageLocation(this, offset, mask);
+                    } else if (type == Double.class) {
+                        newStorageLocation = new FloatStorageLocation(this, offset, mask);
+                    }
+
+                    storageLocations.put(entry.getKey(), newStorageLocation);
+                    primitiveStorageLocationIndex += primitivesNeeded;
+                } else {
+                    if (canStoreInPrimitive && context.getConfiguration().getPrintSpiltInstanceVariables()) {
+                        context.implementationMessage("instance variable %s of type %s spilt due to lack of space", name, type.getName());
+                    }
+
+                    final ObjectStorageLocation newStorageLocation = new ObjectStorageLocation(this, objectStorageLocationIndex);
+                    storageLocations.put(entry.getKey(), newStorageLocation);
+                    objectStorageLocationIndex++;
+                }
+            }
+        }
+
+        primitiveStorageLocationsUsed = primitiveStorageLocationIndex;
+        objectStorageLocationsUsed = objectStorageLocationIndex;
+    }
+
+    /**
+     * Create a new version of this layout, but with a different parent. The new parent probably
+     * comes from the same Ruby class as it did, but it's a new layout because layouts are
+     * immutable, so modifications to the superclass yields a new layout.
+     */
+    public ObjectLayout renew(RubyContext context, ObjectLayout newParent) {
+        return new ObjectLayout(originHint + ".renewed", context, newParent, getStorageTypes());
+    }
+
+    /**
+     * Create a new version of this layout but with a new variable.
+     */
+    public ObjectLayout withNewVariable(RubyContext context, String name, Class type) {
+        final Map<String, Class> storageTypes = getStorageTypes();
+        storageTypes.put(name, type);
+        return new ObjectLayout(originHint + ".withnew", context, parent, storageTypes);
+    }
+
+    /**
+     * Create a new version of this layout but with an existing variable generalized to support any
+     * type.
+     */
+    public ObjectLayout withGeneralisedVariable(RubyContext context, String name) {
+        return withNewVariable(context, name, Object.class);
+    }
+
+    /**
+     * Get a map of instance variable names to the type that they store.
+     */
+    public Map<String, Class> getStorageTypes() {
+        Map<String, Class> storageTypes = new HashMap<>();
+
+        for (Entry<String, StorageLocation> entry : storageLocations.entrySet()) {
+            final String name = entry.getKey();
+            final StorageLocation storageLocation = entry.getValue();
+
+            if (storageLocation.getStoredClass() != null) {
+                storageTypes.put(name, storageLocation.getStoredClass());
+            }
+        }
+
+        return storageTypes;
+    }
+
+    /**
+     * Get a map of instance variable names to the type that they store, but including both this
+     * layout and all parent layouts.
+     */
+    public Map<String, StorageLocation> getAllStorageLocations() {
+        final Map<String, StorageLocation> allStorageLocations = new HashMap<>();
+
+        allStorageLocations.putAll(storageLocations);
+
+        if (parent != null) {
+            allStorageLocations.putAll(parent.getAllStorageLocations());
+        }
+
+        return allStorageLocations;
+    }
+
+    /**
+     * Find a storage location from a name, including in parents.
+     */
+    public StorageLocation findStorageLocation(String name) {
+        final StorageLocation storageLocation = storageLocations.get(name);
+
+        if (storageLocation != null) {
+            return storageLocation;
+        }
+
+        if (parent == null) {
+            return null;
+        }
+
+        return parent.findStorageLocation(name);
+    }
+
+    public int getObjectStorageLocationsUsed() {
+        return objectStorageLocationsUsed;
+    }
+
+    /**
+     * Does this layout include another layout? That is, is that other layout somewhere in the chain
+     * of parents? We say 'include' because all of the variables in a parent layout are available in
+     * your layout as well.
+     */
+    public boolean contains(ObjectLayout other) {
+        ObjectLayout layout = this;
+
+        do {
+            if (other == layout) {
+                return true;
+            }
+
+            layout = layout.parent;
+        } while (layout != null);
+
+        return false;
+    }
+
+    public String getOriginHint() {
+        return originHint;
+    }
+
+    private static long getFirstOffset() {
+        try {
+            final Field fieldOffsetProviderField = NodeUtil.class.getDeclaredField("unsafeFieldOffsetProvider");
+            fieldOffsetProviderField.setAccessible(true);
+            final FieldOffsetProvider fieldOffsetProvider = (FieldOffsetProvider) fieldOffsetProviderField.get(null);
+
+            final Field firstPrimitiveField = RubyBasicObject.class.getDeclaredField("primitiveStorageLocation01");
+            return fieldOffsetProvider.objectFieldOffset(firstPrimitiveField);
+        } catch (NoSuchFieldException | IllegalAccessException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/ObjectStorageLocation.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.objects;
+
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * A storage location for any object.
+ */
+public class ObjectStorageLocation extends StorageLocation {
+
+    private final int index;
+
+    public ObjectStorageLocation(ObjectLayout objectLayout, int index) {
+        super(objectLayout);
+        this.index = index;
+    }
+
+    @Override
+    public boolean isSet(RubyBasicObject object) {
+        return object.objectStorageLocations[index] != null;
+    }
+
+    @Override
+    public Object read(RubyBasicObject object, boolean condition) {
+        final Object result = object.objectStorageLocations[index];
+
+        if (result == null) {
+            return NilPlaceholder.INSTANCE;
+        } else {
+            return result;
+        }
+    }
+
+    @Override
+    public void write(RubyBasicObject object, Object value) {
+        object.objectStorageLocations[index] = value;
+    }
+
+    @Override
+    public Class getStoredClass() {
+        return Object.class;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/PrimitiveStorageLocation.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.objects;
+
+/**
+ * A storage location that uses one of the primitive fields in {@code RubyBasObject}.
+ */
+public abstract class PrimitiveStorageLocation extends StorageLocation {
+
+    protected final long offset;
+    protected final int mask;
+
+    protected PrimitiveStorageLocation(ObjectLayout objectLayout, long offset, int mask) {
+        super(objectLayout);
+        this.offset = offset;
+        this.mask = mask;
+    }
+
+    @Override
+    public boolean isSet(RubyBasicObject object) {
+        return (object.primitiveSetMap & mask) != 0;
+    }
+
+    protected void markAsSet(RubyBasicObject object) {
+        object.primitiveSetMap |= mask;
+    }
+
+    protected void markAsUnset(RubyBasicObject object) {
+        object.primitiveSetMap &= ~mask;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/RubyBasicObject.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.objects;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.lookup.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+
+/**
+ * Represents the Ruby {@code BasicObject} class - the root of the Ruby class hierarchy.
+ */
+public class RubyBasicObject {
+
+    @CompilationFinal protected RubyClass rubyClass;
+    protected RubyClass rubySingletonClass;
+
+    protected LookupNode lookupNode;
+
+    protected long objectID = -1;
+
+    public boolean hasPrivateLayout = false;
+    private ObjectLayout objectLayout;
+
+    public static final int PRIMITIVE_STORAGE_LOCATIONS_COUNT = 14;
+    protected int primitiveStorageLocation01;
+    protected int primitiveStorageLocation02;
+    protected int primitiveStorageLocation03;
+    protected int primitiveStorageLocation04;
+    protected int primitiveStorageLocation05;
+    protected int primitiveStorageLocation06;
+    protected int primitiveStorageLocation07;
+    protected int primitiveStorageLocation08;
+    protected int primitiveStorageLocation09;
+    protected int primitiveStorageLocation10;
+    protected int primitiveStorageLocation11;
+    protected int primitiveStorageLocation12;
+    protected int primitiveStorageLocation13;
+    protected int primitiveStorageLocation14;
+
+    // A bit map to indicate which primitives are set, so that they can be Nil
+    protected int primitiveSetMap;
+
+    protected Object[] objectStorageLocations;
+
+    public RubyBasicObject(RubyClass rubyClass) {
+        if (rubyClass != null) {
+            unsafeSetRubyClass(rubyClass);
+
+            if (rubyClass.getContext().getConfiguration().getFullObjectSpace()) {
+                rubyClass.getContext().getObjectSpaceManager().add(this);
+            }
+        }
+    }
+
+    public void initialize() {
+    }
+
+    public LookupNode getLookupNode() {
+        return lookupNode;
+    }
+
+    public RubyClass getRubyClass() {
+        assert rubyClass != null;
+        return rubyClass;
+    }
+
+    public boolean hasPrivateLayout() {
+        return hasPrivateLayout;
+    }
+
+    public ObjectLayout getObjectLayout() {
+        return objectLayout;
+    }
+
+    public ObjectLayout getUpdatedObjectLayout() {
+        updateLayout();
+        return objectLayout;
+    }
+
+    /**
+     * Does this object have an instance variable defined?
+     */
+    public boolean isInstanceVariableDefined(String name) {
+        if (!hasPrivateLayout && objectLayout != rubyClass.getObjectLayoutForInstances()) {
+            updateLayout();
+        }
+
+        return objectLayout.findStorageLocation(name) != null;
+    }
+
+    /**
+     * Set an instance variable to be a value. Slow path.
+     */
+    public void setInstanceVariable(String name, Object value) {
+        CompilerAsserts.neverPartOfCompilation();
+
+        // If the object's layout doesn't match the class, update
+
+        if (!hasPrivateLayout && objectLayout != rubyClass.getObjectLayoutForInstances()) {
+            updateLayout();
+        }
+
+        // Find the storage location
+
+        StorageLocation storageLocation = objectLayout.findStorageLocation(name);
+
+        if (storageLocation == null) {
+            /*
+             * It doesn't exist, so create a new layout for the class that includes it and update
+             * the layout of this object.
+             */
+
+            rubyClass.setObjectLayoutForInstances(rubyClass.getObjectLayoutForInstances().withNewVariable(rubyClass.getContext(), name, value.getClass()));
+            updateLayout();
+
+            storageLocation = objectLayout.findStorageLocation(name);
+        }
+
+        // Try to write to that storage location
+
+        try {
+            storageLocation.write(this, value);
+        } catch (GeneralizeStorageLocationException e) {
+            /*
+             * It might not be able to store the type that we passed, if not generalize the class's
+             * layout and update the layout of this object.
+             */
+
+            rubyClass.setObjectLayoutForInstances(rubyClass.getObjectLayoutForInstances().withGeneralisedVariable(rubyClass.getContext(), name));
+            updateLayout();
+
+            storageLocation = objectLayout.findStorageLocation(name);
+
+            // Try to write to the generalized storage location
+
+            try {
+                storageLocation.write(this, value);
+            } catch (GeneralizeStorageLocationException e1) {
+                // We know that we just generalized it, so this should not happen
+                throw new RuntimeException("Generalised an instance variable, but it still rejected the value");
+            }
+        }
+    }
+
+    /**
+     * Get the value of an instance variable, or Nil if it isn't defined. Slow path.
+     */
+    public Object getInstanceVariable(String name) {
+        CompilerAsserts.neverPartOfCompilation();
+
+        // If the object's layout doesn't match the class, update
+
+        if (!hasPrivateLayout && objectLayout != rubyClass.getObjectLayoutForInstances()) {
+            updateLayout();
+        }
+
+        // Find the storage location
+
+        final StorageLocation storageLocation = objectLayout.findStorageLocation(name);
+
+        // Get the value
+
+        if (storageLocation == null) {
+            return NilPlaceholder.INSTANCE;
+        }
+
+        return storageLocation.read(this, true);
+    }
+
+    public String[] getInstanceVariableNames() {
+        final Set<String> instanceVariableNames = getInstanceVariables().keySet();
+        return instanceVariableNames.toArray(new String[instanceVariableNames.size()]);
+    }
+
+    public RubyClass getSingletonClass() {
+        if (rubySingletonClass == null) {
+            /*
+             * The object a of class A has a singleton class a' of class Class, with name
+             * #<Class:#<A:objectid>>, and with superclass that is A.
+             * 
+             * irb(main):001:0> class A; end
+             * 
+             * => nil
+             * 
+             * irb(main):002:0> a = A.new
+             * 
+             * => #<A:0x007ff612a631e0>
+             * 
+             * irb(main):003:0> a.singleton_class
+             * 
+             * => #<Class:#<A:0x007ff612a631e0>>
+             * 
+             * irb(main):004:0> a.singleton_class.class
+             * 
+             * => Class
+             * 
+             * irb(main):005:0> a.singleton_class.superclass
+             * 
+             * => A
+             */
+
+            rubySingletonClass = new RubyClass(rubyClass.getParentModule(), rubyClass, String.format("#<Class:#<%s:%d>>", rubyClass.getName(), getObjectID()), true);
+
+            lookupNode = new LookupFork(rubySingletonClass, rubyClass);
+        }
+
+        return rubySingletonClass;
+    }
+
+    public long getObjectID() {
+        if (objectID == -1) {
+            objectID = rubyClass.getContext().getNextObjectID();
+        }
+
+        return objectID;
+    }
+
+    public String inspect() {
+        return toString();
+    }
+
+    /**
+     * Get a map of all instance variables.
+     */
+    protected Map<String, Object> getInstanceVariables() {
+        if (objectLayout == null) {
+            return Collections.emptyMap();
+        }
+
+        final Map<String, Object> instanceVariableMap = new HashMap<>();
+
+        for (Entry<String, StorageLocation> entry : objectLayout.getAllStorageLocations().entrySet()) {
+            final String name = entry.getKey();
+            final StorageLocation storageLocation = entry.getValue();
+
+            if (storageLocation.isSet(this)) {
+                instanceVariableMap.put(name, storageLocation.read(this, true));
+            }
+        }
+
+        return instanceVariableMap;
+    }
+
+    /**
+     * Set instance variables from a map.
+     */
+    protected void setInstanceVariables(Map<String, Object> instanceVariables) {
+        assert instanceVariables != null;
+
+        if (objectLayout == null) {
+            updateLayout();
+        }
+
+        for (Entry<String, Object> entry : instanceVariables.entrySet()) {
+            final StorageLocation storageLocation = objectLayout.findStorageLocation(entry.getKey());
+            assert storageLocation != null;
+
+            try {
+                storageLocation.write(this, entry.getValue());
+            } catch (GeneralizeStorageLocationException e) {
+                throw new RuntimeException("Should not have to be generalising when setting instance variables - " + entry.getValue().getClass().getName() + ", " +
+                                storageLocation.getStoredClass().getName());
+            }
+        }
+    }
+
+    /**
+     * Update the layout of this object to match that of its class.
+     */
+    @CompilerDirectives.SlowPath
+    public void updateLayout() {
+        // Get the current values of instance variables
+
+        final Map<String, Object> instanceVariableMap = getInstanceVariables();
+
+        // Use the layout of the class
+
+        objectLayout = rubyClass.getObjectLayoutForInstances();
+
+        // Make all primitives as unset
+
+        primitiveSetMap = 0;
+
+        // Create a new array for objects
+
+        allocateObjectStorageLocations();
+
+        // Restore values
+
+        setInstanceVariables(instanceVariableMap);
+    }
+
+    private void allocateObjectStorageLocations() {
+        final int objectStorageLocationsUsed = objectLayout.getObjectStorageLocationsUsed();
+
+        if (objectStorageLocationsUsed == 0) {
+            objectStorageLocations = null;
+        } else {
+            objectStorageLocations = new Object[objectStorageLocationsUsed];
+        }
+    }
+
+    public void switchToPrivateLayout() {
+        final RubyContext context = getRubyClass().getContext();
+
+        final Map<String, Object> instanceVariables = getInstanceVariables();
+
+        hasPrivateLayout = true;
+        objectLayout = ObjectLayout.EMPTY;
+
+        for (Entry<String, Object> entry : instanceVariables.entrySet()) {
+            objectLayout = objectLayout.withNewVariable(context, entry.getKey(), entry.getValue().getClass());
+        }
+
+        setInstanceVariables(instanceVariables);
+    }
+
+    public void extend(RubyModule module) {
+        getSingletonClass().include(module);
+    }
+
+    @Override
+    public String toString() {
+        return "#<" + rubyClass.getName() + ":0x" + Long.toHexString(getObjectID()) + ">";
+    }
+
+    public boolean hasSingletonClass() {
+        return rubySingletonClass != null;
+    }
+
+    public Object send(String name, RubyProc block, Object... args) {
+        final RubyMethod method = getLookupNode().lookupMethod(name);
+
+        if (method == null || method.isUndefined()) {
+            throw new RaiseException(getRubyClass().getContext().getCoreLibrary().noMethodError(name, toString()));
+        }
+
+        return method.call(null, this, block, args);
+    }
+
+    public void unsafeSetRubyClass(RubyClass newRubyClass) {
+        assert rubyClass == null;
+
+        rubyClass = newRubyClass;
+        lookupNode = rubyClass;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/StorageLocation.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.objects;
+
+/**
+ * A storage location that abstracts the method for reading and writing values.
+ */
+public abstract class StorageLocation {
+
+    private ObjectLayout objectLayout;
+
+    protected StorageLocation(ObjectLayout objectLayout) {
+        this.objectLayout = objectLayout;
+    }
+
+    public abstract boolean isSet(RubyBasicObject object);
+
+    public abstract Object read(RubyBasicObject object, boolean condition);
+
+    public abstract void write(RubyBasicObject object, Object value) throws GeneralizeStorageLocationException;
+
+    public abstract Class getStoredClass();
+
+    public ObjectLayout getObjectLayout() {
+        return objectLayout;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/objects/Unboxable.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.objects;
+
+/**
+ * An object that can be losslessly unboxed back to a more primitive value.
+ */
+public interface Unboxable {
+
+    Object unbox();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/subsystems/AtExitManager.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.subsystems;
+
+import java.util.*;
+
+import com.oracle.truffle.ruby.runtime.core.*;
+
+/**
+ * Manages at_exit callbacks.
+ */
+public class AtExitManager {
+
+    private final List<RubyProc> blocks = new ArrayList<>();
+
+    public void add(RubyProc block) {
+        blocks.add(block);
+    }
+
+    public void run() {
+        final ListIterator<RubyProc> iterator = blocks.listIterator(blocks.size());
+
+        while (iterator.hasPrevious()) {
+            iterator.previous().call(null);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/subsystems/FeatureManager.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.subsystems;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.control.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+/**
+ * Manages the features loaded into Ruby. This basically means which library files are loaded, but
+ * Ruby often talks about requiring features, not files.
+ * 
+ */
+public class FeatureManager {
+
+    private RubyContext context;
+
+    private final Set<String> requiredFiles = new HashSet<>();
+
+    public FeatureManager(RubyContext context) {
+        this.context = context;
+    }
+
+    public boolean require(String feature) throws IOException {
+        // Some features are handled specially
+
+        if (context.getConfiguration().getRubyVersion().is19OrLater() && feature.equals("continuation")) {
+            // We always load continuations
+            return true;
+        }
+
+        if (feature.equals("stringio")) {
+            context.implementationMessage("stringio not yet implemented");
+            return true;
+        }
+
+        if (feature.equals("rbconfig")) {
+            // Kernel#rbconfig is always there
+            return true;
+        }
+
+        if (feature.equals("pp")) {
+            // Kernel#pretty_inspect is always there
+            return true;
+        }
+
+        // Get the load path
+
+        final Object loadPathObject = context.getCoreLibrary().getGlobalVariablesObject().getInstanceVariable("$:");
+
+        if (!(loadPathObject instanceof RubyArray)) {
+            throw new RuntimeException("$: is not an array");
+        }
+
+        final List<Object> loadPath = ((RubyArray) loadPathObject).asList();
+
+        // Try as a full path
+
+        if (requireInPath("", feature)) {
+            return true;
+        }
+
+        // Try each load path in turn
+
+        for (Object pathObject : loadPath) {
+            final String path = pathObject.toString();
+
+            if (requireInPath(path, feature)) {
+                return true;
+            }
+        }
+
+        // Didn't find the feature
+
+        throw new RaiseException(context.getCoreLibrary().loadErrorCannotLoad(feature));
+    }
+
+    public boolean requireInPath(String path, String feature) throws IOException {
+        if (requireFile(feature)) {
+            return true;
+        }
+
+        if (requireFile(feature + ".rb")) {
+            return true;
+        }
+
+        if (requireFile(path + File.separator + feature)) {
+            return true;
+        }
+
+        if (requireFile(path + File.separator + feature + ".rb")) {
+            return true;
+        }
+
+        return false;
+    }
+
+    private boolean requireFile(String fileName) throws IOException {
+        if (requiredFiles.contains(fileName)) {
+            return true;
+        }
+
+        /*
+         * There is unfortunately no way to check if a string is a file path, or a URL. file:foo.txt
+         * is a valid file name, as well as a valid URL. We try as a file path first.
+         */
+
+        if (new File(fileName).isFile()) {
+            context.loadFile(fileName);
+            requiredFiles.add(fileName);
+            return true;
+        } else {
+            URL url;
+
+            try {
+                url = new URL(fileName);
+            } catch (MalformedURLException e) {
+                return false;
+            }
+
+            InputStream inputStream;
+
+            try {
+                inputStream = url.openConnection().getInputStream();
+            } catch (IOException e) {
+                return false;
+            }
+
+            context.load(context.getSourceManager().get(url.toString(), inputStream));
+            requiredFiles.add(fileName);
+            return true;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/subsystems/FiberManager.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.subsystems;
+
+import java.util.*;
+import java.util.concurrent.*;
+
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+/**
+ * Manages Ruby {@code Fiber} objects.
+ */
+public class FiberManager {
+
+    private final RubyFiber rootFiber;
+    private RubyFiber currentFiber;
+
+    private final Set<RubyFiber> runningFibers = Collections.newSetFromMap(new ConcurrentHashMap<RubyFiber, Boolean>());
+
+    public FiberManager(RubyContext context) {
+        rootFiber = new RubyFiber(context.getCoreLibrary().getFiberClass(), this, context.getThreadManager());
+        currentFiber = rootFiber;
+    }
+
+    public RubyFiber getCurrentFiber() {
+        return currentFiber;
+    }
+
+    public void setCurrentFiber(RubyFiber fiber) {
+        currentFiber = fiber;
+    }
+
+    public void registerFiber(RubyFiber fiber) {
+        runningFibers.add(fiber);
+    }
+
+    public void unregisterFiber(RubyFiber fiber) {
+        runningFibers.remove(fiber);
+    }
+
+    public void shutdown() {
+        for (RubyFiber fiber : runningFibers) {
+            fiber.shutdown();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/subsystems/ObjectSpaceManager.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.subsystems;
+
+import java.lang.ref.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+/**
+ * Supports the Ruby {@code ObjectSpace} module. Object IDs are lazily allocated {@code long}
+ * values, mapped to objects with a weak hash map. Finalizers are implemented with weak references
+ * and reference queues, and are run in a dedicated Ruby thread (but not a dedicated Java thread).
+ */
+public class ObjectSpaceManager {
+
+    private class FinalizerReference extends WeakReference<RubyBasicObject> {
+
+        public List<RubyProc> finalizers = new LinkedList<>();
+
+        public FinalizerReference(RubyBasicObject object, ReferenceQueue<? super RubyBasicObject> queue) {
+            super(object, queue);
+        }
+
+        public void addFinalizer(RubyProc proc) {
+            finalizers.add(proc);
+        }
+
+        public List<RubyProc> getFinalizers() {
+            return finalizers;
+        }
+
+        public void clearFinalizers() {
+            finalizers = new LinkedList<>();
+        }
+
+    }
+
+    private final RubyContext context;
+
+    // TODO(cs): this is wrong - WeakHashMap is not weak in the value
+    private final WeakHashMap<Long, RubyBasicObject> objects = new WeakHashMap<>();
+
+    private final Map<RubyBasicObject, FinalizerReference> finalizerReferences = new WeakHashMap<>();
+    private final ReferenceQueue<RubyBasicObject> finalizerQueue = new ReferenceQueue<>();
+    private RubyThread finalizerThread;
+    private Thread finalizerJavaThread;
+    private boolean stop;
+    private CountDownLatch finished = new CountDownLatch(1);
+
+    public ObjectSpaceManager(RubyContext context) {
+        this.context = context;
+    }
+
+    public void add(RubyBasicObject object) {
+        objects.put(object.getObjectID(), object);
+    }
+
+    public RubyBasicObject lookupId(long id) {
+        return objects.get(id);
+    }
+
+    public void defineFinalizer(RubyBasicObject object, RubyProc proc) {
+        // Record the finalizer against the object
+
+        FinalizerReference finalizerReference = finalizerReferences.get(object);
+
+        if (finalizerReference == null) {
+            finalizerReference = new FinalizerReference(object, finalizerQueue);
+            finalizerReferences.put(object, finalizerReference);
+        }
+
+        finalizerReference.addFinalizer(proc);
+
+        // If there is no finalizer thread, start one
+
+        if (finalizerThread == null) {
+            finalizerThread = new RubyThread(context.getCoreLibrary().getThreadClass(), context.getThreadManager());
+
+            finalizerThread.initialize(new Runnable() {
+
+                @Override
+                public void run() {
+                    runFinalizers();
+                }
+
+            });
+        }
+    }
+
+    public void undefineFinalizer(RubyBasicObject object) {
+        final FinalizerReference finalizerReference = finalizerReferences.get(object);
+
+        if (finalizerReference != null) {
+            finalizerReference.clearFinalizers();
+        }
+    }
+
+    private void runFinalizers() {
+        // Run in a loop
+
+        while (true) {
+            // Is there a finalizer ready to immediately run?
+
+            FinalizerReference finalizerReference = (FinalizerReference) finalizerQueue.poll();
+
+            if (finalizerReference != null) {
+                runFinalizers(finalizerReference);
+                continue;
+            }
+
+            // Check if we've been asked to stop
+
+            if (stop) {
+                break;
+            }
+
+            // Leave the global lock and wait on the finalizer queue
+
+            final RubyThread runningThread = context.getThreadManager().leaveGlobalLock();
+            finalizerJavaThread = Thread.currentThread();
+
+            try {
+                finalizerReference = (FinalizerReference) finalizerQueue.remove();
+            } catch (InterruptedException e) {
+                continue;
+            } finally {
+                context.getThreadManager().enterGlobalLock(runningThread);
+            }
+
+            runFinalizers(finalizerReference);
+        }
+
+        finished.countDown();
+    }
+
+    private static void runFinalizers(FinalizerReference finalizerReference) {
+        try {
+            for (RubyProc proc : finalizerReference.getFinalizers()) {
+                proc.call(null);
+            }
+        } catch (Exception e) {
+            // MRI seems to silently ignore exceptions in finalizers
+        }
+    }
+
+    public void shutdown() {
+        context.getThreadManager().enterGlobalLock(finalizerThread);
+
+        try {
+            // Tell the finalizer thread to stop and wait for it to do so
+
+            if (finalizerThread != null) {
+                stop = true;
+
+                if (finalizerJavaThread != null) {
+                    finalizerJavaThread.interrupt();
+                }
+
+                context.getThreadManager().leaveGlobalLock();
+
+                try {
+                    finished.await();
+                } catch (InterruptedException e) {
+                } finally {
+                    context.getThreadManager().enterGlobalLock(finalizerThread);
+                }
+            }
+
+            // Run any finalizers for objects that are still live
+
+            for (FinalizerReference finalizerReference : finalizerReferences.values()) {
+                runFinalizers(finalizerReference);
+            }
+        } finally {
+            context.getThreadManager().leaveGlobalLock();
+        }
+    }
+
+    public Collection<RubyBasicObject> getObjects() {
+        return objects.values();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/subsystems/ThreadManager.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.subsystems;
+
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.concurrent.locks.*;
+
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+/**
+ * Manages Ruby {@code Thread} objects.
+ */
+public class ThreadManager {
+
+    private final ReentrantLock globalLock = new ReentrantLock();
+
+    private final RubyThread rootThread;
+    private RubyThread currentThread;
+
+    private final Set<RubyThread> runningThreads = Collections.newSetFromMap(new ConcurrentHashMap<RubyThread, Boolean>());
+
+    public ThreadManager(RubyContext context) {
+        rootThread = new RubyThread(context.getCoreLibrary().getFiberClass(), this);
+        runningThreads.add(rootThread);
+        enterGlobalLock(rootThread);
+    }
+
+    /**
+     * Enters the global lock. Reentrant, but be aware that Ruby threads are not one-to-one with
+     * Java threads. Needs to be told which Ruby thread is becoming active as it can't work this out
+     * from the current Java thread. Remember to call {@link #leaveGlobalLock} again before
+     * blocking.
+     */
+    public void enterGlobalLock(RubyThread thread) {
+        globalLock.lock();
+        currentThread = thread;
+    }
+
+    /**
+     * Leaves the global lock, returning the Ruby thread which has just stopped being the current
+     * thread. Remember to call {@link #enterGlobalLock} again with that returned thread before
+     * executing any Ruby code. You probably want to use this with a {@code finally} statement to
+     * make sure that happens
+     */
+    public RubyThread leaveGlobalLock() {
+        if (!globalLock.isHeldByCurrentThread()) {
+            throw new RuntimeException("You don't own this lock!");
+        }
+
+        final RubyThread result = currentThread;
+        globalLock.unlock();
+        return result;
+    }
+
+    public RubyThread getCurrentThread() {
+        return currentThread;
+    }
+
+    public void registerThread(RubyThread thread) {
+        runningThreads.add(thread);
+    }
+
+    public void unregisterThread(RubyThread thread) {
+        runningThreads.remove(thread);
+    }
+
+    public void shutdown() {
+        for (RubyThread thread : runningThreads) {
+            thread.shutdown();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/subsystems/TraceManager.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.subsystems;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.utilities.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+/**
+ * Manages trace events and calls the user's trace method if one is set.
+ * <p>
+ * Once tracing has been enabled via {@link #setTraceProc(RubyProc)}, the underlying instrumentation
+ * remains in effect, along with performance impact.
+ */
+public final class TraceManager {
+
+    private RubyContext context;
+
+    private final AssumedValue<RubyProc> traceProc = new AssumedValue<>("trace-proc", null);
+    private boolean suspended;
+
+    private String lastFile;
+    private int lastLine;
+
+    private final Assumption notTracingAssumption = Truffle.getRuntime().createAssumption("tracing-disabled");
+
+    public TraceManager(RubyContext context) {
+        this.context = context;
+    }
+
+    /**
+     * Produce a trace; it is a runtime error if {@link #hasTraceProc()}{@code == false}.
+     */
+    @CompilerDirectives.SlowPath
+    public void trace(String event, String file, int line, long objectId, RubyBinding binding, String className) {
+        // If tracing is suspended, stop here
+
+        if (suspended) {
+            return;
+        }
+
+        // If the file and line haven't changed since the last trace, stop here
+
+        if (file.equals(lastFile) && line == lastLine) {
+            return;
+        }
+
+        final RubyClass stringClass = context.getCoreLibrary().getStringClass();
+
+        // Suspend tracing while we run the trace proc
+
+        suspended = true;
+
+        try {
+            // Exceptions from within the proc propagate normally
+
+            traceProc.get().call(null, new RubyString(stringClass, event), //
+                            new RubyString(stringClass, file), //
+                            line, //
+                            GeneralConversions.fixnumOrBignum(objectId), //
+                            GeneralConversions.instanceOrNil(binding), //
+                            GeneralConversions.instanceOrNil(className));
+        } finally {
+            // Resume tracing
+
+            suspended = false;
+        }
+
+        // Remember the last trace event file and line
+
+        lastFile = file;
+        lastLine = line;
+    }
+
+    /**
+     * Is there a "trace proc" in effect?
+     */
+    public boolean hasTraceProc() {
+        return traceProc.get() != null;
+    }
+
+    /**
+     * Gets the assumption that there has never yet been tracing enabled. Once the assumption is
+     * invalidated, tracing is presumed permanently enabled even if {@link #hasTraceProc()} returns
+     * {@code false}.
+     */
+    public Assumption getNotTracingAssumption() {
+        return notTracingAssumption;
+    }
+
+    public void setTraceProc(RubyProc newTraceProc) {
+        if (!context.getConfiguration().getTrace()) {
+            throw new RuntimeException("You need the --trace option to use tracing");
+        }
+
+        traceProc.set(newTraceProc);
+        lastFile = null;
+        lastLine = -1;
+
+        notTracingAssumption.invalidate();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.shell/src/com/oracle/truffle/ruby/shell/CommandLineOptions.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.shell;
+
+import java.util.*;
+
+import com.oracle.truffle.ruby.runtime.configuration.*;
+
+/**
+ * Options resulting from parsing a command line by {@link CommandLineParser}.
+ */
+public class CommandLineOptions {
+
+    private final List<String> preRequires;
+    private final String preChangeDirectory;
+
+    private final List<String> extraLoadPath;
+
+    private final String programFile;
+    private final List<String> commandLineScripts;
+    private final List<String> programArgs;
+    private final List<String> switchArgs;
+
+    private final int recordSeparator;
+    private final boolean autosplit;
+    private final String autosplitPattern;
+    private final boolean checkSyntaxOnly;
+    private final boolean lineEndingProcessing;
+    private final boolean inPlaceEdit;
+    private final String inPlaceBackupExtension;
+    private final boolean implicitLoop;
+    private final boolean implicitSedLoop;
+    private final boolean importFromPath;
+    private final boolean stripMessage;
+    private final boolean useJLine;
+
+    private final Configuration configuration;
+
+    public CommandLineOptions(List<String> preRequires, String preChangeDirectory, List<String> extraLoadPath, String programFile, List<String> commandLineScripts, List<String> programArgs,
+                    List<String> switchArgs, int recordSeparator, boolean autosplit, String autosplitPattern, boolean checkSyntaxOnly, boolean lineEndingProcessing, boolean inPlaceEdit,
+                    String inPlaceBackupExtension, boolean implicitLoop, boolean implicitSedLoop, boolean importFromPath, boolean stripMessage, boolean useJLine, Configuration configuration) {
+        this.preRequires = preRequires;
+        this.preChangeDirectory = preChangeDirectory;
+        this.extraLoadPath = extraLoadPath;
+        this.programFile = programFile;
+        this.commandLineScripts = commandLineScripts;
+        this.programArgs = programArgs;
+        this.switchArgs = switchArgs;
+        this.recordSeparator = recordSeparator;
+        this.autosplit = autosplit;
+        this.autosplitPattern = autosplitPattern;
+        this.checkSyntaxOnly = checkSyntaxOnly;
+        this.lineEndingProcessing = lineEndingProcessing;
+        this.inPlaceEdit = inPlaceEdit;
+        this.inPlaceBackupExtension = inPlaceBackupExtension;
+        this.implicitLoop = implicitLoop;
+        this.implicitSedLoop = implicitSedLoop;
+        this.importFromPath = importFromPath;
+        this.stripMessage = stripMessage;
+        this.useJLine = useJLine;
+        this.configuration = configuration;
+    }
+
+    public List<String> getPreRequires() {
+        return preRequires;
+    }
+
+    public String getPreChangeDirectory() {
+        return preChangeDirectory;
+    }
+
+    public List<String> getExtraLoadPath() {
+        return extraLoadPath;
+    }
+
+    public String getProgramFile() {
+        return programFile;
+    }
+
+    public List<String> getCommandLineScripts() {
+        return commandLineScripts;
+    }
+
+    public List<String> getProgramArgs() {
+        return programArgs;
+    }
+
+    public List<String> getSwitchArgs() {
+        return switchArgs;
+    }
+
+    public int getRecordSeparator() {
+        return recordSeparator;
+    }
+
+    public String getAutosplitPattern() {
+        return autosplitPattern;
+    }
+
+    public boolean isAutosplit() {
+        return autosplit;
+    }
+
+    public boolean isCheckSyntaxOnly() {
+        return checkSyntaxOnly;
+    }
+
+    public boolean isLineEndingProcessing() {
+        return lineEndingProcessing;
+    }
+
+    public boolean isInPlaceEdit() {
+        return inPlaceEdit;
+    }
+
+    public String getInPlaceBackupExtension() {
+        return inPlaceBackupExtension;
+    }
+
+    public boolean isImplicitLoop() {
+        return implicitLoop;
+    }
+
+    public boolean isImplicitSedLoop() {
+        return implicitSedLoop;
+    }
+
+    public boolean isImportFromPath() {
+        return importFromPath;
+    }
+
+    public boolean isStripMessage() {
+        return stripMessage;
+    }
+
+    public boolean useJLine() {
+        return useJLine;
+    }
+
+    public Configuration getConfiguration() {
+        return configuration;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.shell/src/com/oracle/truffle/ruby/shell/CommandLineParser.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.shell;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.truffle.ruby.runtime.configuration.*;
+
+/**
+ * MRI-compatible command line parser, producing {@link CommandLineOptions}.
+ */
+public abstract class CommandLineParser {
+
+    /**
+     * Parse an MRI-compatible command line.
+     */
+    public static CommandLineOptions parse(String[] args) {
+        assert args != null;
+
+        final List<String> preRequires = new ArrayList<>();
+        String preChangeDirectory = null;
+
+        final List<String> extraLoadPath = new ArrayList<>();
+
+        String programFile = null;
+        final List<String> commandLineScripts = new ArrayList<>();
+        final List<String> programArgs = new ArrayList<>();
+        final List<String> switchArgs = new ArrayList<>();
+
+        int recordSeparator = -1;
+        boolean autosplit = false;
+        String autosplitPattern = null;
+        boolean checkSyntaxOnly = false;
+        boolean lineEndingProcessing = false;
+        boolean inPlaceEdit = false;
+        String inPlaceBackupExtension = null;
+        boolean implicitLoop = false;
+        boolean implicitSedLoop = false;
+        boolean importFromPath = false;
+        boolean messageStrip = false;
+        boolean useJLine = true;
+
+        final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
+
+        final List<String> normalizedArgs = normalizeArgs(args);
+
+        boolean stillRubyArgs = true;
+        boolean collectingSwitchArgs = false;
+        int n = 0;
+
+        while (n < normalizedArgs.size()) {
+            final String arg = normalizedArgs.get(n);
+
+            if (stillRubyArgs && arg.startsWith("-")) {
+                if (collectingSwitchArgs) {
+                    switchArgs.add(arg);
+                } else if (arg.startsWith("-0")) {
+                    if (arg.length() == 2) {
+                        recordSeparator = 0;
+                    } else {
+                        recordSeparator = Integer.parseInt(arg.substring(2), 8);
+                    }
+                } else if (arg.startsWith("-i")) {
+                    inPlaceEdit = true;
+
+                    if (arg.length() > 2) {
+                        inPlaceBackupExtension = arg.substring(2);
+                    }
+                } else if (arg.startsWith("-W")) {
+                    if (arg.length() == 2) {
+                        configurationBuilder.setWarningLevel(2);
+                    } else if (arg.startsWith("-Wlevel=")) {
+                        configurationBuilder.setWarningLevel(Integer.parseInt(arg.substring("-Wlevel=".length())));
+                    } else {
+                        throw new IllegalArgumentException("bad flag " + arg);
+                    }
+                } else if (arg.startsWith("-T")) {
+                    if (arg.length() == 2) {
+                        configurationBuilder.setTaintCheckLevel(1);
+                    } else if (arg.startsWith("-Tlevel=")) {
+                        configurationBuilder.setTaintCheckLevel(Integer.parseInt(arg.substring("-Tlevel=".length())));
+                    } else {
+                        throw new IllegalArgumentException("bad flag " + arg);
+                    }
+                } else if (arg.startsWith("-x")) {
+                    messageStrip = true;
+
+                    if (arg.length() > 2) {
+                        preChangeDirectory = arg.substring(2);
+                    }
+                } else {
+                    switch (arg) {
+                        case "-C":
+                        case "-e":
+                        case "-E":
+                        case "-F":
+                        case "-I":
+                        case "-r":
+                        case "--home":
+                            if (n + 1 >= normalizedArgs.size()) {
+                                throw new RuntimeException("Expecting value after " + arg);
+                            }
+                    }
+
+                    switch (arg) {
+                        case "--":
+                            stillRubyArgs = false;
+                            break;
+                        case "-a":
+                            autosplit = true;
+                            break;
+                        case "-c":
+                            checkSyntaxOnly = true;
+                            break;
+                        case "-C":
+                            if (n + 1 >= normalizedArgs.size()) {
+                                throw new RuntimeException("Need a directory path after -C");
+                            }
+                            preChangeDirectory = normalizedArgs.get(n + 1);
+                            n++;
+                            break;
+                        case "-d":
+                        case "--debug":
+                            configurationBuilder.setDebug(true);
+                            break;
+                        case "--no-debug":
+                            configurationBuilder.setDebug(false);
+                            break;
+                        case "--trace":
+                            configurationBuilder.setTrace(true);
+                            break;
+                        case "--no-trace":
+                            configurationBuilder.setTrace(false);
+                            break;
+                        case "-e":
+                            commandLineScripts.add(normalizedArgs.get(n + 1));
+                            n++;
+                            break;
+                        case "-E":
+                            final String[] encodings = normalizedArgs.get(n + 1).split(":");
+                            configurationBuilder.setDefaultExternalEncoding(encodings[0]);
+
+                            if (encodings.length == 2) {
+                                configurationBuilder.setDefaultInternalEncoding(encodings[1]);
+                            } else {
+                                throw new IllegalArgumentException("bad flag " + arg);
+                            }
+
+                            n++;
+                            break;
+                        case "-F":
+                            autosplitPattern = normalizedArgs.get(n + 1);
+                            n++;
+                            break;
+                        case "-I":
+                            extraLoadPath.add(normalizedArgs.get(n + 1));
+                            n++;
+                            break;
+                        case "-l":
+                            lineEndingProcessing = true;
+                            break;
+                        case "-n":
+                            implicitLoop = true;
+                            break;
+                        case "-r":
+                            preRequires.add(normalizedArgs.get(n + 1));
+                            n++;
+                            break;
+                        case "-s":
+                            collectingSwitchArgs = true;
+                            break;
+                        case "-p":
+                            implicitSedLoop = true;
+                            break;
+                        case "-S":
+                            importFromPath = true;
+                            break;
+                        case "-w":
+                            configurationBuilder.setWarningLevel(1);
+                            break;
+                        case "-h":
+                        case "--help":
+                            help(System.out);
+                            return null;
+                        case "-v":
+                            version(System.out);
+                            configurationBuilder.setVerbose(true);
+                            break;
+                        case "--version":
+                            version(System.out);
+                            return null;
+                        case "--copyright":
+                            copyright(System.out);
+                            return null;
+                        case "--home":
+                            configurationBuilder.setStandardLibrary(normalizedArgs.get(n + 1) + "/" + ConfigurationBuilder.JRUBY_STDLIB_JAR);
+                            n++;
+                            break;
+                        case "--stdlib":
+                            configurationBuilder.setStandardLibrary(normalizedArgs.get(n + 1));
+                            n++;
+                            break;
+                        case "--1.8":
+                            configurationBuilder.setRubyVersion(RubyVersion.RUBY_18);
+                            break;
+                        case "--1.9":
+                            configurationBuilder.setRubyVersion(RubyVersion.RUBY_19);
+                            break;
+                        case "--2.0":
+                            configurationBuilder.setRubyVersion(RubyVersion.RUBY_20);
+                            break;
+                        case "--full-object-space":
+                            configurationBuilder.setFullObjectSpace(true);
+                            break;
+                        case "--no-jline":
+                            useJLine = false;
+                            break;
+                        case "--print-parse-tree":
+                            configurationBuilder.setPrintParseTree(true);
+                            break;
+                        case "--print-executed-files":
+                            configurationBuilder.setPrintExecutedFiles(true);
+                            break;
+                        case "--print-spilt-instance-variables":
+                            configurationBuilder.setPrintSpiltInstanceVariables(true);
+                            break;
+                        case "--print-uninitialized-calls":
+                            configurationBuilder.setPrintUninitializedCalls(true);
+                            break;
+                        case "--print-java-exceptions":
+                            configurationBuilder.setPrintJavaExceptions(true);
+                            break;
+                        case "--print-ruby-exceptions":
+                            configurationBuilder.setPrintRubyExceptions(true);
+                            break;
+                        default:
+                            throw new IllegalArgumentException("unknown flag " + arg);
+                    }
+                }
+            } else if (programFile == null) {
+                programFile = arg;
+                stillRubyArgs = false;
+            } else {
+                programArgs.add(arg);
+            }
+
+            n++;
+        }
+
+        return new CommandLineOptions(preRequires, preChangeDirectory, extraLoadPath, programFile, commandLineScripts, programArgs, switchArgs, recordSeparator, autosplit, autosplitPattern,
+                        checkSyntaxOnly, lineEndingProcessing, inPlaceEdit, inPlaceBackupExtension, implicitLoop, implicitSedLoop, importFromPath, messageStrip, useJLine, new Configuration(
+                                        configurationBuilder));
+    }
+
+    /**
+     * Produce a canonical set of arguments that includes {@code $RUBYOPT} and has contractions such
+     * as a {@code -rdir} replaced with separate arguments {@code -r} and {@code dir} for simpler
+     * processing.
+     */
+    private static List<String> normalizeArgs(String[] args) {
+        assert args != null;
+
+        // Arguments come from the main method arguments parameter and $RUBYOPT
+
+        final List<String> inputArgs = new ArrayList<>();
+
+        final String rubyoptVar = System.getenv("RUBYOPT");
+
+        if (rubyoptVar != null) {
+            /*
+             * TODO(cs): what we've got here is a string that we are supposed to treat as if it was
+             * an extra part of the command line, including more Ruby options. However, we just get
+             * the string and have to split it into arguments ourselves. Normally the shell does
+             * that, including lots of fancy quoting styles. Are we supposed to re-implement all of
+             * that? Otherwise arguments in RUBYOPT will be parsed differently to if they were
+             * actually on the command line. JRuby just splits like we do. I also think that's what
+             * MRI does, but is this correct?
+             */
+
+            inputArgs.addAll(Arrays.asList(rubyoptVar.split("\\s+")));
+        }
+
+        inputArgs.addAll(Arrays.asList(args));
+
+        // Replace some contractions such as -rdir with -r dir
+
+        final List<String> outputArgs = new ArrayList<>();
+
+        for (String arg : inputArgs) {
+            if (arg.startsWith("-C") || arg.startsWith("-E") || arg.startsWith("-F") || arg.startsWith("-I") || arg.startsWith("-r")) {
+                outputArgs.add(arg.substring(0, 2));
+                outputArgs.add(arg.substring(2));
+            } else {
+                outputArgs.add(arg);
+            }
+        }
+
+        return outputArgs;
+    }
+
+    /**
+     * Print help information.
+     */
+    private static void help(PrintStream out) {
+        out.println("Usage: ruby [switches] [--] [programfile] [arguments]");
+        out.println("  -0[octal]       specify record separator (\0, if no argument)");
+        out.println("  -a              autosplit mode with -n or -p (splits $_ into $F)");
+        out.println("  -c              check syntax only");
+        out.println("  -Cdirectory     cd to directory, before executing your script");
+        out.println("  -d, --debug     set debugging flags (set $DEBUG to true) and enable Debug module");
+        out.println("  -e 'command'    one line of script. Several -e's allowed. Omit [programfile]");
+        out.println("  -Eex[:in]       specify the default external and internal character encodings");
+        out.println("  -Fpattern       split() pattern for autosplit (-a)");
+        out.println("  -i[extension]   edit ARGV files in place (make backup if extension supplied)");
+        out.println("  -Idirectory     specify $LOAD_PATH directory (may be used more than once)");
+        out.println("  -l              enable line ending processing");
+        out.println("  -n              assume 'while gets(); ... end' loop around your script");
+        out.println("  -p              assume loop like -n but print line also like sed");
+        out.println("  -rlibrary       require the library, before executing your script");
+        out.println("  -s              enable some switch parsing for switches after script name");
+        out.println("  -S              look for the script using PATH environment variable");
+        out.println("  -T[level=1]     turn on tainting checks");
+        out.println("  -v              print version number, then turn on verbose mode");
+        out.println("  -w              turn warnings on for your script");
+        out.println("  -W[level=2]     set warning level; 0=silence, 1=medium, 2=verbose");
+        out.println("  -x[directory]   strip off text before #!ruby line and perhaps cd to directory");
+        out.println("  --copyright     print the copyright");
+        out.println("  --version       print the version");
+        out.println("Extra rubytruffle switches:");
+        out.println("  --home dir                        set the location of the Ruby Truffle installation (default . or $RUBY_TRUFFLE_HOME)");
+        out.println("  --stdlib dir                      use a directory for the Ruby standard library");
+        out.println("  --1.8                             1.8 compatibility mode");
+        out.println("  --1.9                             1.9 compatibility mode (default)");
+        out.println("  --2.0                             2.0 compatibility mode");
+        out.println("  --full-object-space               enable full ObjectSpace#each_object and similar");
+        out.println("  --no-debug                        disable debugging");
+        out.println("  --no-trace                        disable tracing");
+        out.println("Debugging rubytruffle switches:");
+        out.println("  --no-cache-constant-lookup        don't cache constant lookups");
+        out.println("  --no-cache-method-calls           don't cache method lookups");
+        out.println("  --no-intrinsic-method-calls       don't turn method calls into intrinsic nodes");
+        out.println("  --no-jline                        don't use JLine");
+        out.println("  --print-parse-tree                print the result of parsing");
+        out.println("  --print-executed-files            print the name of files as they are executed");
+        out.println("  --print-missing-intrinsics        print method calls that don't have intrinsic nodes");
+        out.println("  --print-spilt-instance-variables  print each time a native-typed instance variable is spilt to the boxed array");
+        out.println("  --print-uninitialized-calls       print each time a method call is uninitialized");
+        out.println("  --print-java-exceptions           print Java exception back traces at the point of translating them to Ruby exceptions");
+        out.println("  --print-ruby-exceptions           print the Java exception back traces at the point of raising Ruby exceptions");
+        out.println("Relevant environment variables:");
+        out.println("  RUBYHOME                          location of the Ruby Truffle installation");
+        out.println("  RUBYOPT                           extra command line arguments");
+        out.println("  RUBYLIB                           list of colon separated paths to add to $LOAD_PATH");
+        out.println("  PATH                              as RUBYLIB, if -S is used");
+    }
+
+    /**
+     * Print version information.
+     */
+    private static void version(PrintStream out) {
+        out.printf("ruby (rubytruffle) dev [JVM %s]\n", System.getProperty("java.version"));
+    }
+
+    /**
+     * Print copyright information.
+     */
+    private static void copyright(PrintStream out) {
+        out.println("Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.");
+        out.println("ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.shell/src/com/oracle/truffle/ruby/shell/Shell.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.shell;
+
+import java.io.*;
+
+import jline.console.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.ruby.nodes.core.*;
+import com.oracle.truffle.ruby.parser.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.configuration.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+/**
+ * The entry point class for RubyTruffle. Implements the MRI command line interface.
+ */
+public class Shell {
+
+    /**
+     * Entry point method for Ruby both in batch and interactive mode.
+     */
+    public static void main(String[] args) throws IOException {
+        // Parse the command line
+
+        final CommandLineOptions options = CommandLineParser.parse(args);
+
+        if (options == null) {
+            return;
+        }
+
+        // Setup JLine
+
+        ConsoleReader console = null;
+
+        if (options.useJLine()) {
+            System.setProperty("jline.shutdownhook", "true");
+            console = new ConsoleReader();
+            console.setExpandEvents(false);
+        }
+
+        // Override the home directory if RUBYHOME is set
+
+        final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(options.getConfiguration());
+
+        if (System.getenv("RUBYHOME") != null) {
+            configurationBuilder.setStandardLibrary(System.getenv("RUBYHOME") + "/" + ConfigurationBuilder.JRUBY_STDLIB_JAR);
+        }
+
+        // Use JLine for console input
+
+        final ConsoleReader finalConsole = console;
+
+        if (options.useJLine()) {
+            configurationBuilder.setInputReader(new InputReader() {
+
+                @Override
+                public String readLine(String prompt) throws IOException {
+                    return finalConsole.readLine(prompt);
+                }
+
+            });
+        }
+
+        // Set up a context
+
+        final RubyContext context = new RubyContext(new Configuration(configurationBuilder), new JRubyParser());
+
+        // Bring in core method nodes
+
+        CoreMethodNodeManager.addMethods(context.getCoreLibrary().getObjectClass());
+
+        // Give the core library manager a chance to tweak some of those methods
+
+        context.getCoreLibrary().initializeAfterMethodsAdded();
+
+        // Set program arguments
+
+        for (String arg : options.getProgramArgs()) {
+            context.getCoreLibrary().getArgv().push(context.makeString(arg));
+        }
+
+        if (!options.getSwitchArgs().isEmpty()) {
+            context.implementationMessage("can't set -s switch arguments yet");
+        }
+
+        // Set the load path
+
+        final RubyArray loadPath = (RubyArray) context.getCoreLibrary().getGlobalVariablesObject().getInstanceVariable("$:");
+
+        final String pathVar = System.getenv("PATH");
+
+        if (options.isImportFromPath() && pathVar != null) {
+            for (String path : pathVar.split(File.pathSeparator)) {
+                loadPath.push(context.makeString(path));
+            }
+        }
+
+        for (String path : options.getExtraLoadPath()) {
+            loadPath.push(context.makeString(path));
+        }
+
+        final String rubylibVar = System.getenv("RUBYLIB");
+
+        if (rubylibVar != null) {
+            for (String path : rubylibVar.split(File.pathSeparator)) {
+                loadPath.push(context.makeString(path));
+            }
+        }
+
+        if (context.getConfiguration().getStandardLibrary().endsWith(".jar")) {
+            String version = null;
+
+            switch (configurationBuilder.getRubyVersion()) {
+                case RUBY_18:
+                    version = "1.8";
+                    break;
+                case RUBY_19:
+                    version = "1.9";
+                    break;
+                case RUBY_20:
+                    version = "2.0";
+                    break;
+                case RUBY_21:
+                    version = "2.0";
+                    break;
+            }
+
+            loadPath.push(context.makeString("jar:file:" + context.getConfiguration().getStandardLibrary() + "!/META-INF/jruby.home/lib/ruby/" + version));
+
+        } else {
+            loadPath.push(context.makeString(context.getConfiguration().getStandardLibrary()));
+        }
+
+        // Pre-required modules
+
+        for (String feature : options.getPreRequires()) {
+            context.getFeatureManager().require(feature);
+        }
+
+        // Check for other options that are not implemented yet
+
+        if (options.getRecordSeparator() != -1) {
+            context.implementationMessage("record separator not implemented");
+        }
+
+        if (options.isAutosplit()) {
+            context.implementationMessage("autosplit not implemented");
+        }
+
+        if (options.getPreChangeDirectory() != null) {
+            context.implementationMessage("not able to change directory");
+        }
+
+        if (options.isLineEndingProcessing()) {
+            context.implementationMessage("line end processing not implemented");
+        }
+
+        if (options.isInPlaceEdit()) {
+            context.implementationMessage("in place editing not implemented");
+        }
+
+        if (options.isImplicitLoop() || options.isImplicitSedLoop()) {
+            context.implementationMessage("implicit loops not implemented");
+        }
+
+        if (options.isStripMessage()) {
+            context.implementationMessage("strip message -x option not implemented");
+        }
+
+        // Run the scripts, program file, or run the temporary version of IRB
+
+        try {
+            if (!options.getCommandLineScripts().isEmpty()) {
+                final StringBuilder combinedScript = new StringBuilder();
+
+                for (String script : options.getCommandLineScripts()) {
+                    combinedScript.append(script);
+                    combinedScript.append("\n");
+                }
+
+                try {
+                    final Source source = context.getSourceManager().get("-e", combinedScript.toString());
+                    if (options.isCheckSyntaxOnly()) {
+                        context.getParser().parse(context, source, RubyParser.ParserContext.TOP_LEVEL, null);
+                        System.out.println("Syntax OK");
+                    } else {
+                        context.execute(context, source, RubyParser.ParserContext.TOP_LEVEL, context.getCoreLibrary().getMainObject(), null);
+                    }
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            } else if (options.getProgramFile() != null) {
+                try {
+                    if (options.isCheckSyntaxOnly()) {
+                        final Source source = context.getSourceManager().get(options.getProgramFile());
+                        context.getParser().parse(context, source, RubyParser.ParserContext.TOP_LEVEL, null);
+                        System.out.println("Syntax OK");
+                    } else {
+                        context.loadFile(options.getProgramFile());
+                    }
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            } else {
+                if (options.isCheckSyntaxOnly()) {
+                    System.err.println("Can't check syntax in IRB mode");
+                    return;
+                }
+
+                context.runShell(null, null);
+            }
+        } finally {
+            context.shutdown();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/README	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,21 @@
+This is a configuration of the RubySpec set of specifications -
+http://rubyspec.org. RubySpec is the specifications, and MSpec is the tool to
+run them.
+
+Thanks to Brian Shirai and others who have worked on RubySpec.
+
+At the moment we have only configured the version 1.9 specs, and we only run
+language and command line specs.
+
+In the `specs` directory (everything we do here will be in the `specs`
+directory), you need to clone the MSpec and RubySpec Git repositories:
+
+    $ git clone https://github.com/rubyspec/mspec.git
+    $ git --git-dir=mspec/.git --work-tree=mspec checkout 1343524a06466b7aa0c90798b7894454c8abce0f
+    $ git clone https://github.com/rubyspec/rubyspec.git
+    $ git --git-dir=rubyspec/.git --work-tree=rubyspec checkout 926e356b268fe32c67bec43a21565d727360a89b
+
+Then you can run MSpec to run RubySpec. We can run all of the harness in our
+implementation, not just as an executable under test.
+
+    $ ./rubytruffle mspec/bin/mspec run -t ./rubytruffle --config rubytruffle.mspec --excl-tag fails
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/rubytruffle	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# The command this file executes is what mx would execute, just taken out of
+# the mx wrapper because it appears to interfere with MSpec, and we need a
+# 'executable' (a shell script will do) to run.
+#
+# If this file isn't working for you try generating one for your setup. You
+# will need to do this for example if your Java isn't 1.7.0u45. You can use
+# the command below - the -v flag gives you the Java command, then just append
+# "$@".
+#
+#     $TRUFFLE_DIR/mxtool/mx -v --vm server-nograal ruby -ea -- --home $TRUFFLE_DIR "$@"
+
+TRUFFLE_DIR=../../..
+
+$TRUFFLE_DIR/jdk1.7.0_45/product/bin/java \
+  -server-nograal -d64 -ea \
+  -cp $TRUFFLE_DIR/lib/jline-2.10.jar:$TRUFFLE_DIR/lib/jrubyparser-0.5.0.jar:$TRUFFLE_DIR/lib/jruby-stdlib-1.7.4.jar:$TRUFFLE_DIR/lib/jnr-posix-3.0.0.jar:$TRUFFLE_DIR/lib/jnr-constants-0.8.4.jar:$TRUFFLE_DIR/lib/jnr-ffi-1.0.4.jar:$TRUFFLE_DIR/lib/jffi-1.2.1.jar:$TRUFFLE_DIR/lib/jffi-1.2.1-native.jar:$TRUFFLE_DIR/lib/jnr-x86asm-1.0.2.jar:$TRUFFLE_DIR/lib/asm-4.0.jar:$TRUFFLE_DIR/lib/asm-analysis-4.0.jar:$TRUFFLE_DIR/lib/asm-commons-4.0.jar:$TRUFFLE_DIR/lib/asm-tree-4.0.jar:$TRUFFLE_DIR/lib/asm-util-4.0.jar:$TRUFFLE_DIR/graal/com.oracle.truffle.api/bin:$TRUFFLE_DIR/graal/com.oracle.truffle.ruby.runtime/bin:$TRUFFLE_DIR/graal/com.oracle.truffle.api.dsl/bin:$TRUFFLE_DIR/graal/com.oracle.truffle.ruby.nodes/bin:$TRUFFLE_DIR/graal/com.oracle.truffle.ruby.parser/bin:$TRUFFLE_DIR/graal/com.oracle.truffle.ruby.shell/bin \
+  com.oracle.truffle.ruby.shell.Shell \
+  --home $TRUFFLE_DIR "$@"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/rubytruffle.mspec	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,26 @@
+class MSpecScript
+
+  Rubyspec = "rubyspec"
+
+  set :command_line, [
+    "rubyspec/command_line"
+  ]
+
+  set :language, [
+    "rubyspec/language"
+  ]
+
+  set :tags_patterns, [
+      [/rubyspec/, "tags"],
+      [/_spec.rb$/, "_tags.txt"]
+  ]
+
+  MSpec.enable_feature :encoding
+  MSpec.enable_feature :continuation
+  MSpec.enable_feature :fiber
+  MSpec.enable_feature :fork
+  MSpec.enable_feature :generator
+
+  set :files, get(:command_line) + get(:language)
+
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_a_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,2 @@
+fails:The -a command line option runs the code in loop conditional on Kernel.gets()
+fails:The -a command line option sets $-a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_d_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,3 @@
+fails:The -d command line option sets $DEBUG to true
+fails:The -d command line option sets $VERBOSE to true
+fails:The -d command line option sets $-d to true
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_e_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,2 @@
+fails:The -e command line option with -n and a Fixnum range mimics an awk conditional by comparing an inclusive-end range with $.
+fails:The -e command line option with -n and a Fixnum range mimics a sed conditional by comparing an exclusive-end range with $.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_n_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,4 @@
+fails:The -n command line option runs the code in loop conditional on Kernel.gets()
+fails:The -n command line option only evaluates BEGIN blocks once
+fails:The -n command line option only evaluates END blocks once
+fails:The -n command line option allows summing over a whole file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_p_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,2 @@
+fails:The -p command line option runs the code in loop conditional on Kernel.gets() and prints $_
+fails:The -p command line option sets $-p
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_r_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,1 @@
+fails:The -r command line option requires the specified file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_s_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,8 @@
+fails:The -s command line option when using -- to stop parsing sets the value to true without an explicit value
+fails:The -s command line option when using -- to stop parsing parses single letter args into globals
+fails:The -s command line option when using -- to stop parsing parses long args into globals
+fails:The -s command line option when using -- to stop parsing converts extra dashes into underscores
+fails:The -s command line option when running a script sets the value to true without an explicit value
+fails:The -s command line option when running a script parses single letter args into globals
+fails:The -s command line option when running a script parses long args into globals
+fails:The -s command line option when running a script converts extra dashes into underscores
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_upper_e_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,1 @@
+fails:ruby -E raises a RuntimeError if used with -U
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_upper_f_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,1 @@
+fails:the -F command line option specifies the field separator pattern for -a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_upper_i_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,1 @@
+fails:The -I command line option adds the path to the load path ($:)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_upper_u_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,7 @@
+fails:ruby -U sets Encoding.default_internal to UTF-8
+fails:ruby -U does nothing different if specified multiple times
+fails:ruby -U is overruled by Encoding.default_internal=
+fails:ruby -U does not affect the default external encoding
+fails:ruby -U does not affect the source encoding
+fails:ruby -U raises a RuntimeError if used with -Eext:int
+fails:ruby -U raises a RuntimeError if used with -E:int
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_upper_w_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,3 @@
+fails:The -W command line option with 0 sets $VERBOSE to nil
+fails:The -W command line option with 1 sets $VERBOSE to false
+fails:The -W command line option with 2 sets $VERBOSE to true
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_v_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,1 @@
+fails:The -v command line option sets $VERBOSE to true
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_w_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,1 @@
+fails:The -w command line option sets $VERBOSE to true
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/dash_x_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,2 @@
+fails:The -x command line option runs code after the first /#!.*ruby.*/-ish line in target file
+fails:The -x command line option needs to be reviewed for spec completeness
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/command_line/error_message_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,1 @@
+fails:The error message caused by an exception is not printed to stdout
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/BEGIN_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,4 @@
+fails:The BEGIN keyword runs first in a given code unit
+fails:The BEGIN keyword runs multiple begins in FIFO order
+fails:The BEGIN keyword runs in a shared scope
+fails:The BEGIN keyword accesses variables outside the eval scope
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/alias_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,11 @@
+fails:The alias keyword creates a new name for an existing method
+fails:The alias keyword adds the new method to the list of methods
+fails:The alias keyword adds the new method to the list of public methods
+fails:The alias keyword overwrites an existing method with the target name
+fails:The alias keyword is reversible
+fails:The alias keyword operates on the object's metaclass when used in instance_eval
+fails:The alias keyword operates on methods with splat arguments
+fails:The alias keyword operates on methods with splat arguments on eigenclasses
+fails:The alias keyword operates on methods with splat arguments defined in a superclass
+fails:The alias keyword operates on methods with splat arguments defined in a superclass using text block for class eval
+fails:The alias keyword is not allowed against Fixnum or String instances
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/array_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,4 @@
+fails:The unpacking splat operator (*) returns a new array containing the same values when applied to an array inside an empty array
+fails:The unpacking splat operator (*) unpacks the start and count arguments in an array slice assignment
+fails:Array literals [] treats splatted nil as no element
+fails:The unpacking splat operator (*) when applied to a non-Array value attempts to coerce it to Array if the object respond_to?(:to_a)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/block_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,67 @@
+fails:A block allows to define a block variable with the same name as the enclosing block
+fails:A block taking |a| arguments assigns nil to the argument when no values are yielded
+fails:A block taking |a| arguments does not call #to_ary to convert a single yielded object to an Array
+fails:A block taking |a| arguments assigns the first value yielded to the argument
+fails:A block taking |a, b| arguments assgins nil to the arguments when no values are yielded
+fails:A block taking |a, b| arguments assigns one value yielded to the first argument
+fails:A block taking |a, b| arguments destructures a splatted Array
+fails:A block taking |a, b| arguments calls #to_ary to convert a single yielded object to an Array
+fails:A block taking |a, b| arguments does not call #to_ary if the single yielded object is an Array
+fails:A block taking |a, b| arguments does not call #to_ary if the object does not respond to #to_ary
+fails:A block taking |a, b| arguments raises an TypeError if #to_ary does not return an Array
+fails:A block taking |a, *b| arguments assigns 'nil' and '[]' to the arguments when no values are yielded
+fails:A block taking |a, *b| arguments assigns all yielded values after the first to the rest argument
+fails:A block taking |a, *b| arguments assigns 'nil' and '[]' to the arguments when a single, empty Array is yielded
+fails:A block taking |a, *b| arguments assigns the element of a single element Array to the first argument
+fails:A block taking |a, *b| arguments destructures a splatted Array
+fails:A block taking |a, *b| arguments destructures a single Array value assigning the remaining values to the rest argument
+fails:A block taking |a, *b| arguments calls #to_ary to convert a single yielded object to an Array
+fails:A block taking |a, *b| arguments does not call #to_ary if the single yielded object is an Array
+fails:A block taking |a, *b| arguments raises an TypeError if #to_ary does not return an Array
+fails:A block taking |*| arguments does not call #to_ary if the single yielded object is an Array
+fails:A block taking |*| arguments does not call #to_ary to convert a single yielded object to an Array
+fails:A block taking |*a| arguments assigns all the values passed to the argument as an Array
+fails:A block taking |*a| arguments assigns '[[]]' to the argument when passed an empty Array
+fails:A block taking |*a| arguments assigns a single Array value passed to the argument by wrapping it in an Array
+fails:A block taking |*a| arguments does not call #to_ary if the single yielded object is an Array
+fails:A block taking |*a| arguments does not call #to_ary to convert a single yielded object to an Array
+fails:A block taking |a, | arguments assigns nil to the argument when no values are yielded
+fails:A block taking |a, | arguments assigns the argument the first value yielded
+fails:A block taking |a, | arguments assigns the argument the first of several values yielded when it is an Array
+fails:A block taking |a, | arguments assigns nil to the argument when passed an empty Array
+fails:A block taking |a, | arguments assigns the argument the first element of the Array when passed a single Array
+fails:A block taking |a, | arguments calls #to_ary to convert a single yielded object to an Array
+fails:A block taking |a, | arguments does not call #to_ary if the single yielded object is an Array
+fails:A block taking |a, | arguments raises an TypeError if #to_ary does not return an Array
+fails:A block taking |(a, b)| arguments assigns nil to the arguments when yielded no values
+fails:A block taking |(a, b)| arguments calls #to_ary to convert a single yielded object to an Array
+fails:A block taking |(a, b)| arguments does not call #to_ary if the single yielded object is an Array
+fails:A block taking |(a, b)| arguments does not call #to_ary if the object does not respond to #to_ary
+fails:A block taking |(a, b)| arguments raises an TypeError if #to_ary does not return an Array
+fails:A block taking |(a, b), c| arguments assigns nil to the arguments when yielded no values
+fails:A block taking |(a, b), c| arguments destructures a single one-level Array value yielded
+fails:A block taking |(a, b), c| arguments destructures a single multi-level Array value yielded
+fails:A block taking |(a, b), c| arguments calls #to_ary to convert a single yielded object to an Array
+fails:A block taking |(a, b), c| arguments does not call #to_ary if the single yielded object is an Array
+fails:A block taking |(a, b), c| arguments does not call #to_ary if the object does not respond to #to_ary
+fails:A block taking |(a, b), c| arguments raises an TypeError if #to_ary does not return an Array
+fails:A block taking nested |a, (b, (c, d))| destructures a single multi-level Array value yielded
+fails:A block taking nested |a, (b, (c, d))| destructures a single multi-level Array value yielded
+fails:A block taking nested |a, ((b, c), d)| destructures a single multi-level Array value yielded
+fails:A block taking nested |a, ((b, c), d)| destructures a single multi-level Array value yielded
+fails:A block arguments with _ extracts arguments with _
+fails:Block-local variables override shadowed variables from the outer scope
+fails:Post-args appear after a splat
+fails:Post-args are required
+fails:Post-args with required args gathers remaining args in the splat
+fails:Post-args with required args has an empty splat when there are no remaining args
+fails:Post-args with optional args gathers remaining args in the splat
+fails:Post-args with optional args overrides the optional arg before gathering in the splat
+fails:Post-args with optional args uses the required arg before the optional and the splat
+fails:Post-args with optional args overrides the optional args from left to right before gathering the splat
+fails:A block taking |(a, b)| arguments destructures a single Array value yielded
+fails:A block taking |(a, b)| arguments destructures a single Array value yielded when shadowing an outer variable
+fails:A block taking nested |a, (b, (c, d))| assigns nil to the arguments when yielded no values
+fails:A block taking nested |a, (b, (c, d))| destructures separate yielded values
+fails:A block taking nested |a, ((b, c), d)| assigns nil to the arguments when yielded no values
+fails:A block taking nested |a, ((b, c), d)| destructures separate yielded values
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/break_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,3 @@
+fails:The break statement in a lambda created at the toplevel returns a value when invoking from the toplevel
+fails:The break statement in a lambda created at the toplevel returns a value when invoking from a method
+fails:The break statement in a lambda created at the toplevel returns a value when invoking from a block
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/case_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,12 @@
+fails:The 'case'-construct evaluates the body of the when clause matching the case target expression
+fails:The 'case'-construct evaluates the body of the when clause whose array expression includes the case target expression
+fails:The 'case'-construct evaluates the body of the when clause in left-to-right order if it's an array expression
+fails:The 'case'-construct evaluates the body of the when clause whose range expression includes the case target expression
+fails:The 'case'-construct expands arrays to lists of values
+fails:The 'case'-construct concats arrays before expanding them
+fails:The 'case'-construct never matches when clauses with no values
+fails:The 'case'-construct works even if there's only one when statement
+fails:The 'case'-construct with no target expression evaluates true as only 'true' when true is the first clause
+fails:The 'case'-construct with no target expression evaluates false as only 'false' when false is the first clause
+fails:The 'case'-construct with no target expression treats a literal array as its own when argument, rather than a list of arguments
+fails:The 'case'-construct takes multiple expanded arrays
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/class_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,18 @@
+fails:A class definition has no class variables
+fails:A class definition raises TypeError if the constant qualifying the class is nil
+fails:A class definition raises TypeError if any constant qualifying the class is not a Module
+fails:A class definition allows using self as the superclass if self is a class
+fails:A class definition raises a TypeError if inheriting from a metaclass
+fails:A class definition allows the declaration of class variables in the body
+fails:A class definition stores instance variables defined in the class body in the class object
+fails:A class definition allows the declaration of class variables in a class method
+fails:A class definition allows the definition of class-level instance variables in a class method
+fails:A class definition allows the declaration of class variables in an instance method
+fails:A class definition returns the value of the last statement in the body
+fails:An outer class definition contains the inner classes
+fails:A class definition extending an object (sclass) raises a TypeError when trying to extend numbers
+fails:A class definition extending an object (sclass) allows accessing the block of the original scope
+fails:A class definition extending an object (sclass) can use return to cause the enclosing method to return
+fails:Reopening a class raises a TypeError when superclasses mismatch
+fails:Reopening a class adds new methods to subclasses
+fails:class provides hooks calls inherited when a class is created
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/class_variable_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,10 @@
+fails:A class variable can be accessed from a subclass
+fails:A class variable is set in the superclass
+fails:A class variable defined in a module can be accessed from classes that extend the module
+fails:A class variable defined in a module is not defined in these classes
+fails:A class variable defined in a module is only updated in the module a method defined in the module is used
+fails:A class variable defined in a module is updated in the class when a Method defined in the class is used
+fails:A class variable defined in a module can be accessed from modules that extend the module
+fails:A class variable defined in a module is defined in the extended module
+fails:A class variable defined in a module is not defined in the extending module
+fails:A class variable defined in a module can be accessed inside the class using the module methods
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/constants_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,45 @@
+fails:Literal (A::X) constant resolution sends #const_missing to the original class or module scope
+fails:Literal (A::X) constant resolution raises a TypeError if a non-class or non-module qualifier is given
+fails:Literal (A::X) constant resolution with statically assigned constants does not search the singleton class of the class or module
+fails:Literal (A::X) constant resolution with dynamically assigned constants does not search the singleton class of the class or module
+fails:Literal (A::X) constant resolution with dynamically assigned constants evaluates the right hand side before evaluating a constant path
+fails:Constant resolution within methods sends #const_missing to the original class or module scope
+fails:Constant resolution within methods with statically assigned constants searches the lexical scope of the method not the receiver's immediate class
+fails:Constant resolution within methods with statically assigned constants searches the lexical scope of a singleton method
+fails:Constant resolution within methods with statically assigned constants searches Object as a lexical scope only if Object is explicitly opened
+fails:Constant resolution within methods with dynamically assigned constants searches the immediate class or module scope first
+fails:Constant resolution within methods with dynamically assigned constants searches the superclass before a module included in the superclass
+fails:Constant resolution within methods with dynamically assigned constants searches the lexical scope of the method not the receiver's immediate class
+fails:Constant resolution within methods with dynamically assigned constants searches the lexical scope of a singleton method
+fails:Constant resolution within methods with dynamically assigned constants does not search the lexical scope of the caller
+fails:Constant resolution within methods with dynamically assigned constants searches the lexical scope of a block
+fails:Constant resolution within methods with dynamically assigned constants searches Object as a lexical scope only if Object is explicitly opened
+fails:Constant resolution within methods with ||= assignes constant if previously undefined
+fails:Module#private_constant marked constants remain private even when updated
+fails:Module#private_constant marked constants in a module cannot be accessed from outside the module
+fails:Module#private_constant marked constants in a module cannot be reopened as a module
+fails:Module#private_constant marked constants in a module cannot be reopened as a class
+fails:Module#private_constant marked constants in a module is not defined? with A::B form
+fails:Module#private_constant marked constants in a module can be accessed from lexical scope
+fails:Module#private_constant marked constants in a module is defined? from lexical scope
+fails:Module#private_constant marked constants in a class cannot be accessed from outside the class
+fails:Module#private_constant marked constants in a class cannot be reopened as a module
+fails:Module#private_constant marked constants in a class cannot be reopened as a class
+fails:Module#private_constant marked constants in a class is not defined? with A::B form
+fails:Module#private_constant marked constants in a class can be accessed from lexical scope
+fails:Module#private_constant marked constants in Object cannot be accessed using ::Const form
+fails:Module#private_constant marked constants in Object is not defined? using ::Const form
+fails:Module#public_constant marked constants in a module can be accessed from outside the module
+fails:Module#public_constant marked constants in a module is defined? with A::B form
+fails:Module#public_constant marked constants in a class can be accessed from outside the class
+fails:Module#public_constant marked constants in a class is defined? with A::B form
+fails:Module#public_constant marked constants in Object can be accessed using ::Const form
+fails:Module#public_constant marked constants in Object is defined? using ::Const form
+fails:Module#private_constant marked constants in a class is defined? from lexical scope
+fails:Literal (A::X) constant resolution with statically assigned constants searches a module included in the superclass
+fails:Constant resolution within methods with statically assigned constants searches a module included in the superclass
+fails:Constant resolution within methods with statically assigned constants searches the superclass chain
+fails:Literal (A::X) constant resolution with statically assigned constants searches Object if no class or module qualifier is given
+fails:Literal (A::X) constant resolution with statically assigned constants searches Object after searching other scopes
+fails:Constant resolution within methods with statically assigned constants searches the superclass chain
+fails:Literal (A::X) constant resolution with statically assigned constants searches the superclass chain
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/def_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,28 @@
+fails:Defining an 'initialize' method sets the method's visibility to private
+fails:Defining an 'initialize_copy' method sets the method's visibility to private
+fails:An instance method with a default argument assigns an empty Array to an unused splat argument
+fails:An instance method with a default argument prefers to assign to a default argument when there are no required arguments
+fails:An instance method with a default argument does not evaluate the default when passed a value and a * argument
+fails:A singleton method definition raises RuntimeError if frozen
+fails:Redefining a singleton method does not inherit a previously set visibility 
+fails:Redefining a singleton method does not inherit a previously set visibility 
+fails:A method defined with extreme default arguments may use an fcall as a default
+fails:A method defined with extreme default arguments may use preceding arguments as defaults
+fails:A method defined with extreme default arguments may use a lambda as a default
+fails:A singleton method defined with extreme default arguments may use an fcall as a default
+fails:A singleton method defined with extreme default arguments may use preceding arguments as defaults
+fails:A singleton method defined with extreme default arguments may use a lambda as a default
+fails:A method definition inside a metaclass scope can create a class method
+fails:A method definition inside a metaclass scope can create a singleton method
+fails:A method definition inside a metaclass scope raises RuntimeError if frozen
+fails:A nested method definition creates an instance method when evaluated in an instance method
+fails:A nested method definition creates a class method when evaluated in a class method
+fails:A nested method definition creates a singleton method when evaluated in the metaclass of an instance
+fails:A method definition inside an instance_eval creates a singleton method
+fails:A method definition inside an instance_eval creates a singleton method when evaluated inside a metaclass
+fails:A method definition inside an instance_eval creates a class method when the receiver is a class
+fails:A method definition in an eval creates an instance method
+fails:A method definition in an eval creates a class method
+fails:A method definition in an eval creates a singleton method
+fails:a method definition that sets more than one default parameter all to the same value assigns them all the same object by default
+fails:The def keyword within a closure looks outside the closure for the visibility
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/defined_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,48 @@
+fails:The defined? keyword when called with a method name having a module as receiver returns nil if the method is private
+fails:The defined? keyword when called with a method name having a module as receiver returns nil if the method is protected
+fails:The defined? keyword when called with a method name having a local variable as receiver calls #respond_to_missing?
+fails:The defined? keyword for an expression returns nil for an expression with !~ and an undefined method
+fails:The defined? keyword for an expression returns 'method' for an expression with '!~'
+fails:The defined? keyword for an expression with logical connectives returns nil for an expression with '!' and an unset class variable
+fails:The defined? keyword for an expression with logical connectives returns nil for an expression with 'not' and an unset class variable
+fails:The defined? keyword for an expression with logical connectives returns nil for an expression with '!' and an unset global variable
+fails:The defined? keyword for an expression with logical connectives returns nil for an expression with '!' and an unset instance variable
+fails:The defined? keyword for an expression with logical connectives returns nil for an expression with 'not' and an unset global variable
+fails:The defined? keyword for an expression with logical connectives returns nil for an expression with 'not' and an unset instance variable
+fails:The defined? keyword for variables returns nil for a global variable that has not been read
+fails:The defined? keyword for variables returns nil for a global variable that has been read but not assigned to
+fails:The defined? keyword for variables when a String does not match a Regexp returns nil for $&
+fails:The defined? keyword for variables when a String does not match a Regexp returns nil for $`
+fails:The defined? keyword for variables when a String does not match a Regexp returns nil for $'
+fails:The defined? keyword for variables when a String does not match a Regexp returns nil for $+
+fails:The defined? keyword for variables when a String matches a Regexp returns 'global-variable' for $&
+fails:The defined? keyword for variables when a String matches a Regexp returns 'global-variable' for $`
+fails:The defined? keyword for variables when a String matches a Regexp returns 'global-variable' for $'
+fails:The defined? keyword for variables when a String matches a Regexp returns 'global-variable' for $+
+fails:The defined? keyword for variables when a String matches a Regexp returns 'global-variable' for the capture references
+fails:The defined? keyword for variables when a Regexp does not match a String returns nil for $&
+fails:The defined? keyword for variables when a Regexp does not match a String returns nil for $`
+fails:The defined? keyword for variables when a Regexp does not match a String returns nil for $'
+fails:The defined? keyword for variables when a Regexp does not match a String returns nil for $+
+fails:The defined? keyword for variables when a Regexp matches a String returns 'global-variable' for $&
+fails:The defined? keyword for variables when a Regexp matches a String returns 'global-variable' for $`
+fails:The defined? keyword for variables when a Regexp matches a String returns 'global-variable' for $'
+fails:The defined? keyword for variables when a Regexp matches a String returns 'global-variable' for $+
+fails:The defined? keyword for variables when a Regexp matches a String returns 'global-variable' for the capture references
+fails:The defined? keyword for a scoped constant returns nil when an undefined constant is scoped to a defined constant
+fails:The defined? keyword for a top-level scoped constant returns nil when an undefined constant is scoped to a defined constant
+fails:The defined? keyword for super returns nil when a superclass undef's the method
+fails:The defined? keyword for super for a method taking no arguments returns 'super' from a block when a superclass method exists
+fails:The defined? keyword for super for a method taking no arguments returns 'super' from a #define_method when a superclass method exists
+fails:The defined? keyword for super for a method taking no arguments returns 'super' from a block in a #define_method when a superclass method exists
+fails:The defined? keyword for super for a method taking no arguments returns 'super' when the method exists in a supermodule
+fails:The defined? keyword for super for a method taking arguments returns 'super' when a superclass method exists
+fails:The defined? keyword for super for a method taking arguments returns 'super' from a block when a superclass method exists
+fails:The defined? keyword for super for a method taking arguments returns 'super' from a #define_method when a superclass method exists
+fails:The defined? keyword for super for a method taking arguments returns 'super' from a block in a #define_method when a superclass method exists
+fails:The defined? keyword for super within an included module's method returns 'super' when a superclass method exists in the including hierarchy
+fails:The defined? keyword for instance variables returns nil if not assigned
+fails:The defined? keyword for variables when a String does not match a Regexp returns nil for $1-$9
+fails:The defined? keyword for variables when a String matches a Regexp returns nil for non-captures
+fails:The defined? keyword for variables when a Regexp does not match a String returns nil for $1-$9
+fails:The defined? keyword for variables when a Regexp matches a String returns nil for non-captures
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/encoding_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,14 @@
+fails:The __ENCODING__ pseudo-variable is an instance of Encoding
+fails:The __ENCODING__ pseudo-variable is US-ASCII by default
+fails:The __ENCODING__ pseudo-variable is the evaluated strings's one inside an eval
+fails:The __ENCODING__ pseudo-variable is the encoding specified by a magic comment inside an eval
+fails:The __ENCODING__ pseudo-variable is the encoding specified by a magic comment in the file
+fails:The __ENCODING__ pseudo-variable is Encoding::ASCII_8BIT when the interpreter is invoked with -Ka
+fails:The __ENCODING__ pseudo-variable is Encoding::ASCII_8BIT when the interpreter is invoked with -KA
+fails:The __ENCODING__ pseudo-variable is Encoding::EUC_JP when the interpreter is invoked with -Ke
+fails:The __ENCODING__ pseudo-variable is Encoding::EUC_JP when the interpreter is invoked with -KE
+fails:The __ENCODING__ pseudo-variable is Encoding::UTF_8 when the interpreter is invoked with -Ku
+fails:The __ENCODING__ pseudo-variable is Encoding::UTF_8 when the interpreter is invoked with -KU
+fails:The __ENCODING__ pseudo-variable is Encoding::Windows_31J when the interpreter is invoked with -Ks
+fails:The __ENCODING__ pseudo-variable is Encoding::Windows_31J when the interpreter is invoked with -KS
+fails:The __ENCODING__ pseudo-variable raises a SyntaxError if assigned to
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/ensure_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,2 @@
+fails:An ensure block inside a begin block is executed when an exception is raised in it's corresponding begin block
+fails:An ensure block inside a method is executed when an exception is raised in the method
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/execution_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,2 @@
+fails:`` returns the output of the executed sub-process
+fails:%x is the same as ``
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/file_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,3 @@
+fails:The __FILE__ pseudo-variable equals (eval) inside an eval
+fails:The __FILE__ pseudo-variable equals the absolute path of a file loaded by an absolute path
+fails:The __FILE__ pseudo-variable equals the absolute path of a file loaded by a relative path
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/for_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,6 @@
+fails:The for expression iterates over an Hash passing each key-value pair to the block
+fails:The for expression allows a class variable as an iterator name
+fails:The for expression yields only as many values as there are arguments
+fails:The for expression executes code in containing variable scope
+fails:The for expression executes code in containing variable scope with 'do'
+fails:The for expression returns expr
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/hash_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,1 @@
+fails:Hash literal freezes string keys on initialization
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/line_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,1 @@
+fails:The __LINE__ pseudo-variable equals the line number of the text in a loaded file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/literal_lambda_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,4 @@
+fails:->(){} assigns the given block to the parameter prefixed with an ampersand if such a parameter exists
+fails:->(){} sets parameters appropriately when a combination of parameter types is given between the parenthesis
+fails:->(){} uses lambda's 'rigid' argument handling
+fails:->(){} evaluates constants as normal blocks do
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/magic_comment_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,8 @@
+fails:Magic comment is optional
+fails:Magic comment determines __ENCODING__
+fails:Magic comment is case-insensitive
+fails:Magic comment must be at the first line
+fails:Magic comment must be the first token of the line
+fails:Magic comment can be after the shebang
+fails:Magic comment can take Emacs style
+fails:Magic comment can take vim style
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/match_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,2 @@
+fails:The !~ operator evaluates as a call to !~
+fails:The =~ operator calls the =~ method
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/metaclass_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,16 @@
+fails:self in a metaclass body (class << obj) is TrueClass for true
+fails:self in a metaclass body (class << obj) is FalseClass for false
+fails:self in a metaclass body (class << obj) is NilClass for nil
+fails:self in a metaclass body (class << obj) raises a TypeError for numbers
+fails:self in a metaclass body (class << obj) raises a TypeError for symbols
+fails:self in a metaclass body (class << obj) is a singleton Class instance
+fails:A constant on a metaclass can be accessed via const_get
+fails:A constant on a metaclass cannot be accessed via object::CONST
+fails:A constant on a metaclass raises a NameError for anonymous_module::CONST
+fails:A constant on a metaclass appears in the metaclass constant list
+fails:A constant on a metaclass does not appear in the object's class constant list
+fails:A constant on a metaclass is not preserved when the object is duped
+fails:A constant on a metaclass is preserved when the object is cloned
+fails:calling methods on the metaclass calls a method on the instance's metaclass
+fails:calling methods on the metaclass calls a method in deeper chains of metaclasses
+fails:calling methods on the metaclass calls a method defined on the metaclass of the metaclass
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/module_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,7 @@
+fails:The module keyword reopens a module included in Object
+fails:The module keyword raises a TypeError if the constant is a Class
+fails:The module keyword raises a TypeError if the constant is a String
+fails:The module keyword raises a TypeError if the constant is a Fixnum
+fails:The module keyword raises a TypeError if the constant is nil
+fails:The module keyword raises a TypeError if the constant is true
+fails:The module keyword raises a TypeError if the constant is false
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/next_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,9 @@
+fails:The next statement from within the block returns the argument passed
+fails:The next statement from within the block returns to the invoking method, with the specified value
+fails:The next statement from within the block returns to the currently yielding method in case of chained calls
+fails:Assignment via next assigns objects
+fails:Assignment via next assigns splatted objects
+fails:Assignment via next assigns objects to a splatted reference
+fails:Assignment via next assigns splatted objects to a splatted reference via a splatted yield
+fails:Assignment via next assigns objects to multiple variables
+fails:Assignment via next assigns splatted objects to multiple variables
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/precedence_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,2 @@
+fails:Operators + - have higher precedence than >> <<
+fails:Operators + - are left-associative
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/predefined/data_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,6 @@
+fails:The DATA constant exists when the main script contains __END__
+fails:The DATA constant does not exist when the main script contains no __END__
+fails:The DATA constant does not exist when an included file has a __END__
+fails:The DATA constant does not change when an included files also has a __END__
+fails:The DATA constant is included in an otherwise empty file
+fails:The DATA constant succeeds in locking the file DATA came from
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/predefined_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,108 @@
+fails:Predefined global $~ is set to contain the MatchData object of the last match if successful
+fails:Predefined global $~ is set to nil if the last match was unsuccessful
+fails:Predefined global $~ is set at the method-scoped level rather than block-scoped
+fails:Predefined global $~ raises an error if assigned an object not nil or instanceof MatchData
+fails:Predefined global $~ changes the value of derived capture globals when assigned
+fails:Predefined global $~ changes the value of the derived preceding match global
+fails:Predefined global $~ changes the value of the derived following match global
+fails:Predefined global $~ changes the value of the derived full match global
+fails:Predefined global $& is equivalent to MatchData#[0] on the last match $~
+fails:Predefined global $& sets the encoding to the encoding of the source String
+fails:Predefined global $` is equivalent to MatchData#pre_match on the last match $~
+fails:Predefined global $` sets the encoding to the encoding of the source String
+fails:Predefined global $` sets an empty result to the encoding of the source String
+fails:Predefined global $' is equivalent to MatchData#post_match on the last match $~
+fails:Predefined global $' sets the encoding to the encoding of the source String
+fails:Predefined global $' sets an empty result to the encoding of the source String
+fails:Predefined global $+ is equivalent to $~.captures.last
+fails:Predefined global $+ captures the last non nil capture
+fails:Predefined global $+ sets the encoding to the encoding of the source String
+fails:Predefined globals $1..N are equivalent to $~[N]
+fails:Predefined globals $1..N are nil unless a match group occurs
+fails:Predefined globals $1..N sets the encoding to the encoding of the source String
+fails:Predefined global $stdout is the same as $DEFAULT_OUTPUT from 'English' library
+fails:Predefined global $stdout raises TypeError error if assigned to nil
+fails:Predefined global $stdout raises TypeError error if assigned to object that doesn't respond to #write
+fails:Predefined global $! remains nil after a failed core class "checked" coercion against a class that defines method_missing
+fails:Predefined global $/ changes $-0
+fails:Predefined global $/ does not call #to_str to convert the object to a String
+fails:Predefined global $/ raises a TypeError if assigned a Fixnum
+fails:Predefined global $/ raises a TypeError if assigned a boolean
+fails:Predefined global $-0 changes $/
+fails:Predefined global $-0 does not call #to_str to convert the object to a String
+fails:Predefined global $-0 raises a TypeError if assigned a Fixnum
+fails:Predefined global $-0 raises a TypeError if assigned a boolean
+fails:Predefined global $, raises TypeError if assigned a non-String
+fails:Predefined global $_ is set to the last line read by e.g. StringIO#gets
+fails:Predefined global $_ is set at the method-scoped level rather than block-scoped
+fails:Predefined global $_ is Thread-local
+fails:Execution variable $: does not include '.' when the taint check level > 1
+fails:Execution variable $: is the same object as $LOAD_PATH and $-I
+fails:Execution variable $: is read-only
+fails:Global variable $" is read-only
+fails:Global variable $< is read-only
+fails:Global variable $FILENAME is read-only
+fails:Global variable $? is read-only
+fails:Global variable $? is thread-local
+fails:Global variable $-a is read-only
+fails:Global variable $-l is read-only
+fails:Global variable $-p is read-only
+fails:Global variable $-d is an alias of $DEBUG
+fails:Global variable $-v is an alias of $VERBOSE
+fails:Global variable $-w is an alias of $VERBOSE
+fails:Global variable $0 raises a TypeError when not given an object that can be coerced to a String
+fails:The predefined standard objects includes ARGF
+fails:The predefined global constants includes TRUE
+fails:The predefined global constants includes FALSE
+fails:The predefined global constants includes NIL
+fails:The predefined global constants includes STDIN
+fails:The predefined global constants includes STDOUT
+fails:The predefined global constants includes STDERR
+fails:The predefined global constants includes RUBY_RELEASE_DATE
+fails:The predefined global constants includes TOPLEVEL_BINDING
+fails:Processing RUBYOPT adds the -I path to $LOAD_PATH
+fails:Processing RUBYOPT sets $DEBUG to true for '-d'
+fails:Processing RUBYOPT prints the version number for '-v'
+fails:Processing RUBYOPT sets $VERBOSE to true for '-w'
+fails:Processing RUBYOPT sets $VERBOSE to true for '-W'
+fails:Processing RUBYOPT sets $VERBOSE to nil for '-W0'
+fails:Processing RUBYOPT sets $VERBOSE to false for '-W1'
+fails:Processing RUBYOPT sets $VERBOSE to true for '-W2'
+fails:Processing RUBYOPT requires the file for '-r'
+fails:Processing RUBYOPT raises a RuntimeError for '-a'
+fails:Processing RUBYOPT raises a RuntimeError for '-p'
+fails:Processing RUBYOPT raises a RuntimeError for '-n'
+fails:Processing RUBYOPT raises a RuntimeError for '-y'
+fails:Processing RUBYOPT raises a RuntimeError for '-c'
+fails:Processing RUBYOPT raises a RuntimeError for '-s'
+fails:Processing RUBYOPT raises a RuntimeError for '-h'
+fails:Processing RUBYOPT raises a RuntimeError for '--help'
+fails:Processing RUBYOPT raises a RuntimeError for '-l'
+fails:Processing RUBYOPT raises a RuntimeError for '-S'
+fails:Processing RUBYOPT raises a RuntimeError for '-e'
+fails:Processing RUBYOPT raises a RuntimeError for '-i'
+fails:Processing RUBYOPT raises a RuntimeError for '-x'
+fails:Processing RUBYOPT raises a RuntimeError for '-C'
+fails:Processing RUBYOPT raises a RuntimeError for '-X'
+fails:Processing RUBYOPT raises a RuntimeError for '-F'
+fails:Processing RUBYOPT raises a RuntimeError for '-0'
+fails:Processing RUBYOPT raises a RuntimeError for '--copyright'
+fails:Processing RUBYOPT raises a RuntimeError for '--version'
+fails:Processing RUBYOPT raises a RuntimeError for '--yydebug'
+fails:The predefined global constant STDERR has nil for the external encoding despite Encoding.default_external being changed
+fails:The predefined global constant STDERR has the encodings set by #set_encoding
+fails:The predefined global constant ARGV contains Strings encoded in locale Encoding
+fails:The predefined global constant STDERR has nil for the internal encoding despite Encoding.default_internal being changed
+fails:The predefined global constant STDERR has nil for the internal encoding
+fails:The predefined global constant STDERR has nil for the external encoding
+fails:The predefined global constant STDOUT has nil for the internal encoding despite Encoding.default_internal being changed
+fails:The predefined global constant STDOUT has nil for the internal encoding
+fails:The predefined global constant STDOUT has the encodings set by #set_encoding
+fails:The predefined global constant STDOUT has nil for the external encoding despite Encoding.default_external being changed
+fails:The predefined global constant STDOUT has nil for the external encoding
+fails:The predefined global constant STDIN has nil for the internal encoding despite Encoding.default_internal being changed
+fails:The predefined global constant STDIN has nil for the internal encoding
+fails:The predefined global constant STDIN retains the encoding set by #set_encoding when Encoding.default_external is changed
+fails:The predefined global constant STDIN has the encodings set by #set_encoding
+fails:The predefined global constant STDIN has the same external encoding as Encoding.default_external when that encoding is changed
+fails:The predefined global constant STDIN has the same external encoding as Encoding.default_external
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/private_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,1 @@
+fails:The private keyword is overridden when a new class is opened
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/proc_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,18 @@
+fails:A Proc taking zero arguments raises an ArgumentErro if a value is passed
+fails:A Proc taking || arguments raises an ArgumentError if a value is passed
+fails:A Proc taking |a| arguments does not call #to_ary to convert a single passed object to an Array
+fails:A Proc taking |a| arguments raises an ArgumentError if no value is passed
+fails:A Proc taking |a, b| arguments raises an ArgumentError if passed no values
+fails:A Proc taking |a, b| arguments raises an ArgumentError if passed one value
+fails:A Proc taking |a, b| arguments does not call #to_ary to convert a single passed object to an Array
+fails:A Proc taking |a, *b| arguments raises an ArgumentError if passed no values
+fails:A Proc taking |a, *b| arguments does not call #to_ary to convert a single passed object to an Array
+fails:A Proc taking |*| arguments does not call #to_ary to convert a single passed object to an Array
+fails:A Proc taking |*a| arguments does not call #to_ary to convert a single passed object to an Array
+fails:A Proc taking |a, | arguments raises an ArgumentError when passed no values
+fails:A Proc taking |a, | arguments raises an ArgumentError when passed more than one value
+fails:A Proc taking |a, | arguments does not call #to_ary to convert a single passed object to an Array
+fails:A Proc taking |(a, b)| arguments raises an ArgumentError when passed no values
+fails:A Proc taking |(a, b)| arguments calls #to_ary to convert a single passed object to an Array
+fails:A Proc taking |(a, b)| arguments raises an TypeError if #to_ary does not return an Array
+fails:A Proc taking |(a, b)| arguments destructures a single Array value yielded
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/redo_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,3 @@
+fails:The redo statement restarts block execution if used within block
+fails:The redo statement re-executes the closest loop
+fails:The redo statement re-executes the last step in enumeration
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/anchors_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,1 @@
+fails:Regexps with anchors supports B (non-word-boundary)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/back-references_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,4 @@
+fails:Regexps with back-references saves match data in the $~ pseudo-global variable
+fails:Regexps with back-references saves captures in numbered $[1-9] variables
+fails:Regexps with back-references will not clobber capture variables across threads
+fails:Regexps with back-references resets nested <n> backreference before match of outer subexpression
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/character_classes_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,68 @@
+fails:Regexp with character classes supports [] (character class)
+fails:Regexp with character classes supports [[:alpha:][:digit:][:etc:]] (predefined character classes)
+fails:Regexp with character classes matches ASCII characters with [[:ascii:]]
+fails:Regexp with character classes matches Unicode letter characters with [[:alnum:]]
+fails:Regexp with character classes matches Unicode digits with [[:alnum:]]
+fails:Regexp with character classes doesn't match Unicode control characters with [[:alnum:]]
+fails:Regexp with character classes doesn't match Unicode punctuation characters with [[:alnum:]]
+fails:Regexp with character classes matches Unicode letter characters with [[:alpha:]]
+fails:Regexp with character classes doesn't match Unicode digits with [[:alpha:]]
+fails:Regexp with character classes doesn't match Unicode control characters with [[:alpha:]]
+fails:Regexp with character classes doesn't match Unicode punctuation characters with [[:alpha:]]
+fails:Regexp with character classes matches Unicode space characters with [[:blank:]]
+fails:Regexp with character classes matches Unicode control characters with [[:cntrl:]]
+fails:Regexp with character classes matches Unicode digits with [[:digit:]]
+fails:Regexp with character classes matches Unicode letter characters with [[:graph:]]
+fails:Regexp with character classes matches Unicode digits with [[:graph:]]
+fails:Regexp with character classes matches Unicode marks with [[:graph:]]
+fails:Regexp with character classes matches Unicode punctuation characters with [[:graph:]]
+fails:Regexp with character classes match Unicode format characters with [[:graph:]]
+fails:Regexp with character classes match Unicode private-use characters with [[:graph:]]
+fails:Regexp with character classes matches Unicode lowercase letter characters with [[:lower:]]
+fails:Regexp with character classes matches Unicode lowercase letter characters with [[:print:]]
+fails:Regexp with character classes matches Unicode uppercase letter characters with [[:print:]]
+fails:Regexp with character classes matches Unicode title-case characters with [[:print:]]
+fails:Regexp with character classes matches Unicode digits with [[:print:]]
+fails:Regexp with character classes matches Unicode marks with [[:print:]]
+fails:Regexp with character classes matches Unicode punctuation characters with [[:print:]]
+fails:Regexp with character classes match Unicode format characters with [[:print:]]
+fails:Regexp with character classes match Unicode private-use characters with [[:print:]]
+fails:Regexp with character classes matches Unicode Pc characters with [[:punct:]]
+fails:Regexp with character classes matches Unicode Pd characters with [[:punct:]]
+fails:Regexp with character classes matches Unicode Ps characters with [[:punct:]]
+fails:Regexp with character classes matches Unicode Pe characters with [[:punct:]]
+fails:Regexp with character classes matches Unicode Pi characters with [[:punct:]]
+fails:Regexp with character classes matches Unicode Pf characters with [[:punct:]]
+fails:Regexp with character classes matches Unicode Pf characters with [[:punct:]]
+fails:Regexp with character classes matches Unicode Po characters with [[:punct:]]
+fails:Regexp with character classes matches Unicode Zs characters with [[:space:]]
+fails:Regexp with character classes matches Unicode Zl characters with [[:space:]]
+fails:Regexp with character classes matches Unicode Zp characters with [[:space:]]
+fails:Regexp with character classes matches Unicode uppercase characters with [[:upper:]]
+fails:Regexp with character classes doesn't match Unicode letter characters [^a-fA-F] with [[:xdigit:]]
+fails:Regexp with character classes matches Unicode letter characters [a-fA-F] with [[:xdigit:]]
+fails:Regexp with character classes matches Unicode lowercase characters with [[:word:]]
+fails:Regexp with character classes matches Unicode uppercase characters with [[:word:]]
+fails:Regexp with character classes matches Unicode title-case characters with [[:word:]]
+fails:Regexp with character classes matches Unicode decimal digits with [[:word:]]
+fails:Regexp with character classes matches Unicode marks with [[:word:]]
+fails:Regexp with character classes match Unicode Nl characters with [[:word:]]
+fails:Regexps with anchors supports ^ (line start anchor)
+fails:Regexp with character classes doesn't matches Unicode marks with [[:alnum:]]
+fails:Regexp with character classes doesn't match Unicode lowercase letter characters with [[:punct:]]
+fails:Regexp with character classes doesn't match Unicode uppercase letter characters with [[:punct:]]
+fails:Regexp with character classes doesn't match Unicode title-case characters with [[:punct:]]
+fails:Regexp with character classes doesn't match Unicode digits with [[:punct:]]
+fails:Regexp with character classes doesn't match Unicode marks with [[:punct:]]
+fails:Regexp with character classes doesn't match Unicode format characters with [[:punct:]]
+fails:Regexp with character classes doesn't match Unicode private-use characters with [[:punct:]]
+fails:Regexp with character classes doesn't match Unicode lowercase characters with [[:upper:]]
+fails:Regexp with character classes doesn't match Unicode title-case characters with [[:upper:]]
+fails:Regexp with character classes doesn't match Unicode digits with [[:upper:]]
+fails:Regexp with character classes doesn't match Unicode marks with [[:upper:]]
+fails:Regexp with character classes doesn't match Unicode punctuation characters with [[:upper:]]
+fails:Regexp with character classes doesn't match Unicode control characters with [[:upper:]]
+fails:Regexp with character classes doesn't match Unicode format characters with [[:upper:]]
+fails:Regexp with character classes doesn't match Unicode private-use characters with [[:upper:]]
+fails:Regexps with escape characters support \x (hex characters)
+fails:Regexps with escape characters support \c (control characters)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/encoding_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,23 @@
+fails:Regexps with encoding modifiers supports /e (EUC encoding)
+fails:Regexps with encoding modifiers supports /e (EUC encoding) with interpolation
+fails:Regexps with encoding modifiers supports /e (EUC encoding) with interpolation /o
+fails:Regexps with encoding modifiers uses EUC-JP as /e encoding
+fails:Regexps with encoding modifiers preserves EUC-JP as /e encoding through interpolation
+fails:Regexps with encoding modifiers supports /n (No encoding)
+fails:Regexps with encoding modifiers supports /n (No encoding) with interpolation
+fails:Regexps with encoding modifiers supports /n (No encoding) with interpolation /o
+fails:Regexps with encoding modifiers uses US-ASCII as /n encoding if all chars are 7-bit
+fails:Regexps with encoding modifiers uses ASCII-8BIT as /n encoding if not all chars are 7-bit
+fails:Regexps with encoding modifiers preserves US-ASCII as /n encoding through interpolation if all chars are 7-bit
+fails:Regexps with encoding modifiers preserves ASCII-8BIT as /n encoding through interpolation if all chars are 7-bit
+fails:Regexps with encoding modifiers supports /s (Windows_31J encoding)
+fails:Regexps with encoding modifiers supports /s (Windows_31J encoding) with interpolation
+fails:Regexps with encoding modifiers supports /s (Windows_31J encoding) with interpolation and /o
+fails:Regexps with encoding modifiers uses Windows-31J as /s encoding
+fails:Regexps with encoding modifiers preserves Windows-31J as /s encoding through interpolation
+fails:Regexps with encoding modifiers supports /u (UTF8 encoding)
+fails:Regexps with encoding modifiers supports /u (UTF8 encoding) with interpolation
+fails:Regexps with encoding modifiers supports /u (UTF8 encoding) with interpolation and /o
+fails:Regexps with encoding modifiers uses UTF-8 as /u encoding
+fails:Regexps with encoding modifiers preserves UTF-8 as /u encoding through interpolation
+fails:Regexps with encoding modifiers selects last of multiple encoding specifiers
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/escapes_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,2 @@
+fails:Regexps with escape characters support \x (hex characters)
+fails:Regexps with escape characters support \c (control characters)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/grouping_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,1 @@
+fails:Regexps with grouping raise a SyntaxError when parentheses aren't balanced
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/interpolation_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,7 @@
+fails:Regexps with interpolation allows interpolation of literal regexps
+fails:Regexps with interpolation allows interpolation of any class that responds to to_s
+fails:Regexps with interpolation allows interpolation which mixes modifiers
+fails:Regexps with interpolation gives precedence to escape sequences over substitution
+fails:Regexps with interpolation throws RegexpError for malformed interpolation
+fails:Regexps with interpolation allows interpolation in extended mode
+fails:Regexps with interpolation allows escape sequences in interpolated regexps
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/modifiers_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,9 @@
+fails:Regexps with modifers supports /m (multiline)
+fails:Regexps with modifers supports /x (extended syntax)
+fails:Regexps with modifers supports /o (once)
+fails:Regexps with modifers invokes substitutions for /o only once
+fails:Regexps with modifers supports (?imx-imx) (inline modifiers)
+fails:Regexps with modifers supports (?imx-imx:expr) (scoped inline modifiers)
+fails:Regexps with modifers supports . with /m
+fails:Regexps with modifers supports ASII/Unicode modifiers
+fails:Regexps with modifers raises SyntaxError for ASII/Unicode modifiers
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp/repetition_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,1 @@
+fails:Regexps with repetition does not treat {m,n}+ as possessive
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/regexp_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,16 @@
+fails:Literal Regexps matches against $_ (last input) in a conditional if no explicit matchee provided
+fails:Literal Regexps throws SyntaxError for malformed literals
+fails:Literal Regexps supports paired delimiters with %r
+fails:Literal Regexps supports grouping constructs that are also paired delimiters
+fails:Literal Regexps allows second part of paired delimiters to be used as non-paired delimiters
+fails:Literal Regexps supports non-paired delimiters delimiters with %r
+fails:Literal Regexps allows unescaped / to be used with %r
+fails:Literal Regexps supports . (any character except line terminator)
+fails:Literal Regexps supports | (alternations)
+fails:Literal Regexps supports (?> ) (embedded subexpression)
+fails:Literal Regexps supports (?# )
+fails:Literal Regexps supports (?<= ) (positive lookbehind)
+fails:Literal Regexps supports (?<! ) (negative lookbehind)
+fails:Literal Regexps supports g (named backreference)
+fails:Literal Regexps supports character class composition
+fails:Literal Regexps supports possessive quantifiers
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/rescue_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,9 @@
+fails:The rescue keyword can be used to handle a specific exception
+fails:The rescue keyword can capture the raised exception in a local variable
+fails:The rescue keyword can rescue multiple raised exceptions with a single rescue block
+fails:The rescue keyword can rescue a splatted list of exceptions
+fails:The rescue keyword will only rescue the specified exceptions when doing a splat rescue
+fails:The rescue keyword will execute an else block only if no exceptions were raised
+fails:The rescue keyword will not execute an else block if an exception was raised
+fails:The rescue keyword will not rescue errors raised in an else block in the rescue block above it
+fails:The rescue keyword parses  'a += b rescue c' as 'a += (b rescue c)'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/retry_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,3 @@
+fails:The retry statement re-executes the closest block
+fails:The retry statement raises a SyntaxError when used outside of a begin statement
+fails:The retry keyword inside a begin block's rescue block causes the begin block to be executed again
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/return_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,3 @@
+fails:The return keyword in a Thread raises a LocalJumpError if used to exit a thread
+fails:The return keyword when passed a splat calls 'to_a' on the splatted value first
+fails:The return keyword within define_method stops at the method when the return is used directly
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/send_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,57 @@
+fails:Invoking a method with a block makes it available to yield
+fails:Invoking a method with a block converts the block to a Proc
+fails:Invoking a method with an object as a block uses 'to_proc' for coercion
+fails:Invoking a method raises a SyntaxError with both a literal block and an object as block
+fails:Invoking a method with splat operator makes the object the direct arguments
+fails:Invoking a method without parentheses works
+fails:Invoking a method with a space separating method name and parenthesis treats expression in parenthesis as first argument
+fails:Invoking a method passes literal hashes without curly braces as the last parameter
+fails:Invoking a method passes a literal hash without curly braces or parens
+fails:Invoking a method allows to literal hashes without curly braces as the only parameter
+fails:Invoking a method with zero arguments requires no arguments passed
+fails:Invoking a method with zero arguments raises ArgumentError if the method has a positive arity
+fails:Invoking a method with only manditory arguments requires exactly the same number of passed values
+fails:Invoking a method with only manditory arguments raises ArgumentError if the methods arity doesn't match
+fails:Invoking a method with optional arguments uses the optional argument if none is is passed
+fails:Invoking a method with optional arguments uses the passed argument if available
+fails:Invoking a method with optional arguments raises ArgumentError if extra arguments are passed
+fails:Invoking a method with manditory and optional arguments uses the passed values in left to right order
+fails:Invoking a method with manditory and optional arguments raises an ArgumentError if there are no values for the manditory args
+fails:Invoking a method with manditory and optional arguments raises an ArgumentError if too many values are passed
+fails:Invoking a method with a rest argument is an empty array if there are no additional arguments
+fails:Invoking a method with a rest argument gathers unused arguments
+fails:Invoking a method when the method is not available invokes method_missing
+fails:Invoking a private getter method does not permit self as a receiver
+fails:Invoking a method with .() invokes #call
+fails:Invoking a method allows a vestigial trailing ',' in the arguments
+fails:Invoking a method with splat operator attempts to coerce it to an Array if the object respond_to?(:to_a)
+fails:Invoking a method with splat operator * and non-Array value uses value unchanged if it does not respond_to?(:to_ary)
+fails:Invoking a method accepts additional arguments after splat expansion
+fails:Invoking a method does not expand final array arguments after a splat expansion
+fails:Invoking a method accepts final explicit literal Hash arguments after the splat
+fails:Invoking a method accepts final implicit literal Hash arguments after the splat
+fails:Invoking a method accepts final Hash arguments after the splat
+fails:Invoking a method accepts mandatory and explicit literal Hash arguments after the splat
+fails:Invoking a method accepts mandatory and implicit literal Hash arguments after the splat
+fails:Invoking a method accepts mandatory and Hash arguments after the splat
+fails:Invoking a method converts a final splatted explicit Hash to an Array
+fails:Invoking a method calls #to_a to convert a final splatted Hash object to an Array
+fails:Invoking a method accepts multiple splat expansions in the same argument list
+fails:Invoking a method expands an array to arguments grouped in parentheses
+fails:Invoking a method expands an array to arguments grouped in parentheses and ignores any rest arguments in the array
+fails:Invoking a method expands an array to arguments grouped in parentheses and sets not specified arguments to nil
+fails:Invoking a method expands an array to arguments grouped in parentheses which in turn takes rest arguments
+fails:Invoking a method with required args after the rest arguments binds the required arguments first
+fails:Invoking a method with manditory arguments after optional arguments binds the required arguments first
+fails:Invoking a method new-style hash arguments as the only parameter passes without curly braces
+fails:Invoking a method new-style hash arguments as the only parameter passes without curly braces or parens
+fails:Invoking a method new-style hash arguments as the only parameter handles a hanging comma without curly braces
+fails:Invoking a method new-style hash arguments as the last parameter passes without curly braces
+fails:Invoking a method new-style hash arguments as the last parameter passes without curly braces or parens
+fails:Invoking a method new-style hash arguments as the last parameter handles a hanging comma without curly braces
+fails:Invoking a method mixed new- and old-style hash arguments as the only parameter passes without curly braces
+fails:Invoking a method mixed new- and old-style hash arguments as the only parameter passes without curly braces or parens
+fails:Invoking a method mixed new- and old-style hash arguments as the only parameter handles a hanging comma without curly braces
+fails:Invoking a method mixed new- and old-style hash arguments as the last parameter passes without curly braces
+fails:Invoking a method mixed new- and old-style hash arguments as the last parameter passes without curly braces or parens
+fails:Invoking a method mixed new- and old-style hash arguments as the last parameter handles a hanging comma without curly braces
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/singleton_class_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,51 @@
+fails:A singleton class doesn't have singleton class
+fails:A singleton class is TrueClass for true
+fails:A singleton class is FalseClass for false
+fails:A singleton class is NilClass for nil
+fails:A singleton class raises a TypeError for Fixnum's
+fails:A singleton class raises a TypeError for symbols
+fails:A singleton class is a singleton Class instance
+fails:A singleton class is a Class for classes
+fails:A singleton class inherits from Class for classes
+fails:A singleton class is a subclass of Class's singleton class
+fails:A singleton class is a subclass of the same level of Class's singleton class
+fails:A singleton class is a subclass of a superclass's singleton class
+fails:A singleton class is a subclass of the same level of superclass's singleton class
+fails:A singleton class for BasicObject has Class as it's superclass
+fails:A singleton class for BasicObject has the proper level of superclass for Class
+fails:A singleton class has class String as the superclass of a String instance
+fails:A singleton class has class Bignum as the superclass of a Bignum instance
+fails:A constant on a singleton class can be accessed after the singleton class body is reopened
+fails:A constant on a singleton class can be accessed via self::CONST
+fails:A constant on a singleton class can be accessed via const_get
+fails:A constant on a singleton class is not defined on the object's class
+fails:A constant on a singleton class is not defined in the singleton class opener's scope
+fails:A constant on a singleton class cannot be accessed via object::CONST
+fails:A constant on a singleton class raises a NameError for anonymous_module::CONST
+fails:A constant on a singleton class appears in the singleton class constant list
+fails:A constant on a singleton class does not appear in the object's class constant list
+fails:A constant on a singleton class is not preserved when the object is duped
+fails:A constant on a singleton class is preserved when the object is cloned
+fails:Defining instance methods on a singleton class define public methods
+fails:Instance methods of a singleton class include ones of the object's class
+fails:Instance methods of a singleton class do not include class methods of the object's class
+fails:Instance methods of a singleton class include instance methods of Object
+fails:Instance methods of a singleton class do not include class methods of Object
+fails:Instance methods of a singleton class for a class include instance methods of Class
+fails:Instance methods of a singleton class for a class do not include class methods of Class
+fails:Instance methods of a singleton class for a class do not include instance methods of the singleton class of Class
+fails:Instance methods of a singleton class for a class do not include class methods of the singleton class of Class
+fails:Instance methods of a singleton class for a singleton class includes instance methods of the singleton class of Class
+fails:Instance methods of a singleton class for a singleton class does not include class methods of the singleton class of Class
+fails:Class methods of a singleton class include ones of the object's class
+fails:Class methods of a singleton class do not include instance methods of the object's class
+fails:Class methods of a singleton class include instance methods of Class
+fails:Class methods of a singleton class do not include class methods of Class
+fails:Class methods of a singleton class for a class include instance methods of Class
+fails:Class methods of a singleton class for a class include class methods of Class
+fails:Class methods of a singleton class for a class include instance methods of the singleton class of Class
+fails:Class methods of a singleton class for a class do not include class methods of the singleton class of Class
+fails:Class methods of a singleton class for a singleton class include instance methods of the singleton class of Class
+fails:Class methods of a singleton class for a singleton class include class methods of the singleton class of Class
+fails:Instantiating a singleton class raises a TypeError when new is called
+fails:Instantiating a singleton class raises a TypeError when allocate is called
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/splat_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,2 @@
+fails:Splat operator used to assign a splatted object to an object assigns the returned value of to_a when the splatted object responds to to_a
+fails:Splat operator used to assign a splatted object to an object assigns the object in a new array when it responds to to_a but to_a returns nil
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/string_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,15 @@
+fails:Ruby character strings taints the result of interpolation when an interpolated value is tainted
+fails:Ruby character strings untrusts the result of interpolation when an interpolated value is untrusted
+fails:Ruby character strings call #to_s when the object is not a String
+fails:Ruby character strings call #to_s as a private method
+fails:Ruby character strings uses an internal representation when #to_s doesn't return a String
+fails:Ruby character strings Unicode escaping can be done with \u and four hex digits
+fails:Ruby character strings Unicode escaping can be done with \u{} and one to six hex digits
+fails:Ruby character strings Unicode escaping with US-ASCII source encoding produces an ASCII string when escaping ASCII characters via \u
+fails:Ruby character strings Unicode escaping with US-ASCII source encoding produces an ASCII string when escaping ASCII characters via \u{}
+Ruby character strings Unicode escaping with US-ASCII source encoding produces a UTF-8-encoded string when escaping non-ASCII fails:characters via \u
+fails:Ruby character strings Unicode escaping with US-ASCII source encoding produces a UTF-8-encoded string when escaping non-ASCII characters via \u{}
+fails:Ruby String interpolation creates a String having an Encoding compatible with all components
+fails:Ruby String interpolation creates a String having the Encoding of the components when all are the same Encoding
+fails:Ruby String interpolation raises an Encoding::CompatibilityError if the Encodings are not compatible
+fails:Ruby character strings Unicode escaping with US-ASCII source encoding produces a UTF-8-encoded string when escaping non-ASCII characters via \u
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/super_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,14 @@
+fails:The super keyword searches class methods
+fails:The super keyword searches class methods including modules
+fails:The super keyword calls the correct method when the method visibility is modified
+fails:The super keyword raises an error error when super method does not exist
+fails:The super keyword calls the superclass method when in a block
+fails:The super keyword calls the superclass method when initial method is defined_method'd
+fails:The super keyword can call through a define_method multiple times (caching check)
+fails:The super keyword supers up appropriate name even if used for multiple method names
+fails:The super keyword can be used with implicit arguments from a method defined with define_method
+fails:The super keyword respects the original module a method is aliased from
+fails:The super keyword passes along modified rest args when they weren't originally empty
+fails:The super keyword passes along modified rest args when they were originally empty
+fails:The super keyword sees the included version of a module a method is alias from
+fails:The super keyword can't be used with implicit arguments from a method defined with define_method
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/symbol_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,7 @@
+fails:A Symbol literal is a ':' followed by any number of valid characters
+fails:A Symbol literal is a ':' followed by a single- or double-quoted string that may contain otherwise invalid characters
+fails:A Symbol literal is converted to a literal, unquoted representation if the symbol contains only valid characters
+fails:A Symbol literal can be created by the %s-delimited expression
+fails:A Symbol literal is the same object when created from identical strings
+fails:A Symbol literal can contain null in the string
+fails:A Symbol literal can be an empty string
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/throw_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,3 @@
+fails:The throw keyword does not convert strings to a symbol
+fails:The throw keyword raises an ArgumentError if outside of scope of a matching catch
+fails:The throw keyword raises a ArgumentError if used to exit a thread
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/undef_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,1 @@
+fails:The undef keyword undefines 'meth='
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/until_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,4 @@
+fails:The until modifier with begin .. end block runs block at least once (even if the expression is true)
+fails:The until modifier with begin .. end block evaluates condition after block execution
+fails:The until modifier with begin .. end block skips to end of body with next
+fails:The until modifier with begin .. end block restart the current iteration without reevaluting condition with redo
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/variables_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,29 @@
+fails:Basic assignment calls to_a on the given argument when using a splat
+fails:Basic assignment allows assignment through lambda
+fails:Basic multiple assignment with a single RHS value does not call #to_ary on an Array subclass instance
+fails:Basic multiple assignment with a single RHS value does not call #to_a on an Array subclass instance
+fails:Basic multiple assignment with a single RHS value calls #to_ary on an object
+fails:Basic multiple assignment with a splatted single RHS value does not call #to_ary on an Array subclass instance
+fails:Basic multiple assignment with a splatted single RHS value does not call #to_a on an Array subclass instance
+fails:Basic multiple assignment with a splatted single RHS value calls #to_a on an object if #to_ary is not defined
+fails:Assigning multiple values calls #to_ary on RHS arg if the corresponding LHS var is a splat
+fails:Assigning multiple values allows complex parallel assignment
+fails:Unconditional operator assignment 'var op= expr' is equivalent to 'var = var op expr'
+fails:Unconditional operator assignment 'obj.meth op= expr' is equivalent to 'obj.meth = obj.meth op expr'
+fails:Conditional operator assignment 'obj.meth op= expr' is equivalent to 'obj.meth op obj.meth = expr'
+fails:Conditional operator assignment 'obj.meth op= expr' may not assign at all, depending on the truthiness of lhs
+fails:Operator assignment 'obj.meth op= expr' evaluates lhs one time
+fails:Unconditional operator assignment 'obj[idx] op= expr' is equivalent to 'obj[idx] = obj[idx] op expr'
+fails:Conditional operator assignment 'obj[idx] op= expr' may not assign at all, depending on the truthiness of lhs
+fails:Operator assignment 'obj[idx] op= expr' handles empty index (idx) arguments
+fails:Operator assignment 'obj[idx] op= expr' handles complex index (idx) arguments
+fails:Operator assignment 'obj[idx] op= expr' handles empty splat index (idx) arguments
+fails:Operator assignment 'obj[idx] op= expr' handles single splat index (idx) arguments
+fails:Operator assignment 'obj[idx] op= expr' handles multiple splat index (idx) arguments
+fails:Operator assignment 'obj[idx] op= expr' handles splat index (idx) arguments with normal arguments
+fails:Operator assignment 'obj[idx] op= expr' returns result of rhs not result of []=
+fails:Multiple assignments with grouping A group on the lhs is considered one position and treats its corresponding rhs position like an Array
+fails:Multiple assignments with grouping supports multiple levels of nested groupings
+fails:Multiple assignment has the proper return value
+fails:Multiple assignment, array-style returns an array of all rhs values
+fails:Multiple assignments with splats * on the LHS has to be applied to any parameter
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/while_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,4 @@
+fails:The while modifier with begin .. end block runs block at least once (even if the expression is false)
+fails:The while modifier with begin .. end block evaluates condition after block execution
+fails:The while modifier with begin .. end block skips to end of body with next
+fails:The while modifier with begin .. end block restarts the current iteration without reevaluting condition with redo
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/specs/tags/language/yield_tags.txt	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,21 @@
+fails:The yield call taking no arguments raises a LocalJumpError when the method is not passed a block
+fails:The yield call taking no arguments ignores assignment to the explicit block argument and calls the passed block
+fails:The yield call taking a single argument raises a LocalJumpError when the method is not passed a block
+fails:The yield call taking a single argument passes an empty Array when the argument is an empty Array
+fails:The yield call taking a single argument passes nil as a value
+fails:The yield call taking a single argument passes a single value
+fails:The yield call taking a single argument passes a single, multi-value Array
+fails:The yield call taking multiple arguments raises a LocalJumpError when the method is not passed a block
+fails:The yield call taking multiple arguments passes the arguments to the block
+fails:The yield call taking a single splatted argument raises a LocalJumpError when the method is not passed a block
+fails:The yield call taking a single splatted argument passes a single value
+fails:The yield call taking a single splatted argument passes no arguments when the argument is an empty Array
+fails:The yield call taking a single splatted argument passes the value when the argument is an Array containing a single value
+fails:The yield call taking a single splatted argument passes the values of the Array as individual arguments
+fails:The yield call taking a single splatted argument passes the element of a single element Array
+fails:The yield call taking a single splatted argument passes no values when give nil as an argument
+fails:The yield call taking multiple arguments with a splat raises a LocalJumpError when the method is not passed a block
+fails:The yield call taking multiple arguments with a splat passes the arguments to the block
+fails:The yield call taking multiple arguments with a splat does not pass an argument value if the splatted argument is an empty Array
+fails:The yield call taking multiple arguments with a splat passes the Array elements as arguments if the splatted argument is a non-empty Array
+fails:The yield call taking multiple arguments with a splat does not pass an argument value if the splatted argument is nil
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/RubyTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test;
+
+import static org.junit.Assert.*;
+
+import java.io.*;
+import java.util.*;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.ruby.nodes.core.*;
+import com.oracle.truffle.ruby.parser.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.configuration.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+
+/**
+ * Base class for Ruby tests.
+ */
+public class RubyTests {
+
+    @BeforeClass
+    public static void applyDefaultLocale() {
+        // Avoid printing comparison issues
+        Locale.setDefault(Locale.ENGLISH);
+    }
+
+    /**
+     * Executes some Ruby code and asserts that it prints an expected string. Remember to include
+     * the newline characters.
+     */
+    public static void assertPrints(String expectedOutput, String code, String... args) {
+        assertPrintsWithInput(expectedOutput, code, "", args);
+    }
+
+    /**
+     * Executes some Ruby code and asserts that it prints an expected string. Remember to include
+     * the newline characters. Allows input for {@code Kernel#gets} to be passed in.
+     */
+    public static void assertPrintsWithInput(String expectedOutput, String code, String input, String... args) {
+        assertPrints(null, expectedOutput, "(test)", code, input, args);
+    }
+
+    /**
+     * Executes some Ruby code of a particular version and asserts that it prints an expected
+     * string. Remember to include the newline characters.
+     */
+    public static void assertPrints(RubyVersion rubyVersion, String expectedOutput, String code, String... args) {
+        ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
+        configurationBuilder.setRubyVersion(rubyVersion);
+        assertPrints(new Configuration(configurationBuilder), expectedOutput, "(test)", code, "", args);
+    }
+
+    /**
+     * Executes some Ruby code in a file and asserts that it prints an expected string. Remember to
+     * include the newline characters.
+     */
+    public static void assertFilePrints(String expectedOutput, String fileName, String... args) {
+        assertPrints(null, expectedOutput, fileName, null, "", args);
+    }
+
+    /**
+     * Executes some Ruby code and asserts that it prints an expected string. Remember to include
+     * the newline characters. Also takes a string to simulate input.
+     */
+    public static void assertPrints(Configuration configuration, String expectedOutput, String fileName, String code, String input, String... args) {
+        final ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
+        final PrintStream printStream = new PrintStream(byteArray);
+
+        ConfigurationBuilder configurationBuilder;
+
+        if (configuration == null) {
+            configurationBuilder = new ConfigurationBuilder();
+        } else {
+            configurationBuilder = new ConfigurationBuilder(configuration);
+        }
+
+        configurationBuilder.setStandardOut(printStream);
+
+        final BufferedReader inputReader = new BufferedReader(new StringReader(input));
+
+        configurationBuilder.setInputReader(new InputReader() {
+
+            @Override
+            public String readLine(String prompt) throws IOException {
+                return inputReader.readLine();
+            }
+
+        });
+
+        final RubyContext context = new RubyContext(new Configuration(configurationBuilder), new JRubyParser());
+
+        CoreMethodNodeManager.addMethods(context.getCoreLibrary().getObjectClass());
+        context.getCoreLibrary().initializeAfterMethodsAdded();
+
+        for (String arg : args) {
+            context.getCoreLibrary().getArgv().push(new RubyString(context.getCoreLibrary().getStringClass(), arg));
+        }
+
+        final Source source = context.getSourceManager().getFakeFile(fileName, code);
+
+        context.execute(context, source, RubyParser.ParserContext.TOP_LEVEL, context.getCoreLibrary().getMainObject(), null);
+        context.shutdown();
+
+        assertEquals(expectedOutput, byteArray.toString().replaceAll("\r\n", "\n"));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/ArrayTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.core;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test the {@code Array} class.
+ */
+public class ArrayTests extends RubyTests {
+
+    @Test
+    public void testLiteral() {
+        assertPrints("", "puts []");
+        assertPrints("1\n", "puts [1]");
+        assertPrints("1\n2\n", "puts [1, 2]");
+        assertPrints("1\n2\n3\n", "puts [1, 2, 3]");
+        assertPrints("1\n2\n3\n", "puts [(1), 2, ((3))]");
+    }
+
+    @Test
+    public void testReadIndexSimple() {
+        assertPrints("2\n", "puts [1, 2, 3][1]");
+        assertPrints("2\n", "x = [1, 2, 3]; puts x[1]");
+        assertPrints("\n", "puts [1, 2, 3][10]");
+    }
+
+    @Test
+    public void testReadIndexRange() {
+        assertPrints("2\n3\n", "puts [1, 2, 3][1..2]");
+        assertPrints("2\n3\n", "puts [1, 2, 3][1..-1]");
+        assertPrints("1\n2\n3\n", "puts [1, 2, 3][0..-1]");
+    }
+
+    @Test
+    public void testWriteIndexSimple() {
+        assertPrints("1\n0\n3\n", "x = [1, 2, 3]; x[1] = 0; puts x");
+        assertPrints("0\n", "x = [1, 2, 3]; puts x[1] = 0");
+        assertPrints("1\n\n3\n", "x = [1]; x[2] = 3; puts x");
+    }
+
+    @Test
+    public void testWriteIndexRangeSingle() {
+        assertPrints("1\n0\n", "x = [1, 2, 3]; x[1..2] = 0; puts x");
+        assertPrints("1\n0\n", "x = [1, 2, 3]; x[1..3] = 0; puts x");
+        assertPrints("1\n0\n", "x = [1, 2, 3]; x[1..-1] = 0; puts x");
+        assertPrints("0\n", "x = [1, 2, 3]; x[0..-1] = 0; puts x");
+    }
+
+    @Test
+    public void testWriteIndexRangeArray() {
+        assertPrints("1\n4\n5\n", "x = [1, 2, 3]; x[1..2] = [4, 5]; puts x");
+        assertPrints("1\n4\n5\n", "x = [1, 2, 3]; x[1..-1] = [4, 5]; puts x");
+        assertPrints("4\n5\n6\n", "x = [1, 2, 3]; x[0..-1] = [4, 5, 6]; puts x");
+    }
+
+    @Test
+    public void testInsert() {
+        assertPrints("1\n2\n3\n", "x = [1, 2]; x.insert(2, 3); puts x");
+        assertPrints("1\n2\n3\n", "x = [1, 3]; x.insert(1, 2); puts x");
+        assertPrints("1\n\n3\n", "x = [1]; x.insert(2, 3); puts x");
+    }
+
+    @Test
+    public void testPush() {
+        assertPrints("1\n2\n3\n", "x = [1, 2]; x.push(3); puts x");
+        assertPrints("1\n2\n3\n", "x = [1, 2]; x << 3; puts x");
+        assertPrints("1\n2\n3\n4\n", "x = [1, 2]; x << 3 << 4; puts x");
+    }
+
+    @Test
+    public void testDeleteAt() {
+        assertPrints("1\n3\n", "x = [1, 2, 3]; x.delete_at(1); puts x");
+    }
+
+    @Test
+    public void testDup() {
+        assertPrints("1\n2\n3\n", "x = [1, 2, 3]; y = x.dup; x.delete_at(1); puts y;");
+    }
+
+    @Test
+    public void testOpAssign() {
+        assertPrints("1\n", "x = [0]; x[0] += 1; puts x");
+    }
+
+    @Test
+    public void testSize() {
+        assertPrints("0\n", "puts [].size");
+        assertPrints("1\n", "puts [1].size");
+        assertPrints("2\n", "puts [1, 2].size");
+    }
+
+    @Test
+    public void testEach() {
+        assertPrints("", "[].each { |n| puts n }");
+        assertPrints("1\n", "[1].each { |n| puts n }");
+        assertPrints("1\n2\n3\n", "[1, 2, 3].each { |n| puts n }");
+    }
+
+    @Test
+    public void testMap() {
+        assertPrints("2\n4\n6\n", "puts [1, 2, 3].map { |n| n*2 }");
+    }
+
+    @Test
+    public void testZip() {
+        assertPrints("1\n4\n2\n5\n3\n6\n", "puts [1, 2, 3].zip([4, 5, 6])");
+        assertPrints("1\n4\n2\n5\n", "puts [1, 2].zip([4, 5, 6])");
+        assertPrints("1\n4\n2\n5\n3\n\n", "puts [1, 2, 3].zip([4, 5])");
+        assertPrints("1\n3\n5\n2\n4\n6\n", "puts [1, 2].zip([3, 4], [5, 6])");
+    }
+
+    @Test
+    public void testProduct() {
+        assertPrints("[[1, 3], [1, 4], [2, 3], [2, 4]]\n", "puts [1, 2].product([3, 4]).to_s");
+    }
+
+    @Test
+    public void testInject() {
+        assertPrints("10\n", "puts [2, 3, 4].inject(1) { |a, n| a + n }");
+    }
+
+    @Test
+    public void testLiteralSplat() {
+        assertPrints("[1, 2, 3, 4]\n", "a = [3, 4]; puts [1, 2, *a].to_s");
+        assertPrints("[1, 2, 3, 4, 5, 6]\n", "a = [3, 4]; puts [1, 2, *a, 5, 6].to_s");
+    }
+
+    @Test
+    public void testSplatCast() {
+        assertPrints("[14]\n", "def foo; value = 14; return *value; end; puts foo.to_s");
+    }
+
+    @Test
+    public void testSelect() {
+        assertPrints("[3, 4]\n", "foo = [1, 2, 3, 4]; bar = foo.select { |x| x > 2 }; puts bar.to_s");
+    }
+
+    @Test
+    public void testInclude() {
+        assertPrints("true\nfalse\n", "foo = [1, 2, 3, 4]; puts foo.include? 2; puts foo.include? 5");
+    }
+
+    @Test
+    public void testSub() {
+        assertPrints("[1, 4]\n", "puts ([1, 2, 2, 3, 4] - [2, 3]).to_s");
+    }
+
+    @Test
+    public void testJoin() {
+        assertPrints("1.2.3\n", "puts [1, 2, 3].join('.')");
+    }
+
+    @Test
+    public void testShift() {
+        assertPrints("1\n2\n3\n", "a = [1, 2, 3]; while b = a.shift; puts b; end");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/BignumTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.core;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test the {@code Bignum} class.
+ */
+public class BignumTests extends RubyTests {
+
+    @Test
+    public void testImmediate() {
+        assertPrints("123456789123456789\n", "puts 123456789123456789");
+        assertPrints("574658776654483828\n", "puts 574658776654483828");
+    }
+
+    @Test
+    public void testAddImmediate() {
+        assertPrints("821572354901397406\n", "puts 123456789123456789+698115565777940617");
+        assertPrints("7675735362615108\n", "puts 867676857675 + 7674867685757433");
+        assertPrints("8792416214481\n", "puts 8785647643454 + (6768571027)");
+        assertPrints("8089240320234\n", "puts (7132953783486) + ((956286536748))");
+    }
+
+    @Test
+    public void testSubImmediate() {
+        assertPrints("574658776654483828\n", "puts 698115565777940617-123456789123456789");
+        assertPrints("7674000008899758\n", "puts 7674867685757433 - 867676857675");
+        assertPrints("8778879072427\n", "puts 8785647643454 - (6768571027)");
+        assertPrints("6176667246738\n", "puts (7132953783486) - ((956286536748))");
+    }
+
+    @Test
+    public void testLessImmediate() {
+        assertPrints("false\n", "puts 698115565777940617 < 123456789123456789");
+        assertPrints("true\n", "puts 867676857675 < 7674867685757433");
+        assertPrints("false\n", "puts 8785647643454 < (6768571027)");
+        assertPrints("true\n", "puts (956286536748) < ((7132953783486))");
+    }
+
+    @Test
+    public void testDivmod() {
+        assertPrints("100\n2342\n", "puts 1000000000000000000000002342.divmod(10000000000000000000000000)");
+        assertPrints("Fixnum\n", "puts 1000000000000000000000002342.divmod(10000000000000000000000000)[0].class");
+        assertPrints("Fixnum\n", "puts 1000000000000000000000002342.divmod(10000000000000000000000000)[1].class");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/BoolTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.core;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test {@code true} and {@code false}. Note that there is no {@code Bool} class or type. There is
+ * {@code TrueClass}, {@code FalseClass}, and instances of them {@code true} and {@code false}.
+ */
+public class BoolTests extends RubyTests {
+
+    @Test
+    public void testImmediate() {
+        assertPrints("true\n", "puts true");
+        assertPrints("false\n", "puts false");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/ContinuationTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.core;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.runtime.configuration.*;
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test the {@code Continuation} class.
+ */
+public class ContinuationTests extends RubyTests {
+
+    @Test
+    public void testRequired18() {
+        assertPrints(RubyVersion.RUBY_18, "", "callcc { |c| c.call }");
+    }
+
+    @Test
+    public void testRequired19() {
+        assertPrints(RubyVersion.RUBY_19, "", "require \"continuation\"; callcc { |c| c.call }");
+    }
+
+    @Test
+    public void testRequired20() {
+        assertPrints(RubyVersion.RUBY_20, "", "require \"continuation\"; callcc { |c| c.call }");
+    }
+
+    @Test
+    public void testOneShotGoingUpCallstack() {
+        assertPrints(RubyVersion.RUBY_18, "1\n3\n", "callcc { |c| puts 1; c.call; puts 2 }; puts 3");
+    }
+
+    @Test
+    public void testOneShotGoingUpCallstackReturnValue() {
+        assertPrints(RubyVersion.RUBY_18, "14\n", "puts callcc { |c| c.call 14 }");
+    }
+
+    @Test
+    public void testNestedOneShotGoingUpCallstack() {
+        assertPrints(RubyVersion.RUBY_18, "1\n2\n4\n5\n", "callcc { |c1| puts 1; callcc { |c2| puts 2; c2.call; puts 3 }; puts 4 }; puts 5");
+        assertPrints(RubyVersion.RUBY_18, "1\n2\n5\n", "callcc { |c1| puts 1; callcc { |c2| puts 2; c1.call; puts 3 }; puts 4 }; puts 5");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/FiberTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.core;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test the {@code Fiber} class.
+ */
+public class FiberTests extends RubyTests {
+
+    @Test
+    public void testResume() {
+        assertPrints("14\n", "f = Fiber.new { |x| puts x }; f.resume 14");
+    }
+
+    @Test
+    public void testYield() {
+        assertPrints("14\n", "f = Fiber.new { |x| Fiber.yield x }; puts f.resume(14)");
+    }
+
+    @Test
+    public void testCountdown() {
+        assertPrints("", "f = Fiber.new do |n|\n" + //
+                        "    loop do\n" + //
+                        "        n = Fiber.yield n - 1\n" + //
+                        "    end\n" + //
+                        "end\n" + //
+                        "\n" + //
+                        "n = 1000\n" + //
+                        "\n" + //
+                        "while n > 0\n" + //
+                        "    n = f.resume n\n" + //
+                        "end\n");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/FixnumTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.core;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test the {@code Fixnum} class.
+ */
+public class FixnumTests extends RubyTests {
+
+    @Test
+    public void testImmediate() {
+        assertPrints("2\n", "puts 2");
+        assertPrints("14\n", "puts 14");
+        assertPrints("-14\n", "puts -14");
+    }
+
+    @Test
+    public void testNegate() {
+        assertPrints("-1\n", "x = 1; puts -x");
+        assertPrints("1\n", "x = -1; puts -x");
+    }
+
+    @Test
+    public void testAddImmediate() {
+        assertPrints("16\n", "puts 14+2");
+        assertPrints("14\n", "puts 12 + 2");
+        assertPrints("17\n", "puts 9 + (8)");
+        assertPrints("10\n", "puts (6) + ((4))");
+    }
+
+    @Test
+    public void testSubImmediate() {
+        assertPrints("12\n", "puts 14-2");
+        assertPrints("10\n", "puts 12 - 2");
+        assertPrints("1\n", "puts 9 - (8)");
+        assertPrints("2\n", "puts (6) - ((4))");
+    }
+
+    @Test
+    public void testMulImmediate() {
+        assertPrints("28\n", "puts 14 * 2");
+        assertPrints("20\n", "puts 2 * 10");
+        assertPrints("72\n", "puts 9 * (8)");
+        assertPrints("24\n", "puts (4) * ((6))");
+    }
+
+    @Test
+    public void testDivImmediate() {
+        assertPrints("7\n", "puts 14 / 2");
+        assertPrints("0\n", "puts 2 / 10");
+        assertPrints("1\n", "puts 9 / (8)");
+        assertPrints("0\n", "puts (4) / ((6))");
+    }
+
+    @Test
+    public void testEqualImmediate() {
+        assertPrints("true\n", "puts 14 == 14");
+        assertPrints("true\n", "puts 2 == 2");
+        assertPrints("false\n", "puts 9 == (8)");
+        assertPrints("false\n", "puts (4) == ((6))");
+    }
+
+    @Test
+    public void testNotEqualImmediate() {
+        assertPrints("false\n", "puts 14 != 14");
+        assertPrints("false\n", "puts 2 != 2");
+        assertPrints("true\n", "puts 9 != (8)");
+        assertPrints("true\n", "puts (4) != ((6))");
+    }
+
+    @Test
+    public void testLessImmediate() {
+        assertPrints("false\n", "puts 14 < 2");
+        assertPrints("true\n", "puts 2 < 10");
+        assertPrints("false\n", "puts 9 < (8)");
+        assertPrints("true\n", "puts (4) < ((6))");
+    }
+
+    @Test
+    public void testGreaterEqualImmediate() {
+        assertPrints("true\n", "puts 14 >= 14");
+        assertPrints("true\n", "puts 14 >= 2");
+        assertPrints("false\n", "puts 2 >= 10");
+        assertPrints("true\n", "puts 9 >= (8)");
+        assertPrints("false\n", "puts (4) >= ((6))");
+    }
+
+    @Test
+    public void testLeftShift() {
+        assertPrints("0\n", "puts 0 << 0");
+        assertPrints("0\n", "puts 0 << 1");
+        assertPrints("1\n", "puts 1 << 0");
+        assertPrints("0\n", "puts 1 << -1");
+        assertPrints("0\n", "puts 1 << -2");
+        assertPrints("28\n", "puts 14 << 1");
+        assertPrints("7\n", "puts 14 << -1");
+        assertPrints("4294967296\n", "puts 1 << 32");
+        assertPrints("340282366920938463463374607431768211456\n", "puts 1 << 128");
+        assertPrints("0\n", "puts 1 << -32");
+        assertPrints("Fixnum\n", "puts (14 << 1).class");
+        assertPrints("Bignum\n", "puts (1 << 32).class");
+    }
+
+    @Test
+    public void testDivmod() {
+        // @formatter:off
+        final int[][] tests = new int[][]{
+                        new int[]{13,   4,  3,  1},
+                        new int[]{13,  -4, -4, -3},
+                        new int[]{-13,  4, -4,  3},
+                        new int[]{-13, -4,  3, -1}};
+        // @formatter:on
+
+        for (int[] test : tests) {
+            final int a = test[0];
+            final int b = test[1];
+            final int q = test[2];
+            final int r = test[3];
+            assertPrints(String.format("%d\n%d\n", q, r), String.format("puts %d.divmod(%d)", a, b));
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/FloatTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.core;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test the {@code Float} class.
+ */
+public class FloatTests extends RubyTests {
+
+    @Test
+    public void testImmediate() {
+        assertPrints("2.5\n", "puts 2.5");
+        assertPrints("14.33\n", "puts 14.33");
+    }
+
+    @Test
+    public void testAddImmediate() {
+        assertPrints("16.2\n", "puts 14.1+2.1");
+        assertPrints("14.2\n", "puts 12.1 + 2.1");
+        assertPrints("17.2\n", "puts 9.1 + (8.1)");
+        assertPrints("10.2\n", "puts (6.1) + ((4.1))");
+    }
+
+    @Test
+    public void testSubImmediate() {
+        assertPrints("12.1\n", "puts 14.2-2.1");
+        assertPrints("10.1\n", "puts 12.2 - 2.1");
+        assertPrints("1.0999999999999996\n", "puts 9.2 - (8.1)");
+        assertPrints("2.1000000000000005\n", "puts (6.2) - ((4.1))");
+    }
+
+    @Test
+    public void testMulImmediate() {
+        assertPrints("29.82\n", "puts 14.2*2.1");
+        assertPrints("25.62\n", "puts 12.2 * 2.1");
+        assertPrints("74.52\n", "puts 9.2 * (8.1)");
+        assertPrints("25.419999999999998\n", "puts (6.2) * ((4.1))");
+        assertPrints("7.5\n", "puts 2.5 * 3");
+        assertPrints("7.5\n", "puts 3 * 2.5");
+    }
+
+    @Test
+    public void testDivImmediate() {
+        assertPrints("6.761904761904761\n", "puts 14.2/2.1");
+        assertPrints("5.809523809523809\n", "puts 12.2 / 2.1");
+        assertPrints("1.1358024691358024\n", "puts 9.2 / (8.1)");
+        assertPrints("1.5121951219512197\n", "puts (6.2) / ((4.1))");
+        assertPrints("0.8333333333333334\n", "puts 2.5 / 3");
+        assertPrints("1.2\n", "puts 3 / 2.5");
+    }
+
+    @Test
+    public void testLessImmediate() {
+        assertPrints("false\n", "puts 14.2<2.2");
+        assertPrints("true\n", "puts 2.2 < 10.2");
+        assertPrints("false\n", "puts 9.2 < (8.2)");
+        assertPrints("true\n", "puts (4.2) < ((6.2))");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/HashTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.core;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test the {@code Hash} class.
+ */
+public class HashTests extends RubyTests {
+
+    @Test
+    public void testLiteral() {
+        assertPrints("Hash\n", "puts ({}).class");
+        assertPrints("Hash\n", "puts ({1 => 2, 3 => 4}).class");
+        assertPrints("Hash\n", "puts ({key1: 2, key3: 4}).class");
+    }
+
+    @Test
+    public void testIndex() {
+        assertPrints("4\n", "foo = {1 => 2, 3 => 4}; puts foo[3]");
+    }
+
+    @Test
+    public void testIndexSet() {
+        assertPrints("6\n", "foo = {1 => 2, 3 => 4}; foo[5] = 6; puts foo[5]");
+    }
+
+    @Test
+    public void testKeys() {
+        assertPrints("[1, 3]\n", "foo = {1 => 2, 3 => 4}; puts foo.keys.to_s");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/IntegerTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.core;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test the {@code Integer} class.
+ */
+public class IntegerTests extends RubyTests {
+
+    @Test
+    public void testTimes() {
+        assertPrints("0\n", "1.times { |i| puts i }");
+        assertPrints("0\n1\n2\n", "3.times { |i| puts i }");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/KernelTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.core;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.runtime.configuration.*;
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test {@code Kernel}.
+ */
+public class KernelTests extends RubyTests {
+
+    @Test
+    public void testPutsEmpty() {
+        assertPrints("\n", "puts");
+    }
+
+    @Test
+    public void testPutsString() {
+        assertPrints("1\n", "puts 1");
+    }
+
+    @Test
+    public void testPrintfNoFormatting() {
+        assertPrints("", "printf");
+        assertPrints("foo", "printf \"foo\"");
+        assertPrints("foo\n", "printf \"foo\\n\"");
+    }
+
+    @Test
+    public void testPrintfDecimal() {
+        assertPrints("foo14bar", "printf \"foo%dbar\", 14");
+    }
+
+    @Test
+    public void testGets() {
+        assertPrintsWithInput("test\n", "puts gets", "test\n");
+    }
+
+    @Test
+    public void testInteger() {
+        assertPrints("14\n", "puts Integer(\"14\")");
+    }
+
+    @Test
+    public void testEval() {
+        assertPrints("16\n", "puts eval(\"14 + 2\")");
+    }
+
+    @Test
+    public void testBindingLocalVariables() {
+        // Use the current binding for eval
+        assertPrints("16\n", "x = 14; y = 2; puts eval(\"x + y\", binding)");
+
+        // Use the binding returned from a method for eval
+        assertPrints("16\n", "def foo; x = 14; y = 2; binding; end; puts eval(\"x + y\", foo)");
+    }
+
+    @Test
+    public void testBindingInstanceVariables() {
+        // Use the binding returned from a method in an object for eval
+        assertPrints("16\n", "class Foo; def foo; @x = 14; @y = 2; binding; end; end; puts eval(\"@x + @y\", Foo.new.foo)");
+    }
+
+    @Test
+    public void testSetTraceFuncLine() {
+        final ConfigurationBuilder configuration = new ConfigurationBuilder();
+        configuration.setTrace(true);
+
+        final String code = "def foo\n" + //
+                        "    a = 14\n" + //
+                        "    b = 2\n" + //
+                        "    a + b\n" + //
+                        "end\n" + //
+                        "\n" + //
+                        "set_trace_func proc { |event, file, line, id, binding, classname|\n" + //
+                        "    if event == \"line\"\n" + //
+                        "        puts file + \":\" + line.to_s\n" + //
+                        "    end\n" + //
+                        "}\n" + //
+                        "\n" + //
+                        "foo";
+        final String input = "";
+        final String expected = "(test):13\n(test):2\n(test):3\n(test):4\n";
+        assertPrints(new Configuration(configuration), expected, "(test)", code, input);
+    }
+
+    @Test
+    public void testBlockGiven() {
+        assertPrints("false\n", "def foo; puts block_given?; end; foo");
+        assertPrints("true\n", "def foo; puts block_given?; end; foo do; end");
+        assertPrints("true\n", "def foo; puts block_given?; end; foo {}");
+        assertPrints("true\n", "def foo; puts block_given?; end; foo &:+");
+    }
+
+    @Test
+    public void testLoop() {
+        assertPrints("14\n", "loop do; break; end; puts 14");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/MathTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.core;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test the {@code Math} class.
+ */
+public class MathTests extends RubyTests {
+
+    @Test
+    public void testPI() {
+        assertPrints("3.141592653589793\n", "puts Math::PI");
+    }
+
+    @Test
+    public void testSqrt() {
+        assertPrints("1.0\n", "puts Math.sqrt(1)");
+        assertPrints("1.0\n", "puts Math::sqrt(1)");
+        assertPrints("3.7416573867739413\n", "puts Math::sqrt(14)");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/ModuleTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.core;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test the {@code Module} class.
+ */
+public class ModuleTests extends RubyTests {
+
+    @Test
+    public void testAttrAccessor() {
+        assertPrints("14\n", "class Foo; attr_accessor :x end; foo=Foo.new; foo.x=14; puts foo.x");
+        assertPrints("14\n", "class Foo; attr_accessor(:x) end; foo=Foo.new; foo.x=14; puts foo.x");
+        assertPrints("16\n", "class Foo; attr_accessor(:x, :y) end; foo=Foo.new; foo.x=14; foo.y=2; puts foo.x + foo.y");
+        assertPrints("16\n", "class Foo; attr_accessor :x end; foo=Foo.new; foo.x=2; foo.x+=14; puts foo.x");
+    }
+
+    @Test
+    public void testDefineMethod() {
+        /*
+         * We use Object#send instead of calling define_method directly because that method is
+         * private.
+         */
+
+        assertPrints("14\n", "class Foo; end; Foo.send(:define_method, :foo) do; puts 14; end; Foo.new.foo");
+    }
+
+    @Test
+    public void testDefinedBeforeScopeRun() {
+        assertPrints("Module\n", "module Foo; puts Foo.class; end");
+    }
+
+    @Test
+    public void testDefinedInRootScopeBeforeScopeRun() {
+        assertPrints("Module\n", "module Foo; puts ::Foo.class; end");
+    }
+
+    @Test
+    public void testModuleEval() {
+        assertPrints("14\n", "class Foo; puts 14; end; Foo.module_eval('def foo; end'); Foo.new.foo");
+    }
+
+    @Test
+    public void testNextInBlock() {
+        assertPrints("1\n1\n1\n", "3.times do; puts 1; next; puts 2; end");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/ObjectSpaceTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.core;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.runtime.configuration.*;
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test the {@code ObjectSpace} module.
+ */
+public class ObjectSpaceTests extends RubyTests {
+
+    @Test
+    public void testEachObjectClass() {
+        assertPrints("true\n", "found_string = false; ObjectSpace.each_object(Class) { |o| if o == String; found_string = true; end  }; puts found_string");
+    }
+
+    @Test
+    public void testId2RefClass() {
+        assertPrints("true\n", "puts ObjectSpace._id2ref(String.object_id) == String");
+    }
+
+    @Test
+    public void testEachObjectString() {
+        final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
+        configurationBuilder.setFullObjectSpace(true);
+        final String code = "foo = \"foo\"; found_foo = false; ObjectSpace.each_object(String) { |o| if o == foo; found_foo= true; end  }; puts found_foo";
+        final String input = "";
+        final String expected = "true\n";
+        assertPrints(new Configuration(configurationBuilder), expected, "(test)", code, input);
+    }
+
+    @Test
+    public void testId2RefString() {
+        final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
+        configurationBuilder.setFullObjectSpace(true);
+        final String code = "foo = \"foo\"; puts ObjectSpace._id2ref(foo.object_id) == foo";
+        final String input = "";
+        final String expected = "true\n";
+        assertPrints(new Configuration(configurationBuilder), expected, "(test)", code, input);
+    }
+
+    @Test
+    public void testGarbageCollect() {
+        assertPrints("", "ObjectSpace.garbage_collect");
+        assertPrints("", "ObjectSpace.start");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/ObjectTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.core;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test the {@code Object} class.
+ */
+public class ObjectTests extends RubyTests {
+
+    @Test
+    public void testARGV() {
+        assertPrints("1\n2\n3\n", "puts ARGV", "1", "2", "3");
+    }
+
+    @Test
+    public void testInstanceVariableDefined() {
+        assertPrints("true\n", "class Foo; def initialize; @bar=14; end; end; puts Foo.new.instance_variable_defined?(:@bar)");
+        assertPrints("true\n", "class Foo; def initialize; @bar=14; end; end; puts Foo.new.instance_variable_defined?(\"@bar\")");
+        assertPrints("true\n", "class Foo; def initialize; instance_variable_set(:@bar, 14); end; end; puts Foo.new.instance_variable_defined?(\"@bar\")");
+        assertPrints("false\n", "class Foo; def initialize; @foo=14; end; end; puts Foo.new.instance_variable_defined?(:@bar)");
+        assertPrints("false\n", "class Foo; def initialize; @foo=14; end; end; puts Foo.new.instance_variable_defined?(\"@bar\")");
+        assertPrints("false\n", "class Foo; def initialize; instance_variable_set(:@foo, 14); end; end; puts Foo.new.instance_variable_defined?(\"@bar\")");
+    }
+
+    @Test
+    public void testInstanceVariableGet() {
+        assertPrints("14\n", "class Foo; def initialize; @bar=14; end; end; puts Foo.new.instance_variable_get(:@bar)");
+        assertPrints("14\n", "class Foo; def initialize; @bar=14; end; end; puts Foo.new.instance_variable_get(\"@bar\")");
+    }
+
+    @Test
+    public void testInstanceVariableSet() {
+        assertPrints("14\n", "class Foo; attr_accessor :bar; end; foo = Foo.new; foo.instance_variable_set(:@bar, 14); puts foo.bar");
+        assertPrints("14\n", "class Foo; attr_accessor :bar; end; foo = Foo.new; foo.instance_variable_set(\"@bar\", 14); puts foo.bar");
+    }
+
+    @Test
+    public void testInstanceVariables() {
+        assertPrints("a\nb\n", "class Foo; def initialize; @a=2; @b=14; end; end; puts Foo.new.instance_variables");
+        assertPrints("a\nb\n", "class Foo; def initialize; @a=2; instance_variable_set(:@b, 14); end; end; puts Foo.new.instance_variables");
+    }
+
+    @Test
+    public void testSend() {
+        assertPrints("14\n", "self.send(:puts, 14)");
+        assertPrints("14\n", "self.send(\"puts\", 14)");
+    }
+
+    @Test
+    public void testExtend() {
+        assertPrints("14\n", "class Foo; end; module Bar; def bar; puts 14; end; end; foo = Foo.new; foo.extend(Bar); foo.bar");
+    }
+
+    @Test
+    public void testSingletonMethods() {
+        assertPrints("[:baz]\n", "class Foo; def bar; end; end; foo = Foo.new; def foo.baz; end; puts foo.singleton_methods.to_s");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/ProcTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.core;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.runtime.configuration.*;
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test the {@code Proc} class.
+ */
+public class ProcTests extends RubyTests {
+
+    @Test
+    public void testKernelProc() {
+        assertPrints("1\n", "x = proc { puts 1 }; x.call");
+        assertPrints("1\n", "x = proc { 1 }; puts x.call");
+    }
+
+    @Test
+    public void testKernelLambda() {
+        assertPrints("1\n", "x = lambda { puts 1 }; x.call");
+        assertPrints("1\n", "x = lambda { 1 }; puts x.call");
+    }
+
+    @Test
+    public void testKernelProcNew() {
+        assertPrints("1\n", "x = Proc.new { puts 1 }; x.call");
+        assertPrints("1\n", "x = Proc.new { 1 }; puts x.call");
+    }
+
+    @Test
+    public void testProcReturn18() {
+        assertPrints(RubyVersion.RUBY_18, "2\n", "def foo; x = proc { return 1 }; x.call; return 2; end; puts foo");
+    }
+
+    @Test
+    public void testProcReturn19() {
+        assertPrints(RubyVersion.RUBY_19, "1\n", "def foo; x = proc { return 1 }; x.call; return 2; end; puts foo");
+    }
+
+    @Test
+    public void testProcReturn20() {
+        assertPrints(RubyVersion.RUBY_20, "1\n", "def foo; x = proc { return 1 }; x.call; return 2; end; puts foo");
+    }
+
+    @Test
+    public void testLambdaReturn() {
+        assertPrints("2\n", "def foo; x = lambda { return 1 }; x.call; return 2; end; puts foo");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/RangeTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.core;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test the {@code Range} class.
+ */
+public class RangeTests extends RubyTests {
+
+    @Test
+    public void testImmediate() {
+        assertPrints("1..2\n", "puts 1..2");
+        assertPrints("1..2\n", "puts (1..2)");
+        assertPrints("1..2\n", "puts ((1)..2)");
+        assertPrints("1...2\n", "puts 1...2");
+    }
+
+    @Test
+    public void testVariables() {
+        assertPrints("1..2\n", "x = 1; puts x..2");
+        assertPrints("1..2\n", "y = 2; puts 1..y");
+        assertPrints("1..2\n", "x = 1; y = 2; puts x..y");
+    }
+
+    @Test
+    public void testToArray() {
+        assertPrints("0\n1\n2\n", "puts (0..2).to_a");
+        assertPrints("1\n2\n", "puts (1..2).to_a");
+        assertPrints("1\n2\n", "puts (1...3).to_a");
+        assertPrints("1\n2\n3\n", "puts (1..3).to_a");
+    }
+
+    @Test
+    public void testEach() {
+        assertPrints("", "(1...1).each { |n| puts n }");
+        assertPrints("1\n", "(1...2).each { |n| puts n }");
+        assertPrints("1\n2\n", "(1...3).each { |n| puts n }");
+        assertPrints("1\n2\n3\n", "(1...4).each { |n| puts n }");
+        assertPrints("1\n", "(1..1).each { |n| puts n }");
+        assertPrints("1\n2\n", "(1..2).each { |n| puts n }");
+        assertPrints("1\n2\n3\n", "(1..3).each { |n| puts n }");
+        assertPrints("1\n2\n3\n4\n", "(1..4).each { |n| puts n }");
+        assertPrints("0\n1\n", "(0..1).each { |n| puts n }");
+        assertPrints("", "(4..-2).each { |n| puts n }");
+        assertPrints("-4\n-3\n-2\n", "(-4..-2).each { |n| puts n }");
+        assertPrints("-1\n0\n1\n", "(-1..1).each { |n| puts n }");
+    }
+
+    @Test
+    public void testMap() {
+        assertPrints("2\n4\n6\n", "puts (1..3).map { |n| n*2 }");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/RegexpTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.core;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test the {@code Regexp} class.
+ */
+public class RegexpTests extends RubyTests {
+
+    @Test
+    public void testLiteral() {
+        assertPrints("Regexp\n", "puts /foo/.class");
+    }
+
+    @Test
+    public void testInterpolatedLiteral() {
+        assertPrints("Regexp\n", "puts /foo#{1}/.class");
+    }
+
+    @Test
+    public void testMatch() {
+        assertPrints("0\n", "puts(/foo/ =~ \"foo\")");
+        assertPrints("0\n", "puts(\"foo\" =~ /foo/)");
+        assertPrints("3\n", "puts(/foo/ =~ \"abcfoo\")");
+        assertPrints("3\n", "puts(\"abcfoo\" =~ /foo/)");
+        assertPrints("\n", "puts(/foo/ =~ \"abc\")");
+        assertPrints("\n", "puts(\"abc\" =~ /foo/)");
+    }
+
+    @Test
+    public void testFrameLocalVariableResults() {
+        assertPrints("foo\nbar\nbaz\n", "/(foo)(bar)(baz)/ =~ 'foobarbaz'; puts $1; puts $2; puts $3");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/StringTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.core;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test the {@code String} class.
+ */
+public class StringTests extends RubyTests {
+
+    @Test
+    public void testToI() {
+        assertPrints("2\n", "puts \"2\".to_i");
+        assertPrints("-2\n", "puts \"-2\".to_i");
+        assertPrints("123456789123456789\n", "puts \"123456789123456789\".to_i");
+    }
+
+    @Test
+    public void testFormat() {
+        assertPrints("a\n", "puts \"a\"");
+        assertPrints("1\n", "puts \"%d\" % 1");
+        assertPrints("a1b\n", "puts \"a%db\" % 1");
+        assertPrints("a1.00000b\n", "puts \"a%fb\" % 1");
+        assertPrints("a2.50000b\n", "puts \"a%fb\" % 2.5");
+        assertPrints("3.400000000\n", "puts \"%.9f\" % 3.4");
+        assertPrints("3.400000000\n", "puts \"%0.9f\" % 3.4");
+    }
+
+    @Test
+    public void testThreequal() {
+        assertPrints("false\n", "puts \"a\" === \"b\"");
+        assertPrints("true\n", "puts \"a\" === \"a\"");
+    }
+
+    @Test
+    public void testIndex() {
+        assertPrints("a\n", "puts 'a'[0]");
+        assertPrints("config\n", "puts 'foo.config'[-6..-1]");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/SymbolTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.core;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test the {@code Symbol} class.
+ */
+public class SymbolTests extends RubyTests {
+
+    @Test
+    public void testParses() {
+        assertPrints("", ":foo");
+        assertPrints("", ":\"foo\"");
+    }
+
+    @Test
+    public void testPuts() {
+        assertPrints("foo\n", "puts :foo");
+    }
+
+    @Test
+    public void testInterpolated() {
+        assertPrints("foo123\n", "puts :\"foo1#{2}3\"");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/core/ThreadTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.core;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test the {@code Thread} class.
+ */
+public class ThreadTests extends RubyTests {
+
+    @Test
+    public void testCreateJoin() {
+        assertPrints("1\n2\n", "t = Thread.new { puts 1 }; t.join; puts 2");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/debug/DebugTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.debug;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.runtime.configuration.*;
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test the debugger.
+ */
+public class DebugTests extends RubyTests {
+
+    @Test
+    public void testBreakContinue() {
+        final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
+        configurationBuilder.setDebug(true);
+        final Configuration configuration = new Configuration(configurationBuilder);
+
+        final String fakeFileName = "test.rb";
+        final String code = "Debug.break; puts 2";
+        final String input = "puts 1 \n Debug.continue \n puts 'error' \n puts 'error'";
+        final String expected = "1\n=> \n2\n";
+
+        assertPrints(configuration, expected, fakeFileName, code, input, new String[]{});
+    }
+
+    @Test
+    public void testLineBreak() {
+        final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
+        configurationBuilder.setDebug(true);
+        final Configuration configuration = new Configuration(configurationBuilder);
+
+        final String fakeFileName = "test.rb";
+        final String code = "Debug.break(\"test.rb\", 2) \n puts 2 \n puts 3";
+        final String input = "puts 1 \n Debug.continue \n puts 'error' \n puts 'error'";
+        final String expected = "1\n=> \n2\n3\n";
+
+        assertPrints(configuration, expected, fakeFileName, code, input, new String[]{});
+    }
+
+    @Test
+    public void testLineCustomBreak() {
+        final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
+        configurationBuilder.setDebug(true);
+        final Configuration configuration = new Configuration(configurationBuilder);
+
+        final String fakeFileName = "test.rb";
+        final String code = "Debug.break('test.rb', 2) { puts 1; Debug.break }\nputs 3\nputs 4";
+        final String input = "puts 2 \n Debug.continue \n puts 'error' \n puts 'error'";
+        final String expected = "1\n2\n=> \n3\n4\n";
+
+        assertPrints(configuration, expected, fakeFileName, code, input, new String[]{});
+    }
+
+    @Test
+    public void testLocalBreak() {
+        final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
+        configurationBuilder.setDebug(true);
+        final Configuration configuration = new Configuration(configurationBuilder);
+
+        final String fakeFileName = "test.rb";
+        final String code = "def foo \n puts 0 \n x = 14 \n end \n Debug.break(:foo, :x) \n foo \n puts 2";
+        final String input = "puts 1 \n Debug.continue \n puts 'error' \n puts 'error'";
+        final String expected = "0\n1\n=> \n2\n";
+
+        assertPrints(configuration, expected, fakeFileName, code, input, new String[]{});
+    }
+
+    @Test
+    public void testLocalCustomBreak() {
+        final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
+        configurationBuilder.setDebug(true);
+        final Configuration configuration = new Configuration(configurationBuilder);
+
+        final String fakeFileName = "test.rb";
+        final String code = "def foo \n puts 0 \n x = 14 \n end \n Debug.break(:foo, :x) { |v| puts v; Debug.break } \n foo \n puts 2";
+        final String input = "puts 1 \n Debug.continue \n puts 'error' \n puts 'error'";
+        final String expected = "0\n14\n1\n=> \n2\n";
+
+        assertPrints(configuration, expected, fakeFileName, code, input, new String[]{});
+    }
+
+    @Test
+    public void testRemoveLineBreak() {
+        final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
+        configurationBuilder.setDebug(true);
+        final Configuration configuration = new Configuration(configurationBuilder);
+
+        final String fakeFileName = "test.rb";
+        final String code = "Debug.break('test.rb', 3) \n Debug.remove('test.rb', 3) \n puts 2 \n puts 3";
+        final String input = "puts 1 \n Debug.continue \n puts 'error' \n puts 'error'";
+        final String expected = "2\n3\n";
+
+        assertPrints(configuration, expected, fakeFileName, code, input, new String[]{});
+    }
+
+    @Test
+    public void testRemoveLocalBreak() {
+        final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
+        configurationBuilder.setDebug(true);
+        final Configuration configuration = new Configuration(configurationBuilder);
+
+        final String fakeFileName = "test.rb";
+        final String code = "def foo \n puts 0 \n x = 14 \n end \n Debug.break(:foo, :x) \n foo \n Debug.remove(:foo, :x) \n foo \n puts 2";
+        final String input = "puts 1 \n Debug.continue \n puts 'error' \n puts 'error'";
+        final String expected = "0\n1\n=> \n0\n2\n";
+
+        assertPrints(configuration, expected, fakeFileName, code, input, new String[]{});
+    }
+
+    @Test
+    public void testWhere() {
+        final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
+        configurationBuilder.setDebug(true);
+        final Configuration configuration = new Configuration(configurationBuilder);
+
+        final String fakeFileName = "test.rb";
+        final String code = "puts 1 \n Debug.where \n puts 2";
+        final String expected = "1\ntest.rb:2\n2\n";
+
+        assertPrints(configuration, expected, fakeFileName, code, "", new String[]{});
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/AndTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.language;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test {@code and} expressions, which unusually for Ruby are not methods. This is because with
+ * Ruby's eager evaluation there would be no way to implement the short circuit semantics.
+ */
+public class AndTests extends RubyTests {
+
+    @Test
+    public void testImmediate() {
+        assertPrints("false\n", "puts false && false");
+        assertPrints("false\n", "puts true && false");
+        assertPrints("false\n", "puts false && true");
+        assertPrints("true\n", "puts true && true");
+        assertPrints("false\n", "puts (false and false)");
+        assertPrints("false\n", "puts (true and false)");
+        assertPrints("false\n", "puts (false and true)");
+        assertPrints("true\n", "puts (true and true)");
+    }
+
+    @Test
+    public void testShortCircuits() {
+        assertPrints("false\nfalse\nfalse\n", "x = y = false; puts (x = false) && (y = false); puts x, y");
+        assertPrints("false\ntrue\nfalse\n", "x = y = false; puts (x = true) && (y = false); puts x, y");
+        assertPrints("false\nfalse\nfalse\n", "x = y = false; puts (x = false) && (y = true); puts x, y");
+        assertPrints("true\ntrue\ntrue\n", "x = y = false; puts (x = true) && (y = true); puts x, y");
+        assertPrints("false\nfalse\nfalse\n", "x = y = false; puts ((x = false) and (y = false)); puts x, y");
+        assertPrints("false\ntrue\nfalse\n", "x = y = false; puts ((x = true) and (y = false)); puts x, y");
+        assertPrints("false\nfalse\nfalse\n", "x = y = false; puts ((x = false) and (y = true)); puts x, y");
+        assertPrints("true\ntrue\ntrue\n", "x = y = false; puts ((x = true) and (y = true)); puts x, y");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/BlockTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.language;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test blocks.
+ */
+public class BlockTests extends RubyTests {
+
+    @Test
+    public void testSimpleYield() {
+        assertPrints("1\n", "def foo; yield; end; foo { puts 1 };");
+        assertPrints("1\n", "def foo; yield; end; foo do; puts 1; end;");
+    }
+
+    @Test
+    public void testYieldOneParameter() {
+        assertPrints("1\n", "def foo; yield 1; end; foo { |x| puts x };");
+        assertPrints("1\n", "def foo; yield 1; end; foo do |x|; puts x; end;");
+    }
+
+    @Test
+    public void testYieldTwoParameters() {
+        assertPrints("1\n2\n", "def foo; yield 1, 2; end; foo { |x, y| puts x; puts y; };");
+        assertPrints("1\n2\n", "def foo; yield 1, 2; end; foo do |x, y|; puts x; puts y; end;");
+    }
+
+    @Test
+    public void testSelfCapturedInBlock() {
+        assertPrints("main\n", "[1].each { |n| puts self.to_s }");
+    }
+
+    @Test
+    public void testBlockArgumentsDestructure() {
+        /*
+         * This really subtle. If you pass an array to a block with more than one parameters, it
+         * will be destructured. Any other type won't be destructured. There's no annotation to
+         * indicate that, like there would be with a method with the * operator.
+         */
+
+        assertPrints("1\n", "[1].each { |x| puts x.to_s }");
+        assertPrints("[1, 2]\n", "[[1, 2]].each { |xy| puts xy.to_s }");
+        assertPrints("1\n2\n", "[[1, 2]].each { |x, y| puts x, y }");
+    }
+
+    @Test
+    public void testBlocksHaveTheirOwnScopeForAssignment() {
+        assertPrints("\n", "1.times { x = 14 }; puts defined? x");
+        assertPrints("\n", "1.times do; x = 14; end; puts defined? x");
+    }
+
+    @Test
+    public void testImplicitForBlocksDoNotHaveTheirOwnScopeForAssignment() {
+        assertPrints("local-variable\n", "for n in [1]; x = 14; end; puts defined? x");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/CaseTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.language;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test {@code case} expressions.
+ */
+public class CaseTests extends RubyTests {
+
+    @Test
+    public void testSingle() {
+        assertPrints("1\n4\n", "case 'a'; when 'a'; puts 1; when 'b'; puts 2; else; puts 3; end; puts 4");
+        assertPrints("2\n4\n", "case 'b'; when 'a'; puts 1; when 'b'; puts 2; else; puts 3; end; puts 4");
+        assertPrints("3\n4\n", "case 'c'; when 'a'; puts 1; when 'b'; puts 2; else; puts 3; end; puts 4");
+    }
+
+    @Test
+    public void testMultiple() {
+        assertPrints("1\n4\n", "case 'a'; when 'a', 'b'; puts 1; when 'c'; puts 2; else; puts 3; end; puts 4");
+        assertPrints("1\n4\n", "case 'b'; when 'a', 'b'; puts 1; when 'c'; puts 2; else; puts 3; end; puts 4");
+        assertPrints("2\n4\n", "case 'c'; when 'a', 'b'; puts 1; when 'c'; puts 2; else; puts 3; end; puts 4");
+        assertPrints("3\n4\n", "case 'd'; when 'a', 'b'; puts 1; when 'c'; puts 2; else; puts 3; end; puts 4");
+    }
+
+    @Test
+    public void testSimpleConditions() {
+        assertPrints("1\n", "case; when true; puts 1; when false; puts 2; end");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/ClassLocalTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.language;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test @@ class variables. There is a lot of counter-intuitive behavior here - they aren't instance
+ * variables in class objects. The books describe them as being in a 'class hierarchy', rather than
+ * in a class. Also, the object they are defined it is not consistent - sometimes it is the class of
+ * self, sometimes it's just self.
+ */
+public class ClassLocalTests extends RubyTests {
+
+    @Test
+    public void testBasic() {
+        assertPrints("14\n", "@@x = 14; puts @@x");
+    }
+
+    /*
+     * Test that they are defined for a hierarchy, not a class.
+     */
+
+    @Test
+    public void testHeirarchyNotClassVariable() {
+        assertPrints("2\n", "class Foo; @@value = 14; end; class Bar < Foo; @@value = 2; end; class Foo; puts @@value; end");
+    }
+
+    /*
+     * Test that they take the correct class at different times. In a method, they use the class of
+     * self. In a class definition they use that class, not the class of self, which is Class.
+     */
+
+    @Test
+    public void testCorrectClass() {
+        assertPrints("1\n", "class Foo; @@x = 1; def foo; puts @@x; end; end; Foo.new.foo");
+    }
+
+    @Test
+    public void testWithinSelfMethod() {
+        assertPrints("14\n", "class Foo; @@foo = 14; def self.foo; @@foo; end; end; puts Foo.foo");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/ClassTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.language;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test {@code class} expressions.
+ */
+public class ClassTests extends RubyTests {
+
+    @Test
+    public void testDefine() {
+        assertPrints("Foo\n", "class Foo; end; puts Foo");
+    }
+
+    @Test
+    public void testMethods() {
+        assertPrints("14\n", "class Foo; def test; return 14; end; end; foo=Foo.new; puts foo.test");
+        assertPrints("14\n", "class Foo; def test(x); return x; end; end; foo=Foo.new; puts foo.test(14)");
+    }
+
+    @Test
+    public void testDefineHasScope() {
+        assertPrints("14\n", "x=14; class Foo; x=0; end; puts x");
+        assertPrints("14\n", "class Foo; x=14; puts x; end");
+    }
+
+    @Test
+    public void testInitialise() {
+        assertPrints("14\n", "class Foo; def initialize; puts 14; end; end; Foo.new");
+        assertPrints("14\n", "class Foo; def initialize(x); puts x; end; end; Foo.new 14");
+        assertPrints("14\n", "class Foo; def initialize(x); puts x; end; end; Foo.new(14)");
+    }
+
+    @Test
+    public void testInstanceVariables() {
+        assertPrints("14\n", "class Foo; def a; @x=14; end; def b; @x; end; end; foo=Foo.new; foo.a; puts foo.b");
+    }
+
+    @Test
+    public void testMissingVariables() {
+        assertPrints("NilClass\n", "class Foo; def a; @x; end; end; foo=Foo.new; puts foo.a.class");
+    }
+
+    @Test
+    public void testClassConstants() {
+        assertPrints("14\n", "class Foo; X=14; def foo; puts X; end; end; foo=Foo.new; foo.foo");
+    }
+
+    @Test
+    public void testReopeningSingletonClass() {
+        assertPrints("1\n", "foo = Object.new; class << foo; def bar; puts 1; end; end; foo.bar");
+    }
+
+    @Test
+    public void testInheritance() {
+        assertPrints("14\n", "class Foo; def foo; puts 14; end; end; class Bar < Foo; end; Bar.new.foo");
+    }
+
+    @Test
+    public void testSingletonInheritance() {
+        assertPrints("14\n", "class Foo; def self.foo; puts 14; end; end; class Bar < Foo; end; Bar.foo");
+    }
+
+    @Test
+    public void testNestedClass() {
+        assertPrints("14\n", "class Foo; class Bar; def bar; 14; end; end; def foo; Bar.new; end; end; puts Foo.new.foo.bar");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/ConstantTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.language;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+public class ConstantTests extends RubyTests {
+
+    @Test
+    public void testTopLevelConstants() {
+        assertPrints("14\n", "X=14; class Foo; def foo; puts X; end; end; f=Foo.new; f.foo");
+    }
+
+    @Test
+    public void testNestedConstants() {
+        assertPrints("", "module X; class A; end; class B; class C < A; end; end; end");
+    }
+
+    @Test
+    public void testSearchInParentModules() {
+        assertPrints("14\n", "module A; C = 14; module B; def self.test; puts C; end; end; end; A::B.test");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/ForTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.language;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test {@code for} expressions.
+ */
+public class ForTests extends RubyTests {
+
+    @Test
+    public void testArray() {
+        assertPrints("1\n2\n3\n", "for x in [1, 2, 3]; puts x; end");
+        assertPrints("1\n2\n3\n", "y = [1, 2, 3]; for x in y; puts x; end");
+    }
+
+    @Test
+    public void testRange() {
+        assertPrints("1\n2\n3\n", "for x in 1..3; puts x; end");
+        assertPrints("1\n2\n3\n", "y = 1..3; for x in y; puts x; end");
+        assertPrints("1\n2\n", "for x in 1...3; puts x; end");
+    }
+
+    @Test
+    public void testScopeRO() {
+        assertPrints("14\n", "x=14; for n in [1]; puts x; end");
+    }
+
+    @Test
+    public void testScopeRW() {
+        assertPrints("14\n", "x=0; for n in [1]; x=x+14; puts x; end");
+    }
+
+    @Test
+    public void testNoNewScope() {
+        assertPrints("14\n", "for i in [1]; v = 14; end; puts v");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/GlobalVariableTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.language;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test global variables.
+ */
+public class GlobalVariableTests extends RubyTests {
+
+    @Test
+    public void testMinimal() {
+        assertPrints("14\n", "$foo = 14; puts $foo");
+    }
+
+    @Test
+    public void testScope() {
+        assertPrints("14\n", "def foo; $bar = 14; end; foo; puts $bar");
+        assertPrints("14\n", "$bar = 14; def foo; puts $bar; end; foo");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/IfTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.language;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test {@code if} expressions.
+ */
+public class IfTests extends RubyTests {
+
+    @Test
+    public void testImmediateIf() {
+        assertPrints("1\n", "if true; puts 1 end");
+        assertPrints("", "if false; puts 1 end");
+    }
+
+    @Test
+    public void testImmediateTrailingIf() {
+        assertPrints("1\n", "puts 1 if true");
+        assertPrints("", "puts 1 if false");
+    }
+
+    @Test
+    public void testImmediateIfElse() {
+        assertPrints("1\n", "if true; puts 1 else puts 2 end");
+        assertPrints("2\n", "if false; puts 1 else puts 2 end");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/InterpolatedStringTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.language;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test interpolated strings - that is string literals with #{...} sections in them. Within those
+ * you can have arbitrary Ruby expressions.
+ */
+public class InterpolatedStringTests extends RubyTests {
+
+    @Test
+    public void testBasic() {
+        assertPrints("123\n", "puts \"1#{2}3\"");
+    }
+
+    @Test
+    public void testMethodCall() {
+        assertPrints("123\n", "def foo; 2; end; puts \"1#{foo}3\"");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/LocalTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.language;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test local variables.
+ */
+public class LocalTests extends RubyTests {
+
+    @Test
+    public void testAssignmentTopLevel() {
+        assertPrints("1\n", "x = 1; puts x");
+    }
+
+    @Test
+    public void testAssignmentWithinMethod() {
+        assertPrints("1\n", "def foo; x = 1; puts x; end; foo");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/MethodTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.language;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.runtime.control.*;
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test method definitions and calls.
+ */
+public class MethodTests extends RubyTests {
+
+    @Test
+    public void testDefineCallNoArguments() {
+        assertPrints("1\n", "def foo; puts 1; end; foo()");
+        assertPrints("1\n", "def foo; puts 1; end; foo");
+    }
+
+    @Test
+    public void testDefineCallOnePreArgument() {
+        assertPrints("1\n", "def foo(a); puts a; end; foo(1)");
+        assertPrints("1\n", "def foo(a); puts a; end; foo 1");
+    }
+
+    @Test
+    public void testDefineCallTwoPreArguments() {
+        assertPrints("1\n2\n", "def foo(a, b); puts a; puts b; end; foo(1, 2)");
+        assertPrints("1\n2\n", "def foo(a, b); puts a; puts b; end; foo 1, 2");
+    }
+
+    @Test
+    public void testSingleReturn() {
+        assertPrints("1\n", "def foo; return 1; end; puts foo");
+        assertPrints("1\n", "def foo(n); return n; end; puts foo(1)");
+    }
+
+    @Test
+    public void testImplicitReturn() {
+        assertPrints("1\n", "def foo; 1; end; puts foo");
+        assertPrints("3\n", "def foo; 1+2; end; puts foo");
+        assertPrints("14\n", "def foo; x=14; end; puts foo");
+    }
+
+    @Test
+    public void testNestedCall() {
+        assertPrints("1\n", "def foo(n); return n; end; def bar(n); return foo(n); end; puts bar(1)");
+        assertPrints("1\n1\n1\n", "def foo(n); puts n; return n; end; def bar(n); puts n; return foo(n); end; puts bar(1)");
+        assertPrints("1\n1\n", "def foo(a, b); puts a; puts b; end; def bar(n); foo(n, n); end; bar(1)");
+    }
+
+    @Test
+    public void testNestedOperatorCall() {
+        assertPrints("3\n", "def foo(a, b); puts a + b; end; foo(1, 2)");
+    }
+
+    /**
+     * Tests that arguments are evaluated before method dispatch takes place, by putting an action
+     * in one of the arguments that modifies the method that we should find in dispatch.
+     */
+    @Test
+    public void testArgumentsExecutedBeforeDispatch() {
+        /*
+         * We have to use Object#send instead of calling define_method directly because that method
+         * is private.
+         */
+
+        assertPrints("12\n", "def foo\n" + //
+                        "  Fixnum.send(:define_method, :+) do |other|\n" + //
+                        "    self - other\n" + //
+                        "   end \n" + //
+                        "  2\n" + //
+                        "end\n" + //
+                        "puts 14 + foo");
+    }
+
+    @Test(expected = RaiseException.class)
+    public void testTooFewArguments1() {
+        assertPrints("", "def foo(a); end; foo()");
+    }
+
+    @Test(expected = RaiseException.class)
+    public void testTooFewArguments2() {
+        assertPrints("", "def foo(a, b); end; foo(1)");
+    }
+
+    @Test(expected = RaiseException.class)
+    public void testTooFewArguments3() {
+        assertPrints("", "def foo(a, b, c); end; foo(1, 2)");
+    }
+
+    @Test(expected = RaiseException.class)
+    public void testTooManyArguments1() {
+        assertPrints("", "def foo(); end; foo(1)");
+    }
+
+    @Test(expected = RaiseException.class)
+    public void testTooManyArguments2() {
+        assertPrints("", "def foo(a); end; foo(1, 2)");
+    }
+
+    @Test(expected = RaiseException.class)
+    public void testTooManyArguments3() {
+        assertPrints("", "def foo(a, b); end; foo(1, 2, 3)");
+    }
+
+    @Test
+    public void testPolymophicMethod() {
+        assertPrints("A\nB\n", "class A\n" + //
+                        "    def foo\n" + //
+                        "        puts \"A\"\n" + //
+                        "    end\n" + //
+                        "end\n" + //
+                        "\n" + //
+                        "class B\n" + //
+                        "    def foo\n" + //
+                        "        puts \"B\"\n" + //
+                        "    end\n" + //
+                        "end\n" + //
+                        "\n" + //
+                        "def bar(x)\n" + //
+                        "    x.foo\n" + //
+                        "end\n" + //
+                        "\n" + //
+                        "a = A.new\n" + //
+                        "b = B.new\n" + //
+                        "\n" + //
+                        "bar(a)\n" + //
+                        "bar(b)\n");
+    }
+
+    @Test
+    public void testOneDefaultValue() {
+        assertPrints("1\n2\n", "def foo(a=1); puts a; end; foo; foo(2)");
+    }
+
+    @Test
+    public void testTwoDefaultValues() {
+        assertPrints("1\n2\n3\n2\n3\n4\n", "def foo(a=1,b=2); puts a; puts b; end; foo; foo(3); foo(3, 4)");
+    }
+
+    @Test
+    public void testOneDefaultValueAfterNonDefault() {
+        assertPrints("2\n1\n2\n3\n", "def foo(a, b=1); puts a; puts b; end; foo(2); foo(2, 3)");
+    }
+
+    @Test
+    public void testOneDefaultValueBeforeNonDefault() {
+        assertPrints("1\n2\n2\n3\n", "def foo(a=1, b); puts a; puts b; end; foo(2); foo(2, 3)");
+    }
+
+    @Test
+    public void testBlockArgument() {
+        assertPrints("1\n2\n3\n", "def foo(&block); block.call(14); end; puts 1; foo { |n| puts 2 }; puts 3");
+    }
+
+    @Test
+    public void testBlockArgumentWithOthers() {
+        assertPrints("1\n2\n3\n4\n5\n", "def foo(a, b, &block); puts a; block.call(14); puts b; end; puts 1; foo(2, 4) { |n| puts 3 }; puts 5");
+    }
+
+    @Test
+    public void testBlockPass() {
+        assertPrints("1\n2\n3\n", "def bar; yield; end; def foo(&block); bar(&block); end; puts 1; foo { puts 2 }; puts 3");
+    }
+
+    @Test
+    public void testBlockPassWithOthers() {
+        assertPrints("1\n2\n3\n4\n5\n", "def bar(a, b); puts a; yield; puts b; end; def foo(a, b, &block); bar(a, b, &block); end; puts 1; foo(2, 4) { puts 3 }; puts 5");
+    }
+
+    @Test
+    public void testSplatWhole() {
+        assertPrints("1\n2\n3\n", "def foo(a, b, c); puts a; puts b; puts c; end; d = [1, 2, 3]; foo(*d)");
+    }
+
+    @Test
+    public void testSplatSome() {
+        assertPrints("1\n2\n3\n", "def foo(a, b, c); puts a; puts b; puts c; end; d = [2, 3]; foo(1, *d)");
+    }
+
+    @Test
+    public void testSplatParam() {
+        assertPrints("[1, 2, 3]\n", "def foo(*bar); puts bar.to_s; end; foo(1, 2, 3)");
+    }
+
+    @Test
+    public void testSplatParamWithOther() {
+        assertPrints("1\n[2]\n", "def foo(a, *b); puts a.to_s; puts b.to_s; end; foo(1, 2)");
+    }
+
+    @Test
+    public void testSplatParamWithBlockPass() {
+        assertPrints("[1, 2, 3]\n", "def foo(*bar, &block); block.call(bar); end; foo(1, 2, 3) { |x| puts x.to_s }");
+    }
+
+    @Test
+    public void testSingletonMethod() {
+        assertPrints("1\n", "foo = Object.new; def foo.bar; puts 1; end; foo.bar");
+    }
+
+    @Test
+    public void testAlias() {
+        assertPrints("1\n", "def foo; puts 1; end; alias bar foo; bar");
+        assertPrints("1\n", "class Foo; def foo; puts 1; end; alias bar foo; end; Foo.new.bar");
+    }
+
+    @Test
+    public void testAliasMethod() {
+        assertPrints("1\n", "class Foo; def foo; puts 1; end; alias_method :bar, :foo; end; Foo.new.bar");
+    }
+
+    @Test
+    public void testSymbolAsBlock() {
+        assertPrints("6\n", "puts [1, 2, 3].inject(&:+)");
+    }
+
+    @Test
+    public void testSuper() {
+        assertPrints("1\n2\n3\n", "class Foo; def foo; puts 2; end; end; class Bar < Foo; def foo; puts 1; super; puts 3; end; end; Bar.new.foo");
+    }
+
+    @Test
+    public void testSuperWithArgs() {
+        assertPrints("1\n2\n3\n", "class Foo; def foo(n); puts n; end; end; class Bar < Foo; def foo(n); puts 1; super(n); puts 3; end; end; Bar.new.foo(2)");
+    }
+
+    @Test
+    public void testPushSplat() {
+        assertPrints("[1, 0, 4]\n", "a = [1, 2, 3, 4]; b = [1, 2]; a[*b] = 0; puts a.to_s");
+    }
+
+    @Test
+    public void testBlocksPassedIntoBlocks() {
+        assertPrints("14\n", "def foo; 1.times do; yield; end; end; foo do; puts 14; end");
+    }
+
+    @Test
+    public void testBlocksNotPassedIntoFullMethods() {
+        assertPrints("no block\n", "def foo(&block); if block; puts 'block'; else; puts 'no block'; end; end; def bar; foo; end; bar do; end");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/ModuleTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.language;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test {@code module} expressions.
+ */
+public class ModuleTests extends RubyTests {
+
+    @Test
+    public void testDefine() {
+        assertPrints("Foo\n", "module Foo; end; puts Foo");
+    }
+
+    @Test
+    public void testWithConstantDefinition() {
+        assertPrints("14\n", "module Foo; FOO=14; end; puts Foo::FOO");
+    }
+
+    @Test
+    public void testWithConstantDefinitionAndAccessInDeclaration() {
+        assertPrints("14\n", "module Foo; FOO=14; puts FOO; end");
+    }
+
+    @Test
+    public void testCanAccessObjectConstantsInModuleDefinition() {
+        assertPrints("", "class Foo; end; module Bar; foo = Foo.new; end");
+    }
+
+    @Test
+    public void testInclude() {
+        assertPrints("14\n", "module Foo; FOO=14; end; module Bar; include Foo; end; puts Bar::FOO");
+    }
+
+    @Test
+    public void testModuleFunction() {
+        assertPrints("1\n", "module Foo; def bar; puts 1; end; module_function :bar; end; Foo::bar");
+    }
+
+    @Test
+    public void testDistinctModule() {
+        assertPrints("true\n", "module A; module X; end; end; module B; module X; end; end; puts A::X.object_id != B::X.object_id");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/MultipleAssignmentTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.language;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test multiple assignment, which is sort of like pattern matching for arrays. The arrays can be
+ * implicit on the RHS.
+ */
+public class MultipleAssignmentTests extends RubyTests {
+
+    @Test
+    public void testToLocal() {
+        assertPrints("1\n2\n", "x, y = [1, 2]; puts x, y");
+        assertPrints("1\n2\n", "x, y = 1, 2; puts x, y");
+        assertPrints("1\n2\n", "x = [1, 2]; y, z = x; puts y, z");
+    }
+
+    @Test
+    public void testToArrayIndex() {
+        assertPrints("1\n2\n", "x = []; x[0], x[1] = 1, 2; puts x");
+    }
+
+    @Test
+    public void testSwap() {
+        assertPrints("2\n1\n", "a = [1]; b = [2]; a[0], b[0] = b[0], a[0]; puts a, b");
+    }
+
+    @Test
+    public void testProducesArray() {
+        assertPrints("1\n2\n", "puts((a, b = 1, 2))");
+    }
+
+    @Test
+    public void testWithSplat() {
+        assertPrints("1\n[2, 3]\n", "a, *b = [1, 2, 3]; puts a; puts b.to_s");
+    }
+
+    @Test
+    public void testWithSplatEmpty() {
+        assertPrints("1\n[]\n", "a, *b = [1]; puts a.to_s; puts b.to_s");
+    }
+
+    @Test
+    public void testWithSingleValueRHS() {
+        assertPrints("14\n\n\n", "a, b, c = 14; puts a; puts b; puts c");
+        assertPrints("\n\n\n", "a, b, c = nil; puts a; puts b; puts c");
+    }
+
+    @Test
+    public void testWithSingleSplatLHSAndSingleValueRHS() {
+        assertPrints("[14]\n", "a = *14; puts a.to_s");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/OrTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.language;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test {@code or} expressions, which unusually for Ruby are not methods. This is because with
+ * Ruby's eager evaluation there would be no way to implement the short circuit semantics.
+ */
+public class OrTests extends RubyTests {
+
+    @Test
+    public void testImmediate() {
+        assertPrints("false\n", "puts false || false");
+        assertPrints("true\n", "puts true || false");
+        assertPrints("true\n", "puts false || true");
+        assertPrints("true\n", "puts true || true");
+        assertPrints("false\n", "puts (false or false)");
+        assertPrints("true\n", "puts (true or false)");
+        assertPrints("true\n", "puts (false or true)");
+        assertPrints("true\n", "puts (true or true)");
+    }
+
+    @Test
+    public void testShortCircuits() {
+        assertPrints("false\nfalse\nfalse\n", "x = y = false; puts (x = false) || (y = false); puts x, y");
+        assertPrints("true\ntrue\nfalse\n", "x = y = false; puts (x = true) || (y = false); puts x, y");
+        assertPrints("true\nfalse\ntrue\n", "x = y = false; puts (x = false) || (y = true); puts x, y");
+        assertPrints("true\ntrue\nfalse\n", "x = y = false; puts (x = true) || (y = true); puts x, y");
+        assertPrints("false\nfalse\nfalse\n", "x = y = false; puts ((x = false) or (y = false)); puts x, y");
+        assertPrints("true\ntrue\nfalse\n", "x = y = false; puts ((x = true) or (y = false)); puts x, y");
+        assertPrints("true\nfalse\ntrue\n", "x = y = false; puts ((x = false) or (y = true)); puts x, y");
+        assertPrints("true\ntrue\nfalse\n", "x = y = false; puts ((x = true) or (y = true)); puts x, y");
+    }
+
+    @Test
+    public void testOrAssign() {
+        assertPrints("true\n", "def foo; puts 1; false; end; x = true; x ||= foo; puts x");
+        assertPrints("1\nfalse\n", "def foo; puts 1; false; end; x = false; x ||= foo; puts x");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/PolymorphismTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.language;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test characteristics of polymorphism.
+ */
+public class PolymorphismTests extends RubyTests {
+
+    /**
+     * Test that a polymorphic method that will specialize to double will then not treat integers as
+     * doubles.
+     */
+    @Test
+    public void testSimpleOperatorRedefinition() {
+        assertPrints("16.759999999999998\n16\n", //
+                        "def add(x, y)\n" + //
+                                        "    x + y\n" + //
+                                        "end\n" + //
+                                        "puts add(14.5, 2.26)\n" + //
+                                        "puts add(14, 2)\n");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/RaiseRescueTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.language;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.runtime.control.*;
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test {@code raise} and {@code rescue}.
+ */
+public class RaiseRescueTests extends RubyTests {
+
+    @Test(expected = RaiseException.class)
+    public void testZeroDivisionError() {
+        assertPrints("", "1/0");
+    }
+
+    @Test
+    public void testBeginRescue() {
+        assertPrints("", "begin; rescue; end");
+        assertPrints("", "begin; rescue => e; end");
+        assertPrints("", "begin; rescue ZeroDivisionError => e; end");
+        assertPrints("", "begin; rescue; ensure; end");
+        assertPrints("", "begin; rescue => e; ensure; end");
+        assertPrints("", "begin; rescue ZeroDivisionError => e; ensure; end");
+        assertPrints("", "begin; rescue; else; end");
+        assertPrints("", "begin; rescue => e; else; end");
+        assertPrints("", "begin; rescue ZeroDivisionError => e; else; end");
+        assertPrints("", "def foo; rescue; end");
+        assertPrints("", "def foo; rescue => e; end");
+        assertPrints("", "def foo; rescue ZeroDivisionError => e; end");
+        assertPrints("", "def foo; rescue; ensure; end");
+        assertPrints("", "def foo; rescue => e; ensure; end");
+        assertPrints("", "def foo; rescue ZeroDivisionError => e; ensure; end");
+        assertPrints("", "def foo; rescue; else; end");
+        assertPrints("", "def foo; rescue => e; else; end");
+        assertPrints("", "def foo; rescue ZeroDivisionError => e; else; end");
+    }
+
+    @Test
+    public void testRescueZeroDivisionError() {
+        assertPrints("divided by 0\n3\n4\n", "begin; 1/0; puts 1; rescue => e; puts e; else puts 2; ensure puts 3; end; puts 4");
+        assertPrints("divided by 0\n3\n4\n", "begin; 1/0; puts 1; rescue ZeroDivisionError => e; puts e; else puts 2; ensure puts 3; end; puts 4");
+        assertPrints("1\n2\n3\n4\n", "begin; 1/1; puts 1; rescue ZeroDivisionError => e; puts e; else puts 2; ensure puts 3; end; puts 4");
+        assertPrints("1\n2\n3\n4\n", "begin; 1/1; puts 1; rescue ZeroDivisionError => e; puts e; rescue NameError => e; puts e; else puts 2; ensure puts 3; end; puts 4");
+    }
+
+    @Test
+    public void testSplatRescue() {
+        assertPrints("2\n", "ERRORS=[ZeroDivisionError]; begin; 1/0; puts 1; rescue *ERRORS; puts 2; end");
+    }
+
+    @Test
+    public void testRetry() {
+        assertPrints("1\n3\n1\n2\n5\n", "x=0; begin; puts 1; 1/x; puts 2; rescue ZeroDivisionError; puts 3; x=1; retry; puts 4; end; puts 5");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/RedefinitionTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.language;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test that methods can be redefined.
+ */
+public class RedefinitionTests extends RubyTests {
+
+    /**
+     * Test that a method on Fixnum can be redefined and that we will use the new definition. The
+     * call that expects to find the redefinition needs to have already been specialized, which is
+     * why do it through a method.
+     */
+    @Test
+    public void testSimpleOperatorRedefinition() {
+        assertPrints("3\n-1\n", //
+                        "def add(x, y)\n" + //
+                                        "    x + y\n" + //
+                                        "end\n" + //
+                                        "puts add(1, 2)\n" + //
+                                        "class Fixnum\n" + //
+                                        "    def +(other)\n" + //
+                                        "        self - other\n" + //
+                                        "    end\n" + //
+                                        "end\n" + //
+                                        "puts add(1, 2)\n");
+    }
+
+    /**
+     * This is quite a subtle test. We redefine Float#+. We have a method which calls +. It is
+     * initially specialized to Fixnum, but then used with Float. The tricky bit is that Float has
+     * not been redefined since the operator has been specialized. The operator thinks it is up to
+     * date. When we emit a + node, we need to check if any class that that node could specialize to
+     * has been redefined.
+     */
+    @Test
+    public void testSpecialisationConsidersRedefinitionInOtherClasses() {
+        assertPrints("16\n12.25\n", //
+                        "def add(a, b)\n" + //
+                                        "    a + b\n" + //
+                                        "end\n" + //
+                                        "class Float\n" + //
+                                        "    def +(other)\n" + //
+                                        "        self - other\n" + //
+                                        "    end\n" + //
+                                        "end\n" + //
+                                        "puts add(14, 2)\n" + //
+                                        "puts add(14.5, 2.25)");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/ShortcutTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.language;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test shortcut expressions (syntactic sugar) such as {@code +=} and {@code |=}.
+ */
+public class ShortcutTests extends RubyTests {
+
+    @Test
+    public void testShortcutAddAssign() {
+        assertPrints("2\n", "x = 1; x += 1; puts x");
+    }
+
+    @Test
+    public void testShortcutSubAssign() {
+        assertPrints("0\n", "x = 1; x -= 1; puts x");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/SpecialVariableTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.language;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test variables with special semantics, such as the 'global variables', {@code $_}, {@code $~}
+ * etc.
+ */
+public class SpecialVariableTests extends RubyTests {
+
+    @Test
+    public void testGetsResult() {
+        assertPrintsWithInput("test\n", "gets; puts $_", "test\n");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/UntilTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.language;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test {@code until} expressions.
+ */
+public class UntilTests extends RubyTests {
+
+    @Test
+    public void testSimpleWhile() {
+        assertPrints("0\n", "x = 10; until x == 0; x -= 1; end; puts x");
+        assertPrints("10\n", "x = 0; until x == 10; x += 1; end; puts x");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/language/WhileTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.language;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.test.*;
+
+/**
+ * Test {@code while} expressions.
+ */
+public class WhileTests extends RubyTests {
+
+    @Test
+    public void testSimpleWhile() {
+        assertPrints("0\n", "x = 10; while x > 0; x -= 1; end; puts x");
+        assertPrints("10\n", "x = 0; while x < 10; x += 1; end; puts x");
+    }
+
+    @Test
+    public void testBreak() {
+        assertPrints("1\n", "x = 0; while x < 10; x += 1; break; end; puts x");
+    }
+
+    @Test
+    public void testNext() {
+        assertPrints("10\n", "x = 0; while x < 10; x += 1; next; end; puts x");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/runtime/ObjectLayoutTests.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.test.runtime;
+
+import org.junit.*;
+
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.objects.*;
+
+import static org.junit.Assert.*;
+
+/**
+ * Test the object layout classes.
+ */
+public class ObjectLayoutTests {
+
+    @Test
+    public void testNewInstanceVariable() {
+        final RubyContext context = new RubyContext(null);
+
+        // Create a class and an instance
+
+        final RubyClass classA = new RubyClass(context, null, null, null, "A");
+        final ObjectLayout layoutClassA = classA.getObjectLayoutForInstances();
+
+        final RubyBasicObject objectA = new RubyBasicObject(classA);
+        final ObjectLayout layoutObjectA = objectA.getObjectLayout();
+
+        // Add an instance variable to the instance
+
+        objectA.setInstanceVariable("foo", 14);
+
+        // That should have changed the layout of the class
+
+        assertNotSame(layoutClassA, classA.getObjectLayoutForInstances());
+
+        // If we notify the object, it should also change the layout of that
+
+        objectA.updateLayout();
+        assertNotSame(layoutObjectA, objectA.getObjectLayout());
+
+        // We should be able to find that instance variable as a storage location in the class
+
+        assertNotNull(classA.getObjectLayoutForInstances().findStorageLocation("foo"));
+
+        // We should be able to read that value back out
+
+        assertEquals(14, objectA.getInstanceVariable("foo"));
+    }
+
+    @Test
+    public void testOverflowPrimitives() {
+        final RubyContext context = new RubyContext(null);
+
+        // Create a class and an instance
+
+        final RubyClass classA = new RubyClass(context, null, null, null, "A");
+        final RubyBasicObject objectA = new RubyBasicObject(classA);
+
+        // Add many more Fixnums that we have space for primitives
+
+        final int count = 100;
+
+        for (int n = 0; n < count; n++) {
+            objectA.setInstanceVariable("foo" + n, n);
+        }
+
+        // We should be able to read them back out
+
+        for (int n = 0; n < count; n++) {
+            assertEquals(n, objectA.getInstanceVariable("foo" + n));
+        }
+    }
+
+    @Test
+    public void testGeneralisation() {
+        final RubyContext context = new RubyContext(null);
+
+        // Create a class and two instances
+
+        final RubyClass classA = new RubyClass(context, null, null, null, "A");
+        final RubyBasicObject object1 = new RubyBasicObject(classA);
+        final RubyBasicObject object2 = new RubyBasicObject(classA);
+
+        // Set an instance variable to be a Fixnum in object 1
+
+        object1.setInstanceVariable("foo", 14);
+
+        // We should be able to read that instance variable back, and it should still be a Fixnum
+
+        assertEquals(14, object1.getInstanceVariable("foo"));
+        assertSame(Integer.class, object1.getInstanceVariable("foo").getClass());
+
+        // The underlying instance store should be Fixnum
+
+        assertSame(FixnumStorageLocation.class, object1.getObjectLayout().findStorageLocation("foo").getClass());
+
+        /*
+         * The same instance variable in object 2 should be Nil. Note that this requires that we
+         * realise that even though the instance variable is known about in the layout of object 2,
+         * and we are using a primitive int to hold it, that it hasn't been set and is actually Nil.
+         * We don't want it to appear as 0.
+         */
+
+        assertSame(NilPlaceholder.INSTANCE, object2.getInstanceVariable("foo"));
+
+        /*
+         * We should be able to set the same instance variable in object 2 to also be a Fixnum
+         * without changing the layout.
+         */
+
+        final ObjectLayout objectLayout2 = object2.getObjectLayout();
+        object2.setInstanceVariable("foo", 2);
+        assertEquals(2, object2.getInstanceVariable("foo"));
+        assertSame(Integer.class, object2.getInstanceVariable("foo").getClass());
+        assertSame(objectLayout2, object2.getObjectLayout());
+
+        // Set the instance variable in object 2 to be a Float
+
+        object2.setInstanceVariable("foo", 2.25);
+
+        // We should be able to read that instance variable back, and it should still be a Fixnum
+
+        assertEquals(2.25, object2.getInstanceVariable("foo"));
+        assertSame(Double.class, object2.getInstanceVariable("foo").getClass());
+
+        // Object 1 should give still think the instance variable is a Fixnum
+
+        assertEquals(14, object1.getInstanceVariable("foo"));
+        assertSame(Integer.class, object1.getInstanceVariable("foo").getClass());
+
+        // The underlying instance store in both objects should now be Object
+
+        assertSame(ObjectStorageLocation.class, object1.getObjectLayout().findStorageLocation("foo").getClass());
+        assertSame(ObjectStorageLocation.class, object2.getObjectLayout().findStorageLocation("foo").getClass());
+
+    }
+
+    @Test
+    public void testSubclasses() {
+        final RubyContext context = new RubyContext(null);
+
+        // Create two classes, A, and a subclass, B, and an instance of each
+
+        final RubyClass classA = new RubyClass(context, null, null, null, "A");
+        final RubyClass classB = new RubyClass(context, null, null, classA, "B");
+
+        ObjectLayout layoutClassA = classA.getObjectLayoutForInstances();
+        ObjectLayout layoutClassB = classA.getObjectLayoutForInstances();
+
+        final RubyBasicObject objectA = new RubyBasicObject(classA);
+        final RubyBasicObject objectB = new RubyBasicObject(classB);
+
+        ObjectLayout layoutObjectA = objectA.getObjectLayout();
+        ObjectLayout layoutObjectB = objectB.getObjectLayout();
+
+        // Add an instance variable to the instance of A
+
+        objectA.setInstanceVariable("foo", 14);
+
+        // That should have changed the layout of both classes
+
+        assertNotSame(layoutClassA, classA.getObjectLayoutForInstances());
+        assertNotSame(layoutClassB, classB.getObjectLayoutForInstances());
+
+        layoutClassA = classA.getObjectLayoutForInstances();
+        layoutClassB = classA.getObjectLayoutForInstances();
+
+        // If we notify the objects, both of them should have changed layouts
+
+        objectA.updateLayout();
+        objectB.updateLayout();
+        assertNotSame(layoutObjectA, objectA.getObjectLayout());
+        assertNotSame(layoutObjectB, objectB.getObjectLayout());
+
+        layoutObjectA = objectA.getObjectLayout();
+        layoutObjectB = objectB.getObjectLayout();
+
+        // We should be able to find that instance variable as a storage location in both classes
+
+        assertNotNull(classA.getObjectLayoutForInstances().findStorageLocation("foo"));
+        assertNotNull(classB.getObjectLayoutForInstances().findStorageLocation("foo"));
+
+        // We should be able to read that value back out
+
+        assertEquals(14, objectA.getInstanceVariable("foo"));
+
+        // Add an instance variable to the instance of B
+
+        objectB.setInstanceVariable("bar", 2);
+
+        // This should not have changed the layout of A or the instance of A
+
+        assertSame(layoutClassA, classA.getObjectLayoutForInstances());
+        assertSame(layoutObjectA, objectA.getObjectLayout());
+
+        // But the layout of B and the instance of B should have changed
+
+        assertNotSame(layoutClassB, classB.getObjectLayoutForInstances());
+
+        objectB.updateLayout();
+        assertNotSame(layoutObjectB, objectB.getObjectLayout());
+
+        // We should be able to find the new instance variable in the instance of B but not A
+
+        assertNull(classA.getObjectLayoutForInstances().findStorageLocation("bar"));
+        assertNotNull(classB.getObjectLayoutForInstances().findStorageLocation("bar"));
+
+        // We should be able to read that value back out
+
+        assertEquals(2, objectB.getInstanceVariable("bar"));
+    }
+
+    @Test
+    public void testPerObjectInstanceVariables() {
+        final RubyContext context = new RubyContext(null);
+
+        // Create a class and an instance
+
+        final RubyClass classA = new RubyClass(context, context.getCoreLibrary().getClassClass(), null, null, "A");
+        final RubyBasicObject objectA = new RubyBasicObject(classA);
+
+        ObjectLayout layoutClassA = classA.getObjectLayoutForInstances();
+        ObjectLayout layoutObjectA = objectA.getObjectLayout();
+
+        // Add an instance variable to the instance of A
+
+        objectA.setInstanceVariable("foo", 2);
+
+        // That should have changed the layout of the class and the object
+
+        assertNotSame(layoutClassA, classA.getObjectLayoutForInstances());
+        assertNotSame(layoutObjectA, objectA.getObjectLayout());
+        layoutClassA = classA.getObjectLayoutForInstances();
+        layoutObjectA = classA.getObjectLayout();
+
+        // We should be able to read the value back out
+
+        assertEquals(2, objectA.getInstanceVariable("foo"));
+
+        /*
+         * Switch object A to having a private object layout, as would be done by calls such as
+         * instance_variable_set.
+         */
+
+        objectA.switchToPrivateLayout();
+
+        // Set an instance variable on object A
+
+        objectA.setInstanceVariable("bar", 14);
+
+        // The layout of object A, however, should have changed
+
+        // CS: it hasn't changed because it's still null
+        // assertNotSame(layoutObjectA, objectA.getObjectLayout());
+
+        // We should be able to read the value back out
+
+        assertEquals(14, objectA.getInstanceVariable("bar"));
+
+        /*
+         * We should also be able to read the first variable back out, even though we've switched to
+         * private layout since then.
+         */
+
+        assertEquals(2, objectA.getInstanceVariable("foo"));
+    }
+
+}
--- a/mx/mx_graal.py	Mon Jan 06 14:21:39 2014 +0100
+++ b/mx/mx_graal.py	Mon Jan 06 17:12:09 2014 +0000
@@ -1363,6 +1363,17 @@
 def isGraalEnabled(vm):
     return vm != 'original' and not vm.endswith('nograal')
 
+def rubyShellCp():
+    return mx.classpath("com.oracle.truffle.ruby.shell")
+
+def rubyShellClass():
+    return "com.oracle.truffle.ruby.shell.Shell"
+
+def ruby(args):
+    """run a Ruby program or shell"""
+    vmArgs, rubyArgs = _extract_VM_args(args, useDoubleDash=True)
+    vm(vmArgs + ['-cp', rubyShellCp(), rubyShellClass()] + rubyArgs)
+
 def site(args):
     """create a website containing javadoc and the project dependency graph"""
 
@@ -1522,6 +1533,7 @@
         'longtests' : [longtests, ''],
         'sl' : [sl, '[SL args|@VM options]'],
         'trufflejar' : [trufflejar, ''],
+        'ruby' : [ruby, '[Ruby args|@VM options]']
     }
 
     mx.add_argument('--jacoco', help='instruments com.oracle.* classes using JaCoCo', default='off', choices=['off', 'on', 'append'])
--- a/mx/projects	Mon Jan 06 14:21:39 2014 +0100
+++ b/mx/projects	Mon Jan 06 17:12:09 2014 +0000
@@ -26,6 +26,47 @@
 
 library@OKRA@path=lib/okra-1.2.jar
 library@OKRA@urls=http://cr.openjdk.java.net/~tdeneau/okra-1.2.jar
+library@JRUBYPARSER@path=lib/jrubyparser-0.5.0.jar
+library@JRUBYPARSER@urls=http://repo1.maven.org/maven2/org/jruby/jrubyparser/0.5.0/jrubyparser-0.5.0.jar
+
+library@JLINE@path=lib/jline-2.10.jar
+library@JLINE@urls=http://repo1.maven.org/maven2/jline/jline/2.10/jline-2.10.jar
+
+library@JRUBYSTDLIB@path=lib/jruby-stdlib-1.7.4.jar
+library@JRUBYSTDLIB@urls=http://repo1.maven.org/maven2/org/jruby/jruby-stdlib/1.7.4/jruby-stdlib-1.7.4.jar
+
+library@JNR_POSIX@path=lib/jnr-posix-3.0.0.jar
+library@JNR_POSIX@urls=http://repo1.maven.org/maven2/com/github/jnr/jnr-posix/3.0.0/jnr-posix-3.0.0.jar
+
+library@JNR_CONSTANTS@path=lib/jnr-constants-0.8.4.jar
+library@JNR_CONSTANTS@urls=http://repo1.maven.org/maven2/com/github/jnr/jnr-constants/0.8.4/jnr-constants-0.8.4.jar
+
+library@JNR_FFI@path=lib/jnr-ffi-1.0.4.jar
+library@JNR_FFI@urls=http://repo1.maven.org/maven2/com/github/jnr/jnr-ffi/1.0.4/jnr-ffi-1.0.4.jar
+
+library@JFFI@path=lib/jffi-1.2.1.jar
+library@JFFI@urls=http://repo1.maven.org/maven2/com/github/jnr/jffi/1.2.1/jffi-1.2.1.jar
+
+library@JFFI_NATIVE@path=lib/jffi-1.2.1-native.jar
+library@JFFI_NATIVE@urls=http://search.maven.org/remotecontent?filepath=com/github/jnr/jffi/1.2.1/jffi-1.2.1-native.jar
+
+library@JNR_X86ASM@path=lib/jnr-x86asm-1.0.2.jar
+library@JNR_X86ASM@urls=http://repo1.maven.org/maven2/com/github/jnr/jnr-x86asm/1.0.2/jnr-x86asm-1.0.2.jar
+
+library@ASM@path=lib/asm-4.0.jar
+library@ASM@urls=http://repo1.maven.org/maven2/org/ow2/asm/asm/4.0/asm-4.0.jar
+
+library@ASM_ANALYSIS@path=lib/asm-analysis-4.0.jar
+library@ASM_ANALYSIS@urls=http://repo1.maven.org/maven2/org/ow2/asm/asm-analysis/4.0/asm-analysis-4.0.jar
+
+library@ASM_COMMONS@path=lib/asm-commons-4.0.jar
+library@ASM_COMMONS@urls=http://repo1.maven.org/maven2/org/ow2/asm/asm-commons/4.0/asm-commons-4.0.jar
+
+library@ASM_TREE@path=lib/asm-tree-4.0.jar
+library@ASM_TREE@urls=http://repo1.maven.org/maven2/org/ow2/asm/asm-tree/4.0/asm-tree-4.0.jar
+
+library@ASM_UTIL@path=lib/asm-util-4.0.jar
+library@ASM_UTIL@urls=http://repo1.maven.org/maven2/org/ow2/asm/asm-util/4.0/asm-util-4.0.jar
 
 distribution@GRAAL@path=graal.jar
 distribution@GRAAL@dependencies=\
@@ -691,3 +732,43 @@
 project@com.oracle.graal.truffle.hotspot.amd64@javaCompliance=1.7
 project@com.oracle.graal.truffle.hotspot.amd64@annotationProcessors=com.oracle.graal.service.processor
 project@com.oracle.graal.truffle.hotspot.amd64@workingSets=Graal,Truffle
+
+# truffle.ruby.runtime
+project@com.oracle.truffle.ruby.runtime@subDir=graal
+project@com.oracle.truffle.ruby.runtime@sourceDirs=src
+project@com.oracle.truffle.ruby.runtime@dependencies=JRUBYSTDLIB,JNR_POSIX,JNR_CONSTANTS,JNR_FFI,JFFI,JFFI_NATIVE,JNR_X86ASM,ASM,ASM_ANALYSIS,ASM_COMMONS,ASM_TREE,ASM_UTIL,com.oracle.truffle.api
+project@com.oracle.truffle.ruby.runtime@javaCompliance=1.7
+project@com.oracle.truffle.ruby.runtime@workingSets=Truffle,Ruby
+
+# truffle.ruby.nodes
+project@com.oracle.truffle.ruby.nodes@subDir=graal
+project@com.oracle.truffle.ruby.nodes@sourceDirs=src
+project@com.oracle.truffle.ruby.nodes@dependencies=com.oracle.truffle.ruby.runtime,com.oracle.truffle.api.dsl
+project@com.oracle.truffle.ruby.nodes@checkstyle=com.oracle.truffle.ruby.runtime
+project@com.oracle.truffle.ruby.nodes@javaCompliance=1.7
+project@com.oracle.truffle.ruby.nodes@annotationProcessors=com.oracle.truffle.dsl.processor
+project@com.oracle.truffle.ruby.nodes@workingSets=Truffle,Ruby
+
+# truffle.ruby.parser
+project@com.oracle.truffle.ruby.parser@subDir=graal
+project@com.oracle.truffle.ruby.parser@sourceDirs=src
+project@com.oracle.truffle.ruby.parser@dependencies=JRUBYPARSER,com.oracle.truffle.ruby.nodes
+project@com.oracle.truffle.ruby.parser@checkstyle=com.oracle.truffle.ruby.runtime
+project@com.oracle.truffle.ruby.parser@javaCompliance=1.7
+project@com.oracle.truffle.ruby.parser@workingSets=Truffle,Ruby
+
+# truffle.ruby.shell
+project@com.oracle.truffle.ruby.shell@subDir=graal
+project@com.oracle.truffle.ruby.shell@sourceDirs=src
+project@com.oracle.truffle.ruby.shell@dependencies=JLINE,com.oracle.truffle.ruby.parser
+project@com.oracle.truffle.ruby.shell@checkstyle=com.oracle.truffle.ruby.runtime
+project@com.oracle.truffle.ruby.shell@javaCompliance=1.7
+project@com.oracle.truffle.ruby.shell@workingSets=Truffle,Ruby
+
+# truffle.ruby.test
+project@com.oracle.truffle.ruby.test@subDir=graal
+project@com.oracle.truffle.ruby.test@sourceDirs=src
+project@com.oracle.truffle.ruby.test@dependencies=com.oracle.truffle.ruby.parser,JUNIT
+project@com.oracle.truffle.ruby.test@checkstyle=com.oracle.truffle.ruby.runtime
+project@com.oracle.truffle.ruby.test@javaCompliance=1.7
+project@com.oracle.truffle.ruby.test@workingSets=Truffle,Ruby,Test