}
-int FunctionLiteral::start_position() const {
- return scope()->start_position();
-}
-
-
-int FunctionLiteral::end_position() const {
- return scope()->end_position();
-}
-
-
bool FunctionLiteral::strict_mode() const {
return scope()->is_strict_mode();
}
bool has_only_simple_this_property_assignments,
Handle<FixedArray> this_property_assignments,
int num_parameters,
+ int start_position,
+ int end_position,
Type type,
bool has_duplicate_parameters)
: Expression(isolate),
has_only_simple_this_property_assignments),
this_property_assignments_(this_property_assignments),
num_parameters_(num_parameters),
+ start_position_(start_position),
+ end_position_(end_position),
function_token_position_(RelocInfo::kNoPosition),
inferred_name_(HEAP->empty_string()),
is_expression_(type != DECLARATION),
ZoneList<Statement*>* body() const { return body_; }
void set_function_token_position(int pos) { function_token_position_ = pos; }
int function_token_position() const { return function_token_position_; }
- int start_position() const;
- int end_position() const;
+ int start_position() const { return start_position_; }
+ int end_position() const { return end_position_; }
bool is_expression() const { return is_expression_; }
bool is_anonymous() const { return is_anonymous_; }
bool strict_mode() const;
PREVIOUS_INDEX,
// The extension slot is used for either the global object (in global
// contexts), eval extension object (function contexts), subject of with
- // (with contexts), or the variable name (catch contexts), the serialized
- // scope info (block contexts).
+ // (with contexts), or the variable name (catch contexts).
EXTENSION_INDEX,
GLOBAL_INDEX,
MIN_CONTEXT_SLOTS,
return reinterpret_cast<SerializedScopeInfo*>(object);
}
- // Return the type of this scope.
- ScopeType Type();
-
// Does this scope call eval?
bool CallsEval();
// Return if this has context slots besides MIN_CONTEXT_SLOTS;
bool HasHeapAllocatedLocals();
- // Return if contexts are allocated for this scope.
- bool HasContext();
-
// Lookup support for serialized scope info. Returns the
// the stack slot index for a given slot name if the slot is
// present; otherwise returns a value < 0. The name must be a symbol
}
-Scope* Parser::NewScope(Scope* parent, ScopeType type) {
+Scope* Parser::NewScope(Scope* parent, Scope::Type type) {
Scope* result = new(zone()) Scope(parent, type);
result->Initialize();
return result;
mode_ = FLAG_lazy ? PARSE_LAZILY : PARSE_EAGERLY;
if (allow_natives_syntax_ || extension_ != NULL) mode_ = PARSE_EAGERLY;
- ScopeType type = in_global_context ? GLOBAL_SCOPE : EVAL_SCOPE;
+ Scope::Type type =
+ in_global_context
+ ? Scope::GLOBAL_SCOPE
+ : Scope::EVAL_SCOPE;
Handle<String> no_name = isolate()->factory()->empty_symbol();
FunctionLiteral* result = NULL;
{ Scope* scope = NewScope(top_scope_, type);
- scope->set_start_position(0);
- scope->set_end_position(source->length());
LexicalScope lexical_scope(this, scope, isolate());
if (strict_mode == kStrictMode) {
top_scope_->EnableStrictMode();
lexical_scope.only_simple_this_property_assignments(),
lexical_scope.this_property_assignments(),
0,
+ 0,
+ source->length(),
FunctionLiteral::ANONYMOUS_EXPRESSION,
false); // Does not have duplicate parameters.
} else if (stack_overflow_) {
{
// Parse the function literal.
- Scope* scope = NewScope(top_scope_, GLOBAL_SCOPE);
+ Scope* scope = NewScope(top_scope_, Scope::GLOBAL_SCOPE);
if (!info->closure().is_null()) {
scope = Scope::DeserializeScopeChain(info, scope);
}
// Construct block expecting 16 statements.
Block* body = new(zone()) Block(isolate(), labels, 16, false);
- Scope* block_scope = NewScope(top_scope_, BLOCK_SCOPE);
+ Scope* block_scope = NewScope(top_scope_, Scope::BLOCK_SCOPE);
if (top_scope_->is_strict_mode()) {
block_scope->EnableStrictMode();
}
// Parse the statements and collect escaping labels.
Expect(Token::LBRACE, CHECK_OK);
- block_scope->set_start_position(scanner().location().beg_pos);
{ SaveScope save_scope(this, block_scope);
TargetCollector collector;
Target target(&this->target_stack_, &collector);
}
}
Expect(Token::RBRACE, CHECK_OK);
- block_scope->set_end_position(scanner().location().end_pos);
+
block_scope = block_scope->FinalizeBlockScope();
body->set_block_scope(block_scope);
return body;
Expect(Token::RPAREN, CHECK_OK);
top_scope_->DeclarationScope()->RecordWithStatement();
- Scope* with_scope = NewScope(top_scope_, WITH_SCOPE);
+ Scope* with_scope = NewScope(top_scope_, Scope::WITH_SCOPE);
Statement* stmt;
{ SaveScope save_scope(this, with_scope);
- with_scope->set_start_position(scanner().peek_location().beg_pos);
stmt = ParseStatement(labels, CHECK_OK);
- with_scope->set_end_position(scanner().location().end_pos);
}
return new(zone()) WithStatement(expr, stmt);
}
Consume(Token::CATCH);
Expect(Token::LPAREN, CHECK_OK);
- catch_scope = NewScope(top_scope_, CATCH_SCOPE);
- if (top_scope_->is_strict_mode()) {
- catch_scope->EnableStrictMode();
- }
- catch_scope->set_start_position(scanner().location().beg_pos);
name = ParseIdentifier(CHECK_OK);
if (top_scope_->is_strict_mode() && IsEvalOrArguments(name)) {
if (peek() == Token::LBRACE) {
Target target(&this->target_stack_, &catch_collector);
+ catch_scope = NewScope(top_scope_, Scope::CATCH_SCOPE);
+ if (top_scope_->is_strict_mode()) {
+ catch_scope->EnableStrictMode();
+ }
VariableMode mode = harmony_scoping_ ? LET : VAR;
catch_variable = catch_scope->DeclareLocal(name, mode);
} else {
Expect(Token::LBRACE, CHECK_OK);
}
- catch_scope->set_end_position(scanner().location().end_pos);
+
tok = peek();
}
// Create an in-between scope for let-bound iteration variables.
Scope* saved_scope = top_scope_;
- Scope* for_scope = NewScope(top_scope_, BLOCK_SCOPE);
+ Scope* for_scope = NewScope(top_scope_, Scope::BLOCK_SCOPE);
if (top_scope_->is_strict_mode()) {
for_scope->EnableStrictMode();
}
Expect(Token::FOR, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
- for_scope->set_start_position(scanner().location().beg_pos);
if (peek() != Token::SEMICOLON) {
if (peek() == Token::VAR || peek() == Token::CONST) {
Handle<String> name;
result->AddStatement(variable_statement);
result->AddStatement(loop);
top_scope_ = saved_scope;
- for_scope->set_end_position(scanner().location().end_pos);
for_scope = for_scope->FinalizeBlockScope();
ASSERT(for_scope == NULL);
// Parsed for-in loop w/ variable/const declaration.
body_block->AddStatement(body);
loop->Initialize(temp_proxy, enumerable, body_block);
top_scope_ = saved_scope;
- for_scope->set_end_position(scanner().location().end_pos);
for_scope = for_scope->FinalizeBlockScope();
body_block->set_block_scope(for_scope);
// Parsed for-in loop w/ let declaration.
Statement* body = ParseStatement(NULL, CHECK_OK);
if (loop) loop->Initialize(expression, enumerable, body);
top_scope_ = saved_scope;
- for_scope->set_end_position(scanner().location().end_pos);
for_scope = for_scope->FinalizeBlockScope();
ASSERT(for_scope == NULL);
// Parsed for-in loop.
Statement* body = ParseStatement(NULL, CHECK_OK);
top_scope_ = saved_scope;
- for_scope->set_end_position(scanner().location().end_pos);
for_scope = for_scope->FinalizeBlockScope();
if (for_scope != NULL) {
// Rewrite a for statement of the form
// Function declarations are function scoped in normal mode, so they are
// hoisted. In harmony block scoping mode they are block scoped, so they
// are not hoisted.
- Scope* scope = (type == FunctionLiteral::DECLARATION && !harmony_scoping_)
- ? NewScope(top_scope_->DeclarationScope(), FUNCTION_SCOPE)
- : NewScope(top_scope_, FUNCTION_SCOPE);
+ Scope* scope = (type == FunctionLiteral::DECLARATION &&
+ !harmony_scoping_)
+ ? NewScope(top_scope_->DeclarationScope(), Scope::FUNCTION_SCOPE)
+ : NewScope(top_scope_, Scope::FUNCTION_SCOPE);
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(8);
int materialized_literal_count;
int expected_property_count;
+ int start_pos;
+ int end_pos;
bool only_simple_this_property_assignments;
Handle<FixedArray> this_property_assignments;
bool has_duplicate_parameters = false;
// FormalParameterList ::
// '(' (Identifier)*[','] ')'
Expect(Token::LPAREN, CHECK_OK);
- scope->set_start_position(scanner().location().beg_pos);
+ start_pos = scanner().location().beg_pos;
Scanner::Location name_loc = Scanner::Location::invalid();
Scanner::Location dupe_loc = Scanner::Location::invalid();
Scanner::Location reserved_loc = Scanner::Location::invalid();
// compile after all.
is_lazily_compiled = false;
} else {
- scope->set_end_position(entry.end_pos());
- if (scope->end_position() <= function_block_pos) {
+ end_pos = entry.end_pos();
+ if (end_pos <= function_block_pos) {
// End position greater than end of stream is safe, and hard to check.
ReportInvalidPreparseData(function_name, CHECK_OK);
}
isolate()->counters()->total_preparse_skipped()->Increment(
- scope->end_position() - function_block_pos);
+ end_pos - function_block_pos);
// Seek to position just before terminal '}'.
- scanner().SeekForward(scope->end_position() - 1);
+ scanner().SeekForward(end_pos - 1);
materialized_literal_count = entry.literal_count();
expected_property_count = entry.property_count();
if (entry.strict_mode()) top_scope_->EnableStrictMode();
this_property_assignments = lexical_scope.this_property_assignments();
Expect(Token::RBRACE, CHECK_OK);
- scope->set_end_position(scanner().location().end_pos);
+ end_pos = scanner().location().end_pos;
}
// Validate strict mode.
if (top_scope_->is_strict_mode()) {
if (IsEvalOrArguments(function_name)) {
- int start_pos = scope->start_position();
int position = function_token_position != RelocInfo::kNoPosition
? function_token_position
: (start_pos > 0 ? start_pos - 1 : start_pos);
return NULL;
}
if (name_is_strict_reserved) {
- int start_pos = scope->start_position();
int position = function_token_position != RelocInfo::kNoPosition
? function_token_position
: (start_pos > 0 ? start_pos - 1 : start_pos);
*ok = false;
return NULL;
}
- CheckOctalLiteral(scope->start_position(),
- scope->end_position(),
- CHECK_OK);
+ CheckOctalLiteral(start_pos, end_pos, CHECK_OK);
}
}
only_simple_this_property_assignments,
this_property_assignments,
num_parameters,
+ start_pos,
+ end_pos,
type,
has_duplicate_parameters);
function_literal->set_function_token_position(function_token_position);
return ∅
}
- Scope* NewScope(Scope* parent, ScopeType type);
+ Scope* NewScope(Scope* parent, Scope::Type type);
Handle<String> LookupSymbol(int symbol_id);
}
-// Iterate over the actual scopes visible from a stack frame. The iteration
-// proceeds from the innermost visible nested scope outwards. All scopes are
+// Iterate over the actual scopes visible from a stack frame. All scopes are
// backed by an actual context except the local scope, which is inserted
-// "artificially" in the context chain.
+// "artifically" in the context chain.
class ScopeIterator {
public:
enum ScopeType {
inlined_frame_index_(inlined_frame_index),
function_(JSFunction::cast(frame->function())),
context_(Context::cast(frame->context())),
- nested_scope_chain_(4) {
+ local_done_(false),
+ at_local_(false) {
- // Check whether we are in global code or function code. If there is a stack
- // slot for .result then this function has been created for evaluating
- // global code and it is not a real function.
+ // Check whether the first scope is actually a local scope.
+ // If there is a stack slot for .result then this local scope has been
+ // created for evaluating top level code and it is not a real local scope.
// Checking for the existence of .result seems fragile, but the scope info
// saved with the code object does not otherwise have that information.
int index = function_->shared()->scope_info()->
StackSlotIndex(isolate_->heap()->result_symbol());
-
- // Reparse the code and analyze the scopes.
- ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
- Handle<SharedFunctionInfo> shared_info(function_->shared());
- Handle<Script> script(Script::cast(shared_info->script()));
- Scope* scope;
if (index >= 0) {
- // Global code
- CompilationInfo info(script);
- info.MarkAsGlobal();
- bool result = ParserApi::Parse(&info);
- ASSERT(result);
- result = Scope::Analyze(&info);
- ASSERT(result);
- scope = info.function()->scope();
- } else {
- // Function code
- CompilationInfo info(shared_info);
- bool result = ParserApi::Parse(&info);
- ASSERT(result);
- result = Scope::Analyze(&info);
- ASSERT(result);
- scope = info.function()->scope();
+ local_done_ = true;
+ } else if (context_->IsGlobalContext() ||
+ context_->IsFunctionContext()) {
+ at_local_ = true;
+ } else if (context_->closure() != *function_) {
+ // The context_ is a block or with or catch block from the outer function.
+ ASSERT(context_->IsWithContext() ||
+ context_->IsCatchContext() ||
+ context_->IsBlockContext());
+ at_local_ = true;
}
-
- // Retrieve the scope chain for the current position.
- int statement_position =
- shared_info->code()->SourceStatementPosition(frame_->pc());
- scope->GetNestedScopeChain(&nested_scope_chain_, statement_position);
}
// More scopes?
// Move to the next scope.
void Next() {
- ScopeType scope_type = Type();
- if (scope_type == ScopeTypeGlobal) {
- // The global scope is always the last in the chain.
- ASSERT(context_->IsGlobalContext());
+ // If at a local scope mark the local scope as passed.
+ if (at_local_) {
+ at_local_ = false;
+ local_done_ = true;
+
+ // If the current context is not associated with the local scope the
+ // current context is the next real scope, so don't move to the next
+ // context in this case.
+ if (context_->closure() != *function_) {
+ return;
+ }
+ }
+
+ // The global scope is always the last in the chain.
+ if (context_->IsGlobalContext()) {
context_ = Handle<Context>();
return;
}
- if (nested_scope_chain_.is_empty()) {
- context_ = Handle<Context>(context_->previous(), isolate_);
- } else {
- if (nested_scope_chain_.last()->HasContext()) {
- context_ = Handle<Context>(context_->previous(), isolate_);
- }
- nested_scope_chain_.RemoveLast();
+
+ // Move to the next context.
+ context_ = Handle<Context>(context_->previous(), isolate_);
+
+ // If passing the local scope indicate that the current scope is now the
+ // local scope.
+ if (!local_done_ &&
+ (context_->IsGlobalContext() || context_->IsFunctionContext())) {
+ at_local_ = true;
}
}
// Return the type of the current scope.
ScopeType Type() {
- if (!nested_scope_chain_.is_empty()) {
- Handle<SerializedScopeInfo> scope_info = nested_scope_chain_.last();
- switch (scope_info->Type()) {
- case FUNCTION_SCOPE:
- ASSERT(context_->IsFunctionContext() ||
- !scope_info->HasContext());
- return ScopeTypeLocal;
- case GLOBAL_SCOPE:
- ASSERT(context_->IsGlobalContext());
- return ScopeTypeGlobal;
- case WITH_SCOPE:
- ASSERT(context_->IsWithContext());
- return ScopeTypeWith;
- case CATCH_SCOPE:
- ASSERT(context_->IsCatchContext());
- return ScopeTypeCatch;
- case BLOCK_SCOPE:
- ASSERT(!scope_info->HasContext() ||
- context_->IsBlockContext());
- return ScopeTypeBlock;
- case EVAL_SCOPE:
- UNREACHABLE();
- }
+ if (at_local_) {
+ return ScopeTypeLocal;
}
if (context_->IsGlobalContext()) {
ASSERT(context_->global()->IsGlobalObject());
return Handle<JSObject>(CurrentContext()->global());
case ScopeIterator::ScopeTypeLocal:
// Materialize the content of the local scope into a JSObject.
- ASSERT(nested_scope_chain_.length() == 1);
return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
case ScopeIterator::ScopeTypeWith:
// Return the with object.
return Handle<JSObject>();
}
- Handle<SerializedScopeInfo> CurrentScopeInfo() {
- if (!nested_scope_chain_.is_empty()) {
- return nested_scope_chain_.last();
- } else if (context_->IsBlockContext()) {
- return Handle<SerializedScopeInfo>(
- SerializedScopeInfo::cast(context_->extension()));
- } else if (context_->IsFunctionContext()) {
- return Handle<SerializedScopeInfo>(
- context_->closure()->shared()->scope_info());
- }
- return Handle<SerializedScopeInfo>::null();
- }
-
// Return the context for this scope. For the local context there might not
// be an actual context.
Handle<Context> CurrentContext() {
- if (Type() == ScopeTypeGlobal ||
- nested_scope_chain_.is_empty()) {
- return context_;
- } else if (nested_scope_chain_.last()->HasContext()) {
- return context_;
- } else {
+ if (at_local_ && context_->closure() != *function_) {
return Handle<Context>();
}
+ return context_;
}
#ifdef DEBUG
int inlined_frame_index_;
Handle<JSFunction> function_;
Handle<Context> context_;
- List<Handle<SerializedScopeInfo> > nested_scope_chain_;
+ bool local_done_;
+ bool at_local_;
DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
};
// Creates a copy of the with context chain. The copy of the context chain is
// is linked to the function context supplied.
-static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
- Handle<JSFunction> function,
- Handle<Context> base,
- JavaScriptFrame* frame,
- int inlined_frame_index) {
- HandleScope scope(isolate);
- List<Handle<SerializedScopeInfo> > scope_chain;
- List<Handle<Context> > context_chain;
-
- ScopeIterator it(isolate, frame, inlined_frame_index);
- for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
- it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
- ASSERT(!it.Done());
- scope_chain.Add(it.CurrentScopeInfo());
- context_chain.Add(it.CurrentContext());
+static Handle<Context> CopyWithContextChain(Isolate* isolate,
+ Handle<JSFunction> function,
+ Handle<Context> current,
+ Handle<Context> base) {
+ // At the end of the chain. Return the base context to link to.
+ if (current->IsFunctionContext() || current->IsGlobalContext()) {
+ return base;
}
- // At the end of the chain. Return the base context to link to.
- Handle<Context> context = base;
-
- // Iteratively copy and or materialize the nested contexts.
- while (!scope_chain.is_empty()) {
- Handle<SerializedScopeInfo> scope_info = scope_chain.RemoveLast();
- Handle<Context> current = context_chain.RemoveLast();
- ASSERT(!(scope_info->HasContext() & current.is_null()));
-
- if (scope_info->Type() == CATCH_SCOPE) {
- Handle<String> name(String::cast(current->extension()));
- Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
- context =
- isolate->factory()->NewCatchContext(function,
- context,
- name,
- thrown_object);
- } else if (scope_info->Type() == BLOCK_SCOPE) {
- // Materialize the contents of the block scope into a JSObject.
- Handle<JSObject> block_scope_object =
- MaterializeBlockScope(isolate, current);
- if (block_scope_object.is_null()) {
- return Handle<Context>::null();
- }
- // Allocate a new function context for the debug evaluation and set the
- // extension object.
- Handle<Context> new_context =
- isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
- function);
- new_context->set_extension(*block_scope_object);
- new_context->set_previous(*context);
- context = new_context;
- } else {
- ASSERT(scope_info->Type() == WITH_SCOPE);
- ASSERT(current->IsWithContext());
- Handle<JSObject> extension(JSObject::cast(current->extension()));
- context =
- isolate->factory()->NewWithContext(function, context, extension);
+ // Recursively copy the with and catch contexts.
+ HandleScope scope(isolate);
+ Handle<Context> previous(current->previous());
+ Handle<Context> new_previous =
+ CopyWithContextChain(isolate, function, previous, base);
+ Handle<Context> new_current;
+ if (current->IsCatchContext()) {
+ Handle<String> name(String::cast(current->extension()));
+ Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
+ new_current =
+ isolate->factory()->NewCatchContext(function,
+ new_previous,
+ name,
+ thrown_object);
+ } else if (current->IsBlockContext()) {
+ Handle<SerializedScopeInfo> scope_info(
+ SerializedScopeInfo::cast(current->extension()));
+ new_current =
+ isolate->factory()->NewBlockContext(function, new_previous, scope_info);
+ // Copy context slots.
+ int num_context_slots = scope_info->NumberOfContextSlots();
+ for (int i = Context::MIN_CONTEXT_SLOTS; i < num_context_slots; ++i) {
+ new_current->set(i, current->get(i));
}
+ } else {
+ ASSERT(current->IsWithContext());
+ Handle<JSObject> extension(JSObject::cast(current->extension()));
+ new_current =
+ isolate->factory()->NewWithContext(function, new_previous, extension);
}
-
- return scope.CloseAndEscape(context);
+ return scope.CloseAndEscape(new_current);
}
if (scope_info->HasHeapAllocatedLocals()) {
function_context = Handle<Context>(frame_context->declaration_context());
}
- context = CopyNestedScopeContextChain(isolate,
- go_between,
- context,
- frame,
- inlined_frame_index);
+ context = CopyWithContextChain(isolate, go_between, frame_context, context);
if (additional_context->IsJSObject()) {
Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
: 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()),
//
// - 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
// present)
-template <class T>
-static inline Object** ReadInt(Object** p, T* x) {
- *x = static_cast<T>((reinterpret_cast<Smi*>(*p++))->value());
+static inline Object** ReadInt(Object** p, int* x) {
+ *x = (reinterpret_cast<Smi*>(*p++))->value();
return p;
}
}
-template <class T>
-static inline Object** ReadObject(Object** p, Handle<T>* s) {
- *s = Handle<T>::cast(Handle<Object>(*p++));
+static inline Object** ReadSymbol(Object** p, Handle<String>* s) {
+ *s = Handle<String>(reinterpret_cast<String*>(*p++));
return p;
}
-template <class Allocator, class T>
-static Object** ReadList(Object** p, List<Handle<T>, Allocator >* list) {
+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<T> s;
- p = ReadObject(p, &s);
+ Handle<String> s;
+ p = ReadSymbol(p, &s);
list->Add(s);
}
return p;
while (n-- > 0) {
Handle<String> s;
int m;
- p = ReadObject(p, &s);
+ p = ReadSymbol(p, &s);
p = ReadInt(p, &m);
list->Add(s);
modes->Add(static_cast<VariableMode>(m));
if (data->length() > 0) {
Object** p0 = data->data_start();
Object** p = p0;
- p = ReadObject(p, &function_name_);
+ p = ReadSymbol(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_);
}
-template <class T>
-static inline Object** WriteObject(Object** p, Handle<T> s) {
+static inline Object** WriteSymbol(Object** p, Handle<String> s) {
*p++ = *s;
return p;
}
-template <class Allocator, class T>
-static Object** WriteList(Object** p, List<Handle<T>, Allocator >* list) {
+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 = WriteObject(p, list->at(i));
+ p = WriteSymbol(p, list->at(i));
}
return p;
}
const int n = list->length();
p = WriteInt(p, n);
for (int i = 0; i < n; i++) {
- p = WriteObject(p, list->at(i));
+ p = WriteSymbol(p, list->at(i));
p = WriteInt(p, modes->at(i));
}
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;
+ // function name, calls eval, is_strict_mode, length for 3 tables:
+ const int extra_slots = 1 + 1 + 1 + 3;
int length = extra_slots +
context_slots_.length() * 2 +
parameters_.length() +
Object** p0 = data->data_start();
Object** p = p0;
- p = WriteObject(p, function_name_);
+ p = WriteSymbol(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_);
Object** SerializedScopeInfo::ContextEntriesAddr() {
ASSERT(length() > 0);
- // +4 for function name, calls eval, strict mode, scope type.
- return data_start() + 4;
+ // +3 for function name, calls eval, strict mode.
+ return data_start() + 3;
}
}
-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;
-}
-
-
int SerializedScopeInfo::NumberOfStackSlots() {
if (length() > 0) {
Object** p = StackSlotEntriesAddr();
}
-bool SerializedScopeInfo::HasContext() {
- return HasHeapAllocatedLocals() ||
- Type() == WITH_SCOPE;
-}
-
-
int SerializedScopeInfo::StackSlotIndex(String* name) {
ASSERT(name->IsSymbol());
if (length() > 0) {
namespace v8 {
namespace internal {
-// ScopeInfo represents information about different scopes of a source
-// program and the allocation of the scope's variables. Scope information
-// is stored in a compressed form in SerializedScopeInfo objects and is used
+// Scope information represents information about a functions's
+// scopes (currently only one, because we don't do any inlining)
+// and the allocation of the scope's variables. Scope information
+// is stored in a compressed form in FixedArray objects and is used
// at runtime (stack dumps, deoptimization, etc.).
+//
+// Historical note: In other VMs built by this team, ScopeInfo was
+// usually called DebugInfo since the information was used (among
+// other things) for on-demand debugging (Self, Smalltalk). However,
+// DebugInfo seems misleading, since this information is primarily used
+// in debugging-unrelated contexts.
// Forward defined as
// template <class Allocator = FreeStoreAllocationPolicy> class ScopeInfo;
Handle<String> LocalName(int i) const;
int NumberOfLocals() const;
- ScopeType type() const { return type_; }
// --------------------------------------------------------------------------
// Debugging support
Handle<String> function_name_;
bool calls_eval_;
bool is_strict_mode_;
- ScopeType type_;
List<Handle<String>, Allocator > parameters_;
List<Handle<String>, Allocator > stack_slots_;
List<Handle<String>, Allocator > context_slots_;
// Dummy constructor
-Scope::Scope(ScopeType type)
+Scope::Scope(Type type)
: isolate_(Isolate::Current()),
inner_scopes_(0),
variables_(false),
}
-Scope::Scope(Scope* outer_scope, ScopeType type)
+Scope::Scope(Scope* outer_scope, Type type)
: isolate_(Isolate::Current()),
inner_scopes_(4),
variables_(),
Scope::Scope(Scope* inner_scope,
- ScopeType type,
+ Type type,
Handle<SerializedScopeInfo> scope_info)
: isolate_(Isolate::Current()),
inner_scopes_(4),
}
-void Scope::SetDefaults(ScopeType type,
+void Scope::SetDefaults(Type type,
Scope* outer_scope,
Handle<SerializedScopeInfo> scope_info) {
outer_scope_ = outer_scope;
num_stack_slots_ = 0;
num_heap_slots_ = 0;
scope_info_ = scope_info;
- start_position_ = RelocInfo::kNoPosition;
- end_position_ = RelocInfo::kNoPosition;
}
}
-void Scope::GetNestedScopeChain(
- List<Handle<SerializedScopeInfo> >* chain,
- int position) {
- chain->Add(Handle<SerializedScopeInfo>(GetSerializedScopeInfo()));
-
- for (int i = 0; i < inner_scopes_.length(); i++) {
- Scope* scope = inner_scopes_[i];
- int beg_pos = scope->start_position();
- int end_pos = scope->end_position();
- ASSERT(beg_pos >= 0 && end_pos >= 0);
- if (beg_pos <= position && position <= end_pos) {
- scope->GetNestedScopeChain(chain, position);
- return;
- }
- }
-}
-
-
#ifdef DEBUG
-static const char* Header(ScopeType type) {
+static const char* Header(Scope::Type type) {
switch (type) {
- case EVAL_SCOPE: return "eval";
- case FUNCTION_SCOPE: return "function";
- case GLOBAL_SCOPE: return "global";
- case CATCH_SCOPE: return "catch";
- case BLOCK_SCOPE: return "block";
- case WITH_SCOPE: return "with";
+ case Scope::EVAL_SCOPE: return "eval";
+ case Scope::FUNCTION_SCOPE: return "function";
+ case Scope::GLOBAL_SCOPE: return "global";
+ case Scope::CATCH_SCOPE: return "catch";
+ case Scope::BLOCK_SCOPE: return "block";
+ case Scope::WITH_SCOPE: return "with";
}
UNREACHABLE();
return NULL;
// ---------------------------------------------------------------------------
// Construction
- Scope(Scope* outer_scope, ScopeType type);
+ enum Type {
+ EVAL_SCOPE, // The top-level scope for an eval source.
+ FUNCTION_SCOPE, // The top-level scope for a function.
+ GLOBAL_SCOPE, // The top-level scope for a program or a top-level eval.
+ CATCH_SCOPE, // The scope introduced by catch.
+ BLOCK_SCOPE, // The scope introduced by a new block.
+ WITH_SCOPE // The scope introduced by with.
+ };
+
+ Scope(Scope* outer_scope, Type type);
// Compute top scope and allocate variables. For lazy compilation the top
// scope only contains the single lazily compiled function, so this
strict_mode_ = FLAG_strict_mode;
}
- // Position in the source where this scope begins and ends.
- //
- // * For the scope of a with statement
- // with (obj) stmt
- // start position: start position of first token of 'stmt'
- // end position: end position of last token of 'stmt'
- // * For the scope of a block
- // { stmts }
- // start position: start position of '{'
- // end position: end position of '}'
- // * For the scope of a function literal or decalaration
- // function fun(a,b) { stmts }
- // start position: start position of '('
- // end position: end position of '}'
- // * For the scope of a catch block
- // try { stms } catch(e) { stmts }
- // start position: start position of '('
- // end position: end position of ')'
- // * For the scope of a for-statement
- // for (let x ...) stmt
- // start position: start position of '('
- // end position: end position of last token of 'stmt'
- int start_position() const { return start_position_; }
- void set_start_position(int statement_pos) {
- start_position_ = statement_pos;
- }
- int end_position() const { return end_position_; }
- void set_end_position(int statement_pos) {
- end_position_ = statement_pos;
- }
-
// ---------------------------------------------------------------------------
// Predicates.
// ---------------------------------------------------------------------------
// Accessors.
- // The type of this scope.
- ScopeType type() const { return type_; }
-
// The variable corresponding the 'this' value.
Variable* receiver() { return receiver_; }
// Declarations list.
ZoneList<Declaration*>* declarations() { return &decls_; }
- // Inner scope list.
- ZoneList<Scope*>* inner_scopes() { return &inner_scopes_; }
// ---------------------------------------------------------------------------
// Variable allocation.
Handle<SerializedScopeInfo> GetSerializedScopeInfo();
- // Get the chain of nested scopes within this scope for the source statement
- // position. The scopes will be added to the list from the outermost scope to
- // the innermost scope. Only nested block, catch or with scopes are tracked
- // and will be returned, but no inner function scopes.
- void GetNestedScopeChain(List<Handle<SerializedScopeInfo> >* chain,
- int statement_position);
-
// ---------------------------------------------------------------------------
// Strict mode support.
bool IsDeclared(Handle<String> name) {
protected:
friend class ParserFactory;
- explicit Scope(ScopeType type);
+ explicit Scope(Type type);
Isolate* const isolate_;
ZoneList<Scope*> inner_scopes_; // the immediately enclosed inner scopes
// The scope type.
- ScopeType type_;
+ Type type_;
// Debugging support.
Handle<String> scope_name_;
bool scope_calls_eval_;
// This scope is a strict mode scope.
bool strict_mode_;
- // Source positions.
- int start_position_;
- int end_position_;
// Computed via PropagateScopeInfo.
bool outer_scope_calls_non_strict_eval_;
private:
// Construct a scope based on the scope info.
- Scope(Scope* inner_scope,
- ScopeType type,
- Handle<SerializedScopeInfo> scope_info);
+ Scope(Scope* inner_scope, Type type, Handle<SerializedScopeInfo> scope_info);
// Construct a catch scope with a binding for the name.
Scope(Scope* inner_scope, Handle<String> catch_variable_name);
}
}
- void SetDefaults(ScopeType type,
+ void SetDefaults(Type type,
Scope* outer_scope,
Handle<SerializedScopeInfo> scope_info);
};
};
-enum ScopeType {
- EVAL_SCOPE, // The top-level scope for an eval source.
- FUNCTION_SCOPE, // The top-level scope for a function.
- GLOBAL_SCOPE, // The top-level scope for a program or a top-level eval.
- CATCH_SCOPE, // The scope introduced by catch.
- BLOCK_SCOPE, // The scope introduced by a new block.
- WITH_SCOPE // The scope introduced by with.
-};
-
-
static const uint32_t kHoleNanUpper32 = 0x7FFFFFFF;
static const uint32_t kHoleNanLower32 = 0xFFFFFFFF;
static const uint32_t kNaNOrInfinityLowerBoundUpper32 = 0x7FF00000;
TestScanRegExp("/=/", "=");
TestScanRegExp("/=?/", "=?");
}
-
-
-TEST(ScopePositions) {
- // Test the parser for correctly setting the start and end positions
- // of a scope. We check the scope positions of exactly one scope
- // nested in the global scope of a program. 'inner source' is the
- // source code that determines the part of the source belonging
- // to the nested scope. 'outer_prefix' and 'outer_suffix' are
- // parts of the source that belong to the global scope.
- struct SourceData {
- const char* outer_prefix;
- const char* inner_source;
- const char* outer_suffix;
- i::ScopeType scope_type;
- };
-
- const SourceData source_data[] = {
- { " with ({}) ", "{ block; }", " more;", i::WITH_SCOPE },
- { " with ({}) ", "{ block; }", "; more;", i::WITH_SCOPE },
- { " with ({}) ", "{\n"
- " block;\n"
- " }", "\n"
- " more;", i::WITH_SCOPE },
- { " with ({}) ", "statement;", " more;", i::WITH_SCOPE },
- { " with ({}) ", "statement", "\n"
- " more;", i::WITH_SCOPE },
- { " with ({})\n"
- " ", "statement;", "\n"
- " more;", i::WITH_SCOPE },
- { " try {} catch ", "(e) { block; }", " more;", i::CATCH_SCOPE },
- { " try {} catch ", "(e) { block; }", "; more;", i::CATCH_SCOPE },
- { " try {} catch ", "(e) {\n"
- " block;\n"
- " }", "\n"
- " more;", i::CATCH_SCOPE },
- { " try {} catch ", "(e) { block; }", " finally { block; } more;",
- i::CATCH_SCOPE },
- { " start;\n"
- " ", "{ let block; }", " more;", i::BLOCK_SCOPE },
- { " start;\n"
- " ", "{ let block; }", "; more;", i::BLOCK_SCOPE },
- { " start;\n"
- " ", "{\n"
- " let block;\n"
- " }", "\n"
- " more;", i::BLOCK_SCOPE },
- { " start;\n"
- " function fun", "(a,b) { infunction; }", " more;",
- i::FUNCTION_SCOPE },
- { " start;\n"
- " function fun", "(a,b) {\n"
- " infunction;\n"
- " }", "\n"
- " more;", i::FUNCTION_SCOPE },
- { " (function fun", "(a,b) { infunction; }", ")();",
- i::FUNCTION_SCOPE },
- { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", " more;",
- i::BLOCK_SCOPE },
- { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", "; more;",
- i::BLOCK_SCOPE },
- { " for ", "(let x = 1 ; x < 10; ++ x) {\n"
- " block;\n"
- " }", "\n"
- " more;", i::BLOCK_SCOPE },
- { " for ", "(let x = 1 ; x < 10; ++ x) statement;", " more;",
- i::BLOCK_SCOPE },
- { " for ", "(let x = 1 ; x < 10; ++ x) statement", "\n"
- " more;", i::BLOCK_SCOPE },
- { " for ", "(let x = 1 ; x < 10; ++ x)\n"
- " statement;", "\n"
- " more;", i::BLOCK_SCOPE },
- { " for ", "(let x in {}) { block; }", " more;", i::BLOCK_SCOPE },
- { " for ", "(let x in {}) { block; }", "; more;", i::BLOCK_SCOPE },
- { " for ", "(let x in {}) {\n"
- " block;\n"
- " }", "\n"
- " more;", i::BLOCK_SCOPE },
- { " for ", "(let x in {}) statement;", " more;", i::BLOCK_SCOPE },
- { " for ", "(let x in {}) statement", "\n"
- " more;", i::BLOCK_SCOPE },
- { " for ", "(let x in {})\n"
- " statement;", "\n"
- " more;", i::BLOCK_SCOPE },
- { NULL, NULL, NULL, i::EVAL_SCOPE }
- };
-
- v8::HandleScope handles;
- v8::Persistent<v8::Context> context = v8::Context::New();
- v8::Context::Scope context_scope(context);
-
- int marker;
- i::Isolate::Current()->stack_guard()->SetStackLimit(
- reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
-
- for (int i = 0; source_data[i].outer_prefix; i++) {
- int kPrefixLen = i::StrLength(source_data[i].outer_prefix);
- int kInnerLen = i::StrLength(source_data[i].inner_source);
- int kSuffixLen = i::StrLength(source_data[i].outer_suffix);
- int kProgramSize = kPrefixLen + kInnerLen + kSuffixLen;
- i::Vector<char> program = i::Vector<char>::New(kProgramSize + 1);
- int length;
- length = i::OS::SNPrintF(program, "%s%s%s",
- source_data[i].outer_prefix,
- source_data[i].inner_source,
- source_data[i].outer_suffix);
- ASSERT(length == kProgramSize);
-
- // Parse program source.
- i::Handle<i::String> source(
- FACTORY->NewStringFromAscii(i::CStrVector(program.start())));
- i::Handle<i::Script> script = FACTORY->NewScript(source);
- i::Parser parser(script, false, NULL, NULL);
- parser.SetHarmonyScoping(true);
- i::FunctionLiteral* function =
- parser.ParseProgram(source, true, i::kNonStrictMode);
- ASSERT(function != NULL);
-
- // Check scope types and positions.
- i::Scope* scope = function->scope();
- CHECK(scope->is_global_scope());
- CHECK_EQ(scope->start_position(), 0);
- CHECK_EQ(scope->end_position(), kProgramSize);
- CHECK_EQ(scope->inner_scopes()->length(), 1);
-
- i::Scope* inner_scope = scope->inner_scopes()->at(0);
- CHECK_EQ(inner_scope->type(), source_data[i].scope_type);
- CHECK_EQ(inner_scope->start_position(), kPrefixLen);
- // The end position of a token is one position after the last
- // character belonging to that token.
- CHECK_EQ(inner_scope->end_position(), kPrefixLen + kInnerLen);
- }
-}
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 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:
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Flags: --expose-debug-as debug --allow-natives-syntax
+// Flags: --expose-debug-as debug
// The functions used for testing backtraces. They are at the top to make the
// testing of source line/column easier.
EndTest();
-// With block in function that is marked for optimization while being executed.
-BeginTest("With 7");
-
-function with_7() {
- with({}) {
- %OptimizeFunctionOnNextCall(with_7);
- debugger;
- }
-}
-
-listener_delegate = function(exec_state) {
- CheckScopeChain([debug.ScopeType.With,
- debug.ScopeType.Local,
- debug.ScopeType.Global], exec_state);
- CheckScopeContent({}, 0, exec_state);
-};
-with_7();
-EndTest();
-
-
// Simple closure formed by returning an inner function referering the outer
// functions arguments.
BeginTest("Closure 1");
EndTest();
-// Catch block in function that is marked for optimization while being executed.
-BeginTest("Catch block 7");
-function catch_block_7() {
- %OptimizeFunctionOnNextCall(catch_block_7);
- try {
- throw 'Exception';
- } catch (e) {
- debugger;
- }
-};
-
-
-listener_delegate = function(exec_state) {
- CheckScopeChain([debug.ScopeType.Catch,
- debug.ScopeType.Local,
- debug.ScopeType.Global], exec_state);
- CheckScopeContent({e:'Exception'}, 0, exec_state);
-};
-catch_block_7();
-EndTest();
-
-
assertEquals(begin_test_count, break_count,
'one or more tests did not enter the debugger');
assertEquals(begin_test_count, end_test_count,