Skip to content

Commit

Permalink
introduced EvalFrame
Browse files Browse the repository at this point in the history
  • Loading branch information
iliabylich committed Dec 7, 2019
1 parent c26b3b7 commit 1b0a7a8
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 4 deletions.
43 changes: 41 additions & 2 deletions bin/my.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

class RubyRb
REAL_EVAL = Kernel.instance_method(:eval)
REAL_INSTANCE_EVAL = BasicObject.instance_method(:instance_eval)
REAL_MODULE_EVAL = Module.instance_method(:module_eval)
REAL_CLASS_EVAL = Module.instance_method(:class_eval)
REAL_KERNEL_LAMBDA = Kernel.instance_method(:lambda)

def self.require(file)
Expand Down Expand Up @@ -119,10 +122,46 @@ def require_relative(filepath)
rescue LoadError
binding.irb
end

def eval(code)
iseq = RubyVM::InstructionSequence.compile(code).to_a
iseq[9] = :eval
VM.instance.execute(iseq, _self: self)
end
end
end

def eval(code)
RubyRb.eval(code)
class BasicObject
def instance_eval(code = nil, &block)
if code
iseq = ::RubyVM::InstructionSequence.compile(code).to_a
iseq[9] = :eval
::VM.instance.execute(iseq, _self: self)
else
::RubyRb::REAL_INSTANCE_EVAL.bind(self).call(&block)
end
end
end

class Module
def module_eval(code = nil, &block)
if code
iseq = ::RubyVM::InstructionSequence.compile(code).to_a
iseq[9] = :eval
::VM.instance.execute(iseq, _self: self)
else
::RubyRb::REAL_MODULE_EVAL.bind(self).call(&block)
end
end

def class_eval(code = nil, &block)
if code
iseq = ::RubyVM::InstructionSequence.compile(code).to_a
iseq[9] = :eval
::VM.instance.execute(iseq, _self: self)
else
::RubyRb::REAL_CLASS_EVAL.bind(self).call(&block)
end
end
end

Expand Down
16 changes: 14 additions & 2 deletions executor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,17 @@ def execute_opt_plus(_)
def execute_opt_send_without_block((options, _flag))
mid = options[:mid]

if current_frame.eval? &&
(options[:flag] & VM_CALL_VCALL).nonzero? &&
(parent = current_frame.parent_frame) &&
parent.locals.declared?(name: mid)

# x = 1; eval("x") - x is a VCALL in eval, so maybe it's a local variable of the parent frame
result = parent.locals.find(name: mid).value
push(result)
return
end

if mid == :module_function && options[:orig_argc] == 0
current_frame.open_module_function_section!
push(nil)
Expand Down Expand Up @@ -636,8 +647,9 @@ def execute_getblockparam((_, level))
push(frame.block)
end

def execute_getblockparamproxy(args)
push(current_frame.block)
def execute_getblockparamproxy((_, level))
frame = level.times.inject(current_frame) { |f| f.parent_frame }
push(frame.block)
end

def execute_nop(*); end
Expand Down
6 changes: 6 additions & 0 deletions vm.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ def push_frame(iseq, **payload)
@frame_stack.push_top(
iseq: iseq
)
when :eval
@frame_stack.push_eval(
iseq: iseq,
parent_frame: current_frame,
_self: payload[:_self]
)
when :class
case
when iseq.name.start_with?('<module')
Expand Down
4 changes: 4 additions & 0 deletions vm/frame_stack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ def push_ensure(**args)
push EnsureFrame.new(**args)
end

def push_eval(**args)
push EvalFrame.new(**args)
end

def pop
@stack.pop
end
Expand Down
1 change: 1 addition & 0 deletions vm/frames.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@
require_relative './frames/block_frame'
require_relative './frames/ensure_frame'
require_relative './frames/rescue_frame'
require_relative './frames/eval_frame'

require_relative './frame_stack'
18 changes: 18 additions & 0 deletions vm/frames/eval_frame.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
EvalFrame = FrameClass.new do
attr_reader :parent_frame

def initialize(parent_frame:, _self:)
@parent_frame = parent_frame

self._self = _self
self.nesting = parent_frame.nesting
end

def pretty_name
"EVAL"
end

def eval?
true
end
end
1 change: 1 addition & 0 deletions vm/frames/factory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def pretty_name
def can_return?; false; end
def can_do_next?; false; end
def can_yield?; false; end
def eval?; false; end

def prepare; end

Expand Down

0 comments on commit 1b0a7a8

Please sign in to comment.