Author: [email protected]
Date: Wed Feb 18 05:54:13 2009
New Revision: 1301
Modified:
branches/bleeding_edge/src/codegen-arm.cc
branches/bleeding_edge/src/codegen-arm.h
branches/bleeding_edge/src/codegen-ia32.cc
Log:
ARM side of load optimization in the presence of eval.
Review URL: http://codereview.chromium.org/20453
Modified: branches/bleeding_edge/src/codegen-arm.cc
==============================================================================
--- branches/bleeding_edge/src/codegen-arm.cc (original)
+++ branches/bleeding_edge/src/codegen-arm.cc Wed Feb 18 05:54:13 2009
@@ -369,7 +369,7 @@
ASSERT(!tmp.is(cp)); // do not overwrite context register
Register context = cp;
int chain_length = scope()->ContextChainLength(slot->var()->scope());
- for (int i = chain_length; i-- > 0;) {
+ for (int i = 0; i < chain_length; i++) {
// Load the closure.
// (All contexts, even 'with' contexts, have a closure,
// and it is the same for all contexts inside a function.
@@ -397,6 +397,35 @@
}
+MemOperand CodeGenerator::ContextSlotOperandCheckExtensions(Slot* slot,
+ Register tmp,
+ Register tmp2,
+ Label* slow) {
+ ASSERT(slot->type() == Slot::CONTEXT);
+ int index = slot->index();
+ Register context = cp;
+ for (Scope* s = scope(); s != slot->var()->scope(); s =
s->outer_scope()) {
+ if (s->num_heap_slots() > 0) {
+ if (s->calls_eval()) {
+ // Check that extension is NULL.
+ __ ldr(tmp2, ContextOperand(context, Context::EXTENSION_INDEX));
+ __ tst(tmp2, tmp2);
+ __ b(ne, slow);
+ }
+ __ ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
+ __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset));
+ context = tmp;
+ }
+ }
+ // Check that last extension is NULL.
+ __ ldr(tmp2, ContextOperand(tmp, Context::EXTENSION_INDEX));
+ __ tst(tmp2, tmp2);
+ __ b(ne, slow);
+ __ ldr(tmp, ContextOperand(tmp, Context::FCONTEXT_INDEX));
+ return ContextOperand(tmp, index);
+}
+
+
// Loads a value on TOS. If it is a boolean value, the result may have been
// (partially) translated into branches, or it may have set the condition
// code register. If force_cc is set, the value is forced to set the
@@ -1985,7 +2014,28 @@
if (slot->type() == Slot::LOOKUP) {
ASSERT(slot->var()->is_dynamic());
- // For now, just do a runtime call.
+ Label slow, done;
+
+ // Generate fast-case code for variables that might be shadowed by
+ // eval-introduced variables. Eval is used a lot without
+ // introducing variables. In those cases, we do not want to
+ // perform a runtime call for all variables in the scope
+ // containing the eval.
+ if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
+ LoadFromGlobalSlotCheckExtensions(slot, typeof_state, r1, r2, &slow);
+ __ b(&done);
+
+ } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
+ Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot();
+ __ ldr(r0,
+ ContextSlotOperandCheckExtensions(potential_slot,
+ r1,
+ r2,
+ &slow));
+ __ b(&done);
+ }
+
+ __ bind(&slow);
frame_->Push(cp);
__ mov(r0, Operand(slot->var()->name()));
frame_->Push(r0);
@@ -1995,6 +2045,8 @@
} else {
__ CallRuntime(Runtime::kLoadContextSlot, 2);
}
+
+ __ bind(&done);
frame_->Push(r0);
} else {
@@ -2016,6 +2068,51 @@
frame_->Push(r0);
}
}
+}
+
+
+void CodeGenerator::LoadFromGlobalSlotCheckExtensions(Slot* slot,
+ TypeofState
typeof_state,
+ Register tmp,
+ Register tmp2,
+ Label* slow) {
+ // Check that no extension objects have been created by calls to
+ // eval from the current scope to the global scope.
+ Register context = cp;
+ for (Scope* s = scope(); s != NULL; s = s->outer_scope()) {
+ if (s->num_heap_slots() > 0) {
+ if (s->calls_eval()) {
+ // Check that extension is NULL.
+ __ ldr(tmp2, ContextOperand(context, Context::EXTENSION_INDEX));
+ __ tst(tmp2, tmp2);
+ __ b(ne, slow);
+ }
+ // Load next context in chain.
+ __ ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
+ __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset));
+ context = tmp;
+ }
+ // If no outer scope calls eval, we do not need to check more
+ // context extensions.
+ if (!s->outer_scope_calls_eval()) break;
+ }
+
+ // All extension objects were empty and it is safe to use a global
+ // load IC call.
+ Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+ // Load the global object.
+ LoadGlobal();
+ // Setup the name register.
+ __ mov(r2, Operand(slot->var()->name()));
+ // Call IC stub.
+ if (typeof_state == INSIDE_TYPEOF) {
+ __ Call(ic, RelocInfo::CODE_TARGET);
+ } else {
+ __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
+ }
+
+ // Pop the global object. The result is in r0.
+ frame_->Pop();
}
Modified: branches/bleeding_edge/src/codegen-arm.h
==============================================================================
--- branches/bleeding_edge/src/codegen-arm.h (original)
+++ branches/bleeding_edge/src/codegen-arm.h Wed Feb 18 05:54:13 2009
@@ -256,6 +256,11 @@
MemOperand SlotOperand(Slot* slot, Register tmp);
+ MemOperand ContextSlotOperandCheckExtensions(Slot* slot,
+ Register tmp,
+ Register tmp2,
+ Label* slow);
+
// Expressions
MemOperand GlobalObject() const {
return ContextOperand(cp, Context::GLOBAL_INDEX);
@@ -272,6 +277,11 @@
// Read a value from a slot and leave it on top of the expression stack.
void LoadFromSlot(Slot* slot, TypeofState typeof_state);
+ void LoadFromGlobalSlotCheckExtensions(Slot* slot,
+ TypeofState typeof_state,
+ Register tmp,
+ Register tmp2,
+ Label* slow);
// Special code for typeof expressions: Unfortunately, we must
// be careful when loading the expression in 'typeof'
Modified: branches/bleeding_edge/src/codegen-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/codegen-ia32.cc (original)
+++ branches/bleeding_edge/src/codegen-ia32.cc Wed Feb 18 05:54:13 2009
@@ -455,16 +455,17 @@
Label* slow) {
ASSERT(slot->type() == Slot::CONTEXT);
int index = slot->index();
- __ mov(tmp, Operand(esi));
+ Register context = esi;
for (Scope* s = scope(); s != slot->var()->scope(); s =
s->outer_scope()) {
if (s->num_heap_slots() > 0) {
if (s->calls_eval()) {
// Check that extension is NULL.
- __ cmp(ContextOperand(tmp, Context::EXTENSION_INDEX),
Immediate(0));
+ __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
Immediate(0));
__ j(not_equal, slow, not_taken);
}
- __ mov(tmp, ContextOperand(tmp, Context::CLOSURE_INDEX));
+ __ mov(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
__ mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset));
+ context = tmp;
}
}
// Check that last extension is NULL.
@@ -2412,17 +2413,18 @@
Label* slow) {
// Check that no extension objects have been created by calls to
// eval from the current scope to the global scope.
- __ mov(tmp, Operand(esi));
+ Register context = esi;
for (Scope* s = scope(); s != NULL; s = s->outer_scope()) {
if (s->num_heap_slots() > 0) {
if (s->calls_eval()) {
// Check that extension is NULL.
- __ cmp(ContextOperand(tmp, Context::EXTENSION_INDEX),
Immediate(0));
+ __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
Immediate(0));
__ j(not_equal, slow, not_taken);
}
// Load next context in chain.
- __ mov(tmp, ContextOperand(tmp, Context::CLOSURE_INDEX));
+ __ mov(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
__ mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset));
+ context = tmp;
}
// If no outer scope calls eval, we do not need to check more
// context extensions.
--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---