| 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 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 260 __ CallRuntime(Runtime::kNewContext, 1); // eax holds the result | 260 __ CallRuntime(Runtime::kNewContext, 1); // eax holds the result |
| 261 | 261 |
| 262 if (kDebug) { | 262 if (kDebug) { |
| 263 Label verified_true; | 263 Label verified_true; |
| 264 // Verify eax and esi are the same in debug mode | 264 // Verify eax and esi are the same in debug mode |
| 265 __ cmp(eax, Operand(esi)); | 265 __ cmp(eax, Operand(esi)); |
| 266 __ j(equal, &verified_true); | 266 __ j(equal, &verified_true); |
| 267 __ int3(); | 267 __ int3(); |
| 268 __ bind(&verified_true); | 268 __ bind(&verified_true); |
| 269 } | 269 } |
| 270 | |
| 271 // Update context local. | 270 // Update context local. |
| 272 __ mov(frame_->Context(), esi); | 271 __ mov(frame_->Context(), esi); |
| 273 // Restore the arguments array pointer, if any. | |
| 274 } | 272 } |
| 275 | 273 |
| 276 // TODO(1241774): Improve this code: | 274 // TODO(1241774): Improve this code: |
| 277 // 1) only needed if we have a context | 275 // 1) only needed if we have a context |
| 278 // 2) no need to recompute context ptr every single time | 276 // 2) no need to recompute context ptr every single time |
| 279 // 3) don't copy parameter operand code from SlotOperand! | 277 // 3) don't copy parameter operand code from SlotOperand! |
| 280 { | 278 { |
| 281 Comment cmnt2(masm_, "[ copy context parameters into .context"); | 279 Comment cmnt2(masm_, "[ copy context parameters into .context"); |
| 282 | 280 |
| 283 // Note that iteration order is relevant here! If we have the same | 281 // Note that iteration order is relevant here! If we have the same |
| (...skipping 19 matching lines...) Expand all Loading... |
| 303 __ mov(SlotOperand(slot, ecx), eax); | 301 __ mov(SlotOperand(slot, ecx), eax); |
| 304 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 302 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
| 305 __ RecordWrite(ecx, offset, eax, ebx); | 303 __ RecordWrite(ecx, offset, eax, ebx); |
| 306 } | 304 } |
| 307 } | 305 } |
| 308 } | 306 } |
| 309 | 307 |
| 310 // This section stores the pointer to the arguments object that | 308 // This section stores the pointer to the arguments object that |
| 311 // was allocated and copied into above. If the address was not | 309 // was allocated and copied into above. If the address was not |
| 312 // saved to TOS, we push ecx onto the stack. | 310 // saved to TOS, we push ecx onto the stack. |
| 313 | 311 // |
| 314 // Store the arguments object. | 312 // Store the arguments object. This must happen after context |
| 315 // This must happen after context initialization because | 313 // initialization because the arguments object may be stored in the |
| 316 // the arguments object may be stored in the context | 314 // context. |
| 317 if (arguments_object_allocated) { | 315 if (arguments_object_allocated) { |
| 318 ASSERT(scope_->arguments() != NULL); | 316 ASSERT(scope_->arguments() != NULL); |
| 319 ASSERT(scope_->arguments_shadow() != NULL); | 317 ASSERT(scope_->arguments_shadow() != NULL); |
| 320 Comment cmnt(masm_, "[ store arguments object"); | 318 Comment cmnt(masm_, "[ store arguments object"); |
| 321 { Reference shadow_ref(this, scope_->arguments_shadow()); | 319 { Reference shadow_ref(this, scope_->arguments_shadow()); |
| 322 ASSERT(shadow_ref.is_slot()); | 320 ASSERT(shadow_ref.is_slot()); |
| 323 { Reference arguments_ref(this, scope_->arguments()); | 321 { Reference arguments_ref(this, scope_->arguments()); |
| 324 ASSERT(arguments_ref.is_slot()); | 322 ASSERT(arguments_ref.is_slot()); |
| 325 // If the newly-allocated arguments object is already on the | 323 // If the newly-allocated arguments object is already on the |
| 326 // stack, we make use of the convenient property that references | 324 // stack, we make use of the convenient property that references |
| 327 // representing slots take up no space on the expression stack | 325 // representing slots take up no space on the expression stack |
| 328 // (ie, it doesn't matter that the stored value is actually below | 326 // (ie, it doesn't matter that the stored value is actually below |
| 329 // the reference). | 327 // the reference). |
| 330 // | 328 // |
| 331 // If the newly-allocated argument object is not already on | 329 // If the newly-allocated argument object is not already on |
| 332 // the stack, we rely on the property that loading a | 330 // the stack, we rely on the property that loading a |
| 333 // zero-sized reference will not clobber the ecx register. | 331 // zero-sized reference will not clobber the ecx register. |
| 334 if (!arguments_object_saved) { | 332 if (!arguments_object_saved) { |
| 335 frame_->Push(ecx); | 333 frame_->Push(ecx); |
| 336 } | 334 } |
| 337 arguments_ref.SetValue(NOT_CONST_INIT); | 335 arguments_ref.SetValue(NOT_CONST_INIT); |
| 338 } | 336 } |
| 339 shadow_ref.SetValue(NOT_CONST_INIT); | 337 shadow_ref.SetValue(NOT_CONST_INIT); |
| 340 } | 338 } |
| 341 frame_->Pop(); // Value is no longer needed. | 339 frame_->Pop(); // Value is no longer needed. |
| 342 } | 340 } |
| 343 | 341 |
| 344 // Generate code to 'execute' declarations and initialize | 342 // Generate code to 'execute' declarations and initialize functions |
| 345 // functions (source elements). In case of an illegal | 343 // (source elements). In case of an illegal redeclaration we need to |
| 346 // redeclaration we need to handle that instead of processing the | 344 // handle that instead of processing the declarations. |
| 347 // declarations. | |
| 348 if (scope_->HasIllegalRedeclaration()) { | 345 if (scope_->HasIllegalRedeclaration()) { |
| 349 Comment cmnt(masm_, "[ illegal redeclarations"); | 346 Comment cmnt(masm_, "[ illegal redeclarations"); |
| 350 scope_->VisitIllegalRedeclaration(this); | 347 scope_->VisitIllegalRedeclaration(this); |
| 351 } else { | 348 } else { |
| 352 Comment cmnt(masm_, "[ declarations"); | 349 Comment cmnt(masm_, "[ declarations"); |
| 353 ProcessDeclarations(scope_->declarations()); | 350 ProcessDeclarations(scope_->declarations()); |
| 354 // Bail out if a stack-overflow exception occurred when | 351 // Bail out if a stack-overflow exception occurred when processing |
| 355 // processing declarations. | 352 // declarations. |
| 356 if (HasStackOverflow()) return; | 353 if (HasStackOverflow()) return; |
| 357 } | 354 } |
| 358 | 355 |
| 359 if (FLAG_trace) { | 356 if (FLAG_trace) { |
| 360 __ CallRuntime(Runtime::kTraceEnter, 0); | 357 __ CallRuntime(Runtime::kTraceEnter, 0); |
| 361 // Ignore the return value. | 358 // Ignore the return value. |
| 362 } | 359 } |
| 363 CheckStack(); | 360 CheckStack(); |
| 364 | 361 |
| 365 // Compile the body of the function in a vanilla state. Don't | 362 // Compile the body of the function in a vanilla state. Don't |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 441 } | 438 } |
| 442 | 439 |
| 443 default: | 440 default: |
| 444 UNREACHABLE(); | 441 UNREACHABLE(); |
| 445 return Operand(eax); | 442 return Operand(eax); |
| 446 } | 443 } |
| 447 } | 444 } |
| 448 | 445 |
| 449 | 446 |
| 450 // Loads a value on TOS. If it is a boolean value, the result may have been | 447 // Loads a value on TOS. If it is a boolean value, the result may have been |
| 451 // (partially) translated into branches, or it may have set the condition code | 448 // (partially) translated into branches, or it may have set the condition |
| 452 // register. If force_cc is set, the value is forced to set the condition code | 449 // code register. If force_cc is set, the value is forced to set the |
| 453 // register and no value is pushed. If the condition code register was set, | 450 // condition code register and no value is pushed. If the condition code |
| 454 // has_cc() is true and cc_reg_ contains the condition to test for 'true'. | 451 // register was set, has_cc() is true and cc_reg_ contains the condition to |
| 452 // test for 'true'. |
| 455 void CodeGenerator::LoadCondition(Expression* x, | 453 void CodeGenerator::LoadCondition(Expression* x, |
| 456 TypeofState typeof_state, | 454 TypeofState typeof_state, |
| 457 Label* true_target, | 455 Label* true_target, |
| 458 Label* false_target, | 456 Label* false_target, |
| 459 bool force_cc) { | 457 bool force_cc) { |
| 460 ASSERT(!has_cc()); | 458 ASSERT(!has_cc()); |
| 461 | 459 |
| 462 { CodeGenState new_state(this, typeof_state, true_target, false_target); | 460 { CodeGenState new_state(this, typeof_state, true_target, false_target); |
| 463 Visit(x); | 461 Visit(x); |
| 464 } | 462 } |
| 465 if (force_cc && !has_cc()) { | 463 if (force_cc && !has_cc()) { |
| 464 // Convert the TOS value to a boolean in the condition code register. |
| 465 // Visiting an expression may possibly choose neither (a) to leave a |
| 466 // value in the condition code register nor (b) to leave a value in TOS |
| 467 // (eg, by compiling to only jumps to the targets). In that case the |
| 468 // code generated by ToBoolean is wrong because it assumes the value of |
| 469 // the expression in TOS. So long as there is always a value in TOS or |
| 470 // the condition code register when control falls through to here (there |
| 471 // is), the code generated by ToBoolean is dead and therefore safe. |
| 466 ToBoolean(true_target, false_target); | 472 ToBoolean(true_target, false_target); |
| 467 } | 473 } |
| 468 ASSERT(has_cc() || !force_cc); | 474 ASSERT(has_cc() || !force_cc); |
| 469 } | 475 } |
| 470 | 476 |
| 471 | 477 |
| 472 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { | 478 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { |
| 473 Label true_target; | 479 Label true_target; |
| 474 Label false_target; | 480 Label false_target; |
| 475 LoadCondition(x, typeof_state, &true_target, &false_target, false); | 481 LoadCondition(x, typeof_state, &true_target, &false_target, false); |
| 476 | 482 |
| 477 if (has_cc()) { | 483 if (has_cc()) { |
| 478 // convert cc_reg_ into a bool | 484 // convert cc_reg_ into a bool |
| 479 | |
| 480 Label loaded, materialize_true; | 485 Label loaded, materialize_true; |
| 481 __ j(cc_reg_, &materialize_true); | 486 __ j(cc_reg_, &materialize_true); |
| 482 frame_->Push(Immediate(Factory::false_value())); | 487 frame_->Push(Immediate(Factory::false_value())); |
| 483 __ jmp(&loaded); | 488 __ jmp(&loaded); |
| 484 __ bind(&materialize_true); | 489 __ bind(&materialize_true); |
| 485 frame_->Push(Immediate(Factory::true_value())); | 490 frame_->Push(Immediate(Factory::true_value())); |
| 486 __ bind(&loaded); | 491 __ bind(&loaded); |
| 487 cc_reg_ = no_condition; | 492 cc_reg_ = no_condition; |
| 488 } | 493 } |
| 489 | 494 |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 656 ASSERT(kSmiTag == 0); | 661 ASSERT(kSmiTag == 0); |
| 657 __ test(eax, Operand(eax)); | 662 __ test(eax, Operand(eax)); |
| 658 __ j(zero, false_target); | 663 __ j(zero, false_target); |
| 659 __ test(eax, Immediate(kSmiTagMask)); | 664 __ test(eax, Immediate(kSmiTagMask)); |
| 660 __ j(zero, true_target); | 665 __ j(zero, true_target); |
| 661 | 666 |
| 662 // Call the stub for all other cases. | 667 // Call the stub for all other cases. |
| 663 frame_->Push(eax); // Undo the pop(eax) from above. | 668 frame_->Push(eax); // Undo the pop(eax) from above. |
| 664 ToBooleanStub stub; | 669 ToBooleanStub stub; |
| 665 __ CallStub(&stub); | 670 __ CallStub(&stub); |
| 666 // Convert result (eax) to condition code. | 671 // Convert the result (eax) to condition code. |
| 667 __ test(eax, Operand(eax)); | 672 __ test(eax, Operand(eax)); |
| 668 | 673 |
| 669 ASSERT(not_equal == not_zero); | 674 ASSERT(not_equal == not_zero); |
| 670 cc_reg_ = not_equal; | 675 cc_reg_ = not_equal; |
| 671 } | 676 } |
| 672 | 677 |
| 673 | 678 |
| 674 class FloatingPointHelper : public AllStatic { | 679 class FloatingPointHelper : public AllStatic { |
| 675 public: | 680 public: |
| 676 // Code pattern for loading floating point values. Input values must | 681 // Code pattern for loading floating point values. Input values must |
| (...skipping 1514 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2191 frame_->Pop(eax); | 2196 frame_->Pop(eax); |
| 2192 ExternalReference handler_address(Top::k_handler_address); | 2197 ExternalReference handler_address(Top::k_handler_address); |
| 2193 __ mov(edx, Operand::StaticVariable(handler_address)); | 2198 __ mov(edx, Operand::StaticVariable(handler_address)); |
| 2194 const int kNextOffset = StackHandlerConstants::kNextOffset + | 2199 const int kNextOffset = StackHandlerConstants::kNextOffset + |
| 2195 StackHandlerConstants::kAddressDisplacement; | 2200 StackHandlerConstants::kAddressDisplacement; |
| 2196 __ lea(esp, Operand(edx, kNextOffset)); | 2201 __ lea(esp, Operand(edx, kNextOffset)); |
| 2197 | 2202 |
| 2198 frame_->Pop(Operand::StaticVariable(handler_address)); | 2203 frame_->Pop(Operand::StaticVariable(handler_address)); |
| 2199 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); | 2204 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
| 2200 // Next_sp popped. | 2205 // Next_sp popped. |
| 2201 // Preserve the TOS in a register across stack manipulation. | |
| 2202 frame_->Push(eax); | 2206 frame_->Push(eax); |
| 2203 | 2207 |
| 2204 // --- Finally block --- | 2208 // --- Finally block --- |
| 2205 __ bind(&finally_block); | 2209 __ bind(&finally_block); |
| 2206 | 2210 |
| 2207 // Push the state on the stack. | 2211 // Push the state on the stack. |
| 2208 frame_->Push(ecx); | 2212 frame_->Push(ecx); |
| 2209 | 2213 |
| 2210 // We keep two elements on the stack - the (possibly faked) result | 2214 // We keep two elements on the stack - the (possibly faked) result |
| 2211 // and the state - while evaluating the finally block. Record it, so | 2215 // and the state - while evaluating the finally block. Record it, so |
| (...skipping 2937 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5149 | 5153 |
| 5150 // Slow-case: Go through the JavaScript implementation. | 5154 // Slow-case: Go through the JavaScript implementation. |
| 5151 __ bind(&slow); | 5155 __ bind(&slow); |
| 5152 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 5156 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 5153 } | 5157 } |
| 5154 | 5158 |
| 5155 | 5159 |
| 5156 #undef __ | 5160 #undef __ |
| 5157 | 5161 |
| 5158 } } // namespace v8::internal | 5162 } } // namespace v8::internal |
| OLD | NEW |