Remove variable rewrites and the unneccesary Slot class.

R=fschneider@chromium.org
BUG=
TEST=

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9162 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 296612c1
This diff is collapsed.
......@@ -198,14 +198,14 @@ bool LCodeGen::GeneratePrologue() {
// Copy any necessary parameters into the context.
int num_parameters = scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
Slot* slot = scope()->parameter(i)->AsSlot();
if (slot != NULL && slot->type() == Slot::CONTEXT) {
Variable* var = scope()->parameter(i);
if (var->IsContextSlot()) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ ldr(r0, MemOperand(fp, parameter_offset));
// Store it in the context.
__ mov(r1, Operand(Context::SlotOffset(slot->index())));
__ mov(r1, Operand(Context::SlotOffset(var->index())));
__ str(r0, MemOperand(cp, r1));
// Update the write barrier. This clobbers all involved
// registers, so we have to use two more registers to avoid
......
......@@ -39,8 +39,6 @@ namespace internal {
// ----------------------------------------------------------------------------
// All the Accept member functions for each syntax tree node type.
void Slot::Accept(AstVisitor* v) { v->VisitSlot(this); }
#define DECL_ACCEPT(type) \
void type::Accept(AstVisitor* v) { v->Visit##type(this); }
AST_NODE_LIST(DECL_ACCEPT)
......@@ -396,12 +394,6 @@ bool TargetCollector::IsInlineable() const {
}
bool Slot::IsInlineable() const {
UNREACHABLE();
return false;
}
bool ForInStatement::IsInlineable() const {
return false;
}
......@@ -542,7 +534,7 @@ bool Conditional::IsInlineable() const {
bool VariableProxy::IsInlineable() const {
return var()->is_global() || var()->IsStackAllocated();
return var()->IsUnallocated() || var()->IsStackAllocated();
}
......
......@@ -165,7 +165,6 @@ class AstNode: public ZoneObject {
virtual BreakableStatement* AsBreakableStatement() { return NULL; }
virtual IterationStatement* AsIterationStatement() { return NULL; }
virtual MaterializedLiteral* AsMaterializedLiteral() { return NULL; }
virtual Slot* AsSlot() { return NULL; }
// True if the node is simple enough for us to inline calls containing it.
virtual bool IsInlineable() const = 0;
......@@ -1112,9 +1111,6 @@ class VariableProxy: public Expression {
DECLARE_NODE_TYPE(VariableProxy)
// Type testing & conversion
Variable* AsVariable() { return (this == NULL) ? NULL : var_; }
virtual bool IsValidLeftHandSide() {
return var_ == NULL ? true : var_->IsValidLeftHandSide();
}
......@@ -1131,10 +1127,7 @@ class VariableProxy: public Expression {
return !is_this() && name().is_identical_to(n);
}
bool IsArguments() {
Variable* variable = AsVariable();
return (variable == NULL) ? false : variable->is_arguments();
}
bool IsArguments() { return var_ != NULL && var_->is_arguments(); }
Handle<String> name() const { return name_; }
Variable* var() const { return var_; }
......@@ -1165,55 +1158,6 @@ class VariableProxy: public Expression {
};
class Slot: public Expression {
public:
enum Type {
// A slot in the parameter section on the stack. index() is
// the parameter index, counting left-to-right, starting at 0.
PARAMETER,
// A slot in the local section on the stack. index() is
// the variable index in the stack frame, starting at 0.
LOCAL,
// An indexed slot in a heap context. index() is the
// variable index in the context object on the heap,
// starting at 0. var()->scope() is the corresponding
// scope.
CONTEXT,
// A named slot in a heap context. var()->name() is the
// variable name in the context object on the heap,
// with lookup starting at the current context. index()
// is invalid.
LOOKUP
};
Slot(Isolate* isolate, Variable* var, Type type, int index)
: Expression(isolate), var_(var), type_(type), index_(index) {
ASSERT(var != NULL);
}
virtual void Accept(AstVisitor* v);
virtual Slot* AsSlot() { return this; }
bool IsStackAllocated() { return type_ == PARAMETER || type_ == LOCAL; }
// Accessors
Variable* var() const { return var_; }
Type type() const { return type_; }
int index() const { return index_; }
bool is_arguments() const { return var_->is_arguments(); }
virtual bool IsInlineable() const;
private:
Variable* var_;
Type type_;
int index_;
};
class Property: public Expression {
public:
Property(Isolate* isolate,
......@@ -2194,9 +2138,6 @@ class AstVisitor BASE_EMBEDDED {
void SetStackOverflow() { stack_overflow_ = true; }
void ClearStackOverflow() { stack_overflow_ = false; }
// Nodes not appearing in the AST, including slots.
virtual void VisitSlot(Slot* node) { UNREACHABLE(); }
// Individual AST nodes.
#define DEF_VISIT(type) \
virtual void Visit##type(type* node) = 0;
......
......@@ -190,9 +190,9 @@ void BreakableStatementChecker::VisitArrayLiteral(ArrayLiteral* expr) {
void BreakableStatementChecker::VisitAssignment(Assignment* expr) {
// If assigning to a property (including a global property) the assignment is
// breakable.
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
VariableProxy* proxy = expr->target()->AsVariableProxy();
Property* prop = expr->target()->AsProperty();
if (prop != NULL || (var != NULL && var->is_global())) {
if (prop != NULL || (proxy != NULL && proxy->var()->IsUnallocated())) {
is_breakable_ = true;
return;
}
......@@ -395,26 +395,6 @@ void FullCodeGenerator::RecordStackCheck(int ast_id) {
}
int FullCodeGenerator::SlotOffset(Slot* slot) {
ASSERT(slot != NULL);
// Offset is negative because higher indexes are at lower addresses.
int offset = -slot->index() * kPointerSize;
// Adjust by a (parameter or local) base offset.
switch (slot->type()) {
case Slot::PARAMETER:
offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
break;
case Slot::LOCAL:
offset += JavaScriptFrameConstants::kLocal0Offset;
break;
case Slot::CONTEXT:
case Slot::LOOKUP:
UNREACHABLE();
}
return offset;
}
bool FullCodeGenerator::ShouldInlineSmiCase(Token::Value op) {
// Inline smi case inside loops, but not division and modulo which
// are too complicated and take up too much space.
......@@ -529,34 +509,21 @@ void FullCodeGenerator::DoTest(const TestContext* context) {
void FullCodeGenerator::VisitDeclarations(
ZoneList<Declaration*>* declarations) {
int length = declarations->length();
int globals = 0;
int global_count = 0;
for (int i = 0; i < length; i++) {
Declaration* decl = declarations->at(i);
Variable* var = decl->proxy()->var();
Slot* slot = var->AsSlot();
// If it was not possible to allocate the variable at compile
// time, we need to "declare" it at runtime to make sure it
// actually exists in the local context.
if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
VisitDeclaration(decl);
} else {
// Count global variables and functions for later processing
globals++;
}
EmitDeclaration(decl->proxy(), decl->mode(), decl->fun(), &global_count);
}
// Compute array of global variable and function declarations.
// Do nothing in case of no declared global functions or variables.
if (globals > 0) {
// Batch declare global functions and variables.
if (global_count > 0) {
Handle<FixedArray> array =
isolate()->factory()->NewFixedArray(2 * globals, TENURED);
isolate()->factory()->NewFixedArray(2 * global_count, TENURED);
for (int j = 0, i = 0; i < length; i++) {
Declaration* decl = declarations->at(i);
Variable* var = decl->proxy()->var();
Slot* slot = var->AsSlot();
if ((slot == NULL || slot->type() != Slot::LOOKUP) && var->is_global()) {
if (var->IsUnallocated()) {
array->set(j++, *(var->name()));
if (decl->fun() == NULL) {
if (var->mode() == Variable::CONST) {
......@@ -578,7 +545,7 @@ void FullCodeGenerator::VisitDeclarations(
}
}
// Invoke the platform-dependent code generator to do the actual
// declaration the global variables and functions.
// declaration the global functions and variables.
DeclareGlobals(array);
}
}
......
......@@ -304,10 +304,6 @@ class FullCodeGenerator: public AstVisitor {
// with a GC-safe value.
void ClearAccumulator();
// Compute the frame pointer relative offset for a given local or
// parameter slot.
int SlotOffset(Slot* slot);
// Determine whether or not to inline the smi case for the given
// operation.
bool ShouldInlineSmiCase(Token::Value op);
......@@ -337,13 +333,29 @@ class FullCodeGenerator: public AstVisitor {
Label* fall_through);
#endif // V8_TARGET_ARCH_MIPS
void Move(Slot* dst, Register source, Register scratch1, Register scratch2);
void Move(Register dst, Slot* source);
// Return an operand used to read/write to a known (ie, non-LOOKUP) slot.
// May emit code to traverse the context chain, destroying the scratch
// register.
MemOperand EmitSlotSearch(Slot* slot, Register scratch);
// Load the value of a known (PARAMETER, LOCAL, or CONTEXT) variable into
// a register. Emits a context chain walk if if necessary (so does
// SetVar) so avoid calling both on the same variable.
void GetVar(Register destination, Variable* var);
// Assign to a known (PARAMETER, LOCAL, or CONTEXT) variable. If it's in
// the context, the write barrier will be emitted and source, scratch0,
// scratch1 will be clobbered. Emits a context chain walk if if necessary
// (so does GetVar) so avoid calling both on the same variable.
void SetVar(Variable* var,
Register source,
Register scratch0,
Register scratch1);
// An operand used to read/write a stack-allocated (PARAMETER or LOCAL)
// variable. Writing does not need the write barrier.
MemOperand StackOperand(Variable* var);
// An operand used to read/write a known (PARAMETER, LOCAL, or CONTEXT)
// variable. May emit code to traverse the context chain, loading the
// found context into the scratch register. Writing to this operand will
// need the write barrier if location is CONTEXT.
MemOperand VarOperand(Variable* var, Register scratch);
// Forward the bailout responsibility for the given expression to
// the next child visited (which must be in a test context).
......@@ -421,7 +433,8 @@ class FullCodeGenerator: public AstVisitor {
// declaration. Functions have an initial value.
void EmitDeclaration(VariableProxy* proxy,
Variable::Mode mode,
FunctionLiteral* function);
FunctionLiteral* function,
int* global_count);
// Platform-specific code for checking the stack limit at the back edge of
// a loop.
......@@ -452,11 +465,11 @@ class FullCodeGenerator: public AstVisitor {
#undef EMIT_INLINE_RUNTIME_CALL
// Platform-specific code for loading variables.
void EmitLoadGlobalSlotCheckExtensions(Slot* slot,
void EmitLoadGlobalCheckExtensions(Variable* var,
TypeofState typeof_state,
Label* slow);
MemOperand ContextSlotOperandCheckExtensions(Slot* slot, Label* slow);
void EmitDynamicLoadFromSlotFastCase(Slot* slot,
MemOperand ContextSlotOperandCheckExtensions(Variable* var, Label* slow);
void EmitDynamicLookupFastCase(Variable* var,
TypeofState typeof_state,
Label* slow,
Label* done);
......@@ -636,11 +649,11 @@ class FullCodeGenerator: public AstVisitor {
// this expression context.
virtual void Plug(bool flag) const = 0;
// Emit code to convert a pure value (in a register, slot, as a literal,
// or on top of the stack) into the result expected according to this
// expression context.
// Emit code to convert a pure value (in a register, known variable
// location, as a literal, or on top of the stack) into the result
// expected according to this expression context.
virtual void Plug(Register reg) const = 0;
virtual void Plug(Slot* slot) const = 0;
virtual void Plug(Variable* var) const = 0;
virtual void Plug(Handle<Object> lit) const = 0;
virtual void Plug(Heap::RootListIndex index) const = 0;
virtual void PlugTOS() const = 0;
......@@ -698,7 +711,7 @@ class FullCodeGenerator: public AstVisitor {
virtual void Plug(bool flag) const;
virtual void Plug(Register reg) const;
virtual void Plug(Label* materialize_true, Label* materialize_false) const;
virtual void Plug(Slot* slot) const;
virtual void Plug(Variable* var) const;
virtual void Plug(Handle<Object> lit) const;
virtual void Plug(Heap::RootListIndex) const;
virtual void PlugTOS() const;
......@@ -721,7 +734,7 @@ class FullCodeGenerator: public AstVisitor {
virtual void Plug(bool flag) const;
virtual void Plug(Register reg) const;
virtual void Plug(Label* materialize_true, Label* materialize_false) const;
virtual void Plug(Slot* slot) const;
virtual void Plug(Variable* var) const;
virtual void Plug(Handle<Object> lit) const;
virtual void Plug(Heap::RootListIndex) const;
virtual void PlugTOS() const;
......@@ -762,7 +775,7 @@ class FullCodeGenerator: public AstVisitor {
virtual void Plug(bool flag) const;
virtual void Plug(Register reg) const;
virtual void Plug(Label* materialize_true, Label* materialize_false) const;
virtual void Plug(Slot* slot) const;
virtual void Plug(Variable* var) const;
virtual void Plug(Handle<Object> lit) const;
virtual void Plug(Heap::RootListIndex) const;
virtual void PlugTOS() const;
......@@ -792,7 +805,7 @@ class FullCodeGenerator: public AstVisitor {
virtual void Plug(bool flag) const;
virtual void Plug(Register reg) const;
virtual void Plug(Label* materialize_true, Label* materialize_false) const;
virtual void Plug(Slot* slot) const;
virtual void Plug(Variable* var) const;
virtual void Plug(Handle<Object> lit) const;
virtual void Plug(Heap::RootListIndex) const;
virtual void PlugTOS() const;
......
This diff is collapsed.
......@@ -455,12 +455,11 @@ class HEnvironment: public ZoneObject {
// by 1 (receiver is parameter index -1 but environment index 0).
// Stack-allocated local indices are shifted by the number of parameters.
int IndexFor(Variable* variable) const {
Slot* slot = variable->AsSlot();
ASSERT(slot != NULL && slot->IsStackAllocated());
int shift = (slot->type() == Slot::PARAMETER)
ASSERT(variable->IsStackAllocated());
int shift = variable->IsParameter()
? 1
: parameter_count_ + specials_count_;
return slot->index() + shift;
return variable->index() + shift;
}
Handle<JSFunction> closure_;
......
This diff is collapsed.
......@@ -194,14 +194,14 @@ bool LCodeGen::GeneratePrologue() {
// Copy parameters into context if necessary.
int num_parameters = scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
Slot* slot = scope()->parameter(i)->AsSlot();
if (slot != NULL && slot->type() == Slot::CONTEXT) {
Variable* var = scope()->parameter(i);
if (var->IsContextSlot()) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ mov(eax, Operand(ebp, parameter_offset));
// Store it in the context.
int context_offset = Context::SlotOffset(slot->index());
int context_offset = Context::SlotOffset(var->index());
__ mov(Operand(esi, context_offset), eax);
// Update the write barrier. This clobbers all involved
// registers, so we have to use a third register to avoid
......
......@@ -860,8 +860,7 @@ class FunctionInfoListener {
int j = 0;
for (int i = 0; i < list.length(); i++) {
Variable* var1 = list[i];
Slot* slot = var1->AsSlot();
if (slot != NULL && slot->type() == Slot::CONTEXT) {
if (var1->IsContextSlot()) {
if (j != i) {
list[j] = var1;
}
......@@ -873,7 +872,7 @@ class FunctionInfoListener {
for (int k = 1; k < j; k++) {
int l = k;
for (int m = k + 1; m < j; m++) {
if (list[l]->AsSlot()->index() > list[m]->AsSlot()->index()) {
if (list[l]->index() > list[m]->index()) {
l = m;
}
}
......@@ -887,7 +886,7 @@ class FunctionInfoListener {
SetElementNonStrict(
scope_info_list,
scope_info_length,
Handle<Smi>(Smi::FromInt(list[i]->AsSlot()->index())));
Handle<Smi>(Smi::FromInt(list[i]->index())));
scope_info_length++;
}
SetElementNonStrict(scope_info_list,
......
......@@ -200,7 +200,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
// Copy any necessary parameters into the context.
int num_parameters = info->scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
Slot* slot = scope()->parameter(i)->AsSlot();
Slot* slot = scope()->parameter(i)->rewrite();
if (slot != NULL && slot->type() == Slot::CONTEXT) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
......@@ -252,7 +252,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
ArgumentsAccessStub stub(type);
__ CallStub(&stub);
Move(arguments->AsSlot(), v0, a1, a2);
Move(arguments->rewrite(), v0, a1, a2);
}
if (FLAG_trace) {
......@@ -633,6 +633,7 @@ MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
return ContextOperand(scratch, slot->index());
}
case Slot::LOOKUP:
case Slot::GLOBAL:
UNREACHABLE();
}
UNREACHABLE();
......@@ -697,7 +698,7 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
Comment cmnt(masm_, "[ Declaration");
Variable* variable = proxy->var();
ASSERT(variable != NULL); // Must have been resolved.
Slot* slot = variable->AsSlot();
Slot* slot = variable->rewrite();
ASSERT(slot != NULL);
switch (slot->type()) {
case Slot::PARAMETER:
......@@ -772,6 +773,9 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
__ CallRuntime(Runtime::kDeclareContextSlot, 4);
break;
}
case Slot::GLOBAL:
UNREACHABLE();
}
}
......@@ -1192,7 +1196,7 @@ void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow);
__ Branch(done);
} else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot();
Slot* potential_slot = slot->var()->local_if_not_shadowed()->rewrite();
Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
if (potential_slot != NULL) {
// Generate fast case for locals that rewrite to slots.
......@@ -1218,7 +1222,7 @@ void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
// variables. Then load the argument from the arguments
// object using keyed load.
__ lw(a1,
ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(),
ContextSlotOperandCheckExtensions(obj_proxy->var()->rewrite(),
slow));
__ li(a0, Operand(key_literal->handle()));
Handle<Code> ic =
......@@ -1239,7 +1243,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
// Three cases: non-this global variables, lookup slots, and all other
// types of slots.
Slot* slot = var->AsSlot();
Slot* slot = var->rewrite();
ASSERT((var->is_global() && !var->is_this()) == (slot == NULL));
if (slot == NULL) {
......@@ -1836,7 +1840,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
void FullCodeGenerator::EmitVariableAssignment(Variable* var,
Token::Value op) {
ASSERT(var != NULL);
ASSERT(var->is_global() || var->AsSlot() != NULL);
ASSERT(var->is_global() || var->rewrite() != NULL);
if (var->is_global()) {
ASSERT(!var->is_this());
......@@ -1856,7 +1860,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
// scope. However, unlike var initializers, const initializers are able
// to drill a hole to that function context, even from inside a 'with'
// context. We thus bypass the normal static scope lookup.
Slot* slot = var->AsSlot();
Slot* slot = var->rewrite();
Label skip;
switch (slot->type()) {
case Slot::PARAMETER:
......@@ -1877,6 +1881,8 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
__ Push(cp, a0); // Context and name.
__ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
break;
case Slot::GLOBAL:
UNREACHABLE();
}
__ bind(&skip);
} else if (var->mode() == Variable::LET && op != Token::INIT_LET) {
......@@ -1933,7 +1939,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
} else if (var->mode() != Variable::CONST) {
// Perform the assignment for non-const variables. Const assignments
// are simply skipped.
Slot* slot = var->AsSlot();
Slot* slot = var->rewrite();
switch (slot->type()) {
case Slot::PARAMETER:
case Slot::LOCAL:
......@@ -1960,6 +1966,9 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
__ Push(cp, a1, a0); // Context, name, strict mode.
__ CallRuntime(Runtime::kStoreContextSlot, 4);
break;
case Slot::GLOBAL:
UNREACHABLE();
}
}
}
......@@ -2227,9 +2236,9 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// in generated code. If we succeed, there is no need to perform a
// context lookup in the runtime system.
Label done;
if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) {
if (var->rewrite() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) {
Label slow;
EmitLoadGlobalSlotCheckExtensions(var->AsSlot(),
EmitLoadGlobalSlotCheckExtensions(var->rewrite(),
NOT_INSIDE_TYPEOF,
&slow);
// Push the function and resolve eval.
......@@ -2267,15 +2276,15 @@ void FullCodeGenerator::VisitCall(Call* expr) {
__ lw(a0, GlobalObjectOperand());
__ push(a0);
EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
} else if (var != NULL && var->AsSlot() != NULL &&
var->AsSlot()->type() == Slot::LOOKUP) {
} else if (var != NULL && var->rewrite() != NULL &&
var->rewrite()->type() == Slot::LOOKUP) {
// Call to a lookup slot (dynamically introduced variable).
Label slow, done;
{ PreservePositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
EmitDynamicLoadFromSlotFastCase(var->rewrite(),
NOT_INSIDE_TYPEOF,
&slow,
&done);
......@@ -3680,8 +3689,8 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
__ Push(a2, a1, a0);
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
context()->Plug(v0);
} else if (var->AsSlot() != NULL &&
var->AsSlot()->type() != Slot::LOOKUP) {
} else if (var->rewrite() != NULL &&
var->rewrite()->type() != Slot::LOOKUP) {
// Result of deleting non-global, non-dynamic variables is false.
// The subexpression does not have side effects.
context()->Plug(false);
......@@ -3971,13 +3980,13 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
PrepareForBailout(expr, TOS_REG);
context()->Plug(v0);
} else if (proxy != NULL &&
proxy->var()->AsSlot() != NULL &&
proxy->var()->AsSlot()->type() == Slot::LOOKUP) {
proxy->var()->rewrite() != NULL &&
proxy->var()->rewrite()->type() == Slot::LOOKUP) {
Label done, slow;
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
Slot* slot = proxy->var()->AsSlot();
Slot* slot = proxy->var()->rewrite();
EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
__ bind(&slow);
......
......@@ -284,28 +284,6 @@ void PrettyPrinter::VisitArrayLiteral(ArrayLiteral* node) {
}
void PrettyPrinter::VisitSlot(Slot* node) {
switch (node->type()) {
case Slot::PARAMETER:
Print("parameter[%d]", node->index());
break;
case Slot::LOCAL:
Print("local[%d]", node->index());
break;
case Slot::CONTEXT:
Print("context[%d]", node->index());
break;
case Slot::LOOKUP:
Print("lookup[");
PrintLiteral(node->var()->name(), false);
Print("]");
break;
default:
UNREACHABLE();
}
}
void PrettyPrinter::VisitVariableProxy(VariableProxy* node) {
PrintLiteral(node->name(), false);
}
......@@ -751,7 +729,7 @@ void AstPrinter::VisitDeclaration(Declaration* node) {
if (node->fun() == NULL) {
// var or const declarations
PrintLiteralWithModeIndented(Variable::Mode2String(node->mode()),
node->proxy()->AsVariable(),
node->proxy()->var(),
node->proxy()->name());
} else {
// function declarations
......@@ -959,19 +937,26 @@ void AstPrinter::VisitArrayLiteral(ArrayLiteral* node) {
}
void AstPrinter::VisitSlot(Slot* node) {
PrintIndented("SLOT ");
PrettyPrinter::VisitSlot(node);
Print("\n");
}
void AstPrinter::VisitVariableProxy(VariableProxy* node) {
PrintLiteralWithModeIndented("VAR PROXY", node->AsVariable(), node->name());
Variable* var = node->var();
if (var != NULL && var->rewrite() != NULL) {
IndentedScope indent(this);
Visit(var->rewrite());
PrintLiteralWithModeIndented("VAR PROXY", var, node->name());
{ IndentedScope indent(this);
switch (var->location()) {
case Variable::UNALLOCATED:
break;
case Variable::PARAMETER:
Print("parameter[%d]", var->index());
break;
case Variable::LOCAL:
Print("local[%d]", var->index());
break;
case Variable::CONTEXT:
Print("context[%d]", var->index());
break;
case Variable::LOOKUP:
Print("lookup");
break;
}
}
}
......@@ -1287,39 +1272,32 @@ void JsonAstBuilder::VisitConditional(Conditional* expr) {
}
void JsonAstBuilder::VisitSlot(Slot* expr) {
TagScope tag(this, "Slot");
void JsonAstBuilder::VisitVariableProxy(VariableProxy* expr) {
TagScope tag(this, "Variable");
{
AttributesScope attributes(this);
switch (expr->type()) {
case Slot::PARAMETER:
AddAttribute("type", "PARAMETER");
Variable* var = expr->var();
AddAttribute("name", var->name());
switch (var->location()) {
case Variable::UNALLOCATED:
AddAttribute("location", "UNALLOCATED");
break;
case Slot::LOCAL:
AddAttribute("type", "LOCAL");
case Variable::PARAMETER:
AddAttribute("location", "PARAMETER");
AddAttribute("index", var->index());
break;
case Slot::CONTEXT:
AddAttribute("type", "CONTEXT");
case Variable::LOCAL:
AddAttribute("location", "LOCAL");
AddAttribute("index", var->index());
break;
case Slot::LOOKUP:
AddAttribute("type", "LOOKUP");
case Variable::CONTEXT:
AddAttribute("location", "CONTEXT");
AddAttribute("index", var->index());
break;
case Variable::LOOKUP:
AddAttribute("location", "LOOKUP");
break;
}
AddAttribute("index", expr->index());
}
}
void JsonAstBuilder::VisitVariableProxy(VariableProxy* expr) {
if (expr->var()->rewrite() == NULL) {
TagScope tag(this, "VariableProxy");
{
AttributesScope attributes(this);
AddAttribute("name", expr->name());
AddAttribute("mode", Variable::Mode2String(expr->var()->mode()));
}
} else {
Visit(expr->var()->rewrite());
}
}
......
......@@ -52,7 +52,6 @@ class PrettyPrinter: public AstVisitor {
// Print a node to stdout.
static void PrintOut(AstNode* node);
virtual void VisitSlot(Slot* node);
// Individual nodes
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT)
......@@ -87,7 +86,6 @@ class AstPrinter: public PrettyPrinter {
const char* PrintProgram(FunctionLiteral* program);
// Individual nodes
virtual void VisitSlot(Slot* node);
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
......@@ -163,7 +161,6 @@ class JsonAstBuilder: public PrettyPrinter {
void AddAttribute(const char* name, bool value);
// AST node visit functions.
virtual void VisitSlot(Slot* node);
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
......
......@@ -39,12 +39,8 @@ namespace internal {
static int CompareLocal(Variable* const* v, Variable* const* w) {
Slot* s = (*v)->AsSlot();
Slot* t = (*w)->AsSlot();
// We may have rewritten parameters (that are in the arguments object)
// and which may have a NULL slot... - find a better solution...
int x = (s != NULL ? s->index() : 0);
int y = (t != NULL ? t->index() : 0);
int x = (*v)->index();
int y = (*w)->index();
// Consider sorting them according to type as well?
return x - y;
}
......@@ -86,38 +82,35 @@ ScopeInfo<Allocator>::ScopeInfo(Scope* scope)
for (int i = 0; i < locals.length(); i++) {
Variable* var = locals[i];
if (var->is_used()) {
Slot* slot = var->AsSlot();
if (slot != NULL) {
switch (slot->type()) {
case Slot::PARAMETER:
// explicitly added to parameters_ above - ignore
switch (var->location()) {
case Variable::UNALLOCATED:
case Variable::PARAMETER:
break;
case Slot::LOCAL:
ASSERT(stack_slots_.length() == slot->index());
case Variable::LOCAL:
ASSERT(stack_slots_.length() == var->index());
stack_slots_.Add(var->name());
break;
case Slot::CONTEXT:
case Variable::CONTEXT:
heap_locals.Add(var);
break;
case Slot::LOOKUP:
// This is currently not used.
case Variable::LOOKUP:
// We don't expect lookup variables in the locals list.
UNREACHABLE();
break;
}
}
}
}
// Add heap locals.
if (scope->num_heap_slots() > 0) {
// Add user-defined slots.
for (int i = 0; i < heap_locals.length(); i++) {
ASSERT(heap_locals[i]->AsSlot()->index() - Context::MIN_CONTEXT_SLOTS ==
ASSERT(heap_locals[i]->index() - Context::MIN_CONTEXT_SLOTS ==
context_slots_.length());
ASSERT(heap_locals[i]->AsSlot()->index() - Context::MIN_CONTEXT_SLOTS ==
ASSERT(heap_locals[i]->index() - Context::MIN_CONTEXT_SLOTS ==
context_modes_.length());
context_slots_.Add(heap_locals[i]->name());
context_modes_.Add(heap_locals[i]->mode());
......@@ -140,9 +133,9 @@ ScopeInfo<Allocator>::ScopeInfo(Scope* scope)
// list - instead it must be handled separately in the
// Contexts::Lookup() function. Thus record an empty symbol here so we
// get the correct number of context slots.
ASSERT(proxy->var()->AsSlot()->index() - Context::MIN_CONTEXT_SLOTS ==
ASSERT(proxy->var()->index() - Context::MIN_CONTEXT_SLOTS ==
context_slots_.length());
ASSERT(proxy->var()->AsSlot()->index() - Context::MIN_CONTEXT_SLOTS ==
ASSERT(proxy->var()->index() - Context::MIN_CONTEXT_SLOTS ==
context_modes_.length());
context_slots_.Add(FACTORY->empty_symbol());
context_modes_.Add(Variable::INTERNAL);
......
......@@ -31,7 +31,6 @@
#include "bootstrapper.h"
#include "compiler.h"
#include "prettyprinter.h"
#include "scopeinfo.h"
#include "allocation-inl.h"
......@@ -314,7 +313,7 @@ void Scope::Initialize(bool inside_with) {
Variable::VAR,
false,
Variable::THIS);
var->set_rewrite(NewSlot(var, Slot::PARAMETER, -1));
var->AllocateTo(Variable::PARAMETER, -1);
receiver_ = var;
}
......@@ -389,7 +388,7 @@ Variable* Scope::LocalLookup(Handle<String> name) {
Variable* var =
variables_.Declare(this, name, mode, true, Variable::NORMAL);
var->set_rewrite(NewSlot(var, Slot::CONTEXT, index));
var->AllocateTo(Variable::CONTEXT, index);
return var;
}
......@@ -410,7 +409,7 @@ Variable* Scope::DeclareFunctionVar(Handle<String> name) {
Variable* function_var =
new Variable(this, name, Variable::CONST, true, Variable::NORMAL);
function_ = new(isolate_->zone()) VariableProxy(isolate_, function_var);
return function_->var();
return function_var;
}
......@@ -438,7 +437,8 @@ Variable* Scope::DeclareLocal(Handle<String> name, Variable::Mode mode) {
Variable* Scope::DeclareGlobal(Handle<String> name) {
ASSERT(is_global_scope());
return variables_.Declare(this, name, Variable::DYNAMIC_GLOBAL, true,
return variables_.Declare(this, name, Variable::DYNAMIC_GLOBAL,
true,
Variable::NORMAL);
}
......@@ -471,8 +471,11 @@ void Scope::RemoveUnresolved(VariableProxy* var) {
Variable* Scope::NewTemporary(Handle<String> name) {
ASSERT(!already_resolved());
Variable* var =
new Variable(this, name, Variable::TEMPORARY, true, Variable::NORMAL);
Variable* var = new Variable(this,
name,
Variable::TEMPORARY,
true,
Variable::NORMAL);
temps_.Add(var);
return var;
}
......@@ -665,17 +668,35 @@ static void PrintName(Handle<String> name) {
}
static void PrintVar(PrettyPrinter* printer, int indent, Variable* var) {
if (var->is_used() || var->rewrite() != NULL) {
static void PrintLocation(Variable* var) {
switch (var->location()) {
case Variable::UNALLOCATED:
break;
case Variable::PARAMETER:
PrintF("parameter[%d]", var->index());
break;
case Variable::LOCAL:
PrintF("local[%d]", var->index());
break;
case Variable::CONTEXT:
PrintF("context[%d]", var->index());
break;
case Variable::LOOKUP:
PrintF("lookup");
break;
}
}
static void PrintVar(int indent, Variable* var) {
if (var->is_used() || !var->IsUnallocated()) {
Indent(indent, Variable::Mode2String(var->mode()));
PrintF(" ");
PrintName(var->name());
PrintF("; // ");
if (var->rewrite() != NULL) {
PrintF("%s, ", printer->Print(var->rewrite()));
if (var->is_accessed_from_inner_function_scope()) PrintF(", ");
}
PrintLocation(var);
if (var->is_accessed_from_inner_function_scope()) {
if (!var->IsUnallocated()) PrintF(", ");
PrintF("inner scope access");
}
PrintF("\n");
......@@ -683,10 +704,10 @@ static void PrintVar(PrettyPrinter* printer, int indent, Variable* var) {
}
static void PrintMap(PrettyPrinter* printer, int indent, VariableMap* map) {
static void PrintMap(int indent, VariableMap* map) {
for (VariableMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) {
Variable* var = reinterpret_cast<Variable*>(p->value);
PrintVar(printer, indent, var);
PrintVar(indent, var);
}
}
......@@ -743,25 +764,24 @@ void Scope::Print(int n) {
PrintF("%d heap slots\n", num_heap_slots_); }
// Print locals.
PrettyPrinter printer;
Indent(n1, "// function var\n");
if (function_ != NULL) {
PrintVar(&printer, n1, function_->var());
PrintVar(n1, function_->var());
}
Indent(n1, "// temporary vars\n");
for (int i = 0; i < temps_.length(); i++) {
PrintVar(&printer, n1, temps_[i]);
PrintVar(n1, temps_[i]);
}
Indent(n1, "// local vars\n");
PrintMap(&printer, n1, &variables_);
PrintMap(n1, &variables_);
Indent(n1, "// dynamic vars\n");
if (dynamics_ != NULL) {
PrintMap(&printer, n1, dynamics_->GetMap(Variable::DYNAMIC));
PrintMap(&printer, n1, dynamics_->GetMap(Variable::DYNAMIC_LOCAL));
PrintMap(&printer, n1, dynamics_->GetMap(Variable::DYNAMIC_GLOBAL));
PrintMap(n1, dynamics_->GetMap(Variable::DYNAMIC));
PrintMap(n1, dynamics_->GetMap(Variable::DYNAMIC_LOCAL));
PrintMap(n1, dynamics_->GetMap(Variable::DYNAMIC_GLOBAL));
}
// Print inner scopes (disable by providing negative n).
......@@ -785,7 +805,7 @@ Variable* Scope::NonLocal(Handle<String> name, Variable::Mode mode) {
// Declare a new non-local.
var = map->Declare(NULL, name, mode, true, Variable::NORMAL);
// Allocate it by giving it a dynamic lookup.
var->set_rewrite(NewSlot(var, Slot::LOOKUP, -1));
var->AllocateTo(Variable::LOOKUP, -1);
}
return var;
}
......@@ -1045,12 +1065,12 @@ bool Scope::HasArgumentsParameter() {
void Scope::AllocateStackSlot(Variable* var) {
var->set_rewrite(NewSlot(var, Slot::LOCAL, num_stack_slots_++));
var->AllocateTo(Variable::LOCAL, num_stack_slots_++);
}
void Scope::AllocateHeapSlot(Variable* var) {
var->set_rewrite(NewSlot(var, Slot::CONTEXT, num_heap_slots_++));
var->AllocateTo(Variable::CONTEXT, num_heap_slots_++);
}
......@@ -1096,14 +1116,14 @@ void Scope::AllocateParameterLocals() {
if (MustAllocate(var)) {
if (MustAllocateInContext(var)) {
ASSERT(var->rewrite() == NULL || var->IsContextSlot());
if (var->rewrite() == NULL) {
ASSERT(var->IsUnallocated() || var->IsContextSlot());
if (var->IsUnallocated()) {
AllocateHeapSlot(var);
}
} else {
ASSERT(var->rewrite() == NULL || var->IsParameter());
if (var->rewrite() == NULL) {
var->set_rewrite(NewSlot(var, Slot::PARAMETER, i));
ASSERT(var->IsUnallocated() || var->IsParameter());
if (var->IsUnallocated()) {
var->AllocateTo(Variable::PARAMETER, i);
}
}
}
......@@ -1113,11 +1133,9 @@ void Scope::AllocateParameterLocals() {
void Scope::AllocateNonParameterLocal(Variable* var) {
ASSERT(var->scope() == this);
ASSERT(var->rewrite() == NULL ||
!var->IsVariable(isolate_->factory()->result_symbol()) ||
var->AsSlot() == NULL ||
var->AsSlot()->type() != Slot::LOCAL);
if (var->rewrite() == NULL && MustAllocate(var)) {
ASSERT(!var->IsVariable(isolate_->factory()->result_symbol()) ||
!var->IsStackLocal());
if (var->IsUnallocated() && MustAllocate(var)) {
if (MustAllocateInContext(var)) {
AllocateHeapSlot(var);
} else {
......
......@@ -444,10 +444,6 @@ class Scope: public ZoneObject {
// Construct a catch scope with a binding for the name.
Scope(Scope* inner_scope, Handle<String> catch_variable_name);
inline Slot* NewSlot(Variable* var, Slot::Type type, int index) {
return new(isolate_->zone()) Slot(isolate_, var, type, index);
}
void AddInnerScope(Scope* inner_scope) {
if (inner_scope != NULL) {
inner_scopes_.Add(inner_scope);
......
......@@ -53,34 +53,6 @@ const char* Variable::Mode2String(Mode mode) {
}
Property* Variable::AsProperty() const {
return rewrite_ == NULL ? NULL : rewrite_->AsProperty();
}
Slot* Variable::AsSlot() const { return rewrite_; }
bool Variable::IsStackAllocated() const {
return rewrite_ != NULL && rewrite_->IsStackAllocated();
}
bool Variable::IsParameter() const {
return rewrite_ != NULL && rewrite_->type() == Slot::PARAMETER;
}
bool Variable::IsStackLocal() const {
return rewrite_ != NULL && rewrite_->type() == Slot::LOCAL;
}
bool Variable::IsContextSlot() const {
return rewrite_ != NULL && rewrite_->type() == Slot::CONTEXT;
}
Variable::Variable(Scope* scope,
Handle<String> name,
Mode mode,
......@@ -90,8 +62,9 @@ Variable::Variable(Scope* scope,
name_(name),
mode_(mode),
kind_(kind),
location_(UNALLOCATED),
index_(-1),
local_if_not_shadowed_(NULL),
rewrite_(NULL),
is_valid_LHS_(is_valid_LHS),
is_accessed_from_inner_function_scope_(false),
is_used_(false) {
......
......@@ -74,6 +74,33 @@ class Variable: public ZoneObject {
ARGUMENTS
};
enum Location {
// Before and during variable allocation, a variable whose location is
// not yet determined. After allocation, a variable looked up as a
// property on the global object (and possibly absent). name() is the
// variable name, index() is invalid.
UNALLOCATED,
// A slot in the parameter section on the stack. index() is the
// parameter index, counting left-to-right. The reciever is index -1;
// the first parameter is index 0.
PARAMETER,
// A slot in the local section on the stack. index() is the variable
// index in the stack frame, starting at 0.
LOCAL,
// An indexed slot in a heap context. index() is the variable index in
// the context object on the heap, starting at 0. scope() is the
// corresponding scope.
CONTEXT,
// A named slot in a heap context. name() is the variable name in the
// context object on the heap, with lookup starting at the current
// context. index() is invalid.
LOOKUP
};
Variable(Scope* scope,
Handle<String> name,
Mode mode,
......@@ -83,10 +110,6 @@ class Variable: public ZoneObject {
// Printing support
static const char* Mode2String(Mode mode);
// Type testing & conversion. Global variables are not slots.
Property* AsProperty() const;
Slot* AsSlot() const;
bool IsValidLeftHandSide() { return is_valid_LHS_; }
// The source code for an eval() call may refer to a variable that is
......@@ -111,10 +134,12 @@ class Variable: public ZoneObject {
return !is_this() && name().is_identical_to(n);
}
bool IsStackAllocated() const;
bool IsParameter() const; // Includes 'this'.
bool IsStackLocal() const;
bool IsContextSlot() const;
bool IsUnallocated() const { return location_ == UNALLOCATED; }
bool IsParameter() const { return location_ == PARAMETER; }
bool IsStackLocal() const { return location_ == LOCAL; }
bool IsStackAllocated() const { return IsParameter() || IsStackLocal(); }
bool IsContextSlot() const { return location_ == CONTEXT; }
bool IsLookupSlot() const { return location_ == LOOKUP; }
bool is_dynamic() const {
return (mode_ == DYNAMIC ||
......@@ -141,20 +166,24 @@ class Variable: public ZoneObject {
local_if_not_shadowed_ = local;
}
Slot* rewrite() const { return rewrite_; }
void set_rewrite(Slot* slot) { rewrite_ = slot; }
Location location() const { return location_; }
int index() const { return index_; }
void AllocateTo(Location location, int index) {
location_ = location;
index_ = index;
}
private:
Scope* scope_;
Handle<String> name_;
Mode mode_;
Kind kind_;
Location location_;
int index_;
Variable* local_if_not_shadowed_;
// Code generation.
Slot* rewrite_;
// Valid as a LHS? (const and this are not valid LHS, for example)
bool is_valid_LHS_;
......
This diff is collapsed.
......@@ -207,14 +207,14 @@ bool LCodeGen::GeneratePrologue() {
// Copy any necessary parameters into the context.
int num_parameters = scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
Slot* slot = scope()->parameter(i)->AsSlot();
if (slot != NULL && slot->type() == Slot::CONTEXT) {
Variable* var = scope()->parameter(i);
if (var->IsContextSlot()) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ movq(rax, Operand(rbp, parameter_offset));
// Store it in the context.
int context_offset = Context::SlotOffset(slot->index());
int context_offset = Context::SlotOffset(var->index());
__ movq(Operand(rsi, context_offset), rax);
// Update the write barrier. This clobbers all involved
// registers, so we have use a third register to avoid
......
// Copyright 2010 the V8 project authors. All rights reserved.
// 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:
......@@ -66,6 +66,7 @@ assertEquals(2, ((delete 0) || 2) + 1);
assertEquals(3, (function (x) { return ((delete x) || 2) + 1; })(0));
// 'this' at toplevel is different from all other global variables---not
// deletable.
// 'this' is not a Reference so delete returns true (see section 11.4.1,
// step 2 of ES 5.1).
assertEquals(true, delete this);
assertEquals(true, (function () { return delete this; })());
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