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

Side by Side Diff: src/codegen-arm.cc

Issue 20499: Experimental: merge from bleeding edge 1298:1307. Port the eval... (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/toiger/
Patch Set: '' Created 11 years, 10 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/codegen-arm.h ('k') | src/codegen-ia32.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 295 matching lines...) Expand 10 before | Expand all | Expand 10 after
306 return frame_->ParameterAt(index); 306 return frame_->ParameterAt(index);
307 307
308 case Slot::LOCAL: 308 case Slot::LOCAL:
309 return frame_->LocalAt(index); 309 return frame_->LocalAt(index);
310 310
311 case Slot::CONTEXT: { 311 case Slot::CONTEXT: {
312 // Follow the context chain if necessary. 312 // Follow the context chain if necessary.
313 ASSERT(!tmp.is(cp)); // do not overwrite context register 313 ASSERT(!tmp.is(cp)); // do not overwrite context register
314 Register context = cp; 314 Register context = cp;
315 int chain_length = scope()->ContextChainLength(slot->var()->scope()); 315 int chain_length = scope()->ContextChainLength(slot->var()->scope());
316 for (int i = chain_length; i-- > 0;) { 316 for (int i = 0; i < chain_length; i++) {
317 // Load the closure. 317 // Load the closure.
318 // (All contexts, even 'with' contexts, have a closure, 318 // (All contexts, even 'with' contexts, have a closure,
319 // and it is the same for all contexts inside a function. 319 // and it is the same for all contexts inside a function.
320 // There is no need to go to the function context first.) 320 // There is no need to go to the function context first.)
321 __ ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); 321 __ ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
322 // Load the function context (which is the incoming, outer context). 322 // Load the function context (which is the incoming, outer context).
323 __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset)); 323 __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset));
324 context = tmp; 324 context = tmp;
325 } 325 }
326 // We may have a 'with' context now. Get the function context. 326 // We may have a 'with' context now. Get the function context.
327 // (In fact this mov may never be the needed, since the scope analysis 327 // (In fact this mov may never be the needed, since the scope analysis
328 // may not permit a direct context access in this case and thus we are 328 // may not permit a direct context access in this case and thus we are
329 // always at a function context. However it is safe to dereference be- 329 // always at a function context. However it is safe to dereference be-
330 // cause the function context of a function context is itself. Before 330 // cause the function context of a function context is itself. Before
331 // deleting this mov we should try to create a counter-example first, 331 // deleting this mov we should try to create a counter-example first,
332 // though...) 332 // though...)
333 __ ldr(tmp, ContextOperand(context, Context::FCONTEXT_INDEX)); 333 __ ldr(tmp, ContextOperand(context, Context::FCONTEXT_INDEX));
334 return ContextOperand(tmp, index); 334 return ContextOperand(tmp, index);
335 } 335 }
336 336
337 default: 337 default:
338 UNREACHABLE(); 338 UNREACHABLE();
339 return MemOperand(r0, 0); 339 return MemOperand(r0, 0);
340 } 340 }
341 } 341 }
342 342
343 343
344 MemOperand CodeGenerator::ContextSlotOperandCheckExtensions(
345 Slot* slot,
346 Register tmp,
347 Register tmp2,
348 JumpTarget* slow) {
349 ASSERT(slot->type() == Slot::CONTEXT);
350 Register context = cp;
351
352 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
353 if (s->num_heap_slots() > 0) {
354 if (s->calls_eval()) {
355 // Check that extension is NULL.
356 __ ldr(tmp2, ContextOperand(context, Context::EXTENSION_INDEX));
357 __ tst(tmp2, tmp2);
358 slow->Branch(ne);
359 }
360 __ ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
361 __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset));
362 context = tmp;
363 }
364 }
365 // Check that last extension is NULL.
366 __ ldr(tmp2, ContextOperand(context, Context::EXTENSION_INDEX));
367 __ tst(tmp2, tmp2);
368 slow->Branch(ne);
369 __ ldr(tmp, ContextOperand(context, Context::FCONTEXT_INDEX));
370 return ContextOperand(tmp, slot->index());
371 }
372
373
344 // Loads a value on TOS. If it is a boolean value, the result may have been 374 // Loads a value on TOS. If it is a boolean value, the result may have been
345 // (partially) translated into branches, or it may have set the condition 375 // (partially) translated into branches, or it may have set the condition
346 // code register. If force_cc is set, the value is forced to set the 376 // code register. If force_cc is set, the value is forced to set the
347 // condition code register and no value is pushed. If the condition code 377 // condition code register and no value is pushed. If the condition code
348 // register was set, has_cc() is true and cc_reg_ contains the condition to 378 // register was set, has_cc() is true and cc_reg_ contains the condition to
349 // test for 'true'. 379 // test for 'true'.
350 void CodeGenerator::LoadCondition(Expression* x, 380 void CodeGenerator::LoadCondition(Expression* x,
351 TypeofState typeof_state, 381 TypeofState typeof_state,
352 JumpTarget* true_target, 382 JumpTarget* true_target,
353 JumpTarget* false_target, 383 JumpTarget* false_target,
(...skipping 740 matching lines...) Expand 10 before | Expand all | Expand 10 after
1094 Variable* var = node->proxy()->var(); 1124 Variable* var = node->proxy()->var();
1095 ASSERT(var != NULL); // must have been resolved 1125 ASSERT(var != NULL); // must have been resolved
1096 Slot* slot = var->slot(); 1126 Slot* slot = var->slot();
1097 1127
1098 // If it was not possible to allocate the variable at compile time, 1128 // If it was not possible to allocate the variable at compile time,
1099 // we need to "declare" it at runtime to make sure it actually 1129 // we need to "declare" it at runtime to make sure it actually
1100 // exists in the local context. 1130 // exists in the local context.
1101 if (slot != NULL && slot->type() == Slot::LOOKUP) { 1131 if (slot != NULL && slot->type() == Slot::LOOKUP) {
1102 // Variables with a "LOOKUP" slot were introduced as non-locals 1132 // Variables with a "LOOKUP" slot were introduced as non-locals
1103 // during variable resolution and must have mode DYNAMIC. 1133 // during variable resolution and must have mode DYNAMIC.
1104 ASSERT(var->mode() == Variable::DYNAMIC); 1134 ASSERT(var->is_dynamic());
1105 // For now, just do a runtime call. 1135 // For now, just do a runtime call.
1106 frame_->EmitPush(cp); 1136 frame_->EmitPush(cp);
1107 __ mov(r0, Operand(var->name())); 1137 __ mov(r0, Operand(var->name()));
1108 frame_->EmitPush(r0); 1138 frame_->EmitPush(r0);
1109 // Declaration nodes are always declared in only two modes. 1139 // Declaration nodes are always declared in only two modes.
1110 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST); 1140 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST);
1111 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY; 1141 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY;
1112 __ mov(r0, Operand(Smi::FromInt(attr))); 1142 __ mov(r0, Operand(Smi::FromInt(attr)));
1113 frame_->EmitPush(r0); 1143 frame_->EmitPush(r0);
1114 // Push initial value, if any. 1144 // Push initial value, if any.
(...skipping 1090 matching lines...) Expand 10 before | Expand all | Expand 10 after
2205 exit.Jump(); 2235 exit.Jump();
2206 else_.Bind(); 2236 else_.Bind();
2207 LoadAndSpill(node->else_expression(), typeof_state()); 2237 LoadAndSpill(node->else_expression(), typeof_state());
2208 exit.Bind(); 2238 exit.Bind();
2209 } 2239 }
2210 2240
2211 2241
2212 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { 2242 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
2213 VirtualFrame::SpilledScope spilled_scope(this); 2243 VirtualFrame::SpilledScope spilled_scope(this);
2214 if (slot->type() == Slot::LOOKUP) { 2244 if (slot->type() == Slot::LOOKUP) {
2215 ASSERT(slot->var()->mode() == Variable::DYNAMIC); 2245 ASSERT(slot->var()->is_dynamic());
2216 2246
2217 // For now, just do a runtime call. 2247 JumpTarget slow(this);
2248 JumpTarget done(this);
2249
2250 // Generate fast-case code for variables that might be shadowed by
2251 // eval-introduced variables. Eval is used a lot without
2252 // introducing variables. In those cases, we do not want to
2253 // perform a runtime call for all variables in the scope
2254 // containing the eval.
2255 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
2256 LoadFromGlobalSlotCheckExtensions(slot, typeof_state, r1, r2, &slow);
2257 // If there was no control flow to slow, we can exit early.
2258 if (!slow.is_linked()) {
2259 frame_->EmitPush(r0);
2260 return;
2261 }
2262
2263 done.Jump();
2264
2265 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
2266 Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot();
2267 __ ldr(r0,
2268 ContextSlotOperandCheckExtensions(potential_slot,
2269 r1,
2270 r2,
2271 &slow));
2272 // There is always control flow to slow from
2273 // ContextSlotOperandCheckExtensions.
2274 done.Jump();
2275 }
2276
2277 slow.Bind();
2218 frame_->EmitPush(cp); 2278 frame_->EmitPush(cp);
2219 __ mov(r0, Operand(slot->var()->name())); 2279 __ mov(r0, Operand(slot->var()->name()));
2220 frame_->EmitPush(r0); 2280 frame_->EmitPush(r0);
2221 2281
2222 if (typeof_state == INSIDE_TYPEOF) { 2282 if (typeof_state == INSIDE_TYPEOF) {
2223 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); 2283 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
2224 } else { 2284 } else {
2225 frame_->CallRuntime(Runtime::kLoadContextSlot, 2); 2285 frame_->CallRuntime(Runtime::kLoadContextSlot, 2);
2226 } 2286 }
2287
2288 done.Bind();
2227 frame_->EmitPush(r0); 2289 frame_->EmitPush(r0);
2228 2290
2229 } else { 2291 } else {
2230 // Note: We would like to keep the assert below, but it fires because of 2292 // Note: We would like to keep the assert below, but it fires because of
2231 // some nasty code in LoadTypeofExpression() which should be removed... 2293 // some nasty code in LoadTypeofExpression() which should be removed...
2232 // ASSERT(slot->var()->mode() != Variable::DYNAMIC); 2294 // ASSERT(!slot->var()->is_dynamic());
2233 2295
2234 // Special handling for locals allocated in registers. 2296 // Special handling for locals allocated in registers.
2235 __ ldr(r0, SlotOperand(slot, r2)); 2297 __ ldr(r0, SlotOperand(slot, r2));
2236 frame_->EmitPush(r0); 2298 frame_->EmitPush(r0);
2237 if (slot->var()->mode() == Variable::CONST) { 2299 if (slot->var()->mode() == Variable::CONST) {
2238 // Const slots may contain 'the hole' value (the constant hasn't been 2300 // Const slots may contain 'the hole' value (the constant hasn't been
2239 // initialized yet) which needs to be converted into the 'undefined' 2301 // initialized yet) which needs to be converted into the 'undefined'
2240 // value. 2302 // value.
2241 Comment cmnt(masm_, "[ Unhole const"); 2303 Comment cmnt(masm_, "[ Unhole const");
2242 frame_->EmitPop(r0); 2304 frame_->EmitPop(r0);
2243 __ cmp(r0, Operand(Factory::the_hole_value())); 2305 __ cmp(r0, Operand(Factory::the_hole_value()));
2244 __ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq); 2306 __ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq);
2245 frame_->EmitPush(r0); 2307 frame_->EmitPush(r0);
2246 } 2308 }
2247 } 2309 }
2248 } 2310 }
2249 2311
2250 2312
2313 void CodeGenerator::LoadFromGlobalSlotCheckExtensions(Slot* slot,
2314 TypeofState typeof_state,
2315 Register tmp,
2316 Register tmp2,
2317 JumpTarget* slow) {
2318 // Check that no extension objects have been created by calls to
2319 // eval from the current scope to the global scope.
2320 Register context = cp;
2321 for (Scope* s = scope(); s != NULL; s = s->outer_scope()) {
2322 if (s->num_heap_slots() > 0) {
2323 if (s->calls_eval()) {
2324 // Check that extension is NULL.
2325 __ ldr(tmp2, ContextOperand(context, Context::EXTENSION_INDEX));
2326 __ tst(tmp2, tmp2);
2327 slow->Branch(ne);
2328 }
2329 // Load next context in chain.
2330 __ ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
2331 __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset));
2332 context = tmp;
2333 }
2334 // If no outer scope calls eval, we do not need to check more
2335 // context extensions.
2336 if (!s->outer_scope_calls_eval()) break;
2337 }
2338
2339 // All extension objects were empty and it is safe to use a global
2340 // load IC call.
2341 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
2342 // Load the global object.
2343 LoadGlobal();
2344 // Setup the name register.
2345 Result name = allocator_->Allocate(r2);
2346 ASSERT(name.is_valid()); // We are in spilled code.
2347 __ mov(name.reg(), Operand(slot->var()->name()));
2348 // Call IC stub.
2349 if (typeof_state == INSIDE_TYPEOF) {
2350 frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET, &name, 0);
2351 } else {
2352 frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET_CONTEXT, &name, 0);
2353 }
2354
2355 // Drop the global object. The result is in r0.
2356 frame_->Drop();
2357 }
2358
2359
2251 void CodeGenerator::VisitSlot(Slot* node) { 2360 void CodeGenerator::VisitSlot(Slot* node) {
2252 VirtualFrame::SpilledScope spilled_scope(this); 2361 VirtualFrame::SpilledScope spilled_scope(this);
2253 Comment cmnt(masm_, "[ Slot"); 2362 Comment cmnt(masm_, "[ Slot");
2254 LoadFromSlot(node, typeof_state()); 2363 LoadFromSlot(node, typeof_state());
2255 } 2364 }
2256 2365
2257 2366
2258 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { 2367 void CodeGenerator::VisitVariableProxy(VariableProxy* node) {
2259 VirtualFrame::SpilledScope spilled_scope(this); 2368 VirtualFrame::SpilledScope spilled_scope(this);
2260 Comment cmnt(masm_, "[ VariableProxy"); 2369 Comment cmnt(masm_, "[ VariableProxy");
(...skipping 1426 matching lines...) Expand 10 before | Expand all | Expand 10 after
3687 if (property != NULL) { 3796 if (property != NULL) {
3688 cgen_->CodeForSourcePosition(property->position()); 3797 cgen_->CodeForSourcePosition(property->position());
3689 } 3798 }
3690 3799
3691 switch (type_) { 3800 switch (type_) {
3692 case SLOT: { 3801 case SLOT: {
3693 Comment cmnt(masm, "[ Store to Slot"); 3802 Comment cmnt(masm, "[ Store to Slot");
3694 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); 3803 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
3695 ASSERT(slot != NULL); 3804 ASSERT(slot != NULL);
3696 if (slot->type() == Slot::LOOKUP) { 3805 if (slot->type() == Slot::LOOKUP) {
3697 ASSERT(slot->var()->mode() == Variable::DYNAMIC); 3806 ASSERT(slot->var()->is_dynamic());
3698 3807
3699 // For now, just do a runtime call. 3808 // For now, just do a runtime call.
3700 frame->EmitPush(cp); 3809 frame->EmitPush(cp);
3701 __ mov(r0, Operand(slot->var()->name())); 3810 __ mov(r0, Operand(slot->var()->name()));
3702 frame->EmitPush(r0); 3811 frame->EmitPush(r0);
3703 3812
3704 if (init_state == CONST_INIT) { 3813 if (init_state == CONST_INIT) {
3705 // Same as the case for a normal store, but ignores attribute 3814 // Same as the case for a normal store, but ignores attribute
3706 // (e.g. READ_ONLY) of context slot so that we can initialize 3815 // (e.g. READ_ONLY) of context slot so that we can initialize
3707 // const properties (introduced via eval("const foo = (some 3816 // const properties (introduced via eval("const foo = (some
(...skipping 11 matching lines...) Expand all
3719 // context slot followed by initialization. 3828 // context slot followed by initialization.
3720 frame->CallRuntime(Runtime::kInitializeConstContextSlot, 3); 3829 frame->CallRuntime(Runtime::kInitializeConstContextSlot, 3);
3721 } else { 3830 } else {
3722 frame->CallRuntime(Runtime::kStoreContextSlot, 3); 3831 frame->CallRuntime(Runtime::kStoreContextSlot, 3);
3723 } 3832 }
3724 // Storing a variable must keep the (new) value on the expression 3833 // Storing a variable must keep the (new) value on the expression
3725 // stack. This is necessary for compiling assignment expressions. 3834 // stack. This is necessary for compiling assignment expressions.
3726 frame->EmitPush(r0); 3835 frame->EmitPush(r0);
3727 3836
3728 } else { 3837 } else {
3729 ASSERT(slot->var()->mode() != Variable::DYNAMIC); 3838 ASSERT(!slot->var()->is_dynamic());
3730 3839
3731 JumpTarget exit(cgen_); 3840 JumpTarget exit(cgen_);
3732 if (init_state == CONST_INIT) { 3841 if (init_state == CONST_INIT) {
3733 ASSERT(slot->var()->mode() == Variable::CONST); 3842 ASSERT(slot->var()->mode() == Variable::CONST);
3734 // Only the first const initialization must be executed (the slot 3843 // Only the first const initialization must be executed (the slot
3735 // still contains 'the hole' value). When the assignment is 3844 // still contains 'the hole' value). When the assignment is
3736 // executed, the code is identical to a normal store (see below). 3845 // executed, the code is identical to a normal store (see below).
3737 Comment cmnt(masm, "[ Init const"); 3846 Comment cmnt(masm, "[ Init const");
3738 __ ldr(r2, cgen_->SlotOperand(slot, r2)); 3847 __ ldr(r2, cgen_->SlotOperand(slot, r2));
3739 __ cmp(r2, Operand(Factory::the_hole_value())); 3848 __ cmp(r2, Operand(Factory::the_hole_value()));
(...skipping 980 matching lines...) Expand 10 before | Expand all | Expand 10 after
4720 __ mov(r2, Operand(0)); 4829 __ mov(r2, Operand(0));
4721 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); 4830 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
4722 __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)), 4831 __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)),
4723 RelocInfo::CODE_TARGET); 4832 RelocInfo::CODE_TARGET);
4724 } 4833 }
4725 4834
4726 4835
4727 #undef __ 4836 #undef __
4728 4837
4729 } } // namespace v8::internal 4838 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/codegen-arm.h ('k') | src/codegen-ia32.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698