| Index: src/scopeinfo.cc
 | 
| ===================================================================
 | 
| --- src/scopeinfo.cc	(revision 5059)
 | 
| +++ src/scopeinfo.cc	(working copy)
 | 
| @@ -204,12 +204,6 @@
 | 
|  }
 | 
|  
 | 
|  
 | 
| -static inline Object** ReadSentinel(Object** p) {
 | 
| -  ASSERT(*p == NULL);
 | 
| -  return p + 1;
 | 
| -}
 | 
| -
 | 
| -
 | 
|  template <class Allocator>
 | 
|  static Object** ReadList(Object** p, List<Handle<String>, Allocator >* list) {
 | 
|    ASSERT(list->is_empty());
 | 
| @@ -220,7 +214,7 @@
 | 
|      p = ReadSymbol(p, &s);
 | 
|      list->Add(s);
 | 
|    }
 | 
| -  return ReadSentinel(p);
 | 
| +  return p;
 | 
|  }
 | 
|  
 | 
|  
 | 
| @@ -239,42 +233,19 @@
 | 
|      list->Add(s);
 | 
|      modes->Add(static_cast<Variable::Mode>(m));
 | 
|    }
 | 
| -  return ReadSentinel(p);
 | 
| +  return p;
 | 
|  }
 | 
|  
 | 
|  
 | 
|  template<class Allocator>
 | 
| -Handle<Object> ScopeInfo<Allocator>::CreateHeapObject(Scope* scope) {
 | 
| -  ScopeInfo<ZoneListAllocationPolicy> sinfo(scope);
 | 
| -  return sinfo.Serialize();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -template<class Allocator>
 | 
| -Object* ScopeInfo<Allocator>::EmptyHeapObject() {
 | 
| -  return Heap::empty_fixed_array();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -inline bool IsNotEmpty(Object* data) {
 | 
| -  return FixedArray::cast(data)->length() != 0;
 | 
| -}
 | 
| -
 | 
| -
 | 
| -inline Object** GetDataStart(Object* data) {
 | 
| -  return FixedArray::cast(data)->data_start();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -template<class Allocator>
 | 
| -ScopeInfo<Allocator>::ScopeInfo(Object* data)
 | 
| +ScopeInfo<Allocator>::ScopeInfo(SerializedScopeInfo* data)
 | 
|    : function_name_(Factory::empty_symbol()),
 | 
|      parameters_(4),
 | 
|      stack_slots_(8),
 | 
|      context_slots_(8),
 | 
|      context_modes_(8) {
 | 
| -  if (IsNotEmpty(data)) {
 | 
| -    Object** p0 = GetDataStart(data);
 | 
| +  if (data->length() > 0) {
 | 
| +    Object** p0 = data->data_start();
 | 
|      Object** p = p0;
 | 
|      p = ReadSymbol(p, &function_name_);
 | 
|      p = ReadBool(p, &calls_eval_);
 | 
| @@ -304,12 +275,6 @@
 | 
|  }
 | 
|  
 | 
|  
 | 
| -static inline Object** WriteSentinel(Object** p) {
 | 
| -  *p++ = NULL;
 | 
| -  return p;
 | 
| -}
 | 
| -
 | 
| -
 | 
|  template <class Allocator>
 | 
|  static Object** WriteList(Object** p, List<Handle<String>, Allocator >* list) {
 | 
|    const int n = list->length();
 | 
| @@ -317,7 +282,7 @@
 | 
|    for (int i = 0; i < n; i++) {
 | 
|      p = WriteSymbol(p, list->at(i));
 | 
|    }
 | 
| -  return WriteSentinel(p);
 | 
| +  return p;
 | 
|  }
 | 
|  
 | 
|  
 | 
| @@ -331,23 +296,24 @@
 | 
|      p = WriteSymbol(p, list->at(i));
 | 
|      p = WriteInt(p, modes->at(i));
 | 
|    }
 | 
| -  return WriteSentinel(p);
 | 
| +  return p;
 | 
|  }
 | 
|  
 | 
|  
 | 
|  template<class Allocator>
 | 
| -Handle<Object> ScopeInfo<Allocator>::Serialize() {
 | 
| -  // function name, calls eval, length & sentinel for 3 tables:
 | 
| -  const int extra_slots = 1 + 1 + 2 * 3;
 | 
| +Handle<SerializedScopeInfo> ScopeInfo<Allocator>::Serialize() {
 | 
| +  // function name, calls eval, length for 3 tables:
 | 
| +  const int extra_slots = 1 + 1 + 3;
 | 
|    int length = extra_slots +
 | 
|                 context_slots_.length() * 2 +
 | 
|                 parameters_.length() +
 | 
|                 stack_slots_.length();
 | 
|  
 | 
| -  Handle<Object> data(Factory::NewFixedArray(length, TENURED));
 | 
| +  Handle<SerializedScopeInfo> data(
 | 
| +      SerializedScopeInfo::cast(*Factory::NewFixedArray(length, TENURED)));
 | 
|    AssertNoAllocation nogc;
 | 
|  
 | 
| -  Object** p0 = GetDataStart(*data);
 | 
| +  Object** p0 = data->data_start();
 | 
|    Object** p = p0;
 | 
|    p = WriteSymbol(p, function_name_);
 | 
|    p = WriteBool(p, calls_eval_);
 | 
| @@ -360,36 +326,69 @@
 | 
|  }
 | 
|  
 | 
|  
 | 
| -static Object** ContextEntriesAddr(Object* data) {
 | 
| -  ASSERT(IsNotEmpty(data));
 | 
| -  // +2 for function name and calls eval:
 | 
| -  return GetDataStart(data) + 2;
 | 
| +template<class Allocator>
 | 
| +Handle<String> ScopeInfo<Allocator>::LocalName(int i) const {
 | 
| +  // A local variable can be allocated either on the stack or in the context.
 | 
| +  // For variables allocated in the context they are always preceded by
 | 
| +  // Context::MIN_CONTEXT_SLOTS of fixed allocated slots in the context.
 | 
| +  if (i < number_of_stack_slots()) {
 | 
| +    return stack_slot_name(i);
 | 
| +  } else {
 | 
| +    return context_slot_name(i - number_of_stack_slots() +
 | 
| +                             Context::MIN_CONTEXT_SLOTS);
 | 
| +  }
 | 
|  }
 | 
|  
 | 
|  
 | 
| -static Object** ParameterEntriesAddr(Object* data) {
 | 
| -  ASSERT(IsNotEmpty(data));
 | 
| -  Object** p = ContextEntriesAddr(data);
 | 
| -  int n;  // number of context slots;
 | 
| -  p = ReadInt(p, &n);
 | 
| -  return p + n*2 + 1;  // *2 for pairs, +1 for sentinel
 | 
| +template<class Allocator>
 | 
| +int ScopeInfo<Allocator>::NumberOfLocals() const {
 | 
| +  int number_of_locals = number_of_stack_slots();
 | 
| +  if (number_of_context_slots() > 0) {
 | 
| +    ASSERT(number_of_context_slots() >= Context::MIN_CONTEXT_SLOTS);
 | 
| +    number_of_locals += number_of_context_slots() - Context::MIN_CONTEXT_SLOTS;
 | 
| +  }
 | 
| +  return number_of_locals;
 | 
|  }
 | 
|  
 | 
|  
 | 
| -static Object** StackSlotEntriesAddr(Object* data) {
 | 
| -  ASSERT(IsNotEmpty(data));
 | 
| -  Object** p = ParameterEntriesAddr(data);
 | 
| -  int n;  // number of parameter slots;
 | 
| -  p = ReadInt(p, &n);
 | 
| -  return p + n + 1;  // +1 for sentinel
 | 
| +Handle<SerializedScopeInfo> SerializedScopeInfo::Create(Scope* scope) {
 | 
| +  ScopeInfo<ZoneListAllocationPolicy> sinfo(scope);
 | 
| +  return sinfo.Serialize();
 | 
|  }
 | 
|  
 | 
|  
 | 
| -template<class Allocator>
 | 
| -bool ScopeInfo<Allocator>::CallsEval(Object* data) {
 | 
| -  if (IsNotEmpty(data)) {
 | 
| -    // +1 for function name:
 | 
| -    Object** p = GetDataStart(data) + 1;
 | 
| +SerializedScopeInfo* SerializedScopeInfo::Empty() {
 | 
| +  return reinterpret_cast<SerializedScopeInfo*>(Heap::empty_fixed_array());
 | 
| +}
 | 
| +
 | 
| +
 | 
| +Object** SerializedScopeInfo::ContextEntriesAddr() {
 | 
| +  ASSERT(length() > 0);
 | 
| +  return data_start() + 2;  // +2 for function name and calls eval.
 | 
| +}
 | 
| +
 | 
| +
 | 
| +Object** SerializedScopeInfo::ParameterEntriesAddr() {
 | 
| +  ASSERT(length() > 0);
 | 
| +  Object** p = ContextEntriesAddr();
 | 
| +  int number_of_context_slots;
 | 
| +  p = ReadInt(p, &number_of_context_slots);
 | 
| +  return p + number_of_context_slots*2;  // *2 for pairs
 | 
| +}
 | 
| +
 | 
| +
 | 
| +Object** SerializedScopeInfo::StackSlotEntriesAddr() {
 | 
| +  ASSERT(length() > 0);
 | 
| +  Object** p = ParameterEntriesAddr();
 | 
| +  int number_of_parameter_slots;
 | 
| +  p = ReadInt(p, &number_of_parameter_slots);
 | 
| +  return p + number_of_parameter_slots;
 | 
| +}
 | 
| +
 | 
| +
 | 
| +bool SerializedScopeInfo::CallsEval() {
 | 
| +  if (length() > 0) {
 | 
| +    Object** p = data_start() + 1;  // +1 for function name.
 | 
|      bool calls_eval;
 | 
|      p = ReadBool(p, &calls_eval);
 | 
|      return calls_eval;
 | 
| @@ -398,53 +397,49 @@
 | 
|  }
 | 
|  
 | 
|  
 | 
| -template<class Allocator>
 | 
| -int ScopeInfo<Allocator>::NumberOfStackSlots(Object* data) {
 | 
| -  if (IsNotEmpty(data)) {
 | 
| -    Object** p = StackSlotEntriesAddr(data);
 | 
| -    int n;  // number of stack slots;
 | 
| -    ReadInt(p, &n);
 | 
| -    return n;
 | 
| +int SerializedScopeInfo::NumberOfStackSlots() {
 | 
| +  if (length() > 0) {
 | 
| +    Object** p = StackSlotEntriesAddr();
 | 
| +    int number_of_stack_slots;
 | 
| +    ReadInt(p, &number_of_stack_slots);
 | 
| +    return number_of_stack_slots;
 | 
|    }
 | 
|    return 0;
 | 
|  }
 | 
|  
 | 
|  
 | 
| -template<class Allocator>
 | 
| -int ScopeInfo<Allocator>::NumberOfContextSlots(Object* data) {
 | 
| -  if (IsNotEmpty(data)) {
 | 
| -    Object** p = ContextEntriesAddr(data);
 | 
| -    int n;  // number of context slots;
 | 
| -    ReadInt(p, &n);
 | 
| -    return n + Context::MIN_CONTEXT_SLOTS;
 | 
| +int SerializedScopeInfo::NumberOfContextSlots() {
 | 
| +  if (length() > 0) {
 | 
| +    Object** p = ContextEntriesAddr();
 | 
| +    int number_of_context_slots;
 | 
| +    ReadInt(p, &number_of_context_slots);
 | 
| +    return number_of_context_slots + Context::MIN_CONTEXT_SLOTS;
 | 
|    }
 | 
|    return 0;
 | 
|  }
 | 
|  
 | 
|  
 | 
| -template<class Allocator>
 | 
| -bool ScopeInfo<Allocator>::HasHeapAllocatedLocals(Object* data) {
 | 
| -  if (IsNotEmpty(data)) {
 | 
| -    Object** p = ContextEntriesAddr(data);
 | 
| -    int n;  // number of context slots;
 | 
| -    ReadInt(p, &n);
 | 
| -    return n > 0;
 | 
| +bool SerializedScopeInfo::HasHeapAllocatedLocals() {
 | 
| +  if (length() > 0) {
 | 
| +    Object** p = ContextEntriesAddr();
 | 
| +    int number_of_context_slots;
 | 
| +    ReadInt(p, &number_of_context_slots);
 | 
| +    return number_of_context_slots > 0;
 | 
|    }
 | 
|    return false;
 | 
|  }
 | 
|  
 | 
|  
 | 
| -template<class Allocator>
 | 
| -int ScopeInfo<Allocator>::StackSlotIndex(Object* data, String* name) {
 | 
| +int SerializedScopeInfo::StackSlotIndex(String* name) {
 | 
|    ASSERT(name->IsSymbol());
 | 
| -  if (IsNotEmpty(data)) {
 | 
| -    // Loop below depends on the NULL sentinel after the stack slot names.
 | 
| -    ASSERT(NumberOfStackSlots(data) > 0 ||
 | 
| -           *(StackSlotEntriesAddr(data) + 1) == NULL);
 | 
| -    // slots start after length entry
 | 
| -    Object** p0 = StackSlotEntriesAddr(data) + 1;
 | 
| +  if (length() > 0) {
 | 
| +    // Slots start after length entry.
 | 
| +    Object** p0 = StackSlotEntriesAddr();
 | 
| +    int number_of_stack_slots;
 | 
| +    p0 = ReadInt(p0, &number_of_stack_slots);
 | 
|      Object** p = p0;
 | 
| -    while (*p != NULL) {
 | 
| +    Object** end = p0 + number_of_stack_slots;
 | 
| +    while (p != end) {
 | 
|        if (*p == name) return static_cast<int>(p - p0);
 | 
|        p++;
 | 
|      }
 | 
| @@ -452,24 +447,18 @@
 | 
|    return -1;
 | 
|  }
 | 
|  
 | 
| -
 | 
| -template<class Allocator>
 | 
| -int ScopeInfo<Allocator>::ContextSlotIndex(Object* data,
 | 
| -                                           String* name,
 | 
| -                                           Variable::Mode* mode) {
 | 
| +int SerializedScopeInfo::ContextSlotIndex(String* name, Variable::Mode* mode) {
 | 
|    ASSERT(name->IsSymbol());
 | 
| -  int result = ContextSlotCache::Lookup(data, name, mode);
 | 
| +  int result = ContextSlotCache::Lookup(this, name, mode);
 | 
|    if (result != ContextSlotCache::kNotFound) return result;
 | 
| -  if (IsNotEmpty(data)) {
 | 
| -    // Loop below depends on the NULL sentinel after the context slot names.
 | 
| -    ASSERT(NumberOfContextSlots(data) >= Context::MIN_CONTEXT_SLOTS ||
 | 
| -           *(ContextEntriesAddr(data) + 1) == NULL);
 | 
| -
 | 
| -    // slots start after length entry
 | 
| -    Object** p0 = ContextEntriesAddr(data) + 1;
 | 
| +  if (length() > 0) {
 | 
| +    // Slots start after length entry.
 | 
| +    Object** p0 = ContextEntriesAddr();
 | 
| +    int number_of_context_slots;
 | 
| +    p0 = ReadInt(p0, &number_of_context_slots);
 | 
|      Object** p = p0;
 | 
| -    // contexts may have no variable slots (in the presence of eval()).
 | 
| -    while (*p != NULL) {
 | 
| +    Object** end = p0 + number_of_context_slots * 2;
 | 
| +    while (p != end) {
 | 
|        if (*p == name) {
 | 
|          ASSERT(((p - p0) & 1) == 0);
 | 
|          int v;
 | 
| @@ -477,21 +466,20 @@
 | 
|          Variable::Mode mode_value = static_cast<Variable::Mode>(v);
 | 
|          if (mode != NULL) *mode = mode_value;
 | 
|          result = static_cast<int>((p - p0) >> 1) + Context::MIN_CONTEXT_SLOTS;
 | 
| -        ContextSlotCache::Update(data, name, mode_value, result);
 | 
| +        ContextSlotCache::Update(this, name, mode_value, result);
 | 
|          return result;
 | 
|        }
 | 
|        p += 2;
 | 
|      }
 | 
|    }
 | 
| -  ContextSlotCache::Update(data, name, Variable::INTERNAL, -1);
 | 
| +  ContextSlotCache::Update(this, name, Variable::INTERNAL, -1);
 | 
|    return -1;
 | 
|  }
 | 
|  
 | 
|  
 | 
| -template<class Allocator>
 | 
| -int ScopeInfo<Allocator>::ParameterIndex(Object* data, String* name) {
 | 
| +int SerializedScopeInfo::ParameterIndex(String* name) {
 | 
|    ASSERT(name->IsSymbol());
 | 
| -  if (IsNotEmpty(data)) {
 | 
| +  if (length() > 0) {
 | 
|      // We must read parameters from the end since for
 | 
|      // multiply declared parameters the value of the
 | 
|      // last declaration of that parameter is used
 | 
| @@ -502,10 +490,10 @@
 | 
|      // once, with corresponding index. This requires a new
 | 
|      // implementation of the ScopeInfo code. See also other
 | 
|      // comments in this file regarding this.
 | 
| -    Object** p = ParameterEntriesAddr(data);
 | 
| -    int n;  // number of parameters
 | 
| -    Object** p0 = ReadInt(p, &n);
 | 
| -    p = p0 + n;
 | 
| +    Object** p = ParameterEntriesAddr();
 | 
| +    int number_of_parameter_slots;
 | 
| +    Object** p0 = ReadInt(p, &number_of_parameter_slots);
 | 
| +    p = p0 + number_of_parameter_slots;
 | 
|      while (p > p0) {
 | 
|        p--;
 | 
|        if (*p == name) return static_cast<int>(p - p0);
 | 
| @@ -515,50 +503,23 @@
 | 
|  }
 | 
|  
 | 
|  
 | 
| -template<class Allocator>
 | 
| -int ScopeInfo<Allocator>::FunctionContextSlotIndex(Object* data, String* name) {
 | 
| +int SerializedScopeInfo::FunctionContextSlotIndex(String* name) {
 | 
|    ASSERT(name->IsSymbol());
 | 
| -  if (IsNotEmpty(data)) {
 | 
| -    Object** p = GetDataStart(data);
 | 
| +  if (length() > 0) {
 | 
| +    Object** p = data_start();
 | 
|      if (*p == name) {
 | 
| -      p = ContextEntriesAddr(data);
 | 
| -      int n;  // number of context slots
 | 
| -      ReadInt(p, &n);
 | 
| -      ASSERT(n != 0);
 | 
| +      p = ContextEntriesAddr();
 | 
| +      int number_of_context_slots;
 | 
| +      ReadInt(p, &number_of_context_slots);
 | 
| +      ASSERT(number_of_context_slots != 0);
 | 
|        // The function context slot is the last entry.
 | 
| -      return n + Context::MIN_CONTEXT_SLOTS - 1;
 | 
| +      return number_of_context_slots + Context::MIN_CONTEXT_SLOTS - 1;
 | 
|      }
 | 
|    }
 | 
|    return -1;
 | 
|  }
 | 
|  
 | 
|  
 | 
| -template<class Allocator>
 | 
| -Handle<String> ScopeInfo<Allocator>::LocalName(int i) const {
 | 
| -  // A local variable can be allocated either on the stack or in the context.
 | 
| -  // For variables allocated in the context they are always preceded by the
 | 
| -  // number Context::MIN_CONTEXT_SLOTS number of fixed allocated slots in the
 | 
| -  // context.
 | 
| -  if (i < number_of_stack_slots()) {
 | 
| -    return stack_slot_name(i);
 | 
| -  } else {
 | 
| -    return context_slot_name(i - number_of_stack_slots() +
 | 
| -                             Context::MIN_CONTEXT_SLOTS);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -template<class Allocator>
 | 
| -int ScopeInfo<Allocator>::NumberOfLocals() const {
 | 
| -  int number_of_locals = number_of_stack_slots();
 | 
| -  if (number_of_context_slots() > 0) {
 | 
| -    ASSERT(number_of_context_slots() >= Context::MIN_CONTEXT_SLOTS);
 | 
| -    number_of_locals += number_of_context_slots() - Context::MIN_CONTEXT_SLOTS;
 | 
| -  }
 | 
| -  return number_of_locals;
 | 
| -}
 | 
| -
 | 
| -
 | 
|  int ContextSlotCache::Hash(Object* data, String* name) {
 | 
|    // Uses only lower 32 bits if pointers are larger.
 | 
|    uintptr_t addr_hash =
 | 
| 
 |