Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add support in the jit for instance variables in VM objects

Before this was following the slow path, even though we can staticly
compute the offsets and write these values directly. This change adds
support for that, so it makes for example setting @shared in a String
much faster.
  • Loading branch information...
commit e1d5b5361968570f8d6f90de2fb406c5763eb995 1 parent 829eef1
@dbussink dbussink authored
View
2  vm/codegen/field_extract.rb
@@ -1107,8 +1107,10 @@ def write_if_new(path)
fields = cpp.all_fields
f.puts " ti->slot_accessors.resize(#{fields.size});\n"
+ f.puts " ti->slot_types.resize(#{fields.size});\n"
fields.each do |name, type, idx|
f.puts " ti->slots[state->symbol(\"@#{name}\")->index()] = #{idx};"
+ f.puts " ti->slot_types[#{idx}] = #{type}::type;"
f.puts " ti->slot_accessors[#{idx}] = Primitives::resolve_primitive(state, state->symbol(\"access_#{n}_#{name}\"));"
end
f.puts " ti->populate_slot_locations();"
View
65 vm/llvm/jit_operations.hpp
@@ -1083,6 +1083,71 @@ namespace rubinius {
return create_load(pos, "field");
}
+ void set_object_type_slot(Value* obj, int field, int offset, object_type type, Value* val) {
+ BasicBlock* not_nil = new_block("not_nil");
+ BasicBlock* cont = new_block("type_verified");
+ BasicBlock* failure = new_block("type_unverified");
+ BasicBlock* done = new_block("done");
+ BasicBlock* ref = new_block("is_reference");
+
+
+ create_conditional_branch(cont, not_nil, check_is_immediate(val, cNil));
+ set_block(not_nil);
+
+ switch(type) {
+ case Fixnum::type:
+ case Integer::type:
+ // Optimize here for the common case that the integer is a fixnum
+ create_conditional_branch(cont, failure, check_is_fixnum(val));
+ break;
+ case Symbol::type:
+ create_conditional_branch(cont, failure, check_is_symbol(val));
+ break;
+ case Object::type:
+ // Any type here is a valid type, so no need for a type check
+ create_branch(cont);
+ break;
+ default:
+ create_conditional_branch(ref, failure, check_is_reference(val));
+ set_block(ref);
+ create_conditional_branch(cont, failure, check_type_bits(val, type));
+ break;
+ }
+
+ set_block(cont);
+ set_object_slot(obj, offset, val);
+ create_branch(done);
+
+ set_block(failure);
+
+ Signature sig(ls_, ObjType);
+
+ sig << StateTy;
+ sig << ObjType;
+ sig << ls_->Int32Ty;
+ sig << ObjType;
+
+ Value* call_args[] = {
+ state_,
+ obj,
+ cint(field),
+ val
+ };
+
+ Value* ret = sig.call("rbx_set_my_field", call_args, 4, "field", b());
+ check_for_exception(ret, false);
+
+ failure = current_block();
+
+ create_branch(done);
+
+ set_block(done);
+
+ PHINode* phi = b().CreatePHI(ObjType, 2, "push_ivar");
+ phi->addIncoming(val, cont);
+ phi->addIncoming(ret, failure);
+ }
+
void set_object_slot(Value* obj, int offset, Value* val) {
assert(offset % sizeof(Object*) == 0);
View
113 vm/llvm/jit_visit.hpp
@@ -3384,8 +3384,11 @@ namespace rubinius {
}
void visit_set_ivar(opcode which) {
+ Value* self = get_self();
+ Value* ivar = stack_top();
Symbol* name = as<Symbol>(literal(which));
+ set_has_side_effects();
if(Class* klass = try_as<Class>(info().self_class())) {
if(ls_->config().jit_inline_debug) {
@@ -3393,11 +3396,19 @@ namespace rubinius {
<< ls_->symbol_debug_str(name);
}
- // slot ivars (Array#@size for example) have type checks, so use the slow
- // path for now.
+ TypeInfo* ti = klass->type_info();
+ TypeInfo::Slots::iterator it = ti->slots.find(name->index());
- Value* self = get_self();
+ if(it != ti->slots.end()) {
+ int field = it->second;
+ int offset = ti->slot_locations[field];
+ set_object_type_slot(self, field, offset, ti->slot_types[field], ivar);
+ if(ls_->config().jit_inline_debug) {
+ ls_->log() << " (slot: " << it->second << ")\n";
+ }
+ return;
+ }
LookupTable* pii = klass->packed_ivar_info();
if(!pii->nil_p()) {
bool found = false;
@@ -3407,7 +3418,7 @@ namespace rubinius {
int index = which->to_native();
int offset = sizeof(Object) + (sizeof(Object*) * index);
- set_object_slot(self, offset, stack_top());
+ set_object_slot(self, offset, ivar);
if(ls_->config().jit_inline_debug) {
ls_->log() << " (packed index: " << index << ", " << offset << ")\n";
@@ -3426,7 +3437,6 @@ namespace rubinius {
<< ls_->symbol_debug_str(name) << "\n";
}
- set_has_side_effects();
Signature sig(ls_, ObjType);
@@ -3436,14 +3446,12 @@ namespace rubinius {
sig << ObjType;
sig << ObjType;
- Value* self = get_self();
-
Value* call_args[] = {
state_,
call_frame_,
self,
- constant(as<Symbol>(literal(which))),
- stack_top()
+ constant(name),
+ ivar
};
Value* ret = sig.call("rbx_set_ivar", call_args, 5, "ivar", b());
@@ -3451,45 +3459,80 @@ namespace rubinius {
}
void visit_push_my_field(opcode which) {
- Signature sig(ls_, ObjType);
+ Value* self = get_self();
- sig << StateTy;
- sig << ObjType;
- sig << ls_->Int32Ty;
+ if(Class* klass = try_as<Class>(info().self_class())) {
- Value* self = get_self();
+ if(ls_->config().jit_inline_debug) {
+ context().inline_log("inline field read");
+ ls_->log() << " (slot: " << which << ")\n";
+ }
- Value* call_args[] = {
- state_,
- self,
- cint(which)
- };
+ TypeInfo* ti = klass->type_info();
+ int offset = ti->slot_locations[which];
+ stack_push(get_object_slot(self, offset));
+ } else {
- Value* val = sig.call("rbx_push_my_field", call_args, 3, "field", b());
- check_for_exception(val);
- stack_push(val);
+ if(ls_->config().jit_inline_debug) {
+ context().inline_log("inline field read slow path");
+ ls_->log() << " (slot: " << which << ")\n";
+ }
+ Signature sig(ls_, ObjType);
+
+ sig << StateTy;
+ sig << ObjType;
+ sig << ls_->Int32Ty;
+
+ Value* call_args[] = {
+ state_,
+ self,
+ cint(which)
+ };
+
+ Value* val = sig.call("rbx_push_my_field", call_args, 3, "field", b());
+ check_for_exception(val);
+ stack_push(val);
+ }
}
void visit_store_my_field(opcode which) {
set_has_side_effects();
- Signature sig(ls_, ObjType);
+ Value* self = get_self();
+ Value* ivar = stack_top();
- sig << StateTy;
- sig << ObjType;
- sig << ls_->Int32Ty;
- sig << ObjType;
+ if(Class* klass = try_as<Class>(info().self_class())) {
- Value* self = get_self();
+ if(ls_->config().jit_inline_debug) {
+ context().inline_log("inline field write");
+ ls_->log() << " (slot: " << which << ")\n";
+ }
- Value* call_args[] = {
- state_,
- self,
- cint(which),
- stack_top()
- };
+ TypeInfo* ti = klass->type_info();
+ int offset = ti->slot_locations[which];
+ set_object_type_slot(self, which, offset, ti->slot_types[which], ivar);
+ } else {
+
+ if(ls_->config().jit_inline_debug) {
+ context().inline_log("inline write slow path");
+ ls_->log() << " (slot: " << which << ")\n";
+ }
+ Signature sig(ls_, ObjType);
- sig.call("rbx_set_my_field", call_args, 4, "field", b());
+ sig << StateTy;
+ sig << ObjType;
+ sig << ls_->Int32Ty;
+ sig << ObjType;
+
+ Value* call_args[] = {
+ state_,
+ self,
+ cint(which),
+ ivar
+ };
+
+ sig.call("rbx_set_my_field", call_args, 4, "field", b());
+ }
}
void visit_shift_array() {
View
2  vm/type_info.cpp
@@ -26,8 +26,8 @@ namespace rubinius {
: state_(NULL)
, instance_size(sizeof(Object))
, slots()
- , type(type)
, type_name()
+ , type(type)
, allow_user_allocate(true)
{}
View
4 vm/type_info.hpp
@@ -38,6 +38,7 @@ namespace rubinius {
public: // Types
typedef std::map<native_int, long> Slots;
+ typedef std::vector<object_type> SlotTypes;
typedef std::vector<executor> AccessorPrimitives;
typedef std::vector<uintptr_t> SlotLocations;
@@ -49,10 +50,11 @@ namespace rubinius {
size_t instance_size;
static size_t instance_sizes[(int)LastObjectType];
Slots slots;
+ SlotTypes slot_types;
AccessorPrimitives slot_accessors;
SlotLocations slot_locations;
- object_type type;
std::string type_name;
+ object_type type;
bool allow_user_allocate;
public: /* Class initializers */
Please sign in to comment.
Something went wrong with that request. Please try again.