Commit 3c7ca304 authored by keuchel@chromium.org's avatar keuchel@chromium.org

Preliminary code for block scopes and block contexts.

BUG=
TEST=

Review URL: http://codereview.chromium.org/7549008

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8911 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 431b51ac
...@@ -50,7 +50,8 @@ Block::Block(Isolate* isolate, ...@@ -50,7 +50,8 @@ Block::Block(Isolate* isolate,
bool is_initializer_block) bool is_initializer_block)
: BreakableStatement(isolate, labels, TARGET_FOR_NAMED_ONLY), : BreakableStatement(isolate, labels, TARGET_FOR_NAMED_ONLY),
statements_(capacity), statements_(capacity),
is_initializer_block_(is_initializer_block) { is_initializer_block_(is_initializer_block),
block_scope_(NULL) {
} }
......
...@@ -359,9 +359,13 @@ class Block: public BreakableStatement { ...@@ -359,9 +359,13 @@ class Block: public BreakableStatement {
ZoneList<Statement*>* statements() { return &statements_; } ZoneList<Statement*>* statements() { return &statements_; }
bool is_initializer_block() const { return is_initializer_block_; } bool is_initializer_block() const { return is_initializer_block_; }
Scope* block_scope() const { return block_scope_; }
void set_block_scope(Scope* block_scope) { block_scope_ = block_scope; }
private: private:
ZoneList<Statement*> statements_; ZoneList<Statement*> statements_;
bool is_initializer_block_; bool is_initializer_block_;
Scope* block_scope_;
}; };
......
...@@ -109,7 +109,7 @@ Handle<Object> Context::Lookup(Handle<String> name, ...@@ -109,7 +109,7 @@ Handle<Object> Context::Lookup(Handle<String> name,
} }
// Check extension/with/global object. // Check extension/with/global object.
if (context->has_extension()) { if (!context->IsBlockContext() && context->has_extension()) {
if (context->IsCatchContext()) { if (context->IsCatchContext()) {
// Catch contexts have the variable name in the extension slot. // Catch contexts have the variable name in the extension slot.
if (name->Equals(String::cast(context->extension()))) { if (name->Equals(String::cast(context->extension()))) {
...@@ -121,6 +121,9 @@ Handle<Object> Context::Lookup(Handle<String> name, ...@@ -121,6 +121,9 @@ Handle<Object> Context::Lookup(Handle<String> name,
return context; return context;
} }
} else { } else {
ASSERT(context->IsGlobalContext() ||
context->IsFunctionContext() ||
context->IsWithContext());
// Global, function, and with contexts may have an object in the // Global, function, and with contexts may have an object in the
// extension slot. // extension slot.
Handle<JSObject> extension(JSObject::cast(context->extension()), Handle<JSObject> extension(JSObject::cast(context->extension()),
...@@ -145,11 +148,20 @@ Handle<Object> Context::Lookup(Handle<String> name, ...@@ -145,11 +148,20 @@ Handle<Object> Context::Lookup(Handle<String> name,
} }
} }
// Only functions can have locals, parameters, and a function name. // Check serialized scope information of functions and blocks. Only
if (context->IsFunctionContext()) { // functions can have parameters, and a function name.
if (context->IsFunctionContext() || context->IsBlockContext()) {
// We may have context-local slots. Check locals in the context. // We may have context-local slots. Check locals in the context.
Handle<SerializedScopeInfo> scope_info( Handle<SerializedScopeInfo> scope_info;
context->closure()->shared()->scope_info(), isolate); if (context->IsFunctionContext()) {
scope_info = Handle<SerializedScopeInfo>(
context->closure()->shared()->scope_info(), isolate);
} else {
ASSERT(context->IsBlockContext());
scope_info = Handle<SerializedScopeInfo>(
SerializedScopeInfo::cast(context->extension()), isolate);
}
Variable::Mode mode; Variable::Mode mode;
int index = scope_info->ContextSlotIndex(*name, &mode); int index = scope_info->ContextSlotIndex(*name, &mode);
ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS); ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS);
......
...@@ -295,6 +295,10 @@ class Context: public FixedArray { ...@@ -295,6 +295,10 @@ class Context: public FixedArray {
Map* map = this->map(); Map* map = this->map();
return map == map->GetHeap()->with_context_map(); return map == map->GetHeap()->with_context_map();
} }
bool IsBlockContext() {
Map* map = this->map();
return map == map->GetHeap()->block_context_map();
}
// Tells whether the global context is marked with out of memory. // Tells whether the global context is marked with out of memory.
inline bool has_out_of_memory(); inline bool has_out_of_memory();
......
...@@ -740,6 +740,7 @@ Persistent<Context> Shell::CreateEvaluationContext() { ...@@ -740,6 +740,7 @@ Persistent<Context> Shell::CreateEvaluationContext() {
// Initialize the global objects // Initialize the global objects
Handle<ObjectTemplate> global_template = CreateGlobalTemplate(); Handle<ObjectTemplate> global_template = CreateGlobalTemplate();
Persistent<Context> context = Context::New(NULL, global_template); Persistent<Context> context = Context::New(NULL, global_template);
ASSERT(!context.IsEmpty());
Context::Scope scope(context); Context::Scope scope(context);
#ifndef V8_SHARED #ifndef V8_SHARED
......
...@@ -103,7 +103,8 @@ Debug.ScopeType = { Global: 0, ...@@ -103,7 +103,8 @@ Debug.ScopeType = { Global: 0,
Local: 1, Local: 1,
With: 2, With: 2,
Closure: 3, Closure: 3,
Catch: 4 }; Catch: 4,
Block: 5 };
// Current debug state. // Current debug state.
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "macro-assembler.h" #include "macro-assembler.h"
#include "objects.h" #include "objects.h"
#include "objects-visiting.h" #include "objects-visiting.h"
#include "scopeinfo.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -291,6 +292,19 @@ Handle<Context> Factory::NewWithContext(Handle<JSFunction> function, ...@@ -291,6 +292,19 @@ Handle<Context> Factory::NewWithContext(Handle<JSFunction> function,
} }
Handle<Context> Factory::NewBlockContext(
Handle<JSFunction> function,
Handle<Context> previous,
Handle<SerializedScopeInfo> scope_info) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateBlockContext(*function,
*previous,
*scope_info),
Context);
}
Handle<Struct> Factory::NewStruct(InstanceType type) { Handle<Struct> Factory::NewStruct(InstanceType type) {
CALL_HEAP_FUNCTION( CALL_HEAP_FUNCTION(
isolate(), isolate(),
...@@ -734,6 +748,14 @@ Handle<JSFunction> Factory::NewFunctionWithoutPrototype(Handle<String> name, ...@@ -734,6 +748,14 @@ Handle<JSFunction> Factory::NewFunctionWithoutPrototype(Handle<String> name,
} }
Handle<SerializedScopeInfo> Factory::NewSerializedScopeInfo(int length) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateSerializedScopeInfo(length),
SerializedScopeInfo);
}
Handle<Code> Factory::NewCode(const CodeDesc& desc, Handle<Code> Factory::NewCode(const CodeDesc& desc,
Code::Flags flags, Code::Flags flags,
Handle<Object> self_ref, Handle<Object> self_ref,
......
...@@ -167,6 +167,11 @@ class Factory { ...@@ -167,6 +167,11 @@ class Factory {
Handle<Context> previous, Handle<Context> previous,
Handle<JSObject> extension); Handle<JSObject> extension);
// Create a 'block' context.
Handle<Context> NewBlockContext(Handle<JSFunction> function,
Handle<Context> previous,
Handle<SerializedScopeInfo> scope_info);
// Return the Symbol matching the passed in string. // Return the Symbol matching the passed in string.
Handle<String> SymbolFromString(Handle<String> value); Handle<String> SymbolFromString(Handle<String> value);
...@@ -277,6 +282,8 @@ class Factory { ...@@ -277,6 +282,8 @@ class Factory {
Handle<Context> context, Handle<Context> context,
PretenureFlag pretenure = TENURED); PretenureFlag pretenure = TENURED);
Handle<SerializedScopeInfo> NewSerializedScopeInfo(int length);
Handle<Code> NewCode(const CodeDesc& desc, Handle<Code> NewCode(const CodeDesc& desc,
Code::Flags flags, Code::Flags flags,
Handle<Object> self_reference, Handle<Object> self_reference,
......
...@@ -100,6 +100,7 @@ private: ...@@ -100,6 +100,7 @@ private:
DEFINE_bool(harmony_typeof, false, "enable harmony semantics for typeof") DEFINE_bool(harmony_typeof, false, "enable harmony semantics for typeof")
DEFINE_bool(harmony_proxies, false, "enable harmony proxies") DEFINE_bool(harmony_proxies, false, "enable harmony proxies")
DEFINE_bool(harmony_weakmaps, false, "enable harmony weak maps") DEFINE_bool(harmony_weakmaps, false, "enable harmony weak maps")
DEFINE_bool(harmony_block_scoping, false, "enable harmony block scoping")
// Flags for experimental implementation features. // Flags for experimental implementation features.
DEFINE_bool(unbox_double_arrays, true, "automatically unbox arrays of doubles") DEFINE_bool(unbox_double_arrays, true, "automatically unbox arrays of doubles")
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include "macro-assembler.h" #include "macro-assembler.h"
#include "prettyprinter.h" #include "prettyprinter.h"
#include "scopes.h" #include "scopes.h"
#include "scopeinfo.h"
#include "stub-cache.h" #include "stub-cache.h"
namespace v8 { namespace v8 {
...@@ -845,8 +846,23 @@ void FullCodeGenerator::VisitBlock(Block* stmt) { ...@@ -845,8 +846,23 @@ void FullCodeGenerator::VisitBlock(Block* stmt) {
Breakable nested_statement(this, stmt); Breakable nested_statement(this, stmt);
SetStatementPosition(stmt); SetStatementPosition(stmt);
Scope* saved_scope = scope();
if (stmt->block_scope() != NULL) {
{ Comment cmnt(masm_, "[ Extend block context");
scope_ = stmt->block_scope();
__ Push(scope_->GetSerializedScopeInfo());
PushFunctionArgumentForContextAllocation();
__ CallRuntime(Runtime::kPushBlockContext, 2);
StoreToFrameField(StandardFrameConstants::kContextOffset,
context_register());
}
{ Comment cmnt(masm_, "[ Declarations");
VisitDeclarations(scope_->declarations());
}
}
PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
VisitStatements(stmt->statements()); VisitStatements(stmt->statements());
scope_ = saved_scope;
__ bind(nested_statement.break_target()); __ bind(nested_statement.break_target());
PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
} }
......
...@@ -1745,6 +1745,12 @@ bool Heap::CreateInitialMaps() { ...@@ -1745,6 +1745,12 @@ bool Heap::CreateInitialMaps() {
set_fixed_cow_array_map(Map::cast(obj)); set_fixed_cow_array_map(Map::cast(obj));
ASSERT(fixed_array_map() != fixed_cow_array_map()); ASSERT(fixed_array_map() != fixed_cow_array_map());
{ MaybeObject* maybe_obj =
AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
if (!maybe_obj->ToObject(&obj)) return false;
}
set_serialized_scope_info_map(Map::cast(obj));
{ MaybeObject* maybe_obj = AllocateMap(HEAP_NUMBER_TYPE, HeapNumber::kSize); { MaybeObject* maybe_obj = AllocateMap(HEAP_NUMBER_TYPE, HeapNumber::kSize);
if (!maybe_obj->ToObject(&obj)) return false; if (!maybe_obj->ToObject(&obj)) return false;
} }
...@@ -1906,6 +1912,12 @@ bool Heap::CreateInitialMaps() { ...@@ -1906,6 +1912,12 @@ bool Heap::CreateInitialMaps() {
} }
set_with_context_map(Map::cast(obj)); set_with_context_map(Map::cast(obj));
{ MaybeObject* maybe_obj =
AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
if (!maybe_obj->ToObject(&obj)) return false;
}
set_block_context_map(Map::cast(obj));
{ MaybeObject* maybe_obj = { MaybeObject* maybe_obj =
AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel); AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
if (!maybe_obj->ToObject(&obj)) return false; if (!maybe_obj->ToObject(&obj)) return false;
...@@ -4017,6 +4029,37 @@ MaybeObject* Heap::AllocateWithContext(JSFunction* function, ...@@ -4017,6 +4029,37 @@ MaybeObject* Heap::AllocateWithContext(JSFunction* function,
} }
MaybeObject* Heap::AllocateBlockContext(JSFunction* function,
Context* previous,
SerializedScopeInfo* scope_info) {
Object* result;
{ MaybeObject* maybe_result =
AllocateFixedArray(scope_info->NumberOfContextSlots());
if (!maybe_result->ToObject(&result)) return maybe_result;
}
// TODO(keuchel): properly initialize context slots.
Context* context = reinterpret_cast<Context*>(result);
context->set_map(block_context_map());
context->set_closure(function);
context->set_previous(previous);
context->set_extension(scope_info);
context->set_global(previous->global());
return context;
}
MaybeObject* Heap::AllocateSerializedScopeInfo(int length) {
Object* result;
{ MaybeObject* maybe_result = AllocateFixedArray(length, TENURED);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
SerializedScopeInfo* scope_info =
reinterpret_cast<SerializedScopeInfo*>(result);
scope_info->set_map(serialized_scope_info_map());
return scope_info;
}
MaybeObject* Heap::AllocateStruct(InstanceType type) { MaybeObject* Heap::AllocateStruct(InstanceType type) {
Map* map; Map* map;
switch (type) { switch (type) {
......
...@@ -65,6 +65,7 @@ inline Heap* _inline_get_heap_(); ...@@ -65,6 +65,7 @@ inline Heap* _inline_get_heap_();
V(Map, heap_number_map, HeapNumberMap) \ V(Map, heap_number_map, HeapNumberMap) \
V(Map, global_context_map, GlobalContextMap) \ V(Map, global_context_map, GlobalContextMap) \
V(Map, fixed_array_map, FixedArrayMap) \ V(Map, fixed_array_map, FixedArrayMap) \
V(Map, serialized_scope_info_map, SerializedScopeInfoMap) \
V(Map, fixed_cow_array_map, FixedCOWArrayMap) \ V(Map, fixed_cow_array_map, FixedCOWArrayMap) \
V(Map, fixed_double_array_map, FixedDoubleArrayMap) \ V(Map, fixed_double_array_map, FixedDoubleArrayMap) \
V(Object, no_interceptor_result_sentinel, NoInterceptorResultSentinel) \ V(Object, no_interceptor_result_sentinel, NoInterceptorResultSentinel) \
...@@ -111,6 +112,7 @@ inline Heap* _inline_get_heap_(); ...@@ -111,6 +112,7 @@ inline Heap* _inline_get_heap_();
V(Map, function_context_map, FunctionContextMap) \ V(Map, function_context_map, FunctionContextMap) \
V(Map, catch_context_map, CatchContextMap) \ V(Map, catch_context_map, CatchContextMap) \
V(Map, with_context_map, WithContextMap) \ V(Map, with_context_map, WithContextMap) \
V(Map, block_context_map, BlockContextMap) \
V(Map, code_map, CodeMap) \ V(Map, code_map, CodeMap) \
V(Map, oddball_map, OddballMap) \ V(Map, oddball_map, OddballMap) \
V(Map, global_property_cell_map, GlobalPropertyCellMap) \ V(Map, global_property_cell_map, GlobalPropertyCellMap) \
...@@ -221,7 +223,8 @@ inline Heap* _inline_get_heap_(); ...@@ -221,7 +223,8 @@ inline Heap* _inline_get_heap_();
V(closure_symbol, "(closure)") \ V(closure_symbol, "(closure)") \
V(use_strict, "use strict") \ V(use_strict, "use strict") \
V(dot_symbol, ".") \ V(dot_symbol, ".") \
V(anonymous_function_symbol, "(anonymous function)") V(anonymous_function_symbol, "(anonymous function)") \
V(block_scope_symbol, ".block")
// Forward declarations. // Forward declarations.
class GCTracer; class GCTracer;
...@@ -484,6 +487,9 @@ class Heap { ...@@ -484,6 +487,9 @@ class Heap {
// Allocates an empty code cache. // Allocates an empty code cache.
MUST_USE_RESULT MaybeObject* AllocateCodeCache(); MUST_USE_RESULT MaybeObject* AllocateCodeCache();
// Allocates a serialized scope info.
MUST_USE_RESULT MaybeObject* AllocateSerializedScopeInfo(int length);
// Allocates an empty PolymorphicCodeCache. // Allocates an empty PolymorphicCodeCache.
MUST_USE_RESULT MaybeObject* AllocatePolymorphicCodeCache(); MUST_USE_RESULT MaybeObject* AllocatePolymorphicCodeCache();
...@@ -669,6 +675,11 @@ class Heap { ...@@ -669,6 +675,11 @@ class Heap {
Context* previous, Context* previous,
JSObject* extension); JSObject* extension);
// Allocate a block context.
MUST_USE_RESULT MaybeObject* AllocateBlockContext(JSFunction* function,
Context* previous,
SerializedScopeInfo* info);
// Allocates a new utility object in the old generation. // Allocates a new utility object in the old generation.
MUST_USE_RESULT MaybeObject* AllocateStruct(InstanceType type); MUST_USE_RESULT MaybeObject* AllocateStruct(InstanceType type);
......
...@@ -2480,6 +2480,9 @@ void HGraphBuilder::VisitBlock(Block* stmt) { ...@@ -2480,6 +2480,9 @@ void HGraphBuilder::VisitBlock(Block* stmt) {
ASSERT(!HasStackOverflow()); ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL); ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor()); ASSERT(current_block()->HasPredecessor());
if (stmt->block_scope() != NULL) {
return Bailout("ScopedBlock");
}
BreakAndContinueInfo break_info(stmt); BreakAndContinueInfo break_info(stmt);
{ BreakAndContinueScope push(&break_info, this); { BreakAndContinueScope push(&break_info, this);
CHECK_BAILOUT(VisitStatements(stmt->statements())); CHECK_BAILOUT(VisitStatements(stmt->statements()));
......
...@@ -195,7 +195,8 @@ ScopeType = { Global: 0, ...@@ -195,7 +195,8 @@ ScopeType = { Global: 0,
Local: 1, Local: 1,
With: 2, With: 2,
Closure: 3, Closure: 3,
Catch: 4 }; Catch: 4,
Block: 5 };
// Mirror hierarchy: // Mirror hierarchy:
......
...@@ -552,7 +552,8 @@ bool Object::IsContext() { ...@@ -552,7 +552,8 @@ bool Object::IsContext() {
return (map == heap->function_context_map() || return (map == heap->function_context_map() ||
map == heap->catch_context_map() || map == heap->catch_context_map() ||
map == heap->with_context_map() || map == heap->with_context_map() ||
map == heap->global_context_map()); map == heap->global_context_map() ||
map == heap->block_context_map());
} }
return false; return false;
} }
...@@ -565,6 +566,13 @@ bool Object::IsGlobalContext() { ...@@ -565,6 +566,13 @@ bool Object::IsGlobalContext() {
} }
bool Object::IsSerializedScopeInfo() {
return Object::IsHeapObject() &&
HeapObject::cast(this)->map() ==
HeapObject::cast(this)->GetHeap()->serialized_scope_info_map();
}
bool Object::IsJSFunction() { bool Object::IsJSFunction() {
return Object::IsHeapObject() return Object::IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type() == JS_FUNCTION_TYPE; && HeapObject::cast(this)->map()->instance_type() == JS_FUNCTION_TYPE;
......
...@@ -743,6 +743,7 @@ class MaybeObject BASE_EMBEDDED { ...@@ -743,6 +743,7 @@ class MaybeObject BASE_EMBEDDED {
V(FixedDoubleArray) \ V(FixedDoubleArray) \
V(Context) \ V(Context) \
V(GlobalContext) \ V(GlobalContext) \
V(SerializedScopeInfo) \
V(JSFunction) \ V(JSFunction) \
V(Code) \ V(Code) \
V(Oddball) \ V(Oddball) \
......
...@@ -584,7 +584,8 @@ Parser::Parser(Handle<Script> script, ...@@ -584,7 +584,8 @@ Parser::Parser(Handle<Script> script,
pre_data_(pre_data), pre_data_(pre_data),
fni_(NULL), fni_(NULL),
stack_overflow_(false), stack_overflow_(false),
parenthesized_function_(false) { parenthesized_function_(false),
harmony_block_scoping_(false) {
AstNode::ResetIds(); AstNode::ResetIds();
} }
...@@ -809,6 +810,9 @@ void Parser::ReportMessageAt(Scanner::Location source_location, ...@@ -809,6 +810,9 @@ void Parser::ReportMessageAt(Scanner::Location source_location,
isolate()->Throw(*result, &location); isolate()->Throw(*result, &location);
} }
void Parser::SetHarmonyBlockScoping(bool block_scoping) {
harmony_block_scoping_ = block_scoping;
}
// Base class containing common code for the different finder classes used by // Base class containing common code for the different finder classes used by
// the parser. // the parser.
...@@ -1487,6 +1491,8 @@ Statement* Parser::ParseFunctionDeclaration(bool* ok) { ...@@ -1487,6 +1491,8 @@ Statement* Parser::ParseFunctionDeclaration(bool* ok) {
Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) { Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) {
if (harmony_block_scoping_) return ParseScopedBlock(labels, ok);
// Block :: // Block ::
// '{' Statement* '}' // '{' Statement* '}'
...@@ -1510,6 +1516,56 @@ Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) { ...@@ -1510,6 +1516,56 @@ Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) {
} }
Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) {
// Construct block expecting 16 statements.
Block* body = new(zone()) Block(isolate(), labels, 16, false);
Scope* saved_scope = top_scope_;
Scope* block_scope = NewScope(top_scope_,
Scope::BLOCK_SCOPE,
inside_with());
body->set_block_scope(block_scope);
block_scope->DeclareLocal(isolate()->factory()->block_scope_symbol(),
Variable::VAR);
if (top_scope_->is_strict_mode()) {
block_scope->EnableStrictMode();
}
top_scope_ = block_scope;
// Parse the statements and collect escaping labels.
TargetCollector collector;
Target target(&this->target_stack_, &collector);
Expect(Token::LBRACE, CHECK_OK);
{
Target target_body(&this->target_stack_, body);
InitializationBlockFinder block_finder(top_scope_, target_stack_);
while (peek() != Token::RBRACE) {
Statement* stat = ParseStatement(NULL, CHECK_OK);
if (stat && !stat->IsEmpty()) {
body->AddStatement(stat);
block_finder.Update(stat);
}
}
}
Expect(Token::RBRACE, CHECK_OK);
// Create exit block.
Block* exit = new(zone()) Block(isolate(), NULL, 1, false);
exit->AddStatement(new(zone()) ExitContextStatement());
// Create a try-finally statement.
TryFinallyStatement* try_finally =
new(zone()) TryFinallyStatement(body, exit);
try_finally->set_escaping_targets(collector.targets());
top_scope_ = saved_scope;
// Create a result block.
Block* result = new(zone()) Block(isolate(), NULL, 1, false);
result->AddStatement(try_finally);
return result;
}
Block* Parser::ParseVariableStatement(bool* ok) { Block* Parser::ParseVariableStatement(bool* ok) {
// VariableStatement :: // VariableStatement ::
// VariableDeclarations ';' // VariableDeclarations ';'
...@@ -5105,6 +5161,8 @@ bool ParserApi::Parse(CompilationInfo* info) { ...@@ -5105,6 +5161,8 @@ bool ParserApi::Parse(CompilationInfo* info) {
Handle<Script> script = info->script(); Handle<Script> script = info->script();
if (info->is_lazy()) { if (info->is_lazy()) {
Parser parser(script, true, NULL, NULL); Parser parser(script, true, NULL, NULL);
parser.SetHarmonyBlockScoping(!info->is_native() &&
FLAG_harmony_block_scoping);
result = parser.ParseLazy(info); result = parser.ParseLazy(info);
} else { } else {
// Whether we allow %identifier(..) syntax. // Whether we allow %identifier(..) syntax.
...@@ -5112,6 +5170,8 @@ bool ParserApi::Parse(CompilationInfo* info) { ...@@ -5112,6 +5170,8 @@ bool ParserApi::Parse(CompilationInfo* info) {
info->allows_natives_syntax() || FLAG_allow_natives_syntax; info->allows_natives_syntax() || FLAG_allow_natives_syntax;
ScriptDataImpl* pre_data = info->pre_parse_data(); ScriptDataImpl* pre_data = info->pre_parse_data();
Parser parser(script, allow_natives_syntax, info->extension(), pre_data); Parser parser(script, allow_natives_syntax, info->extension(), pre_data);
parser.SetHarmonyBlockScoping(!info->is_native() &&
FLAG_harmony_block_scoping);
if (pre_data != NULL && pre_data->has_error()) { if (pre_data != NULL && pre_data->has_error()) {
Scanner::Location loc = pre_data->MessageLocation(); Scanner::Location loc = pre_data->MessageLocation();
const char* message = pre_data->BuildMessage(); const char* message = pre_data->BuildMessage();
...@@ -5130,7 +5190,6 @@ bool ParserApi::Parse(CompilationInfo* info) { ...@@ -5130,7 +5190,6 @@ bool ParserApi::Parse(CompilationInfo* info) {
info->StrictMode()); info->StrictMode());
} }
} }
info->SetFunction(result); info->SetFunction(result);
return (result != NULL); return (result != NULL);
} }
......
...@@ -435,6 +435,7 @@ class Parser { ...@@ -435,6 +435,7 @@ class Parser {
void ReportMessageAt(Scanner::Location loc, void ReportMessageAt(Scanner::Location loc,
const char* message, const char* message,
Vector<Handle<String> > args); Vector<Handle<String> > args);
void SetHarmonyBlockScoping(bool block_scoping);
private: private:
// Limit on number of function parameters is chosen arbitrarily. // Limit on number of function parameters is chosen arbitrarily.
...@@ -483,6 +484,7 @@ class Parser { ...@@ -483,6 +484,7 @@ class Parser {
Statement* ParseFunctionDeclaration(bool* ok); Statement* ParseFunctionDeclaration(bool* ok);
Statement* ParseNativeDeclaration(bool* ok); Statement* ParseNativeDeclaration(bool* ok);
Block* ParseBlock(ZoneStringList* labels, bool* ok); Block* ParseBlock(ZoneStringList* labels, bool* ok);
Block* ParseScopedBlock(ZoneStringList* labels, bool* ok);
Block* ParseVariableStatement(bool* ok); Block* ParseVariableStatement(bool* ok);
Block* ParseVariableDeclarations(bool accept_IN, Block* ParseVariableDeclarations(bool accept_IN,
Handle<String>* out, Handle<String>* out,
...@@ -715,6 +717,7 @@ class Parser { ...@@ -715,6 +717,7 @@ class Parser {
// Heuristically that means that the function will be called immediately, // Heuristically that means that the function will be called immediately,
// so never lazily compile it. // so never lazily compile it.
bool parenthesized_function_; bool parenthesized_function_;
bool harmony_block_scoping_;
friend class LexicalScope; friend class LexicalScope;
}; };
......
...@@ -8316,6 +8316,30 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) { ...@@ -8316,6 +8316,30 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
} }
RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
NoHandleAllocation ha;
ASSERT(args.length() == 2);
SerializedScopeInfo* scope_info = SerializedScopeInfo::cast(args[0]);
JSFunction* function;
if (args[1]->IsSmi()) {
// A smi sentinel indicates a context nested inside global code rather
// than some function. There is a canonical empty function that can be
// gotten from the global context.
function = isolate->context()->global_context()->closure();
} else {
function = JSFunction::cast(args[1]);
}
Context* context;
MaybeObject* maybe_context =
isolate->heap()->AllocateBlockContext(function,
isolate->context(),
scope_info);
if (!maybe_context->To(&context)) return maybe_context;
isolate->set_context(context);
return context;
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) { RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
HandleScope scope(isolate); HandleScope scope(isolate);
ASSERT(args.length() == 2); ASSERT(args.length() == 2);
...@@ -10641,6 +10665,34 @@ static Handle<JSObject> MaterializeCatchScope(Isolate* isolate, ...@@ -10641,6 +10665,34 @@ static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
} }
// Create a plain JSObject which materializes the block scope for the specified
// block context.
static Handle<JSObject> MaterializeBlockScope(
Isolate* isolate,
Handle<Context> context) {
ASSERT(context->IsBlockContext());
Handle<SerializedScopeInfo> serialized_scope_info(
SerializedScopeInfo::cast(context->extension()));
ScopeInfo<> scope_info(*serialized_scope_info);
// Allocate and initialize a JSObject with all the arguments, stack locals
// heap locals and extension properties of the debugged function.
Handle<JSObject> block_scope =
isolate->factory()->NewJSObject(isolate->object_function());
// Fill all context locals.
if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
if (!CopyContextLocalsToScopeObject(isolate,
serialized_scope_info, scope_info,
context, block_scope)) {
return Handle<JSObject>();
}
}
return block_scope;
}
// Iterate over the actual scopes visible from a stack frame. 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 // backed by an actual context except the local scope, which is inserted
// "artifically" in the context chain. // "artifically" in the context chain.
...@@ -10651,7 +10703,8 @@ class ScopeIterator { ...@@ -10651,7 +10703,8 @@ class ScopeIterator {
ScopeTypeLocal, ScopeTypeLocal,
ScopeTypeWith, ScopeTypeWith,
ScopeTypeClosure, ScopeTypeClosure,
ScopeTypeCatch ScopeTypeCatch,
ScopeTypeBlock
}; };
ScopeIterator(Isolate* isolate, ScopeIterator(Isolate* isolate,
...@@ -10677,8 +10730,10 @@ class ScopeIterator { ...@@ -10677,8 +10730,10 @@ class ScopeIterator {
} else if (context_->IsFunctionContext()) { } else if (context_->IsFunctionContext()) {
at_local_ = true; at_local_ = true;
} else if (context_->closure() != *function_) { } else if (context_->closure() != *function_) {
// The context_ is a with or catch block from the outer function. // The context_ is a block or with or catch block from the outer function.
ASSERT(context_->IsWithContext() || context_->IsCatchContext()); ASSERT(context_->IsWithContext() ||
context_->IsCatchContext() ||
context_->IsBlockContext());
at_local_ = true; at_local_ = true;
} }
} }
...@@ -10733,6 +10788,9 @@ class ScopeIterator { ...@@ -10733,6 +10788,9 @@ class ScopeIterator {
if (context_->IsCatchContext()) { if (context_->IsCatchContext()) {
return ScopeTypeCatch; return ScopeTypeCatch;
} }
if (context_->IsBlockContext()) {
return ScopeTypeBlock;
}
ASSERT(context_->IsWithContext()); ASSERT(context_->IsWithContext());
return ScopeTypeWith; return ScopeTypeWith;
} }
...@@ -10753,6 +10811,8 @@ class ScopeIterator { ...@@ -10753,6 +10811,8 @@ class ScopeIterator {
case ScopeIterator::ScopeTypeClosure: case ScopeIterator::ScopeTypeClosure:
// Materialize the content of the closure scope into a JSObject. // Materialize the content of the closure scope into a JSObject.
return MaterializeClosure(isolate_, CurrentContext()); return MaterializeClosure(isolate_, CurrentContext());
case ScopeIterator::ScopeTypeBlock:
return MaterializeBlockScope(isolate_, CurrentContext());
} }
UNREACHABLE(); UNREACHABLE();
return Handle<JSObject>(); return Handle<JSObject>();
...@@ -11309,7 +11369,13 @@ static Handle<Context> CopyWithContextChain(Isolate* isolate, ...@@ -11309,7 +11369,13 @@ static Handle<Context> CopyWithContextChain(Isolate* isolate,
new_previous, new_previous,
name, name,
thrown_object); thrown_object);
} else if (current->IsBlockContext()) {
Handle<SerializedScopeInfo> scope_info(
SerializedScopeInfo::cast(current->extension()));
new_current =
isolate->factory()->NewBlockContext(function, new_previous, scope_info);
} else { } else {
ASSERT(current->IsWithContext());
Handle<JSObject> extension(JSObject::cast(current->extension())); Handle<JSObject> extension(JSObject::cast(current->extension()));
new_current = new_current =
isolate->factory()->NewWithContext(function, new_previous, extension); isolate->factory()->NewWithContext(function, new_previous, extension);
......
...@@ -310,6 +310,7 @@ namespace internal { ...@@ -310,6 +310,7 @@ namespace internal {
F(NewFunctionContext, 1, 1) \ F(NewFunctionContext, 1, 1) \
F(PushWithContext, 2, 1) \ F(PushWithContext, 2, 1) \
F(PushCatchContext, 3, 1) \ F(PushCatchContext, 3, 1) \
F(PushBlockContext, 2, 1) \
F(DeleteContextSlot, 2, 1) \ F(DeleteContextSlot, 2, 1) \
F(LoadContextSlot, 2, 2) \ F(LoadContextSlot, 2, 2) \
F(LoadContextSlotNoReferenceError, 2, 2) \ F(LoadContextSlotNoReferenceError, 2, 2) \
......
...@@ -313,7 +313,7 @@ Handle<SerializedScopeInfo> ScopeInfo<Allocator>::Serialize() { ...@@ -313,7 +313,7 @@ Handle<SerializedScopeInfo> ScopeInfo<Allocator>::Serialize() {
stack_slots_.length(); stack_slots_.length();
Handle<SerializedScopeInfo> data( Handle<SerializedScopeInfo> data(
SerializedScopeInfo::cast(*FACTORY->NewFixedArray(length, TENURED))); SerializedScopeInfo::cast(*FACTORY->NewSerializedScopeInfo(length)));
AssertNoAllocation nogc; AssertNoAllocation nogc;
Object** p0 = data->data_start(); Object** p0 = data->data_start();
......
...@@ -107,7 +107,7 @@ class SerializedScopeInfo : public FixedArray { ...@@ -107,7 +107,7 @@ class SerializedScopeInfo : public FixedArray {
public : public :
static SerializedScopeInfo* cast(Object* object) { static SerializedScopeInfo* cast(Object* object) {
ASSERT(object->IsFixedArray()); ASSERT(object->IsSerializedScopeInfo());
return reinterpret_cast<SerializedScopeInfo*>(object); return reinterpret_cast<SerializedScopeInfo*>(object);
} }
......
...@@ -146,7 +146,9 @@ Scope::Scope(Scope* outer_scope, Type type) ...@@ -146,7 +146,9 @@ Scope::Scope(Scope* outer_scope, Type type)
} }
Scope::Scope(Scope* inner_scope, Handle<SerializedScopeInfo> scope_info) Scope::Scope(Scope* inner_scope,
Type type,
Handle<SerializedScopeInfo> scope_info)
: isolate_(Isolate::Current()), : isolate_(Isolate::Current()),
inner_scopes_(4), inner_scopes_(4),
variables_(), variables_(),
...@@ -156,7 +158,7 @@ Scope::Scope(Scope* inner_scope, Handle<SerializedScopeInfo> scope_info) ...@@ -156,7 +158,7 @@ Scope::Scope(Scope* inner_scope, Handle<SerializedScopeInfo> scope_info)
decls_(4), decls_(4),
already_resolved_(true) { already_resolved_(true) {
ASSERT(!scope_info.is_null()); ASSERT(!scope_info.is_null());
SetDefaults(FUNCTION_SCOPE, NULL, scope_info); SetDefaults(type, NULL, scope_info);
if (scope_info->HasHeapAllocatedLocals()) { if (scope_info->HasHeapAllocatedLocals()) {
num_heap_slots_ = scope_info_->NumberOfContextSlots(); num_heap_slots_ = scope_info_->NumberOfContextSlots();
} }
...@@ -232,8 +234,13 @@ Scope* Scope::DeserializeScopeChain(CompilationInfo* info, ...@@ -232,8 +234,13 @@ Scope* Scope::DeserializeScopeChain(CompilationInfo* info,
if (context->IsFunctionContext()) { if (context->IsFunctionContext()) {
SerializedScopeInfo* scope_info = SerializedScopeInfo* scope_info =
context->closure()->shared()->scope_info(); context->closure()->shared()->scope_info();
current_scope = current_scope = new Scope(current_scope, FUNCTION_SCOPE,
new Scope(current_scope, Handle<SerializedScopeInfo>(scope_info)); Handle<SerializedScopeInfo>(scope_info));
} else if (context->IsBlockContext()) {
SerializedScopeInfo* scope_info =
SerializedScopeInfo::cast(context->extension());
current_scope = new Scope(current_scope, BLOCK_SCOPE,
Handle<SerializedScopeInfo>(scope_info));
} else { } else {
ASSERT(context->IsCatchContext()); ASSERT(context->IsCatchContext());
String* name = String::cast(context->extension()); String* name = String::cast(context->extension());
...@@ -294,10 +301,13 @@ void Scope::Initialize(bool inside_with) { ...@@ -294,10 +301,13 @@ void Scope::Initialize(bool inside_with) {
// instead load them directly from the stack. Currently, the only // instead load them directly from the stack. Currently, the only
// such parameter is 'this' which is passed on the stack when // such parameter is 'this' which is passed on the stack when
// invoking scripts // invoking scripts
if (is_catch_scope()) { if (is_catch_scope() || is_block_scope()) {
ASSERT(outer_scope() != NULL); ASSERT(outer_scope() != NULL);
receiver_ = outer_scope()->receiver(); receiver_ = outer_scope()->receiver();
} else { } else {
ASSERT(is_function_scope() ||
is_global_scope() ||
is_eval_scope());
Variable* var = Variable* var =
variables_.Declare(this, variables_.Declare(this,
isolate_->factory()->this_symbol(), isolate_->factory()->this_symbol(),
...@@ -559,13 +569,22 @@ int Scope::ContextChainLength(Scope* scope) { ...@@ -559,13 +569,22 @@ int Scope::ContextChainLength(Scope* scope) {
Scope* Scope::DeclarationScope() { Scope* Scope::DeclarationScope() {
Scope* scope = this; Scope* scope = this;
while (scope->is_catch_scope()) { while (scope->is_catch_scope() ||
scope->is_block_scope()) {
scope = scope->outer_scope(); scope = scope->outer_scope();
} }
return scope; return scope;
} }
Handle<SerializedScopeInfo> Scope::GetSerializedScopeInfo() {
if (scope_info_.is_null()) {
scope_info_ = SerializedScopeInfo::Create(this);
}
return scope_info_;
}
#ifdef DEBUG #ifdef DEBUG
static const char* Header(Scope::Type type) { static const char* Header(Scope::Type type) {
switch (type) { switch (type) {
...@@ -573,6 +592,7 @@ static const char* Header(Scope::Type type) { ...@@ -573,6 +592,7 @@ static const char* Header(Scope::Type type) {
case Scope::FUNCTION_SCOPE: return "function"; case Scope::FUNCTION_SCOPE: return "function";
case Scope::GLOBAL_SCOPE: return "global"; case Scope::GLOBAL_SCOPE: return "global";
case Scope::CATCH_SCOPE: return "catch"; case Scope::CATCH_SCOPE: return "catch";
case Scope::BLOCK_SCOPE: return "block";
} }
UNREACHABLE(); UNREACHABLE();
return NULL; return NULL;
...@@ -598,9 +618,11 @@ static void PrintVar(PrettyPrinter* printer, int indent, Variable* var) { ...@@ -598,9 +618,11 @@ static void PrintVar(PrettyPrinter* printer, int indent, Variable* var) {
PrintF("; // "); PrintF("; // ");
if (var->rewrite() != NULL) { if (var->rewrite() != NULL) {
PrintF("%s, ", printer->Print(var->rewrite())); PrintF("%s, ", printer->Print(var->rewrite()));
if (var->is_accessed_from_inner_scope()) PrintF(", "); if (var->is_accessed_from_inner_function_scope()) PrintF(", ");
}
if (var->is_accessed_from_inner_function_scope()) {
PrintF("inner scope access");
} }
if (var->is_accessed_from_inner_scope()) PrintF("inner scope access");
PrintF("\n"); PrintF("\n");
} }
} }
...@@ -721,7 +743,7 @@ Variable* Scope::NonLocal(Handle<String> name, Variable::Mode mode) { ...@@ -721,7 +743,7 @@ Variable* Scope::NonLocal(Handle<String> name, Variable::Mode mode) {
// another variable that is introduced dynamically via an 'eval' call // another variable that is introduced dynamically via an 'eval' call
// or a 'with' statement). // or a 'with' statement).
Variable* Scope::LookupRecursive(Handle<String> name, Variable* Scope::LookupRecursive(Handle<String> name,
bool inner_lookup, bool from_inner_function,
Variable** invalidated_local) { Variable** invalidated_local) {
// If we find a variable, but the current scope calls 'eval', the found // If we find a variable, but the current scope calls 'eval', the found
// variable may not be the correct one (the 'eval' may introduce a // variable may not be the correct one (the 'eval' may introduce a
...@@ -737,7 +759,7 @@ Variable* Scope::LookupRecursive(Handle<String> name, ...@@ -737,7 +759,7 @@ Variable* Scope::LookupRecursive(Handle<String> name,
// (Even if there is an 'eval' in this scope which introduces the // (Even if there is an 'eval' in this scope which introduces the
// same variable again, the resulting variable remains the same. // same variable again, the resulting variable remains the same.
// Note that enclosing 'with' statements are handled at the call site.) // Note that enclosing 'with' statements are handled at the call site.)
if (!inner_lookup) if (!from_inner_function)
return var; return var;
} else { } else {
...@@ -753,7 +775,10 @@ Variable* Scope::LookupRecursive(Handle<String> name, ...@@ -753,7 +775,10 @@ Variable* Scope::LookupRecursive(Handle<String> name,
var = function_; var = function_;
} else if (outer_scope_ != NULL) { } else if (outer_scope_ != NULL) {
var = outer_scope_->LookupRecursive(name, true, invalidated_local); var = outer_scope_->LookupRecursive(
name,
is_function_scope() || from_inner_function,
invalidated_local);
// We may have found a variable in an outer scope. However, if // We may have found a variable in an outer scope. However, if
// the current scope is inside a 'with', the actual variable may // the current scope is inside a 'with', the actual variable may
// be a property introduced via the 'with' statement. Then, the // be a property introduced via the 'with' statement. Then, the
...@@ -770,8 +795,8 @@ Variable* Scope::LookupRecursive(Handle<String> name, ...@@ -770,8 +795,8 @@ Variable* Scope::LookupRecursive(Handle<String> name,
ASSERT(var != NULL); ASSERT(var != NULL);
// If this is a lookup from an inner scope, mark the variable. // If this is a lookup from an inner scope, mark the variable.
if (inner_lookup) { if (from_inner_function) {
var->MarkAsAccessedFromInnerScope(); var->MarkAsAccessedFromInnerFunctionScope();
} }
// If the variable we have found is just a guess, invalidate the // If the variable we have found is just a guess, invalidate the
...@@ -922,11 +947,12 @@ bool Scope::MustAllocate(Variable* var) { ...@@ -922,11 +947,12 @@ bool Scope::MustAllocate(Variable* var) {
// via an eval() call. This is only possible if the variable has a // via an eval() call. This is only possible if the variable has a
// visible name. // visible name.
if ((var->is_this() || var->name()->length() > 0) && if ((var->is_this() || var->name()->length() > 0) &&
(var->is_accessed_from_inner_scope() || (var->is_accessed_from_inner_function_scope() ||
scope_calls_eval_ || scope_calls_eval_ ||
inner_scope_calls_eval_ || inner_scope_calls_eval_ ||
scope_contains_with_ || scope_contains_with_ ||
is_catch_scope())) { is_catch_scope() ||
is_block_scope())) {
var->set_is_used(true); var->set_is_used(true);
} }
// Global variables do not need to be allocated. // Global variables do not need to be allocated.
...@@ -943,8 +969,8 @@ bool Scope::MustAllocateInContext(Variable* var) { ...@@ -943,8 +969,8 @@ bool Scope::MustAllocateInContext(Variable* var) {
// Exceptions: temporary variables are never allocated in a context; // Exceptions: temporary variables are never allocated in a context;
// catch-bound variables are always allocated in a context. // catch-bound variables are always allocated in a context.
if (var->mode() == Variable::TEMPORARY) return false; if (var->mode() == Variable::TEMPORARY) return false;
if (is_catch_scope()) return true; if (is_catch_scope() || is_block_scope()) return true;
return var->is_accessed_from_inner_scope() || return var->is_accessed_from_inner_function_scope() ||
scope_calls_eval_ || scope_calls_eval_ ||
inner_scope_calls_eval_ || inner_scope_calls_eval_ ||
scope_contains_with_ || scope_contains_with_ ||
...@@ -1010,7 +1036,7 @@ void Scope::AllocateParameterLocals() { ...@@ -1010,7 +1036,7 @@ void Scope::AllocateParameterLocals() {
if (uses_nonstrict_arguments) { if (uses_nonstrict_arguments) {
// Give the parameter a use from an inner scope, to force allocation // Give the parameter a use from an inner scope, to force allocation
// to the context. // to the context.
var->MarkAsAccessedFromInnerScope(); var->MarkAsAccessedFromInnerFunctionScope();
} }
if (MustAllocate(var)) { if (MustAllocate(var)) {
......
...@@ -93,7 +93,8 @@ class Scope: public ZoneObject { ...@@ -93,7 +93,8 @@ class Scope: public ZoneObject {
EVAL_SCOPE, // The top-level scope for an eval source. EVAL_SCOPE, // The top-level scope for an eval source.
FUNCTION_SCOPE, // The top-level scope for a function. FUNCTION_SCOPE, // The top-level scope for a function.
GLOBAL_SCOPE, // The top-level scope for a program or a top-level eval. GLOBAL_SCOPE, // The top-level scope for a program or a top-level eval.
CATCH_SCOPE // The scope introduced by catch. CATCH_SCOPE, // The scope introduced by catch.
BLOCK_SCOPE // The scope introduced by a new block.
}; };
Scope(Scope* outer_scope, Type type); Scope(Scope* outer_scope, Type type);
...@@ -204,6 +205,7 @@ class Scope: public ZoneObject { ...@@ -204,6 +205,7 @@ class Scope: public ZoneObject {
bool is_function_scope() const { return type_ == FUNCTION_SCOPE; } bool is_function_scope() const { return type_ == FUNCTION_SCOPE; }
bool is_global_scope() const { return type_ == GLOBAL_SCOPE; } bool is_global_scope() const { return type_ == GLOBAL_SCOPE; }
bool is_catch_scope() const { return type_ == CATCH_SCOPE; } bool is_catch_scope() const { return type_ == CATCH_SCOPE; }
bool is_block_scope() const { return type_ == BLOCK_SCOPE; }
bool is_strict_mode() const { return strict_mode_; } bool is_strict_mode() const { return strict_mode_; }
bool is_strict_mode_eval_scope() const { bool is_strict_mode_eval_scope() const {
return is_eval_scope() && is_strict_mode(); return is_eval_scope() && is_strict_mode();
...@@ -294,6 +296,8 @@ class Scope: public ZoneObject { ...@@ -294,6 +296,8 @@ class Scope: public ZoneObject {
// where var declarations will be hoisted to in the implementation. // where var declarations will be hoisted to in the implementation.
Scope* DeclarationScope(); Scope* DeclarationScope();
Handle<SerializedScopeInfo> GetSerializedScopeInfo();
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Strict mode support. // Strict mode support.
bool IsDeclared(Handle<String> name) { bool IsDeclared(Handle<String> name) {
...@@ -397,7 +401,7 @@ class Scope: public ZoneObject { ...@@ -397,7 +401,7 @@ class Scope: public ZoneObject {
// Variable resolution. // Variable resolution.
Variable* LookupRecursive(Handle<String> name, Variable* LookupRecursive(Handle<String> name,
bool inner_lookup, bool from_inner_function,
Variable** invalidated_local); Variable** invalidated_local);
void ResolveVariable(Scope* global_scope, void ResolveVariable(Scope* global_scope,
Handle<Context> context, Handle<Context> context,
...@@ -425,8 +429,8 @@ class Scope: public ZoneObject { ...@@ -425,8 +429,8 @@ class Scope: public ZoneObject {
void AllocateVariablesRecursively(); void AllocateVariablesRecursively();
private: private:
// Construct a function scope based on the scope info. // Construct a function or block scope based on the scope info.
Scope(Scope* inner_scope, Handle<SerializedScopeInfo> scope_info); Scope(Scope* inner_scope, Type type, Handle<SerializedScopeInfo> scope_info);
// Construct a catch scope with a binding for the name. // Construct a catch scope with a binding for the name.
Scope(Scope* inner_scope, Handle<String> catch_variable_name); Scope(Scope* inner_scope, Handle<String> catch_variable_name);
......
...@@ -544,6 +544,7 @@ class PartialSerializer : public Serializer { ...@@ -544,6 +544,7 @@ class PartialSerializer : public Serializer {
ASSERT(!o->IsScript()); ASSERT(!o->IsScript());
return o->IsString() || o->IsSharedFunctionInfo() || return o->IsString() || o->IsSharedFunctionInfo() ||
o->IsHeapNumber() || o->IsCode() || o->IsHeapNumber() || o->IsCode() ||
o->IsSerializedScopeInfo() ||
o->map() == HEAP->fixed_cow_array_map(); o->map() == HEAP->fixed_cow_array_map();
} }
......
...@@ -92,7 +92,7 @@ Variable::Variable(Scope* scope, ...@@ -92,7 +92,7 @@ Variable::Variable(Scope* scope,
local_if_not_shadowed_(NULL), local_if_not_shadowed_(NULL),
rewrite_(NULL), rewrite_(NULL),
is_valid_LHS_(is_valid_LHS), is_valid_LHS_(is_valid_LHS),
is_accessed_from_inner_scope_(false), is_accessed_from_inner_function_scope_(false),
is_used_(false) { is_used_(false) {
// names must be canonicalized for fast equality checks // names must be canonicalized for fast equality checks
ASSERT(name->IsSymbol()); ASSERT(name->IsSymbol());
......
...@@ -95,11 +95,12 @@ class Variable: public ZoneObject { ...@@ -95,11 +95,12 @@ class Variable: public ZoneObject {
Handle<String> name() const { return name_; } Handle<String> name() const { return name_; }
Mode mode() const { return mode_; } Mode mode() const { return mode_; }
bool is_accessed_from_inner_scope() const { bool is_accessed_from_inner_function_scope() const {
return is_accessed_from_inner_scope_; return is_accessed_from_inner_function_scope_;
} }
void MarkAsAccessedFromInnerScope() { void MarkAsAccessedFromInnerFunctionScope() {
is_accessed_from_inner_scope_ = true; ASSERT(mode_ != TEMPORARY);
is_accessed_from_inner_function_scope_ = true;
} }
bool is_used() { return is_used_; } bool is_used() { return is_used_; }
void set_is_used(bool flag) { is_used_ = flag; } void set_is_used(bool flag) { is_used_ = flag; }
...@@ -156,7 +157,7 @@ class Variable: public ZoneObject { ...@@ -156,7 +157,7 @@ class Variable: public ZoneObject {
bool is_valid_LHS_; bool is_valid_LHS_;
// Usage info. // Usage info.
bool is_accessed_from_inner_scope_; // set by variable resolver bool is_accessed_from_inner_function_scope_; // set by variable resolver
bool is_used_; bool is_used_;
}; };
......
...@@ -146,6 +146,7 @@ var knownProblems = { ...@@ -146,6 +146,7 @@ var knownProblems = {
"NewStrictArgumentsFast": true, "NewStrictArgumentsFast": true,
"PushWithContext": true, "PushWithContext": true,
"PushCatchContext": true, "PushCatchContext": true,
"PushBlockContext": true,
"LazyCompile": true, "LazyCompile": true,
"LazyRecompile": true, "LazyRecompile": true,
"NotifyDeoptimized": true, "NotifyDeoptimized": true,
......
// Copyright 2011 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.
// Flags: --allow-natives-syntax
// Test deserialization of block contexts during lazy compilation
// of closures.
function f() {
var g;
{
// TODO(keuchel): introduce let
var x = 0;
g = function () {
x = x + 1;
return x;
}
}
return g;
}
var o = f();
assertEquals(1, o());
assertEquals(2, o());
assertEquals(3, o());
%OptimizeFunctionOnNextCall(o);
assertEquals(4, o());
// Copyright 2011 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.
// Flags: --allow-natives-syntax --harmony-block-scoping
// Test functionality of block scopes.
// Hoisting of var declarations.
function f1() {
{
var x = 1;
var y;
}
assertEquals(1, x)
assertEquals(undefined, y)
}
f1();
// Dynamic lookup through block scopes.
function f2(one) {
var x = one + 1;
// TODO(keuchel): introduce let
// let y = one + 2;
if (one == 1) {
// Parameter
assertEquals(1, eval('one'));
// Function local var variable
assertEquals(2, eval('x'));
// Function local let variable
// TODO(keuchel): introduce let
// assertEquals(3, eval('y'));
}
}
f2(1);
This diff is collapsed.
// Copyright 2011 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.
// Flags: --expose-debug-as debug
// Test debug evaluation for functions without local context, but with
// nested catch contexts.
function f() {
{ // Line 1.
var i = 1; // Line 2. // TODO(keuchel): introduce let
try { // Line 3.
throw 'stuff'; // Line 4.
} catch (e) { // Line 5.
x = 2; // Line 6.
}
}
};
// Get the Debug object exposed from the debug context global object.
Debug = debug.Debug
// Set breakpoint on line 6.
var bp = Debug.setBreakPoint(f, 6);
function listener(event, exec_state, event_data, data) {
if (event == Debug.DebugEvent.Break) {
result = exec_state.frame().evaluate("i").value();
}
};
// Add the debug event listener.
Debug.setListener(listener);
result = -1;
f();
assertEquals(1, result);
// Clear breakpoint.
Debug.clearBreakPoint(bp);
// Get rid of the debug event listener.
Debug.setListener(null);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment