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 |