Skip to content

Commit

Permalink
Feature #7035
Browse files Browse the repository at this point in the history
* compile.c (defined_expr), insns.def (defined): share single frozen
  strings.  [EXPERIMENTAL] [ruby-core:47558][Feature #7035]
* iseq.c (rb_iseq_defined_string): make expression strings.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37025 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
  • Loading branch information
nobu committed Sep 24, 2012
1 parent 8ac52a9 commit 2314b80
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 29 deletions.
7 changes: 7 additions & 0 deletions ChangeLog
@@ -1,3 +1,10 @@
Mon Sep 24 17:36:51 2012 Nobuyoshi Nakada <nobu@ruby-lang.org>

* compile.c (defined_expr), insns.def (defined): share single frozen
strings. [EXPERIMENTAL] [ruby-core:47558][Feature #7035]

* iseq.c (rb_iseq_defined_string): make expression strings.

Mon Sep 24 11:22:36 2012 NARUSE, Yui <naruse@ruby-lang.org> Mon Sep 24 11:22:36 2012 NARUSE, Yui <naruse@ruby-lang.org>


* tool/merger.rb: add --ticket option to add ticket number. * tool/merger.rb: add --ticket option to add ticket number.
Expand Down
24 changes: 11 additions & 13 deletions compile.c
Expand Up @@ -2701,23 +2701,23 @@ static int
defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *ret, defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *ret,
NODE *node, LABEL **lfinish, VALUE needstr) NODE *node, LABEL **lfinish, VALUE needstr)
{ {
const char *estr = 0; enum defined_type expr_type = 0;
enum node_type type; enum node_type type;


switch (type = nd_type(node)) { switch (type = nd_type(node)) {


/* easy literals */ /* easy literals */
case NODE_NIL: case NODE_NIL:
estr = "nil"; expr_type = DEFINED_NIL;
break; break;
case NODE_SELF: case NODE_SELF:
estr = "self"; expr_type = DEFINED_SELF;
break; break;
case NODE_TRUE: case NODE_TRUE:
estr = "true"; expr_type = DEFINED_TRUE;
break; break;
case NODE_FALSE: case NODE_FALSE:
estr = "false"; expr_type = DEFINED_FALSE;
break; break;


case NODE_ARRAY:{ case NODE_ARRAY:{
Expand All @@ -2738,13 +2738,13 @@ defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *ret,
case NODE_AND: case NODE_AND:
case NODE_OR: case NODE_OR:
default: default:
estr = "expression"; expr_type = DEFINED_EXPR;
break; break;


/* variables */ /* variables */
case NODE_LVAR: case NODE_LVAR:
case NODE_DVAR: case NODE_DVAR:
estr = "local-variable"; expr_type = DEFINED_LVAR;
break; break;


case NODE_IVAR: case NODE_IVAR:
Expand Down Expand Up @@ -2866,16 +2866,14 @@ defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *ret,
case NODE_CDECL: case NODE_CDECL:
case NODE_CVDECL: case NODE_CVDECL:
case NODE_CVASGN: case NODE_CVASGN:
estr = "assignment"; expr_type = DEFINED_ASGN;
break; break;
} }


if (estr != 0) { if (expr_type) {
if (needstr != Qfalse) { if (needstr != Qfalse) {
VALUE str = rb_str_new2(estr); VALUE str = rb_iseq_defined_string(expr_type);
hide_obj(str); ADD_INSN1(ret, nd_line(node), putobject, str);
ADD_INSN1(ret, nd_line(node), putstring, str);
iseq_add_mark_object_compile_time(iseq, str);
} }
else { else {
ADD_INSN1(ret, nd_line(node), putobject, Qtrue); ADD_INSN1(ret, nd_line(node), putobject, Qtrue);
Expand Down
24 changes: 12 additions & 12 deletions insns.def
Expand Up @@ -716,44 +716,44 @@ defined
(VALUE val) (VALUE val)
{ {
VALUE klass; VALUE klass;
const char *expr_type = 0; enum defined_type expr_type = 0;
enum defined_type type = (enum defined_type)op_type; enum defined_type type = (enum defined_type)op_type;


val = Qnil; val = Qnil;


switch (type) { switch (type) {
case DEFINED_IVAR: case DEFINED_IVAR:
if (rb_ivar_defined(GET_SELF(), SYM2ID(obj))) { if (rb_ivar_defined(GET_SELF(), SYM2ID(obj))) {
expr_type = "instance-variable"; expr_type = DEFINED_IVAR;
} }
break; break;
case DEFINED_IVAR2: case DEFINED_IVAR2:
klass = vm_get_cbase(GET_ISEQ(), GET_EP()); klass = vm_get_cbase(GET_ISEQ(), GET_EP());
break; break;
case DEFINED_GVAR: case DEFINED_GVAR:
if (rb_gvar_defined(rb_global_entry(SYM2ID(obj)))) { if (rb_gvar_defined(rb_global_entry(SYM2ID(obj)))) {
expr_type = "global-variable"; expr_type = DEFINED_GVAR;
} }
break; break;
case DEFINED_CVAR: case DEFINED_CVAR:
{ {
NODE *cref = rb_vm_get_cref(GET_ISEQ(), GET_EP()); NODE *cref = rb_vm_get_cref(GET_ISEQ(), GET_EP());
klass = vm_get_cvar_base(cref, GET_CFP()); klass = vm_get_cvar_base(cref, GET_CFP());
if (rb_cvar_defined(klass, SYM2ID(obj))) { if (rb_cvar_defined(klass, SYM2ID(obj))) {
expr_type = "class variable"; expr_type = DEFINED_CVAR;
} }
break; break;
} }
case DEFINED_CONST: case DEFINED_CONST:
klass = v; klass = v;
if (vm_get_ev_const(th, GET_ISEQ(), klass, SYM2ID(obj), 1)) { if (vm_get_ev_const(th, GET_ISEQ(), klass, SYM2ID(obj), 1)) {
expr_type = "constant"; expr_type = DEFINED_CONST;
} }
break; break;
case DEFINED_FUNC: case DEFINED_FUNC:
klass = CLASS_OF(v); klass = CLASS_OF(v);
if (rb_method_boundp(klass, SYM2ID(obj), 0)) { if (rb_method_boundp(klass, SYM2ID(obj), 0)) {
expr_type = "method"; expr_type = DEFINED_METHOD;
} }
break; break;
case DEFINED_METHOD:{ case DEFINED_METHOD:{
Expand All @@ -765,7 +765,7 @@ defined
if (!((me->flag & NOEX_PROTECTED) && if (!((me->flag & NOEX_PROTECTED) &&
!rb_obj_is_kind_of(GET_SELF(), !rb_obj_is_kind_of(GET_SELF(),
rb_class_real(klass)))) { rb_class_real(klass)))) {
expr_type = "method"; expr_type = DEFINED_METHOD;
} }
} }
} }
Expand All @@ -776,13 +776,13 @@ defined
args[0] = obj; args[1] = Qfalse; args[0] = obj; args[1] = Qfalse;
r = rb_check_funcall(v, rb_intern("respond_to_missing?"), 2, args); r = rb_check_funcall(v, rb_intern("respond_to_missing?"), 2, args);
if (r != Qundef && RTEST(r)) if (r != Qundef && RTEST(r))
expr_type = "method"; expr_type = DEFINED_METHOD;
} }
break; break;
} }
case DEFINED_YIELD: case DEFINED_YIELD:
if (GET_BLOCK_PTR()) { if (GET_BLOCK_PTR()) {
expr_type = "yield"; expr_type = DEFINED_YIELD;
} }
break; break;
case DEFINED_ZSUPER:{ case DEFINED_ZSUPER:{
Expand All @@ -791,15 +791,15 @@ defined
VALUE klass = vm_search_normal_superclass(GET_CFP()->klass); VALUE klass = vm_search_normal_superclass(GET_CFP()->klass);
ID id = me->def ? me->def->original_id : me->called_id; ID id = me->def ? me->def->original_id : me->called_id;
if (rb_method_boundp(klass, id, 0)) { if (rb_method_boundp(klass, id, 0)) {
expr_type = "super"; expr_type = DEFINED_ZSUPER;
} }
} }
break; break;
} }
case DEFINED_REF:{ case DEFINED_REF:{
val = vm_getspecial(th, GET_LEP(), Qfalse, FIX2INT(obj)); val = vm_getspecial(th, GET_LEP(), Qfalse, FIX2INT(obj));
if (val != Qnil) { if (val != Qnil) {
expr_type = "global-variable"; expr_type = DEFINED_GVAR;
} }
break; break;
} }
Expand All @@ -809,7 +809,7 @@ defined
} }
if (expr_type != 0) { if (expr_type != 0) {
if (needstr != Qfalse) { if (needstr != Qfalse) {
val = rb_str_new2(expr_type); val = rb_iseq_defined_string(expr_type);
} }
else { else {
val = Qtrue; val = Qtrue;
Expand Down
41 changes: 41 additions & 0 deletions iseq.c
Expand Up @@ -18,6 +18,8 @@
#include "vm_core.h" #include "vm_core.h"
#include "iseq.h" #include "iseq.h"


#define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))

#include "insns.inc" #include "insns.inc"
#include "insns_info.inc" #include "insns_info.inc"


Expand Down Expand Up @@ -1747,6 +1749,45 @@ rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
return args; return args;
} }


VALUE
rb_iseq_defined_string(enum defined_type type)
{
static const char expr_names[][18] = {
"nil",
"instance-variable",
"local-variable",
"global-variable",
"class variable",
"constant",
"method",
"yield",
"super",
"self",
"true",
"false",
"assignment",
"expression",
};
const char *estr;
VALUE *defs, str;

if ((unsigned)(type - 1) >= (unsigned)numberof(expr_names)) return 0;
estr = expr_names[type - 1];
if (!estr[0]) return 0;
defs = GET_VM()->defined_strings;
if (!defs) {
defs = ruby_xcalloc(numberof(expr_names), sizeof(VALUE));
GET_VM()->defined_strings = defs;
}
str = defs[type];
if (!str) {
str = rb_str_new_cstr(estr);;
OBJ_FREEZE(str);
defs[type] = str;
}
return str;
}

/* ruby2cext */ /* ruby2cext */


VALUE VALUE
Expand Down
15 changes: 12 additions & 3 deletions iseq.h
Expand Up @@ -106,18 +106,27 @@ struct iseq_compile_data {
/* defined? */ /* defined? */


enum defined_type { enum defined_type {
DEFINED_IVAR = 1, DEFINED_NIL = 1,
DEFINED_IVAR2, DEFINED_IVAR,
DEFINED_LVAR,
DEFINED_GVAR, DEFINED_GVAR,
DEFINED_CVAR, DEFINED_CVAR,
DEFINED_CONST, DEFINED_CONST,
DEFINED_METHOD, DEFINED_METHOD,
DEFINED_YIELD, DEFINED_YIELD,
DEFINED_REF,
DEFINED_ZSUPER, DEFINED_ZSUPER,
DEFINED_SELF,
DEFINED_TRUE,
DEFINED_FALSE,
DEFINED_ASGN,
DEFINED_EXPR,
DEFINED_IVAR2,
DEFINED_REF,
DEFINED_FUNC DEFINED_FUNC
}; };


VALUE rb_iseq_defined_string(enum defined_type type);

#if defined __GNUC__ && __GNUC__ >= 4 #if defined __GNUC__ && __GNUC__ >= 4
#pragma GCC visibility pop #pragma GCC visibility pop
#endif #endif
Expand Down
6 changes: 6 additions & 0 deletions test/ruby/test_defined.rb
Expand Up @@ -86,6 +86,12 @@ def test_defined
assert_equal nil, defined?($2) assert_equal nil, defined?($2)
end end


def test_defined_impl_specific
feature7035 = '[ruby-core:47558]' # not spec
assert_operator(defined?(Foo), :frozen?, feature7035)
assert_same(defined?(Foo), defined?(Array), feature7035)
end

class TestAutoloadedSuperclass class TestAutoloadedSuperclass
autoload :A, "a" autoload :A, "a"
end end
Expand Down
10 changes: 9 additions & 1 deletion vm.c
Expand Up @@ -1515,6 +1515,9 @@ rb_vm_mark(void *ptr)
if (vm->trap_list[i].cmd) if (vm->trap_list[i].cmd)
rb_gc_mark(vm->trap_list[i].cmd); rb_gc_mark(vm->trap_list[i].cmd);
} }
if (vm->defined_strings) {
rb_gc_mark_locations(vm->defined_strings, vm->defined_strings + DEFINED_EXPR);
}
} }


RUBY_MARK_LEAVE("vm"); RUBY_MARK_LEAVE("vm");
Expand Down Expand Up @@ -1560,7 +1563,12 @@ vm_memsize(const void *ptr)
{ {
if (ptr) { if (ptr) {
const rb_vm_t *vmobj = ptr; const rb_vm_t *vmobj = ptr;
return sizeof(rb_vm_t) + st_memsize(vmobj->living_threads); size_t size = sizeof(rb_vm_t);
size += st_memsize(vmobj->living_threads);
if (vmobj->defined_strings) {
size += DEFINED_EXPR * sizeof(VALUE);
}
return size;
} }
else { else {
return 0; return 0;
Expand Down
2 changes: 2 additions & 0 deletions vm_core.h
Expand Up @@ -349,6 +349,8 @@ typedef struct rb_vm_struct {
* objects so do *NOT* mark this when you GC. * objects so do *NOT* mark this when you GC.
*/ */
struct RArray at_exit; struct RArray at_exit;

VALUE *defined_strings;
} rb_vm_t; } rb_vm_t;


typedef struct { typedef struct {
Expand Down

0 comments on commit 2314b80

Please sign in to comment.