| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 362 return frame_->Parameter(index); | 362 return frame_->Parameter(index); |
| 363 | 363 |
| 364 case Slot::LOCAL: | 364 case Slot::LOCAL: |
| 365 return frame_->Local(index); | 365 return frame_->Local(index); |
| 366 | 366 |
| 367 case Slot::CONTEXT: { | 367 case Slot::CONTEXT: { |
| 368 // Follow the context chain if necessary. | 368 // Follow the context chain if necessary. |
| 369 ASSERT(!tmp.is(cp)); // do not overwrite context register | 369 ASSERT(!tmp.is(cp)); // do not overwrite context register |
| 370 Register context = cp; | 370 Register context = cp; |
| 371 int chain_length = scope()->ContextChainLength(slot->var()->scope()); | 371 int chain_length = scope()->ContextChainLength(slot->var()->scope()); |
| 372 for (int i = chain_length; i-- > 0;) { | 372 for (int i = 0; i < chain_length; i++) { |
| 373 // Load the closure. | 373 // Load the closure. |
| 374 // (All contexts, even 'with' contexts, have a closure, | 374 // (All contexts, even 'with' contexts, have a closure, |
| 375 // and it is the same for all contexts inside a function. | 375 // and it is the same for all contexts inside a function. |
| 376 // There is no need to go to the function context first.) | 376 // There is no need to go to the function context first.) |
| 377 __ ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); | 377 __ ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); |
| 378 // Load the function context (which is the incoming, outer context). | 378 // Load the function context (which is the incoming, outer context). |
| 379 __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset)); | 379 __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset)); |
| 380 context = tmp; | 380 context = tmp; |
| 381 } | 381 } |
| 382 // We may have a 'with' context now. Get the function context. | 382 // We may have a 'with' context now. Get the function context. |
| 383 // (In fact this mov may never be the needed, since the scope analysis | 383 // (In fact this mov may never be the needed, since the scope analysis |
| 384 // may not permit a direct context access in this case and thus we are | 384 // may not permit a direct context access in this case and thus we are |
| 385 // always at a function context. However it is safe to dereference be- | 385 // always at a function context. However it is safe to dereference be- |
| 386 // cause the function context of a function context is itself. Before | 386 // cause the function context of a function context is itself. Before |
| 387 // deleting this mov we should try to create a counter-example first, | 387 // deleting this mov we should try to create a counter-example first, |
| 388 // though...) | 388 // though...) |
| 389 __ ldr(tmp, ContextOperand(context, Context::FCONTEXT_INDEX)); | 389 __ ldr(tmp, ContextOperand(context, Context::FCONTEXT_INDEX)); |
| 390 return ContextOperand(tmp, index); | 390 return ContextOperand(tmp, index); |
| 391 } | 391 } |
| 392 | 392 |
| 393 default: | 393 default: |
| 394 UNREACHABLE(); | 394 UNREACHABLE(); |
| 395 return MemOperand(r0, 0); | 395 return MemOperand(r0, 0); |
| 396 } | 396 } |
| 397 } | 397 } |
| 398 | 398 |
| 399 | 399 |
| 400 MemOperand CodeGenerator::ContextSlotOperandCheckExtensions(Slot* slot, |
| 401 Register tmp, |
| 402 Register tmp2, |
| 403 Label* slow) { |
| 404 ASSERT(slot->type() == Slot::CONTEXT); |
| 405 int index = slot->index(); |
| 406 Register context = cp; |
| 407 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) { |
| 408 if (s->num_heap_slots() > 0) { |
| 409 if (s->calls_eval()) { |
| 410 // Check that extension is NULL. |
| 411 __ ldr(tmp2, ContextOperand(context, Context::EXTENSION_INDEX)); |
| 412 __ tst(tmp2, tmp2); |
| 413 __ b(ne, slow); |
| 414 } |
| 415 __ ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); |
| 416 __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset)); |
| 417 context = tmp; |
| 418 } |
| 419 } |
| 420 // Check that last extension is NULL. |
| 421 __ ldr(tmp2, ContextOperand(tmp, Context::EXTENSION_INDEX)); |
| 422 __ tst(tmp2, tmp2); |
| 423 __ b(ne, slow); |
| 424 __ ldr(tmp, ContextOperand(tmp, Context::FCONTEXT_INDEX)); |
| 425 return ContextOperand(tmp, index); |
| 426 } |
| 427 |
| 428 |
| 400 // Loads a value on TOS. If it is a boolean value, the result may have been | 429 // Loads a value on TOS. If it is a boolean value, the result may have been |
| 401 // (partially) translated into branches, or it may have set the condition | 430 // (partially) translated into branches, or it may have set the condition |
| 402 // code register. If force_cc is set, the value is forced to set the | 431 // code register. If force_cc is set, the value is forced to set the |
| 403 // condition code register and no value is pushed. If the condition code | 432 // condition code register and no value is pushed. If the condition code |
| 404 // register was set, has_cc() is true and cc_reg_ contains the condition to | 433 // register was set, has_cc() is true and cc_reg_ contains the condition to |
| 405 // test for 'true'. | 434 // test for 'true'. |
| 406 void CodeGenerator::LoadCondition(Expression* x, | 435 void CodeGenerator::LoadCondition(Expression* x, |
| 407 TypeofState typeof_state, | 436 TypeofState typeof_state, |
| 408 Label* true_target, | 437 Label* true_target, |
| 409 Label* false_target, | 438 Label* false_target, |
| (...skipping 1568 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1978 __ bind(&else_); | 2007 __ bind(&else_); |
| 1979 Load(node->else_expression(), typeof_state()); | 2008 Load(node->else_expression(), typeof_state()); |
| 1980 __ bind(&exit); | 2009 __ bind(&exit); |
| 1981 } | 2010 } |
| 1982 | 2011 |
| 1983 | 2012 |
| 1984 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { | 2013 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { |
| 1985 if (slot->type() == Slot::LOOKUP) { | 2014 if (slot->type() == Slot::LOOKUP) { |
| 1986 ASSERT(slot->var()->is_dynamic()); | 2015 ASSERT(slot->var()->is_dynamic()); |
| 1987 | 2016 |
| 1988 // For now, just do a runtime call. | 2017 Label slow, done; |
| 2018 |
| 2019 // Generate fast-case code for variables that might be shadowed by |
| 2020 // eval-introduced variables. Eval is used a lot without |
| 2021 // introducing variables. In those cases, we do not want to |
| 2022 // perform a runtime call for all variables in the scope |
| 2023 // containing the eval. |
| 2024 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { |
| 2025 LoadFromGlobalSlotCheckExtensions(slot, typeof_state, r1, r2, &slow); |
| 2026 __ b(&done); |
| 2027 |
| 2028 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { |
| 2029 Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot(); |
| 2030 __ ldr(r0, |
| 2031 ContextSlotOperandCheckExtensions(potential_slot, |
| 2032 r1, |
| 2033 r2, |
| 2034 &slow)); |
| 2035 __ b(&done); |
| 2036 } |
| 2037 |
| 2038 __ bind(&slow); |
| 1989 frame_->Push(cp); | 2039 frame_->Push(cp); |
| 1990 __ mov(r0, Operand(slot->var()->name())); | 2040 __ mov(r0, Operand(slot->var()->name())); |
| 1991 frame_->Push(r0); | 2041 frame_->Push(r0); |
| 1992 | 2042 |
| 1993 if (typeof_state == INSIDE_TYPEOF) { | 2043 if (typeof_state == INSIDE_TYPEOF) { |
| 1994 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 2044 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| 1995 } else { | 2045 } else { |
| 1996 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 2046 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| 1997 } | 2047 } |
| 2048 |
| 2049 __ bind(&done); |
| 1998 frame_->Push(r0); | 2050 frame_->Push(r0); |
| 1999 | 2051 |
| 2000 } else { | 2052 } else { |
| 2001 // Note: We would like to keep the assert below, but it fires because of | 2053 // Note: We would like to keep the assert below, but it fires because of |
| 2002 // some nasty code in LoadTypeofExpression() which should be removed... | 2054 // some nasty code in LoadTypeofExpression() which should be removed... |
| 2003 // ASSERT(!slot->var()->is_dynamic()); | 2055 // ASSERT(!slot->var()->is_dynamic()); |
| 2004 | 2056 |
| 2005 // Special handling for locals allocated in registers. | 2057 // Special handling for locals allocated in registers. |
| 2006 __ ldr(r0, SlotOperand(slot, r2)); | 2058 __ ldr(r0, SlotOperand(slot, r2)); |
| 2007 frame_->Push(r0); | 2059 frame_->Push(r0); |
| 2008 if (slot->var()->mode() == Variable::CONST) { | 2060 if (slot->var()->mode() == Variable::CONST) { |
| 2009 // Const slots may contain 'the hole' value (the constant hasn't been | 2061 // Const slots may contain 'the hole' value (the constant hasn't been |
| 2010 // initialized yet) which needs to be converted into the 'undefined' | 2062 // initialized yet) which needs to be converted into the 'undefined' |
| 2011 // value. | 2063 // value. |
| 2012 Comment cmnt(masm_, "[ Unhole const"); | 2064 Comment cmnt(masm_, "[ Unhole const"); |
| 2013 frame_->Pop(r0); | 2065 frame_->Pop(r0); |
| 2014 __ cmp(r0, Operand(Factory::the_hole_value())); | 2066 __ cmp(r0, Operand(Factory::the_hole_value())); |
| 2015 __ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq); | 2067 __ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq); |
| 2016 frame_->Push(r0); | 2068 frame_->Push(r0); |
| 2017 } | 2069 } |
| 2018 } | 2070 } |
| 2019 } | 2071 } |
| 2020 | 2072 |
| 2021 | 2073 |
| 2074 void CodeGenerator::LoadFromGlobalSlotCheckExtensions(Slot* slot, |
| 2075 TypeofState typeof_state, |
| 2076 Register tmp, |
| 2077 Register tmp2, |
| 2078 Label* slow) { |
| 2079 // Check that no extension objects have been created by calls to |
| 2080 // eval from the current scope to the global scope. |
| 2081 Register context = cp; |
| 2082 for (Scope* s = scope(); s != NULL; s = s->outer_scope()) { |
| 2083 if (s->num_heap_slots() > 0) { |
| 2084 if (s->calls_eval()) { |
| 2085 // Check that extension is NULL. |
| 2086 __ ldr(tmp2, ContextOperand(context, Context::EXTENSION_INDEX)); |
| 2087 __ tst(tmp2, tmp2); |
| 2088 __ b(ne, slow); |
| 2089 } |
| 2090 // Load next context in chain. |
| 2091 __ ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); |
| 2092 __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset)); |
| 2093 context = tmp; |
| 2094 } |
| 2095 // If no outer scope calls eval, we do not need to check more |
| 2096 // context extensions. |
| 2097 if (!s->outer_scope_calls_eval()) break; |
| 2098 } |
| 2099 |
| 2100 // All extension objects were empty and it is safe to use a global |
| 2101 // load IC call. |
| 2102 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 2103 // Load the global object. |
| 2104 LoadGlobal(); |
| 2105 // Setup the name register. |
| 2106 __ mov(r2, Operand(slot->var()->name())); |
| 2107 // Call IC stub. |
| 2108 if (typeof_state == INSIDE_TYPEOF) { |
| 2109 __ Call(ic, RelocInfo::CODE_TARGET); |
| 2110 } else { |
| 2111 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 2112 } |
| 2113 |
| 2114 // Pop the global object. The result is in r0. |
| 2115 frame_->Pop(); |
| 2116 } |
| 2117 |
| 2118 |
| 2022 void CodeGenerator::VisitSlot(Slot* node) { | 2119 void CodeGenerator::VisitSlot(Slot* node) { |
| 2023 Comment cmnt(masm_, "[ Slot"); | 2120 Comment cmnt(masm_, "[ Slot"); |
| 2024 LoadFromSlot(node, typeof_state()); | 2121 LoadFromSlot(node, typeof_state()); |
| 2025 } | 2122 } |
| 2026 | 2123 |
| 2027 | 2124 |
| 2028 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { | 2125 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { |
| 2029 Comment cmnt(masm_, "[ VariableProxy"); | 2126 Comment cmnt(masm_, "[ VariableProxy"); |
| 2030 | 2127 |
| 2031 Variable* var = node->var(); | 2128 Variable* var = node->var(); |
| (...skipping 2329 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4361 __ mov(r2, Operand(0)); | 4458 __ mov(r2, Operand(0)); |
| 4362 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); | 4459 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); |
| 4363 __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)), | 4460 __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)), |
| 4364 RelocInfo::CODE_TARGET); | 4461 RelocInfo::CODE_TARGET); |
| 4365 } | 4462 } |
| 4366 | 4463 |
| 4367 | 4464 |
| 4368 #undef __ | 4465 #undef __ |
| 4369 | 4466 |
| 4370 } } // namespace v8::internal | 4467 } } // namespace v8::internal |
| OLD | NEW |