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

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

Issue 20419: Optimize loads from variables that might be shadowed by variables... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
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-ia32.h ('k') | src/contexts.cc » ('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 404 matching lines...) Expand 10 before | Expand all | Expand 10 after
415 return frame_->Parameter(index); 415 return frame_->Parameter(index);
416 416
417 case Slot::LOCAL: 417 case Slot::LOCAL:
418 return frame_->Local(index); 418 return frame_->Local(index);
419 419
420 case Slot::CONTEXT: { 420 case Slot::CONTEXT: {
421 // Follow the context chain if necessary. 421 // Follow the context chain if necessary.
422 ASSERT(!tmp.is(esi)); // do not overwrite context register 422 ASSERT(!tmp.is(esi)); // do not overwrite context register
423 Register context = esi; 423 Register context = esi;
424 int chain_length = scope()->ContextChainLength(slot->var()->scope()); 424 int chain_length = scope()->ContextChainLength(slot->var()->scope());
425 for (int i = chain_length; i-- > 0;) { 425 for (int i = 0; i < chain_length; i++) {
426 // Load the closure. 426 // Load the closure.
427 // (All contexts, even 'with' contexts, have a closure, 427 // (All contexts, even 'with' contexts, have a closure,
428 // and it is the same for all contexts inside a function. 428 // and it is the same for all contexts inside a function.
429 // There is no need to go to the function context first.) 429 // There is no need to go to the function context first.)
430 __ mov(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); 430 __ mov(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
431 // Load the function context (which is the incoming, outer context). 431 // Load the function context (which is the incoming, outer context).
432 __ mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset)); 432 __ mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset));
433 context = tmp; 433 context = tmp;
434 } 434 }
435 // We may have a 'with' context now. Get the function context. 435 // We may have a 'with' context now. Get the function context.
436 // (In fact this mov may never be the needed, since the scope analysis 436 // (In fact this mov may never be the needed, since the scope analysis
437 // may not permit a direct context access in this case and thus we are 437 // may not permit a direct context access in this case and thus we are
438 // always at a function context. However it is safe to dereference be- 438 // always at a function context. However it is safe to dereference be-
439 // cause the function context of a function context is itself. Before 439 // cause the function context of a function context is itself. Before
440 // deleting this mov we should try to create a counter-example first, 440 // deleting this mov we should try to create a counter-example first,
441 // though...) 441 // though...)
442 __ mov(tmp, ContextOperand(context, Context::FCONTEXT_INDEX)); 442 __ mov(tmp, ContextOperand(context, Context::FCONTEXT_INDEX));
443 return ContextOperand(tmp, index); 443 return ContextOperand(tmp, index);
444 } 444 }
445 445
446 default: 446 default:
447 UNREACHABLE(); 447 UNREACHABLE();
448 return Operand(eax); 448 return Operand(eax);
449 } 449 }
450 } 450 }
451 451
452 452
453 Operand CodeGenerator::ContextSlotOperandCheckExtensions(Slot* slot,
454 Register tmp,
455 Label* slow) {
456 ASSERT(slot->type() == Slot::CONTEXT);
457 int index = slot->index();
458 __ mov(tmp, Operand(esi));
459 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
460 if (s->num_heap_slots() > 0) {
461 if (s->calls_eval()) {
462 // Check that extension is NULL.
463 __ cmp(ContextOperand(tmp, Context::EXTENSION_INDEX), Immediate(0));
464 __ j(not_equal, slow, not_taken);
465 }
466 __ mov(tmp, ContextOperand(tmp, Context::CLOSURE_INDEX));
467 __ mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset));
468 }
469 }
470 // Check that last extension is NULL.
471 __ cmp(ContextOperand(tmp, Context::EXTENSION_INDEX), Immediate(0));
472 __ j(not_equal, slow, not_taken);
473 __ mov(tmp, ContextOperand(tmp, Context::FCONTEXT_INDEX));
474 return ContextOperand(tmp, index);
475 }
476
477
478
453 // Loads a value on TOS. If it is a boolean value, the result may have been 479 // Loads a value on TOS. If it is a boolean value, the result may have been
454 // (partially) translated into branches, or it may have set the condition 480 // (partially) translated into branches, or it may have set the condition
455 // code register. If force_cc is set, the value is forced to set the 481 // code register. If force_cc is set, the value is forced to set the
456 // condition code register and no value is pushed. If the condition code 482 // condition code register and no value is pushed. If the condition code
457 // register was set, has_cc() is true and cc_reg_ contains the condition to 483 // register was set, has_cc() is true and cc_reg_ contains the condition to
458 // test for 'true'. 484 // test for 'true'.
459 void CodeGenerator::LoadCondition(Expression* x, 485 void CodeGenerator::LoadCondition(Expression* x,
460 TypeofState typeof_state, 486 TypeofState typeof_state,
461 Label* true_target, 487 Label* true_target,
462 Label* false_target, 488 Label* false_target,
(...skipping 934 matching lines...) Expand 10 before | Expand all | Expand 10 after
1397 Variable* var = node->proxy()->var(); 1423 Variable* var = node->proxy()->var();
1398 ASSERT(var != NULL); // must have been resolved 1424 ASSERT(var != NULL); // must have been resolved
1399 Slot* slot = var->slot(); 1425 Slot* slot = var->slot();
1400 1426
1401 // If it was not possible to allocate the variable at compile time, 1427 // If it was not possible to allocate the variable at compile time,
1402 // we need to "declare" it at runtime to make sure it actually 1428 // we need to "declare" it at runtime to make sure it actually
1403 // exists in the local context. 1429 // exists in the local context.
1404 if (slot != NULL && slot->type() == Slot::LOOKUP) { 1430 if (slot != NULL && slot->type() == Slot::LOOKUP) {
1405 // Variables with a "LOOKUP" slot were introduced as non-locals 1431 // Variables with a "LOOKUP" slot were introduced as non-locals
1406 // during variable resolution and must have mode DYNAMIC. 1432 // during variable resolution and must have mode DYNAMIC.
1407 ASSERT(var->mode() == Variable::DYNAMIC); 1433 ASSERT(var->is_dynamic());
1408 // For now, just do a runtime call. 1434 // For now, just do a runtime call.
1409 frame_->Push(esi); 1435 frame_->Push(esi);
1410 frame_->Push(Immediate(var->name())); 1436 frame_->Push(Immediate(var->name()));
1411 // Declaration nodes are always introduced in one of two modes. 1437 // Declaration nodes are always introduced in one of two modes.
1412 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST); 1438 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST);
1413 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY; 1439 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY;
1414 frame_->Push(Immediate(Smi::FromInt(attr))); 1440 frame_->Push(Immediate(Smi::FromInt(attr)));
1415 // Push initial value, if any. 1441 // Push initial value, if any.
1416 // Note: For variables we must not push an initial value (such as 1442 // Note: For variables we must not push an initial value (such as
1417 // 'undefined') because we may have a (legal) redeclaration and we 1443 // 'undefined') because we may have a (legal) redeclaration and we
(...skipping 898 matching lines...) Expand 10 before | Expand all | Expand 10 after
2316 Load(node->then_expression(), typeof_state()); 2342 Load(node->then_expression(), typeof_state());
2317 __ jmp(&exit); 2343 __ jmp(&exit);
2318 __ bind(&else_); 2344 __ bind(&else_);
2319 Load(node->else_expression(), typeof_state()); 2345 Load(node->else_expression(), typeof_state());
2320 __ bind(&exit); 2346 __ bind(&exit);
2321 } 2347 }
2322 2348
2323 2349
2324 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { 2350 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
2325 if (slot->type() == Slot::LOOKUP) { 2351 if (slot->type() == Slot::LOOKUP) {
2326 ASSERT(slot->var()->mode() == Variable::DYNAMIC); 2352 ASSERT(slot->var()->is_dynamic());
2327 2353
2328 // For now, just do a runtime call. 2354 Label slow, done;
2355
2356 // Generate fast-case code for variables that might be shadowed by
2357 // eval-introduced variables. Eval is used a lot without
2358 // introducing variables. In those cases, we do not want to
2359 // perform a runtime call for all variables in the scope
2360 // containing the eval.
2361 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
2362 LoadFromGlobalSlotCheckExtensions(slot, typeof_state, ebx, &slow);
2363 __ jmp(&done);
2364
2365 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
2366 Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot();
2367 __ mov(eax,
2368 ContextSlotOperandCheckExtensions(potential_slot,
2369 ebx,
2370 &slow));
2371 __ jmp(&done);
2372 }
2373
2374 __ bind(&slow);
2329 frame_->Push(esi); 2375 frame_->Push(esi);
2330 frame_->Push(Immediate(slot->var()->name())); 2376 frame_->Push(Immediate(slot->var()->name()));
2331
2332 if (typeof_state == INSIDE_TYPEOF) { 2377 if (typeof_state == INSIDE_TYPEOF) {
2333 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); 2378 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
2334 } else { 2379 } else {
2335 __ CallRuntime(Runtime::kLoadContextSlot, 2); 2380 __ CallRuntime(Runtime::kLoadContextSlot, 2);
2336 } 2381 }
2382
2383 __ bind(&done);
2337 frame_->Push(eax); 2384 frame_->Push(eax);
2338 2385
2339 } else { 2386 } else {
2340 // Note: We would like to keep the assert below, but it fires because of 2387 // Note: We would like to keep the assert below, but it fires because of
2341 // some nasty code in LoadTypeofExpression() which should be removed... 2388 // some nasty code in LoadTypeofExpression() which should be removed...
2342 // ASSERT(slot->var()->mode() != Variable::DYNAMIC); 2389 // ASSERT(!slot->var()->is_dynamic());
2343 if (slot->var()->mode() == Variable::CONST) { 2390 if (slot->var()->mode() == Variable::CONST) {
2344 // Const slots may contain 'the hole' value (the constant hasn't been 2391 // Const slots may contain 'the hole' value (the constant hasn't been
2345 // initialized yet) which needs to be converted into the 'undefined' 2392 // initialized yet) which needs to be converted into the 'undefined'
2346 // value. 2393 // value.
2347 Comment cmnt(masm_, "[ Load const"); 2394 Comment cmnt(masm_, "[ Load const");
2348 Label exit; 2395 Label exit;
2349 __ mov(eax, SlotOperand(slot, ecx)); 2396 __ mov(eax, SlotOperand(slot, ecx));
2350 __ cmp(eax, Factory::the_hole_value()); 2397 __ cmp(eax, Factory::the_hole_value());
2351 __ j(not_equal, &exit); 2398 __ j(not_equal, &exit);
2352 __ mov(eax, Factory::undefined_value()); 2399 __ mov(eax, Factory::undefined_value());
2353 __ bind(&exit); 2400 __ bind(&exit);
2354 frame_->Push(eax); 2401 frame_->Push(eax);
2355 } else { 2402 } else {
2356 frame_->Push(SlotOperand(slot, ecx)); 2403 frame_->Push(SlotOperand(slot, ecx));
2357 } 2404 }
2358 } 2405 }
2359 } 2406 }
2360 2407
2361 2408
2409 void CodeGenerator::LoadFromGlobalSlotCheckExtensions(Slot* slot,
2410 TypeofState typeof_state,
2411 Register tmp,
2412 Label* slow) {
2413 // Check that no extension objects have been created by calls to
2414 // eval from the current scope to the global scope.
2415 __ mov(tmp, Operand(esi));
2416 for (Scope* s = scope(); s != NULL; s = s->outer_scope()) {
2417 if (s->num_heap_slots() > 0) {
2418 if (s->calls_eval()) {
2419 // Check that extension is NULL.
2420 __ cmp(ContextOperand(tmp, Context::EXTENSION_INDEX), Immediate(0));
2421 __ j(not_equal, slow, not_taken);
2422 }
2423 // Load next context in chain.
2424 __ mov(tmp, ContextOperand(tmp, Context::CLOSURE_INDEX));
2425 __ mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset));
2426 }
2427 // If no outer scope calls eval, we do not need to check more
2428 // context extensions.
2429 if (!s->outer_scope_calls_eval()) break;
2430 }
2431
2432 // All extension objects were empty and it is safe to use a global
2433 // load IC call.
2434 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
2435 // Load the global object.
2436 LoadGlobal();
2437 // Setup the name register.
2438 __ mov(ecx, slot->var()->name());
2439 // Call IC stub.
2440 if (typeof_state == INSIDE_TYPEOF) {
2441 __ call(ic, RelocInfo::CODE_TARGET);
2442 } else {
2443 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
2444 }
2445
2446 // Pop the global object. The result is in eax.
2447 frame_->Pop();
2448 }
2449
2450
2362 void CodeGenerator::VisitSlot(Slot* node) { 2451 void CodeGenerator::VisitSlot(Slot* node) {
2363 Comment cmnt(masm_, "[ Slot"); 2452 Comment cmnt(masm_, "[ Slot");
2364 LoadFromSlot(node, typeof_state()); 2453 LoadFromSlot(node, typeof_state());
2365 } 2454 }
2366 2455
2367 2456
2368 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { 2457 void CodeGenerator::VisitVariableProxy(VariableProxy* node) {
2369 Comment cmnt(masm_, "[ VariableProxy"); 2458 Comment cmnt(masm_, "[ VariableProxy");
2370 Variable* var = node->var(); 2459 Variable* var = node->var();
2371 Expression* expr = var->rewrite(); 2460 Expression* expr = var->rewrite();
(...skipping 1634 matching lines...) Expand 10 before | Expand all | Expand 10 after
4006 ASSERT(!is_illegal()); 4095 ASSERT(!is_illegal());
4007 ASSERT(!cgen_->has_cc()); 4096 ASSERT(!cgen_->has_cc());
4008 MacroAssembler* masm = cgen_->masm(); 4097 MacroAssembler* masm = cgen_->masm();
4009 VirtualFrame* frame = cgen_->frame(); 4098 VirtualFrame* frame = cgen_->frame();
4010 switch (type_) { 4099 switch (type_) {
4011 case SLOT: { 4100 case SLOT: {
4012 Comment cmnt(masm, "[ Store to Slot"); 4101 Comment cmnt(masm, "[ Store to Slot");
4013 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); 4102 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
4014 ASSERT(slot != NULL); 4103 ASSERT(slot != NULL);
4015 if (slot->type() == Slot::LOOKUP) { 4104 if (slot->type() == Slot::LOOKUP) {
4016 ASSERT(slot->var()->mode() == Variable::DYNAMIC); 4105 ASSERT(slot->var()->is_dynamic());
4017 4106
4018 // For now, just do a runtime call. 4107 // For now, just do a runtime call.
4019 frame->Push(esi); 4108 frame->Push(esi);
4020 frame->Push(Immediate(slot->var()->name())); 4109 frame->Push(Immediate(slot->var()->name()));
4021 4110
4022 if (init_state == CONST_INIT) { 4111 if (init_state == CONST_INIT) {
4023 // Same as the case for a normal store, but ignores attribute 4112 // Same as the case for a normal store, but ignores attribute
4024 // (e.g. READ_ONLY) of context slot so that we can initialize 4113 // (e.g. READ_ONLY) of context slot so that we can initialize
4025 // const properties (introduced via eval("const foo = (some 4114 // const properties (introduced via eval("const foo = (some
4026 // expr);")). Also, uses the current function context instead of 4115 // expr);")). Also, uses the current function context instead of
(...skipping 11 matching lines...) Expand all
4038 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); 4127 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
4039 } else { 4128 } else {
4040 __ CallRuntime(Runtime::kStoreContextSlot, 3); 4129 __ CallRuntime(Runtime::kStoreContextSlot, 3);
4041 } 4130 }
4042 // Storing a variable must keep the (new) value on the expression 4131 // Storing a variable must keep the (new) value on the expression
4043 // stack. This is necessary for compiling chained assignment 4132 // stack. This is necessary for compiling chained assignment
4044 // expressions. 4133 // expressions.
4045 frame->Push(eax); 4134 frame->Push(eax);
4046 4135
4047 } else { 4136 } else {
4048 ASSERT(slot->var()->mode() != Variable::DYNAMIC); 4137 ASSERT(!slot->var()->is_dynamic());
4049 4138
4050 Label exit; 4139 Label exit;
4051 if (init_state == CONST_INIT) { 4140 if (init_state == CONST_INIT) {
4052 ASSERT(slot->var()->mode() == Variable::CONST); 4141 ASSERT(slot->var()->mode() == Variable::CONST);
4053 // Only the first const initialization must be executed (the slot 4142 // Only the first const initialization must be executed (the slot
4054 // still contains 'the hole' value). When the assignment is 4143 // still contains 'the hole' value). When the assignment is
4055 // executed, the code is identical to a normal store (see below). 4144 // executed, the code is identical to a normal store (see below).
4056 Comment cmnt(masm, "[ Init const"); 4145 Comment cmnt(masm, "[ Init const");
4057 __ mov(eax, cgen_->SlotOperand(slot, ecx)); 4146 __ mov(eax, cgen_->SlotOperand(slot, ecx));
4058 __ cmp(eax, Factory::the_hole_value()); 4147 __ cmp(eax, Factory::the_hole_value());
(...skipping 1272 matching lines...) Expand 10 before | Expand all | Expand 10 after
5331 5420
5332 // Slow-case: Go through the JavaScript implementation. 5421 // Slow-case: Go through the JavaScript implementation.
5333 __ bind(&slow); 5422 __ bind(&slow);
5334 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); 5423 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
5335 } 5424 }
5336 5425
5337 5426
5338 #undef __ 5427 #undef __
5339 5428
5340 } } // namespace v8::internal 5429 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/codegen-ia32.h ('k') | src/contexts.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698