| Index: src/scopeinfo.cc
|
| diff --git a/src/scopeinfo.cc b/src/scopeinfo.cc
|
| index 8ea5f1e734151684828637ea1138dbc8250bbe34..f7933a98946d98c7480f99fc935809ab6a6d95ad 100644
|
| --- a/src/scopeinfo.cc
|
| +++ b/src/scopeinfo.cc
|
| @@ -46,475 +46,304 @@ 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) {
|
| + ZoneList<Variable*> variables(32); // 32 is a wild guess
|
| + 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];
|
| + ASSERT(var->is_used());
|
| + 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);
|
| + function_name_info = NONE;
|
| + function_variable_mode = VAR;
|
| }
|
|
|
| - // 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());
|
| - }
|
| - }
|
| -}
|
| + 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 = kVariablePartIndex
|
| + + num_parameters + num_stack_locals + 2 * num_context_locals
|
| + + (has_function_name ? 2 : 0);
|
|
|
| + Handle<ScopeInfo> scope_info = FACTORY->NewScopeInfo(length);
|
|
|
| -// 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)
|
| -
|
| -
|
| -template <class T>
|
| -static inline Object** ReadInt(Object** p, T* x) {
|
| - *x = static_cast<T>((reinterpret_cast<Smi*>(*p++))->value());
|
| - return p;
|
| -}
|
| -
|
| -
|
| -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;
|
| -}
|
| + // 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->SetFlags(flags);
|
| + scope_info->SetNumParameters(num_parameters);
|
| + scope_info->SetNumStackLocals(num_stack_locals);
|
| + scope_info->SetNumContextLocals(num_context_locals);
|
|
|
| + int index = kVariablePartIndex;
|
| + // 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->NumStackLocals() &&
|
| + var_index == scope_info->NumberOfStackSlots() - 1));
|
| + ASSERT(function_name_info != CONTEXT ||
|
| + var_index == scope_info->ContextLength() - 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->NumParameters());
|
| + ASSERT(scope->num_stack_slots() == scope_info->NumberOfStackSlots());
|
| + ASSERT(scope->num_heap_slots() == scope_info->ContextLength());
|
| + 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));
|
| - }
|
| - return p;
|
| +bool ScopeInfo::CallsEval() {
|
| + return length() > 0 && CallsEvalField::decode(Flags());
|
| }
|
|
|
|
|
| -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));
|
| - }
|
| - return p;
|
| +bool ScopeInfo::IsStrictMode() {
|
| + return length() > 0 && StrictModeField::decode(Flags());
|
| }
|
|
|
|
|
| -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 NumStackLocals() + NumContextLocals();
|
| }
|
|
|
|
|
| -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 =
|
| + FunctionVariableField::decode(Flags()) == STACK;
|
| + return NumStackLocals() + (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::ContextLength() {
|
| + if (length() > 0) {
|
| + int context_locals = NumContextLocals();
|
| + bool function_name_context_slot =
|
| + FunctionVariableField::decode(Flags()) == CONTEXT;
|
| + 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 NumContextLocals() > 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 ContextLength() > 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;
|
| - }
|
| - return false;
|
| +String* ScopeInfo::FunctionName() {
|
| + ASSERT(HasFunctionName());
|
| + return String::cast(get(FunctionNameEntryIndex()));
|
| }
|
|
|
|
|
| -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;
|
| +String* ScopeInfo::ParameterName(int var) {
|
| + ASSERT(0 <= var && var < NumParameters());
|
| + int info_index = ParameterEntriesIndex() + var;
|
| + return 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;
|
| +String* ScopeInfo::LocalName(int var) {
|
| + ASSERT(0 <= var && var < NumberOfLocals());
|
| + ASSERT(StackLocalEntriesIndex() + NumStackLocals() ==
|
| + ContextLocalNameEntriesIndex());
|
| + int info_index = StackLocalEntriesIndex() + var;
|
| + return 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;
|
| +String* ScopeInfo::StackLocalName(int var) {
|
| + ASSERT(0 <= var && var < NumStackLocals());
|
| + int info_index = StackLocalEntriesIndex() + var;
|
| + return 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;
|
| +String* ScopeInfo::ContextLocalName(int var) {
|
| + ASSERT(0 <= var && var < NumContextLocals());
|
| + int info_index = ContextLocalNameEntriesIndex() + var;
|
| + return String::cast(get(info_index));
|
| }
|
|
|
|
|
| -bool SerializedScopeInfo::HasContext() {
|
| - return HasHeapAllocatedLocals() ||
|
| - Type() == WITH_SCOPE;
|
| +VariableMode ScopeInfo::ContextLocalMode(int var) {
|
| + ASSERT(0 <= var && var < NumContextLocals());
|
| + 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() + NumStackLocals();
|
| + 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;
|
| + ASSERT(mode != NULL);
|
| 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);
|
| - 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);
|
| + ContextSlotCache* context_slot_cache = GetIsolate()->context_slot_cache();
|
| + int result = context_slot_cache->Lookup(this, name, mode);
|
| + if (result != ContextSlotCache::kNotFound) {
|
| + ASSERT(result < ContextLength());
|
| + return result;
|
| + }
|
| +
|
| + int start = ContextLocalNameEntriesIndex();
|
| + int end = ContextLocalNameEntriesIndex() + NumContextLocals();
|
| + for (int i = start; i < end; ++i) {
|
| + if (name == get(i)) {
|
| + int var = i - start;
|
| + *mode = ContextLocalMode(var);
|
| + result = Context::MIN_CONTEXT_SLOTS + var;
|
| + context_slot_cache->Update(this, name, *mode, result);
|
| + ASSERT(result < ContextLength());
|
| 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 +351,58 @@ 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() + NumParameters();
|
| + 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());
|
| + ASSERT(mode != NULL);
|
| 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 &&
|
| + FunctionName() == name) {
|
| + *mode = FunctionVariableMode::decode(Flags());
|
| + return Smi::cast(get(FunctionNameEntryIndex() + 1))->value();
|
| }
|
| }
|
| return -1;
|
| }
|
|
|
|
|
| +int ScopeInfo::ParameterEntriesIndex() {
|
| + ASSERT(length() > 0);
|
| + return kVariablePartIndex;
|
| +}
|
| +
|
| +
|
| +int ScopeInfo::StackLocalEntriesIndex() {
|
| + return ParameterEntriesIndex() + NumParameters();
|
| +}
|
| +
|
| +
|
| +int ScopeInfo::ContextLocalNameEntriesIndex() {
|
| + return StackLocalEntriesIndex() + NumStackLocals();
|
| +}
|
| +
|
| +
|
| +int ScopeInfo::ContextLocalModeEntriesIndex() {
|
| + return ContextLocalNameEntriesIndex() + NumContextLocals();
|
| +}
|
| +
|
| +
|
| +int ScopeInfo::FunctionNameEntryIndex() {
|
| + return ContextLocalModeEntriesIndex() + NumContextLocals();
|
| +}
|
| +
|
| +
|
| int ContextSlotCache::Hash(Object* data, String* name) {
|
| // Uses only lower 32 bits if pointers are larger.
|
| uintptr_t addr_hash =
|
| @@ -631,46 +469,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()) {
|
| + FunctionName()->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() + NumParameters(),
|
| + this);
|
| + PrintList("stack slots", 0,
|
| + StackLocalEntriesIndex(),
|
| + StackLocalEntriesIndex() + NumStackLocals(),
|
| + this);
|
| + PrintList("context slots",
|
| + Context::MIN_CONTEXT_SLOTS,
|
| + ContextLocalNameEntriesIndex(),
|
| + ContextLocalNameEntriesIndex() + NumContextLocals(),
|
| + 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
|
|
|