Chromium Code Reviews| Index: src/scopeinfo.cc |
| diff --git a/src/scopeinfo.cc b/src/scopeinfo.cc |
| index 8ea5f1e734151684828637ea1138dbc8250bbe34..59e707dc5258b2e8953d358686957ca5e010bfaa 100644 |
| --- a/src/scopeinfo.cc |
| +++ b/src/scopeinfo.cc |
| @@ -46,475 +46,315 @@ static int CompareLocal(Variable* const* v, Variable* const* w) { |
| } |
| -template<class Allocator> |
| -ScopeInfo<Allocator>::ScopeInfo(Scope* scope) |
| - : function_name_(FACTORY->empty_symbol()), |
| - calls_eval_(scope->calls_eval()), |
| - is_strict_mode_(scope->is_strict_mode()), |
| - type_(scope->type()), |
| - parameters_(scope->num_parameters()), |
| - stack_slots_(scope->num_stack_slots()), |
| - context_slots_(scope->num_heap_slots()), |
| - context_modes_(scope->num_heap_slots()) { |
| - // Add parameters. |
| - for (int i = 0; i < scope->num_parameters(); i++) { |
| - ASSERT(parameters_.length() == i); |
| - parameters_.Add(scope->parameter(i)->name()); |
| - } |
| +Handle<ScopeInfo> ScopeInfo::Create(Scope* scope) { |
|
Kevin Millikin (Chromium)
2011/11/02 16:31:19
Now that you've removed the template parameter, I
Steven
2011/11/02 18:52:59
Done.
|
| + ZoneList<Variable*> variables(32); // 32 is a wild guess |
|
Kevin Millikin (Chromium)
2011/11/02 16:31:19
Again, not your code, but the "wild guess" here se
Steven
2011/11/02 18:52:59
Will do this in a new CL. Here we are only interes
|
| + ASSERT(variables.is_empty()); |
| + scope->CollectUsedVariables(&variables); |
| - // Add stack locals and collect heap locals. |
| - // We are assuming that the locals' slots are allocated in |
| - // increasing order, so we can simply add them to the |
| - // ScopeInfo lists. However, due to usage analysis, this is |
| - // not true for context-allocated locals: Some of them |
| - // may be parameters which are allocated before the |
| - // non-parameter locals. When the non-parameter locals are |
| - // sorted according to usage, the allocated slot indices may |
| - // not be in increasing order with the variable list anymore. |
| - // Thus, we first collect the context-allocated locals, and then |
| - // sort them by context slot index before adding them to the |
| - // ScopeInfo list. |
| - List<Variable*, Allocator> locals(32); // 32 is a wild guess |
| - ASSERT(locals.is_empty()); |
| - scope->CollectUsedVariables(&locals); |
| - locals.Sort(&CompareLocal); |
| + ZoneList<Variable*> stack_locals(scope->num_stack_slots()); |
| + ZoneList<Variable*> context_locals(scope->num_heap_slots()); |
| - List<Variable*, Allocator> heap_locals(locals.length()); |
| - for (int i = 0; i < locals.length(); i++) { |
| - Variable* var = locals[i]; |
| - if (var->is_used()) { |
| - switch (var->location()) { |
| - case Variable::UNALLOCATED: |
| - case Variable::PARAMETER: |
| - break; |
| + // Collect stack and context locals. |
| + for (int i = 0; i < variables.length(); i++) { |
| + Variable* var = variables[i]; |
| + if (!var->is_used()) continue; |
|
Kevin Millikin (Chromium)
2011/11/02 16:31:19
It's not clear how "CollectUsedVariables" can coll
Steven
2011/11/02 18:52:59
A bit flip because of faulty hardware :P
Done.
On
|
| + switch (var->location()) { |
| + case Variable::UNALLOCATED: |
| + case Variable::PARAMETER: |
| + break; |
| - case Variable::LOCAL: |
| - ASSERT(stack_slots_.length() == var->index()); |
| - stack_slots_.Add(var->name()); |
| - break; |
| + case Variable::LOCAL: |
| + stack_locals.Add(var); |
| + break; |
| - case Variable::CONTEXT: |
| - heap_locals.Add(var); |
| - break; |
| + case Variable::CONTEXT: |
| + context_locals.Add(var); |
| + break; |
| - case Variable::LOOKUP: |
| - // We don't expect lookup variables in the locals list. |
| - UNREACHABLE(); |
| - break; |
| - } |
| + case Variable::LOOKUP: |
| + // We don't expect lookup variables in the locals list. |
| + UNREACHABLE(); |
| + break; |
| } |
| } |
| - // Add heap locals. |
| - if (scope->num_heap_slots() > 0) { |
| - // Add user-defined slots. |
| - for (int i = 0; i < heap_locals.length(); i++) { |
| - ASSERT(heap_locals[i]->index() - Context::MIN_CONTEXT_SLOTS == |
| - context_slots_.length()); |
| - ASSERT(heap_locals[i]->index() - Context::MIN_CONTEXT_SLOTS == |
| - context_modes_.length()); |
| - context_slots_.Add(heap_locals[i]->name()); |
| - context_modes_.Add(heap_locals[i]->mode()); |
| + // Determine use and location of the function variable if it is present. |
| + FunctionVariableInfo function_name_info; |
| + VariableMode function_variable_mode; |
| + if (scope->is_function_scope() && scope->function() != NULL) { |
| + Variable* var = scope->function()->var(); |
| + if (!var->is_used()) { |
| + function_name_info = UNUSED; |
| + } else if (var->IsContextSlot()) { |
| + function_name_info = CONTEXT; |
| + } else { |
| + ASSERT(var->IsStackLocal()); |
| + function_name_info = STACK; |
| } |
| - |
| + function_variable_mode = var->mode(); |
| } else { |
| - ASSERT(heap_locals.length() == 0); |
| - } |
| - |
| - // Add the function context slot, if present. |
| - // For now, this must happen at the very end because of the |
| - // ordering of the scope info slots and the respective slot indices. |
| - if (scope->is_function_scope()) { |
| - VariableProxy* proxy = scope->function(); |
| - if (proxy != NULL && |
| - proxy->var()->is_used() && |
| - proxy->var()->IsContextSlot()) { |
| - function_name_ = proxy->name(); |
| - // Note that we must not find the function name in the context slot |
| - // list - instead it must be handled separately in the |
| - // Contexts::Lookup() function. Thus record an empty symbol here so we |
| - // get the correct number of context slots. |
| - ASSERT(proxy->var()->index() - Context::MIN_CONTEXT_SLOTS == |
| - context_slots_.length()); |
| - ASSERT(proxy->var()->index() - Context::MIN_CONTEXT_SLOTS == |
| - context_modes_.length()); |
| - context_slots_.Add(FACTORY->empty_symbol()); |
| - context_modes_.Add(proxy->var()->mode()); |
| - } |
| + function_name_info = NONE; |
| + function_variable_mode = VAR; |
| } |
| -} |
| - |
| - |
| -// Encoding format in a FixedArray object: |
| -// |
| -// - function name |
| -// |
| -// - calls eval boolean flag |
| -// |
| -// - is strict mode scope |
| -// |
| -// - scope type |
| -// |
| -// - number of variables in the context object (smi) (= function context |
| -// slot index + 1) |
| -// - list of pairs (name, Var mode) of context-allocated variables (starting |
| -// with context slot 0) |
| -// |
| -// - number of parameters (smi) |
| -// - list of parameter names (starting with parameter 0 first) |
| -// |
| -// - number of variables on the stack (smi) |
| -// - list of names of stack-allocated variables (starting with stack slot 0) |
| - |
| -// The ScopeInfo representation could be simplified and the ScopeInfo |
| -// re-implemented (with almost the same interface). Here is a |
| -// suggestion for the new format: |
| -// |
| -// - have a single list with all variable names (parameters, stack locals, |
| -// context locals), followed by a list of non-Object* values containing |
| -// the variables information (what kind, index, attributes) |
| -// - searching the linear list of names is fast and yields an index into the |
| -// list if the variable name is found |
| -// - that list index is then used to find the variable information in the |
| -// subsequent list |
| -// - the list entries don't have to be in any particular order, so all the |
| -// current sorting business can go away |
| -// - the ScopeInfo lookup routines can be reduced to perhaps a single lookup |
| -// which returns all information at once |
| -// - when gathering the information from a Scope, we only need to iterate |
| -// through the local variables (parameters and context info is already |
| -// present) |
| + const bool has_function_name = function_name_info != NONE; |
| + const int num_parameters = scope->num_parameters(); |
| + const int num_stack_locals = stack_locals.length(); |
| + const int num_context_locals = context_locals.length(); |
| + const int length = VARIABLE_PART_INDEX |
| + + num_parameters + num_stack_locals + 2 * num_context_locals |
| + + (has_function_name ? 2 : 0); |
| -template <class T> |
| -static inline Object** ReadInt(Object** p, T* x) { |
| - *x = static_cast<T>((reinterpret_cast<Smi*>(*p++))->value()); |
| - return p; |
| -} |
| + Handle<ScopeInfo> scope_info = FACTORY->NewScopeInfo(length); |
| + // Encode the flags. |
| + int flags = TypeField::encode(scope->type()) | |
| + CallsEvalField::encode(scope->calls_eval()) | |
| + StrictModeField::encode(scope->is_strict_mode()) | |
| + FunctionVariableField::encode(function_name_info) | |
| + FunctionVariableMode::encode(function_variable_mode); |
| + scope_info->set_flags(flags); |
| + scope_info->set_num_parameters(num_parameters); |
| + scope_info->set_num_stack_locals(num_stack_locals); |
| + scope_info->set_num_context_locals(num_context_locals); |
| -static inline Object** ReadBool(Object** p, bool* x) { |
| - *x = (reinterpret_cast<Smi*>(*p++))->value() != 0; |
| - return p; |
| -} |
| - |
| - |
| -template <class T> |
| -static inline Object** ReadObject(Object** p, Handle<T>* s) { |
| - *s = Handle<T>::cast(Handle<Object>(*p++)); |
| - return p; |
| -} |
| - |
| + int index = VARIABLE_PART_INDEX; |
| + // Add parameters. |
| + ASSERT(index == scope_info->ParameterEntriesIndex()); |
| + for (int i = 0; i < num_parameters; ++i) { |
| + scope_info->set(index++, *scope->parameter(i)->name()); |
| + } |
| -template <class Allocator, class T> |
| -static Object** ReadList(Object** p, List<Handle<T>, Allocator >* list) { |
| - ASSERT(list->is_empty()); |
| - int n; |
| - p = ReadInt(p, &n); |
| - while (n-- > 0) { |
| - Handle<T> s; |
| - p = ReadObject(p, &s); |
| - list->Add(s); |
| + // Add stack locals' names. We are assuming that the stack locals' |
| + // slots are allocated in increasing order, so we can simply add |
| + // them to the ScopeInfo object. |
| + ASSERT(index == scope_info->StackLocalEntriesIndex()); |
| + for (int i = 0; i < num_stack_locals; ++i) { |
| + ASSERT(stack_locals[i]->index() == i); |
| + scope_info->set(index++, *stack_locals[i]->name()); |
| } |
| - return p; |
| -} |
| + // Due to usage analysis, context-allocated locals are not necessarily in |
| + // increasing order: Some of them may be parameters which are allocated before |
| + // the non-parameter locals. When the non-parameter locals are sorted |
| + // according to usage, the allocated slot indices may not be in increasing |
| + // order with the variable list anymore. Thus, we first need to sort them by |
| + // context slot index before adding them to the ScopeInfo object. |
| + context_locals.Sort(&CompareLocal); |
| -template <class Allocator> |
| -static Object** ReadList(Object** p, |
| - List<Handle<String>, Allocator>* list, |
| - List<VariableMode, Allocator>* modes) { |
| - ASSERT(list->is_empty()); |
| - int n; |
| - p = ReadInt(p, &n); |
| - while (n-- > 0) { |
| - Handle<String> s; |
| - int m; |
| - p = ReadObject(p, &s); |
| - p = ReadInt(p, &m); |
| - list->Add(s); |
| - modes->Add(static_cast<VariableMode>(m)); |
| + // Add context locals' names. |
| + ASSERT(index == scope_info->ContextLocalNameEntriesIndex()); |
| + for (int i = 0; i < num_context_locals; ++i) { |
| + scope_info->set(index++, *context_locals[i]->name()); |
| } |
| - return p; |
| -} |
| - |
| -template<class Allocator> |
| -ScopeInfo<Allocator>::ScopeInfo(SerializedScopeInfo* data) |
| - : function_name_(FACTORY->empty_symbol()), |
| - parameters_(4), |
| - stack_slots_(8), |
| - context_slots_(8), |
| - context_modes_(8) { |
| - if (data->length() > 0) { |
| - Object** p0 = data->data_start(); |
| - Object** p = p0; |
| - p = ReadObject(p, &function_name_); |
| - p = ReadBool(p, &calls_eval_); |
| - p = ReadBool(p, &is_strict_mode_); |
| - p = ReadInt(p, &type_); |
| - p = ReadList<Allocator>(p, &context_slots_, &context_modes_); |
| - p = ReadList<Allocator>(p, ¶meters_); |
| - p = ReadList<Allocator>(p, &stack_slots_); |
| - ASSERT((p - p0) == FixedArray::cast(data)->length()); |
| + // Add context locals' modes. |
| + ASSERT(index == scope_info->ContextLocalModeEntriesIndex()); |
| + for (int i = 0; i < num_context_locals; ++i) { |
| + scope_info->set(index++, Smi::FromInt(context_locals[i]->mode())); |
| } |
| -} |
| + // If present, add the function variable name and its index. |
| + ASSERT(index == scope_info->FunctionNameEntryIndex()); |
| + if (has_function_name) { |
| + int var_index = scope->function()->var()->index(); |
| + scope_info->set(index++, *scope->function()->name()); |
| + scope_info->set(index++, Smi::FromInt(var_index)); |
| + ASSERT(function_name_info != STACK || |
| + (var_index == scope_info->num_stack_locals() && |
| + var_index == scope_info->NumberOfStackSlots() - 1)); |
| + ASSERT(function_name_info != CONTEXT || |
| + var_index == scope_info->NumberOfContextSlots() - 1); |
| + } |
| -static inline Object** WriteInt(Object** p, int x) { |
| - *p++ = Smi::FromInt(x); |
| - return p; |
| + ASSERT(index == scope_info->length()); |
| + ASSERT(scope->num_parameters() == scope_info->num_parameters()); |
| + ASSERT(scope->num_stack_slots() == scope_info->NumberOfStackSlots()); |
| + ASSERT(scope->num_heap_slots() == scope_info->NumberOfContextSlots()); |
| + return scope_info; |
| } |
| -static inline Object** WriteBool(Object** p, bool b) { |
| - *p++ = Smi::FromInt(b ? 1 : 0); |
| - return p; |
| +ScopeInfo* ScopeInfo::Empty() { |
| + return reinterpret_cast<ScopeInfo*>(HEAP->empty_fixed_array()); |
| } |
| -template <class T> |
| -static inline Object** WriteObject(Object** p, Handle<T> s) { |
| - *p++ = *s; |
| - return p; |
| +ScopeType ScopeInfo::Type() { |
| + ASSERT(length() > 0); |
| + return TypeField::decode(flags()); |
| } |
| -template <class Allocator, class T> |
| -static Object** WriteList(Object** p, List<Handle<T>, Allocator >* list) { |
| - const int n = list->length(); |
| - p = WriteInt(p, n); |
| - for (int i = 0; i < n; i++) { |
| - p = WriteObject(p, list->at(i)); |
| +bool ScopeInfo::CallsEval() { |
|
Kevin Millikin (Chromium)
2011/11/02 16:31:19
I like
return length() > 0 && CallsEvalField::dec
Steven
2011/11/02 18:52:59
Done.
|
| + if (length() > 0) { |
| + return CallsEvalField::decode(flags()); |
| + } else { |
| + return false; |
| } |
| - return p; |
| } |
| -template <class Allocator> |
| -static Object** WriteList(Object** p, |
| - List<Handle<String>, Allocator>* list, |
| - List<VariableMode, Allocator>* modes) { |
| - const int n = list->length(); |
| - p = WriteInt(p, n); |
| - for (int i = 0; i < n; i++) { |
| - p = WriteObject(p, list->at(i)); |
| - p = WriteInt(p, modes->at(i)); |
| +bool ScopeInfo::IsStrictMode() { |
| + if (length() > 0) { |
| + return StrictModeField::decode(flags()); |
| + } else { |
| + return false; |
| } |
| - return p; |
| } |
| -template<class Allocator> |
| -Handle<SerializedScopeInfo> ScopeInfo<Allocator>::Serialize() { |
| - // function name, calls eval, is_strict_mode, scope type, |
| - // length for 3 tables: |
| - const int extra_slots = 1 + 1 + 1 + 1 + 3; |
| - int length = extra_slots + |
| - context_slots_.length() * 2 + |
| - parameters_.length() + |
| - stack_slots_.length(); |
| - |
| - Handle<SerializedScopeInfo> data( |
| - SerializedScopeInfo::cast(*FACTORY->NewSerializedScopeInfo(length))); |
| - AssertNoAllocation nogc; |
| - |
| - Object** p0 = data->data_start(); |
| - Object** p = p0; |
| - p = WriteObject(p, function_name_); |
| - p = WriteBool(p, calls_eval_); |
| - p = WriteBool(p, is_strict_mode_); |
| - p = WriteInt(p, type_); |
| - p = WriteList(p, &context_slots_, &context_modes_); |
| - p = WriteList(p, ¶meters_); |
| - p = WriteList(p, &stack_slots_); |
| - ASSERT((p - p0) == length); |
| - |
| - return data; |
| +int ScopeInfo::NumberOfLocals() { |
| + return num_stack_locals() + num_context_locals(); |
| } |
| -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); |
| +int ScopeInfo::NumberOfStackSlots() { |
| + if (length() > 0) { |
| + bool function_name_stack_slot = STACK == |
|
Kevin Millikin (Chromium)
2011/11/02 16:31:19
Hmmm, I could see this requiring two tries to read
Steven
2011/11/02 18:52:59
Done.
|
| + FunctionVariableField::decode(flags()); |
| + return num_stack_locals() + (function_name_stack_slot ? 1 : 0); |
| } |
| + return 0; |
| } |
| -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; |
| +int ScopeInfo::NumberOfContextSlots() { |
| + if (length() > 0) { |
| + int context_locals = num_context_locals(); |
| + bool function_name_context_slot = CONTEXT == |
|
Kevin Millikin (Chromium)
2011/11/02 16:31:19
Same comment as just above.
Steven
2011/11/02 18:52:59
Done.
|
| + FunctionVariableField::decode(flags()); |
| + bool has_context = context_locals > 0 || |
| + function_name_context_slot || |
| + Type() == WITH_SCOPE || |
| + (Type() == FUNCTION_SCOPE && CallsEval()); |
| + if (has_context) { |
| + return Context::MIN_CONTEXT_SLOTS + context_locals + |
| + (function_name_context_slot ? 1 : 0); |
| + } |
| } |
| - return number_of_locals; |
| -} |
| - |
| - |
| -Handle<SerializedScopeInfo> SerializedScopeInfo::Create(Scope* scope) { |
| - ScopeInfo<ZoneListAllocationPolicy> sinfo(scope); |
| - return sinfo.Serialize(); |
| -} |
| - |
| - |
| -SerializedScopeInfo* SerializedScopeInfo::Empty() { |
| - return reinterpret_cast<SerializedScopeInfo*>(HEAP->empty_fixed_array()); |
| -} |
| - |
| - |
| -Object** SerializedScopeInfo::ContextEntriesAddr() { |
| - ASSERT(length() > 0); |
| - // +4 for function name, calls eval, strict mode, scope type. |
| - return data_start() + 4; |
| + return 0; |
| } |
| -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 |
| +bool ScopeInfo::HasFunctionName() { |
| + if (length() > 0) { |
| + return NONE != FunctionVariableField::decode(flags()); |
| + } else { |
| + return false; |
| + } |
| } |
| -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 ScopeInfo::HasHeapAllocatedLocals() { |
| + if (length() > 0) { |
| + return num_context_locals() > 0; |
| + } else { |
| + return false; |
| + } |
| } |
| -bool SerializedScopeInfo::CallsEval() { |
| +bool ScopeInfo::HasContext() { |
| if (length() > 0) { |
| - Object** p = data_start() + 1; // +1 for function name. |
| - bool calls_eval; |
| - p = ReadBool(p, &calls_eval); |
| - return calls_eval; |
| + return NumberOfContextSlots() > 0; |
| + } else { |
| + return false; |
| } |
| - return false; |
| } |
| -bool SerializedScopeInfo::IsStrictMode() { |
| - if (length() > 0) { |
| - Object** p = data_start() + 2; // +2 for function name, calls eval. |
| - bool strict_mode; |
| - p = ReadBool(p, &strict_mode); |
| - return strict_mode; |
| +Handle<String> ScopeInfo::function_name() { |
| + if (HasFunctionName()) { |
| + return Handle<String>(String::cast(get(FunctionNameEntryIndex()))); |
| + } else { |
| + return Handle<String>(); |
| } |
| - return false; |
| } |
| -ScopeType SerializedScopeInfo::Type() { |
| - ASSERT(length() > 0); |
| - // +3 for function name, calls eval, strict mode. |
| - Object** p = data_start() + 3; |
| - ScopeType type; |
| - p = ReadInt(p, &type); |
| - return type; |
| +Handle<String> ScopeInfo::parameter_name(int var) { |
| + ASSERT(0 <= var && var < num_parameters()); |
| + int info_index = ParameterEntriesIndex() + var; |
| + return Handle<String>(String::cast(get(info_index))); |
| } |
| -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; |
| +Handle<String> ScopeInfo::local_name(int var) { |
| + ASSERT(0 <= var && var < NumberOfLocals()); |
| + ASSERT(StackLocalEntriesIndex() + num_stack_locals() == |
| + ContextLocalNameEntriesIndex()); |
| + int info_index = StackLocalEntriesIndex() + var; |
| + return Handle<String>(String::cast(get(info_index))); |
| } |
| -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; |
| +Handle<String> ScopeInfo::stack_local_name(int var) { |
| + ASSERT(0 <= var && var < num_stack_locals()); |
| + int info_index = StackLocalEntriesIndex() + var; |
| + return Handle<String>(String::cast(get(info_index))); |
| } |
| -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; |
| +Handle<String> ScopeInfo::context_local_name(int var) { |
| + ASSERT(0 <= var && var < num_context_locals()); |
| + int info_index = ContextLocalNameEntriesIndex() + var; |
| + return Handle<String>(String::cast(get(info_index))); |
| } |
| -bool SerializedScopeInfo::HasContext() { |
| - return HasHeapAllocatedLocals() || |
| - Type() == WITH_SCOPE; |
| +VariableMode ScopeInfo::context_local_mode(int var) { |
| + ASSERT(0 <= var && var < num_context_locals()); |
| + int info_index = ContextLocalModeEntriesIndex() + var; |
| + return static_cast<VariableMode>(Smi::cast(get(info_index))->value()); |
| } |
| -int SerializedScopeInfo::StackSlotIndex(String* name) { |
| +int ScopeInfo::StackSlotIndex(String* name) { |
| ASSERT(name->IsSymbol()); |
| 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; |
| - Object** end = p0 + number_of_stack_slots; |
| - while (p != end) { |
| - if (*p == name) return static_cast<int>(p - p0); |
| - p++; |
| + int start = StackLocalEntriesIndex(); |
| + int end = StackLocalEntriesIndex() + num_stack_locals(); |
| + for (int i = start; i < end; ++i) { |
| + if (name == get(i)) { |
| + return i - start; |
| + } |
| } |
| } |
| return -1; |
| } |
| -int SerializedScopeInfo::ContextSlotIndex(String* name, VariableMode* mode) { |
| + |
| +int ScopeInfo::ContextSlotIndex(String* name, VariableMode* mode) { |
| ASSERT(name->IsSymbol()); |
| - Isolate* isolate = GetIsolate(); |
| - int result = isolate->context_slot_cache()->Lookup(this, name, mode); |
| - if (result != ContextSlotCache::kNotFound) return result; |
| 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; |
| - Object** end = p0 + number_of_context_slots * 2; |
| - while (p != end) { |
| - if (*p == name) { |
| - ASSERT(((p - p0) & 1) == 0); |
| - int v; |
| - ReadInt(p + 1, &v); |
| - VariableMode mode_value = static_cast<VariableMode>(v); |
| + ContextSlotCache* context_slot_cache = GetIsolate()->context_slot_cache(); |
| + int result = context_slot_cache->Lookup(this, name, mode); |
| + if (result != ContextSlotCache::kNotFound) { |
| + ASSERT(result < NumberOfContextSlots()); |
| + return result; |
| + } |
| + |
| + int start = ContextLocalNameEntriesIndex(); |
| + int end = ContextLocalNameEntriesIndex() + num_context_locals(); |
| + for (int i = start; i < end; ++i) { |
| + if (name == get(i)) { |
| + int var = i - start; |
| + VariableMode mode_value = context_local_mode(var); |
| if (mode != NULL) *mode = mode_value; |
| - result = static_cast<int>((p - p0) >> 1) + Context::MIN_CONTEXT_SLOTS; |
| - isolate->context_slot_cache()->Update(this, name, mode_value, result); |
| + result = Context::MIN_CONTEXT_SLOTS + var; |
| + context_slot_cache->Update(this, name, mode_value, result); |
| + ASSERT(result < NumberOfContextSlots()); |
| return result; |
| } |
| - p += 2; |
| } |
| + context_slot_cache->Update(this, name, INTERNAL, -1); |
| } |
| - isolate->context_slot_cache()->Update(this, name, INTERNAL, -1); |
| return -1; |
| } |
| -int SerializedScopeInfo::ParameterIndex(String* name) { |
| +int ScopeInfo::ParameterIndex(String* name) { |
| ASSERT(name->IsSymbol()); |
| if (length() > 0) { |
| // We must read parameters from the end since for |
| @@ -522,49 +362,57 @@ int SerializedScopeInfo::ParameterIndex(String* name) { |
| // last declaration of that parameter is used |
| // inside a function (and thus we need to look |
| // at the last index). Was bug# 1110337. |
| - // |
| - // Eventually, we should only register such parameters |
| - // 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(); |
| - 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); |
| + int start = ParameterEntriesIndex(); |
| + int end = ParameterEntriesIndex() + num_parameters(); |
| + for (int i = end - 1; i >= start; --i) { |
| + if (name == get(i)) { |
| + return i - start; |
| + } |
| } |
| } |
| return -1; |
| } |
| -int SerializedScopeInfo::FunctionContextSlotIndex(String* name, |
| - VariableMode* mode) { |
| +int ScopeInfo::FunctionContextSlotIndex(String* name, VariableMode* mode) { |
| ASSERT(name->IsSymbol()); |
| if (length() > 0) { |
| - Object** p = data_start(); |
| - if (*p == name) { |
| - p = ContextEntriesAddr(); |
| - int number_of_context_slots; |
| - p = ReadInt(p, &number_of_context_slots); |
| - ASSERT(number_of_context_slots != 0); |
| - // The function context slot is the last entry. |
| - if (mode != NULL) { |
| - // Seek to context slot entry. |
| - p += (number_of_context_slots - 1) * 2; |
| - // Seek to mode. |
| - ++p; |
| - ReadInt(p, mode); |
| - } |
| - return number_of_context_slots + Context::MIN_CONTEXT_SLOTS - 1; |
| + if (FunctionVariableField::decode(flags()) == CONTEXT && |
| + *function_name() == name) { |
| + if (mode != NULL) *mode = FunctionVariableMode::decode(flags()); |
| + return Smi::cast(get(FunctionNameEntryIndex() + 1))->value(); |
| } |
| } |
| return -1; |
| } |
| +int ScopeInfo::ParameterEntriesIndex() { |
| + ASSERT(length() > 0); |
| + return VARIABLE_PART_INDEX; |
| +} |
| + |
| + |
| +int ScopeInfo::StackLocalEntriesIndex() { |
| + return ParameterEntriesIndex() + num_parameters(); |
| +} |
| + |
| + |
| +int ScopeInfo::ContextLocalNameEntriesIndex() { |
| + return StackLocalEntriesIndex() + num_stack_locals(); |
| +} |
| + |
| + |
| +int ScopeInfo::ContextLocalModeEntriesIndex() { |
| + return ContextLocalNameEntriesIndex() + num_context_locals(); |
| +} |
| + |
| + |
| +int ScopeInfo::FunctionNameEntryIndex() { |
| + return ContextLocalModeEntriesIndex() + num_context_locals(); |
| +} |
| + |
| + |
| int ContextSlotCache::Hash(Object* data, String* name) { |
| // Uses only lower 32 bits if pointers are larger. |
| uintptr_t addr_hash = |
| @@ -631,46 +479,50 @@ void ContextSlotCache::ValidateEntry(Object* data, |
| } |
| -template <class Allocator> |
| static void PrintList(const char* list_name, |
| int nof_internal_slots, |
| - List<Handle<String>, Allocator>& list) { |
| - if (list.length() > 0) { |
| + int start, |
| + int end, |
| + ScopeInfo* scope_info) { |
| + if (start < end) { |
| PrintF("\n // %s\n", list_name); |
| if (nof_internal_slots > 0) { |
| PrintF(" %2d - %2d [internal slots]\n", 0 , nof_internal_slots - 1); |
| } |
| - for (int i = 0; i < list.length(); i++) { |
| - PrintF(" %2d ", i + nof_internal_slots); |
| - list[i]->ShortPrint(); |
| + for (int i = nof_internal_slots; start < end; ++i, ++start) { |
| + PrintF(" %2d ", i); |
| + String::cast(scope_info->get(start))->ShortPrint(); |
| PrintF("\n"); |
| } |
| } |
| } |
| -template<class Allocator> |
| -void ScopeInfo<Allocator>::Print() { |
| +void ScopeInfo::Print() { |
| PrintF("ScopeInfo "); |
| - if (function_name_->length() > 0) |
| - function_name_->ShortPrint(); |
| - else |
| + if (HasFunctionName()) { |
| + function_name()->ShortPrint(); |
| + } else { |
| PrintF("/* no function name */"); |
| + } |
| PrintF("{"); |
| - PrintList<Allocator>("parameters", 0, parameters_); |
| - PrintList<Allocator>("stack slots", 0, stack_slots_); |
| - PrintList<Allocator>("context slots", Context::MIN_CONTEXT_SLOTS, |
| - context_slots_); |
| + PrintList("parameters", 0, |
| + ParameterEntriesIndex(), |
| + ParameterEntriesIndex() + num_parameters(), |
| + this); |
| + PrintList("stack slots", 0, |
| + StackLocalEntriesIndex(), |
| + StackLocalEntriesIndex() + num_stack_locals(), |
| + this); |
| + PrintList("context slots", |
| + Context::MIN_CONTEXT_SLOTS, |
| + ContextLocalNameEntriesIndex(), |
| + ContextLocalNameEntriesIndex() + num_context_locals(), |
| + this); |
| PrintF("}\n"); |
| } |
| #endif // DEBUG |
| - |
| -// Make sure the classes get instantiated by the template system. |
| -template class ScopeInfo<FreeStoreAllocationPolicy>; |
| -template class ScopeInfo<PreallocatedStorage>; |
| -template class ScopeInfo<ZoneListAllocationPolicy>; |
| - |
| } } // namespace v8::internal |