[前][次][番号順一覧][スレッド一覧]

ruby-changes:20997

From: ko1 <ko1@a...>
Date: Wed, 24 Aug 2011 15:31:30 +0900 (JST)
Subject: [ruby-changes:20997] ko1:r33046 (trunk): * iseq.h, iseq.c, compile.c: Change the line number data structure

ko1	2011-08-24 15:31:15 +0900 (Wed, 24 Aug 2011)

  New Revision: 33046

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=33046

  Log:
    * iseq.h, iseq.c, compile.c: Change the line number data structure
      to solve an issue reported at [ruby-dev:44413] [Ruby 1.9 - Bug #5217].
      Before this fix, each instruction has an information including
      line number (iseq::iseq_insn_info_table).  Instead of this data
      structure, recording only line number changing places
      (iseq::iseq_line_info_table).
      The order of entries in iseq_line_info_table is ascending order of
      iseq_line_info_table_entry::position.  You can get a line number
      by an iseq and a program counter with this data structure.
      This fix reduces memory consumption of iseq (bytecode).
      On my measurement, a rails application consumes 21.8MB for
      iseq with this fix on the 32bit CPU.  Without this fix, it
      consumes 24.7MB for iseq [ruby-dev:44415].
    * proc.c: ditto.
    * vm_insnhelper.c: ditto.
    * vm_method.c: ditto.
    * vm.c (rb_vm_get_sourceline): change to use rb_iseq_line_no().

  Modified files:
    trunk/ChangeLog
    trunk/compile.c
    trunk/iseq.c
    trunk/iseq.h
    trunk/proc.c
    trunk/vm.c
    trunk/vm_core.h
    trunk/vm_insnhelper.c
    trunk/vm_method.c

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 33045)
+++ ChangeLog	(revision 33046)
@@ -1,3 +1,27 @@
+Wed Aug 24 15:13:56 2011  Koichi Sasada  <ko1@a...>
+
+	* iseq.h, iseq.c, compile.c: Change the line number data structure
+	  to solve an issue reported at [ruby-dev:44413] [Ruby 1.9 - Bug #5217].
+	  Before this fix, each instruction has an information including
+	  line number (iseq::iseq_insn_info_table).  Instead of this data
+	  structure, recording only line number changing places
+	  (iseq::iseq_line_info_table).
+	  The order of entries in iseq_line_info_table is ascending order of
+	  iseq_line_info_table_entry::position.  You can get a line number
+	  by an iseq and a program counter with this data structure.
+	  This fix reduces memory consumption of iseq (bytecode).
+	  On my measurement, a rails application consumes 21.8MB for
+	  iseq with this fix on the 32bit CPU.  Without this fix, it
+	  consumes 24.7MB for iseq [ruby-dev:44415].
+
+	* proc.c: ditto.
+
+	* vm_insnhelper.c: ditto.
+
+	* vm_method.c: ditto.
+
+	* vm.c (rb_vm_get_sourceline): change to use rb_iseq_line_no().
+
 Wed Aug 24 09:49:10 2011  Koichi Sasada  <ko1@a...>
 
 	* insns.def (defined): fix to checking class variable.
Index: vm_core.h
===================================================================
--- vm_core.h	(revision 33045)
+++ vm_core.h	(revision 33046)
@@ -176,8 +176,8 @@
     unsigned short line_no;
 
     /* insn info, must be freed */
-    struct iseq_insn_info_entry *insn_info_table;
-    size_t insn_info_size;
+    struct iseq_line_info_entry *line_info_table;
+    size_t line_info_size;
 
     ID *local_table;		/* must free */
     int local_table_size;
Index: iseq.c
===================================================================
--- iseq.c	(revision 33045)
+++ iseq.c	(revision 33046)
@@ -78,7 +78,7 @@
 	    }
 
 	    RUBY_FREE_UNLESS_NULL(iseq->iseq);
-	    RUBY_FREE_UNLESS_NULL(iseq->insn_info_table);
+	    RUBY_FREE_UNLESS_NULL(iseq->line_info_table);
 	    RUBY_FREE_UNLESS_NULL(iseq->local_table);
 	    RUBY_FREE_UNLESS_NULL(iseq->ic_entries);
 	    RUBY_FREE_UNLESS_NULL(iseq->catch_table);
@@ -136,7 +136,7 @@
 	    }
 
 	    size += iseq->iseq_size * sizeof(VALUE);
-	    size += iseq->insn_info_size * sizeof(struct iseq_insn_info_entry);
+	    size += iseq->line_info_size * sizeof(struct iseq_line_info_entry);
 	    size += iseq->local_table_size * sizeof(ID);
 	    size += iseq->catch_table_size * sizeof(struct iseq_catch_table_entry);
 	    size += iseq->arg_opts * sizeof(VALUE);
@@ -680,25 +680,45 @@
 /* TODO: search algorithm is brute force.
          this should be binary search or so. */
 
-static struct iseq_insn_info_entry *
-get_insn_info(const rb_iseq_t *iseq, const unsigned long pos)
+static struct iseq_line_info_entry *
+get_line_info(const rb_iseq_t *iseq, size_t pos)
 {
-    unsigned long i, size = iseq->insn_info_size;
-    struct iseq_insn_info_entry *table = iseq->insn_info_table;
+    size_t i = 0, size = iseq->line_info_size;
+    struct iseq_line_info_entry *table = iseq->line_info_table;
+    const int debug = 0;
 
-    for (i = 0; i < size; i++) {
+    if (debug) {
+	printf("size: %d\n", size);
+	printf("table[%d]: position: %d, line: %d, pos: %d\n",
+	       i, table[i].position, table[i].line_no, pos);
+    }
+
+    if (size == 0) {
+	return 0;
+    }
+    else if (size == 1) {
+	return &table[0];
+    }
+    else {
+	for (i=1; i<size; i++) {
+	    if (debug) printf("table[%d]: position: %d, line: %d, pos: %d\n",
+			      i, table[i].position, table[i].line_no, pos);
+
 	if (table[i].position == pos) {
 	    return &table[i];
 	}
+	    if (table[i].position > pos) {
+		return &table[i-1];
     }
-
-    return 0;
+	}
+    }
+    return &table[i-1];
 }
 
-static unsigned short
-find_line_no(rb_iseq_t *iseq, unsigned long pos)
+static unsigned int
+find_line_no(const rb_iseq_t *iseq, size_t pos)
 {
-    struct iseq_insn_info_entry *entry = get_insn_info(iseq, pos);
+    struct iseq_line_info_entry *entry = get_line_info(iseq, pos);
     if (entry) {
 	return entry->line_no;
     }
@@ -707,26 +727,17 @@
     }
 }
 
-static unsigned short
-find_prev_line_no(rb_iseq_t *iseqdat, unsigned long pos)
+unsigned int
+rb_iseq_line_no(const rb_iseq_t *iseq, size_t pos)
 {
-    unsigned long i, size = iseqdat->insn_info_size;
-    struct iseq_insn_info_entry *iiary = iseqdat->insn_info_table;
-
-    for (i = 0; i < size; i++) {
-	if (iiary[i].position == pos) {
-	    if (i > 0) {
-		return iiary[i - 1].line_no;
+    if (pos == 0) {
+	return find_line_no(iseq, pos);
 	    }
 	    else {
-		return 0;
-	    }
+	return find_line_no(iseq, pos - 1);
 	}
     }
 
-    return 0;
-}
-
 static VALUE
 insn_operand_intern(rb_iseq_t *iseq,
 		    VALUE insn, int op_no, VALUE op,
@@ -865,23 +876,15 @@
 	}
     }
 
-    if (1) {
-	int line_no = find_line_no(iseqdat, pos);
-	int prev = find_prev_line_no(iseqdat, pos);
+    {
+	unsigned int line_no = find_line_no(iseqdat, pos);
+	unsigned int prev = pos == 0 ? 0 : find_line_no(iseqdat, pos - 1);
 	if (line_no && line_no != prev) {
 	    long slen = RSTRING_LEN(str);
 	    slen = (slen > 70) ? 0 : (70 - slen);
 	    str = rb_str_catf(str, "%*s(%4d)", (int)slen, "", line_no);
 	}
     }
-    else {
-	/* for debug */
-	struct iseq_insn_info_entry *entry = get_insn_info(iseqdat, pos);
-	long slen = RSTRING_LEN(str);
-	slen = (slen > 60) ? 0 : (60 - slen);
-	str = rb_str_catf(str, "%*s(line: %d, sp: %d)",
-			  (int)slen, "", entry->line_no, entry->sp);
-    }
 
     if (ret) {
 	rb_str_cat2(str, "\n");
@@ -1098,8 +1101,8 @@
 static VALUE
 iseq_data_to_ary(rb_iseq_t *iseq)
 {
-    long i, pos;
-    int line = 0;
+    long i, pos, ti;
+    unsigned int line = 0;
     VALUE *seq;
 
     VALUE val = rb_ary_new();
@@ -1298,6 +1301,7 @@
 
     /* make body with labels and insert line number */
     body = rb_ary_new();
+    ti = 0;
 
     for (i=0, pos=0; i<RARRAY_LEN(nbody); i++) {
 	VALUE ary = RARRAY_PTR(nbody)[i];
@@ -1307,9 +1311,10 @@
 	    rb_ary_push(body, (VALUE)label);
 	}
 
-	if (iseq->insn_info_table[i].line_no != line) {
-	    line = iseq->insn_info_table[i].line_no;
+	if (iseq->line_info_table[ti].position == pos) {
+	    line = iseq->line_info_table[ti].line_no;
 	    rb_ary_push(body, INT2FIX(line));
+	    ti++;
 	}
 
 	rb_ary_push(body, ary);
@@ -1441,7 +1446,7 @@
 rb_iseq_build_for_ruby2cext(
     const rb_iseq_t *iseq_template,
     const rb_insn_func_t *func,
-    const struct iseq_insn_info_entry *insn_info_table,
+    const struct iseq_line_info_entry *line_info_table,
     const char **local_table,
     const VALUE *arg_opt_table,
     const struct iseq_catch_table_entry *catch_table,
@@ -1479,8 +1484,8 @@
   } \
 } while (0)
 
-    ALLOC_AND_COPY(iseq->insn_info_table, insn_info_table,
-		   struct iseq_insn_info_entry, iseq->insn_info_size);
+    ALLOC_AND_COPY(iseq->line_info_table, line_info_table,
+		   struct iseq_line_info_entry, iseq->line_info_size);
 
     ALLOC_AND_COPY(iseq->catch_table, catch_table,
 		   struct iseq_catch_table_entry, iseq->catch_table_size);
Index: iseq.h
===================================================================
--- iseq.h	(revision 33045)
+++ iseq.h	(revision 33046)
@@ -26,6 +26,7 @@
 VALUE rb_iseq_load(VALUE data, VALUE parent, VALUE opt);
 VALUE rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc);
 struct st_table *ruby_insn_make_insn_table(void);
+unsigned int rb_iseq_line_no(const rb_iseq_t *iseq, size_t pos);
 
 /* proc.c */
 rb_iseq_t *rb_method_get_iseq(VALUE body);
@@ -43,10 +44,9 @@
     int debug_level;
 };
 
-struct iseq_insn_info_entry {
-    unsigned short position;
-    unsigned short line_no;
-    unsigned short sp;
+struct iseq_line_info_entry {
+    unsigned int position;
+    unsigned int line_no;
 };
 
 struct iseq_catch_table_entry {
Index: compile.c
===================================================================
--- compile.c	(revision 33045)
+++ compile.c	(revision 33046)
@@ -51,7 +51,7 @@
 typedef struct iseq_insn_data {
     LINK_ELEMENT link;
     enum ruby_vminsn_type insn_id;
-    int line_no;
+    unsigned int line_no;
     int operand_size;
     int sc_state;
     VALUE *operands;
@@ -1283,7 +1283,8 @@
 {
     LABEL *lobj;
     INSN *iobj;
-    struct iseq_insn_info_entry *insn_info_table;
+    struct iseq_line_info_entry *line_info_table;
+    unsigned int last_line = 0;
     LINK_ELEMENT *list;
     VALUE *generated_iseq;
 
@@ -1335,7 +1336,7 @@
 
     /* make instruction sequence */
     generated_iseq = ALLOC_N(VALUE, pos);
-    insn_info_table = ALLOC_N(struct iseq_insn_info_entry, k);
+    line_info_table = ALLOC_N(struct iseq_line_info_entry, k);
     iseq->ic_entries = ALLOC_N(struct iseq_inline_cache_entry, iseq->ic_size);
     MEMZERO(iseq->ic_entries, struct iseq_inline_cache_entry, iseq->ic_size);
 
@@ -1373,7 +1374,7 @@
 				     "operand size miss! (%d for %d)",
 				     iobj->operand_size, len - 1);
 		    xfree(generated_iseq);
-		    xfree(insn_info_table);
+		    xfree(line_info_table);
 		    return 0;
 		}
 
@@ -1476,15 +1477,16 @@
 			rb_compile_error(RSTRING_PTR(iseq->filename), iobj->line_no,
 					 "unknown operand type: %c", type);
 			xfree(generated_iseq);
-			xfree(insn_info_table);
+			xfree(line_info_table);
 			return 0;
 		    }
 		}
-		insn_info_table[k].line_no = iobj->line_no;
-		insn_info_table[k].position = pos;
-		insn_info_table[k].sp = sp;
+		if (last_line != iobj->line_no) {
+		    line_info_table[k].line_no = last_line = iobj->line_no;
+		    line_info_table[k].position = pos;
+		k++;
+		}
 		pos += len;
-		k++;
 		break;
 	    }
 	  case ISEQ_ELEMENT_LABEL:
@@ -1512,19 +1514,21 @@
 
 		if (adjust->line_no != -1) {
 		    if (orig_sp - sp > 0) {
-			insn_info_table[k].line_no = adjust->line_no;
-			insn_info_table[k].position = pos;
-			insn_info_table[k].sp = sp;
+			if (last_line != (unsigned int)adjust->line_no) {
+			    line_info_table[k].line_no = last_line = adjust->line_no;
+			    line_info_table[k].position = pos;
 			k++;
+			}
 			generated_iseq[pos++] = BIN(adjuststack);
 			generated_iseq[pos++] = orig_sp - sp;
 		    }
 		    else if (orig_sp - sp == 0) {
 			/* jump to next insn */
-			insn_info_table[k].line_no = adjust->line_no;
-			insn_info_table[k].position = pos;
-			insn_info_table[k].sp = sp;
+			if (last_line != (unsigned int)adjust->line_no) {
+			    line_info_table[k].line_no = last_line = adjust->line_no;
+			    line_info_table[k].position = pos;
 			k++;
+			}
 			generated_iseq[pos++] = BIN(jump);
 			generated_iseq[pos++] = 0;
 		    }
@@ -1550,10 +1554,12 @@
 
     iseq->iseq = (void *)generated_iseq;
     iseq->iseq_size = pos;
-    iseq->insn_info_table = insn_info_table;
-    iseq->insn_info_size = k;
     iseq->stack_max = stack_max;
 
+    line_info_table = ruby_xrealloc(line_info_table, k * sizeof(struct iseq_line_info_entry));
+    iseq->line_info_table = line_info_table;
+    iseq->line_info_size = k;
+
     return COMPILE_OK;
 }
 
@@ -5288,6 +5294,7 @@
     long i, len = RARRAY_LEN(body);
     int j;
     int line_no = 0;
+
     /*
      * index -> LABEL *label
      */
Index: proc.c
===================================================================
--- proc.c	(revision 33045)
+++ proc.c	(revision 33046)
@@ -685,7 +685,7 @@
 
     if (!iseq) return Qnil;
     loc[0] = iseq->filename;
-    if (iseq->insn_info_table) {
+    if (iseq->line_info_table) {
 	loc[1] = INT2FIX(rb_iseq_first_lineno(iseq));
     }
     else {
@@ -823,7 +823,7 @@
     if (RUBY_VM_NORMAL_ISEQ_P(iseq)) {
 	int line_no = 0;
 
-	if (iseq->insn_info_table) {
+	if (iseq->line_info_table) {
 	    line_no = rb_iseq_first_lineno(iseq);
 	}
 	str = rb_sprintf("#<%s:%p@%s:%d%s>", cname, (void *)self,
Index: vm_method.c
===================================================================
--- vm_method.c	(revision 33045)
+++ vm_method.c	(revision 33046)
@@ -216,7 +216,7 @@
 		break;
 	    }
 	    if (iseq && !NIL_P(iseq->filename)) {
-		int line = iseq->insn_info_table ? rb_iseq_first_lineno(iseq) : 0;
+		int line = iseq->line_info_table ? rb_iseq_first_lineno(iseq) : 0;
 		rb_compile_warning(RSTRING_PTR(iseq->filename), line,
 				   "previous definition of %s was here",
 				   rb_id2name(old_def->original_id));
Index: vm.c
===================================================================
--- vm.c	(revision 33045)
+++ vm.c	(revision 33046)
@@ -716,20 +716,10 @@
     int line_no = 0;
     const rb_iseq_t *iseq = cfp->iseq;
 
-    if (RUBY_VM_NORMAL_ISEQ_P(iseq) && iseq->insn_info_size > 0) {
-	rb_num_t i;
+    if (RUBY_VM_NORMAL_ISEQ_P(iseq)) {
 	size_t pos = cfp->pc - cfp->iseq->iseq_encoded;
-
-	if (iseq->insn_info_table[0].position == pos) goto found;
-	for (i = 1; i < iseq->insn_info_size; i++) {
-	    if (iseq->insn_info_table[i].position == pos) {
-		line_no = iseq->insn_info_table[i - 1].line_no;
-		goto found;
+	line_no = rb_iseq_line_no(iseq, pos);
 	    }
-	}
-	line_no = iseq->insn_info_table[i - 1].line_no;
-    }
-  found:
     return line_no;
 }
 
Index: vm_insnhelper.c
===================================================================
--- vm_insnhelper.c	(revision 33045)
+++ vm_insnhelper.c	(revision 33046)
@@ -118,8 +118,8 @@
     if (iseq) {
 	int line_no = 1;
 
-	if (iseq->insn_info_size) {
-	    line_no = iseq->insn_info_table[0].line_no;
+	if (iseq->line_info_size) {
+	    line_no = iseq->line_info_table[0].line_no;
 	}
 
 	err_line = rb_sprintf("%s:%d:in `%s'",

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]