Browse files

Add stack locals, fix current exception logic

This adds the ability to have stack locals. These are local variables,
indexed purely by number, that don't follow ruby semantics. They can not
be closed over, and are allocated by adding extra slots at the end of
the operand stack.

The only use of these stack locals is to save and restore the current
exception when entering and exiting a rescue/ensure.
  • Loading branch information...
1 parent bb8f168 commit a60934805999370307dde5364d2c966fef854579 Evan Phoenix committed Dec 27, 2009
View
5 lib/compiler/ast/control_flow.rb
@@ -461,8 +461,9 @@ def bytecode(g, force=false)
g.push :nil
end
- if g.state.rescue?
- g.clear_exception
+ if lcl = g.state.rescue?
+ g.push_stack_local lcl
+ g.pop_exception
end
if g.state.block?
View
31 lib/compiler/ast/exceptions.rb
@@ -34,6 +34,11 @@ def bytecode(g)
# TODO: ?
g.new_label.set!
+ g.push_exception
+ current_exc = g.new_stack_local
+ g.set_stack_local current_exc
+ g.pop
+
g.state.push_ensure
@body.bytecode(g)
g.state.pop_ensure
@@ -42,9 +47,10 @@ def bytecode(g)
g.goto ok
ex.set!
+
g.push_exception
- g.state.push_rescue
+ g.state.push_rescue(current_exc)
@ensure.bytecode(g)
g.state.pop_rescue
g.pop
@@ -93,8 +99,11 @@ def bytecode(g)
els = g.new_label
done = g.new_label
- # Save the current exception into a local
+ # Save the current exception into a stack local
g.push_exception
+ current_exc = g.new_stack_local
+ g.set_stack_local current_exc
+ g.pop
g.retry.set!
ex = g.new_label
@@ -119,16 +128,17 @@ def bytecode(g)
g.pop_unwind
# Reset the outer exception
- g.swap
+ g.push_stack_local current_exc
g.pop_exception
+
g.goto current_break
end
g.break = current_break
end
ex.set!
- @rescue.bytecode(g, reraise, done)
+ @rescue.bytecode(g, reraise, done, current_exc)
reraise.set!
g.reraise
@@ -139,7 +149,7 @@ def bytecode(g)
end
done.set!
- g.swap
+ g.push_stack_local current_exc
g.pop_exception
end
g.pop_modifiers
@@ -197,7 +207,7 @@ def assignment?(node)
return true if value.kind_of? GlobalVariableAccess and value.name == :$!
end
- def bytecode(g, reraise, done)
+ def bytecode(g, reraise, done, current_exc)
pos(g)
body = g.new_label
@@ -229,18 +239,21 @@ def bytecode(g, reraise, done)
current_break = g.break
g.break = g.new_label
- g.state.push_rescue
+ g.state.push_rescue(current_exc)
@body.bytecode(g)
g.state.pop_rescue
+
g.clear_exception
g.goto done
if g.break.used?
g.break.set!
g.clear_exception
- g.swap
+ # Reset the outer exception
+ g.push_stack_local current_exc
g.pop_exception
+
if current_break
g.goto current_break
else
@@ -251,7 +264,7 @@ def bytecode(g, reraise, done)
g.break = current_break
if @next
if_false.set!
- @next.bytecode(g, reraise, done)
+ @next.bytecode(g, reraise, done, current_exc)
end
end
end
View
10 lib/compiler/ast/node.rb
@@ -133,22 +133,22 @@ class State
def initialize(scope)
@scope = scope
- @rescue = 0
@ensure = 0
@block = 0
@masgn = 0
+ @rescue = []
end
- def push_rescue
- @rescue += 1
+ def push_rescue(val)
+ @rescue.push(val)
end
def pop_rescue
- @rescue -= 1 if rescue?
+ @rescue.pop if rescue?
end
def rescue?
- @rescue > 0
+ @rescue.last
end
def push_ensure
View
10 lib/compiler/generator.rb
@@ -64,6 +64,8 @@ def initialize
@state = []
@generators = []
+
+ @stack_locals = 0
end
attr_reader :ip, :stream, :iseq, :literals
@@ -147,7 +149,7 @@ def package(klass)
cm.local_count = @local_count
cm.local_names = @local_names.to_tuple if @local_names
- cm.stack_size = @stack_size
+ cm.stack_size = @stack_size + @stack_locals
cm.file = @file
cm.name = @name
cm.primitive = @primitive
@@ -169,6 +171,12 @@ def set_label_positions
# Helpers
+ def new_stack_local
+ idx = @stack_locals
+ @stack_locals += 1
+ return idx
+ end
+
def add(instruction, arg1=nil, arg2=nil)
@stream << InstructionSet[instruction].bytecode
length = 1
View
1 lib/compiler/printers.rb
@@ -31,6 +31,7 @@ def match?(name)
def print_header(cm)
name = cm.name.inspect
size = (SEPARATOR_SIZE - name.size - 2) / 2
+ size = 1 if size <= 0
puts "\n#{"=" * size} #{name} #{"=" * (size + name.size % 2)}"
print "Arguments: "
print "#{cm.required_args} required, #{cm.total_args} total"
View
7 spec/compiler/defn_spec.rb
@@ -29,7 +29,10 @@ def m
ensure_noexc_lbl = d.new_label
d.setup_unwind ensure_exc_lbl
+
d.new_label.set!
+ exc = d.save_exception
+
d.push_literal :a
d.ensure_return
d.pop_unwind
@@ -38,7 +41,9 @@ def m
ensure_exc_lbl.set!
d.push_exception
d.push_literal :b
- d.clear_exception
+
+ d.restore_exception exc
+
d.ret
d.pop
d.pop_exception
View
4 spec/compiler/ensure_spec.rb
@@ -20,6 +20,8 @@
top.set!
+ g.save_exception
+
g.push_modifiers
g.push :nil
g.pop_modifiers
@@ -129,6 +131,8 @@
top.set!
+ saved = save_exception()
+
g.push 14
g.pop
g.push 2
View
12 spec/compiler/iter_spec.rb
@@ -385,8 +385,10 @@
top_lbl = d.new_label
top_lbl.set!
+ e_saved = d.save_exception
d.push_modifiers
- d.push_exception
+
+ r_saved = d.save_exception
retry_lbl.set!
@@ -427,8 +429,8 @@
reraise_lbl.set!
d.clear_exception
- d.swap
- d.pop_exception
+
+ d.restore_exception(r_saved)
d.raise_break
next_lbl.set!
@@ -437,8 +439,8 @@
else_lbl.set!
last_lbl.set!
- d.swap
- d.pop_exception
+
+ d.restore_exception r_saved
d.pop_modifiers
d.pop_unwind
View
52 spec/compiler/rescue_spec.rb
@@ -317,7 +317,8 @@
body = g.new_label
g.push_modifiers
- g.push_exception
+
+ saved = g.save_exception
rr.set!
@@ -353,8 +354,7 @@
last.set!
- g.swap
- g.pop_exception
+ g.restore_exception saved
g.pop_modifiers
end
end
@@ -374,7 +374,7 @@
body = g.new_label
g.push_modifiers
- g.push_exception
+ saved = g.save_exception
rr.set!
@@ -408,8 +408,7 @@
fin.set!
last.set!
- g.swap
- g.pop_exception
+ g.restore_exception saved
g.pop_modifiers
end
end
@@ -429,7 +428,7 @@
body = g.new_label
g.push_modifiers
- g.push_exception
+ saved = g.save_exception
rr.set!
@@ -468,8 +467,7 @@
fin.set!
last.set!
- g.swap
- g.pop_exception
+ g.restore_exception saved
g.pop_modifiers
end
end
@@ -490,7 +488,7 @@
body = g.new_label
g.push_modifiers
- g.push_exception
+ saved = g.save_exception
rr.set!
@@ -529,8 +527,7 @@
fin.set!
last.set!
- g.swap
- g.pop_exception
+ g.restore_exception saved
g.pop_modifiers
end
end
@@ -551,7 +548,7 @@
body = g.new_label
g.push_modifiers
- g.push_exception
+ saved = g.save_exception
rr.set!
@@ -593,8 +590,7 @@
fin.set!
last.set!
- g.swap
- g.pop_exception
+ g.restore_exception saved
g.pop_modifiers
end
end
@@ -614,7 +610,7 @@
body = g.new_label
g.push_modifiers
- g.push_exception
+ saved = g.save_exception
rr.set!
@@ -636,7 +632,7 @@
g.goto rr
body.set!
g.push :nil
- g.clear_exception
+ g.restore_exception saved
g.ret
g.clear_exception
g.goto last
@@ -648,8 +644,7 @@
fin.set!
last.set!
- g.swap
- g.pop_exception
+ g.restore_exception saved
g.pop_modifiers
end
end
@@ -678,7 +673,8 @@
g.push 2
when :StandardError
g.push 3
- g.clear_exception
+ g.push_stack_local 1
+ g.pop_exception
g.ret
end
end
@@ -751,7 +747,7 @@ def x
bottom = g.new_label
g.push_modifiers
- g.push_exception
+ saved = g.save_exception
retry_lbl.set!
g.setup_unwind exc_lbl
@@ -801,8 +797,8 @@ def x
noexc_lbl.set!
done.set!
- g.swap
- g.pop_exception
+
+ g.restore_exception saved
g.pop_modifiers
end
end
@@ -831,7 +827,7 @@ def x
bottom = g.new_label
g.push_modifiers
- g.push_exception
+ saved = g.save_exception
retry_lbl.set! # 1
g.setup_unwind exc_lbl
@@ -879,17 +875,17 @@ def x
cur_brk_lbl.set! # 9
g.clear_exception
- g.swap
- g.pop_exception
+
+ g.restore_exception saved
+
g.raise_break
reraise_lbl.set! # 10
g.reraise
noexc_lbl.set! # 11
done.set! # 12
- g.swap
- g.pop_exception
+ g.restore_exception saved
g.pop_modifiers
end
end
View
19 spec/compiler/while_spec.rb
@@ -285,7 +285,8 @@
# redo
g.new_label.set! # 2
g.push_modifiers
- g.push_exception
+ saved = g.save_exception
+
retry_lbl.set! # 3
g.setup_unwind exc_lbl
@@ -301,8 +302,8 @@
cur_brk_lbl.set! # 5
g.pop_unwind
- g.swap
- g.pop_exception
+
+ g.restore_exception saved
g.goto break_lbl
exc_lbl.set! # 6
@@ -322,8 +323,7 @@
noexc_lbl.set! # 9
done.set! # 10
- g.swap
- g.pop_exception
+ g.restore_exception saved
g.pop_modifiers
g.pop
@@ -370,7 +370,7 @@
# redo
g.new_label.set! # 2
g.push_modifiers
- g.push_exception
+ saved = g.save_exception
retry_lbl.set! # 3
g.setup_unwind exc_lbl
@@ -398,17 +398,16 @@
cur_brk_lbl.set! # 7
g.clear_exception
- g.swap
- g.pop_exception
+
+ g.restore_exception saved
g.goto break_lbl
reraise_lbl.set! # 8
g.reraise
noexc_lbl.set! # 9
done.set! # 10
- g.swap
- g.pop_exception
+ g.restore_exception saved
g.pop_modifiers
g.pop
View
33 spec/custom/helpers/generator.rb
@@ -93,6 +93,13 @@ def initialize
@slot = 0
@g = self
@state = []
+ @stack_locals = 0
+ end
+
+ def new_stack_local
+ idx = @stack_locals
+ @stack_locals += 1
+ return idx
end
def state
@@ -115,6 +122,8 @@ def convert_to_ary(ary)
ary.map do |item|
if item.respond_to? :to_ary
convert_to_ary item.to_ary
+ elsif item.kind_of? TestGenerator
+ item.to_a
else
item
end
@@ -446,6 +455,20 @@ def in_module(name)
g.send :__module_init__, 0
end
+ def save_exception
+ idx = new_stack_local
+ push_exception
+ set_stack_local idx
+ pop
+
+ return idx
+ end
+
+ def restore_exception(idx)
+ push_stack_local idx
+ pop_exception
+ end
+
def in_rescue(*klasses)
jump_retry = g.new_label
jump_else = g.new_label
@@ -467,10 +490,13 @@ def in_rescue(*klasses)
jump_top = g.new_label
jump_top.set!
+
+ save_exception
end
g.push_modifiers
- g.push_exception
+
+ r_saved = save_exception
jump_retry.set!
@@ -514,8 +540,9 @@ def in_rescue(*klasses)
yield :else
jump_last.set!
- g.swap
- g.pop_exception
+
+ restore_exception r_saved
+
g.pop_modifiers
if has_ensure then
View
2 vm/instructions.cpp
@@ -52,6 +52,8 @@ using namespace rubinius;
#define stack_position(where) (STACK_PTR = call_frame->stk + where)
#define stack_calculate_sp() (STACK_PTR - call_frame->stk)
+#define stack_local(which) call_frame->stk[vmm->stack_size - which - 1]
+
#define next_int ((opcode)(stream[call_frame->inc_ip()]))
#define both_fixnum_p(_p1, _p2) ((uintptr_t)(_p1) & (uintptr_t)(_p2) & TAG_FIXNUM)
View
10 vm/instructions.def
@@ -622,7 +622,7 @@ end
instruction pop_exception() [ exception -- ]
Object* top = stack_pop();
if(top->nil_p()) {
- state->thread_state()->clear_exception();
+ state->thread_state()->clear_exception(true);
} else {
state->thread_state()->set_exception(state, top);
}
@@ -2392,3 +2392,11 @@ end
instruction push_undef() [ -- value ]
stack_push(G(undefined));
end
+
+instruction push_stack_local(which) [ -- value ]
+ stack_push(stack_local(which));
+end
+
+instruction set_stack_local(which) [ value -- value ]
+ stack_local(which) = stack_top();
+end
View
8 vm/llvm/jit_operations.hpp
@@ -338,9 +338,13 @@ namespace rubinius {
// Stack manipulations
//
+ Value* stack_slot_position(int which) {
+ assert(which >= 0 && which < vmmethod()->stack_size);
+ return b().CreateConstGEP1_32(stack_, which, "stack_pos");
+ }
+
Value* stack_ptr() {
- assert(sp_ >= 0 && sp_ < vmmethod()->stack_size);
- return b().CreateConstGEP1_32(stack_, sp_, "stack_pos");
+ return stack_slot_position(sp_);
}
void set_sp(int sp) {
View
2 vm/llvm/jit_util.cpp
@@ -726,7 +726,7 @@ extern "C" {
return Qnil;
}
- Object* rbx_pop_exception(STATE, Object* top) {
+ Object* rbx_pop_exception(STATE, CallFrame* call_frame, Object* top) {
if(top->nil_p()) {
state->thread_state()->clear_exception();
} else {
View
15 vm/llvm/jit_visit.hpp
@@ -1119,6 +1119,16 @@ namespace rubinius {
return b().CreateGEP(vars, idx2, idx2+3, "local_pos");
}
+ void visit_push_stack_local(opcode which) {
+ Value* pos = stack_slot_position(vmmethod()->stack_size - which - 1);
+ stack_push(b().CreateLoad(pos, "stack_local"));
+ }
+
+ void visit_set_stack_local(opcode which) {
+ Value* pos = stack_slot_position(vmmethod()->stack_size - which - 1);
+ b().CreateStore(stack_top(), pos);
+ }
+
void visit_push_local(opcode which) {
Value* idx2[] = {
ConstantInt::get(ls_->Int32Ty, 0),
@@ -2621,15 +2631,16 @@ namespace rubinius {
std::vector<const Type*> types;
types.push_back(VMTy);
+ types.push_back(CallFrameTy);
types.push_back(ObjType);
FunctionType* ft = FunctionType::get(ObjType, types, false);
Function* func = cast<Function>(
module_->getOrInsertFunction("rbx_pop_exception", ft));
- Value* call_args[] = { vm_, stack_pop() };
+ Value* call_args[] = { vm_, call_frame_, stack_pop() };
- b().CreateCall(func, call_args, call_args+2);
+ b().CreateCall(func, call_args, call_args+3);
}
void visit_find_const(opcode which) {
View
11 vm/thread_state.cpp
@@ -23,6 +23,17 @@ namespace rubinius {
}
}
+ void ThreadState::clear_exception(bool all) {
+ if(raise_reason_ == cNone) return;
+ if(!all && raise_reason_ != cException) {
+ std::cout << "WARNING: clearing non exception raise reason!\n";
+ }
+ raise_value_.set(Qnil);
+ raise_reason_ = cNone;
+ destination_scope_.set(Qnil);
+ throw_dest_.set(Qnil);
+ }
+
void ThreadState::set_exception(STATE, Object* obj) {
if(obj->kind_of_p(state, G(exc_vm_internal))) {
Object* reason = obj->get_ivar(state, state->symbol("reason"));
View
11 vm/thread_state.hpp
@@ -41,16 +41,7 @@ namespace rubinius {
return throw_dest_.get();
}
- void clear_exception(bool all = false) {
- if(raise_reason_ == cNone) return;
- if(!all && raise_reason_ != cException) {
- std::cout << "WARNING: clearing non exception raise reason!\n";
- }
- raise_value_.set(Qnil);
- raise_reason_ = cNone;
- destination_scope_.set(Qnil);
- throw_dest_.set(Qnil);
- }
+ void clear_exception(bool all = false);
Object* as_object(STATE);
void set_exception(STATE, Object* obj);

0 comments on commit a609348

Please sign in to comment.