summaryrefslogtreecommitdiffstats
path: root/V8Binding/v8/src/scopeinfo.cc
diff options
context:
space:
mode:
Diffstat (limited to 'V8Binding/v8/src/scopeinfo.cc')
-rw-r--r--V8Binding/v8/src/scopeinfo.cc650
1 files changed, 0 insertions, 650 deletions
diff --git a/V8Binding/v8/src/scopeinfo.cc b/V8Binding/v8/src/scopeinfo.cc
deleted file mode 100644
index 8a237fd..0000000
--- a/V8Binding/v8/src/scopeinfo.cc
+++ /dev/null
@@ -1,650 +0,0 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include <stdlib.h>
-
-#include "v8.h"
-
-#include "scopeinfo.h"
-#include "scopes.h"
-
-namespace v8 {
-namespace internal {
-
-
-static int CompareLocal(Variable* const* v, Variable* const* w) {
- Slot* s = (*v)->slot();
- Slot* t = (*w)->slot();
- // We may have rewritten parameters (that are in the arguments object)
- // and which may have a NULL slot... - find a better solution...
- int x = (s != NULL ? s->index() : 0);
- int y = (t != NULL ? t->index() : 0);
- // Consider sorting them according to type as well?
- return x - y;
-}
-
-
-template<class Allocator>
-ScopeInfo<Allocator>::ScopeInfo(Scope* scope)
- : function_name_(Factory::empty_symbol()),
- calls_eval_(scope->calls_eval()),
- 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());
- }
-
- // 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);
-
- List<Variable*, Allocator> heap_locals(locals.length());
- for (int i = 0; i < locals.length(); i++) {
- Variable* var = locals[i];
- if (var->var_uses()->is_used()) {
- Slot* slot = var->slot();
- if (slot != NULL) {
- switch (slot->type()) {
- case Slot::PARAMETER:
- // explicitly added to parameters_ above - ignore
- break;
-
- case Slot::LOCAL:
- ASSERT(stack_slots_.length() == slot->index());
- stack_slots_.Add(var->name());
- break;
-
- case Slot::CONTEXT:
- heap_locals.Add(var);
- break;
-
- case Slot::LOOKUP:
- case Slot::GLOBAL:
- // these are currently not used
- 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]->slot()->index() - Context::MIN_CONTEXT_SLOTS ==
- context_slots_.length());
- ASSERT(heap_locals[i]->slot()->index() - Context::MIN_CONTEXT_SLOTS ==
- context_modes_.length());
- context_slots_.Add(heap_locals[i]->name());
- context_modes_.Add(heap_locals[i]->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()) {
- Variable* var = scope->function();
- if (var != NULL &&
- var->var_uses()->is_used() &&
- var->slot()->type() == Slot::CONTEXT) {
- function_name_ = var->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(var->slot()->index() - Context::MIN_CONTEXT_SLOTS ==
- context_slots_.length());
- ASSERT(var->slot()->index() - Context::MIN_CONTEXT_SLOTS ==
- context_modes_.length());
- context_slots_.Add(Factory::empty_symbol());
- context_modes_.Add(Variable::INTERNAL);
- }
- }
-}
-
-
-// Encoding format in the Code object:
-//
-// - function name
-//
-// - 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)
-// - NULL (sentinel)
-//
-// - number of parameters (smi)
-// - list of parameter names (starting with parameter 0 first)
-// - NULL (sentinel)
-//
-// - number of variables on the stack (smi)
-// - list of names of stack-allocated variables (starting with stack slot 0)
-// - NULL (sentinel)
-
-// 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)
-
-
-static inline Object** ReadInt(Object** p, int* x) {
- *x = (reinterpret_cast<Smi*>(*p++))->value();
- return p;
-}
-
-
-static inline Object** ReadBool(Object** p, bool* x) {
- *x = (reinterpret_cast<Smi*>(*p++))->value() != 0;
- return p;
-}
-
-
-static inline Object** ReadSymbol(Object** p, Handle<String>* s) {
- *s = Handle<String>(reinterpret_cast<String*>(*p++));
- return p;
-}
-
-
-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());
- int n;
- p = ReadInt(p, &n);
- while (n-- > 0) {
- Handle<String> s;
- p = ReadSymbol(p, &s);
- list->Add(s);
- }
- return ReadSentinel(p);
-}
-
-
-template <class Allocator>
-static Object** ReadList(Object** p,
- List<Handle<String>, Allocator>* list,
- List<Variable::Mode, Allocator>* modes) {
- ASSERT(list->is_empty());
- int n;
- p = ReadInt(p, &n);
- while (n-- > 0) {
- Handle<String> s;
- int m;
- p = ReadSymbol(p, &s);
- p = ReadInt(p, &m);
- list->Add(s);
- modes->Add(static_cast<Variable::Mode>(m));
- }
- return ReadSentinel(p);
-}
-
-
-template<class Allocator>
-ScopeInfo<Allocator>::ScopeInfo(Code* code)
- : function_name_(Factory::empty_symbol()),
- parameters_(4),
- stack_slots_(8),
- context_slots_(8),
- context_modes_(8) {
- if (code == NULL || code->sinfo_size() == 0) return;
-
- Object** p0 = &Memory::Object_at(code->sinfo_start());
- Object** p = p0;
- p = ReadSymbol(p, &function_name_);
- p = ReadBool(p, &calls_eval_);
- p = ReadList<Allocator>(p, &context_slots_, &context_modes_);
- p = ReadList<Allocator>(p, &parameters_);
- p = ReadList<Allocator>(p, &stack_slots_);
- ASSERT((p - p0) * kPointerSize == code->sinfo_size());
-}
-
-
-static inline Object** WriteInt(Object** p, int x) {
- *p++ = Smi::FromInt(x);
- return p;
-}
-
-
-static inline Object** WriteBool(Object** p, bool b) {
- *p++ = Smi::FromInt(b ? 1 : 0);
- return p;
-}
-
-
-static inline Object** WriteSymbol(Object** p, Handle<String> s) {
- *p++ = *s;
- return p;
-}
-
-
-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();
- p = WriteInt(p, n);
- for (int i = 0; i < n; i++) {
- p = WriteSymbol(p, list->at(i));
- }
- return WriteSentinel(p);
-}
-
-
-template <class Allocator>
-static Object** WriteList(Object** p,
- List<Handle<String>, Allocator>* list,
- List<Variable::Mode, Allocator>* modes) {
- const int n = list->length();
- p = WriteInt(p, n);
- for (int i = 0; i < n; i++) {
- p = WriteSymbol(p, list->at(i));
- p = WriteInt(p, modes->at(i));
- }
- return WriteSentinel(p);
-}
-
-
-template<class Allocator>
-int ScopeInfo<Allocator>::Serialize(Code* code) {
- // function name, calls eval, length & sentinel for 3 tables:
- const int extra_slots = 1 + 1 + 2 * 3;
- int size = (extra_slots +
- context_slots_.length() * 2 +
- parameters_.length() +
- stack_slots_.length()) * kPointerSize;
-
- if (code != NULL) {
- CHECK(code->sinfo_size() == size);
- Object** p0 = &Memory::Object_at(code->sinfo_start());
- Object** p = p0;
- p = WriteSymbol(p, function_name_);
- p = WriteBool(p, calls_eval_);
- p = WriteList(p, &context_slots_, &context_modes_);
- p = WriteList(p, &parameters_);
- p = WriteList(p, &stack_slots_);
- ASSERT((p - p0) * kPointerSize == size);
- }
-
- return size;
-}
-
-
-template<class Allocator>
-void ScopeInfo<Allocator>::IterateScopeInfo(Code* code, ObjectVisitor* v) {
- Object** start = &Memory::Object_at(code->sinfo_start());
- Object** end = &Memory::Object_at(code->sinfo_start() + code->sinfo_size());
- v->VisitPointers(start, end);
-}
-
-
-static Object** ContextEntriesAddr(Code* code) {
- ASSERT(code->sinfo_size() > 0);
- // +2 for function name and calls eval:
- return &Memory::Object_at(code->sinfo_start()) + 2;
-}
-
-
-static Object** ParameterEntriesAddr(Code* code) {
- ASSERT(code->sinfo_size() > 0);
- Object** p = ContextEntriesAddr(code);
- int n; // number of context slots;
- p = ReadInt(p, &n);
- return p + n*2 + 1; // *2 for pairs, +1 for sentinel
-}
-
-
-static Object** StackSlotEntriesAddr(Code* code) {
- ASSERT(code->sinfo_size() > 0);
- Object** p = ParameterEntriesAddr(code);
- int n; // number of parameter slots;
- p = ReadInt(p, &n);
- return p + n + 1; // +1 for sentinel
-}
-
-
-template<class Allocator>
-bool ScopeInfo<Allocator>::CallsEval(Code* code) {
- if (code->sinfo_size() > 0) {
- // +1 for function name:
- Object** p = &Memory::Object_at(code->sinfo_start()) + 1;
- bool calls_eval;
- p = ReadBool(p, &calls_eval);
- return calls_eval;
- }
- return true;
-}
-
-
-template<class Allocator>
-int ScopeInfo<Allocator>::NumberOfStackSlots(Code* code) {
- if (code->sinfo_size() > 0) {
- Object** p = StackSlotEntriesAddr(code);
- int n; // number of stack slots;
- ReadInt(p, &n);
- return n;
- }
- return 0;
-}
-
-
-template<class Allocator>
-int ScopeInfo<Allocator>::NumberOfContextSlots(Code* code) {
- if (code->sinfo_size() > 0) {
- Object** p = ContextEntriesAddr(code);
- int n; // number of context slots;
- ReadInt(p, &n);
- return n + Context::MIN_CONTEXT_SLOTS;
- }
- return 0;
-}
-
-
-template<class Allocator>
-int ScopeInfo<Allocator>::StackSlotIndex(Code* code, String* name) {
- ASSERT(name->IsSymbol());
- if (code->sinfo_size() > 0) {
- // Loop below depends on the NULL sentinel after the stack slot names.
- ASSERT(NumberOfStackSlots(code) > 0 ||
- *(StackSlotEntriesAddr(code) + 1) == NULL);
- // slots start after length entry
- Object** p0 = StackSlotEntriesAddr(code) + 1;
- Object** p = p0;
- while (*p != NULL) {
- if (*p == name) return p - p0;
- p++;
- }
- }
- return -1;
-}
-
-
-template<class Allocator>
-int ScopeInfo<Allocator>::ContextSlotIndex(Code* code,
- String* name,
- Variable::Mode* mode) {
- ASSERT(name->IsSymbol());
- int result = ContextSlotCache::Lookup(code, name, mode);
- if (result != ContextSlotCache::kNotFound) return result;
- if (code->sinfo_size() > 0) {
- // Loop below depends on the NULL sentinel after the context slot names.
- ASSERT(NumberOfContextSlots(code) >= Context::MIN_CONTEXT_SLOTS ||
- *(ContextEntriesAddr(code) + 1) == NULL);
-
- // slots start after length entry
- Object** p0 = ContextEntriesAddr(code) + 1;
- Object** p = p0;
- // contexts may have no variable slots (in the presence of eval()).
- while (*p != NULL) {
- if (*p == name) {
- ASSERT(((p - p0) & 1) == 0);
- int v;
- ReadInt(p + 1, &v);
- Variable::Mode mode_value = static_cast<Variable::Mode>(v);
- if (mode != NULL) *mode = mode_value;
- result = ((p - p0) >> 1) + Context::MIN_CONTEXT_SLOTS;
- ContextSlotCache::Update(code, name, mode_value, result);
- return result;
- }
- p += 2;
- }
- }
- ContextSlotCache::Update(code, name, Variable::INTERNAL, -1);
- return -1;
-}
-
-
-template<class Allocator>
-int ScopeInfo<Allocator>::ParameterIndex(Code* code, String* name) {
- ASSERT(name->IsSymbol());
- if (code->sinfo_size() > 0) {
- // We must read parameters from the end since for
- // multiply declared parameters the value of the
- // 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(code);
- int n; // number of parameters
- Object** p0 = ReadInt(p, &n);
- p = p0 + n;
- while (p > p0) {
- p--;
- if (*p == name) return p - p0;
- }
- }
- return -1;
-}
-
-
-template<class Allocator>
-int ScopeInfo<Allocator>::FunctionContextSlotIndex(Code* code, String* name) {
- ASSERT(name->IsSymbol());
- if (code->sinfo_size() > 0) {
- Object** p = &Memory::Object_at(code->sinfo_start());
- if (*p == name) {
- p = ContextEntriesAddr(code);
- int n; // number of context slots
- ReadInt(p, &n);
- ASSERT(n != 0);
- // The function context slot is the last entry.
- return n + 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(Code* code, String* name) {
- // Uses only lower 32 bits if pointers are larger.
- uintptr_t addr_hash =
- static_cast<uint32_t>(reinterpret_cast<uintptr_t>(code)) >> 2;
- return (addr_hash ^ name->Hash()) % kLength;
-}
-
-
-int ContextSlotCache::Lookup(Code* code,
- String* name,
- Variable::Mode* mode) {
- int index = Hash(code, name);
- Key& key = keys_[index];
- if ((key.code == code) && key.name->Equals(name)) {
- Value result(values_[index]);
- if (mode != NULL) *mode = result.mode();
- return result.index() + kNotFound;
- }
- return kNotFound;
-}
-
-
-void ContextSlotCache::Update(Code* code,
- String* name,
- Variable::Mode mode,
- int slot_index) {
- String* symbol;
- ASSERT(slot_index > kNotFound);
- if (Heap::LookupSymbolIfExists(name, &symbol)) {
- int index = Hash(code, symbol);
- Key& key = keys_[index];
- key.code = code;
- key.name = symbol;
- // Please note value only takes a uint as index.
- values_[index] = Value(mode, slot_index - kNotFound).raw();
-#ifdef DEBUG
- ValidateEntry(code, name, mode, slot_index);
-#endif
- }
-}
-
-
-void ContextSlotCache::Clear() {
- for (int index = 0; index < kLength; index++) keys_[index].code = NULL;
-}
-
-
-ContextSlotCache::Key ContextSlotCache::keys_[ContextSlotCache::kLength];
-
-
-uint32_t ContextSlotCache::values_[ContextSlotCache::kLength];
-
-
-#ifdef DEBUG
-
-void ContextSlotCache::ValidateEntry(Code* code,
- String* name,
- Variable::Mode mode,
- int slot_index) {
- String* symbol;
- if (Heap::LookupSymbolIfExists(name, &symbol)) {
- int index = Hash(code, name);
- Key& key = keys_[index];
- ASSERT(key.code == code);
- ASSERT(key.name->Equals(name));
- Value result(values_[index]);
- ASSERT(result.mode() == mode);
- ASSERT(result.index() + kNotFound == slot_index);
- }
-}
-
-
-template <class Allocator>
-static void PrintList(const char* list_name,
- int nof_internal_slots,
- List<Handle<String>, Allocator>& list) {
- if (list.length() > 0) {
- 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();
- PrintF("\n");
- }
- }
-}
-
-
-template<class Allocator>
-void ScopeInfo<Allocator>::Print() {
- PrintF("ScopeInfo ");
- if (function_name_->length() > 0)
- 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_);
-
- 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