Commit 62f3e48d authored by whesse@chromium.org's avatar whesse@chromium.org

Refactor Reference so that SetValue and GetValue pop the reference state.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3720 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 80d71c64
// Copyright 2006-2009 the V8 project authors. All rights reserved. // Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
...@@ -605,14 +605,19 @@ void CodeGenerator::LoadTypeofExpression(Expression* expr) { ...@@ -605,14 +605,19 @@ void CodeGenerator::LoadTypeofExpression(Expression* expr) {
} }
Reference::Reference(CodeGenerator* cgen, Expression* expression) Reference::Reference(CodeGenerator* cgen,
: cgen_(cgen), expression_(expression), type_(ILLEGAL) { Expression* expression,
bool persist_after_get)
: cgen_(cgen),
expression_(expression),
type_(ILLEGAL),
persist_after_get_(persist_after_get) {
cgen->LoadReference(this); cgen->LoadReference(this);
} }
Reference::~Reference() { Reference::~Reference() {
cgen_->UnloadReference(this); ASSERT(is_unloaded() || is_illegal());
} }
...@@ -661,6 +666,7 @@ void CodeGenerator::UnloadReference(Reference* ref) { ...@@ -661,6 +666,7 @@ void CodeGenerator::UnloadReference(Reference* ref) {
frame_->Drop(size); frame_->Drop(size);
frame_->EmitPush(r0); frame_->EmitPush(r0);
} }
ref->set_unloaded();
} }
...@@ -1244,8 +1250,6 @@ void CodeGenerator::VisitDeclaration(Declaration* node) { ...@@ -1244,8 +1250,6 @@ void CodeGenerator::VisitDeclaration(Declaration* node) {
Reference target(this, node->proxy()); Reference target(this, node->proxy());
LoadAndSpill(val); LoadAndSpill(val);
target.SetValue(NOT_CONST_INIT); target.SetValue(NOT_CONST_INIT);
// The reference is removed from the stack (preserving TOS) when
// it goes out of scope.
} }
// Get rid of the assigned value (declarations are statements). // Get rid of the assigned value (declarations are statements).
frame_->Drop(); frame_->Drop();
...@@ -1932,25 +1936,17 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) { ...@@ -1932,25 +1936,17 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
if (each.size() > 0) { if (each.size() > 0) {
__ ldr(r0, frame_->ElementAt(each.size())); __ ldr(r0, frame_->ElementAt(each.size()));
frame_->EmitPush(r0); frame_->EmitPush(r0);
} each.SetValue(NOT_CONST_INIT);
// If the reference was to a slot we rely on the convenient property frame_->Drop(2);
// that it doesn't matter whether a value (eg, r3 pushed above) is } else {
// right on top of or right underneath a zero-sized reference. // If the reference was to a slot we rely on the convenient property
each.SetValue(NOT_CONST_INIT); // that it doesn't matter whether a value (eg, r3 pushed above) is
if (each.size() > 0) { // right on top of or right underneath a zero-sized reference.
// It's safe to pop the value lying on top of the reference before each.SetValue(NOT_CONST_INIT);
// unloading the reference itself (which preserves the top of stack, frame_->Drop();
// ie, now the topmost value of the non-zero sized reference), since
// we will discard the top of stack after unloading the reference
// anyway.
frame_->EmitPop(r0);
} }
} }
} }
// Discard the i'th entry pushed above or else the remainder of the
// reference, whichever is currently on top of the stack.
frame_->Drop();
// Body. // Body.
CheckStack(); // TODO(1222600): ignore if body contains calls. CheckStack(); // TODO(1222600): ignore if body contains calls.
VisitAndSpill(node->body()); VisitAndSpill(node->body());
...@@ -2844,7 +2840,7 @@ void CodeGenerator::VisitAssignment(Assignment* node) { ...@@ -2844,7 +2840,7 @@ void CodeGenerator::VisitAssignment(Assignment* node) {
VirtualFrame::SpilledScope spilled_scope; VirtualFrame::SpilledScope spilled_scope;
Comment cmnt(masm_, "[ Assignment"); Comment cmnt(masm_, "[ Assignment");
{ Reference target(this, node->target()); { Reference target(this, node->target(), node->is_compound());
if (target.is_illegal()) { if (target.is_illegal()) {
// Fool the virtual frame into thinking that we left the assignment's // Fool the virtual frame into thinking that we left the assignment's
// value on the frame. // value on the frame.
...@@ -2859,8 +2855,7 @@ void CodeGenerator::VisitAssignment(Assignment* node) { ...@@ -2859,8 +2855,7 @@ void CodeGenerator::VisitAssignment(Assignment* node) {
node->op() == Token::INIT_CONST) { node->op() == Token::INIT_CONST) {
LoadAndSpill(node->value()); LoadAndSpill(node->value());
} else { } else { // Assignment is a compound assignment.
// +=, *= and similar binary assignments.
// Get the old value of the lhs. // Get the old value of the lhs.
target.GetValueAndSpill(); target.GetValueAndSpill();
Literal* literal = node->value()->AsLiteral(); Literal* literal = node->value()->AsLiteral();
...@@ -2881,13 +2876,12 @@ void CodeGenerator::VisitAssignment(Assignment* node) { ...@@ -2881,13 +2876,12 @@ void CodeGenerator::VisitAssignment(Assignment* node) {
frame_->EmitPush(r0); frame_->EmitPush(r0);
} }
} }
Variable* var = node->target()->AsVariableProxy()->AsVariable(); Variable* var = node->target()->AsVariableProxy()->AsVariable();
if (var != NULL && if (var != NULL &&
(var->mode() == Variable::CONST) && (var->mode() == Variable::CONST) &&
node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) { node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) {
// Assignment ignored - leave the value on the stack. // Assignment ignored - leave the value on the stack.
UnloadReference(&target);
} else { } else {
CodeForSourcePosition(node->position()); CodeForSourcePosition(node->position());
if (node->op() == Token::INIT_CONST) { if (node->op() == Token::INIT_CONST) {
...@@ -3097,16 +3091,20 @@ void CodeGenerator::VisitCall(Call* node) { ...@@ -3097,16 +3091,20 @@ void CodeGenerator::VisitCall(Call* node) {
// JavaScript example: 'array[index](1, 2, 3)' // JavaScript example: 'array[index](1, 2, 3)'
// ------------------------------------------- // -------------------------------------------
// Load the function to call from the property through a reference. LoadAndSpill(property->obj());
Reference ref(this, property); LoadAndSpill(property->key());
ref.GetValueAndSpill(); // receiver EmitKeyedLoad(false);
frame_->Drop(); // key
// Pass receiver to called function. // Put the function below the receiver.
if (property->is_synthetic()) { if (property->is_synthetic()) {
// Use the global receiver.
frame_->Drop();
frame_->EmitPush(r0);
LoadGlobalReceiver(r0); LoadGlobalReceiver(r0);
} else { } else {
__ ldr(r0, frame_->ElementAt(ref.size())); frame_->EmitPop(r1); // receiver
frame_->EmitPush(r0); frame_->EmitPush(r0); // function
frame_->EmitPush(r1); // receiver
} }
// Call the function. // Call the function.
...@@ -3807,7 +3805,9 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) { ...@@ -3807,7 +3805,9 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
frame_->EmitPush(r0); frame_->EmitPush(r0);
} }
{ Reference target(this, node->expression()); // A constant reference is not saved to, so a constant reference is not a
// compound assignment reference.
{ Reference target(this, node->expression(), !is_const);
if (target.is_illegal()) { if (target.is_illegal()) {
// Spoof the virtual frame to have the expected height (one higher // Spoof the virtual frame to have the expected height (one higher
// than on entry). // than on entry).
...@@ -4268,6 +4268,16 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) { ...@@ -4268,6 +4268,16 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
} }
void CodeGenerator::EmitKeyedLoad(bool is_global) {
Comment cmnt(masm_, "[ Load from keyed Property");
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
RelocInfo::Mode rmode = is_global
? RelocInfo::CODE_TARGET_CONTEXT
: RelocInfo::CODE_TARGET;
frame_->CallCodeObject(ic, rmode, 0);
}
#ifdef DEBUG #ifdef DEBUG
bool CodeGenerator::HasValidEntryRegisters() { return true; } bool CodeGenerator::HasValidEntryRegisters() { return true; }
#endif #endif
...@@ -4334,23 +4344,21 @@ void Reference::GetValue() { ...@@ -4334,23 +4344,21 @@ void Reference::GetValue() {
case KEYED: { case KEYED: {
// TODO(181): Implement inlined version of array indexing once // TODO(181): Implement inlined version of array indexing once
// loop nesting is properly tracked on ARM. // loop nesting is properly tracked on ARM.
VirtualFrame* frame = cgen_->frame();
Comment cmnt(masm, "[ Load from keyed Property");
ASSERT(property != NULL); ASSERT(property != NULL);
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
Variable* var = expression_->AsVariableProxy()->AsVariable(); Variable* var = expression_->AsVariableProxy()->AsVariable();
ASSERT(var == NULL || var->is_global()); ASSERT(var == NULL || var->is_global());
RelocInfo::Mode rmode = (var == NULL) cgen_->EmitKeyedLoad(var != NULL);
? RelocInfo::CODE_TARGET cgen_->frame()->EmitPush(r0);
: RelocInfo::CODE_TARGET_CONTEXT;
frame->CallCodeObject(ic, rmode, 0);
frame->EmitPush(r0);
break; break;
} }
default: default:
UNREACHABLE(); UNREACHABLE();
} }
if (!persist_after_get_) {
cgen_->UnloadReference(this);
}
} }
...@@ -4412,6 +4420,7 @@ void Reference::SetValue(InitState init_state) { ...@@ -4412,6 +4420,7 @@ void Reference::SetValue(InitState init_state) {
default: default:
UNREACHABLE(); UNREACHABLE();
} }
cgen_->UnloadReference(this);
} }
......
// Copyright 2006-2008 the V8 project authors. All rights reserved. // Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
...@@ -43,57 +43,69 @@ enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF }; ...@@ -43,57 +43,69 @@ enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// Reference support // Reference support
// A reference is a C++ stack-allocated object that keeps an ECMA // A reference is a C++ stack-allocated object that puts a
// reference on the execution stack while in scope. For variables // reference on the virtual frame. The reference may be consumed
// the reference is empty, indicating that it isn't necessary to // by GetValue, TakeValue, SetValue, and Codegen::UnloadReference.
// store state on the stack for keeping track of references to those. // When the lifetime (scope) of a valid reference ends, it must have
// For properties, we keep either one (named) or two (indexed) values // been consumed, and be in state UNLOADED.
// on the execution stack to represent the reference.
class Reference BASE_EMBEDDED { class Reference BASE_EMBEDDED {
public: public:
// The values of the types is important, see size(). // The values of the types is important, see size().
enum Type { ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 }; enum Type { UNLOADED = -2, ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 };
Reference(CodeGenerator* cgen, Expression* expression); Reference(CodeGenerator* cgen,
Expression* expression,
bool persist_after_get = false);
~Reference(); ~Reference();
Expression* expression() const { return expression_; } Expression* expression() const { return expression_; }
Type type() const { return type_; } Type type() const { return type_; }
void set_type(Type value) { void set_type(Type value) {
ASSERT(type_ == ILLEGAL); ASSERT_EQ(ILLEGAL, type_);
type_ = value; type_ = value;
} }
void set_unloaded() {
ASSERT_NE(ILLEGAL, type_);
ASSERT_NE(UNLOADED, type_);
type_ = UNLOADED;
}
// The size the reference takes up on the stack. // The size the reference takes up on the stack.
int size() const { return (type_ == ILLEGAL) ? 0 : type_; } int size() const {
return (type_ < SLOT) ? 0 : type_;
}
bool is_illegal() const { return type_ == ILLEGAL; } bool is_illegal() const { return type_ == ILLEGAL; }
bool is_slot() const { return type_ == SLOT; } bool is_slot() const { return type_ == SLOT; }
bool is_property() const { return type_ == NAMED || type_ == KEYED; } bool is_property() const { return type_ == NAMED || type_ == KEYED; }
bool is_unloaded() const { return type_ == UNLOADED; }
// Return the name. Only valid for named property references. // Return the name. Only valid for named property references.
Handle<String> GetName(); Handle<String> GetName();
// Generate code to push the value of the reference on top of the // Generate code to push the value of the reference on top of the
// expression stack. The reference is expected to be already on top of // expression stack. The reference is expected to be already on top of
// the expression stack, and it is left in place with its value above it. // the expression stack, and it is consumed by the call unless the
// reference is for a compound assignment.
// If the reference is not consumed, it is left in place under its value.
void GetValue(); void GetValue();
// Generate code to push the value of a reference on top of the expression // Generate code to pop a reference, push the value of the reference,
// stack and then spill the stack frame. This function is used temporarily // and then spill the stack frame.
// while the code generator is being transformed.
inline void GetValueAndSpill(); inline void GetValueAndSpill();
// Generate code to store the value on top of the expression stack in the // Generate code to store the value on top of the expression stack in the
// reference. The reference is expected to be immediately below the value // reference. The reference is expected to be immediately below the value
// on the expression stack. The stored value is left in place (with the // on the expression stack. The value is stored in the location specified
// reference intact below it) to support chained assignments. // by the reference, and is left on top of the stack, after the reference
// is popped from beneath it (unloaded).
void SetValue(InitState init_state); void SetValue(InitState init_state);
private: private:
CodeGenerator* cgen_; CodeGenerator* cgen_;
Expression* expression_; Expression* expression_;
Type type_; Type type_;
// Keep the reference on the stack after get, so it can be used by set later.
bool persist_after_get_;
}; };
...@@ -274,6 +286,9 @@ class CodeGenerator: public AstVisitor { ...@@ -274,6 +286,9 @@ class CodeGenerator: public AstVisitor {
void LoadFromSlot(Slot* slot, TypeofState typeof_state); void LoadFromSlot(Slot* slot, TypeofState typeof_state);
// Store the value on top of the stack to a slot. // Store the value on top of the stack to a slot.
void StoreToSlot(Slot* slot, InitState init_state); void StoreToSlot(Slot* slot, InitState init_state);
// Load a keyed property, leaving it in r0. The receiver and key are
// passed on the stack, and remain there.
void EmitKeyedLoad(bool is_global);
void LoadFromGlobalSlotCheckExtensions(Slot* slot, void LoadFromGlobalSlotCheckExtensions(Slot* slot,
TypeofState typeof_state, TypeofState typeof_state,
......
This diff is collapsed.
// Copyright 2006-2008 the V8 project authors. All rights reserved. // Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
...@@ -43,57 +43,70 @@ enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF }; ...@@ -43,57 +43,70 @@ enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// Reference support // Reference support
// A reference is a C++ stack-allocated object that keeps an ECMA // A reference is a C++ stack-allocated object that puts a
// reference on the execution stack while in scope. For variables // reference on the virtual frame. The reference may be consumed
// the reference is empty, indicating that it isn't necessary to // by GetValue, TakeValue, SetValue, and Codegen::UnloadReference.
// store state on the stack for keeping track of references to those. // When the lifetime (scope) of a valid reference ends, it must have
// For properties, we keep either one (named) or two (indexed) values // been consumed, and be in state UNLOADED.
// on the execution stack to represent the reference.
class Reference BASE_EMBEDDED { class Reference BASE_EMBEDDED {
public: public:
// The values of the types is important, see size(). // The values of the types is important, see size().
enum Type { ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 }; enum Type { UNLOADED = -2, ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 };
Reference(CodeGenerator* cgen, Expression* expression); Reference(CodeGenerator* cgen,
Expression* expression,
bool persist_after_get = false);
~Reference(); ~Reference();
Expression* expression() const { return expression_; } Expression* expression() const { return expression_; }
Type type() const { return type_; } Type type() const { return type_; }
void set_type(Type value) { void set_type(Type value) {
ASSERT(type_ == ILLEGAL); ASSERT_EQ(ILLEGAL, type_);
type_ = value; type_ = value;
} }
void set_unloaded() {
ASSERT_NE(ILLEGAL, type_);
ASSERT_NE(UNLOADED, type_);
type_ = UNLOADED;
}
// The size the reference takes up on the stack. // The size the reference takes up on the stack.
int size() const { return (type_ == ILLEGAL) ? 0 : type_; } int size() const {
return (type_ < SLOT) ? 0 : type_;
}
bool is_illegal() const { return type_ == ILLEGAL; } bool is_illegal() const { return type_ == ILLEGAL; }
bool is_slot() const { return type_ == SLOT; } bool is_slot() const { return type_ == SLOT; }
bool is_property() const { return type_ == NAMED || type_ == KEYED; } bool is_property() const { return type_ == NAMED || type_ == KEYED; }
bool is_unloaded() const { return type_ == UNLOADED; }
// Return the name. Only valid for named property references. // Return the name. Only valid for named property references.
Handle<String> GetName(); Handle<String> GetName();
// Generate code to push the value of the reference on top of the // Generate code to push the value of the reference on top of the
// expression stack. The reference is expected to be already on top of // expression stack. The reference is expected to be already on top of
// the expression stack, and it is left in place with its value above it. // the expression stack, and it is consumed by the call unless the
// reference is for a compound assignment.
// If the reference is not consumed, it is left in place under its value.
void GetValue(); void GetValue();
// Like GetValue except that the slot is expected to be written to before // Like GetValue except that the slot is expected to be written to before
// being read from again. Thae value of the reference may be invalidated, // being read from again. The value of the reference may be invalidated,
// causing subsequent attempts to read it to fail. // causing subsequent attempts to read it to fail.
void TakeValue(); void TakeValue();
// Generate code to store the value on top of the expression stack in the // Generate code to store the value on top of the expression stack in the
// reference. The reference is expected to be immediately below the value // reference. The reference is expected to be immediately below the value
// on the expression stack. The stored value is left in place (with the // on the expression stack. The value is stored in the location specified
// reference intact below it) to support chained assignments. // by the reference, and is left on top of the stack, after the reference
// is popped from beneath it (unloaded).
void SetValue(InitState init_state); void SetValue(InitState init_state);
private: private:
CodeGenerator* cgen_; CodeGenerator* cgen_;
Expression* expression_; Expression* expression_;
Type type_; Type type_;
// Keep the reference on the stack after get, so it can be used by set later.
bool persist_after_get_;
}; };
...@@ -420,6 +433,11 @@ class CodeGenerator: public AstVisitor { ...@@ -420,6 +433,11 @@ class CodeGenerator: public AstVisitor {
// value in place. // value in place.
void StoreToSlot(Slot* slot, InitState init_state); void StoreToSlot(Slot* slot, InitState init_state);
// Load a property of an object, returning it in a Result.
// The object and the property name are passed on the stack, and
// not changed.
Result EmitKeyedLoad(bool is_global);
// Special code for typeof expressions: Unfortunately, we must // Special code for typeof expressions: Unfortunately, we must
// be careful when loading the expression in 'typeof' // be careful when loading the expression in 'typeof'
// expressions. We are not allowed to throw reference errors for // expressions. We are not allowed to throw reference errors for
...@@ -479,10 +497,10 @@ class CodeGenerator: public AstVisitor { ...@@ -479,10 +497,10 @@ class CodeGenerator: public AstVisitor {
CallFunctionFlags flags, CallFunctionFlags flags,
int position); int position);
// Use an optimized version of Function.prototype.apply that avoid // An optimized implementation of expressions of the form
// allocating the arguments object and just copies the arguments // x.apply(y, arguments). We call x the applicand and y the receiver.
// from the stack. // The optimization avoids allocating an arguments object if possible.
void CallApplyLazy(Property* apply, void CallApplyLazy(Expression* applicand,
Expression* receiver, Expression* receiver,
VariableProxy* arguments, VariableProxy* arguments,
int position); int position);
......
This diff is collapsed.
// Copyright 2009 the V8 project authors. All rights reserved. // Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
...@@ -43,57 +43,70 @@ enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF }; ...@@ -43,57 +43,70 @@ enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// Reference support // Reference support
// A reference is a C++ stack-allocated object that keeps an ECMA // A reference is a C++ stack-allocated object that puts a
// reference on the execution stack while in scope. For variables // reference on the virtual frame. The reference may be consumed
// the reference is empty, indicating that it isn't necessary to // by GetValue, TakeValue, SetValue, and Codegen::UnloadReference.
// store state on the stack for keeping track of references to those. // When the lifetime (scope) of a valid reference ends, it must have
// For properties, we keep either one (named) or two (indexed) values // been consumed, and be in state UNLOADED.
// on the execution stack to represent the reference.
class Reference BASE_EMBEDDED { class Reference BASE_EMBEDDED {
public: public:
// The values of the types is important, see size(). // The values of the types is important, see size().
enum Type { ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 }; enum Type { UNLOADED = -2, ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 };
Reference(CodeGenerator* cgen, Expression* expression);
Reference(CodeGenerator* cgen,
Expression* expression,
bool persist_after_get = false);
~Reference(); ~Reference();
Expression* expression() const { return expression_; } Expression* expression() const { return expression_; }
Type type() const { return type_; } Type type() const { return type_; }
void set_type(Type value) { void set_type(Type value) {
ASSERT(type_ == ILLEGAL); ASSERT_EQ(ILLEGAL, type_);
type_ = value; type_ = value;
} }
void set_unloaded() {
ASSERT_NE(ILLEGAL, type_);
ASSERT_NE(UNLOADED, type_);
type_ = UNLOADED;
}
// The size the reference takes up on the stack. // The size the reference takes up on the stack.
int size() const { return (type_ == ILLEGAL) ? 0 : type_; } int size() const {
return (type_ < SLOT) ? 0 : type_;
}
bool is_illegal() const { return type_ == ILLEGAL; } bool is_illegal() const { return type_ == ILLEGAL; }
bool is_slot() const { return type_ == SLOT; } bool is_slot() const { return type_ == SLOT; }
bool is_property() const { return type_ == NAMED || type_ == KEYED; } bool is_property() const { return type_ == NAMED || type_ == KEYED; }
bool is_unloaded() const { return type_ == UNLOADED; }
// Return the name. Only valid for named property references. // Return the name. Only valid for named property references.
Handle<String> GetName(); Handle<String> GetName();
// Generate code to push the value of the reference on top of the // Generate code to push the value of the reference on top of the
// expression stack. The reference is expected to be already on top of // expression stack. The reference is expected to be already on top of
// the expression stack, and it is left in place with its value above it. // the expression stack, and it is consumed by the call unless the
// reference is for a compound assignment.
// If the reference is not consumed, it is left in place under its value.
void GetValue(); void GetValue();
// Like GetValue except that the slot is expected to be written to before // Like GetValue except that the slot is expected to be written to before
// being read from again. Thae value of the reference may be invalidated, // being read from again. The value of the reference may be invalidated,
// causing subsequent attempts to read it to fail. // causing subsequent attempts to read it to fail.
void TakeValue(); void TakeValue();
// Generate code to store the value on top of the expression stack in the // Generate code to store the value on top of the expression stack in the
// reference. The reference is expected to be immediately below the value // reference. The reference is expected to be immediately below the value
// on the expression stack. The stored value is left in place (with the // on the expression stack. The value is stored in the location specified
// reference intact below it) to support chained assignments. // by the reference, and is left on top of the stack, after the reference
// is popped from beneath it (unloaded).
void SetValue(InitState init_state); void SetValue(InitState init_state);
private: private:
CodeGenerator* cgen_; CodeGenerator* cgen_;
Expression* expression_; Expression* expression_;
Type type_; Type type_;
bool persist_after_get_;
}; };
...@@ -422,6 +435,11 @@ class CodeGenerator: public AstVisitor { ...@@ -422,6 +435,11 @@ class CodeGenerator: public AstVisitor {
// value in place. // value in place.
void StoreToSlot(Slot* slot, InitState init_state); void StoreToSlot(Slot* slot, InitState init_state);
// Load a property of an object, returning it in a Result.
// The object and the property name are passed on the stack, and
// not changed.
Result EmitKeyedLoad(bool is_global);
// Special code for typeof expressions: Unfortunately, we must // Special code for typeof expressions: Unfortunately, we must
// be careful when loading the expression in 'typeof' // be careful when loading the expression in 'typeof'
// expressions. We are not allowed to throw reference errors for // expressions. We are not allowed to throw reference errors for
...@@ -478,10 +496,10 @@ class CodeGenerator: public AstVisitor { ...@@ -478,10 +496,10 @@ class CodeGenerator: public AstVisitor {
CallFunctionFlags flags, CallFunctionFlags flags,
int position); int position);
// Use an optimized version of Function.prototype.apply that avoid // An optimized implementation of expressions of the form
// allocating the arguments object and just copies the arguments // x.apply(y, arguments). We call x the applicand and y the receiver.
// from the stack. // The optimization avoids allocating an arguments object if possible.
void CallApplyLazy(Property* apply, void CallApplyLazy(Expression* applicand,
Expression* receiver, Expression* receiver,
VariableProxy* arguments, VariableProxy* arguments,
int position); int position);
......
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