* src/scopes.h (ForceContextAllocation, has_forced_context_allocation):
New interface to force context allocation for an entire function's
scope.
* src/scopes.cc: Unless a new scope is a function scope, if its outer
scope has forced context allocation, it should also force context
allocation.
(MustAllocateInContext): Return true if the scope as a whole has
forced context allocation.
(CollectStackAndContextLocals): Allow temporaries to be
context-allocated.
* src/parser.cc (ParseFunctionLiteral): Force context allocation for
generator scopes.
* src/v8globals.h (VariableMode): Update comment on TEMPORARY.
* src/arm/full-codegen-arm.cc (Generate):
* src/ia32/full-codegen-ia32.cc (Generate):
* src/x64/full-codegen-x64.cc (Generate): Assert that generators have no
stack slots.
* test/mjsunit/harmony/generators-instantiation.js: New test.
BUG=v8:2355
TEST=mjsunit/harmony/generators-instantiation
Review URL: https://codereview.chromium.org/
13408005
Patch from Andy Wingo <wingo@igalia.com>.
git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14152
ce2b1a6d-e550-0410-aec6-
3dcde31c8c00
// the frame (that is done below).
FrameScope frame_scope(masm_, StackFrame::MANUAL);
- int locals_count = info->scope()->num_stack_slots();
-
info->set_prologue_offset(masm_->pc_offset());
{
PredictableCodeSizeScope predictible_code_size_scope(
}
{ Comment cmnt(masm_, "[ Allocate locals");
+ int locals_count = info->scope()->num_stack_slots();
+ // Generators allocate locals, if any, in context slots.
+ ASSERT(!info->function()->is_generator() || locals_count == 0);
for (int i = 0; i < locals_count; i++) {
__ push(ip);
}
{ Comment cmnt(masm_, "[ Allocate locals");
int locals_count = info->scope()->num_stack_slots();
+ // Generators allocate locals, if any, in context slots.
+ ASSERT(!info->function()->is_generator() || locals_count == 0);
if (locals_count == 1) {
__ push(Immediate(isolate()->factory()->undefined_value()));
} else if (locals_count > 1) {
// Parse function body.
{ FunctionState function_state(this, scope, is_generator, isolate());
top_scope_->SetScopeName(function_name);
+ // For generators, allocating variables in contexts is currently a win
+ // because it minimizes the work needed to suspend and resume an activation.
+ if (is_generator) top_scope_->ForceContextAllocation();
// FormalParameterList ::
// '(' (Identifier)*[','] ')'
outer_scope_calls_non_strict_eval_ = false;
inner_scope_calls_eval_ = false;
force_eager_compilation_ = false;
+ force_context_allocation_ = (outer_scope != NULL && !is_function_scope())
+ ? outer_scope->has_forced_context_allocation() : false;
num_var_or_const_ = 0;
num_stack_slots_ = 0;
num_heap_slots_ = 0;
}
}
- // Collect temporaries which are always allocated on the stack.
+ // Collect temporaries which are always allocated on the stack, unless the
+ // context as a whole has forced context allocation.
for (int i = 0; i < temps_.length(); i++) {
Variable* var = temps_[i];
if (var->is_used()) {
- ASSERT(var->IsStackLocal());
- stack_locals->Add(var, zone());
+ if (var->IsContextSlot()) {
+ ASSERT(has_forced_context_allocation());
+ context_locals->Add(var, zone());
+ } else {
+ ASSERT(var->IsStackLocal());
+ stack_locals->Add(var, zone());
+ }
}
}
// an eval() call or a runtime with lookup), it must be allocated in the
// context.
//
- // Exceptions: temporary variables are never allocated in a context;
- // catch-bound variables are always allocated in a context.
+ // Exceptions: If the scope as a whole has forced context allocation, all
+ // variables will have context allocation, even temporaries. Otherwise
+ // temporary variables are always stack-allocated. Catch-bound variables are
+ // always context-allocated.
+ if (has_forced_context_allocation()) return true;
if (var->mode() == TEMPORARY) return false;
if (var->mode() == INTERNAL) return true;
if (is_catch_scope() || is_block_scope() || is_module_scope()) return true;
end_position_ = statement_pos;
}
+ // In some cases we want to force context allocation for a whole scope.
+ void ForceContextAllocation() {
+ ASSERT(!already_resolved());
+ force_context_allocation_ = true;
+ }
+ bool has_forced_context_allocation() const {
+ return force_context_allocation_;
+ }
+
// ---------------------------------------------------------------------------
// Predicates.
bool outer_scope_calls_non_strict_eval_;
bool inner_scope_calls_eval_;
bool force_eager_compilation_;
+ bool force_context_allocation_;
// True if it doesn't need scope resolution (e.g., if the scope was
// constructed based on a serialized scope info or a catch context).
INTERNAL, // like VAR, but not user-visible (may or may not
// be in a context)
- TEMPORARY, // temporary variables (not user-visible), never
- // in a context
+ TEMPORARY, // temporary variables (not user-visible), stack-allocated
+ // unless the scope as a whole has forced context allocation
DYNAMIC, // always require dynamic lookup (we don't know
// the declaration)
{ Comment cmnt(masm_, "[ Allocate locals");
int locals_count = info->scope()->num_stack_slots();
+ // Generators allocate locals, if any, in context slots.
+ ASSERT(!info->function()->is_generator() || locals_count == 0);
if (locals_count == 1) {
__ PushRoot(Heap::kUndefinedValueRootIndex);
} else if (locals_count > 1) {
--- /dev/null
+// Copyright 2013 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: --harmony-generators --harmony-scoping
+
+// Test instantations of generators.
+
+// Generators shouldn't allocate stack slots. This test will abort in debug
+// mode if generators have stack slots.
+function TestContextAllocation() {
+ function* g1(a, b, c) { yield 1; return [a, b, c]; }
+ function* g2() { yield 1; return arguments; }
+ function* g3() { yield 1; return this; }
+ function* g4() { var x = 10; yield 1; return x; }
+ // Temporary variable context allocation
+ function* g5(l) { "use strict"; yield 1; for (let x in l) { yield x; } }
+
+ g1();
+ g2();
+ g3();
+ g4();
+ g5(["foo"]);
+}
+
+TestContextAllocation();