Logo Search packages:      
Sourcecode: jlint version File versions

local_context.cc

#include "local_context.hh"

//
// Methods of local_context class
//

vbm_operand* ctx_push_var::transfer(method_desc* method, vbm_operand* sp, 
                                    byte, byte&)
{
  var_desc* var = &method->vars[var_index];
  if (var->type == tp_void) { 
    if (IS_INT_TYPE(var_type)) { 
      var->min  = ranges[var_type].min;
      var->max  = ranges[var_type].max;
      var->mask = var->min|var->max;
    } else if (var_type == tp_long) { 
      var[0].min  = 0x80000000;
      var[0].max  = 0x7fffffff;
      var[0].mask = 0xffffffff;
      var[1].min  = 0;
      var[1].max  = 0xffffffff;
      var[1].mask = 0xffffffff;      
    } else { 
      var->mask = (var->type == tp_self) 
        ? var_desc::vs_not_null : var_desc::vs_unknown;
      var->min = 0;
      var->max = MAX_ARRAY_LENGTH;
    }
  }
  var->type = var_type;
  var->name = *var_name;
  var->start_pc = var_start_pc;
  return sp;
}

vbm_operand* ctx_pop_var::transfer(method_desc* method, vbm_operand* sp, 
                                   byte, byte&)
{
  var_desc* var = &method->vars[var_index];
  for (field_desc* field = method->cls->fields; 
       field != NULL; 
       field = field->next)
    { 
      // Do not produce message about shadowing of class camponent by local
      // variable in case when local variable is formal parameter of the
      // method and programmer explicitly refer class object component
      // by "this": this.x = x;
      if (field->name == var->name 
          && (!(field->attr & field_desc::f_used) 
              || var->start_pc != 0 /* not formal parameter*/))
        {
          method->message(msg_shadow_local, var->start_pc, 
                          &var->name, method->cls);
          break;
        }
    }
  var->type = tp_void;
  var->name = utf_string("???");
  return sp;
}


vbm_operand* ctx_split::transfer(method_desc* method, vbm_operand* sp, 
                                 byte cop, byte& prev_cop)
{
  if (n_branches > 0 && cmd == cmd_save_ctx) { 
    vars = new var_desc[method->n_vars];
    memcpy(vars, method->vars, method->n_vars*sizeof(var_desc));
  } else { 
    vars = NULL;
  }
  switch_var_index = -1;
  in_monitor = method->in_monitor;

  vbm_operand* left_op = sp-2;
  vbm_operand* right_op = sp-1;
    
  switch (cop) { 
  case jsr:
  case jsr_w:  
    sp->type = tp_object;
    sp->mask = var_desc::vs_not_null;
    sp->min = 0;
    sp->max = MAX_ARRAY_LENGTH;
    stack_pointer = sp+1;
    break;
  case tableswitch:
  case lookupswitch:
    stack_pointer = right_op;
    switch_var_index = right_op->index;
    break;
  case ifeq:
    if (vars != NULL && right_op->index >= 0) { 
      // state at the branch address
      var_desc* var = &vars[right_op->index];
      if (prev_cop == iand) { 
        // Operation of form (x & const) == 0
        if (IS_INT_TYPE(var->type)) { 
          var->mask &= ~right_op->mask;
        }
      } else { 
        var->max = var->min = 0;
        if (IS_INT_TYPE(var->type)) { 
          var->mask = 0;
        }
      } 
    }
    stack_pointer = right_op;
    break;
  case ifne:
    if (right_op->index >= 0) { // value of local var. was pushed on stack 
      // state after if
      var_desc* var = &method->vars[right_op->index];
      if (prev_cop == iand) { 
        // Operation of form (x & const) != 0
        if (IS_INT_TYPE(var->type)) { 
          var->mask &= ~right_op->mask;
        }
      } else { 
        var->max = var->min = 0;
        if (IS_INT_TYPE(var->type)) { 
          var->mask = 0;
        }
      }
    }
    stack_pointer = right_op;
    break;
  case iflt:
    if (right_op->index >= 0) { 
      // state after if
      var_desc* var = &method->vars[right_op->index];
      if (var->min < 0) var->min = 0;
      if (var->max < 0) var->max = 0;
      if (IS_INT_TYPE(var->type)) { 
        var->mask &= ~SIGN_BIT;
      }
      if (vars != NULL) { // forward branch
        // state at the branch address
        var = &vars[right_op->index];
        if (var->min >= 0) var->min = -1;
        if (var->max >= 0) var->max = -1;
      }
    }
    stack_pointer = right_op;
    break;      
  case ifge:
    if (right_op->index >= 0) { 
      // state after if
      var_desc* var = &method->vars[right_op->index];
      if (var->min >= 0) var->min = -1;
      if (var->max >= 0) var->max = -1;
      if (vars != NULL) { // forward branch
        // state at the branch address
        var = &vars[right_op->index];
        if (var->min < 0) var->min = 0;
        if (var->max < 0) var->max = 0;
        if (IS_INT_TYPE(var->type)) { 
          var->mask &= ~SIGN_BIT;
        }
      }
    }
    stack_pointer = right_op;
    break;      
  case ifgt:
    if (right_op->index >= 0) { 
      // state after if
      var_desc* var = &method->vars[right_op->index];
      if (var->min > 0) var->min = 0;
      if (var->max > 0) var->max = 0;
      if (vars != NULL) { // forward branch
        // state at the branch address
        var = &vars[right_op->index];
        if (var->min <= 0) var->min = 1;
        if (var->max <= 0) var->max = 1;
        if (IS_INT_TYPE(var->type)) { 
          var->mask &= ~SIGN_BIT;
        }
      }
    }
    stack_pointer = right_op;
    break;      
  case ifle:
    if (right_op->index >= 0) { 
      // state after if
      var_desc* var = &method->vars[right_op->index];
      if (var->min <= 0) var->min = 1;
      if (var->max <= 0) var->max = 1;
      if (IS_INT_TYPE(var->type)) { 
        var->mask &= ~SIGN_BIT;
      }
      if (vars != NULL) { // forward branch
        // state at the branch address
        var = &vars[right_op->index];
        if (var->min > 0) var->min = 0;
        if (var->max > 0) var->max = 0;
      }
    }
    stack_pointer = right_op;
    break;      
  case if_icmpeq:
    if (vars != NULL) { 
      // state at the branch address
      if (right_op->index >= 0) { 
        var_desc* var = &vars[right_op->index];
        if (var->min < left_op->min) var->min = left_op->min;
        if (var->max > left_op->max) var->max = left_op->max;
        if (var->min > var->max) var->min = var->max; // recovery
        if (IS_INT_TYPE(var->type)) { 
          var->mask &= left_op->mask;
        }
      }
      if (left_op->index >= 0) { 
        var_desc* var = &vars[left_op->index];
        if (var->min < right_op->min) var->min = right_op->min;
        if (var->max > right_op->max) var->max = right_op->max;
        if (var->min > var->max) var->min = var->max; // recovery
        if (IS_INT_TYPE(var->type)) { 
          var->mask &= right_op->mask;
        }
      }
    }
    stack_pointer = left_op;
    break;      
  case if_icmpne:
    if (right_op->index >= 0) { 
      // state after if
      var_desc* var = &method->vars[right_op->index];
      if (var->min < left_op->min) var->min = left_op->min;
      if (var->max > left_op->max) var->max = left_op->max;
      if (var->min > var->max) var->min = var->max; // recovery
      if (IS_INT_TYPE(var->type)) { 
        var->mask &= left_op->mask;
      }
    }
    if (left_op->index >= 0) { 
      var_desc* var = &method->vars[left_op->index];
      if (var->min < right_op->min) var->min = right_op->min;
      if (var->max > right_op->max) var->max = right_op->max;
      if (var->min > var->max) var->min = var->max; // recovery
      if (IS_INT_TYPE(var->type)) { 
        var->mask &= right_op->mask;
      }
    }
    stack_pointer = left_op;
    break;      
  case if_icmplt:
    if (right_op->index >= 0) {   
      // left >= right
      var_desc* var = &method->vars[right_op->index];
      if (var->max > left_op->max) { 
        var->max = left_op->max;
        if (var->min > var->max) var->min = var->max;
      }
      if (vars != NULL) { 
        // left < right
        var = &vars[right_op->index];
        if (var->min <= left_op->min) { 
          var->min = left_op->min == ranges[tp_int].max 
            ? left_op->min : left_op->min+1;
          if (var->min > var->max) var->max = var->min;
        }
      }
    }
    if (left_op->index >= 0) { 
      // left >= right
      var_desc* var = &method->vars[left_op->index];
      if (var->min < right_op->min) { 
        var->min = right_op->min;
        if (var->min > var->max) var->max = var->min;
      }
      if (vars != NULL) { 
        // left < right
        var = &vars[left_op->index];
        if (var->max >= right_op->max) { 
          var->max = right_op->max == ranges[tp_int].min 
            ? right_op->max : right_op->max-1;
          if (var->min > var->max) var->min = var->max;
        }
      }
    }
    stack_pointer = left_op;  
    break;
  case if_icmple:
    if (right_op->index >= 0) {   
      // left > right
      var_desc* var = &method->vars[right_op->index];
      if (var->max >= left_op->max) { 
        var->max = left_op->max == ranges[tp_int].min
          ? left_op->max : left_op->max-1;
        if (var->min > var->max) var->min = var->max;
      }
      if (vars != NULL) { 
        // left <= right
        var = &vars[right_op->index];
        if (var->min < left_op->min) { 
          var->min = left_op->min;
          if (var->min > var->max) var->max = var->min;
        }
      }
    }
    if (left_op->index >= 0) { 
      // left > right
      var_desc* var = &method->vars[left_op->index];
      if (var->min <= right_op->min) { 
        var->min = right_op->min == ranges[tp_int].max
          ? right_op->min : right_op->min+1;
        if (var->min > var->max) var->max = var->min;
      }
      if (vars != NULL) { 
        // left <= right
        var = &vars[left_op->index];
        if (var->max > right_op->max) { 
          var->max = right_op->max;
          if (var->min > var->max) var->min = var->max;
        }
      }
    }
    stack_pointer = left_op;  
    break;
  case if_icmpgt:
    if (right_op->index >= 0) {   
      // left <= right
      var_desc* var = &method->vars[right_op->index];
      if (var->min < left_op->min) { 
        var->min = left_op->min;
        if (var->min > var->max) var->max = var->min;
      }
      if (vars != NULL) { 
        // left > right
        var = &vars[right_op->index];
        if (var->max >= left_op->max) { 
          var->max = left_op->max == ranges[tp_int].min 
            ? left_op->max : left_op->max-1;
          if (var->min > var->max) var->min = var->max;
        }
      }
    }
    if (left_op->index >= 0) { 
      // left <= right
      var_desc* var = &method->vars[left_op->index];
      if (var->max > right_op->max) { 
        var->max = right_op->max;
        if (var->min > var->max) var->min = var->max;
      }
      if (vars != NULL) { 
        // left > right
        var = &vars[left_op->index];
        if (var->min <= right_op->min) { 
          var->min = right_op->min == ranges[tp_int].max 
            ? right_op->min : right_op->min+1;
          if (var->min > var->max) var->max = var->min;
        }
      }
    }
    stack_pointer = left_op;  
    break;
  case if_icmpge:
    if (right_op->index >= 0) {   
      // left < right
      var_desc* var = &method->vars[right_op->index];
      if (var->min <= left_op->min) { 
        var->min = left_op->min == ranges[tp_int].max
          ? left_op->min : left_op->min+1;
        if (var->min > var->max) var->max = var->min;
      }
      if (vars != NULL) { 
        // left >= right
        var = &vars[right_op->index];
        if (var->max > left_op->max) { 
          var->max = left_op->max;
          if (var->min > var->max) var->min = var->max;
        }
      }
    }
    if (left_op->index >= 0) { 
      // left < right
      var_desc* var = &method->vars[left_op->index];
      if (var->max >= right_op->max) { 
        var->max = right_op->max == ranges[tp_int].min
          ? right_op->max : right_op->max-1;
        if (var->min > var->max) var->min = var->max;
      }
      if (vars != NULL) { 
        // left >= right
        var = &vars[left_op->index];
        if (var->min < right_op->min) { 
          var->min = right_op->min;
          if (var->min > var->max) var->max = var->min;
        }
      }
    }
    stack_pointer = left_op;  
    break;
  case if_acmpeq:
    if (vars != NULL) { 
      if (right_op->index >= 0) { 
        vars[right_op->index].mask &= left_op->mask;
      } 
      if (left_op->index >= 0) { 
        vars[left_op->index].mask &= right_op->mask;
      } 
    }
    stack_pointer = left_op;
    break;
  case if_acmpne:
    if (right_op->index >= 0) { 
      method->vars[right_op->index].mask &= left_op->mask;
    } 
    if (left_op->index >= 0) { 
      method->vars[left_op->index].mask &= right_op->mask;
    } 
    stack_pointer = left_op;
    break;
  case ifnull:
    if (right_op->index >= 0) { 
      method->vars[right_op->index].mask |= var_desc::vs_not_null;
      if (vars != NULL) { 
        vars[right_op->index].mask &= ~var_desc::vs_not_null;
      }
    }
    stack_pointer = right_op;
    break;
  case ifnonnull:
    if (right_op->index >= 0) { 
      method->vars[right_op->index].mask &= ~var_desc::vs_not_null;
      if (vars != NULL) { 
        vars[right_op->index].mask |= var_desc::vs_not_null;
      }
    }
    stack_pointer = right_op;
    break;
  default:
    stack_pointer = sp;
  }
  stack_top[1] = stack_pointer[-1];
  stack_top[0] = stack_pointer[-2];
  return sp;
}

 

vbm_operand* ctx_merge::transfer(method_desc* method, vbm_operand* sp, 
                                 byte, byte& prev_cop)
{
  var_desc save_var;
  method->in_monitor = come_from->in_monitor;
  if (cmd == cmd_case_ctx && come_from->switch_var_index >= 0) { 
    // If branch is part of switch and switch expression is local variable,
    // then we know value of this variable if this branch takes place
    var_desc* var = &come_from->vars[come_from->switch_var_index];
    save_var = *var;
    var->max = var->min = var->mask = case_value;
  }
  var_desc* v0 = method->vars;
  var_desc* v1 = come_from->vars;
  if (prev_cop == goto_near || prev_cop == goto_w 
      || prev_cop == ret || prev_cop == athrow 
      || prev_cop == lookupswitch || prev_cop == tableswitch
      || unsigned(prev_cop - ireturn) <= unsigned(vreturn-ireturn))
    {
      // Control can be passed to this point only by branch: 
      // no need to merge states
      for (int i = method->n_vars; --i >= 0; v0++, v1++) { 
        if (v0->type == v1->type) { 
          v0->min = v1->min;
          v0->max = v1->max;
          v0->mask = v1->mask;
        } else if (v1->type == tp_void) { 
          v0->type = tp_void;
        }
      }
      sp = come_from->stack_pointer;
      sp[-1] = come_from->stack_top[1];
      sp[-2] = come_from->stack_top[0];
      // all successive ctx_merge::transfer should merge variables properties
      prev_cop = nop; 
    } else { 
      // merge states
      for (int i = method->n_vars; --i >= 0; v0++, v1++) { 
        if (v0->type == v1->type) { 
          if (IS_INT_TYPE(v0->type)) { 
            if (v0->min > v1->min) v0->min = v1->min;
            if (v0->max < v1->max) v0->max = v1->max;
            v0->mask |= v1->mask;
#ifdef INT8_DEFINED
          } else if (v0->type == tp_long) { 
            int8 min0  = LOAD_INT8(v0,min); 
            int8 max0  = LOAD_INT8(v0,max); 
            int8 mask0 = LOAD_INT8(v0,mask); 
            int8 min1  = LOAD_INT8(v1,min); 
            int8 max1  = LOAD_INT8(v1,max); 
            int8 mask1 = LOAD_INT8(v1,mask); 
            if (min0 > min1) { 
              STORE_INT8(v0, min, min1);
            } 
            if (max0 < max1) { 
              STORE_INT8(v0, max, max1); 
            }
            mask0 |= mask1;
            STORE_INT8(v0, mask, mask0);
            v0 += 1; 
            v1 += 1; 
            i -= 1; 
            assert(i >= 0);
#endif
          } else { 
            if (v0->min > v1->min) v0->min = v1->min;
            if (v0->max < v1->max) v0->max = v1->max;
            v0->mask &= v1->mask;
          }
        } else if (v0->type != tp_void && v1->type == tp_void) { 
          if (IS_INT_TYPE(v0->type)) { 
            v0->min = ranges[tp_int].min;
            v0->max = ranges[tp_int].max;
            v0->mask = ALL_BITS;
          } else if (v0->type == tp_long) { 
            v0[0].min  = 0x80000000;
            v0[0].max  = 0x7fffffff;
            v0[0].mask = 0xffffffff;
            v0[1].min  = 0x00000000;
            v0[1].max  = 0xffffffff;
            v0[1].mask = 0xffffffff;
          } else { 
            v0->min = 0;
            v0->max = MAX_ARRAY_LENGTH;
          }
        }
      }
      assert(sp == come_from->stack_pointer);
      if (IS_INT_TYPE(come_from->stack_top[1].type)) { 
        if (sp[-1].min > come_from->stack_top[1].min) { 
          sp[-1].min = come_from->stack_top[1].min;
        } 
        if (sp[-1].max < come_from->stack_top[1].max) { 
          sp[-1].max = come_from->stack_top[1].max;
        }
        sp[-1].mask |= come_from->stack_top[1].mask;
#ifdef INT8_DEFINED
      } else if (come_from->stack_top[1].type == tp_long) { 
        int8 min0  = LOAD_INT8(sp-2,min); 
        int8 max0  = LOAD_INT8(sp-2,max); 
        int8 mask0 = LOAD_INT8(sp-2,mask); 
        int8 min1  = LOAD_INT8(come_from->stack_top,min); 
        int8 max1  = LOAD_INT8(come_from->stack_top,max); 
        int8 mask1 = LOAD_INT8(come_from->stack_top,mask); 
        if (min0 > min1) {
          STORE_INT8(sp-2, min, min1);
        } 
        if (max0 < max1) { 
          STORE_INT8(sp-2, max, max1); 
        }
        mask0 |= mask1;
        STORE_INT8(sp-2, mask, mask0);      
#endif
      } else { 
        if (sp[-1].min > come_from->stack_top[1].min) { 
          sp[-1].min = come_from->stack_top[1].min;
        } 
        if (sp[-1].max < come_from->stack_top[1].max) { 
          sp[-1].max = come_from->stack_top[1].max;
        }
        sp[-1].mask &= come_from->stack_top[1].mask;
      }
    }
  if (--come_from->n_branches == 0) { 
    delete[] come_from->vars;
  } else if (cmd == cmd_case_ctx && come_from->switch_var_index >= 0) { 
    // restore state of switch expression varaible, 
    // because it can be used in other branches
    come_from->vars[come_from->switch_var_index] = save_var;
  }
  return sp;
}

vbm_operand* ctx_entry_point::transfer(method_desc* method, vbm_operand* sp, 
                                       byte, byte&)
{
#if 1
  //
  // As far as state of variable is not followed correctly in case of 
  // subroutine execution or catching exception, the obviouse approach is
  // to reset state of all local variables. But in this case we will loose
  // useful information, so I decide to keep variables state, 
  // hopping that it will not cause confusing Jlint messages.
  //
  var_desc* var = method->vars;
  for (int i = method->n_vars; --i >= 0; var++) { 
    int type = var->type;
    if (IS_INT_TYPE(type)) { 
      var->min  = ranges[type].min;
      var->max  = ranges[type].max;
      var->mask = var->min | var->max;
    } else if (type == tp_long) { 
      var->min  = 0x80000000;
      var->max  = 0x7fffffff;
      var->mask = 0xffffffff;
      var += 1;
      var->min  = 0x00000000;
      var->max  = 0xffffffff;
      var->mask = 0xffffffff;
      i -= 1;
      assert(i >= 0);
    } else { 
      var->min  = 0;
      var->max  = MAX_ARRAY_LENGTH;
      var->mask = var_desc::vs_unknown;
    }
  }
#endif
  sp->type = tp_object;
  sp->mask = var_desc::vs_not_null;
  sp->min = 0;
  sp->max = MAX_ARRAY_LENGTH;
  return sp+1; // execption object is pushed on stack
}
   

vbm_operand* ctx_reset::transfer(method_desc* method, vbm_operand* sp, 
                                 byte, byte&)
{
  var_desc* var = method->vars;
  for (int n = method->n_vars, i = 0; i < n; i++, var++) { 
    //
    // Reset vaules of local variables which were modified in region of
    // code between backward jump label and backward jump intruction
    //
    if (method->var_store_count[i] != var_store_count[i]) { 
      int type = var->type;
      if (IS_INT_TYPE(type)) { 
        var->min  = ranges[type].min;
        var->max  = ranges[type].max;
        var->mask = var->min | var->max;
      } else if (type == tp_long) { 
        var->min  = 0x80000000;
        var->max  = 0x7fffffff;
        var->mask = 0xffffffff;
        var += 1;
        var->min  = 0x00000000;
        var->max  = 0xffffffff;
        var->mask = 0xffffffff;
        i += 1;
        assert(i < n);
      } else { 
        var->mask = var_desc::vs_unknown;
        var->min  = 0;
        var->max  = MAX_ARRAY_LENGTH;
      }
    }
  }
  delete[] var_store_count;
  return sp;
}

Generated by  Doxygen 1.6.0   Back to index