Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(83)

Unified Diff: src/codegen-ia32.cc

Issue 1889: Remove some of the state-dependent behavior from the code generator.... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 12 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« src/codegen-arm.cc ('K') | « src/codegen-arm.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/codegen-ia32.cc
===================================================================
--- src/codegen-ia32.cc (revision 246)
+++ src/codegen-ia32.cc (working copy)
@@ -115,9 +115,7 @@
enum AccessType {
UNDEFINED,
LOAD,
- LOAD_TYPEOF_EXPR,
- STORE,
- INIT_CONST
+ LOAD_TYPEOF_EXPR
};
CodeGenState()
@@ -187,7 +185,6 @@
// The following are used by class Reference.
void LoadReference(Reference* ref);
void UnloadReference(Reference* ref);
- friend class Reference;
// State
bool has_cc() const { return cc_reg_ >= 0; }
@@ -198,27 +195,40 @@
Label* false_target() const { return state_->false_target(); }
// Expressions
- Operand GlobalObject() const {
+ Operand GlobalObject() const {
return ContextOperand(esi, Context::GLOBAL_INDEX);
}
- // Support functions for accessing parameters.
+ // Support functions for accessing parameters. Static versions can
+ // require some code generator state to be passed in as arguments.
+ static Operand ParameterOperand(Scope* scope, int index) {
+ ASSERT(-2 <= index && index < scope->num_parameters());
+ return Operand(ebp, (1 + scope->num_parameters() - index) * kPointerSize);
+ }
+
Operand ParameterOperand(int index) const {
- ASSERT(-2 <= index && index < scope_->num_parameters());
- return Operand(ebp, (1 + scope_->num_parameters() - index) * kPointerSize);
+ return ParameterOperand(scope_, index);
}
Operand ReceiverOperand() const { return ParameterOperand(-1); }
+
Operand FunctionOperand() const {
return Operand(ebp, JavaScriptFrameConstants::kFunctionOffset);
}
- Operand ContextOperand(Register context, int index) const {
+ static Operand ContextOperand(Register context, int index) {
return Operand(context, Context::SlotOffset(index));
}
- Operand SlotOperand(Slot* slot, Register tmp);
+ static Operand SlotOperand(MacroAssembler* masm,
+ Scope* scope,
+ Slot* slot,
+ Register tmp);
+ Operand SlotOperand(Slot* slot, Register tmp) {
+ return SlotOperand(masm_, scope_, slot, tmp);
+ }
+
void LoadCondition(Expression* x,
CodeGenState::AccessType access,
Label* true_target,
@@ -237,20 +247,42 @@
void LoadTypeofExpression(Expression* x);
// References
- void AccessReference(Reference* ref, CodeGenState::AccessType access);
- void GetValue(Reference* ref) { AccessReference(ref, CodeGenState::LOAD); }
- void SetValue(Reference* ref) { AccessReference(ref, CodeGenState::STORE); }
+ // Generate code to fetch the value of a reference. The reference is
+ // expected to be on top of the expression stack. It is left in place and
+ // its value is pushed on top of it.
+ void GetValue(Reference* ref);
+
+ // Generate code to store a value in a reference. The stored value is
+ // expected on top of the expression stack, with the reference immediately
+ // below it. The expression stack is left unchanged.
+ void SetValue(Reference* ref) {
+ ASSERT(!has_cc());
+ ASSERT(!ref->is_illegal());
+ ref->expression()->GenerateStoreCode(masm_, scope_, ref, false);
+ }
+
+ // Same as SetValue, used to set the initial value of a constant.
void InitConst(Reference* ref) {
- AccessReference(ref, CodeGenState::INIT_CONST);
+ ASSERT(!has_cc());
+ ASSERT(!ref->is_illegal());
+ ref->expression()->GenerateStoreCode(masm_, scope_, ref, true);
}
- void ToBoolean(Label* true_target, Label* false_target);
+ // Generate code to fetch a value from a property of a reference. The
+ // reference is expected on top of the expression stack. It is left in
+ // place and its value is pushed on top of it.
+ void GetReferenceProperty(Expression* key);
+ // Generate code to store a value in a property of a reference. The
+ // stored value is expected on top of the expression stack, with the
+ // reference immediately below it. The expression stack is left
+ // unchanged.
+ static void SetReferenceProperty(MacroAssembler* masm,
+ Reference* ref,
+ Expression* key);
- // Access property from the reference (must be at the TOS).
- void AccessReferenceProperty(Expression* key,
- CodeGenState::AccessType access);
+ void ToBoolean(Label* true_target, Label* false_target);
void GenericBinaryOperation(
Token::Value op,
@@ -316,6 +348,11 @@
virtual void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
virtual void GenerateObjectEquals(ZoneList<Expression*>* args);
+
+ friend class Reference;
+ friend class Property;
+ friend class VariableProxy;
+ friend class Slot;
};
@@ -633,7 +670,10 @@
}
-Operand Ia32CodeGenerator::SlotOperand(Slot* slot, Register tmp) {
+Operand Ia32CodeGenerator::SlotOperand(MacroAssembler* masm,
+ Scope* scope,
+ Slot* slot,
+ Register tmp) {
// Currently, this assertion will fail if we try to assign to
// a constant variable that is constant because it is read-only
// (such as the variable referring to a named function expression).
@@ -645,10 +685,10 @@
ASSERT(slot != NULL);
int index = slot->index();
switch (slot->type()) {
- case Slot::PARAMETER: return ParameterOperand(index);
+ case Slot::PARAMETER: return ParameterOperand(scope, index);
case Slot::LOCAL: {
- ASSERT(0 <= index && index < scope_->num_stack_slots());
+ ASSERT(0 <= index && index < scope->num_stack_slots());
const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
return Operand(ebp, kLocal0Offset - index * kPointerSize);
}
@@ -657,15 +697,15 @@
// Follow the context chain if necessary.
ASSERT(!tmp.is(esi)); // do not overwrite context register
Register context = esi;
- int chain_length = scope_->ContextChainLength(slot->var()->scope());
+ int chain_length = scope->ContextChainLength(slot->var()->scope());
for (int i = chain_length; i-- > 0;) {
// Load the closure.
// (All contexts, even 'with' contexts, have a closure,
// and it is the same for all contexts inside a function.
// There is no need to go to the function context first.)
- __ mov(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
+ masm->mov(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
// Load the function context (which is the incoming, outer context).
- __ mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset));
+ masm->mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset));
context = tmp;
}
// We may have a 'with' context now. Get the function context.
@@ -675,7 +715,7 @@
// cause the function context of a function context is itself. Before
// deleting this mov we should try to create a counter-example first,
// though...)
- __ mov(tmp, ContextOperand(context, Context::FCONTEXT_INDEX));
+ masm->mov(tmp, ContextOperand(context, Context::FCONTEXT_INDEX));
return ContextOperand(tmp, index);
}
@@ -852,18 +892,123 @@
}
-void Ia32CodeGenerator::AccessReference(Reference* ref,
- CodeGenState::AccessType access) {
+void Ia32CodeGenerator::GetValue(Reference* ref) {
ASSERT(!has_cc());
ASSERT(ref->type() != Reference::ILLEGAL);
CodeGenState* old_state = state_;
- CodeGenState new_state(access, ref, true_target(), false_target());
+ CodeGenState new_state(CodeGenState::LOAD, ref, true_target(),
+ false_target());
state_ = &new_state;
Visit(ref->expression());
state_ = old_state;
}
+void Property::GenerateStoreCode(MacroAssembler* masm,
+ Scope* scope,
+ Reference* ref,
+ bool is_const_init) {
+ Comment cmnt(masm, "[ Store to Property");
+ masm->RecordPosition(position());
+ Ia32CodeGenerator::SetReferenceProperty(masm, ref, key());
+}
+
+
+void VariableProxy::GenerateStoreCode(MacroAssembler* masm,
+ Scope* scope,
+ Reference* ref,
+ bool is_const_init) {
+
+ Comment cmnt(masm, "[ Store to VariableProxy");
+ Variable* node = var();
+
+ Expression* expr = node->rewrite();
+ if (expr != NULL) {
+ expr->GenerateStoreCode(masm, scope, ref, is_const_init);
+ } else {
+ ASSERT(node->is_global());
+ if (node->AsProperty() != NULL) {
+ masm->RecordPosition(node->AsProperty()->position());
+ }
+ Ia32CodeGenerator::SetReferenceProperty(masm, ref,
+ new Literal(node->name()));
+ }
+}
+
+
+void Slot::GenerateStoreCode(MacroAssembler* masm,
+ Scope* scope,
+ Reference* ref,
+ bool is_const_init) {
+ Comment cmnt(masm, "[ Store to Slot");
+
+ if (type() == Slot::LOOKUP) {
+ ASSERT(var()->mode() == Variable::DYNAMIC);
+
+ // For now, just do a runtime call.
+ masm->push(Operand(esi));
+ masm->push(Immediate(var()->name()));
+
+ if (is_const_init) {
+ // Same as the case for a normal store, but ignores attribute
+ // (e.g. READ_ONLY) of context slot so that we can initialize const
+ // properties (introduced via eval("const foo = (some expr);")). Also,
+ // uses the current function context instead of the top context.
+ //
+ // Note that we must declare the foo upon entry of eval(), via a
+ // context slot declaration, but we cannot initialize it at the same
+ // time, because the const declaration may be at the end of the eval
+ // code (sigh...) and the const variable may have been used before
+ // (where its value is 'undefined'). Thus, we can only do the
+ // initialization when we actually encounter the expression and when
+ // the expression operands are defined and valid, and thus we need the
+ // split into 2 operations: declaration of the context slot followed
+ // by initialization.
+ masm->CallRuntime(Runtime::kInitializeConstContextSlot, 3);
+ } else {
+ masm->CallRuntime(Runtime::kStoreContextSlot, 3);
+ }
+ // Storing a variable must keep the (new) value on the expression
+ // stack. This is necessary for compiling assignment expressions.
+ masm->push(eax);
+
+ } else {
+ ASSERT(var()->mode() != Variable::DYNAMIC);
+
+ Label exit;
+ if (is_const_init) {
+ ASSERT(var()->mode() == Variable::CONST);
+ // Only the first const initialization must be executed (the slot
+ // still contains 'the hole' value). When the assignment is executed,
+ // the code is identical to a normal store (see below).
+ Comment cmnt(masm, "[ Init const");
+ masm->mov(eax, Ia32CodeGenerator::SlotOperand(masm, scope, this, ecx));
+ masm->cmp(eax, Factory::the_hole_value());
+ masm->j(not_equal, &exit);
+ }
+
+ // We must execute the store.
+ // Storing a variable must keep the (new) value on the stack. This is
+ // necessary for compiling assignment expressions. ecx may be loaded
+ // with context; used below in RecordWrite.
+ //
+ // Note: We will reach here even with node->var()->mode() ==
+ // Variable::CONST because of const declarations which will initialize
+ // consts to 'the hole' value and by doing so, end up calling this
+ // code.
+ masm->pop(eax);
+ masm->mov(Ia32CodeGenerator::SlotOperand(masm, scope, this, ecx), eax);
+ masm->push(eax); // RecordWrite may destroy the value in eax.
+ if (type() == Slot::CONTEXT) {
+ // ecx is loaded with context when calling SlotOperand above.
+ int offset = FixedArray::kHeaderSize + index() * kPointerSize;
+ masm->RecordWrite(ecx, offset, eax, ebx);
+ }
+ masm->bind(&exit);
+ }
+}
+
+
#undef __
#define __ masm->
@@ -991,63 +1136,41 @@
}
-void Ia32CodeGenerator::AccessReferenceProperty(
- Expression* key,
- CodeGenState::AccessType access) {
+void Ia32CodeGenerator::GetReferenceProperty(Expression* key) {
Reference::Type type = ref()->type();
- ASSERT(type != Reference::ILLEGAL);
+ ASSERT(!ref()->is_illegal());
iposva 2008/09/10 18:01:44 Same nit as on ARM: Don't you want to assert befor
Kevin Millikin (Chromium) 2008/09/11 07:15:55 Done.
- // TODO(1241834): Make sure that this is sufficient. If there is a chance
- // that reference errors can be thrown below, we must distinguish
- // between the 2 kinds of loads (typeof expression loads must not
- // throw a reference error).
- bool is_load = (access == CodeGenState::LOAD ||
- access == CodeGenState::LOAD_TYPEOF_EXPR);
-
+ // TODO(1241834): Make sure that this it is safe to ignore the distinction
+ // between access types LOAD and LOAD_TYPEOF_EXPR. If there is a chance
+ // that reference errors can be thrown below, we must distinguish between
+ // the two kinds of loads (typeof expression loads must not throw a
+ // reference error).
if (type == Reference::NAMED) {
// Compute the name of the property.
Literal* literal = key->AsLiteral();
Handle<String> name(String::cast(*literal->handle()));
- // Call the appropriate IC code.
- if (is_load) {
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
- Variable* var = ref()->expression()->AsVariableProxy()->AsVariable();
- // Setup the name register.
- __ Set(ecx, Immediate(name));
- if (var != NULL) {
- ASSERT(var->is_global());
- __ call(ic, code_target_context);
- } else {
- __ call(ic, code_target);
- }
+ Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+ Variable* var = ref()->expression()->AsVariableProxy()->AsVariable();
+ // Setup the name register.
+ __ Set(ecx, Immediate(name));
+ if (var != NULL) {
+ ASSERT(var->is_global());
+ __ call(ic, code_target_context);
} else {
- Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
- // TODO(1222589): Make the IC grab the values from the stack.
- __ pop(eax);
- // Setup the name register.
- __ Set(ecx, Immediate(name));
__ call(ic, code_target);
}
} else {
// Access keyed property.
ASSERT(type == Reference::KEYED);
- if (is_load) {
- // Call IC code.
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
- Variable* var = ref()->expression()->AsVariableProxy()->AsVariable();
- if (var != NULL) {
- ASSERT(var->is_global());
- __ call(ic, code_target_context);
- } else {
- __ call(ic, code_target);
- }
+ // Call IC code.
+ Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+ Variable* var = ref()->expression()->AsVariableProxy()->AsVariable();
+ if (var != NULL) {
+ ASSERT(var->is_global());
+ __ call(ic, code_target_context);
} else {
- // Call IC code.
- Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
- // TODO(1222589): Make the IC grab the values from the stack.
- __ pop(eax);
__ call(ic, code_target);
}
}
@@ -1055,6 +1178,38 @@
}
+void Ia32CodeGenerator::SetReferenceProperty(MacroAssembler* masm,
+ Reference* ref,
+ Expression* key) {
+ Reference::Type type = ref->type();
+ ASSERT(!ref->is_illegal());
+
+ if (type == Reference::NAMED) {
+ // Compute the name of the property.
+ Literal* literal = key->AsLiteral();
+ Handle<String> name(String::cast(*literal->handle()));
+
+ // Call the appropriate IC code.
+ Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
+ // TODO(1222589): Make the IC grab the values from the stack.
+ masm->pop(eax);
+ // Setup the name register.
+ masm->Set(ecx, Immediate(name));
+ masm->call(ic, code_target);
+ } else {
+ // Access keyed property.
+ ASSERT(type == Reference::KEYED);
+
+ // Call IC code.
+ Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
+ // TODO(1222589): Make the IC grab the values from the stack.
+ masm->pop(eax);
+ masm->call(ic, code_target);
+ }
+ masm->push(eax); // IC call leaves result in eax, push it out
+}
+
+
#undef __
#define __ masm->
@@ -3325,6 +3480,7 @@
void Ia32CodeGenerator::VisitSlot(Slot* node) {
+ ASSERT(access() != CodeGenState::UNDEFINED);
Comment cmnt(masm_, "[ Slot");
if (node->type() == Slot::LOOKUP) {
@@ -3334,151 +3490,56 @@
__ push(Operand(esi));
__ push(Immediate(node->var()->name()));
- switch (access()) {
- case CodeGenState::UNDEFINED:
- UNREACHABLE();
- break;
-
- case CodeGenState::LOAD:
- __ CallRuntime(Runtime::kLoadContextSlot, 2);
- __ push(eax);
- // result (TOS) is the value that was loaded
- break;
-
- case CodeGenState::LOAD_TYPEOF_EXPR:
- __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
- __ push(eax);
- // result (TOS) is the value that was loaded
- break;
-
- case CodeGenState::STORE:
- // Storing a variable must keep the (new) value on the
- // stack. This is necessary for compiling assignment
- // expressions.
- __ CallRuntime(Runtime::kStoreContextSlot, 3);
- __ push(eax);
- // result (TOS) is the value that was stored
- break;
-
- case CodeGenState::INIT_CONST:
- // Same as STORE but ignores attribute (e.g. READ_ONLY) of
- // context slot so that we can initialize const properties
- // (introduced via eval("const foo = (some expr);")). Also,
- // uses the current function context instead of the top
- // context.
- //
- // Note that we must declare the foo upon entry of eval(),
- // via a context slot declaration, but we cannot initialize
- // it at the same time, because the const declaration may
- // be at the end of the eval code (sigh...) and the const
- // variable may have been used before (where its value is
- // 'undefined'). Thus, we can only do the initialization
- // when we actually encounter the expression and when the
- // expression operands are defined and valid, and thus we
- // need the split into 2 operations: declaration of the
- // context slot followed by initialization.
- //
- __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
- __ push(eax);
- break;
+ if (access() == CodeGenState::LOAD) {
+ __ CallRuntime(Runtime::kLoadContextSlot, 2);
+ } else {
+ // CodeGenState::LOAD_TYPEOF_EXPR.
iposva 2008/09/10 18:01:44 Same comment as on ARM: Please assert that the Cod
Kevin Millikin (Chromium) 2008/09/11 07:15:55 Done.
+ __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
}
+ __ push(eax);
} else {
- // Note: We would like to keep the assert below, but it fires because
- // of some nasty code in LoadTypeofExpression() which should be removed...
+ // Note: We would like to keep the assert below, but it fires because of
+ // some nasty code in LoadTypeofExpression() which should be removed...
// ASSERT(node->var()->mode() != Variable::DYNAMIC);
- switch (access()) {
- case CodeGenState::UNDEFINED:
- UNREACHABLE();
- break;
-
- case CodeGenState::LOAD: // fall through
- case CodeGenState::LOAD_TYPEOF_EXPR:
- if (node->var()->mode() == Variable::CONST) {
- // Const slots may contain 'the hole' value (the constant hasn't
- // been initialized yet) which needs to be converted into the
- // 'undefined' value.
- Comment cmnt(masm_, "[ Load const");
- Label L;
- __ mov(eax, SlotOperand(node, ecx));
- __ cmp(eax, Factory::the_hole_value());
- __ j(not_equal, &L);
- __ mov(eax, Factory::undefined_value());
- __ bind(&L);
- __ push(eax);
- } else {
- __ push(SlotOperand(node, ecx));
- }
- break;
-
- case CodeGenState::INIT_CONST:
- ASSERT(node->var()->mode() == Variable::CONST);
- // Only the first const initialization must be executed (the slot
- // still contains 'the hole' value). When the assignment is executed,
- // the code is identical to a normal store (see below).
- { Comment cmnt(masm_, "[ Init const");
- Label L;
- __ mov(eax, SlotOperand(node, ecx));
- __ cmp(eax, Factory::the_hole_value());
- __ j(not_equal, &L);
- // We must execute the store.
- __ mov(eax, TOS);
- __ mov(SlotOperand(node, ecx), eax);
- if (node->type() == Slot::CONTEXT) {
- // ecx is loaded with context when calling SlotOperand above.
- int offset = FixedArray::kHeaderSize + node->index() * kPointerSize;
- __ RecordWrite(ecx, offset, eax, ebx);
- }
- __ bind(&L);
- }
- break;
-
- case CodeGenState::STORE:
- // Storing a variable must keep the (new) value on the stack. This
- // is necessary for compiling assignment expressions.
- // ecx may be loaded with context; used below in RecordWrite.
- //
- // Note: We will reach here even with node->var()->mode() ==
- // Variable::CONST because of const declarations which will
- // initialize consts to 'the hole' value and by doing so, end
- // up calling this code.
- __ pop(eax);
- __ mov(SlotOperand(node, ecx), eax);
- __ push(eax); // RecordWrite may destroy the value in eax.
- if (node->type() == Slot::CONTEXT) {
- // ecx is loaded with context when calling SlotOperand above.
- int offset = FixedArray::kHeaderSize + node->index() * kPointerSize;
- __ RecordWrite(ecx, offset, eax, ebx);
- }
- break;
+ if (node->var()->mode() == Variable::CONST) {
+ // Const slots may contain 'the hole' value (the constant hasn't been
+ // initialized yet) which needs to be converted into the 'undefined'
+ // value.
+ Comment cmnt(masm_, "[ Load const");
+ Label L;
+ __ mov(eax, SlotOperand(node, ecx));
+ __ cmp(eax, Factory::the_hole_value());
+ __ j(not_equal, &L);
+ __ mov(eax, Factory::undefined_value());
+ __ bind(&L);
+ __ push(eax);
+ } else {
+ __ push(SlotOperand(node, ecx));
}
}
}
-void Ia32CodeGenerator::VisitVariableProxy(VariableProxy* proxy_node) {
+void Ia32CodeGenerator::VisitVariableProxy(VariableProxy* node) {
Comment cmnt(masm_, "[ VariableProxy");
- Variable* node = proxy_node->var();
+ Variable* var_node = node->var();
- Expression* x = node->rewrite();
- if (x != NULL) {
- Visit(x);
- return;
- }
-
- ASSERT(node->is_global());
- if (is_referenced()) {
- if (node->AsProperty() != NULL) {
- __ RecordPosition(node->AsProperty()->position());
+ Expression* expr = var_node->rewrite();
+ if (expr != NULL) {
+ Visit(expr);
+ } else {
+ ASSERT(var_node->is_global());
+ if (is_referenced()) {
+ if (var_node->AsProperty() != NULL) {
+ __ RecordPosition(var_node->AsProperty()->position());
+ }
+ GetReferenceProperty(new Literal(var_node->name()));
+ } else {
+ Reference property(this, node);
+ GetValue(&property);
}
- AccessReferenceProperty(new Literal(node->name()), access());
-
- } else {
- // All stores are through references.
- ASSERT(access() != CodeGenState::STORE);
- Reference property(this, proxy_node);
- GetValue(&property);
}
}
@@ -3784,10 +3845,8 @@
if (is_referenced()) {
__ RecordPosition(node->position());
- AccessReferenceProperty(node->key(), access());
+ GetReferenceProperty(node->key());
} else {
- // All stores are through references.
- ASSERT(access() != CodeGenState::STORE);
Reference property(this, node);
__ RecordPosition(node->position());
GetValue(&property);
« src/codegen-arm.cc ('K') | « src/codegen-arm.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698