Version 3.4.9.
Added support for debugger inspection of locals in optimized frames (issue 1140).
Fixed SConstruct to pass correct defines to samples/preparser when building with library=shared.
Made date parser handle ES5 Date Time Strings correctly (issue 1498).
Fixed a bug in Object.defineProperty on the arguments object.
Performance improvetments on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@8528 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/scopes.cc b/src/scopes.cc
index 74d0c2a..5546875 100644
--- a/src/scopes.cc
+++ b/src/scopes.cc
@@ -119,9 +119,9 @@
temps_(0),
params_(0),
unresolved_(0),
- decls_(0) {
+ decls_(0),
+ already_resolved_(false) {
SetDefaults(type, NULL, Handle<SerializedScopeInfo>::null());
- ASSERT(!resolved());
}
@@ -131,14 +131,14 @@
temps_(4),
params_(4),
unresolved_(16),
- decls_(4) {
+ decls_(4),
+ already_resolved_(false) {
SetDefaults(type, outer_scope, Handle<SerializedScopeInfo>::null());
// At some point we might want to provide outer scopes to
// eval scopes (by walking the stack and reading the scope info).
// In that case, the ASSERT below needs to be adjusted.
ASSERT((type == GLOBAL_SCOPE || type == EVAL_SCOPE) == (outer_scope == NULL));
ASSERT(!HasIllegalRedeclaration());
- ASSERT(!resolved());
}
@@ -148,18 +148,37 @@
temps_(4),
params_(4),
unresolved_(16),
- decls_(4) {
+ decls_(4),
+ already_resolved_(true) {
ASSERT(!scope_info.is_null());
SetDefaults(FUNCTION_SCOPE, NULL, scope_info);
- ASSERT(resolved());
if (scope_info->HasHeapAllocatedLocals()) {
num_heap_slots_ = scope_info_->NumberOfContextSlots();
}
-
AddInnerScope(inner_scope);
}
+Scope::Scope(Scope* inner_scope, Handle<String> catch_variable_name)
+ : inner_scopes_(1),
+ variables_(),
+ temps_(0),
+ params_(0),
+ unresolved_(0),
+ decls_(0),
+ already_resolved_(true) {
+ SetDefaults(CATCH_SCOPE, NULL, Handle<SerializedScopeInfo>::null());
+ AddInnerScope(inner_scope);
+ ++num_var_or_const_;
+ Variable* variable = variables_.Declare(this,
+ catch_variable_name,
+ Variable::VAR,
+ true, // Valid left-hand side.
+ Variable::NORMAL);
+ AllocateHeapSlot(variable);
+}
+
+
void Scope::SetDefaults(Type type,
Scope* outer_scope,
Handle<SerializedScopeInfo> scope_info) {
@@ -190,30 +209,43 @@
Scope* Scope::DeserializeScopeChain(CompilationInfo* info,
Scope* global_scope) {
+ // Reconstruct the outer scope chain from a closure's context chain.
ASSERT(!info->closure().is_null());
- // If we have a serialized scope info, reuse it.
+ Context* context = info->closure()->context();
+ Scope* current_scope = NULL;
Scope* innermost_scope = NULL;
- Scope* scope = NULL;
-
- SerializedScopeInfo* scope_info = info->closure()->shared()->scope_info();
- if (scope_info != SerializedScopeInfo::Empty()) {
- JSFunction* current = *info->closure();
- do {
- current = current->context()->closure();
- Handle<SerializedScopeInfo> scope_info(current->shared()->scope_info());
- if (*scope_info != SerializedScopeInfo::Empty()) {
- scope = new Scope(scope, scope_info);
- if (innermost_scope == NULL) innermost_scope = scope;
- } else {
- ASSERT(current->context()->IsGlobalContext());
+ bool contains_with = false;
+ while (!context->IsGlobalContext()) {
+ if (context->IsWithContext()) {
+ // All the inner scopes are inside a with.
+ contains_with = true;
+ for (Scope* s = innermost_scope; s != NULL; s = s->outer_scope()) {
+ s->scope_inside_with_ = true;
}
- } while (!current->context()->IsGlobalContext());
+ } else {
+ if (context->IsFunctionContext()) {
+ SerializedScopeInfo* scope_info =
+ context->closure()->shared()->scope_info();
+ current_scope =
+ new Scope(current_scope, Handle<SerializedScopeInfo>(scope_info));
+ } else {
+ ASSERT(context->IsCatchContext());
+ String* name = String::cast(context->extension());
+ current_scope = new Scope(current_scope, Handle<String>(name));
+ }
+ if (contains_with) current_scope->RecordWithStatement();
+ if (innermost_scope == NULL) innermost_scope = current_scope;
+ }
+
+ // Forget about a with when we move to a context for a different function.
+ if (context->previous()->closure() != context->closure()) {
+ contains_with = false;
+ }
+ context = context->previous();
}
- global_scope->AddInnerScope(scope);
- if (innermost_scope == NULL) innermost_scope = global_scope;
-
- return innermost_scope;
+ global_scope->AddInnerScope(current_scope);
+ return (innermost_scope == NULL) ? global_scope : innermost_scope;
}
@@ -238,7 +270,7 @@
void Scope::Initialize(bool inside_with) {
- ASSERT(!resolved());
+ ASSERT(!already_resolved());
// Add this scope as a new inner scope of the outer scope.
if (outer_scope_ != NULL) {
@@ -256,11 +288,16 @@
// instead load them directly from the stack. Currently, the only
// such parameter is 'this' which is passed on the stack when
// invoking scripts
- Variable* var =
- variables_.Declare(this, FACTORY->this_symbol(), Variable::VAR,
- false, Variable::THIS);
- var->set_rewrite(new Slot(var, Slot::PARAMETER, -1));
- receiver_ = var;
+ if (is_catch_scope()) {
+ ASSERT(outer_scope() != NULL);
+ receiver_ = outer_scope()->receiver();
+ } else {
+ Variable* var =
+ variables_.Declare(this, FACTORY->this_symbol(), Variable::VAR,
+ false, Variable::THIS);
+ var->set_rewrite(new Slot(var, Slot::PARAMETER, -1));
+ receiver_ = var;
+ }
if (is_function_scope()) {
// Declare 'arguments' variable which exists in all functions.
@@ -274,11 +311,10 @@
Variable* Scope::LocalLookup(Handle<String> name) {
Variable* result = variables_.Lookup(name);
- if (result != NULL || !resolved()) {
+ if (result != NULL || scope_info_.is_null()) {
return result;
}
- // If the scope is resolved, we can find a variable in serialized scope
- // info.
+ // If we have a serialized scope info, we might find the variable there.
//
// We should never lookup 'arguments' in this scope as it is implicitly
// present in every scope.
@@ -326,7 +362,7 @@
void Scope::DeclareParameter(Handle<String> name) {
- ASSERT(!resolved());
+ ASSERT(!already_resolved());
ASSERT(is_function_scope());
Variable* var =
variables_.Declare(this, name, Variable::VAR, true, Variable::NORMAL);
@@ -335,7 +371,7 @@
Variable* Scope::DeclareLocal(Handle<String> name, Variable::Mode mode) {
- ASSERT(!resolved());
+ ASSERT(!already_resolved());
// This function handles VAR and CONST modes. DYNAMIC variables are
// introduces during variable allocation, INTERNAL variables are allocated
// explicitly, and TEMPORARY variables are allocated via NewTemporary().
@@ -358,7 +394,7 @@
// Note that we must not share the unresolved variables with
// the same name because they may be removed selectively via
// RemoveUnresolved().
- ASSERT(!resolved());
+ ASSERT(!already_resolved());
VariableProxy* proxy = new VariableProxy(name, false, inside_with, position);
unresolved_.Add(proxy);
return proxy;
@@ -378,7 +414,7 @@
Variable* Scope::NewTemporary(Handle<String> name) {
- ASSERT(!resolved());
+ ASSERT(!already_resolved());
Variable* var =
new Variable(this, name, Variable::TEMPORARY, true, Variable::NORMAL);
temps_.Add(var);
@@ -508,12 +544,22 @@
}
+Scope* Scope::DeclarationScope() {
+ Scope* scope = this;
+ while (scope->is_catch_scope()) {
+ scope = scope->outer_scope();
+ }
+ return scope;
+}
+
+
#ifdef DEBUG
static const char* Header(Scope::Type type) {
switch (type) {
case Scope::EVAL_SCOPE: return "eval";
case Scope::FUNCTION_SCOPE: return "function";
case Scope::GLOBAL_SCOPE: return "global";
+ case Scope::CATCH_SCOPE: return "catch";
}
UNREACHABLE();
return NULL;
@@ -864,8 +910,10 @@
// visible name.
if ((var->is_this() || var->name()->length() > 0) &&
(var->is_accessed_from_inner_scope() ||
- scope_calls_eval_ || inner_scope_calls_eval_ ||
- scope_contains_with_)) {
+ scope_calls_eval_ ||
+ inner_scope_calls_eval_ ||
+ scope_contains_with_ ||
+ is_catch_scope())) {
var->set_is_used(true);
}
// Global variables do not need to be allocated.
@@ -874,16 +922,20 @@
bool Scope::MustAllocateInContext(Variable* var) {
- // If var is accessed from an inner scope, or if there is a
- // possibility that it might be accessed from the current or an inner
- // scope (through an eval() call), it must be allocated in the
- // context. Exception: temporary variables are not allocated in the
+ // If var is accessed from an inner scope, or if there is a possibility
+ // that it might be accessed from the current or an inner scope (through
+ // an eval() call or a runtime with lookup), it must be allocated in the
// context.
- return
- var->mode() != Variable::TEMPORARY &&
- (var->is_accessed_from_inner_scope() ||
- scope_calls_eval_ || inner_scope_calls_eval_ ||
- scope_contains_with_ || var->is_global());
+ //
+ // Exceptions: temporary variables are never allocated in a context;
+ // catch-bound variables are always allocated in a context.
+ if (var->mode() == Variable::TEMPORARY) return false;
+ if (is_catch_scope()) return true;
+ return var->is_accessed_from_inner_scope() ||
+ scope_calls_eval_ ||
+ inner_scope_calls_eval_ ||
+ scope_contains_with_ ||
+ var->is_global();
}
@@ -1010,7 +1062,7 @@
// If scope is already resolved, we still need to allocate
// variables in inner scopes which might not had been resolved yet.
- if (resolved()) return;
+ if (already_resolved()) return;
// The number of slots required for variables.
num_stack_slots_ = 0;
num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;