Closed Bug 496418 Opened 15 years ago Closed 14 years ago

Port esp to 4.5

Categories

(Developer Infrastructure :: Source Code Analysis, defect)

x86
Linux
defect
Not set
normal

Tracking

(Not tracked)

RESOLVED FIXED

People

(Reporter: taras.mozilla, Assigned: taras.mozilla)

References

Details

Attachments

(2 files, 6 obsolete files)

      No description provided.
Attached patch supporting library changes (obsolete) — Splinter Review
This is the easy part of the patch. CFG stuff changed only a tiny bit. However, this feels to be the wrong way to go about doing loading gcc-specific library versions.

Seems that we should provide stackable libraries based on gcc version number. So during configure correct libraries would be symlinked/installed. Not yet sure what the cleanest way to accomplish that would be.
Assignee: nobody → tglek
Attached patch core esp changes (obsolete) — Splinter Review
This patch pretty much sucks. Attaching it here for reference until I find a better solution.

With this all of the relevant treehydra tests pass. 3 fail, but those seem silly and version-specific(need to add version-magic to testsuite too)

Overall I don't think it would be impossible to support multiple versions of gcc from the library standpoint. I'm less sure about providing abstraction layers to be able to analyze stuff from multiple GCCs in the same analysis script. Seems like that would be messy and fragile.
analysis.js includes a couple of symbols that are unavailable in GCC 4.5: FILTER_EXPR and EXEC_PTR_EXPR. 
When I apply these patches, and comment out the cases for FILTER_EXPR and EXEC_PTR_EXPR, a couple of testcases in make check_treehydra still fail. 

- test_locks_bad1.js, test_locks_bad3.js, and test_locks_bad4.js fail because the location is printed differently: 
    Failure msg: Expected 'locks_bad4.cc:13: error: precondition not met' in error output; not found. stderr:locks_bad4.cc: In function ‘void bad3(int)’:
locks_bad4.cc:13:12: error: precondition not met: expected UNLOCKED (U), got LOCKED (L)

- test_locks_good.js, test_locks_bad2.js, test_locks_good2.js fail with a "not found" javascript exception (same calltree on all three): 
    Test command: /usr/lib/gcc/i486-linux-gnu/4.5.1/cc1plus -quiet -fplugin=../gcc_treehydra.so -o /dev/null -fplugin-arg-gcc_treehydra-=test_locks_good.js locks_good.cc
    Failure msg: Expected no error output, got error output :../libs/gcc_util.js:233: JS Exception: not found
:0:	#0: Error("not found")
../libs/gcc_util.js:233:	#1: link_switch([object GCCNode],[object GCCNode],[object GCCNode],[object Array])
../libs/gcc_util.js:244:	#2: ([object GCCNode])
../libs/unstable/esp.js:371:	#3: ([object GCCNode],[object Array],(function (v1, v2) {var values = [v1, v2];if (values.indexOf(av.LOCKED) != -1 || values.indexOf(av.UNLOCKED) != -1) {return ESP.NOT_REACHED;}return Zero_NonZero.meet(v1, v2);}),0)
./esp_lock.js:103:	#4: LockCheck([object GCCNode],0)
./esp_lock.js:40:	#5: process_tree([object GCCNode])

- probably unrelated to this bug: test_location.js, test_lang_type.js, and test_stringlit.js end with emptystring output (test_location.js) or empty stdout and stderr. test_lang_type.js is badly broken: even if I add a print-statement to the top of function checker it doesn't produce output. 
  Probably related to test_walk_tree.js error: 
    Test command: /usr/lib/gcc/i486-linux-gnu/4.5.1/cc1plus -quiet -fplugin=../gcc_treehydra.so -o /dev/null -fplugin-arg-gcc_treehydra-=test_walk_tree.js longevity.cc
    Failure msg: Expected 'OK' output; Errors:
 longevity.cc:179:1: warning: ‘stack’ attribute directive ignored
../libs/treehydra.js:315: JS Exception: walk_tree didn't visit enough nodes, 0 out of 1visited
:0:	#0: Error("walk_tree didn't visit enough nodes, 0 out of 1visited")
../libs/treehydra.js:315:	#1: sanity_check((void 0))
./test_walk_tree.js:5:	#2: process_tree([object GCCNode])

- unrelated:
    Test command: /usr/lib/gcc/i486-linux-gnu/4.5.1/cc1plus -quiet -fplugin=../gcc_treehydra.so -o /dev/null -fplugin-arg-gcc_treehydra-=test_u5.js t4.cc
    Failure msg: Expected 'OK' output; Errors:
 ./test_u5.js:8: JS Exception: TypeError: DECL_LANG_SPECIFIC(func).decl_flags is undefined
./test_u5.js:8:	#0: process_tree([object GCCNode])
Attached patch supporting library changes v2 (obsolete) — Splinter Review
Currently working on getting these to work with 4.3 as well but this fixes the problem with link_switches.
Attachment #381598 - Attachment is obsolete: true
Attached patch core esp changes v2 (obsolete) — Splinter Review
Added a dummy define for FILTER_EXPR/EXC_PTR_EXPR above filter_crap. I suppose we'll still need to handle these for 4.3.
Attachment #381599 - Attachment is obsolete: true
Attachment #447438 - Attachment is patch: true
Attachment #447438 - Attachment mime type: application/octet-stream → text/plain
Attached patch supporting library changes v3 (obsolete) — Splinter Review
These changes should allow porting all existing analyses to the tuple style while still retaining 4.3 support. Treehydra with 4.3 will still accept the old-style scripts (js and xpcom tests pass).
Attachment #447438 - Attachment is obsolete: true
Attachment #448614 - Flags: review?(tglek)
Attached patch core esp changes v3 (obsolete) — Splinter Review
Attachment #447439 - Attachment is obsolete: true
Attachment #448615 - Flags: review?(tglek)
Comment on attachment 448614 [details] [diff] [review]
supporting library changes v3


> /** Return the source code location of the argument, which must be a tree.
>  *  The result is a JS object with 'file', 'line', and 'column' properties. */
> function location_of(t) {
>+  // detect gimple tuples
>+  if (t.hasOwnProperty("gsbase"))
>+    return t.gsbase.location

This is kind of ugly, would be nicer if you found a better way.

Rest looks good.
Attachment #448614 - Flags: review?(tglek) → review+
Attachment #448615 - Flags: review?(tglek) → review+
Comment on attachment 448615 [details] [diff] [review]
core esp changes v3


> /** Iterate over variables defined by the instruction. 
>     If kind == 'strong', iterate over only strong defs. */
>+function ensure_decl_p(decl) {
>+  if (!DECL_P(decl))
>+    throw new Error("Fix code to only put decls here. Got :"+decl.tree_code());
>+  return decl
>+}

That function + comment don't go together

Rest looks good
adding GIMPLE_TUPLE_P is not much of an improvement but I need this kind of thing to fix tree_code() and operands() as well.
Attachment #448614 - Attachment is obsolete: true
Attachment #448895 - Flags: review?
Attachment #448895 - Flags: review? → review?(tglek)
carrying over r+
Attachment #448615 - Attachment is obsolete: true
Attachment #448897 - Flags: review+
Comment on attachment 448895 [details] [diff] [review]
supporting library changes v4

>diff --git a/libs/gcc_compat.js b/libs/gcc_compat.js
>--- a/libs/gcc_compat.js
>+++ b/libs/gcc_compat.js
>@@ -113,24 +113,32 @@ function TREE_OPERAND_LENGTH (node)
> }
> 
> var GIMPLE_STMT_P = isGCC42 ?
>   function (NODE) { return false; } :
>   function (NODE) {
>     return TREE_CODE_CLASS (TREE_CODE ((NODE))) == tcc_gimple_stmt
>   }
> 
>+// This macro was eventually removed in GCC 4.5, however this
>+// is needed to simultaneously handle GENERIC and GIMPLE.
>+function GIMPLE_TUPLE_P (node) {
>+  return node.hasOwnProperty("gsbase");
>+}
>+
> function TREE_OPERAND (node, i) {
>   return node.exp.operands[i]
> }
> 
>-var GIMPLE_STMT_OPERAND = isGCC42 ? TREE_OPERAND :
>-  function (node, i) {
>-    return node.gstmt.operands[i]
>-  }
>+var GIMPLE_STMT_OPERAND = isGCC42 ?
>+  TREE_OPERAND : isGCC43 ?
>+    function (node, i) {
>+      return node.gstmt.operands[i]
>+    } :
>+    gimple_op
> 
> function GENERIC_TREE_OPERAND (node, i)
> {
>   if (GIMPLE_STMT_P (node))
>     return GIMPLE_STMT_OPERAND (node, i);
>   return TREE_OPERAND (node, i);
> }
> 
>@@ -485,17 +493,19 @@ let EDGE_FALSE_VALUE = 2048;
> function SWITCH_COND(expr) { return TREE_OPERAND(expr, 0); }
> function SWITCH_BODY(expr) { return TREE_OPERAND(expr, 1); }
> function SWITCH_LABELS(expr) { return TREE_OPERAND(expr, 2); }
> 
> function CASE_LOW(expr) { return TREE_OPERAND(expr, 0); }
> function CASE_HIGH(expr) { return TREE_OPERAND(expr, 1); }
> function CASE_LABEL(expr) { return TREE_OPERAND(expr, 2); }
> 
>-function LABEL_DECL_UID(decl) { return decl.decl_common.pointer_alias_set; }
>+var LABEL_DECL_UID = isUsingGCCTuples ?
>+  function (decl) { return decl.label_decl.label_decl_uid; } :
>+  function (decl) { return decl.decl_common.pointer_alias_set; }
> 
> /** Given an OBJ_TYPE_REF, return a FUNCTION_DECL for the method. */
> function resolve_virtual_fun_from_obj_type_ref(ref) {
>   // This is a GCC macro definition, copied here for the use of this
>   // function only.
>   let TARGET_VTABLE_USES_DESCRIPTORS = 0;
> 
>   let obj_type = TREE_TYPE(OBJ_TYPE_REF_OBJECT(ref));
>@@ -520,16 +530,18 @@ function stdarg_p(fntype) {
>   return last != undefined && TREE_CODE(last) != VOID_TYPE;
> }
> 
> let UNKNOWN_LOCATION = undefined;
> 
> /** Return the source code location of the argument, which must be a tree.
>  *  The result is a JS object with 'file', 'line', and 'column' properties. */
> function location_of(t) {
>+  if (GIMPLE_TUPLE_P(t))
>+    return t.gsbase.location;
>   if (TREE_CODE (t) == PARM_DECL && DECL_CONTEXT (t))
>     t = DECL_CONTEXT (t);
>   else if (TYPE_P (t)) {
>     t = TYPE_MAIN_DECL (t);
>     /* pointer and reference types don't have a TYPE_MAIN_DECL, or a location */
>     if (!t)
>       return UNKNOWN_LOCATION;
>   }
>@@ -788,26 +800,18 @@ function c_common_type_for_mode (mode, u
>   
>   if (TYPE_MODE(long_long_integer_type_node()) == mode)
>     return unsignedp ? long_long_unsigned_type_node() : long_long_integer_type_node();
> 
>   return undefined;
> }
> 
> // tuple stuff
>-
>-function bb_gimple_seq(bb) {
>-  let gimple_bb_info = bb.il.gimple
>-  return gimple_bb_info ? gimple_bb_info.seq.first : undefined
>-}
>-
>-function bb_gs_iterate(bb) {
>-  let seq = bb_gimple_seq(bb)
>-  for(;seq;seq=seq.next)
>-    yield seq.stmt
>+function gimple_code (gs) {
>+  return gs.gsbase.code
> }
> 
> function gimple_location (gs)
> {
>   return gs.gsbase.location;
> }
> function gimple_op(gs, i) {
>   return gs.gimple_ops[i]
>@@ -839,8 +843,55 @@ function gimple_num_ops (gs)
> }
> 
> function gimple_call_arg_iterator (gs) {
>   let num_ops = gimple_num_ops (gs)
>   for (let i = 3;i<num_ops;i++) {
>     yield gs.gimple_ops[i]
>   }
> }
>+
>+function gimple_call_arg (gs, i) {
>+  return gs.gimple_ops[3+i]
>+}
>+
>+function gimple_switch_index (gs) {
>+  return gs.gimple_ops[0]
>+}
>+
>+function gimple_switch_num_labels (gs)
>+{
>+  return gimple_num_ops (gs) - 1;
>+}
>+
>+function gimple_switch_label (gs, index)
>+{
>+  return gs.gimple_ops[index + 1];
>+}
>+
>+let _comparisons = null;
>+
>+var gimple_cond_code = isUsingGCCTuples ?
>+  function (gs) {
>+    if (!this._comparisons) {
>+      this._comparisons = {}
>+      let enums = [LT_EXPR, LE_EXPR, GT_EXPR, GE_EXPR, EQ_EXPR, NE_EXPR];
>+      for each (let e in enums)
>+        this._comparisons[e.value] = e
>+    }
>+    let ret = _comparisons[gs.gsbase.subcode];
>+    if (!ret)
>+      throw new Error("Unexpected gimple_cond subcode");
>+    return ret
>+  } :
>+  function (cond_expr) {
>+    return TREE_CODE(TREE_OPERAND(cond_expr, 0));
>+  }
>+
>+var condition_operand = isUsingGCCTuples ? 
>+  function (gimple_cond, i) {
>+    return gimple_op(gimple_cond, i);
>+  } :
>+  function (cond_expr, i) {
>+    let expr = TREE_OPERAND(cond_expr, 0);
>+    let cond_op = TREE_OPERAND(expr, i);
>+    return cond_op;
>+  }
>diff --git a/libs/gcc_print.js b/libs/gcc_print.js
>--- a/libs/gcc_print.js
>+++ b/libs/gcc_print.js
>@@ -309,16 +309,35 @@ function edge_string(edge, cfg) {
> 
> /** Return a string representation of a return value from location_of. 
>  *  Use loc.toString() instead; this is for compatibility with existing
>  *  scripts. */
> function loc_string(loc) {
>   return loc.toString();
> }
> 
>+function cond_code_display(code) {
>+  switch(code) {
>+  case LT_EXPR:
>+    return '<=';
>+  case LE_EXPR:
>+    return '<';
>+  case GT_EXPR:
>+    return '>';
>+  case GE_EXPR:
>+    return '>=';
>+  case EQ_EXPR:
>+    return '==';
>+  case NE_EXPR:
>+    return '!=';
>+  default:
>+    throw new Error("Invalid conditional code value");
>+  }
>+}
>+
> // tuple stuff
> function gs_display(gs) {
>   switch(gs.gsbase.code) {
>   case GIMPLE_CALL: {
>     let fn = gimple_call_fndecl(gs);
>     let lhs = gimple_call_lhs(gs);
>     let args = []
>     for (a in gimple_call_arg_iterator(gs)) {
>@@ -331,16 +350,20 @@ function gs_display(gs) {
>   case GIMPLE_ASSIGN:
>     return expr_display(gs.gimple_ops[0]) + " = " + expr_display(gs.gimple_ops[1])
>   case GIMPLE_RETURN: {
>     let op = gs.gimple_ops[0];
>     return "return " + (op ? expr_display(gs.gimple_ops[0]) : "")
>   }
>   case GIMPLE_LABEL: 
>     return decl_name(gs.gimple_ops[0]) + ':'
>-  case GIMPLE_COND:
>-    return "if ("+expr_display(gs.gimple_ops[0])+")"
>+  case GIMPLE_RESX:
>+    return "catch: //exception handler"
>+  case GIMPLE_COND: {
>+    let op = cond_code_display (gimple_cond_code (gs));
>+    return "if ("+expr_display(gs.gimple_ops[0])+" " + op+ " " +expr_display(gs.gimple_ops[1])+")"
>+  }
>   case GIMPLE_SWITCH:
>     return "switch ("+expr_display(gs.gimple_ops[0])+")"
>   default:
>     return "Unhandled " + gs.gsbase.code
>   }
> }
>diff --git a/libs/gcc_util.js b/libs/gcc_util.js
>--- a/libs/gcc_util.js
>+++ b/libs/gcc_util.js
>@@ -146,57 +146,187 @@ function bb_pred_edges(bb) {
>  */
> var bb_stmt_list = isGCC42 ?
>   function (bb) { return bb.stmt_list; } :
>   function (bb) {
>     let iltree = bb.il.tree;
>     return iltree ? iltree.stmt_list : undefined;
>   }    
> 
>+/** Iterate over statements of a BB. */
>+let bb_isn_iterator;
>+/** Iterate over statements of a BB in reverse. */
>+let bb_isn_iterator_reverse;
> /** Last instruction of a BB. Throws an exception if there are no instructions. */
>-function bb_isn_last(bb) {
>+let bb_isn_last;
>+
>+// link_switches is a bit of a rough fit here but ok for now.
>+
>+/** Link up switches with the CFG by annotating the outgoing edges
>+ *  with the case labels in a .case_val field, with null for default.
>+ *
>+ *  Return a list of finally_tmp variables found.
>+ *
>+ *  The purpose of this function is to allow analyses such as ESP to
>+ *  track the conditions that hold on branches of a switch. */
>+let link_switches;
>+
>+if (isUsingGCCTuples) {
>+function bb_gimple_seq(bb) {
>+  let gimple_bb_info = bb.il.gimple
>+  return gimple_bb_info ? gimple_bb_info.seq : undefined
>+}
>+
>+bb_isn_iterator = function (bb) {
>+  let seq = bb_gimple_seq(bb)
>+  if (!seq)
>+    return
>+  for(let seq_node = seq.first;seq_node;seq_node=seq_node.next)
>+    yield seq_node.stmt
>+}
>+
>+bb_isn_iterator_reverse = function (bb) {
>+  let seq = bb_gimple_seq(bb)
>+  if (!seq)
>+    return
>+  let seq_node = seq.last
>+  for(;seq_node;seq_node=seq_node.prev)
>+    yield seq_node.stmt
>+}
>+
>+bb_isn_last = function (bb) {
>+  let seq = bb_gimple_seq(bb)
>+  return seq.last.stmt;
>+}
>+  
>+link_switches = function (cfg) {
>+  /** Helper for link_switches. */
>+  function link_switch(cfg, bb, isn) {
>+    // GCC uses a default label for finally_tmp vars, even though there
>+    // is really only one possibility. We'll find it and put that in, 
>+    // to help later analyses track branches.
>+    let label_count = gimple_switch_num_labels (isn)
>+    
>+    let max_val;
>+    
>+    for (i = 0; i < label_count; i++) {
>+      cl = gimple_switch_label (isn, i)
>+      let case_val = CASE_LOW(cl) == undefined ? null : TREE_INT_CST_LOW(CASE_LOW(cl));
>+      if (case_val != null && (max_val == undefined || case_val > max_val))
>+        max_val = case_val;
>+      if (is_finally_tmp(gimple_switch_index(isn)) && case_val == null) {
>+        case_val = max_val + 1;
>+      }
>+
>+      let label_uid = LABEL_DECL_UID(CASE_LABEL(cl));
>+      let bb_succ = cfg.x_label_to_block_map.base.vec[label_uid];
>+      //print(label_uid + ' ' + bb_label(bb_succ));
>+      let found = false;
>+      for each (let e in bb_succ_edges(bb)) {
>+        //print('BBS ' + e.dest.index + ' ' + bb_succ.index);
>+        if (e.dest == bb_succ) {
>+          e.case_val = case_val;
>+          found = true;
>+          //print('LINK ' + e.src.index + ' -> ' + e.dest.index + ": " + e.case_val);
>+          break;
>+        }
>+      }
>+      if (!found)
>+        throw new Error("not found");
>+    }
>+  }
>+  let ans = [];
>+  for (let bb in cfg_bb_iterator(cfg)) {
>+    for (let isn in bb_isn_iterator(bb)) {
>+      if (gimple_code(isn) == GIMPLE_SWITCH) {
>+        let cond = gimple_switch_index(isn)
>+        if (is_finally_tmp(cond)) {
>+          ans.push(cond);
>+        }
>+        link_switch(cfg, bb, isn, ans);
>+      }
>+    }
>+  }
>+  return ans;
>+}
>+} else {
>+bb_isn_iterator = function (bb) {
>+  let outer_stmt_list = bb_stmt_list(bb);
>+  if (outer_stmt_list != undefined) {
>+    let stmt_list = outer_stmt_list.stmt_list;
>+    for (let cur = stmt_list.head; cur; cur = cur.next) {
>+      yield cur.stmt;
>+    }
>+  }
>+}
>+
>+bb_isn_iterator_reverse = function (bb) {
>+  let outer_stmt_list = bb_stmt_list(bb);
>+  if (outer_stmt_list != undefined) {
>+    let stmt_list = outer_stmt_list.stmt_list;
>+    for (let cur = stmt_list.tail; cur; cur = cur.prev) {
>+      yield cur.stmt;
>+    }
>+  }
>+}
>+  
>+bb_isn_last = function (bb) {
>   let stmt_list = bb_stmt_list(bb).stmt_list;
>   return stmt_list.tail.stmt;
> }
> 
>-/** Iterate over statements of a BB. */
>-function bb_isn_iterator(bb) {
>-  let outer_stmt_list = bb_stmt_list(bb);
>-  if (outer_stmt_list != undefined) {
>-    let stmt_list = outer_stmt_list.stmt_list;
>-    let head = stmt_list.head;
>-    let tail = stmt_list.tail;
>-    let cur = head;
>-    // Apparently this can be undefined. Not sure why.
>-    if (!cur) return;
>-    while (true) {
>-      yield cur.stmt;
>-      if (cur == tail) break;
>-      cur = cur.next;
>+link_switches = function(cfg) {
>+  /** Helper for link_switches. */
>+  function link_switch(cfg, bb, isn) {
>+    // GCC uses a default label for finally_tmp vars, even though there
>+    // is really only one possibility. We'll find it and put that in, 
>+    // to help later analyses track branches.
>+    let max_val;
>+    for each (let cl in SWITCH_LABELS(isn).vec.a) {
>+      let case_val = CASE_LOW(cl) == undefined ? null : TREE_INT_CST_LOW(CASE_LOW(cl));
>+      if (case_val != null && (max_val == undefined || case_val > max_val))
>+        max_val = case_val;
>+      if (is_finally_tmp(SWITCH_COND(isn)) && case_val == null) {
>+        case_val = max_val + 1;
>+      }
>+
>+      let label_uid = LABEL_DECL_UID(CASE_LABEL(cl));
>+      let bb_succ = cfg.x_label_to_block_map.base.vec[label_uid];
>+      //print(label_uid + ' ' + bb_label(bb_succ));
>+      let found = false;
>+      for each (let e in bb_succ_edges(bb)) {
>+        //print('BBS ' + e.dest.index + ' ' + bb_succ.index);
>+        if (e.dest == bb_succ) {
>+          e.case_val = case_val;
>+          found = true;
>+          //print('LINK ' + e.src.index + ' -> ' + e.dest.index + ": " + e.case_val);
>+          break;
>+        }
>+      }
>+      if (!found)
>+        throw new Error("not found");
>     }
>   }
>-}
> 
>-/** Iterator over statements of a BB in reverse order. */
>-function bb_isn_iterator_reverse(bb) {
>-  let outer_stmt_list = bb_stmt_list(bb);
>-  if (outer_stmt_list != undefined) {
>-    let stmt_list = outer_stmt_list.stmt_list;
>-    let head = stmt_list.head;
>-    let tail = stmt_list.tail;
>-    let cur = tail;
>-    // Apparently this can be undefined. Not sure why.
>-    if (!cur) return;
>-    while (true) {
>-      yield cur.stmt;
>-      if (cur == head) break;
>-      cur = cur.prev;
>+  let ans = [];
>+  for (let bb in cfg_bb_iterator(cfg)) {
>+    for (let isn in bb_isn_iterator(bb)) {
>+      if (TREE_CODE(isn) == SWITCH_EXPR) {
>+        if (is_finally_tmp(SWITCH_COND(isn))) {
>+          ans.push(SWITCH_COND(isn));
>+        }
>+        link_switch(cfg, bb, isn, ans);
>+      }
>     }
>   }
>+  return ans;
> }
>+ 
>+}//isUsingGCCTuples
>+
> 
> 
> // Translate GCC FUNCTION_DECL to a pure JS object
> 
> // Declaration translators
> 
> /** Iterator over elements of a GCC TREE_CHAIN list representation. */
> function flatten_chain(chain_head) {
>@@ -308,72 +438,16 @@ function dfs_base_iterator(record_type) 
>     done.add(type);
>     yield type;
>     for each (let base in VEC_iterate(BINFO_BASE_BINFOS(binfo))) {
>       work.push(base);
>     }
>   }
> }
> 
>-// link_switches is a bit of a rough fit here but ok for now.
>-
>-/** Link up switches with the CFG by annotating the outgoing edges
>- *  with the case labels in a .case_val field, with null for default.
>- *
>- *  Return a list of finally_tmp variables found.
>- *
>- *  The purpose of this function is to allow analyses such as ESP to
>- *  track the conditions that hold on branches of a switch. */
>-function link_switches(cfg) {
>-  let ans = [];
>-  for (let bb in cfg_bb_iterator(cfg)) {
>-    for (let isn in bb_isn_iterator(bb)) {
>-      if (TREE_CODE(isn) == SWITCH_EXPR) {
>-        if (is_finally_tmp(SWITCH_COND(isn))) {
>-          ans.push(SWITCH_COND(isn));
>-        }
>-        link_switch(cfg, bb, isn, ans);
>-      }
>-    }
>-  }
>-  return ans;
>-}
>-
>-/** Helper for link_switches. */
>-function link_switch(cfg, bb, isn) {
>-  // GCC uses a default label for finally_tmp vars, even though there
>-  // is really only one possibility. We'll find it and put that in, 
>-  // to help later analyses track branches.
>-  let max_val;
>-  for each (let cl in SWITCH_LABELS(isn).vec.a) {
>-    let case_val = CASE_LOW(cl) == undefined ? null : TREE_INT_CST_LOW(CASE_LOW(cl));
>-    if (case_val != null && (max_val == undefined || case_val > max_val))
>-      max_val = case_val;
>-    if (is_finally_tmp(SWITCH_COND(isn)) && case_val == null) {
>-      case_val = max_val + 1;
>-    }
>-
>-    let label_uid = LABEL_DECL_UID(CASE_LABEL(cl));
>-    let bb_succ = cfg.x_label_to_block_map.base.vec[label_uid];
>-    //print(label_uid + ' ' + bb_label(bb_succ));
>-    let found = false;
>-    for each (let e in bb_succ_edges(bb)) {
>-      //print('BBS ' + e.dest.index + ' ' + bb_succ.index);
>-      if (e.dest == bb_succ) {
>-        e.case_val = case_val;
>-        found = true;
>-        //print('LINK ' + e.src.index + ' -> ' + e.dest.index + ": " + e.case_val);
>-        break;
>-      }
>-    }
>-    if (!found)
>-      throw new Error("not found");
>-  }
>-}
>-
> /** Return true if the given variable is a 'finally_tmp' variable, i.e., introduced
>  *  by GCC for a finally block (including destructors). */
> function is_finally_tmp(decl) {
>   let s = expr_display(decl);
>   return s.substr(0, 11) == 'finally_tmp';
> }
> 
> function translate_attributes(atts) {
>diff --git a/libs/platform.js b/libs/platform.js
>--- a/libs/platform.js
>+++ b/libs/platform.js
>@@ -15,8 +15,9 @@
>  * You should have received a copy of the GNU General Public License along
>  * with this program; if not, write to the Free Software Foundation, Inc.,
>  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
>  */
> 
> const isGCCApple = (sys.gcc_version.indexOf('Apple') != -1);
> const isGCC42 = (sys.gcc_version.indexOf('4.2') == 0);
> const isGCC43 = (sys.gcc_version.indexOf('4.3') == 0);
>+const isUsingGCCTuples = !(isGCC42 || isGCC43)
>diff --git a/libs/treehydra.js b/libs/treehydra.js
>--- a/libs/treehydra.js
>+++ b/libs/treehydra.js
>@@ -16,16 +16,18 @@
>  * with this program; if not, write to the Free Software Foundation, Inc.,
>  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
>  */
> 
> include ("xhydra.js")
> include ("map.js")
> include ("platform.js")
> include ("gcc_compat.js")
>+include ("gcc_util.js")
>+include ("gcc_print.js")
> 
> function unhandledLazyProperty (prop) {
>     /* Special case: the interpreter will look for this property when
>      * iterating. It doesn't appear in the prototype chain either, but
>      * apparently that's fine--the interpreter will use default iterator
>      * behavior, but only if we return true here. */
>   if (prop != "__iterator__")
>     throw new Error("No " + prop + " in this lazy object")
>@@ -42,16 +44,30 @@ if (TREE_CODE) {
> 
> if (isGCC42) {
>   // try to increase the chances of linux scripts working on osx out of the box
>   this.GIMPLE_MODIFY_STMT = MODIFY_EXPR;
>   this.POINTER_PLUS_EXPR = PLUS_EXPR;
>   this.FIXED_POINT_TYPE = {};
>  }
> 
>+if (!isUsingGCCTuples) {
>+  this.gimple_code = TREE_CODE;
>+  this.GIMPLE_CALL = CALL_EXPR;
>+  this.GIMPLE_ASSIGN = GIMPLE_MODIFY_STMT;
>+  this.GIMPLE_COND = COND_EXPR;
>+  this.GIMPLE_SWITCH = SWITCH_EXPR;
>+  this.GIMPLE_RETURN = RETURN_EXPR;
>+  this.gimple_call_fndecl = call_function_decl;
>+  this.gimple_call_arg = call_arg;
>+  this.gimple_call_arg_iterator = call_arg_iterator;
>+  this.gs_display = isn_display;
>+  this.gimple_op = function(isn, i) { return isn.operands()[i]; }
>+}
>+
> // Class that the lazyness builds itself around of
> function GCCNode () {
> }
> 
> GCCNode.prototype.toString = function () {
>   if (!this._struct_name) {
>     if (this.common) {
>       let ls = ["{tree_code:" + this.tree_code()]
Attachment #448895 - Flags: review?(tglek) → review+
Depends on: 572819
Product: Core → Firefox Build System
Product: Firefox Build System → Developer Infrastructure
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: